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