Root/target/linux/generic/files/fs/yaffs2/yaffs_fs.c

1/*
2 * YAFFS: Yet Another Flash File System. A NAND-flash specific file system.
3 *
4 * Copyright (C) 2002-2007 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
34const char *yaffs_fs_c_version =
35    "$Id: yaffs_fs.c,v 1.63 2007-09-19 20:35:40 imcd Exp $";
36extern const char *yaffs_guts_c_version;
37
38#include <linux/version.h>
39#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
40#include <linux/config.h>
41#endif
42#include <linux/kernel.h>
43#include <linux/module.h>
44#include <linux/slab.h>
45#include <linux/init.h>
46#include <linux/list.h>
47#include <linux/fs.h>
48#include <linux/proc_fs.h>
49#include <linux/smp_lock.h>
50#include <linux/pagemap.h>
51#include <linux/mtd/mtd.h>
52#include <linux/interrupt.h>
53#include <linux/string.h>
54#include <linux/ctype.h>
55
56#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
57
58#include <linux/statfs.h> /* Added NCB 15-8-2003 */
59#include <asm/statfs.h>
60#define UnlockPage(p) unlock_page(p)
61#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
62
63/* FIXME: use sb->s_id instead ? */
64#define yaffs_devname(sb, buf) bdevname(sb->s_bdev, buf)
65
66#else
67
68#include <linux/locks.h>
69#define BDEVNAME_SIZE 0
70#define yaffs_devname(sb, buf) kdevname(sb->s_dev)
71
72#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
73/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */
74#define __user
75#endif
76
77#endif
78
79#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
80#define WRITE_SIZE_STR "writesize"
81#define WRITE_SIZE(mtd) (mtd)->writesize
82#else
83#define WRITE_SIZE_STR "oobblock"
84#define WRITE_SIZE(mtd) (mtd)->oobblock
85#endif
86
87#include <asm/uaccess.h>
88
89#include "yportenv.h"
90#include "yaffs_guts.h"
91
92#include <linux/mtd/mtd.h>
93#include "yaffs_mtdif.h"
94#include "yaffs_mtdif1.h"
95#include "yaffs_mtdif2.h"
96
97unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS;
98unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS;
99
100/* Module Parameters */
101#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
102module_param(yaffs_traceMask,uint,0644);
103module_param(yaffs_wr_attempts,uint,0644);
104#else
105MODULE_PARM(yaffs_traceMask,"i");
106MODULE_PARM(yaffs_wr_attempts,"i");
107#endif
108
109/*#define T(x) printk x */
110
111#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
112#define yaffs_InodeToObjectLV(iptr) (iptr)->i_private
113#else
114#define yaffs_InodeToObjectLV(iptr) (iptr)->u.generic_ip
115#endif
116
117#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr)))
118#define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode)
119
120#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
121#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->s_fs_info)
122#else
123#define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp)
124#endif
125
126static void yaffs_put_super(struct super_block *sb);
127
128static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
129                loff_t * pos);
130
131#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
132static int yaffs_file_flush(struct file *file, fl_owner_t id);
133#else
134static int yaffs_file_flush(struct file *file);
135#endif
136
137static int yaffs_sync_object(struct file *file, struct dentry *dentry,
138                 int datasync);
139
140static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
141
142#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
143static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
144            struct nameidata *n);
145static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
146                   struct nameidata *n);
147#else
148static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
149static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
150#endif
151static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
152              struct dentry *dentry);
153static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
154static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
155             const char *symname);
156static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
157
158#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
159static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
160               dev_t dev);
161#else
162static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
163               int dev);
164#endif
165static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
166            struct inode *new_dir, struct dentry *new_dentry);
167static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
168
169#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
170static int yaffs_sync_fs(struct super_block *sb, int wait);
171static void yaffs_write_super(struct super_block *sb);
172#else
173static int yaffs_sync_fs(struct super_block *sb);
174static int yaffs_write_super(struct super_block *sb);
175#endif
176
177#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
178static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
179#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
180static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
181#else
182static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
183#endif
184static void yaffs_read_inode(struct inode *inode);
185
186static void yaffs_put_inode(struct inode *inode);
187static void yaffs_delete_inode(struct inode *);
188static void yaffs_clear_inode(struct inode *);
189
190static int yaffs_readpage(struct file *file, struct page *page);
191#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
192static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
193#else
194static int yaffs_writepage(struct page *page);
195#endif
196static int yaffs_prepare_write(struct file *f, struct page *pg,
197                   unsigned offset, unsigned to);
198static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
199                  unsigned to);
200
201static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
202              int buflen);
203#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
204static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
205#else
206static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
207#endif
208
209static struct address_space_operations yaffs_file_address_operations = {
210    .readpage = yaffs_readpage,
211    .writepage = yaffs_writepage,
212    .prepare_write = yaffs_prepare_write,
213    .commit_write = yaffs_commit_write,
214};
215
216#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,22))
217static struct file_operations yaffs_file_operations = {
218    .read = do_sync_read,
219    .write = do_sync_write,
220    .aio_read = generic_file_aio_read,
221    .aio_write = generic_file_aio_write,
222    .mmap = generic_file_mmap,
223    .flush = yaffs_file_flush,
224    .fsync = yaffs_sync_object,
225    .splice_read = generic_file_splice_read,
226    .splice_write = generic_file_splice_write,
227};
228
229#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18))
230
231static struct file_operations yaffs_file_operations = {
232    .read = do_sync_read,
233    .write = do_sync_write,
234    .aio_read = generic_file_aio_read,
235    .aio_write = generic_file_aio_write,
236    .mmap = generic_file_mmap,
237    .flush = yaffs_file_flush,
238    .fsync = yaffs_sync_object,
239    .sendfile = generic_file_sendfile,
240};
241
242#else
243
244static struct file_operations yaffs_file_operations = {
245    .read = generic_file_read,
246    .write = generic_file_write,
247    .mmap = generic_file_mmap,
248    .flush = yaffs_file_flush,
249    .fsync = yaffs_sync_object,
250#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
251    .sendfile = generic_file_sendfile,
252#endif
253};
254#endif
255
256static struct inode_operations yaffs_file_inode_operations = {
257    .setattr = yaffs_setattr,
258};
259
260static struct inode_operations yaffs_symlink_inode_operations = {
261    .readlink = yaffs_readlink,
262    .follow_link = yaffs_follow_link,
263    .setattr = yaffs_setattr,
264};
265
266static struct inode_operations yaffs_dir_inode_operations = {
267    .create = yaffs_create,
268    .lookup = yaffs_lookup,
269    .link = yaffs_link,
270    .unlink = yaffs_unlink,
271    .symlink = yaffs_symlink,
272    .mkdir = yaffs_mkdir,
273    .rmdir = yaffs_unlink,
274    .mknod = yaffs_mknod,
275    .rename = yaffs_rename,
276    .setattr = yaffs_setattr,
277};
278
279static struct file_operations yaffs_dir_operations = {
280    .read = generic_read_dir,
281    .readdir = yaffs_readdir,
282    .fsync = yaffs_sync_object,
283};
284
285static struct super_operations yaffs_super_ops = {
286    .statfs = yaffs_statfs,
287    .read_inode = yaffs_read_inode,
288    .put_inode = yaffs_put_inode,
289    .put_super = yaffs_put_super,
290    .delete_inode = yaffs_delete_inode,
291    .clear_inode = yaffs_clear_inode,
292    .sync_fs = yaffs_sync_fs,
293    .write_super = yaffs_write_super,
294};
295
296static void yaffs_GrossLock(yaffs_Device * dev)
297{
298    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs locking\n"));
299
300    down(&dev->grossLock);
301}
302
303static void yaffs_GrossUnlock(yaffs_Device * dev)
304{
305    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs unlocking\n"));
306    up(&dev->grossLock);
307
308}
309
310static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
311              int buflen)
312{
313    unsigned char *alias;
314    int ret;
315
316    yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
317
318    yaffs_GrossLock(dev);
319
320    alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
321
322    yaffs_GrossUnlock(dev);
323
324    if (!alias)
325        return -ENOMEM;
326
327    ret = vfs_readlink(dentry, buffer, buflen, alias);
328    kfree(alias);
329    return ret;
330}
331
332#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
333static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
334#else
335static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
336#endif
337{
338    unsigned char *alias;
339    int ret;
340    yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
341
342    yaffs_GrossLock(dev);
343
344    alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry));
345
346    yaffs_GrossUnlock(dev);
347
348    if (!alias)
349        {
350        ret = -ENOMEM;
351        goto out;
352        }
353
354    ret = vfs_follow_link(nd, alias);
355    kfree(alias);
356out:
357#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
358    return ERR_PTR (ret);
359#else
360    return ret;
361#endif
362}
363
364struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
365                  yaffs_Object * obj);
366
367/*
368 * Lookup is used to find objects in the fs
369 */
370#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
371
372static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
373                   struct nameidata *n)
374#else
375static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry)
376#endif
377{
378    yaffs_Object *obj;
379    struct inode *inode = NULL; /* NCB 2.5/2.6 needs NULL here */
380
381    yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev;
382
383    yaffs_GrossLock(dev);
384
385    T(YAFFS_TRACE_OS,
386      (KERN_DEBUG "yaffs_lookup for %d:%s\n",
387       yaffs_InodeToObject(dir)->objectId, dentry->d_name.name));
388
389    obj =
390        yaffs_FindObjectByName(yaffs_InodeToObject(dir),
391                   dentry->d_name.name);
392
393    obj = yaffs_GetEquivalentObject(obj); /* in case it was a hardlink */
394
395    /* Can't hold gross lock when calling yaffs_get_inode() */
396    yaffs_GrossUnlock(dev);
397
398    if (obj) {
399        T(YAFFS_TRACE_OS,
400          (KERN_DEBUG "yaffs_lookup found %d\n", obj->objectId));
401
402        inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
403
404        if (inode) {
405            T(YAFFS_TRACE_OS,
406              (KERN_DEBUG "yaffs_loookup dentry \n"));
407/* #if 0 asserted by NCB for 2.5/6 compatability - falls through to
408 * d_add even if NULL inode */
409#if 0
410            /*dget(dentry); // try to solve directory bug */
411            d_add(dentry, inode);
412
413            /* return dentry; */
414            return NULL;
415#endif
416        }
417
418    } else {
419        T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_lookup not found\n"));
420
421    }
422
423/* added NCB for 2.5/6 compatability - forces add even if inode is
424 * NULL which creates dentry hash */
425    d_add(dentry, inode);
426
427    return NULL;
428    /* return (ERR_PTR(-EIO)); */
429
430}
431
432/* For now put inode is just for debugging
433 * Put inode is called when the inode **structure** is put.
434 */
435static void yaffs_put_inode(struct inode *inode)
436{
437    T(YAFFS_TRACE_OS,
438      ("yaffs_put_inode: ino %d, count %d\n", (int)inode->i_ino,
439       atomic_read(&inode->i_count)));
440
441}
442
443/* clear is called to tell the fs to release any per-inode data it holds */
444static void yaffs_clear_inode(struct inode *inode)
445{
446    yaffs_Object *obj;
447    yaffs_Device *dev;
448
449    obj = yaffs_InodeToObject(inode);
450
451    T(YAFFS_TRACE_OS,
452      ("yaffs_clear_inode: ino %d, count %d %s\n", (int)inode->i_ino,
453       atomic_read(&inode->i_count),
454       obj ? "object exists" : "null object"));
455
456    if (obj) {
457        dev = obj->myDev;
458        yaffs_GrossLock(dev);
459
460        /* Clear the association between the inode and
461         * the yaffs_Object.
462         */
463        obj->myInode = NULL;
464        yaffs_InodeToObjectLV(inode) = NULL;
465
466        /* If the object freeing was deferred, then the real
467         * free happens now.
468         * This should fix the inode inconsistency problem.
469         */
470
471        yaffs_HandleDeferedFree(obj);
472
473        yaffs_GrossUnlock(dev);
474    }
475
476}
477
478/* delete is called when the link count is zero and the inode
479 * is put (ie. nobody wants to know about it anymore, time to
480 * delete the file).
481 * NB Must call clear_inode()
482 */
483static void yaffs_delete_inode(struct inode *inode)
484{
485    yaffs_Object *obj = yaffs_InodeToObject(inode);
486    yaffs_Device *dev;
487
488    T(YAFFS_TRACE_OS,
489      ("yaffs_delete_inode: ino %d, count %d %s\n", (int)inode->i_ino,
490       atomic_read(&inode->i_count),
491       obj ? "object exists" : "null object"));
492
493    if (obj) {
494        dev = obj->myDev;
495        yaffs_GrossLock(dev);
496        yaffs_DeleteFile(obj);
497        yaffs_GrossUnlock(dev);
498    }
499#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
500        truncate_inode_pages (&inode->i_data, 0);
501#endif
502    clear_inode(inode);
503}
504
505#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
506static int yaffs_file_flush(struct file *file, fl_owner_t id)
507#else
508static int yaffs_file_flush(struct file *file)
509#endif
510{
511    yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry);
512
513    yaffs_Device *dev = obj->myDev;
514
515    T(YAFFS_TRACE_OS,
516      (KERN_DEBUG "yaffs_file_flush object %d (%s)\n", obj->objectId,
517       obj->dirty ? "dirty" : "clean"));
518
519    yaffs_GrossLock(dev);
520
521    yaffs_FlushFile(obj, 1);
522
523    yaffs_GrossUnlock(dev);
524
525    return 0;
526}
527
528static int yaffs_readpage_nolock(struct file *f, struct page *pg)
529{
530    /* Lifted from jffs2 */
531
532    yaffs_Object *obj;
533    unsigned char *pg_buf;
534    int ret;
535
536    yaffs_Device *dev;
537
538    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_readpage at %08x, size %08x\n",
539               (unsigned)(pg->index << PAGE_CACHE_SHIFT),
540               (unsigned)PAGE_CACHE_SIZE));
541
542    obj = yaffs_DentryToObject(f->f_dentry);
543
544    dev = obj->myDev;
545
546#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
547    BUG_ON(!PageLocked(pg));
548#else
549    if (!PageLocked(pg))
550        PAGE_BUG(pg);
551#endif
552
553    pg_buf = kmap(pg);
554    /* FIXME: Can kmap fail? */
555
556    yaffs_GrossLock(dev);
557
558    ret =
559        yaffs_ReadDataFromFile(obj, pg_buf, pg->index << PAGE_CACHE_SHIFT,
560                   PAGE_CACHE_SIZE);
561
562    yaffs_GrossUnlock(dev);
563
564    if (ret >= 0)
565        ret = 0;
566
567    if (ret) {
568        ClearPageUptodate(pg);
569        SetPageError(pg);
570    } else {
571        SetPageUptodate(pg);
572        ClearPageError(pg);
573    }
574
575    flush_dcache_page(pg);
576    kunmap(pg);
577
578    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_readpage done\n"));
579    return ret;
580}
581
582static int yaffs_readpage_unlock(struct file *f, struct page *pg)
583{
584    int ret = yaffs_readpage_nolock(f, pg);
585    UnlockPage(pg);
586    return ret;
587}
588
589static int yaffs_readpage(struct file *f, struct page *pg)
590{
591    return yaffs_readpage_unlock(f, pg);
592}
593
594/* writepage inspired by/stolen from smbfs */
595
596#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
597static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
598#else
599static int yaffs_writepage(struct page *page)
600#endif
601{
602    struct address_space *mapping = page->mapping;
603    loff_t offset = (loff_t) page->index << PAGE_CACHE_SHIFT;
604    struct inode *inode;
605    unsigned long end_index;
606    char *buffer;
607    yaffs_Object *obj;
608    int nWritten = 0;
609    unsigned nBytes;
610
611    if (!mapping)
612        BUG();
613    inode = mapping->host;
614    if (!inode)
615        BUG();
616
617    if (offset > inode->i_size) {
618        T(YAFFS_TRACE_OS,
619          (KERN_DEBUG
620           "yaffs_writepage at %08x, inode size = %08x!!!\n",
621           (unsigned)(page->index << PAGE_CACHE_SHIFT),
622           (unsigned)inode->i_size));
623        T(YAFFS_TRACE_OS,
624          (KERN_DEBUG " -> don't care!!\n"));
625        unlock_page(page);
626        return 0;
627    }
628
629    end_index = inode->i_size >> PAGE_CACHE_SHIFT;
630
631    /* easy case */
632    if (page->index < end_index) {
633        nBytes = PAGE_CACHE_SIZE;
634    } else {
635        nBytes = inode->i_size & (PAGE_CACHE_SIZE - 1);
636    }
637
638    get_page(page);
639
640    buffer = kmap(page);
641
642    obj = yaffs_InodeToObject(inode);
643    yaffs_GrossLock(obj->myDev);
644
645    T(YAFFS_TRACE_OS,
646      (KERN_DEBUG "yaffs_writepage at %08x, size %08x\n",
647       (unsigned)(page->index << PAGE_CACHE_SHIFT), nBytes));
648    T(YAFFS_TRACE_OS,
649      (KERN_DEBUG "writepag0: obj = %05x, ino = %05x\n",
650       (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
651
652    nWritten =
653        yaffs_WriteDataToFile(obj, buffer, page->index << PAGE_CACHE_SHIFT,
654                  nBytes, 0);
655
656    T(YAFFS_TRACE_OS,
657      (KERN_DEBUG "writepag1: obj = %05x, ino = %05x\n",
658       (int)obj->variant.fileVariant.fileSize, (int)inode->i_size));
659
660    yaffs_GrossUnlock(obj->myDev);
661
662    kunmap(page);
663    SetPageUptodate(page);
664    UnlockPage(page);
665    put_page(page);
666
667    return (nWritten == nBytes) ? 0 : -ENOSPC;
668}
669
670static int yaffs_prepare_write(struct file *f, struct page *pg,
671                   unsigned offset, unsigned to)
672{
673
674    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_prepair_write\n"));
675    if (!Page_Uptodate(pg) && (offset || to < PAGE_CACHE_SIZE))
676        return yaffs_readpage_nolock(f, pg);
677
678    return 0;
679
680}
681
682static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
683                  unsigned to)
684{
685
686    void *addr = page_address(pg) + offset;
687    loff_t pos = (((loff_t) pg->index) << PAGE_CACHE_SHIFT) + offset;
688    int nBytes = to - offset;
689    int nWritten;
690
691    unsigned spos = pos;
692    unsigned saddr = (unsigned)addr;
693
694    T(YAFFS_TRACE_OS,
695      (KERN_DEBUG "yaffs_commit_write addr %x pos %x nBytes %d\n", saddr,
696       spos, nBytes));
697
698    nWritten = yaffs_file_write(f, addr, nBytes, &pos);
699
700    if (nWritten != nBytes) {
701        T(YAFFS_TRACE_OS,
702          (KERN_DEBUG
703           "yaffs_commit_write not same size nWritten %d nBytes %d\n",
704           nWritten, nBytes));
705        SetPageError(pg);
706        ClearPageUptodate(pg);
707    } else {
708        SetPageUptodate(pg);
709    }
710
711    T(YAFFS_TRACE_OS,
712      (KERN_DEBUG "yaffs_commit_write returning %d\n",
713       nWritten == nBytes ? 0 : nWritten));
714
715    return nWritten == nBytes ? 0 : nWritten;
716
717}
718
719static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj)
720{
721    if (inode && obj) {
722
723
724        /* Check mode against the variant type and attempt to repair if broken. */
725         __u32 mode = obj->yst_mode;
726         switch( obj->variantType ){
727         case YAFFS_OBJECT_TYPE_FILE :
728                 if( ! S_ISREG(mode) ){
729                     obj->yst_mode &= ~S_IFMT;
730                     obj->yst_mode |= S_IFREG;
731             }
732
733             break;
734         case YAFFS_OBJECT_TYPE_SYMLINK :
735                 if( ! S_ISLNK(mode) ){
736                     obj->yst_mode &= ~S_IFMT;
737                 obj->yst_mode |= S_IFLNK;
738             }
739
740             break;
741         case YAFFS_OBJECT_TYPE_DIRECTORY :
742                 if( ! S_ISDIR(mode) ){
743                     obj->yst_mode &= ~S_IFMT;
744                     obj->yst_mode |= S_IFDIR;
745             }
746
747             break;
748         case YAFFS_OBJECT_TYPE_UNKNOWN :
749         case YAFFS_OBJECT_TYPE_HARDLINK :
750         case YAFFS_OBJECT_TYPE_SPECIAL :
751         default:
752                 /* TODO? */
753                 break;
754         }
755
756        inode->i_ino = obj->objectId;
757        inode->i_mode = obj->yst_mode;
758        inode->i_uid = obj->yst_uid;
759        inode->i_gid = obj->yst_gid;
760#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
761        inode->i_blksize = inode->i_sb->s_blocksize;
762#endif
763#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
764
765        inode->i_rdev = old_decode_dev(obj->yst_rdev);
766        inode->i_atime.tv_sec = (time_t) (obj->yst_atime);
767        inode->i_atime.tv_nsec = 0;
768        inode->i_mtime.tv_sec = (time_t) obj->yst_mtime;
769        inode->i_mtime.tv_nsec = 0;
770        inode->i_ctime.tv_sec = (time_t) obj->yst_ctime;
771        inode->i_ctime.tv_nsec = 0;
772#else
773        inode->i_rdev = obj->yst_rdev;
774        inode->i_atime = obj->yst_atime;
775        inode->i_mtime = obj->yst_mtime;
776        inode->i_ctime = obj->yst_ctime;
777#endif
778        inode->i_size = yaffs_GetObjectFileLength(obj);
779        inode->i_blocks = (inode->i_size + 511) >> 9;
780
781        inode->i_nlink = yaffs_GetObjectLinkCount(obj);
782
783        T(YAFFS_TRACE_OS,
784          (KERN_DEBUG
785           "yaffs_FillInode mode %x uid %d gid %d size %d count %d\n",
786           inode->i_mode, inode->i_uid, inode->i_gid,
787           (int)inode->i_size, atomic_read(&inode->i_count)));
788
789        switch (obj->yst_mode & S_IFMT) {
790        default: /* fifo, device or socket */
791#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
792            init_special_inode(inode, obj->yst_mode,
793                       old_decode_dev(obj->yst_rdev));
794#else
795            init_special_inode(inode, obj->yst_mode,
796                       (dev_t) (obj->yst_rdev));
797#endif
798            break;
799        case S_IFREG: /* file */
800            inode->i_op = &yaffs_file_inode_operations;
801            inode->i_fop = &yaffs_file_operations;
802            inode->i_mapping->a_ops =
803                &yaffs_file_address_operations;
804            break;
805        case S_IFDIR: /* directory */
806            inode->i_op = &yaffs_dir_inode_operations;
807            inode->i_fop = &yaffs_dir_operations;
808            break;
809        case S_IFLNK: /* symlink */
810            inode->i_op = &yaffs_symlink_inode_operations;
811            break;
812        }
813
814        yaffs_InodeToObjectLV(inode) = obj;
815
816        obj->myInode = inode;
817
818    } else {
819        T(YAFFS_TRACE_OS,
820          (KERN_DEBUG "yaffs_FileInode invalid parameters\n"));
821    }
822
823}
824
825struct inode *yaffs_get_inode(struct super_block *sb, int mode, int dev,
826                  yaffs_Object * obj)
827{
828    struct inode *inode;
829
830    if (!sb) {
831        T(YAFFS_TRACE_OS,
832          (KERN_DEBUG "yaffs_get_inode for NULL super_block!!\n"));
833        return NULL;
834
835    }
836
837    if (!obj) {
838        T(YAFFS_TRACE_OS,
839          (KERN_DEBUG "yaffs_get_inode for NULL object!!\n"));
840        return NULL;
841
842    }
843
844    T(YAFFS_TRACE_OS,
845      (KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId));
846
847    inode = iget(sb, obj->objectId);
848
849    /* NB Side effect: iget calls back to yaffs_read_inode(). */
850    /* iget also increments the inode's i_count */
851    /* NB You can't be holding grossLock or deadlock will happen! */
852
853    return inode;
854}
855
856static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
857                loff_t * pos)
858{
859    yaffs_Object *obj;
860    int nWritten, ipos;
861    struct inode *inode;
862    yaffs_Device *dev;
863
864    obj = yaffs_DentryToObject(f->f_dentry);
865
866    dev = obj->myDev;
867
868    yaffs_GrossLock(dev);
869
870    inode = f->f_dentry->d_inode;
871
872    if (!S_ISBLK(inode->i_mode) && f->f_flags & O_APPEND) {
873        ipos = inode->i_size;
874    } else {
875        ipos = *pos;
876    }
877
878    if (!obj) {
879        T(YAFFS_TRACE_OS,
880          (KERN_DEBUG "yaffs_file_write: hey obj is null!\n"));
881    } else {
882        T(YAFFS_TRACE_OS,
883          (KERN_DEBUG
884           "yaffs_file_write about to write writing %d bytes"
885           "to object %d at %d\n",
886           n, obj->objectId, ipos));
887    }
888
889    nWritten = yaffs_WriteDataToFile(obj, buf, ipos, n, 0);
890
891    T(YAFFS_TRACE_OS,
892      (KERN_DEBUG "yaffs_file_write writing %d bytes, %d written at %d\n",
893       n, nWritten, ipos));
894    if (nWritten > 0) {
895        ipos += nWritten;
896        *pos = ipos;
897        if (ipos > inode->i_size) {
898            inode->i_size = ipos;
899            inode->i_blocks = (ipos + 511) >> 9;
900
901            T(YAFFS_TRACE_OS,
902              (KERN_DEBUG
903               "yaffs_file_write size updated to %d bytes, "
904               "%d blocks\n",
905               ipos, (int)(inode->i_blocks)));
906        }
907
908    }
909    yaffs_GrossUnlock(dev);
910    return nWritten == 0 ? -ENOSPC : nWritten;
911}
912
913static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir)
914{
915    yaffs_Object *obj;
916    yaffs_Device *dev;
917    struct inode *inode = f->f_dentry->d_inode;
918    unsigned long offset, curoffs;
919    struct list_head *i;
920    yaffs_Object *l;
921
922    char name[YAFFS_MAX_NAME_LENGTH + 1];
923
924    obj = yaffs_DentryToObject(f->f_dentry);
925    dev = obj->myDev;
926
927    yaffs_GrossLock(dev);
928
929    offset = f->f_pos;
930
931    T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
932
933    if (offset == 0) {
934        T(YAFFS_TRACE_OS,
935          (KERN_DEBUG "yaffs_readdir: entry . ino %d \n",
936           (int)inode->i_ino));
937        if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR)
938            < 0) {
939            goto out;
940        }
941        offset++;
942        f->f_pos++;
943    }
944    if (offset == 1) {
945        T(YAFFS_TRACE_OS,
946          (KERN_DEBUG "yaffs_readdir: entry .. ino %d \n",
947           (int)f->f_dentry->d_parent->d_inode->i_ino));
948        if (filldir
949            (dirent, "..", 2, offset,
950             f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) {
951            goto out;
952        }
953        offset++;
954        f->f_pos++;
955    }
956
957    curoffs = 1;
958
959    /* If the directory has changed since the open or last call to
960       readdir, rewind to after the 2 canned entries. */
961
962    if (f->f_version != inode->i_version) {
963        offset = 2;
964        f->f_pos = offset;
965        f->f_version = inode->i_version;
966    }
967
968    list_for_each(i, &obj->variant.directoryVariant.children) {
969        curoffs++;
970        if (curoffs >= offset) {
971            l = list_entry(i, yaffs_Object, siblings);
972
973            yaffs_GetObjectName(l, name,
974                        YAFFS_MAX_NAME_LENGTH + 1);
975            T(YAFFS_TRACE_OS,
976              (KERN_DEBUG "yaffs_readdir: %s inode %d\n", name,
977               yaffs_GetObjectInode(l)));
978
979            if (filldir(dirent,
980                    name,
981                    strlen(name),
982                    offset,
983                    yaffs_GetObjectInode(l),
984                    yaffs_GetObjectType(l))
985                < 0) {
986                goto up_and_out;
987            }
988
989            offset++;
990            f->f_pos++;
991        }
992    }
993
994      up_and_out:
995      out:
996
997    yaffs_GrossUnlock(dev);
998
999    return 0;
1000}
1001
1002/*
1003 * File creation. Allocate an inode, and we're done..
1004 */
1005#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1006static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1007               dev_t rdev)
1008#else
1009static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
1010               int rdev)
1011#endif
1012{
1013    struct inode *inode;
1014
1015    yaffs_Object *obj = NULL;
1016    yaffs_Device *dev;
1017
1018    yaffs_Object *parent = yaffs_InodeToObject(dir);
1019
1020    int error = -ENOSPC;
1021    uid_t uid = current->fsuid;
1022    gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
1023
1024    if((dir->i_mode & S_ISGID) && S_ISDIR(mode))
1025        mode |= S_ISGID;
1026
1027    if (parent) {
1028        T(YAFFS_TRACE_OS,
1029          (KERN_DEBUG "yaffs_mknod: parent object %d type %d\n",
1030           parent->objectId, parent->variantType));
1031    } else {
1032        T(YAFFS_TRACE_OS,
1033          (KERN_DEBUG "yaffs_mknod: could not get parent object\n"));
1034        return -EPERM;
1035    }
1036
1037    T(YAFFS_TRACE_OS, ("yaffs_mknod: making oject for %s, "
1038               "mode %x dev %x\n",
1039               dentry->d_name.name, mode, rdev));
1040
1041    dev = parent->myDev;
1042
1043    yaffs_GrossLock(dev);
1044
1045    switch (mode & S_IFMT) {
1046    default:
1047        /* Special (socket, fifo, device...) */
1048        T(YAFFS_TRACE_OS, (KERN_DEBUG
1049                   "yaffs_mknod: making special\n"));
1050#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1051        obj =
1052            yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
1053                       gid, old_encode_dev(rdev));
1054#else
1055        obj =
1056            yaffs_MknodSpecial(parent, dentry->d_name.name, mode, uid,
1057                       gid, rdev);
1058#endif
1059        break;
1060    case S_IFREG: /* file */
1061        T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n"));
1062        obj =
1063            yaffs_MknodFile(parent, dentry->d_name.name, mode, uid,
1064                    gid);
1065        break;
1066    case S_IFDIR: /* directory */
1067        T(YAFFS_TRACE_OS,
1068          (KERN_DEBUG "yaffs_mknod: making directory\n"));
1069        obj =
1070            yaffs_MknodDirectory(parent, dentry->d_name.name, mode,
1071                     uid, gid);
1072        break;
1073    case S_IFLNK: /* symlink */
1074        T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mknod: making file\n"));
1075        obj = NULL; /* Do we ever get here? */
1076        break;
1077    }
1078
1079    /* Can not call yaffs_get_inode() with gross lock held */
1080    yaffs_GrossUnlock(dev);
1081
1082    if (obj) {
1083        inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
1084        d_instantiate(dentry, inode);
1085        T(YAFFS_TRACE_OS,
1086          (KERN_DEBUG "yaffs_mknod created object %d count = %d\n",
1087           obj->objectId, atomic_read(&inode->i_count)));
1088        error = 0;
1089    } else {
1090        T(YAFFS_TRACE_OS,
1091          (KERN_DEBUG "yaffs_mknod failed making object\n"));
1092        error = -ENOMEM;
1093    }
1094
1095    return error;
1096}
1097
1098static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
1099{
1100    int retVal;
1101    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_mkdir\n"));
1102    retVal = yaffs_mknod(dir, dentry, mode | S_IFDIR, 0);
1103#if 0
1104    /* attempt to fix dir bug - didn't work */
1105    if (!retVal) {
1106        dget(dentry);
1107    }
1108#endif
1109    return retVal;
1110}
1111
1112#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1113static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1114            struct nameidata *n)
1115#else
1116static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode)
1117#endif
1118{
1119    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_create\n"));
1120    return yaffs_mknod(dir, dentry, mode | S_IFREG, 0);
1121}
1122
1123static int yaffs_unlink(struct inode *dir, struct dentry *dentry)
1124{
1125    int retVal;
1126
1127    yaffs_Device *dev;
1128
1129    T(YAFFS_TRACE_OS,
1130      (KERN_DEBUG "yaffs_unlink %d:%s\n", (int)(dir->i_ino),
1131       dentry->d_name.name));
1132
1133    dev = yaffs_InodeToObject(dir)->myDev;
1134
1135    yaffs_GrossLock(dev);
1136
1137    retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name);
1138
1139    if (retVal == YAFFS_OK) {
1140        dentry->d_inode->i_nlink--;
1141        dir->i_version++;
1142        yaffs_GrossUnlock(dev);
1143        mark_inode_dirty(dentry->d_inode);
1144        return 0;
1145    }
1146    yaffs_GrossUnlock(dev);
1147    return -ENOTEMPTY;
1148}
1149
1150/*
1151 * Create a link...
1152 */
1153static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
1154              struct dentry *dentry)
1155{
1156    struct inode *inode = old_dentry->d_inode;
1157    yaffs_Object *obj = NULL;
1158    yaffs_Object *link = NULL;
1159    yaffs_Device *dev;
1160
1161    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_link\n"));
1162
1163    obj = yaffs_InodeToObject(inode);
1164    dev = obj->myDev;
1165
1166    yaffs_GrossLock(dev);
1167
1168    if (!S_ISDIR(inode->i_mode)) /* Don't link directories */
1169    {
1170        link =
1171            yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name,
1172                   obj);
1173    }
1174
1175    if (link) {
1176        old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj);
1177        d_instantiate(dentry, old_dentry->d_inode);
1178        atomic_inc(&old_dentry->d_inode->i_count);
1179        T(YAFFS_TRACE_OS,
1180          (KERN_DEBUG "yaffs_link link count %d i_count %d\n",
1181           old_dentry->d_inode->i_nlink,
1182           atomic_read(&old_dentry->d_inode->i_count)));
1183
1184    }
1185
1186    yaffs_GrossUnlock(dev);
1187
1188    if (link) {
1189
1190        return 0;
1191    }
1192
1193    return -EPERM;
1194}
1195
1196static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
1197             const char *symname)
1198{
1199    yaffs_Object *obj;
1200    yaffs_Device *dev;
1201    uid_t uid = current->fsuid;
1202    gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
1203
1204    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_symlink\n"));
1205
1206    dev = yaffs_InodeToObject(dir)->myDev;
1207    yaffs_GrossLock(dev);
1208    obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name,
1209                 S_IFLNK | S_IRWXUGO, uid, gid, symname);
1210    yaffs_GrossUnlock(dev);
1211
1212    if (obj) {
1213
1214        struct inode *inode;
1215
1216        inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
1217        d_instantiate(dentry, inode);
1218        T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink created OK\n"));
1219        return 0;
1220    } else {
1221        T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink not created\n"));
1222
1223    }
1224
1225    return -ENOMEM;
1226}
1227
1228static int yaffs_sync_object(struct file *file, struct dentry *dentry,
1229                 int datasync)
1230{
1231
1232    yaffs_Object *obj;
1233    yaffs_Device *dev;
1234
1235    obj = yaffs_DentryToObject(dentry);
1236
1237    dev = obj->myDev;
1238
1239    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_object\n"));
1240    yaffs_GrossLock(dev);
1241    yaffs_FlushFile(obj, 1);
1242    yaffs_GrossUnlock(dev);
1243    return 0;
1244}
1245
1246/*
1247 * The VFS layer already does all the dentry stuff for rename.
1248 *
1249 * NB: POSIX says you can rename an object over an old object of the same name
1250 */
1251static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
1252            struct inode *new_dir, struct dentry *new_dentry)
1253{
1254    yaffs_Device *dev;
1255    int retVal = YAFFS_FAIL;
1256    yaffs_Object *target;
1257
1258        T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_rename\n"));
1259    dev = yaffs_InodeToObject(old_dir)->myDev;
1260
1261    yaffs_GrossLock(dev);
1262
1263    /* Check if the target is an existing directory that is not empty. */
1264    target =
1265        yaffs_FindObjectByName(yaffs_InodeToObject(new_dir),
1266                   new_dentry->d_name.name);
1267
1268
1269
1270    if (target &&
1271        target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
1272        !list_empty(&target->variant.directoryVariant.children)) {
1273
1274            T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n"));
1275
1276        retVal = YAFFS_FAIL;
1277    } else {
1278
1279        /* Now does unlinking internally using shadowing mechanism */
1280            T(YAFFS_TRACE_OS, (KERN_DEBUG "calling yaffs_RenameObject\n"));
1281
1282        retVal =
1283            yaffs_RenameObject(yaffs_InodeToObject(old_dir),
1284                       old_dentry->d_name.name,
1285                       yaffs_InodeToObject(new_dir),
1286                       new_dentry->d_name.name);
1287
1288    }
1289    yaffs_GrossUnlock(dev);
1290
1291    if (retVal == YAFFS_OK) {
1292        if(target) {
1293            new_dentry->d_inode->i_nlink--;
1294            mark_inode_dirty(new_dentry->d_inode);
1295        }
1296
1297        return 0;
1298    } else {
1299        return -ENOTEMPTY;
1300    }
1301
1302}
1303
1304static int yaffs_setattr(struct dentry *dentry, struct iattr *attr)
1305{
1306    struct inode *inode = dentry->d_inode;
1307    int error;
1308    yaffs_Device *dev;
1309
1310    T(YAFFS_TRACE_OS,
1311      (KERN_DEBUG "yaffs_setattr of object %d\n",
1312       yaffs_InodeToObject(inode)->objectId));
1313
1314    if ((error = inode_change_ok(inode, attr)) == 0) {
1315
1316        dev = yaffs_InodeToObject(inode)->myDev;
1317        yaffs_GrossLock(dev);
1318        if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) ==
1319            YAFFS_OK) {
1320            error = 0;
1321        } else {
1322            error = -EPERM;
1323        }
1324        yaffs_GrossUnlock(dev);
1325        if (!error)
1326            error = inode_setattr(inode, attr);
1327    }
1328    return error;
1329}
1330
1331#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1332static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf)
1333{
1334    yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev;
1335    struct super_block *sb = dentry->d_sb;
1336#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1337static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
1338{
1339    yaffs_Device *dev = yaffs_SuperToDevice(sb);
1340#else
1341static int yaffs_statfs(struct super_block *sb, struct statfs *buf)
1342{
1343    yaffs_Device *dev = yaffs_SuperToDevice(sb);
1344#endif
1345
1346    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_statfs\n"));
1347
1348    yaffs_GrossLock(dev);
1349
1350    buf->f_type = YAFFS_MAGIC;
1351    buf->f_bsize = sb->s_blocksize;
1352    buf->f_namelen = 255;
1353    if (sb->s_blocksize > dev->nDataBytesPerChunk) {
1354
1355        buf->f_blocks =
1356            (dev->endBlock - dev->startBlock +
1357             1) * dev->nChunksPerBlock / (sb->s_blocksize /
1358                          dev->nDataBytesPerChunk);
1359        buf->f_bfree =
1360            yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize /
1361                            dev->nDataBytesPerChunk);
1362    } else {
1363
1364        buf->f_blocks =
1365            (dev->endBlock - dev->startBlock +
1366             1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk /
1367                          sb->s_blocksize);
1368        buf->f_bfree =
1369            yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk /
1370                            sb->s_blocksize);
1371    }
1372    buf->f_files = 0;
1373    buf->f_ffree = 0;
1374    buf->f_bavail = buf->f_bfree;
1375
1376    yaffs_GrossUnlock(dev);
1377    return 0;
1378}
1379
1380
1381/**
1382static int yaffs_do_sync_fs(struct super_block *sb)
1383{
1384
1385    yaffs_Device *dev = yaffs_SuperToDevice(sb);
1386    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_do_sync_fs\n"));
1387
1388    if(sb->s_dirt) {
1389        yaffs_GrossLock(dev);
1390
1391        if(dev)
1392            yaffs_CheckpointSave(dev);
1393
1394        yaffs_GrossUnlock(dev);
1395
1396        sb->s_dirt = 0;
1397    }
1398    return 0;
1399}
1400**/
1401
1402#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1403static void yaffs_write_super(struct super_block *sb)
1404#else
1405static int yaffs_write_super(struct super_block *sb)
1406#endif
1407{
1408
1409    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n"));
1410#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
1411    return 0; /* yaffs_do_sync_fs(sb);*/
1412#endif
1413}
1414
1415
1416#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1417static int yaffs_sync_fs(struct super_block *sb, int wait)
1418#else
1419static int yaffs_sync_fs(struct super_block *sb)
1420#endif
1421{
1422
1423    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n"));
1424
1425    return 0; /* yaffs_do_sync_fs(sb);*/
1426
1427}
1428
1429
1430static void yaffs_read_inode(struct inode *inode)
1431{
1432    /* NB This is called as a side effect of other functions, but
1433     * we had to release the lock to prevent deadlocks, so
1434     * need to lock again.
1435     */
1436
1437    yaffs_Object *obj;
1438    yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb);
1439
1440    T(YAFFS_TRACE_OS,
1441      (KERN_DEBUG "yaffs_read_inode for %d\n", (int)inode->i_ino));
1442
1443    yaffs_GrossLock(dev);
1444
1445    obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
1446
1447    yaffs_FillInodeFromObject(inode, obj);
1448
1449    yaffs_GrossUnlock(dev);
1450}
1451
1452static LIST_HEAD(yaffs_dev_list);
1453
1454#if 0 // not used
1455static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data)
1456{
1457    yaffs_Device *dev = yaffs_SuperToDevice(sb);
1458
1459    if( *flags & MS_RDONLY ) {
1460        struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1461
1462        T(YAFFS_TRACE_OS,
1463            (KERN_DEBUG "yaffs_remount_fs: %s: RO\n", dev->name ));
1464
1465        yaffs_GrossLock(dev);
1466
1467        yaffs_FlushEntireDeviceCache(dev);
1468
1469        yaffs_CheckpointSave(dev);
1470
1471        if (mtd->sync)
1472            mtd->sync(mtd);
1473
1474        yaffs_GrossUnlock(dev);
1475    }
1476    else {
1477        T(YAFFS_TRACE_OS,
1478            (KERN_DEBUG "yaffs_remount_fs: %s: RW\n", dev->name ));
1479    }
1480
1481    return 0;
1482}
1483#endif
1484
1485static void yaffs_put_super(struct super_block *sb)
1486{
1487    yaffs_Device *dev = yaffs_SuperToDevice(sb);
1488
1489    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n"));
1490
1491    yaffs_GrossLock(dev);
1492
1493    yaffs_FlushEntireDeviceCache(dev);
1494
1495    yaffs_CheckpointSave(dev);
1496
1497    if (dev->putSuperFunc) {
1498        dev->putSuperFunc(sb);
1499    }
1500
1501    yaffs_Deinitialise(dev);
1502
1503    yaffs_GrossUnlock(dev);
1504
1505    /* we assume this is protected by lock_kernel() in mount/umount */
1506    list_del(&dev->devList);
1507
1508    if(dev->spareBuffer){
1509        YFREE(dev->spareBuffer);
1510        dev->spareBuffer = NULL;
1511    }
1512
1513    kfree(dev);
1514}
1515
1516
1517static void yaffs_MTDPutSuper(struct super_block *sb)
1518{
1519
1520    struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice;
1521
1522    if (mtd->sync) {
1523        mtd->sync(mtd);
1524    }
1525
1526    put_mtd_device(mtd);
1527}
1528
1529
1530static void yaffs_MarkSuperBlockDirty(void *vsb)
1531{
1532    struct super_block *sb = (struct super_block *)vsb;
1533
1534    T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_MarkSuperBlockDirty() sb = %p\n",sb));
1535// if(sb)
1536// sb->s_dirt = 1;
1537}
1538
1539typedef struct {
1540    int inband_tags;
1541    int skip_checkpoint_read;
1542    int skip_checkpoint_write;
1543    int no_cache;
1544} yaffs_options;
1545
1546#define MAX_OPT_LEN 20
1547static int yaffs_parse_options(yaffs_options *options, const char *options_str)
1548{
1549    char cur_opt[MAX_OPT_LEN+1];
1550    int p;
1551    int error = 0;
1552
1553    /* Parse through the options which is a comma seperated list */
1554
1555    while(options_str && *options_str && !error){
1556        memset(cur_opt,0,MAX_OPT_LEN+1);
1557        p = 0;
1558
1559        while(*options_str && *options_str != ','){
1560            if(p < MAX_OPT_LEN){
1561                cur_opt[p] = *options_str;
1562                p++;
1563            }
1564            options_str++;
1565        }
1566
1567        if(!strcmp(cur_opt,"inband-tags"))
1568            options->inband_tags = 1;
1569        else if(!strcmp(cur_opt,"no-cache"))
1570            options->no_cache = 1;
1571        else if(!strcmp(cur_opt,"no-checkpoint-read"))
1572            options->skip_checkpoint_read = 1;
1573        else if(!strcmp(cur_opt,"no-checkpoint-write"))
1574            options->skip_checkpoint_write = 1;
1575        else if(!strcmp(cur_opt,"no-checkpoint")){
1576            options->skip_checkpoint_read = 1;
1577            options->skip_checkpoint_write = 1;
1578        } else {
1579            printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",cur_opt);
1580            error = 1;
1581        }
1582
1583    }
1584
1585    return error;
1586}
1587
1588static struct super_block *yaffs_internal_read_super(int yaffsVersion,
1589                             struct super_block *sb,
1590                             void *data, int silent)
1591{
1592    int nBlocks;
1593    struct inode *inode = NULL;
1594    struct dentry *root;
1595    yaffs_Device *dev = 0;
1596    char devname_buf[BDEVNAME_SIZE + 1];
1597    struct mtd_info *mtd;
1598    int err;
1599    char *data_str = (char *)data;
1600
1601    yaffs_options options;
1602
1603    sb->s_magic = YAFFS_MAGIC;
1604    sb->s_op = &yaffs_super_ops;
1605
1606    if (!sb)
1607        printk(KERN_INFO "yaffs: sb is NULL\n");
1608    else if (!sb->s_dev)
1609        printk(KERN_INFO "yaffs: sb->s_dev is NULL\n");
1610    else if (!yaffs_devname(sb, devname_buf))
1611        printk(KERN_INFO "yaffs: devname is NULL\n");
1612    else
1613        printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n",
1614               sb->s_dev,
1615               yaffs_devname(sb, devname_buf));
1616
1617    if(!data_str)
1618        data_str = "";
1619
1620    printk(KERN_INFO "yaffs: passed flags \"%s\"\n",data_str);
1621
1622    memset(&options,0,sizeof(options));
1623
1624    if(yaffs_parse_options(&options,data_str)){
1625        /* Option parsing failed */
1626        return NULL;
1627    }
1628
1629
1630    sb->s_blocksize = PAGE_CACHE_SIZE;
1631    sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
1632    T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion));
1633    T(YAFFS_TRACE_OS,
1634      ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));
1635
1636#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY
1637    T(YAFFS_TRACE_OS,
1638      ("yaffs: Write verification disabled. All guarantees "
1639       "null and void\n"));
1640#endif
1641
1642    T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, "
1643                   "\"%s\"\n",
1644                   MAJOR(sb->s_dev), MINOR(sb->s_dev),
1645                   yaffs_devname(sb, devname_buf)));
1646
1647    /* Check it's an mtd device..... */
1648    if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) {
1649        return NULL; /* This isn't an mtd device */
1650    }
1651    /* Get the device */
1652    mtd = get_mtd_device(NULL, MINOR(sb->s_dev));
1653    if (!mtd) {
1654        T(YAFFS_TRACE_ALWAYS,
1655          ("yaffs: MTD device #%u doesn't appear to exist\n",
1656           MINOR(sb->s_dev)));
1657        return NULL;
1658    }
1659    /* Check it's NAND */
1660    if (mtd->type != MTD_NANDFLASH) {
1661        T(YAFFS_TRACE_ALWAYS,
1662          ("yaffs: MTD device is not NAND it's type %d\n", mtd->type));
1663        return NULL;
1664    }
1665
1666    T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase));
1667    T(YAFFS_TRACE_OS, (" read %p\n", mtd->read));
1668    T(YAFFS_TRACE_OS, (" write %p\n", mtd->write));
1669    T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob));
1670    T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob));
1671    T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad));
1672    T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad));
1673    T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd)));
1674    T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize));
1675    T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize));
1676    T(YAFFS_TRACE_OS, (" size %d\n", mtd->size));
1677
1678#ifdef CONFIG_YAFFS_AUTO_YAFFS2
1679
1680    if (yaffsVersion == 1 &&
1681#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1682        mtd->writesize >= 2048) {
1683#else
1684        mtd->oobblock >= 2048) {
1685#endif
1686        T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n"));
1687        yaffsVersion = 2;
1688    }
1689
1690    /* Added NCB 26/5/2006 for completeness */
1691    if (yaffsVersion == 2 &&
1692#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1693        mtd->writesize == 512) {
1694#else
1695        mtd->oobblock == 512) {
1696#endif
1697        T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n"));
1698        yaffsVersion = 1;
1699    }
1700
1701#endif
1702
1703    if (yaffsVersion == 2) {
1704        /* Check for version 2 style functions */
1705        if (!mtd->erase ||
1706            !mtd->block_isbad ||
1707            !mtd->block_markbad ||
1708            !mtd->read ||
1709            !mtd->write ||
1710#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1711            !mtd->read_oob || !mtd->write_oob) {
1712#else
1713            !mtd->write_ecc ||
1714            !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
1715#endif
1716            T(YAFFS_TRACE_ALWAYS,
1717              ("yaffs: MTD device does not support required "
1718               "functions\n"));;
1719            return NULL;
1720        }
1721
1722#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1723        if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
1724#else
1725        if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE ||
1726#endif
1727            mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) {
1728            T(YAFFS_TRACE_ALWAYS,
1729              ("yaffs: MTD device does not have the "
1730               "right page sizes\n"));
1731            return NULL;
1732        }
1733    } else {
1734        /* Check for V1 style functions */
1735        if (!mtd->erase ||
1736            !mtd->read ||
1737            !mtd->write ||
1738#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1739            !mtd->read_oob || !mtd->write_oob) {
1740#else
1741            !mtd->write_ecc ||
1742            !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) {
1743#endif
1744            T(YAFFS_TRACE_ALWAYS,
1745              ("yaffs: MTD device does not support required "
1746               "functions\n"));;
1747            return NULL;
1748        }
1749
1750        if (WRITE_SIZE(mtd) < YAFFS_BYTES_PER_CHUNK ||
1751            mtd->oobsize != YAFFS_BYTES_PER_SPARE) {
1752            T(YAFFS_TRACE_ALWAYS,
1753              ("yaffs: MTD device does not support have the "
1754               "right page sizes\n"));
1755            return NULL;
1756        }
1757    }
1758
1759    /* OK, so if we got here, we have an MTD that's NAND and looks
1760     * like it has the right capabilities
1761     * Set the yaffs_Device up for mtd
1762     */
1763
1764#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1765    sb->s_fs_info = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
1766#else
1767    sb->u.generic_sbp = dev = kmalloc(sizeof(yaffs_Device), GFP_KERNEL);
1768#endif
1769    if (!dev) {
1770        /* Deep shit could not allocate device structure */
1771        T(YAFFS_TRACE_ALWAYS,
1772          ("yaffs_read_super: Failed trying to allocate "
1773           "yaffs_Device. \n"));
1774        return NULL;
1775    }
1776
1777    memset(dev, 0, sizeof(yaffs_Device));
1778    dev->genericDevice = mtd;
1779    dev->name = mtd->name;
1780
1781    /* Set up the memory size parameters.... */
1782
1783    nBlocks = mtd->size / (YAFFS_CHUNKS_PER_BLOCK * YAFFS_BYTES_PER_CHUNK);
1784    dev->startBlock = 0;
1785    dev->endBlock = nBlocks - 1;
1786    dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK;
1787    dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK;
1788    dev->nReservedBlocks = 5;
1789    dev->nShortOpCaches = (options.no_cache) ? 0 : 10;
1790
1791    /* ... and the functions. */
1792    if (yaffsVersion == 2) {
1793        dev->writeChunkWithTagsToNAND =
1794            nandmtd2_WriteChunkWithTagsToNAND;
1795        dev->readChunkWithTagsFromNAND =
1796            nandmtd2_ReadChunkWithTagsFromNAND;
1797        dev->markNANDBlockBad = nandmtd2_MarkNANDBlockBad;
1798        dev->queryNANDBlock = nandmtd2_QueryNANDBlock;
1799        dev->spareBuffer = YMALLOC(mtd->oobsize);
1800        dev->isYaffs2 = 1;
1801#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1802        dev->nDataBytesPerChunk = mtd->writesize;
1803        dev->nChunksPerBlock = mtd->erasesize / mtd->writesize;
1804#else
1805        dev->nDataBytesPerChunk = mtd->oobblock;
1806        dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock;
1807#endif
1808        nBlocks = mtd->size / mtd->erasesize;
1809
1810        dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS;
1811        dev->startBlock = 0;
1812        dev->endBlock = nBlocks - 1;
1813    } else {
1814#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1815        /* use the MTD interface in yaffs_mtdif1.c */
1816        dev->writeChunkWithTagsToNAND =
1817            nandmtd1_WriteChunkWithTagsToNAND;
1818        dev->readChunkWithTagsFromNAND =
1819            nandmtd1_ReadChunkWithTagsFromNAND;
1820        dev->markNANDBlockBad = nandmtd1_MarkNANDBlockBad;
1821        dev->queryNANDBlock = nandmtd1_QueryNANDBlock;
1822#else
1823        dev->writeChunkToNAND = nandmtd_WriteChunkToNAND;
1824        dev->readChunkFromNAND = nandmtd_ReadChunkFromNAND;
1825#endif
1826        dev->isYaffs2 = 0;
1827    }
1828    /* ... and common functions */
1829    dev->eraseBlockInNAND = nandmtd_EraseBlockInNAND;
1830    dev->initialiseNAND = nandmtd_InitialiseNAND;
1831
1832    dev->putSuperFunc = yaffs_MTDPutSuper;
1833
1834    dev->superBlock = (void *)sb;
1835    dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty;
1836
1837
1838#ifndef CONFIG_YAFFS_DOES_ECC
1839    dev->useNANDECC = 1;
1840#endif
1841
1842#ifdef CONFIG_YAFFS_DISABLE_WIDE_TNODES
1843    dev->wideTnodesDisabled = 1;
1844#endif
1845
1846    dev->skipCheckpointRead = options.skip_checkpoint_read;
1847    dev->skipCheckpointWrite = options.skip_checkpoint_write;
1848
1849    /* we assume this is protected by lock_kernel() in mount/umount */
1850    list_add_tail(&dev->devList, &yaffs_dev_list);
1851
1852    init_MUTEX(&dev->grossLock);
1853
1854    yaffs_GrossLock(dev);
1855
1856    err = yaffs_GutsInitialise(dev);
1857
1858    T(YAFFS_TRACE_OS,
1859      ("yaffs_read_super: guts initialised %s\n",
1860       (err == YAFFS_OK) ? "OK" : "FAILED"));
1861
1862    /* Release lock before yaffs_get_inode() */
1863    yaffs_GrossUnlock(dev);
1864
1865    /* Create root inode */
1866    if (err == YAFFS_OK)
1867        inode = yaffs_get_inode(sb, S_IFDIR | 0755, 0,
1868                    yaffs_Root(dev));
1869
1870    if (!inode)
1871        return NULL;
1872
1873    inode->i_op = &yaffs_dir_inode_operations;
1874    inode->i_fop = &yaffs_dir_operations;
1875
1876    T(YAFFS_TRACE_OS, ("yaffs_read_super: got root inode\n"));
1877
1878    root = d_alloc_root(inode);
1879
1880    T(YAFFS_TRACE_OS, ("yaffs_read_super: d_alloc_root done\n"));
1881
1882    if (!root) {
1883        iput(inode);
1884        return NULL;
1885    }
1886    sb->s_root = root;
1887
1888    T(YAFFS_TRACE_OS, ("yaffs_read_super: done\n"));
1889    return sb;
1890}
1891
1892
1893#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1894static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data,
1895                     int silent)
1896{
1897    return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL;
1898}
1899
1900#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1901static int yaffs_read_super(struct file_system_type *fs,
1902                int flags, const char *dev_name,
1903                void *data, struct vfsmount *mnt)
1904{
1905
1906    return get_sb_bdev(fs, flags, dev_name, data,
1907               yaffs_internal_read_super_mtd, mnt);
1908}
1909#else
1910static struct super_block *yaffs_read_super(struct file_system_type *fs,
1911                        int flags, const char *dev_name,
1912                        void *data)
1913{
1914
1915    return get_sb_bdev(fs, flags, dev_name, data,
1916               yaffs_internal_read_super_mtd);
1917}
1918#endif
1919
1920static struct file_system_type yaffs_fs_type = {
1921    .owner = THIS_MODULE,
1922    .name = "yaffs",
1923    .get_sb = yaffs_read_super,
1924    .kill_sb = kill_block_super,
1925    .fs_flags = FS_REQUIRES_DEV,
1926};
1927#else
1928static struct super_block *yaffs_read_super(struct super_block *sb, void *data,
1929                        int silent)
1930{
1931    return yaffs_internal_read_super(1, sb, data, silent);
1932}
1933
1934static DECLARE_FSTYPE(yaffs_fs_type, "yaffs", yaffs_read_super,
1935              FS_REQUIRES_DEV);
1936#endif
1937
1938
1939#ifdef CONFIG_YAFFS_YAFFS2
1940
1941#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
1942static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data,
1943                      int silent)
1944{
1945    return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL;
1946}
1947
1948#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
1949static int yaffs2_read_super(struct file_system_type *fs,
1950            int flags, const char *dev_name, void *data,
1951            struct vfsmount *mnt)
1952{
1953    return get_sb_bdev(fs, flags, dev_name, data,
1954            yaffs2_internal_read_super_mtd, mnt);
1955}
1956#else
1957static struct super_block *yaffs2_read_super(struct file_system_type *fs,
1958                         int flags, const char *dev_name,
1959                         void *data)
1960{
1961
1962    return get_sb_bdev(fs, flags, dev_name, data,
1963               yaffs2_internal_read_super_mtd);
1964}
1965#endif
1966
1967static struct file_system_type yaffs2_fs_type = {
1968    .owner = THIS_MODULE,
1969    .name = "yaffs2",
1970    .get_sb = yaffs2_read_super,
1971    .kill_sb = kill_block_super,
1972    .fs_flags = FS_REQUIRES_DEV,
1973};
1974#else
1975static struct super_block *yaffs2_read_super(struct super_block *sb,
1976                         void *data, int silent)
1977{
1978    return yaffs_internal_read_super(2, sb, data, silent);
1979}
1980
1981static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
1982              FS_REQUIRES_DEV);
1983#endif
1984
1985#endif /* CONFIG_YAFFS_YAFFS2 */
1986
1987static struct proc_dir_entry *my_proc_entry;
1988
1989static char *yaffs_dump_dev(char *buf, yaffs_Device * dev)
1990{
1991    buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock);
1992    buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock);
1993    buf += sprintf(buf, "nDataBytesPerChunk. %d\n", dev->nDataBytesPerChunk);
1994    buf += sprintf(buf, "chunkGroupBits..... %d\n", dev->chunkGroupBits);
1995    buf += sprintf(buf, "chunkGroupSize..... %d\n", dev->chunkGroupSize);
1996    buf += sprintf(buf, "nErasedBlocks...... %d\n", dev->nErasedBlocks);
1997    buf += sprintf(buf, "nReservedBlocks.... %d\n", dev->nReservedBlocks);
1998    buf += sprintf(buf, "nCheckptResBlocks.. %d\n", dev->nCheckpointReservedBlocks);
1999    buf += sprintf(buf, "blocksInCheckpoint. %d\n", dev->blocksInCheckpoint);
2000    buf += sprintf(buf, "nTnodesCreated..... %d\n", dev->nTnodesCreated);
2001    buf += sprintf(buf, "nFreeTnodes........ %d\n", dev->nFreeTnodes);
2002    buf += sprintf(buf, "nObjectsCreated.... %d\n", dev->nObjectsCreated);
2003    buf += sprintf(buf, "nFreeObjects....... %d\n", dev->nFreeObjects);
2004    buf += sprintf(buf, "nFreeChunks........ %d\n", dev->nFreeChunks);
2005    buf += sprintf(buf, "nPageWrites........ %d\n", dev->nPageWrites);
2006    buf += sprintf(buf, "nPageReads......... %d\n", dev->nPageReads);
2007    buf += sprintf(buf, "nBlockErasures..... %d\n", dev->nBlockErasures);
2008    buf += sprintf(buf, "nGCCopies.......... %d\n", dev->nGCCopies);
2009    buf +=
2010        sprintf(buf, "garbageCollections. %d\n", dev->garbageCollections);
2011    buf +=
2012        sprintf(buf, "passiveGCs......... %d\n",
2013            dev->passiveGarbageCollections);
2014    buf += sprintf(buf, "nRetriedWrites..... %d\n", dev->nRetriedWrites);
2015    buf += sprintf(buf, "nShortOpCaches..... %d\n", dev->nShortOpCaches);
2016    buf += sprintf(buf, "nRetireBlocks...... %d\n", dev->nRetiredBlocks);
2017    buf += sprintf(buf, "eccFixed........... %d\n", dev->eccFixed);
2018    buf += sprintf(buf, "eccUnfixed......... %d\n", dev->eccUnfixed);
2019    buf += sprintf(buf, "tagsEccFixed....... %d\n", dev->tagsEccFixed);
2020    buf += sprintf(buf, "tagsEccUnfixed..... %d\n", dev->tagsEccUnfixed);
2021    buf += sprintf(buf, "cacheHits.......... %d\n", dev->cacheHits);
2022    buf += sprintf(buf, "nDeletedFiles...... %d\n", dev->nDeletedFiles);
2023    buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles);
2024    buf +=
2025        sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions);
2026    buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC);
2027    buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2);
2028
2029    return buf;
2030}
2031
2032static int yaffs_proc_read(char *page,
2033               char **start,
2034               off_t offset, int count, int *eof, void *data)
2035{
2036    struct list_head *item;
2037    char *buf = page;
2038    int step = offset;
2039    int n = 0;
2040
2041    /* Get proc_file_read() to step 'offset' by one on each sucessive call.
2042     * We use 'offset' (*ppos) to indicate where we are in devList.
2043     * This also assumes the user has posted a read buffer large
2044     * enough to hold the complete output; but that's life in /proc.
2045     */
2046
2047    *(int *)start = 1;
2048
2049    /* Print header first */
2050    if (step == 0) {
2051        buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__
2052                   "\n%s\n%s\n", yaffs_fs_c_version,
2053                   yaffs_guts_c_version);
2054    }
2055
2056    /* hold lock_kernel while traversing yaffs_dev_list */
2057    lock_kernel();
2058
2059    /* Locate and print the Nth entry. Order N-squared but N is small. */
2060    list_for_each(item, &yaffs_dev_list) {
2061        yaffs_Device *dev = list_entry(item, yaffs_Device, devList);
2062        if (n < step) {
2063            n++;
2064            continue;
2065        }
2066        buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name);
2067        buf = yaffs_dump_dev(buf, dev);
2068        break;
2069    }
2070    unlock_kernel();
2071
2072    return buf - page < count ? buf - page : count;
2073}
2074
2075/**
2076 * Set the verbosity of the warnings and error messages.
2077 *
2078 * Note that the names can only be a..z or _ with the current code.
2079 */
2080
2081static struct {
2082    char *mask_name;
2083    unsigned mask_bitfield;
2084} mask_flags[] = {
2085    {"allocate", YAFFS_TRACE_ALLOCATE},
2086    {"always", YAFFS_TRACE_ALWAYS},
2087    {"bad_blocks", YAFFS_TRACE_BAD_BLOCKS},
2088    {"buffers", YAFFS_TRACE_BUFFERS},
2089    {"bug", YAFFS_TRACE_BUG},
2090    {"checkpt", YAFFS_TRACE_CHECKPOINT},
2091    {"deletion", YAFFS_TRACE_DELETION},
2092    {"erase", YAFFS_TRACE_ERASE},
2093    {"error", YAFFS_TRACE_ERROR},
2094    {"gc_detail", YAFFS_TRACE_GC_DETAIL},
2095    {"gc", YAFFS_TRACE_GC},
2096    {"mtd", YAFFS_TRACE_MTD},
2097    {"nandaccess", YAFFS_TRACE_NANDACCESS},
2098    {"os", YAFFS_TRACE_OS},
2099    {"scan_debug", YAFFS_TRACE_SCAN_DEBUG},
2100    {"scan", YAFFS_TRACE_SCAN},
2101    {"tracing", YAFFS_TRACE_TRACING},
2102
2103    {"verify", YAFFS_TRACE_VERIFY},
2104    {"verify_nand", YAFFS_TRACE_VERIFY_NAND},
2105    {"verify_full", YAFFS_TRACE_VERIFY_FULL},
2106    {"verify_all", YAFFS_TRACE_VERIFY_ALL},
2107
2108    {"write", YAFFS_TRACE_WRITE},
2109    {"all", 0xffffffff},
2110    {"none", 0},
2111    {NULL, 0},
2112};
2113
2114#define MAX_MASK_NAME_LENGTH 40
2115static int yaffs_proc_write(struct file *file, const char *buf,
2116                     unsigned long count, void *data)
2117{
2118    unsigned rg = 0, mask_bitfield;
2119    char *end;
2120    char *mask_name;
2121    const char *x;
2122    char substring[MAX_MASK_NAME_LENGTH+1];
2123    int i;
2124    int done = 0;
2125    int add, len = 0;
2126    int pos = 0;
2127
2128    rg = yaffs_traceMask;
2129
2130    while (!done && (pos < count)) {
2131        done = 1;
2132        while ((pos < count) && isspace(buf[pos])) {
2133            pos++;
2134        }
2135
2136        switch (buf[pos]) {
2137        case '+':
2138        case '-':
2139        case '=':
2140            add = buf[pos];
2141            pos++;
2142            break;
2143
2144        default:
2145            add = ' ';
2146            break;
2147        }
2148        mask_name = NULL;
2149
2150        mask_bitfield = simple_strtoul(buf + pos, &end, 0);
2151        if (end > buf + pos) {
2152            mask_name = "numeral";
2153            len = end - (buf + pos);
2154            pos += len;
2155            done = 0;
2156        } else {
2157            for(x = buf + pos, i = 0;
2158                (*x == '_' || (*x >='a' && *x <= 'z')) &&
2159                i <MAX_MASK_NAME_LENGTH; x++, i++, pos++)
2160                substring[i] = *x;
2161            substring[i] = '\0';
2162
2163            for (i = 0; mask_flags[i].mask_name != NULL; i++) {
2164                if(strcmp(substring,mask_flags[i].mask_name) == 0){
2165                    mask_name = mask_flags[i].mask_name;
2166                    mask_bitfield = mask_flags[i].mask_bitfield;
2167                    done = 0;
2168                    break;
2169                }
2170            }
2171        }
2172
2173        if (mask_name != NULL) {
2174            done = 0;
2175            switch(add) {
2176            case '-':
2177                rg &= ~mask_bitfield;
2178                break;
2179            case '+':
2180                rg |= mask_bitfield;
2181                break;
2182            case '=':
2183                rg = mask_bitfield;
2184                break;
2185            default:
2186                rg |= mask_bitfield;
2187                break;
2188            }
2189        }
2190    }
2191
2192    yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS;
2193
2194    printk("new trace = 0x%08X\n",yaffs_traceMask);
2195
2196    if (rg & YAFFS_TRACE_ALWAYS) {
2197        for (i = 0; mask_flags[i].mask_name != NULL; i++) {
2198            char flag;
2199            flag = ((rg & mask_flags[i].mask_bitfield) == mask_flags[i].mask_bitfield) ? '+' : '-';
2200            printk("%c%s\n", flag, mask_flags[i].mask_name);
2201        }
2202    }
2203
2204    return count;
2205}
2206
2207/* Stuff to handle installation of file systems */
2208struct file_system_to_install {
2209    struct file_system_type *fst;
2210    int installed;
2211};
2212
2213static struct file_system_to_install fs_to_install[] = {
2214//#ifdef CONFIG_YAFFS_YAFFS1
2215    {&yaffs_fs_type, 0},
2216//#endif
2217//#ifdef CONFIG_YAFFS_YAFFS2
2218    {&yaffs2_fs_type, 0},
2219//#endif
2220    {NULL, 0}
2221};
2222
2223static int __init init_yaffs_fs(void)
2224{
2225    int error = 0;
2226    struct file_system_to_install *fsinst;
2227
2228    T(YAFFS_TRACE_ALWAYS,
2229      ("yaffs " __DATE__ " " __TIME__ " Installing. \n"));
2230
2231    /* Install the proc_fs entry */
2232    my_proc_entry = create_proc_entry("yaffs",
2233                           S_IRUGO | S_IFREG,
2234                           &proc_root);
2235
2236    if (my_proc_entry) {
2237        my_proc_entry->write_proc = yaffs_proc_write;
2238        my_proc_entry->read_proc = yaffs_proc_read;
2239        my_proc_entry->data = NULL;
2240    } else {
2241        return -ENOMEM;
2242    }
2243
2244    /* Now add the file system entries */
2245
2246    fsinst = fs_to_install;
2247
2248    while (fsinst->fst && !error) {
2249        error = register_filesystem(fsinst->fst);
2250        if (!error) {
2251            fsinst->installed = 1;
2252        }
2253        fsinst++;
2254    }
2255
2256    /* Any errors? uninstall */
2257    if (error) {
2258        fsinst = fs_to_install;
2259
2260        while (fsinst->fst) {
2261            if (fsinst->installed) {
2262                unregister_filesystem(fsinst->fst);
2263                fsinst->installed = 0;
2264            }
2265            fsinst++;
2266        }
2267    }
2268
2269    return error;
2270}
2271
2272static void __exit exit_yaffs_fs(void)
2273{
2274
2275    struct file_system_to_install *fsinst;
2276
2277    T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
2278                   " removing. \n"));
2279
2280    remove_proc_entry("yaffs", &proc_root);
2281
2282    fsinst = fs_to_install;
2283
2284    while (fsinst->fst) {
2285        if (fsinst->installed) {
2286            unregister_filesystem(fsinst->fst);
2287            fsinst->installed = 0;
2288        }
2289        fsinst++;
2290    }
2291
2292}
2293
2294module_init(init_yaffs_fs)
2295module_exit(exit_yaffs_fs)
2296
2297MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
2298MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
2299MODULE_LICENSE("GPL");
2300

Archive Download this file



interactive