yaffs Add stats tracking and control for background gc instrumentation
[yaffs2.git] / yaffs_fs.c
1 /*
2  * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3  *
4  * Copyright (C) 2002-2010 Aleph One Ltd.
5  *   for Toby Churchill Ltd and Brightstar Engineering
6  *
7  * Created by Charles Manning <charles@aleph1.co.uk>
8  * Acknowledgements:
9  * Luc van OostenRyck for numerous patches.
10  * Nick Bane for numerous patches.
11  * Nick Bane for 2.5/2.6 integration.
12  * Andras Toth for mknod rdev issue.
13  * Michael Fischer for finding the problem with inode inconsistency.
14  * Some code bodily lifted from JFFS
15  *
16  * This program is free software; you can redistribute it and/or modify
17  * it under the terms of the GNU General Public License version 2 as
18  * published by the Free Software Foundation.
19  */
20
21 /*
22  *
23  * This is the file system front-end to YAFFS that hooks it up to
24  * the VFS.
25  *
26  * Special notes:
27  * >> 2.4: sb->u.generic_sbp points to the yaffs_Device associated with
28  *         this superblock
29  * >> 2.6: sb->s_fs_info  points to the yaffs_Device associated with this
30  *         superblock
31  * >> inode->u.generic_ip points to the associated yaffs_Object.
32  */
33
34 #include <linux/version.h>
35
36 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 10))
37 #define YAFFS_COMPILE_BACKGROUND
38 #endif
39
40 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,28))
41 #define YAFFS_COMPILE_EXPORTFS
42 #endif
43
44 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
45 #define YAFFS_USE_SETATTR_COPY
46 #endif
47 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,35))
48 #define YAFFS_HAS_EVICT_INODE
49 #endif
50
51 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
52 #define YAFFS_NEW_FOLLOW_LINK 1
53 #else
54 #define YAFFS_NEW_FOLLOW_LINK 0
55 #endif
56
57 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
58 #include <linux/config.h>
59 #endif
60
61 #include <linux/kernel.h>
62 #include <linux/module.h>
63 #include <linux/slab.h>
64 #include <linux/init.h>
65 #include <linux/fs.h>
66 #include <linux/proc_fs.h>
67 #include <linux/smp_lock.h>
68 #include <linux/pagemap.h>
69 #include <linux/mtd/mtd.h>
70 #include <linux/interrupt.h>
71 #include <linux/string.h>
72 #include <linux/ctype.h>
73
74 #if (YAFFS_NEW_FOLLOW_LINK == 1)
75 #include <linux/namei.h>
76 #endif
77
78 #ifdef YAFFS_COMPILE_EXPORTFS
79 #include <linux/exportfs.h>
80 #endif
81
82 #ifdef YAFFS_COMPILE_BACKGROUND
83 #include <linux/kthread.h>
84 #include <linux/delay.h>
85 #include <linux/freezer.h>
86 #endif
87
88 #include <asm/div64.h>
89
90 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
91
92 #include <linux/statfs.h>
93
94 #define UnlockPage(p) unlock_page(p)
95 #define Page_Uptodate(page)     test_bit(PG_uptodate, &(page)->flags)
96
97 /* FIXME: use sb->s_id instead ? */
98 #define yaffs_devname(sb, buf)  bdevname(sb->s_bdev, buf)
99
100 #else
101
102 #include <linux/locks.h>
103 #define BDEVNAME_SIZE           0
104 #define yaffs_devname(sb, buf)  kdevname(sb->s_dev)
105
106 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0))
107 /* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
108 #define __user
109 #endif
110
111 #endif
112
113 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26))
114 #define YPROC_ROOT  (&proc_root)
115 #else
116 #define YPROC_ROOT  NULL
117 #endif
118
119 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
120 #define WRITE_SIZE_STR "writesize"
121 #define WRITE_SIZE(mtd) ((mtd)->writesize)
122 #else
123 #define WRITE_SIZE_STR "oobblock"
124 #define WRITE_SIZE(mtd) ((mtd)->oobblock)
125 #endif
126
127 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 27))
128 #define YAFFS_USE_WRITE_BEGIN_END 1
129 #else
130 #define YAFFS_USE_WRITE_BEGIN_END 0
131 #endif
132
133 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28))
134 static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size)
135 {
136         uint64_t result = partition_size;
137         do_div(result, block_size);
138         return (uint32_t)result;
139 }
140 #else
141 #define YCALCBLOCKS(s, b) ((s)/(b))
142 #endif
143
144 #include <linux/uaccess.h>
145 #include <linux/mtd/mtd.h>
146
147 #include "yportenv.h"
148 #include "yaffs_trace.h"
149 #include "yaffs_guts.h"
150
151 #include "yaffs_linux.h"
152
153 #include "yaffs_mtdif.h"
154 #include "yaffs_mtdif1.h"
155 #include "yaffs_mtdif2.h"
156
157 unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS;
158 unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
159 unsigned int yaffs_auto_checkpoint = 1;
160 unsigned int yaffs_gc_control = 1;
161 unsigned int yaffs_bg_enable = 1;
162
163 /* Module Parameters */
164 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
165 module_param(yaffs_traceMask, uint, 0644);
166 module_param(yaffs_wr_attempts, uint, 0644);
167 module_param(yaffs_auto_checkpoint, uint, 0644);
168 module_param(yaffs_gc_control, uint, 0644);
169 module_param(yaffs_bg_enable, uint, 0644);
170 #else
171 MODULE_PARM(yaffs_traceMask, "i");
172 MODULE_PARM(yaffs_wr_attempts, "i");
173 MODULE_PARM(yaffs_auto_checkpoint, "i");
174 MODULE_PARM(yaffs_gc_control, "i");
175 #endif
176
177 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25))
178 /* use iget and read_inode */
179 #define Y_IGET(sb, inum) iget((sb), (inum))
180 static void yaffs_read_inode(struct inode *inode);
181
182 #else
183 /* Call local equivalent */
184 #define YAFFS_USE_OWN_IGET
185 #define Y_IGET(sb, inum) yaffs_iget((sb), (inum))
186
187 static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
188 #endif
189
190 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
191 #define yaffs_InodeToObjectLV(iptr) ((iptr)->i_private)
192 #else
193 #define yaffs_InodeToObjectLV(iptr) ((iptr)->u.generic_ip)
194 #endif
195
196 #define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
197 #define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
198
199 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
200 #define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
201 #else
202 #define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
203 #endif
204
205
206 #define update_dir_time(dir) do {\
207                         (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
208                 } while(0)
209                 
210 static void yaffs_put_super(struct super_block *sb);
211
212 static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
213                                 loff_t *pos);
214 static ssize_t yaffs_hold_space(struct file *f);
215 static void yaffs_release_space(struct file *f);
216
217 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
218 static int yaffs_file_flush(struct file *file, fl_owner_t id);
219 #else
220 static int yaffs_file_flush(struct file *file);
221 #endif
222
223 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
224 static int yaffs_sync_object(struct file *file, int datasync);
225 #else
226 static int yaffs_sync_object(struct file *file, struct dentry *dentry,
227                                 int datasync);
228 #endif
229
230 static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
231
232 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
233 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
234                         struct nameidata *n);
235 static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
236                                         struct nameidata *n);
237 #else
238 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
239 static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
240 #endif
241 static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
242                         struct dentry *dentry);
243 static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
244 static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
245                         const char *symname);
246 static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
247
248 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
249 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
250                         dev_t dev);
251 #else
252 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
253                         int dev);
254 #endif
255 static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
256                         struct inode *new_dir, struct dentry *new_dentry);
257 static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
258
259 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
260 static int yaffs_sync_fs(struct super_block *sb, int wait);
261 static void yaffs_write_super(struct super_block *sb);
262 #else
263 static int yaffs_sync_fs(struct super_block *sb);
264 static int yaffs_write_super(struct super_block *sb);
265 #endif
266
267 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
268 static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
269 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
270 static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
271 #else
272 static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
273 #endif
274
275 #ifdef YAFFS_HAS_PUT_INODE
276 static void yaffs_put_inode(struct inode *inode);
277 #endif
278
279 #ifdef YAFFS_HAS_EVICT_INODE
280 static void yaffs_evict_inode(struct inode *);
281 #else
282 static void yaffs_delete_inode(struct inode *);
283 static void yaffs_clear_inode(struct inode *);
284 #endif
285
286 static int yaffs_readpage(struct file *file, struct page *page);
287 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
288 static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
289 #else
290 static int yaffs_writepage(struct page *page);
291 #endif
292
293 #ifdef CONFIG_YAFFS_XATTR
294 int yaffs_setxattr(struct dentry *dentry, const char *name,
295                         const void *value, size_t size, int flags);
296 ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
297                         size_t size);
298 int yaffs_removexattr(struct dentry *dentry, const char *name);
299 ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size);
300 #endif
301
302
303 #if (YAFFS_USE_WRITE_BEGIN_END != 0)
304 static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
305                                 loff_t pos, unsigned len, unsigned flags,
306                                 struct page **pagep, void **fsdata);
307 static int yaffs_write_end(struct file *filp, struct address_space *mapping,
308                                 loff_t pos, unsigned len, unsigned copied,
309                                 struct page *pg, void *fsdadata);
310 #else
311 static int yaffs_prepare_write(struct file *f, struct page *pg,
312                                 unsigned offset, unsigned to);
313 static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
314                                 unsigned to);
315
316 #endif
317
318 static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
319                                 int buflen);
320 #if (YAFFS_NEW_FOLLOW_LINK == 1)
321 void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias);
322 static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
323 #else
324 static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
325 #endif
326
327 static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev);
328
329 static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin);
330
331 static int yaffs_vfs_setattr(struct inode *, struct iattr *);
332
333
334 static struct address_space_operations yaffs_file_address_operations = {
335         .readpage = yaffs_readpage,
336         .writepage = yaffs_writepage,
337 #if (YAFFS_USE_WRITE_BEGIN_END > 0)
338         .write_begin = yaffs_write_begin,
339         .write_end = yaffs_write_end,
340 #else
341         .prepare_write = yaffs_prepare_write,
342         .commit_write = yaffs_commit_write,
343 #endif
344 };
345
346
347 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 22))
348 static const struct file_operations yaffs_file_operations = {
349         .read = do_sync_read,
350         .write = do_sync_write,
351         .aio_read = generic_file_aio_read,
352         .aio_write = generic_file_aio_write,
353         .mmap = generic_file_mmap,
354         .flush = yaffs_file_flush,
355         .fsync = yaffs_sync_object,
356         .splice_read = generic_file_splice_read,
357         .splice_write = generic_file_splice_write,
358         .llseek = generic_file_llseek,
359 };
360
361 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 18))
362
363 static const struct file_operations yaffs_file_operations = {
364         .read = do_sync_read,
365         .write = do_sync_write,
366         .aio_read = generic_file_aio_read,
367         .aio_write = generic_file_aio_write,
368         .mmap = generic_file_mmap,
369         .flush = yaffs_file_flush,
370         .fsync = yaffs_sync_object,
371         .sendfile = generic_file_sendfile,
372 };
373
374 #else
375
376 static const struct file_operations yaffs_file_operations = {
377         .read = generic_file_read,
378         .write = generic_file_write,
379         .mmap = generic_file_mmap,
380         .flush = yaffs_file_flush,
381         .fsync = yaffs_sync_object,
382 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
383         .sendfile = generic_file_sendfile,
384 #endif
385 };
386 #endif
387
388 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
389 static void zero_user_segment(struct page *page, unsigned start, unsigned end)
390 {
391         void * kaddr = kmap_atomic(page, KM_USER0);
392         memset(kaddr + start, 0, end - start);
393         kunmap_atomic(kaddr, KM_USER0);
394         flush_dcache_page(page);
395 }
396 #endif
397
398
399 static const struct inode_operations yaffs_file_inode_operations = {
400         .setattr = yaffs_setattr,
401 #ifdef CONFIG_YAFFS_XATTR
402         .setxattr = yaffs_setxattr,
403         .getxattr = yaffs_getxattr,
404         .listxattr = yaffs_listxattr,
405         .removexattr = yaffs_removexattr,
406 #endif
407 };
408
409 static const struct inode_operations yaffs_symlink_inode_operations = {
410         .readlink = yaffs_readlink,
411         .follow_link = yaffs_follow_link,
412 #if (YAFFS_NEW_FOLLOW_LINK == 1)
413         .put_link = yaffs_put_link,
414 #endif
415         .setattr = yaffs_setattr,
416 #ifdef CONFIG_YAFFS_XATTR
417         .setxattr = yaffs_setxattr,
418         .getxattr = yaffs_getxattr,
419         .listxattr = yaffs_listxattr,
420         .removexattr = yaffs_removexattr,
421 #endif
422 };
423
424 static const struct inode_operations yaffs_dir_inode_operations = {
425         .create = yaffs_create,
426         .lookup = yaffs_lookup,
427         .link = yaffs_link,
428         .unlink = yaffs_unlink,
429         .symlink = yaffs_symlink,
430         .mkdir = yaffs_mkdir,
431         .rmdir = yaffs_unlink,
432         .mknod = yaffs_mknod,
433         .rename = yaffs_rename,
434         .setattr = yaffs_setattr,
435 #ifdef CONFIG_YAFFS_XATTR
436         .setxattr = yaffs_setxattr,
437         .getxattr = yaffs_getxattr,
438         .listxattr = yaffs_listxattr,
439         .removexattr = yaffs_removexattr,
440 #endif
441 };
442
443 static const struct file_operations yaffs_dir_operations = {
444         .read = generic_read_dir,
445         .readdir = yaffs_readdir,
446         .fsync = yaffs_sync_object,
447         .llseek = yaffs_dir_llseek,
448 };
449
450 static const struct super_operations yaffs_super_ops = {
451         .statfs = yaffs_statfs,
452
453 #ifndef YAFFS_USE_OWN_IGET
454         .read_inode = yaffs_read_inode,
455 #endif
456 #ifdef YAFFS_HAS_PUT_INODE
457         .put_inode = yaffs_put_inode,
458 #endif
459         .put_super = yaffs_put_super,
460 #ifdef YAFFS_HAS_EVICT_INODE
461         .evict_inode = yaffs_evict_inode,
462 #else
463         .delete_inode = yaffs_delete_inode,
464         .clear_inode = yaffs_clear_inode,
465 #endif
466         .sync_fs = yaffs_sync_fs,
467         .write_super = yaffs_write_super,
468 };
469
470
471 static  int yaffs_vfs_setattr(struct inode *inode, struct iattr *attr)
472 {
473 #ifdef  YAFFS_USE_SETATTR_COPY
474         setattr_copy(inode,attr);
475         return 0;
476 #else
477         return inode_setattr(inode, attr);
478 #endif
479
480 }
481
482 static unsigned yaffs_gc_control_callback(yaffs_Device *dev)
483 {
484         return yaffs_gc_control;
485 }
486                                                                                                                         
487 static void yaffs_GrossLock(yaffs_Device *dev)
488 {
489         T(YAFFS_TRACE_LOCK, (TSTR("yaffs locking %p\n"), current));
490         down(&(yaffs_DeviceToLC(dev)->grossLock));
491         T(YAFFS_TRACE_LOCK, (TSTR("yaffs locked %p\n"), current));
492 }
493
494 static void yaffs_GrossUnlock(yaffs_Device *dev)
495 {
496         T(YAFFS_TRACE_LOCK, (TSTR("yaffs unlocking %p\n"), current));
497         up(&(yaffs_DeviceToLC(dev)->grossLock));
498 }
499
500 #ifdef YAFFS_COMPILE_EXPORTFS
501
502 static struct inode *
503 yaffs2_nfs_get_inode(struct super_block *sb, uint64_t ino, uint32_t generation)
504 {
505         return Y_IGET(sb, ino);
506 }
507
508 static struct dentry *
509 yaffs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
510 {
511         return generic_fh_to_dentry(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode) ;
512 }
513
514 static struct dentry *
515  yaffs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type)
516 {
517         return generic_fh_to_parent(sb, fid, fh_len, fh_type, yaffs2_nfs_get_inode);
518 }
519
520 struct dentry *yaffs2_get_parent(struct dentry *dentry)
521 {
522
523         struct super_block *sb = dentry->d_inode->i_sb;
524         struct dentry *parent = ERR_PTR(-ENOENT);
525         struct inode *inode;
526         unsigned long parent_ino;
527         yaffs_Object *d_obj;
528         yaffs_Object *parent_obj;
529
530         d_obj = yaffs_InodeToObject(dentry->d_inode);
531
532         if (d_obj) {
533                 parent_obj = d_obj->parent;
534                 if (parent_obj) {
535                         parent_ino = yaffs_GetObjectInode(parent_obj);
536                         inode = Y_IGET(sb, parent_ino);
537
538                         if (IS_ERR(inode)) {
539                                 parent = ERR_CAST(inode);
540                         } else {
541                                 parent = d_obtain_alias(inode);
542                                 if (!IS_ERR(parent)) {
543                                         parent = ERR_PTR(-ENOMEM);
544                                         iput(inode);
545                                 }
546                         }
547                 }
548         }
549
550         return parent;
551 }
552
553 /* Just declare a zero structure as a NULL value implies
554  * using the default functions of exportfs.
555  */
556
557 static struct export_operations yaffs_export_ops =
558 {
559         .fh_to_dentry = yaffs2_fh_to_dentry,
560         .fh_to_parent = yaffs2_fh_to_parent,
561         .get_parent = yaffs2_get_parent,
562 } ;
563
564 #endif
565
566 /*-----------------------------------------------------------------*/
567 /* Directory search context allows us to unlock access to yaffs during
568  * filldir without causing problems with the directory being modified.
569  * This is similar to the tried and tested mechanism used in yaffs direct.
570  *
571  * A search context iterates along a doubly linked list of siblings in the
572  * directory. If the iterating object is deleted then this would corrupt
573  * the list iteration, likely causing a crash. The search context avoids
574  * this by using the removeObjectCallback to move the search context to the
575  * next object before the object is deleted.
576  *
577  * Many readdirs (and thus seach conexts) may be alive simulateously so
578  * each yaffs_Device has a list of these.
579  *
580  * A seach context lives for the duration of a readdir.
581  *
582  * All these functions must be called while yaffs is locked.
583  */
584
585 struct yaffs_SearchContext {
586         yaffs_Device *dev;
587         yaffs_Object *dirObj;
588         yaffs_Object *nextReturn;
589         struct ylist_head others;
590 };
591
592 /*
593  * yaffs_NewSearch() creates a new search context, initialises it and
594  * adds it to the device's search context list.
595  *
596  * Called at start of readdir.
597  */
598 static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
599 {
600         yaffs_Device *dev = dir->myDev;
601         struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
602         if(sc){
603                 sc->dirObj = dir;
604                 sc->dev = dev;
605                 if( ylist_empty(&sc->dirObj->variant.directoryVariant.children))
606                         sc->nextReturn = NULL;
607                 else
608                         sc->nextReturn = ylist_entry(
609                                 dir->variant.directoryVariant.children.next,
610                                 yaffs_Object,siblings);
611                 YINIT_LIST_HEAD(&sc->others);
612                 ylist_add(&sc->others,&(yaffs_DeviceToLC(dev)->searchContexts));
613         }
614         return sc;
615 }
616
617 /*
618  * yaffs_EndSearch() disposes of a search context and cleans up.
619  */
620 static void yaffs_EndSearch(struct yaffs_SearchContext * sc)
621 {
622         if(sc){
623                 ylist_del(&sc->others);
624                 YFREE(sc);
625         }
626 }
627
628 /*
629  * yaffs_SearchAdvance() moves a search context to the next object.
630  * Called when the search iterates or when an object removal causes
631  * the search context to be moved to the next object.
632  */
633 static void yaffs_SearchAdvance(struct yaffs_SearchContext *sc)
634 {
635         if(!sc)
636                 return;
637
638         if( sc->nextReturn == NULL ||
639                 ylist_empty(&sc->dirObj->variant.directoryVariant.children))
640                 sc->nextReturn = NULL;
641         else {
642                 struct ylist_head *next = sc->nextReturn->siblings.next;
643
644                 if( next == &sc->dirObj->variant.directoryVariant.children)
645                         sc->nextReturn = NULL; /* end of list */
646                 else
647                         sc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
648         }
649 }
650
651 /*
652  * yaffs_RemoveObjectCallback() is called when an object is unlinked.
653  * We check open search contexts and advance any which are currently
654  * on the object being iterated.
655  */
656 static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
657 {
658
659         struct ylist_head *i;
660         struct yaffs_SearchContext *sc;
661         struct ylist_head *search_contexts = &(yaffs_DeviceToLC(obj->myDev)->searchContexts);
662
663
664         /* Iterate through the directory search contexts.
665          * If any are currently on the object being removed, then advance
666          * the search context to the next object to prevent a hanging pointer.
667          */
668          ylist_for_each(i, search_contexts) {
669                 if (i) {
670                         sc = ylist_entry(i, struct yaffs_SearchContext,others);
671                         if(sc->nextReturn == obj)
672                                 yaffs_SearchAdvance(sc);
673                 }
674         }
675
676 }
677
678
679 /*-----------------------------------------------------------------*/
680
681 static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
682                         int buflen)
683 {
684         unsigned char *alias;
685         int ret;
686
687         yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
688
689         yaffs_GrossLock(dev);
690
691         alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
692
693         yaffs_GrossUnlock(dev);
694
695         if (!alias)
696                 return -ENOMEM;
697
698         ret = vfs_readlink(dentry, buffer, buflen, alias);
699         kfree(alias);
700         return ret;
701 }
702
703 #if (YAFFS_NEW_FOLLOW_LINK == 1)
704 static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
705 #else
706 static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
707 #endif
708 {
709         unsigned char *alias;
710         int ret;
711         yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
712
713         yaffs_GrossLock(dev);
714
715         alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
716         yaffs_GrossUnlock(dev);
717
718         if (!alias) {
719                 ret = -ENOMEM;
720                 goto out;
721         }
722
723 #if (YAFFS_NEW_FOLLOW_LINK == 1)
724         nd_set_link(nd, alias);
725         ret = (int)alias;
726 out:
727         return ERR_PTR(ret);
728 #else
729         ret = vfs_follow_link(nd, alias);
730         kfree(alias);
731 out:
732         return ret;
733 #endif
734 }
735
736 #if (YAFFS_NEW_FOLLOW_LINK == 1)
737 void yaffs_put_link(struct dentry *dentry, struct nameidata *nd, void *alias) {
738         kfree(alias);
739 }
740 #endif
741
742 struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
743                                 yaffs_Object *obj);
744
745 /*
746  * Lookup is used to find objects in the fs
747  */
748 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
749
750 static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
751                                 struct nameidata *n)
752 #else
753 static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
754 #endif
755 {
756         yaffs_Object *obj;
757         struct inode *inode = NULL;     /* NCB 2.5/2.6 needs NULL here */
758
759         yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
760
761         if(current != yaffs_DeviceToLC(dev)->readdirProcess)
762                 yaffs_GrossLock(dev);
763
764         T(YAFFS_TRACE_OS,
765                 (TSTR("yaffs_lookup for %d:%s\n"),
766                 yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
767
768         obj = yaffs_FindObjectByName(yaffs_InodeToObject(dir),
769                                         dentry->d_name.name);
770
771         obj = yaffs_GetEquivalentObject(obj);   /* in case it was a hardlink */
772
773         /* Can't hold gross lock when calling yaffs_get_inode() */
774         if(current != yaffs_DeviceToLC(dev)->readdirProcess)
775                 yaffs_GrossUnlock(dev);
776
777         if (obj) {
778                 T(YAFFS_TRACE_OS,
779                         (TSTR("yaffs_lookup found %d\n"), obj->objectId));
780
781                 inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
782
783                 if (inode) {
784                         T(YAFFS_TRACE_OS,
785                                 (TSTR("yaffs_loookup dentry \n")));
786 /* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
787  * d_add even if NULL inode */
788 #if 0
789                         /*dget(dentry); // try to solve directory bug */
790                         d_add(dentry, inode);
791
792                         /* return dentry; */
793                         return NULL;
794 #endif
795                 }
796
797         } else {
798                 T(YAFFS_TRACE_OS,(TSTR("yaffs_lookup not found\n")));
799
800         }
801
802 /* added NCB for 2.5/6 compatability - forces add even if inode is
803  * NULL which creates dentry hash */
804         d_add(dentry, inode);
805
806         return NULL;
807 }
808
809
810 #ifdef YAFFS_HAS_PUT_INODE
811
812 /* For now put inode is just for debugging
813  * Put inode is called when the inode **structure** is put.
814  */
815 static void yaffs_put_inode(struct inode *inode)
816 {
817         T(YAFFS_TRACE_OS,
818                 (TSTR("yaffs_put_inode: ino %d, count %d\n"), (int)inode->i_ino,
819                 atomic_read(&inode->i_count)));
820
821 }
822 #endif
823
824
825 static void yaffs_UnstitchObject(struct inode *inode, yaffs_Object *obj)
826 {
827         /* Clear the association between the inode and
828          * the yaffs_Object.
829          */
830         obj->myInode = NULL;
831         yaffs_InodeToObjectLV(inode) = NULL;
832
833         /* If the object freeing was deferred, then the real
834          * free happens now.
835          * This should fix the inode inconsistency problem.
836          */
837         yaffs_HandleDeferedFree(obj);
838 }
839
840 #ifdef YAFFS_HAS_EVICT_INODE
841 /* yaffs_evict_inode combines into one operation what was previously done in
842  * yaffs_clear_inode() and yaffs_delete_inode()
843  *
844  */
845 static void yaffs_evict_inode( struct inode *inode)
846 {
847         yaffs_Object *obj;
848         yaffs_Device *dev;
849         int deleteme = 0;
850
851         obj = yaffs_InodeToObject(inode);
852
853         T(YAFFS_TRACE_OS,
854                 (TSTR("yaffs_evict_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
855                 atomic_read(&inode->i_count),
856                 obj ? "object exists" : "null object"));
857
858         if (!inode->i_nlink && !is_bad_inode(inode))
859                 deleteme = 1;
860         truncate_inode_pages(&inode->i_data,0);
861
862         if(deleteme && obj){
863                 dev = obj->myDev;
864                 yaffs_GrossLock(dev);
865                 yaffs_DeleteObject(obj);
866                 yaffs_GrossUnlock(dev);
867         }
868         end_writeback(inode);
869         if (obj) {
870                 dev = obj->myDev;
871                 yaffs_GrossLock(dev);
872                 yaffs_UnstitchObject(inode,obj);
873                 yaffs_GrossUnlock(dev);
874         }
875
876
877 }
878 #else
879
880 /* clear is called to tell the fs to release any per-inode data it holds.
881  * The object might still exist on disk and is just being thrown out of the cache
882  * or else the object has actually been deleted and we're being called via
883  * the chain
884  *   yaffs_delete_inode() -> clear_inode()->yaffs_clear_inode()
885  */
886
887 static void yaffs_clear_inode(struct inode *inode)
888 {
889         yaffs_Object *obj;
890         yaffs_Device *dev;
891
892         obj = yaffs_InodeToObject(inode);
893
894         T(YAFFS_TRACE_OS,
895                 (TSTR("yaffs_clear_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
896                 atomic_read(&inode->i_count),
897                 obj ? "object exists" : "null object"));
898
899         if (obj) {
900                 dev = obj->myDev;
901                 yaffs_GrossLock(dev);
902                 yaffs_UnstitchObject(inode,obj);
903                 yaffs_GrossUnlock(dev);
904         }
905
906 }
907
908 /* delete is called when the link count is zero and the inode
909  * is put (ie. nobody wants to know about it anymore, time to
910  * delete the file).
911  * NB Must call clear_inode()
912  */
913 static void yaffs_delete_inode(struct inode *inode)
914 {
915         yaffs_Object *obj = yaffs_InodeToObject(inode);
916         yaffs_Device *dev;
917
918         T(YAFFS_TRACE_OS,
919                 (TSTR("yaffs_delete_inode: ino %d, count %d %s\n"), (int)inode->i_ino,
920                 atomic_read(&inode->i_count),
921                 obj ? "object exists" : "null object"));
922
923         if (obj) {
924                 dev = obj->myDev;
925                 yaffs_GrossLock(dev);
926                 yaffs_DeleteObject(obj);
927                 yaffs_GrossUnlock(dev);
928         }
929 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13))
930         truncate_inode_pages(&inode->i_data, 0);
931 #endif
932         clear_inode(inode);
933 }
934 #endif
935
936
937 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
938 static int yaffs_file_flush(struct file *file, fl_owner_t id)
939 #else
940 static int yaffs_file_flush(struct file *file)
941 #endif
942 {
943         yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
944
945         yaffs_Device *dev = obj->myDev;
946
947         T(YAFFS_TRACE_OS,
948                 (TSTR("yaffs_file_flush object %d (%s)\n"), obj->objectId,
949                 obj->dirty ? "dirty" : "clean"));
950
951         yaffs_GrossLock(dev);
952
953         yaffs_FlushFile(obj, 1, 0);
954
955         yaffs_GrossUnlock(dev);
956
957         return 0;
958 }
959
960 static int yaffs_readpage_nolock(struct file *f, struct page *pg)
961 {
962         /* Lifted from jffs2 */
963
964         yaffs_Object *obj;
965         unsigned char *pg_buf;
966         int ret;
967
968         yaffs_Device *dev;
969
970         T(YAFFS_TRACE_OS,
971                 (TSTR("yaffs_readpage_nolock at %08x, size %08x\n"),
972                 (unsigned)(pg->index << PAGE_CACHE_SHIFT),
973                 (unsigned)PAGE_CACHE_SIZE));
974
975         obj = yaffs_DentryToObject(f->f_dentry);
976
977         dev = obj->myDev;
978
979 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
980         BUG_ON(!PageLocked(pg));
981 #else
982         if (!PageLocked(pg))
983                 PAGE_BUG(pg);
984 #endif
985
986         pg_buf = kmap(pg);
987         /* FIXME: Can kmap fail? */
988
989         yaffs_GrossLock(dev);
990
991         ret = yaffs_ReadDataFromFile(obj, pg_buf,
992                                 pg->index << PAGE_CACHE_SHIFT,
993                                 PAGE_CACHE_SIZE);
994
995         yaffs_GrossUnlock(dev);
996
997         if (ret >= 0)
998                 ret = 0;
999
1000         if (ret) {
1001                 ClearPageUptodate(pg);
1002                 SetPageError(pg);
1003         } else {
1004                 SetPageUptodate(pg);
1005                 ClearPageError(pg);
1006         }
1007
1008         flush_dcache_page(pg);
1009         kunmap(pg);
1010
1011         T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage_nolock done\n")));
1012         return ret;
1013 }
1014
1015 static int yaffs_readpage_unlock(struct file *f, struct page *pg)
1016 {
1017         int ret = yaffs_readpage_nolock(f, pg);
1018         UnlockPage(pg);
1019         return ret;
1020 }
1021
1022 static int yaffs_readpage(struct file *f, struct page *pg)
1023 {
1024         int ret;
1025
1026         T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage\n")));
1027         ret=yaffs_readpage_unlock(f, pg);
1028         T(YAFFS_TRACE_OS, (TSTR("yaffs_readpage done\n")));
1029         return ret;
1030 }
1031
1032 /* writepage inspired by/stolen from smbfs */
1033
1034 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1035 static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
1036 #else
1037 static int yaffs_writepage(struct page *page)
1038 #endif
1039 {
1040         yaffs_Device *dev;
1041         struct address_space *mapping = page->mapping;
1042         struct inode *inode;
1043         unsigned long end_index;
1044         char *buffer;
1045         yaffs_Object *obj;
1046         int nWritten = 0;
1047         unsigned nBytes;
1048         loff_t i_size;
1049
1050         if (!mapping)
1051                 BUG();
1052         inode = mapping->host;
1053         if (!inode)
1054                 BUG();
1055         i_size = i_size_read(inode);
1056
1057         end_index = i_size >> PAGE_CACHE_SHIFT;
1058
1059         if(page->index < end_index)
1060                 nBytes = PAGE_CACHE_SIZE;
1061         else {
1062                 nBytes = i_size & (PAGE_CACHE_SIZE -1);
1063
1064                 if (page->index > end_index || !nBytes) {
1065                         T(YAFFS_TRACE_OS,
1066                                 (TSTR("yaffs_writepage at %08x, inode size = %08x!!!\n"),
1067                                 (unsigned)(page->index << PAGE_CACHE_SHIFT),
1068                                 (unsigned)inode->i_size));
1069                         T(YAFFS_TRACE_OS,
1070                                 (TSTR("                -> don't care!!\n")));
1071
1072                         zero_user_segment(page,0,PAGE_CACHE_SIZE);
1073                         set_page_writeback(page);
1074                         unlock_page(page);
1075                         end_page_writeback(page);
1076                         return 0;
1077                 }
1078         }
1079
1080         if(nBytes != PAGE_CACHE_SIZE)
1081                 zero_user_segment(page,nBytes,PAGE_CACHE_SIZE);
1082
1083         get_page(page);
1084
1085         buffer = kmap(page);
1086
1087         obj = yaffs_InodeToObject(inode);
1088         dev = obj->myDev;
1089         yaffs_GrossLock(dev);
1090
1091         T(YAFFS_TRACE_OS,
1092                 (TSTR("yaffs_writepage at %08x, size %08x\n"),
1093                 (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
1094         T(YAFFS_TRACE_OS,
1095                 (TSTR("writepag0: obj = %05x, ino = %05x\n"),
1096                 (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
1097
1098         nWritten = yaffs_WriteDataToFile(obj, buffer,
1099                         page->index << PAGE_CACHE_SHIFT, nBytes, 0);
1100
1101         yaffs_MarkSuperBlockDirty(dev);
1102
1103         T(YAFFS_TRACE_OS,
1104                 (TSTR("writepag1: obj = %05x, ino = %05x\n"),
1105                 (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
1106
1107         yaffs_GrossUnlock(dev);
1108
1109         kunmap(page);
1110         set_page_writeback(page);
1111         unlock_page(page);
1112         end_page_writeback(page);
1113         put_page(page);
1114
1115         return (nWritten == nBytes) ? 0 : -ENOSPC;
1116 }
1117
1118
1119 #if (YAFFS_USE_WRITE_BEGIN_END > 0)
1120 static int yaffs_write_begin(struct file *filp, struct address_space *mapping,
1121                                 loff_t pos, unsigned len, unsigned flags,
1122                                 struct page **pagep, void **fsdata)
1123 {
1124         struct page *pg = NULL;
1125         pgoff_t index = pos >> PAGE_CACHE_SHIFT;
1126
1127         int ret = 0;
1128         int space_held = 0;
1129
1130         /* Get a page */
1131 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28)
1132         pg = grab_cache_page_write_begin(mapping, index, flags);
1133 #else
1134         pg = __grab_cache_page(mapping, index);
1135 #endif
1136
1137         *pagep = pg;
1138         if (!pg) {
1139                 ret =  -ENOMEM;
1140                 goto out;
1141         }
1142         T(YAFFS_TRACE_OS,
1143                 (TSTR("start yaffs_write_begin index %d(%x) uptodate %d\n"),
1144                 (int)index,(int)index,Page_Uptodate(pg) ? 1 : 0));
1145
1146         /* Get fs space */
1147         space_held = yaffs_hold_space(filp);
1148
1149         if (!space_held) {
1150                 ret = -ENOSPC;
1151                 goto out;
1152         }
1153
1154         /* Update page if required */
1155
1156         if (!Page_Uptodate(pg))
1157                 ret = yaffs_readpage_nolock(filp, pg);
1158
1159         if (ret)
1160                 goto out;
1161
1162         /* Happy path return */
1163         T(YAFFS_TRACE_OS, (TSTR("end yaffs_write_begin - ok\n")));
1164
1165         return 0;
1166
1167 out:
1168         T(YAFFS_TRACE_OS,
1169                 (TSTR("end yaffs_write_begin fail returning %d\n"), ret));
1170         if (space_held)
1171                 yaffs_release_space(filp);
1172         if (pg) {
1173                 unlock_page(pg);
1174                 page_cache_release(pg);
1175         }
1176         return ret;
1177 }
1178
1179 #else
1180
1181 static int yaffs_prepare_write(struct file *f, struct page *pg,
1182                                 unsigned offset, unsigned to)
1183 {
1184         T(YAFFS_TRACE_OS, (TSTR("yaffs_prepair_write\n")));
1185
1186         if (!Page_Uptodate(pg))
1187                 return yaffs_readpage_nolock(f, pg);
1188         return 0;
1189 }
1190 #endif
1191
1192 #if (YAFFS_USE_WRITE_BEGIN_END > 0)
1193 static int yaffs_write_end(struct file *filp, struct address_space *mapping,
1194                                 loff_t pos, unsigned len, unsigned copied,
1195                                 struct page *pg, void *fsdadata)
1196 {
1197         int ret = 0;
1198         void *addr, *kva;
1199         uint32_t offset_into_page = pos & (PAGE_CACHE_SIZE - 1);
1200
1201         kva = kmap(pg);
1202         addr = kva + offset_into_page;
1203
1204         T(YAFFS_TRACE_OS,
1205                 ("yaffs_write_end addr %p pos %x nBytes %d\n",
1206                 addr,(unsigned)pos, copied));
1207
1208         ret = yaffs_file_write(filp, addr, copied, &pos);
1209
1210         if (ret != copied) {
1211                 T(YAFFS_TRACE_OS,
1212                         (TSTR("yaffs_write_end not same size ret %d  copied %d\n"),
1213                         ret, copied));
1214                 SetPageError(pg);
1215         } else {
1216                 /* Nothing */
1217         }
1218
1219         kunmap(pg);
1220
1221         yaffs_release_space(filp);
1222         unlock_page(pg);
1223         page_cache_release(pg);
1224         return ret;
1225 }
1226 #else
1227
1228 static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
1229                                 unsigned to)
1230 {
1231         void *addr, *kva;
1232
1233         loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
1234         int nBytes = to - offset;
1235         int nWritten;
1236
1237         unsigned spos = pos;
1238         unsigned saddr;
1239
1240         kva = kmap(pg);
1241         addr = kva + offset;
1242
1243         saddr = (unsigned) addr;
1244
1245         T(YAFFS_TRACE_OS,
1246                 (TSTR("yaffs_commit_write addr %x pos %x nBytes %d\n"),
1247                 saddr, spos, nBytes));
1248
1249         nWritten = yaffs_file_write(f, addr, nBytes, &pos);
1250
1251         if (nWritten != nBytes) {
1252                 T(YAFFS_TRACE_OS,
1253                         (TSTR("yaffs_commit_write not same size nWritten %d  nBytes %d\n"),
1254                         nWritten, nBytes));
1255                 SetPageError(pg);
1256         } else {
1257                 /* Nothing */
1258         }
1259
1260         kunmap(pg);
1261
1262         T(YAFFS_TRACE_OS,
1263                 (TSTR("yaffs_commit_write returning %d\n"),
1264                 nWritten == nBytes ? 0 : nWritten));
1265
1266         return nWritten == nBytes ? 0 : nWritten;
1267 }
1268 #endif
1269
1270
1271 static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object *obj)
1272 {
1273         if (inode && obj) {
1274
1275
1276                 /* Check mode against the variant type and attempt to repair if broken. */
1277                 __u32 mode = obj->yst_mode;
1278                 switch (obj->variantType) {
1279                 case YAFFS_OBJECT_TYPE_FILE:
1280                         if (!S_ISREG(mode)) {
1281                                 obj->yst_mode &= ~S_IFMT;
1282                                 obj->yst_mode |= S_IFREG;
1283                         }
1284
1285                         break;
1286                 case YAFFS_OBJECT_TYPE_SYMLINK:
1287                         if (!S_ISLNK(mode)) {
1288                                 obj->yst_mode &= ~S_IFMT;
1289                                 obj->yst_mode |= S_IFLNK;
1290                         }
1291
1292                         break;
1293                 case YAFFS_OBJECT_TYPE_DIRECTORY:
1294                         if (!S_ISDIR(mode)) {
1295                                 obj->yst_mode &= ~S_IFMT;
1296                                 obj->yst_mode |= S_IFDIR;
1297                         }
1298
1299                         break;
1300                 case YAFFS_OBJECT_TYPE_UNKNOWN:
1301                 case YAFFS_OBJECT_TYPE_HARDLINK:
1302                 case YAFFS_OBJECT_TYPE_SPECIAL:
1303                 default:
1304                         /* TODO? */
1305                         break;
1306                 }
1307
1308                 inode->i_flags |= S_NOATIME;
1309
1310                 inode->i_ino = obj->objectId;
1311                 inode->i_mode = obj->yst_mode;
1312                 inode->i_uid = obj->yst_uid;
1313                 inode->i_gid = obj->yst_gid;
1314 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19))
1315                 inode->i_blksize = inode->i_sb->s_blocksize;
1316 #endif
1317 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1318
1319                 inode->i_rdev = old_decode_dev(obj->yst_rdev);
1320                 inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
1321                 inode->i_atime.tv_nsec = 0;
1322                 inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
1323                 inode->i_mtime.tv_nsec = 0;
1324                 inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
1325                 inode->i_ctime.tv_nsec = 0;
1326 #else
1327                 inode->i_rdev = obj->yst_rdev;
1328                 inode->i_atime = obj->yst_atime;
1329                 inode->i_mtime = obj->yst_mtime;
1330                 inode->i_ctime = obj->yst_ctime;
1331 #endif
1332                 inode->i_size = yaffs_GetObjectFileLength(obj);
1333                 inode->i_blocks = (inode->i_size + 511) >> 9;
1334
1335                 inode->i_nlink = yaffs_GetObjectLinkCount(obj);
1336
1337                 T(YAFFS_TRACE_OS,
1338                         (TSTR("yaffs_FillInode mode %x uid %d gid %d size %d count %d\n"),
1339                         inode->i_mode, inode->i_uid, inode->i_gid,
1340                         (int)inode->i_size, atomic_read(&inode->i_count)));
1341
1342                 switch (obj->yst_mode & S_IFMT) {
1343                 default:        /* fifo, device or socket */
1344 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1345                         init_special_inode(inode, obj->yst_mode,
1346                                         old_decode_dev(obj->yst_rdev));
1347 #else
1348                         init_special_inode(inode, obj->yst_mode,
1349                                         (dev_t) (obj->yst_rdev));
1350 #endif
1351                         break;
1352                 case S_IFREG:   /* file */
1353                         inode->i_op = &yaffs_file_inode_operations;
1354                         inode->i_fop = &yaffs_file_operations;
1355                         inode->i_mapping->a_ops =
1356                                 &yaffs_file_address_operations;
1357                         break;
1358                 case S_IFDIR:   /* directory */
1359                         inode->i_op = &yaffs_dir_inode_operations;
1360                         inode->i_fop = &yaffs_dir_operations;
1361                         break;
1362                 case S_IFLNK:   /* symlink */
1363                         inode->i_op = &yaffs_symlink_inode_operations;
1364                         break;
1365                 }
1366
1367                 yaffs_InodeToObjectLV(inode) = obj;
1368
1369                 obj->myInode = inode;
1370
1371         } else {
1372                 T(YAFFS_TRACE_OS,
1373                         (TSTR("yaffs_FileInode invalid parameters\n")));
1374         }
1375
1376 }
1377
1378 struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
1379                                 yaffs_Object *obj)
1380 {
1381         struct inode *inode;
1382
1383         if (!sb) {
1384                 T(YAFFS_TRACE_OS,
1385                         (TSTR("yaffs_get_inode for NULL super_block!!\n")));
1386                 return NULL;
1387
1388         }
1389
1390         if (!obj) {
1391                 T(YAFFS_TRACE_OS,
1392                         (TSTR("yaffs_get_inode for NULL object!!\n")));
1393                 return NULL;
1394
1395         }
1396
1397         T(YAFFS_TRACE_OS,
1398                 (TSTR("yaffs_get_inode for object %d\n"), obj->objectId));
1399
1400         inode = Y_IGET(sb, obj->objectId);
1401         if (IS_ERR(inode))
1402                 return NULL;
1403
1404         /* NB Side effect: iget calls back to yaffs_read_inode(). */
1405         /* iget also increments the inode's i_count */
1406         /* NB You can't be holding grossLock or deadlock will happen! */
1407
1408         return inode;
1409 }
1410
1411 static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
1412                                 loff_t *pos)
1413 {
1414         yaffs_Object *obj;
1415         int nWritten, ipos;
1416         struct inode *inode;
1417         yaffs_Device *dev;
1418
1419         obj = yaffs_DentryToObject(f->f_dentry);
1420
1421         dev = obj->myDev;
1422
1423         yaffs_GrossLock(dev);
1424
1425         inode = f->f_dentry->d_inode;
1426
1427         if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND)
1428                 ipos = inode->i_size;
1429         else
1430                 ipos = *pos;
1431
1432         if (!obj)
1433                 T(YAFFS_TRACE_OS,
1434                         (TSTR("yaffs_file_write: hey obj is null!\n")));
1435         else
1436                 T(YAFFS_TRACE_OS,
1437                         (TSTR("yaffs_file_write about to write writing %u(%x) bytes"
1438                         "to object %d at %d(%x)\n"),
1439                         (unsigned) n, (unsigned) n, obj->objectId, ipos,ipos));
1440
1441         nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
1442
1443         yaffs_MarkSuperBlockDirty(dev);
1444
1445         T(YAFFS_TRACE_OS,
1446                 (TSTR("yaffs_file_write: %d(%x) bytes written\n"),
1447                 (unsigned )n,(unsigned)n));
1448
1449         if (nWritten > 0) {
1450                 ipos += nWritten;
1451                 *pos = ipos;
1452                 if (ipos > inode->i_size) {
1453                         inode->i_size = ipos;
1454                         inode->i_blocks = (ipos + 511) >> 9;
1455
1456                         T(YAFFS_TRACE_OS,
1457                                 (TSTR("yaffs_file_write size updated to %d bytes, "
1458                                 "%d blocks\n"),
1459                                 ipos, (int)(inode->i_blocks)));
1460                 }
1461
1462         }
1463         yaffs_GrossUnlock(dev);
1464         return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
1465 }
1466
1467 /* Space holding and freeing is done to ensure we have space available for write_begin/end */
1468 /* For now we just assume few parallel writes and check against a small number. */
1469 /* Todo: need to do this with a counter to handle parallel reads better */
1470
1471 static ssize_t yaffs_hold_space(struct file *f)
1472 {
1473         yaffs_Object *obj;
1474         yaffs_Device *dev;
1475
1476         int nFreeChunks;
1477
1478
1479         obj = yaffs_DentryToObject(f->f_dentry);
1480
1481         dev = obj->myDev;
1482
1483         yaffs_GrossLock(dev);
1484
1485         nFreeChunks = yaffs_GetNumberOfFreeChunks(dev);
1486
1487         yaffs_GrossUnlock(dev);
1488
1489         return (nFreeChunks > 20) ? 1 : 0;
1490 }
1491
1492 static void yaffs_release_space(struct file *f)
1493 {
1494         yaffs_Object *obj;
1495         yaffs_Device *dev;
1496
1497
1498         obj = yaffs_DentryToObject(f->f_dentry);
1499
1500         dev = obj->myDev;
1501
1502         yaffs_GrossLock(dev);
1503
1504
1505         yaffs_GrossUnlock(dev);
1506 }
1507
1508
1509 static loff_t yaffs_dir_llseek(struct file *file, loff_t offset, int origin)
1510 {
1511         long long retval;
1512
1513         lock_kernel();
1514
1515         switch (origin){
1516         case 2:
1517                 offset += i_size_read(file->f_path.dentry->d_inode);
1518                 break;
1519         case 1:
1520                 offset += file->f_pos;
1521         }
1522         retval = -EINVAL;
1523
1524         if (offset >= 0){
1525                 if (offset != file->f_pos)
1526                         file->f_pos = offset;
1527
1528                 retval = offset;
1529         }
1530         unlock_kernel();
1531         return retval;
1532 }
1533
1534
1535 static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
1536 {
1537         yaffs_Object *obj;
1538         yaffs_Device *dev;
1539         struct yaffs_SearchContext *sc;
1540         struct inode *inode = f->f_dentry->d_inode;
1541         unsigned long offset, curoffs;
1542         yaffs_Object *l;
1543         int retVal = 0;
1544
1545         char name[YAFFS_MAX_NAME_LENGTH + 1];
1546
1547         obj = yaffs_DentryToObject(f->f_dentry);
1548         dev = obj->myDev;
1549
1550         yaffs_GrossLock(dev);
1551
1552         yaffs_DeviceToLC(dev)->readdirProcess = current;
1553
1554         offset = f->f_pos;
1555
1556         sc = yaffs_NewSearch(obj);
1557         if(!sc){
1558                 retVal = -ENOMEM;
1559                 goto out;
1560         }
1561
1562         T(YAFFS_TRACE_OS, (TSTR("yaffs_readdir: starting at %d\n"), (int)offset));
1563
1564         if (offset == 0) {
1565                 T(YAFFS_TRACE_OS,
1566                         (TSTR("yaffs_readdir: entry . ino %d \n"),
1567                         (int)inode->i_ino));
1568                 yaffs_GrossUnlock(dev);
1569                 if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0){
1570                         yaffs_GrossLock(dev);
1571                         goto out;
1572                 }
1573                 yaffs_GrossLock(dev);
1574                 offset++;
1575                 f->f_pos++;
1576         }
1577         if (offset == 1) {
1578                 T(YAFFS_TRACE_OS,
1579                         (TSTR("yaffs_readdir: entry .. ino %d \n"),
1580                         (int)f->f_dentry->d_parent->d_inode->i_ino));
1581                 yaffs_GrossUnlock(dev);
1582                 if (filldir(dirent, "..", 2, offset,
1583                         f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0){
1584                         yaffs_GrossLock(dev);
1585                         goto out;
1586                 }
1587                 yaffs_GrossLock(dev);
1588                 offset++;
1589                 f->f_pos++;
1590         }
1591
1592         curoffs = 1;
1593
1594         /* If the directory has changed since the open or last call to
1595            readdir, rewind to after the 2 canned entries. */
1596         if (f->f_version != inode->i_version) {
1597                 offset = 2;
1598                 f->f_pos = offset;
1599                 f->f_version = inode->i_version;
1600         }
1601
1602         while(sc->nextReturn){
1603                 curoffs++;
1604                 l = sc->nextReturn;
1605                 if (curoffs >= offset) {
1606                         int this_inode = yaffs_GetObjectInode(l);
1607                         int this_type = yaffs_GetObjectType(l);
1608
1609                         yaffs_GetObjectName(l, name,
1610                                             YAFFS_MAX_NAME_LENGTH + 1);
1611                         T(YAFFS_TRACE_OS,
1612                           (TSTR("yaffs_readdir: %s inode %d\n"),
1613                           name, yaffs_GetObjectInode(l)));
1614
1615                         yaffs_GrossUnlock(dev);
1616
1617                         if (filldir(dirent,
1618                                         name,
1619                                         strlen(name),
1620                                         offset,
1621                                         this_inode,
1622                                         this_type) < 0){
1623                                 yaffs_GrossLock(dev);
1624                                 goto out;
1625                         }
1626
1627                         yaffs_GrossLock(dev);
1628
1629                         offset++;
1630                         f->f_pos++;
1631                 }
1632                 yaffs_SearchAdvance(sc);
1633         }
1634
1635 out:
1636         yaffs_EndSearch(sc);
1637         yaffs_DeviceToLC(dev)->readdirProcess = NULL;
1638         yaffs_GrossUnlock(dev);
1639
1640         return retVal;
1641 }
1642
1643
1644
1645 /*
1646  * File creation. Allocate an inode, and we're done..
1647  */
1648
1649 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
1650 #define YCRED(x) x
1651 #else
1652 #define YCRED(x) (x->cred)
1653 #endif
1654
1655 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1656 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1657                         dev_t rdev)
1658 #else
1659 static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1660                         int rdev)
1661 #endif
1662 {
1663         struct inode *inode;
1664
1665         yaffs_Object *obj = NULL;
1666         yaffs_Device *dev;
1667
1668         yaffs_Object *parent = yaffs_InodeToObject(dir);
1669
1670         int error = -ENOSPC;
1671         uid_t uid = YCRED(current)->fsuid;
1672         gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
1673
1674         if ((dir->i_mode & S_ISGID) && S_ISDIR(mode))
1675                 mode |= S_ISGID;
1676
1677         if (parent) {
1678                 T(YAFFS_TRACE_OS,
1679                         (TSTR("yaffs_mknod: parent object %d type %d\n"),
1680                         parent->objectId, parent->variantType));
1681         } else {
1682                 T(YAFFS_TRACE_OS,
1683                         (TSTR("yaffs_mknod: could not get parent object\n")));
1684                 return -EPERM;
1685         }
1686
1687         T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making oject for %s, "
1688                         "mode %x dev %x\n"),
1689                         dentry->d_name.name, mode, rdev));
1690
1691         dev = parent->myDev;
1692
1693         yaffs_GrossLock(dev);
1694
1695         switch (mode & S_IFMT) {
1696         default:
1697                 /* Special (socket, fifo, device...) */
1698                 T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making special\n")));
1699 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1700                 obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
1701                                 gid, old_encode_dev(rdev));
1702 #else
1703                 obj = yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
1704                                 gid, rdev);
1705 #endif
1706                 break;
1707         case S_IFREG:           /* file          */
1708                 T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making file\n")));
1709                 obj = yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
1710                                 gid);
1711                 break;
1712         case S_IFDIR:           /* directory */
1713                 T(YAFFS_TRACE_OS,
1714                         (TSTR("yaffs_mknod: making directory\n")));
1715                 obj = yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
1716                                         uid, gid);
1717                 break;
1718         case S_IFLNK:           /* symlink */
1719                 T(YAFFS_TRACE_OS, (TSTR("yaffs_mknod: making symlink\n")));
1720                 obj = NULL;     /* Do we ever get here? */
1721                 break;
1722         }
1723
1724         /* Can not call yaffs_get_inode() with gross lock held */
1725         yaffs_GrossUnlock(dev);
1726
1727         if (obj) {
1728                 inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
1729                 d_instantiate(dentry, inode);
1730                 update_dir_time(dir);
1731                 T(YAFFS_TRACE_OS,
1732                         (TSTR("yaffs_mknod created object %d count = %d\n"),
1733                         obj->objectId, atomic_read(&inode->i_count)));
1734                 error = 0;
1735                 yaffs_FillInodeFromObject(dir,parent);
1736         } else {
1737                 T(YAFFS_TRACE_OS,
1738                         (TSTR("yaffs_mknod failed making object\n")));
1739                 error = -ENOMEM;
1740         }
1741
1742         return error;
1743 }
1744
1745 static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1746 {
1747         int retVal;
1748         T(YAFFS_TRACE_OS, (TSTR("yaffs_mkdir\n")));
1749         retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
1750         return retVal;
1751 }
1752
1753 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
1754 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1755                         struct nameidata *n)
1756 #else
1757 static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
1758 #endif
1759 {
1760         T(YAFFS_TRACE_OS,(TSTR("yaffs_create\n")));
1761         return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
1762 }
1763
1764 static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
1765 {
1766         int retVal;
1767
1768         yaffs_Device *dev;
1769         yaffs_Object *obj;
1770
1771         T(YAFFS_TRACE_OS,
1772                 (TSTR("yaffs_unlink %d:%s\n"),
1773                 (int)(dir->i_ino),
1774                 dentry->d_name.name));
1775         obj = yaffs_InodeToObject(dir);
1776         dev = obj->myDev;
1777
1778         yaffs_GrossLock(dev);
1779
1780         retVal = yaffs_Unlink(obj, dentry->d_name.name);
1781
1782         if (retVal == YAFFS_OK) {
1783                 dentry->d_inode->i_nlink--;
1784                 dir->i_version++;
1785                 yaffs_GrossUnlock(dev);
1786                 mark_inode_dirty(dentry->d_inode);
1787                 update_dir_time(dir);
1788                 return 0;
1789         }
1790         yaffs_GrossUnlock(dev);
1791         return -ENOTEMPTY;
1792 }
1793
1794 /*
1795  * Create a link...
1796  */
1797 static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1798                         struct dentry *dentry)
1799 {
1800         struct inode *inode = old_dentry->d_inode;
1801         yaffs_Object *obj = NULL;
1802         yaffs_Object *link = NULL;
1803         yaffs_Device *dev;
1804
1805         T(YAFFS_TRACE_OS, (TSTR("yaffs_link\n")));
1806
1807         obj = yaffs_InodeToObject(inode);
1808         dev = obj->myDev;
1809
1810         yaffs_GrossLock(dev);
1811
1812         if (!S_ISDIR(inode->i_mode))            /* Don't link directories */
1813                 link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
1814                         obj);
1815
1816         if (link) {
1817                 old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
1818                 d_instantiate(dentry, old_dentry->d_inode);
1819                 atomic_inc(&old_dentry->d_inode->i_count);
1820                 T(YAFFS_TRACE_OS,
1821                         (TSTR("yaffs_link link count %d i_count %d\n"),
1822                         old_dentry->d_inode->i_nlink,
1823                         atomic_read(&old_dentry->d_inode->i_count)));
1824         }
1825
1826         yaffs_GrossUnlock(dev);
1827
1828         if (link){
1829                 update_dir_time(dir);
1830                 return 0;
1831         }
1832
1833         return -EPERM;
1834 }
1835
1836 static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1837                                 const char *symname)
1838 {
1839         yaffs_Object *obj;
1840         yaffs_Device *dev;
1841         uid_t uid = YCRED(current)->fsuid;
1842         gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : YCRED(current)->fsgid;
1843
1844         T(YAFFS_TRACE_OS, (TSTR("yaffs_symlink\n")));
1845
1846         dev = yaffs_InodeToObject(dir)->myDev;
1847         yaffs_GrossLock(dev);
1848         obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
1849                                 S_IFLNK | S_IRWXUGO, uid, gid, symname);
1850         yaffs_GrossUnlock(dev);
1851
1852         if (obj) {
1853                 struct inode *inode;
1854
1855                 inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1856                 d_instantiate(dentry, inode);
1857                 update_dir_time(dir);
1858                 T(YAFFS_TRACE_OS, (TSTR("symlink created OK\n")));
1859                 return 0;
1860         } else {
1861                 T(YAFFS_TRACE_OS, (TSTR("symlink not created\n")));
1862         }
1863
1864         return -ENOMEM;
1865 }
1866
1867 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
1868 static int yaffs_sync_object(struct file *file, int datasync)
1869 #else
1870 static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1871                                 int datasync)
1872 #endif
1873 {
1874
1875         yaffs_Object *obj;
1876         yaffs_Device *dev;
1877 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 34))
1878         struct dentry *dentry = file->f_path.dentry;
1879 #endif
1880
1881         obj = yaffs_DentryToObject(dentry);
1882
1883         dev = obj->myDev;
1884
1885         T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
1886                 (TSTR("yaffs_sync_object\n")));
1887         yaffs_GrossLock(dev);
1888         yaffs_FlushFile(obj, 1, datasync);
1889         yaffs_GrossUnlock(dev);
1890         return 0;
1891 }
1892
1893 /*
1894  * The VFS layer already does all the dentry stuff for rename.
1895  *
1896  * NB: POSIX says you can rename an object over an old object of the same name
1897  */
1898 static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1899                         struct inode *new_dir, struct dentry *new_dentry)
1900 {
1901         yaffs_Device *dev;
1902         int retVal = YAFFS_FAIL;
1903         yaffs_Object *target;
1904
1905         T(YAFFS_TRACE_OS, (TSTR("yaffs_rename\n")));
1906         dev = yaffs_InodeToObject(old_dir)->myDev;
1907
1908         yaffs_GrossLock(dev);
1909
1910         /* Check if the target is an existing directory that is not empty. */
1911         target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
1912                                 new_dentry->d_name.name);
1913
1914
1915
1916         if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
1917                 !ylist_empty(&target->variant.directoryVariant.children)) {
1918
1919                 T(YAFFS_TRACE_OS, (TSTR("target is non-empty dir\n")));
1920
1921                 retVal = YAFFS_FAIL;
1922         } else {
1923                 /* Now does unlinking internally using shadowing mechanism */
1924                 T(YAFFS_TRACE_OS, (TSTR("calling yaffs_RenameObject\n")));
1925
1926                 retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir),
1927                                 old_dentry->d_name.name,
1928                                 yaffs_InodeToObject(new_dir),
1929                                 new_dentry->d_name.name);
1930         }
1931         yaffs_GrossUnlock(dev);
1932
1933         if (retVal == YAFFS_OK) {
1934                 if (target) {
1935                         new_dentry->d_inode->i_nlink--;
1936                         mark_inode_dirty(new_dentry->d_inode);
1937                 }
1938                 
1939                 update_dir_time(old_dir);
1940                 if(old_dir != new_dir)
1941                         update_dir_time(new_dir);
1942                 return 0;
1943         } else {
1944                 return -ENOTEMPTY;
1945         }
1946 }
1947
1948 static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
1949 {
1950         struct inode *inode = dentry->d_inode;
1951         int error = 0;
1952         yaffs_Device *dev;
1953
1954         T(YAFFS_TRACE_OS,
1955                 (TSTR("yaffs_setattr of object %d\n"),
1956                 yaffs_InodeToObject(inode)->objectId));
1957
1958         /* Fail if a requested resize >= 2GB */         
1959         if (attr->ia_valid & ATTR_SIZE &&
1960                 (attr->ia_size >> 31))
1961                 error = -EINVAL;
1962
1963         if (error == 0)
1964                 error = inode_change_ok(inode, attr);
1965         if (error == 0) {
1966                 int result;
1967                 if (!error){
1968                         error = yaffs_vfs_setattr(inode, attr);
1969                         T(YAFFS_TRACE_OS,(TSTR("inode_setattr called\n")));
1970                         if (attr->ia_valid & ATTR_SIZE)
1971                                 truncate_inode_pages(&inode->i_data,attr->ia_size);
1972                 }
1973                 dev = yaffs_InodeToObject(inode)->myDev;
1974                 if (attr->ia_valid & ATTR_SIZE){
1975                         T(YAFFS_TRACE_OS,(TSTR("resize to %d(%x)\n"),
1976                                 (int)(attr->ia_size),(int)(attr->ia_size)));
1977                 }
1978                 yaffs_GrossLock(dev);
1979                 result = yaffs_SetAttributes(yaffs_InodeToObject(inode), attr);
1980                 if(result == YAFFS_OK) {
1981                         error = 0;
1982                 } else {
1983                         error = -EPERM;
1984                 }
1985                 yaffs_GrossUnlock(dev);
1986
1987         }
1988
1989         T(YAFFS_TRACE_OS,
1990                 (TSTR("yaffs_setattr done returning %d\n"),error));
1991
1992         return error;
1993 }
1994
1995 #ifdef CONFIG_YAFFS_XATTR
1996 int yaffs_setxattr(struct dentry *dentry, const char *name,
1997                         const void *value, size_t size, int flags)
1998 {
1999         struct inode *inode = dentry->d_inode;
2000         int error = 0;
2001         yaffs_Device *dev;
2002         yaffs_Object *obj = yaffs_InodeToObject(inode);
2003
2004         T(YAFFS_TRACE_OS,
2005                 (TSTR("yaffs_setxattr of object %d\n"),
2006                 obj->objectId));
2007
2008
2009         if (error == 0) {
2010                 int result;
2011                 dev = obj->myDev;
2012                 yaffs_GrossLock(dev);
2013                 result = yaffs_SetXAttribute(obj, name, value, size, flags);
2014                 if(result == YAFFS_OK)
2015                         error = 0;
2016                 else if(result < 0)
2017                         error = result;
2018                 yaffs_GrossUnlock(dev);
2019
2020         }
2021         T(YAFFS_TRACE_OS,
2022                 (TSTR("yaffs_setxattr done returning %d\n"),error));
2023
2024         return error;
2025 }
2026
2027
2028 ssize_t yaffs_getxattr(struct dentry *dentry, const char *name, void *buff,
2029                         size_t size)
2030 {
2031         struct inode *inode = dentry->d_inode;
2032         int error = 0;
2033         yaffs_Device *dev;
2034         yaffs_Object *obj = yaffs_InodeToObject(inode);
2035
2036         T(YAFFS_TRACE_OS,
2037                 (TSTR("yaffs_getxattr of object %d\n"),
2038                 obj->objectId));
2039
2040
2041         if (error == 0) {
2042                 dev = obj->myDev;
2043                 yaffs_GrossLock(dev);
2044                 error = yaffs_GetXAttribute(obj, name, buff, size);
2045                 yaffs_GrossUnlock(dev);
2046
2047         }
2048         T(YAFFS_TRACE_OS,
2049                 (TSTR("yaffs_getxattr done returning %d\n"),error));
2050
2051         return error;
2052 }
2053
2054 int yaffs_removexattr(struct dentry *dentry, const char *name)
2055 {
2056         struct inode *inode = dentry->d_inode;
2057         int error = 0;
2058         yaffs_Device *dev;
2059         yaffs_Object *obj = yaffs_InodeToObject(inode);
2060
2061         T(YAFFS_TRACE_OS,
2062                 (TSTR("yaffs_removexattr of object %d\n"),
2063                 obj->objectId));
2064
2065
2066         if (error == 0) {
2067                 int result;
2068                 dev = obj->myDev;
2069                 yaffs_GrossLock(dev);
2070                 result = yaffs_RemoveXAttribute(obj, name);
2071                 if(result == YAFFS_OK)
2072                         error = 0;
2073                 else if(result < 0)
2074                         error = result;
2075                 yaffs_GrossUnlock(dev);
2076
2077         }
2078         T(YAFFS_TRACE_OS,
2079                 (TSTR("yaffs_removexattr done returning %d\n"),error));
2080
2081         return error;
2082 }
2083
2084 ssize_t yaffs_listxattr(struct dentry *dentry, char *buff, size_t size)
2085 {
2086         struct inode *inode = dentry->d_inode;
2087         int error = 0;
2088         yaffs_Device *dev;
2089         yaffs_Object *obj = yaffs_InodeToObject(inode);
2090
2091         T(YAFFS_TRACE_OS,
2092                 (TSTR("yaffs_listxattr of object %d\n"),
2093                 obj->objectId));
2094
2095
2096         if (error == 0) {
2097                 dev = obj->myDev;
2098                 yaffs_GrossLock(dev);
2099                 error = yaffs_ListXAttributes(obj, buff, size);
2100                 yaffs_GrossUnlock(dev);
2101
2102         }
2103         T(YAFFS_TRACE_OS,
2104                 (TSTR("yaffs_listxattr done returning %d\n"),error));
2105
2106         return error;
2107 }
2108
2109 #endif
2110
2111
2112 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2113 static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
2114 {
2115         yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
2116         struct super_block *sb = dentry->d_sb;
2117 #elif (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2118 static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
2119 {
2120         yaffs_Device *dev = yaffs_SuperToDevice(sb);
2121 #else
2122 static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
2123 {
2124         yaffs_Device *dev = yaffs_SuperToDevice(sb);
2125 #endif
2126
2127         T(YAFFS_TRACE_OS, (TSTR("yaffs_statfs\n")));
2128
2129         yaffs_GrossLock(dev);
2130
2131         buf->f_type = YAFFS_MAGIC;
2132         buf->f_bsize = sb->s_blocksize;
2133         buf->f_namelen = 255;
2134
2135         if (dev->nDataBytesPerChunk & (dev->nDataBytesPerChunk - 1)) {
2136                 /* Do this if chunk size is not a power of 2 */
2137
2138                 uint64_t bytesInDev;
2139                 uint64_t bytesFree;
2140
2141                 bytesInDev = ((uint64_t)((dev->param.endBlock - dev->param.startBlock + 1))) *
2142                         ((uint64_t)(dev->param.nChunksPerBlock * dev->nDataBytesPerChunk));
2143
2144                 do_div(bytesInDev, sb->s_blocksize); /* bytesInDev becomes the number of blocks */
2145                 buf->f_blocks = bytesInDev;
2146
2147                 bytesFree  = ((uint64_t)(yaffs_GetNumberOfFreeChunks(dev))) *
2148                         ((uint64_t)(dev->nDataBytesPerChunk));
2149
2150                 do_div(bytesFree, sb->s_blocksize);
2151
2152                 buf->f_bfree = bytesFree;
2153
2154         } else if (sb->s_blocksize > dev->nDataBytesPerChunk) {
2155
2156                 buf->f_blocks =
2157                         (dev->param.endBlock - dev->param.startBlock + 1) *
2158                         dev->param.nChunksPerBlock /
2159                         (sb->s_blocksize / dev->nDataBytesPerChunk);
2160                 buf->f_bfree =
2161                         yaffs_GetNumberOfFreeChunks(dev) /
2162                         (sb->s_blocksize / dev->nDataBytesPerChunk);
2163         } else {
2164                 buf->f_blocks =
2165                         (dev->param.endBlock - dev->param.startBlock + 1) *
2166                         dev->param.nChunksPerBlock *
2167                         (dev->nDataBytesPerChunk / sb->s_blocksize);
2168
2169                 buf->f_bfree =
2170                         yaffs_GetNumberOfFreeChunks(dev) *
2171                         (dev->nDataBytesPerChunk / sb->s_blocksize);
2172         }
2173
2174         buf->f_files = 0;
2175         buf->f_ffree = 0;
2176         buf->f_bavail = buf->f_bfree;
2177
2178         yaffs_GrossUnlock(dev);
2179         return 0;
2180 }
2181
2182
2183
2184 static void yaffs_FlushInodes(struct super_block *sb)
2185 {
2186         struct inode *iptr;
2187         yaffs_Object *obj;
2188         
2189         list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){
2190                 obj = yaffs_InodeToObject(iptr);
2191                 if(obj){
2192                         T(YAFFS_TRACE_OS, (TSTR("flushing obj %d\n"),
2193                                 obj->objectId));
2194                         yaffs_FlushFile(obj,1,0);
2195                 }
2196         }
2197 }
2198
2199
2200 static void yaffs_FlushSuperBlock(struct super_block *sb, int do_checkpoint)
2201 {
2202         yaffs_Device *dev = yaffs_SuperToDevice(sb);    
2203         if(!dev)
2204                 return;
2205         
2206         yaffs_FlushInodes(sb);
2207         yaffs_UpdateDirtyDirectories(dev);
2208         yaffs_FlushEntireDeviceCache(dev);
2209         if(do_checkpoint)
2210                 yaffs_CheckpointSave(dev);
2211 }
2212
2213
2214 static unsigned yaffs_bg_gc_urgency(yaffs_Device *dev)
2215 {
2216         unsigned erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
2217         struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
2218         unsigned scatteredFree = 0; /* Free chunks not in an erased block */
2219
2220         if(erasedChunks < dev->nFreeChunks)
2221                 scatteredFree = (dev->nFreeChunks - erasedChunks);
2222
2223         if(!context->bgRunning)
2224                 return 0;
2225         else if(scatteredFree < (dev->param.nChunksPerBlock * 2))
2226                 return 0;
2227         else if(erasedChunks > dev->nFreeChunks/2)
2228                 return 0;
2229         else if(erasedChunks > dev->nFreeChunks/4)
2230                 return 1;
2231         else
2232                 return 2;
2233 }
2234
2235 static int yaffs_do_sync_fs(struct super_block *sb,
2236                                 int request_checkpoint)
2237 {
2238
2239         yaffs_Device *dev = yaffs_SuperToDevice(sb);
2240         unsigned int oneshot_checkpoint = (yaffs_auto_checkpoint & 4);
2241         unsigned gc_urgent = yaffs_bg_gc_urgency(dev);
2242         int do_checkpoint;
2243
2244         T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
2245                 (TSTR("yaffs_do_sync_fs: gc-urgency %d %s %s%s\n"),
2246                 gc_urgent,
2247                 sb->s_dirt ? "dirty" : "clean",
2248                 request_checkpoint ? "checkpoint requested" : "no checkpoint",
2249                 oneshot_checkpoint ? " one-shot" : "" ));
2250
2251         yaffs_GrossLock(dev);
2252         do_checkpoint = ((request_checkpoint && !gc_urgent) ||
2253                         oneshot_checkpoint) &&
2254                         !dev->isCheckpointed;
2255
2256         if (sb->s_dirt || do_checkpoint) {
2257                 yaffs_FlushSuperBlock(sb, !dev->isCheckpointed && do_checkpoint);
2258                 sb->s_dirt = 0;
2259                 if(oneshot_checkpoint)
2260                         yaffs_auto_checkpoint &= ~4;
2261         }
2262         yaffs_GrossUnlock(dev);
2263
2264         return 0;
2265 }
2266
2267 /*
2268  * yaffs background thread functions .
2269  * yaffs_BackgroundThread() the thread function
2270  * yaffs_BackgroundStart() launches the background thread.
2271  * yaffs_BackgroundStop() cleans up the background thread.
2272  *
2273  * NB: 
2274  * The thread should only run after the yaffs is initialised
2275  * The thread should be stopped before yaffs is unmounted.
2276  * The thread should not do any writing while the fs is in read only.
2277  */
2278
2279 #ifdef YAFFS_COMPILE_BACKGROUND
2280
2281 void yaffs_background_waker(unsigned long data)
2282 {
2283         wake_up_process((struct task_struct *)data);
2284 }
2285
2286 static int yaffs_BackgroundThread(void *data)
2287 {
2288         yaffs_Device *dev = (yaffs_Device *)data;
2289         struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
2290         unsigned long now = jiffies;
2291         unsigned long next_dir_update = now;
2292         unsigned long next_gc = now;
2293         unsigned long expires;
2294         unsigned int urgency;
2295
2296         int gcResult;
2297         struct timer_list timer;
2298
2299         T(YAFFS_TRACE_BACKGROUND,
2300                 (TSTR("yaffs_background starting for dev %p\n"),
2301                 (void *)dev));
2302
2303         set_freezable();
2304
2305         while(context->bgRunning){
2306                 T(YAFFS_TRACE_BACKGROUND,
2307                         (TSTR("yaffs_background\n")));
2308
2309                 if(kthread_should_stop())
2310                         break;
2311
2312                 if(try_to_freeze())
2313                         continue;
2314
2315                 yaffs_GrossLock(dev);
2316
2317                 now = jiffies;
2318
2319                 if(time_after(now, next_dir_update) && yaffs_bg_enable){
2320                         yaffs_UpdateDirtyDirectories(dev);
2321                         next_dir_update = now + HZ;
2322                 }
2323
2324                 if(time_after(now,next_gc) && yaffs_bg_enable){
2325                         if(!dev->isCheckpointed){
2326                                 urgency = yaffs_bg_gc_urgency(dev);
2327                                 gcResult = yaffs_BackgroundGarbageCollect(dev, urgency);
2328                                 if(urgency > 1)
2329                                         next_gc = now + HZ/20+1;
2330                                 else if(urgency > 0)
2331                                         next_gc = now + HZ/10+1;
2332                                 else
2333                                         next_gc = now + HZ * 2;
2334                         } else /*
2335                                 * gc not running so set to next_dir_update
2336                                 * to cut down on wake ups
2337                                 */
2338                                 next_gc = next_dir_update;
2339                 }
2340                 yaffs_GrossUnlock(dev);
2341 #if 1
2342                 expires = next_dir_update;
2343                 if (time_before(next_gc,expires))
2344                         expires = next_gc;
2345                 if(time_before(expires,now))
2346                         expires = now + HZ;
2347
2348                 init_timer_on_stack(&timer);
2349                 timer.expires = expires+1;
2350                 timer.data = (unsigned long) current;
2351                 timer.function = yaffs_background_waker;
2352
2353                 set_current_state(TASK_INTERRUPTIBLE);
2354                 add_timer(&timer);
2355                 schedule();
2356                 del_timer_sync(&timer);
2357 #else
2358                 msleep(10);
2359 #endif
2360         }
2361
2362         return 0;
2363 }
2364
2365 static int yaffs_BackgroundStart(yaffs_Device *dev)
2366 {
2367         int retval = 0;
2368         struct yaffs_LinuxContext *context = yaffs_DeviceToLC(dev);
2369
2370         if(dev->readOnly)
2371                 return -1;
2372
2373         context->bgRunning = 1;
2374
2375         context->bgThread = kthread_run(yaffs_BackgroundThread,
2376                                 (void *)dev,"yaffs-bg-%d",context->mount_id);
2377
2378         if(IS_ERR(context->bgThread)){
2379                 retval = PTR_ERR(context->bgThread);
2380                 context->bgThread = NULL;
2381                 context->bgRunning = 0;
2382         }
2383         return retval;
2384 }
2385
2386 static void yaffs_BackgroundStop(yaffs_Device *dev)
2387 {
2388         struct yaffs_LinuxContext *ctxt = yaffs_DeviceToLC(dev);
2389
2390         ctxt->bgRunning = 0;
2391
2392         if( ctxt->bgThread){
2393                 kthread_stop(ctxt->bgThread);
2394                 ctxt->bgThread = NULL;
2395         }
2396 }
2397 #else
2398 static int yaffs_BackgroundThread(void *data)
2399 {
2400         return 0;
2401 }
2402
2403 static int yaffs_BackgroundStart(yaffs_Device *dev)
2404 {
2405         return 0;
2406 }
2407
2408 static void yaffs_BackgroundStop(yaffs_Device *dev)
2409 {
2410 }
2411 #endif
2412
2413
2414 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2415 static void yaffs_write_super(struct super_block *sb)
2416 #else
2417 static int yaffs_write_super(struct super_block *sb)
2418 #endif
2419 {
2420         unsigned request_checkpoint = (yaffs_auto_checkpoint >= 2);
2421
2422         T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC | YAFFS_TRACE_BACKGROUND,
2423                 (TSTR("yaffs_write_super%s\n"),
2424                 request_checkpoint ? " checkpt" : ""));
2425
2426         yaffs_do_sync_fs(sb, request_checkpoint);
2427
2428 #if (LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 18))
2429         return 0;
2430 #endif
2431 }
2432
2433
2434 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2435 static int yaffs_sync_fs(struct super_block *sb, int wait)
2436 #else
2437 static int yaffs_sync_fs(struct super_block *sb)
2438 #endif
2439 {
2440         unsigned request_checkpoint = (yaffs_auto_checkpoint >= 1);
2441
2442         T(YAFFS_TRACE_OS | YAFFS_TRACE_SYNC,
2443                 (TSTR("yaffs_sync_fs%s\n"),
2444                 request_checkpoint ? " checkpt" : ""));
2445
2446         yaffs_do_sync_fs(sb, request_checkpoint);
2447
2448         return 0;
2449 }
2450
2451 #ifdef YAFFS_USE_OWN_IGET
2452
2453 static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
2454 {
2455         struct inode *inode;
2456         yaffs_Object *obj;
2457         yaffs_Device *dev = yaffs_SuperToDevice(sb);
2458
2459         T(YAFFS_TRACE_OS,
2460                 (TSTR("yaffs_iget for %lu\n"), ino));
2461
2462         inode = iget_locked(sb, ino);
2463         if (!inode)
2464                 return ERR_PTR(-ENOMEM);
2465         if (!(inode->i_state & I_NEW))
2466                 return inode;
2467
2468         /* NB This is called as a side effect of other functions, but
2469          * we had to release the lock to prevent deadlocks, so
2470          * need to lock again.
2471          */
2472
2473         yaffs_GrossLock(dev);
2474
2475         obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2476
2477         yaffs_FillInodeFromObject(inode, obj);
2478
2479         yaffs_GrossUnlock(dev);
2480
2481         unlock_new_inode(inode);
2482         return inode;
2483 }
2484
2485 #else
2486
2487 static void yaffs_read_inode(struct inode *inode)
2488 {
2489         /* NB This is called as a side effect of other functions, but
2490          * we had to release the lock to prevent deadlocks, so
2491          * need to lock again.
2492          */
2493
2494         yaffs_Object *obj;
2495         yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
2496
2497         T(YAFFS_TRACE_OS,
2498                 (TSTR("yaffs_read_inode for %d\n"), (int)inode->i_ino));
2499
2500         if(current != yaffs_DeviceToLC(dev)->readdirProcess)
2501                 yaffs_GrossLock(dev);
2502
2503         obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
2504
2505         yaffs_FillInodeFromObject(inode, obj);
2506
2507         if(current != yaffs_DeviceToLC(dev)->readdirProcess)
2508                 yaffs_GrossUnlock(dev);
2509 }
2510
2511 #endif
2512
2513 static YLIST_HEAD(yaffs_context_list);
2514 struct semaphore yaffs_context_lock;
2515
2516 static void yaffs_put_super(struct super_block *sb)
2517 {
2518         yaffs_Device *dev = yaffs_SuperToDevice(sb);
2519
2520         T(YAFFS_TRACE_OS, (TSTR("yaffs_put_super\n")));
2521
2522         T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
2523                 (TSTR("Shutting down yaffs background thread\n")));
2524         yaffs_BackgroundStop(dev);
2525         T(YAFFS_TRACE_OS | YAFFS_TRACE_BACKGROUND,
2526                 (TSTR("yaffs background thread shut down\n")));
2527
2528         yaffs_GrossLock(dev);
2529
2530         yaffs_FlushSuperBlock(sb,1);
2531
2532         if (yaffs_DeviceToLC(dev)->putSuperFunc)
2533                 yaffs_DeviceToLC(dev)->putSuperFunc(sb);
2534
2535
2536         yaffs_Deinitialise(dev);
2537
2538         yaffs_GrossUnlock(dev);
2539
2540         down(&yaffs_context_lock);
2541         ylist_del_init(&(yaffs_DeviceToLC(dev)->contextList));
2542         up(&yaffs_context_lock);
2543
2544         if (yaffs_DeviceToLC(dev)->spareBuffer) {
2545                 YFREE(yaffs_DeviceToLC(dev)->spareBuffer);
2546                 yaffs_DeviceToLC(dev)->spareBuffer = NULL;
2547         }
2548
2549         kfree(dev);
2550 }
2551
2552
2553 static void yaffs_MTDPutSuper(struct super_block *sb)
2554 {
2555         struct mtd_info *mtd = yaffs_DeviceToMtd(yaffs_SuperToDevice(sb));
2556
2557         if (mtd->sync)
2558                 mtd->sync(mtd);
2559
2560         put_mtd_device(mtd);
2561 }
2562
2563
2564 static void yaffs_MarkSuperBlockDirty(yaffs_Device *dev)
2565 {
2566         struct super_block *sb = yaffs_DeviceToLC(dev)->superBlock;
2567
2568         T(YAFFS_TRACE_OS, (TSTR("yaffs_MarkSuperBlockDirty() sb = %p\n"), sb));
2569         if (sb)
2570                 sb->s_dirt = 1;
2571 }
2572
2573 typedef struct {
2574         int inband_tags;
2575         int skip_checkpoint_read;
2576         int skip_checkpoint_write;
2577         int no_cache;
2578         int tags_ecc_on;
2579         int tags_ecc_overridden;
2580         int lazy_loading_enabled;
2581         int lazy_loading_overridden;
2582         int empty_lost_and_found;
2583         int empty_lost_and_found_overridden;
2584 } yaffs_options;
2585
2586 #define MAX_OPT_LEN 30
2587 static int yaffs_parse_options(yaffs_options *options, const char *options_str)
2588 {
2589         char cur_opt[MAX_OPT_LEN + 1];
2590         int p;
2591         int error = 0;
2592
2593         /* Parse through the options which is a comma seperated list */
2594
2595         while (options_str && *options_str && !error) {
2596                 memset(cur_opt, 0, MAX_OPT_LEN + 1);
2597                 p = 0;
2598
2599                 while(*options_str == ',')
2600                         options_str++;
2601
2602                 while (*options_str && *options_str != ',') {
2603                         if (p < MAX_OPT_LEN) {
2604                                 cur_opt[p] = *options_str;
2605                                 p++;
2606                         }
2607                         options_str++;
2608                 }
2609
2610                 if (!strcmp(cur_opt, "inband-tags"))
2611                         options->inband_tags = 1;
2612                 else if (!strcmp(cur_opt, "tags-ecc-off")){
2613                         options->tags_ecc_on = 0;
2614                         options->tags_ecc_overridden=1;
2615                 } else if (!strcmp(cur_opt, "tags-ecc-on")){
2616                         options->tags_ecc_on = 1;
2617                         options->tags_ecc_overridden = 1;
2618                 } else if (!strcmp(cur_opt, "lazy-loading-off")){
2619                         options->lazy_loading_enabled = 0;
2620                         options->lazy_loading_overridden=1;
2621                 } else if (!strcmp(cur_opt, "lazy-loading-on")){
2622                         options->lazy_loading_enabled = 1;
2623                         options->lazy_loading_overridden = 1;
2624                 } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){
2625                         options->empty_lost_and_found = 0;
2626                         options->empty_lost_and_found_overridden=1;
2627                 } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){
2628                         options->empty_lost_and_found = 1;
2629                         options->empty_lost_and_found_overridden=1;
2630                 } else if (!strcmp(cur_opt, "no-cache"))
2631                         options->no_cache = 1;
2632                 else if (!strcmp(cur_opt, "no-checkpoint-read"))
2633                         options->skip_checkpoint_read = 1;
2634                 else if (!strcmp(cur_opt, "no-checkpoint-write"))
2635                         options->skip_checkpoint_write = 1;
2636                 else if (!strcmp(cur_opt, "no-checkpoint")) {
2637                         options->skip_checkpoint_read = 1;
2638                         options->skip_checkpoint_write = 1;
2639                 } else {
2640                         printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
2641                                         cur_opt);
2642                         error = 1;
2643                 }
2644         }
2645
2646         return error;
2647 }
2648
2649 static struct super_block *yaffs_internal_read_super(int yaffsVersion,
2650                                                 struct super_block *sb,
2651                                                 void *data, int silent)
2652 {
2653         int nBlocks;
2654         struct inode *inode = NULL;
2655         struct dentry *root;
2656         yaffs_Device *dev = 0;
2657         char devname_buf[BDEVNAME_SIZE + 1];
2658         struct mtd_info *mtd;
2659         int err;
2660         char *data_str = (char *)data;
2661         struct yaffs_LinuxContext *context = NULL;
2662         yaffs_DeviceParam *param;
2663
2664         int readOnly = 0;
2665
2666         yaffs_options options;
2667
2668         unsigned mount_id;
2669         int found;
2670         struct yaffs_LinuxContext *context_iterator;
2671         struct ylist_head *l;
2672
2673         sb->s_magic = YAFFS_MAGIC;
2674         sb->s_op = &yaffs_super_ops;
2675         sb->s_flags |= MS_NOATIME;
2676
2677         readOnly =((sb->s_flags & MS_RDONLY) != 0);
2678
2679
2680 #ifdef YAFFS_COMPILE_EXPORTFS
2681         sb->s_export_op = &yaffs_export_ops;
2682 #endif
2683
2684         if (!sb)
2685                 printk(KERN_INFO "yaffs: sb is NULL\n");
2686         else if (!sb->s_dev)
2687                 printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
2688         else if (!yaffs_devname(sb, devname_buf))
2689                 printk(KERN_INFO "yaffs: devname is NULL\n");
2690         else
2691                 printk(KERN_INFO "yaffs: dev is %d name is \"%s\" %s\n",
2692                        sb->s_dev,
2693                        yaffs_devname(sb, devname_buf),
2694                        readOnly ? "ro" : "rw");
2695
2696         if (!data_str)
2697                 data_str = "";
2698
2699         printk(KERN_INFO "yaffs: passed flags \"%s\"\n", data_str);
2700
2701         memset(&options, 0, sizeof(options));
2702
2703         if (yaffs_parse_options(&options, data_str)) {
2704                 /* Option parsing failed */
2705                 return NULL;
2706         }
2707
2708
2709         sb->s_blocksize = PAGE_CACHE_SIZE;
2710         sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
2711
2712         T(YAFFS_TRACE_OS,
2713                 (TSTR("yaffs_read_super: Using yaffs%d\n"), yaffsVersion));
2714         T(YAFFS_TRACE_OS,
2715                 (TSTR("yaffs_read_super: block size %d\n"),
2716                 (int)(sb->s_blocksize)));
2717
2718         T(YAFFS_TRACE_ALWAYS,
2719                 (TSTR("yaffs: Attempting MTD mount of %u.%u,\"%s\"\n"),
2720                MAJOR(sb->s_dev), MINOR(sb->s_dev),
2721                yaffs_devname(sb, devname_buf)));
2722
2723         /* Check it's an mtd device..... */
2724         if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR)
2725                 return NULL;    /* This isn't an mtd device */
2726
2727         /* Get the device */
2728         mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
2729         if (!mtd) {
2730                 T(YAFFS_TRACE_ALWAYS,
2731                         (TSTR("yaffs: MTD device #%u doesn't appear to exist\n"),
2732                         MINOR(sb->s_dev)));
2733                 return NULL;
2734         }
2735         /* Check it's NAND */
2736         if (mtd->type != MTD_NANDFLASH) {
2737                 T(YAFFS_TRACE_ALWAYS,
2738                         (TSTR("yaffs: MTD device is not NAND it's type %d\n"),
2739                         mtd->type));
2740                 return NULL;
2741         }
2742
2743         T(YAFFS_TRACE_OS, (TSTR(" erase %p\n"), mtd->erase));
2744         T(YAFFS_TRACE_OS, (TSTR(" read %p\n"), mtd->read));
2745         T(YAFFS_TRACE_OS, (TSTR(" write %p\n"), mtd->write));
2746         T(YAFFS_TRACE_OS, (TSTR(" readoob %p\n"), mtd->read_oob));
2747         T(YAFFS_TRACE_OS, (TSTR(" writeoob %p\n"), mtd->write_oob));
2748         T(YAFFS_TRACE_OS, (TSTR(" block_isbad %p\n"), mtd->block_isbad));
2749         T(YAFFS_TRACE_OS, (TSTR(" block_markbad %p\n"), mtd->block_markbad));
2750         T(YAFFS_TRACE_OS, (TSTR(" %s %d\n"), WRITE_SIZE_STR, WRITE_SIZE(mtd)));
2751         T(YAFFS_TRACE_OS, (TSTR(" oobsize %d\n"), mtd->oobsize));
2752         T(YAFFS_TRACE_OS, (TSTR(" erasesize %d\n"), mtd->erasesize));
2753 #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
2754         T(YAFFS_TRACE_OS, (TSTR(" size %u\n"), mtd->size));
2755 #else
2756         T(YAFFS_TRACE_OS, (TSTR(" size %lld\n"), mtd->size));
2757 #endif
2758
2759 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
2760
2761         if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
2762                 T(YAFFS_TRACE_ALWAYS,
2763                         (TSTR("yaffs: auto selecting yaffs2\n")));
2764                 yaffsVersion = 2;
2765         }
2766
2767         /* Added NCB 26/5/2006 for completeness */
2768         if (yaffsVersion == 2 && !options.inband_tags && WRITE_SIZE(mtd) == 512) {
2769                 T(YAFFS_TRACE_ALWAYS,
2770                         (TSTR("yaffs: auto selecting yaffs1\n")));
2771                 yaffsVersion = 1;
2772         }
2773
2774 #endif
2775
2776         if (yaffsVersion == 2) {
2777                 /* Check for version 2 style functions */
2778                 if (!mtd->erase ||
2779                     !mtd->block_isbad ||
2780                     !mtd->block_markbad ||
2781                     !mtd->read ||
2782                     !mtd->write ||
2783 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2784                     !mtd->read_oob || !mtd->write_oob) {
2785 #else
2786                     !mtd->write_ecc ||
2787                     !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
2788 #endif
2789                         T(YAFFS_TRACE_ALWAYS,
2790                           (TSTR("yaffs: MTD device does not support required "
2791                            "functions\n")));
2792                         return NULL;
2793                 }
2794
2795                 if ((WRITE_SIZE(mtd) < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
2796                     mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) &&
2797                     !options.inband_tags) {
2798                         T(YAFFS_TRACE_ALWAYS,
2799                           (TSTR("yaffs: MTD device does not have the "
2800                            "right page sizes\n")));
2801                         return NULL;
2802                 }
2803         } else {
2804                 /* Check for V1 style functions */
2805                 if (!mtd->erase ||
2806                     !mtd->read ||
2807                     !mtd->write ||
2808 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2809                     !mtd->read_oob || !mtd->write_oob) {
2810 #else
2811                     !mtd->write_ecc ||
2812                     !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
2813 #endif
2814                         T(YAFFS_TRACE_ALWAYS,
2815                           (TSTR("yaffs: MTD device does not support required "
2816                            "functions\n")));
2817                         return NULL;
2818                 }
2819
2820                 if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
2821                     mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
2822                         T(YAFFS_TRACE_ALWAYS,
2823                           (TSTR("yaffs: MTD device does not support have the "
2824                            "right page sizes\n")));
2825                         return NULL;
2826                 }
2827         }
2828
2829         /* OK, so if we got here, we have an MTD that's NAND and looks
2830          * like it has the right capabilities
2831          * Set the yaffs_Device up for mtd
2832          */
2833
2834         if (!readOnly && !(mtd->flags & MTD_WRITEABLE)){
2835                 readOnly = 1;
2836                 printk(KERN_INFO "yaffs: mtd is read only, setting superblock read only");
2837                 sb->s_flags |= MS_RDONLY;
2838         }
2839
2840         dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
2841         context = kmalloc(sizeof(struct yaffs_LinuxContext),GFP_KERNEL);
2842         
2843         if(!dev || !context ){
2844                 if(dev)
2845                         kfree(dev);
2846                 if(context)
2847                         kfree(context);
2848                 dev = NULL;
2849                 context = NULL;
2850         }
2851
2852         if (!dev) {
2853                 /* Deep shit could not allocate device structure */
2854                 T(YAFFS_TRACE_ALWAYS,
2855                   (TSTR("yaffs_read_super: Failed trying to allocate "
2856                    "yaffs_Device. \n")));
2857                 return NULL;
2858         }
2859         memset(dev, 0, sizeof(yaffs_Device));
2860         param = &(dev->param);
2861
2862         memset(context,0,sizeof(struct yaffs_LinuxContext));
2863         dev->osContext = context;
2864         YINIT_LIST_HEAD(&(context->contextList));
2865         context->dev = dev;
2866         context->superBlock = sb;
2867
2868         dev->readOnly = readOnly;
2869
2870 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
2871         sb->s_fs_info = dev;
2872 #else
2873         sb->u.generic_sbp = dev;
2874 #endif
2875         
2876         dev->driverContext = mtd;
2877         param->name = mtd->name;
2878
2879         /* Set up the memory size parameters.... */
2880
2881         nBlocks = YCALCBLOCKS(mtd->size, (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK));
2882
2883         param->startBlock = 0;
2884         param->endBlock = nBlocks - 1;
2885         param->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
2886         param->totalBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
2887         param->nReservedBlocks = 5;
2888         param->nShortOpCaches = (options.no_cache) ? 0 : 10;
2889         param->inbandTags = options.inband_tags;
2890
2891 #ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD
2892         param->disableLazyLoad = 1;
2893 #endif
2894 #ifdef CONFIG_YAFFS_XATTR
2895         param->enableXattr = 1;
2896 #endif
2897         if(options.lazy_loading_overridden)
2898                 param->disableLazyLoad = !options.lazy_loading_enabled;
2899
2900 #ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC
2901         param->noTagsECC = 1;
2902 #endif
2903
2904 #ifdef CONFIG_YAFFS_DISABLE_BACKGROUND
2905 #else
2906         param->deferDirectoryUpdate = 1;
2907 #endif
2908
2909         if(options.tags_ecc_overridden)
2910                 param->noTagsECC = !options.tags_ecc_on;
2911
2912 #ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
2913         param->emptyLostAndFound = 1;
2914 #endif
2915
2916 #ifdef CONFIG_YAFFS_DISABLE_BLOCK_REFRESHING
2917         param->refreshPeriod = 0;
2918 #else
2919         param->refreshPeriod = 500;
2920 #endif
2921
2922         if(options.empty_lost_and_found_overridden)
2923                 param->emptyLostAndFound = options.empty_lost_and_found;
2924
2925         /* ... and the functions. */
2926         if (yaffsVersion == 2) {
2927                 param->writeChunkWithTagsToNAND =
2928                     nandmtd2_WriteChunkWithTagsToNAND;
2929                 param->readChunkWithTagsFromNAND =
2930                     nandmtd2_ReadChunkWithTagsFromNAND;
2931                 param->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
2932                 param->queryNANDBlock = nandmtd2_QueryNANDBlock;
2933                 yaffs_DeviceToLC(dev)->spareBuffer = YMALLOC(mtd->oobsize);
2934                 param->isYaffs2 = 1;
2935 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2936                 param->totalBytesPerChunk = mtd->writesize;
2937                 param->nChunksPerBlock = mtd->erasesize / mtd->writesize;
2938 #else
2939                 param->totalBytesPerChunk = mtd->oobblock;
2940                 param->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
2941 #endif
2942                 nBlocks = YCALCBLOCKS(mtd->size, mtd->erasesize);
2943
2944                 param->startBlock = 0;
2945                 param->endBlock = nBlocks - 1;
2946         } else {
2947 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
2948                 /* use the MTD interface in yaffs_mtdif1.c */
2949                 param->writeChunkWithTagsToNAND =
2950                         nandmtd1_WriteChunkWithTagsToNAND;
2951                 param->readChunkWithTagsFromNAND =
2952                         nandmtd1_ReadChunkWithTagsFromNAND;
2953                 param->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
2954                 param->queryNANDBlock = nandmtd1_QueryNANDBlock;
2955 #else
2956                 param->writeChunkToNAND = nandmtd_WriteChunkToNAND;
2957                 param->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
2958 #endif
2959                 param->isYaffs2 = 0;
2960         }
2961         /* ... and common functions */
2962         param->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
2963         param->initialiseNAND = nandmtd_InitialiseNAND;
2964
2965         yaffs_DeviceToLC(dev)->putSuperFunc = yaffs_MTDPutSuper;
2966
2967         param->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
2968         param->gcControl = yaffs_gc_control_callback;
2969
2970         yaffs_DeviceToLC(dev)->superBlock= sb;
2971         
2972
2973 #ifndef CONFIG_YAFFS_DOES_ECC
2974         param->useNANDECC = 1;
2975 #endif
2976
2977 #ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
2978         param->wideTnodesDisabled = 1;
2979 #endif
2980
2981         param->skipCheckpointRead = options.skip_checkpoint_read;
2982         param->skipCheckpointWrite = options.skip_checkpoint_write;
2983
2984         down(&yaffs_context_lock);
2985         /* Get a mount id */
2986         found = 0;
2987         for(mount_id=0; ! found; mount_id++){
2988                 found = 1;
2989                 ylist_for_each(l,&yaffs_context_list){
2990                         context_iterator = ylist_entry(l,struct yaffs_LinuxContext,contextList);
2991                         if(context_iterator->mount_id == mount_id)
2992                                 found = 0;
2993                 }
2994         }
2995         context->mount_id = mount_id;
2996
2997         ylist_add_tail(&(yaffs_DeviceToLC(dev)->contextList), &yaffs_context_list);
2998         up(&yaffs_context_lock);
2999
3000         /* Directory search handling...*/
3001         YINIT_LIST_HEAD(&(yaffs_DeviceToLC(dev)->searchContexts));
3002         param->removeObjectCallback = yaffs_RemoveObjectCallback;
3003
3004         init_MUTEX(&(yaffs_DeviceToLC(dev)->grossLock));
3005
3006         yaffs_GrossLock(dev);
3007
3008         err = yaffs_GutsInitialise(dev);
3009
3010         T(YAFFS_TRACE_OS,
3011           (TSTR("yaffs_read_super: guts initialised %s\n"),
3012            (err == YAFFS_OK) ? "OK" : "FAILED"));
3013            
3014         if(err == YAFFS_OK)
3015                 yaffs_BackgroundStart(dev);
3016                 
3017         if(!context->bgThread)
3018                 param->deferDirectoryUpdate = 0;
3019
3020
3021         /* Release lock before yaffs_get_inode() */
3022         yaffs_GrossUnlock(dev);
3023
3024         /* Create root inode */
3025         if (err == YAFFS_OK)
3026                 inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
3027                                         yaffs_Root(dev));
3028
3029         if (!inode)
3030                 return NULL;
3031
3032         inode->i_op = &yaffs_dir_inode_operations;
3033         inode->i_fop = &yaffs_dir_operations;
3034
3035         T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: got root inode\n")));
3036
3037         root = d_alloc_root(inode);
3038
3039         T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: d_alloc_root done\n")));
3040
3041         if (!root) {
3042                 iput(inode);
3043                 return NULL;
3044         }
3045         sb->s_root = root;
3046         sb->s_dirt = !dev->isCheckpointed;
3047         T(YAFFS_TRACE_ALWAYS,
3048                 (TSTR("yaffs_read_super: isCheckpointed %d\n"),
3049                 dev->isCheckpointed));
3050
3051         T(YAFFS_TRACE_OS, (TSTR("yaffs_read_super: done\n")));
3052         return sb;
3053 }
3054
3055
3056 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3057 static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
3058                                          int silent)
3059 {
3060         return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
3061 }
3062
3063 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3064 static int yaffs_read_super(struct file_system_type *fs,
3065                             int flags, const char *dev_name,
3066                             void *data, struct vfsmount *mnt)
3067 {
3068
3069         return get_sb_bdev(fs, flags, dev_name, data,
3070                            yaffs_internal_read_super_mtd, mnt);
3071 }
3072 #else
3073 static struct super_block *yaffs_read_super(struct file_system_type *fs,
3074                                             int flags, const char *dev_name,
3075                                             void *data)
3076 {
3077
3078         return get_sb_bdev(fs, flags, dev_name, data,
3079                            yaffs_internal_read_super_mtd);
3080 }
3081 #endif
3082
3083 static struct file_system_type yaffs_fs_type = {
3084         .owner = THIS_MODULE,
3085         .name = "yaffs",
3086         .get_sb = yaffs_read_super,
3087         .kill_sb = kill_block_super,
3088         .fs_flags = FS_REQUIRES_DEV,
3089 };
3090 #else
3091 static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
3092                                             int silent)
3093 {
3094         return yaffs_internal_read_super(1, sb, data, silent);
3095 }
3096
3097 static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
3098                       FS_REQUIRES_DEV);
3099 #endif
3100
3101
3102 #ifdef CONFIG_YAFFS_YAFFS2
3103
3104 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 5, 0))
3105 static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
3106                                           int silent)
3107 {
3108         return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
3109 }
3110
3111 #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 17))
3112 static int yaffs2_read_super(struct file_system_type *fs,
3113                         int flags, const char *dev_name, void *data,
3114                         struct vfsmount *mnt)
3115 {
3116         return get_sb_bdev(fs, flags, dev_name, data,
3117                         yaffs2_internal_read_super_mtd, mnt);
3118 }
3119 #else
3120 static struct super_block *yaffs2_read_super(struct file_system_type *fs,
3121                                              int flags, const char *dev_name,
3122                                              void *data)
3123 {
3124
3125         return get_sb_bdev(fs, flags, dev_name, data,
3126                            yaffs2_internal_read_super_mtd);
3127 }
3128 #endif
3129
3130 static struct file_system_type yaffs2_fs_type = {
3131         .owner = THIS_MODULE,
3132         .name = "yaffs2",
3133         .get_sb = yaffs2_read_super,
3134         .kill_sb = kill_block_super,
3135         .fs_flags = FS_REQUIRES_DEV,
3136 };
3137 #else
3138 static struct super_block *yaffs2_read_super(struct super_block *sb,
3139                                              void *data, int silent)
3140 {
3141         return yaffs_internal_read_super(2, sb, data, silent);
3142 }
3143
3144 static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
3145                       FS_REQUIRES_DEV);
3146 #endif
3147
3148 #endif                          /* CONFIG_YAFFS_YAFFS2 */
3149
3150 static struct proc_dir_entry *my_proc_entry;
3151 static struct proc_dir_entry *debug_proc_entry;
3152
3153 static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev)
3154 {
3155         buf += sprintf(buf, "startBlock......... %d\n", dev->param.startBlock);
3156         buf += sprintf(buf, "endBlock........... %d\n", dev->param.endBlock);
3157         buf += sprintf(buf, "totalBytesPerChunk. %d\n", dev->param.totalBytesPerChunk);
3158         buf += sprintf(buf, "useNANDECC......... %d\n", dev->param.useNANDECC);
3159         buf += sprintf(buf, "noTagsECC.......... %d\n", dev->param.noTagsECC);
3160         buf += sprintf(buf, "isYaffs2........... %d\n", dev->param.isYaffs2);
3161         buf += sprintf(buf, "inbandTags......... %d\n", dev->param.inbandTags);
3162         buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->param.emptyLostAndFound);
3163         buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->param.disableLazyLoad);
3164         buf += sprintf(buf, "refreshPeriod...... %d\n", dev->param.refreshPeriod);
3165         buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->param.nShortOpCaches);
3166         buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->param.nReservedBlocks);
3167
3168         buf += sprintf(buf, "\n");
3169
3170         return buf;
3171 }
3172
3173
3174 static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev)
3175 {
3176         buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
3177         buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
3178         buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
3179         buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
3180         buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
3181         buf += sprintf(buf, "\n");
3182         buf += sprintf(buf, "nTnodes............ %d\n", dev->nTnodes);
3183         buf += sprintf(buf, "nObjects........... %d\n", dev->nObjects);
3184         buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
3185         buf += sprintf(buf, "\n");
3186         buf += sprintf(buf, "nPageWrites........ %u\n", dev->nPageWrites);
3187         buf += sprintf(buf, "nPageReads......... %u\n", dev->nPageReads);
3188         buf += sprintf(buf, "nBlockErasures..... %u\n", dev->nBlockErasures);
3189         buf += sprintf(buf, "nGCCopies.......... %u\n", dev->nGCCopies);
3190         buf += sprintf(buf, "allGCs............. %u\n", dev->allGCs);
3191         buf += sprintf(buf, "passiveGCs......... %u\n", dev->passiveGCs);
3192         buf += sprintf(buf, "oldestDirtyGCs..... %u\n", dev->oldestDirtyGCs);
3193         buf += sprintf(buf, "nGCBlocks.......... %u\n", dev->nGCBlocks);
3194         buf += sprintf(buf, "backgroundGCs...... %u\n", dev->backgroundGCs);
3195         buf += sprintf(buf, "nRetriedWrites..... %u\n", dev->nRetriedWrites);
3196         buf += sprintf(buf, "nRetireBlocks...... %u\n", dev->nRetiredBlocks);
3197         buf += sprintf(buf, "eccFixed........... %u\n", dev->eccFixed);
3198         buf += sprintf(buf, "eccUnfixed......... %u\n", dev->eccUnfixed);
3199         buf += sprintf(buf, "tagsEccFixed....... %u\n", dev->tagsEccFixed);
3200         buf += sprintf(buf, "tagsEccUnfixed..... %u\n", dev->tagsEccUnfixed);
3201         buf += sprintf(buf, "cacheHits.......... %u\n", dev->cacheHits);
3202         buf += sprintf(buf, "nDeletedFiles...... %u\n", dev->nDeletedFiles);
3203         buf += sprintf(buf, "nUnlinkedFiles..... %u\n", dev->nUnlinkedFiles);
3204         buf += sprintf(buf, "refreshCount....... %u\n", dev->refreshCount);
3205         buf +=
3206             sprintf(buf, "nBackgroudDeletions %u\n", dev->nBackgroundDeletions);
3207
3208         return buf;
3209 }
3210
3211 static int yaffs_proc_read(char *page,
3212                            char **start,
3213                            off_t offset, int count, int *eof, void *data)
3214 {
3215         struct ylist_head *item;
3216         char *buf = page;
3217         int step = offset;
3218         int n = 0;
3219
3220         /* Get proc_file_read() to step 'offset' by one on each sucessive call.
3221          * We use 'offset' (*ppos) to indicate where we are in devList.
3222          * This also assumes the user has posted a read buffer large
3223          * enough to hold the complete output; but that's life in /proc.
3224          */
3225
3226         *(int *)start = 1;
3227
3228         /* Print header first */
3229         if (step == 0)
3230                 buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__"\n");
3231         else if (step == 1)
3232                 buf += sprintf(buf,"\n");
3233         else {
3234                 step-=2;
3235                 
3236                 down(&yaffs_context_lock);
3237
3238                 /* Locate and print the Nth entry.  Order N-squared but N is small. */
3239                 ylist_for_each(item, &yaffs_context_list) {
3240                         struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
3241                         yaffs_Device *dev = dc->dev;
3242
3243                         if (n < (step & ~1)) {
3244                                 n+=2;
3245                                 continue;
3246                         }
3247                         if((step & 1)==0){
3248                                 buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->param.name);
3249                                 buf = yaffs_dump_dev_part0(buf, dev);
3250                         } else
3251                                 buf = yaffs_dump_dev_part1(buf, dev);
3252                         
3253                         break;
3254                 }
3255                 up(&yaffs_context_lock);
3256         }
3257
3258         return buf - page < count ? buf - page : count;
3259 }
3260
3261 static int yaffs_stats_proc_read(char *page,
3262                                 char **start,
3263                                 off_t offset, int count, int *eof, void *data)
3264 {
3265         struct ylist_head *item;
3266         char *buf = page;
3267         int n = 0;
3268
3269         down(&yaffs_context_lock);
3270
3271         /* Locate and print the Nth entry.  Order N-squared but N is small. */
3272         ylist_for_each(item, &yaffs_context_list) {
3273                 struct yaffs_LinuxContext *dc = ylist_entry(item, struct yaffs_LinuxContext, contextList);
3274                 yaffs_Device *dev = dc->dev;
3275
3276                 int erasedChunks;
3277
3278                 erasedChunks = dev->nErasedBlocks * dev->param.nChunksPerBlock;
3279                 
3280                 buf += sprintf(buf,"%d, %d, %d, %u, %u, %u, %u\n",
3281                                 n, dev->nFreeChunks, erasedChunks,
3282                                 dev->backgroundGCs, dev->oldestDirtyGCs,
3283                                 dev->nObjects, dev->nTnodes);
3284         }
3285         up(&yaffs_context_lock);
3286
3287
3288         return buf - page < count ? buf - page : count;
3289 }
3290
3291 /**
3292  * Set the verbosity of the warnings and error messages.
3293  *
3294  * Note that the names can only be a..z or _ with the current code.
3295  */
3296
3297 static struct {
3298         char *mask_name;
3299         unsigned mask_bitfield;
3300 } mask_flags[] = {
3301         {"allocate", YAFFS_TRACE_ALLOCATE},
3302         {"always", YAFFS_TRACE_ALWAYS},
3303         {"background", YAFFS_TRACE_BACKGROUND},
3304         {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
3305         {"buffers", YAFFS_TRACE_BUFFERS},
3306         {"bug", YAFFS_TRACE_BUG},
3307         {"checkpt", YAFFS_TRACE_CHECKPOINT},
3308         {"deletion", YAFFS_TRACE_DELETION},
3309         {"erase", YAFFS_TRACE_ERASE},
3310         {"error", YAFFS_TRACE_ERROR},
3311         {"gc_detail", YAFFS_TRACE_GC_DETAIL},
3312         {"gc", YAFFS_TRACE_GC},
3313         {"lock", YAFFS_TRACE_LOCK},
3314         {"mtd", YAFFS_TRACE_MTD},
3315         {"nandaccess", YAFFS_TRACE_NANDACCESS},
3316         {"os", YAFFS_TRACE_OS},
3317         {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
3318         {"scan", YAFFS_TRACE_SCAN},
3319         {"tracing", YAFFS_TRACE_TRACING},
3320         {"sync", YAFFS_TRACE_SYNC},
3321         {"write", YAFFS_TRACE_WRITE},
3322
3323         {"verify", YAFFS_TRACE_VERIFY},
3324         {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
3325         {"verify_full", YAFFS_TRACE_VERIFY_FULL},
3326         {"verify_all", YAFFS_TRACE_VERIFY_ALL},
3327
3328         {"all", 0xffffffff},
3329         {"none", 0},
3330         {NULL, 0},
3331 };
3332
3333 #define MAX_MASK_NAME_LENGTH 40
3334 static int yaffs_proc_write_trace_options(struct file *file, const char *buf,
3335                                          unsigned long count, void *data)
3336 {
3337         unsigned rg = 0, mask_bitfield;
3338         char *end;
3339         char *mask_name;
3340         const char *x;
3341         char substring[MAX_MASK_NAME_LENGTH + 1];
3342         int i;
3343         int done = 0;
3344         int add, len = 0;
3345         int pos = 0;
3346
3347         rg = yaffs_traceMask;
3348
3349         while (!done && (pos < count)) {
3350                 done = 1;
3351                 while ((pos < count) && isspace(buf[pos]))
3352                         pos++;
3353
3354                 switch (buf[pos]) {
3355                 case '+':
3356                 case '-':
3357                 case '=':
3358                         add = buf[pos];
3359                         pos++;
3360                         break;
3361
3362                 default:
3363                         add = ' ';
3364                         break;
3365                 }
3366                 mask_name = NULL;
3367
3368                 mask_bitfield = simple_strtoul(buf + pos, &end, 0);
3369
3370                 if (end > buf + pos) {
3371                         mask_name = "numeral";
3372                         len = end - (buf + pos);
3373                         pos += len;
3374                         done = 0;
3375                 } else {
3376                         for (x = buf + pos, i = 0;
3377                             (*x == '_' || (*x >= 'a' && *x <= 'z')) &&
3378                             i < MAX_MASK_NAME_LENGTH; x++, i++, pos++)
3379                                 substring[i] = *x;
3380                         substring[i] = '\0';
3381
3382                         for (i = 0; mask_flags[i].mask_name != NULL; i++) {
3383                                 if (strcmp(substring, mask_flags[i].mask_name) == 0) {
3384                                         mask_name = mask_flags[i].mask_name;
3385                                         mask_bitfield = mask_flags[i].mask_bitfield;
3386                                         done = 0;
3387                                         break;
3388                                 }
3389                         }
3390                 }
3391
3392                 if (mask_name != NULL) {
3393                         done = 0;
3394                         switch (add) {
3395                         case '-':
3396                                 rg &= ~mask_bitfield;
3397                                 break;
3398                         case '+':
3399                                 rg |= mask_bitfield;
3400                                 break;
3401                         case '=':
3402                                 rg = mask_bitfield;
3403                                 break;
3404                         default:
3405                                 rg |= mask_bitfield;
3406                                 break;
3407                         }
3408                 }
3409         }
3410
3411         yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
3412
3413         printk(KERN_DEBUG "new trace = 0x%08X\n", yaffs_traceMask);
3414
3415         if (rg & YAFFS_TRACE_ALWAYS) {
3416                 for (i = 0; mask_flags[i].mask_name != NULL; i++) {
3417                         char flag;
3418                         flag = ((rg & mask_flags[i].mask_bitfield) ==
3419                                 mask_flags[i].mask_bitfield) ? '+' : '-';
3420                         printk(KERN_DEBUG "%c%s\n", flag, mask_flags[i].mask_name);
3421                 }
3422         }
3423
3424         return count;
3425 }
3426
3427
3428 static int yaffs_proc_write(struct file *file, const char *buf,
3429                                          unsigned long count, void *data)
3430 {
3431         return yaffs_proc_write_trace_options(file, buf, count, data);
3432 }
3433
3434 /* Stuff to handle installation of file systems */
3435 struct file_system_to_install {
3436         struct file_system_type *fst;
3437         int installed;
3438 };
3439
3440 static struct file_system_to_install fs_to_install[] = {
3441         {&yaffs_fs_type, 0},
3442         {&yaffs2_fs_type, 0},
3443         {NULL, 0}
3444 };
3445
3446 static int __init init_yaffs_fs(void)
3447 {
3448         int error = 0;
3449         struct file_system_to_install *fsinst;
3450
3451         T(YAFFS_TRACE_ALWAYS,
3452           (TSTR("yaffs built " __DATE__ " " __TIME__ " Installing. \n")));
3453
3454 #ifdef CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED
3455         T(YAFFS_TRACE_ALWAYS,
3456           (TSTR(" \n\n\n\nYAFFS-WARNING CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED selected.\n\n\n\n")));
3457 #endif
3458
3459
3460
3461
3462         init_MUTEX(&yaffs_context_lock);
3463
3464         /* Install the proc_fs entries */
3465         my_proc_entry = create_proc_entry("yaffs",
3466                                                S_IRUGO | S_IFREG,
3467                                                YPROC_ROOT);
3468
3469         if (my_proc_entry) {
3470                 my_proc_entry->write_proc = yaffs_proc_write;
3471                 my_proc_entry->read_proc = yaffs_proc_read;
3472                 my_proc_entry->data = NULL;
3473         } else
3474                 return -ENOMEM;
3475
3476         debug_proc_entry = create_proc_entry("yaffs_stats",
3477                                                S_IRUGO | S_IFREG,
3478                                                YPROC_ROOT);
3479
3480         if (debug_proc_entry) {
3481                 debug_proc_entry->write_proc = NULL;
3482                 debug_proc_entry->read_proc = yaffs_stats_proc_read;
3483                 debug_proc_entry->data = NULL;
3484         } else
3485                 return -ENOMEM;
3486
3487         /* Now add the file system entries */
3488
3489         fsinst = fs_to_install;
3490
3491         while (fsinst->fst && !error) {
3492                 error = register_filesystem(fsinst->fst);
3493                 if (!error)
3494                         fsinst->installed = 1;
3495                 fsinst++;
3496         }
3497
3498         /* Any errors? uninstall  */
3499         if (error) {
3500                 fsinst = fs_to_install;
3501
3502                 while (fsinst->fst) {
3503                         if (fsinst->installed) {
3504                                 unregister_filesystem(fsinst->fst);
3505                                 fsinst->installed = 0;
3506                         }
3507                         fsinst++;
3508                 }
3509         }
3510
3511         return error;
3512 }
3513
3514 static void __exit exit_yaffs_fs(void)
3515 {
3516
3517         struct file_system_to_install *fsinst;
3518
3519         T(YAFFS_TRACE_ALWAYS,
3520                 (TSTR("yaffs built " __DATE__ " " __TIME__ " removing. \n")));
3521
3522         remove_proc_entry("yaffs", YPROC_ROOT);
3523         remove_proc_entry("yaffs_stats", YPROC_ROOT);
3524
3525         fsinst = fs_to_install;
3526
3527         while (fsinst->fst) {
3528                 if (fsinst->installed) {
3529                         unregister_filesystem(fsinst->fst);
3530                         fsinst->installed = 0;
3531                 }
3532                 fsinst++;
3533         }
3534 }
3535
3536 module_init(init_yaffs_fs)
3537 module_exit(exit_yaffs_fs)
3538
3539 MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
3540 MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2010");
3541 MODULE_LICENSE("GPL");