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@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
33const char *yaffs_fs_c_version =
34    "$Id: yaffs_fs.c,v 1.53 2006/10/03 10:13:03 charles Exp $";
35extern 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
81unsigned 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
101static void yaffs_put_super(struct super_block *sb);
102
103static 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))
107static int yaffs_file_flush(struct file *file, fl_owner_t id);
108#else
109static int yaffs_file_flush(struct file *file);
110#endif
111
112static int yaffs_sync_object(struct file *file, struct dentry *dentry,
113			     int datasync);
114
115static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir);
116
117#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
118static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
119			struct nameidata *n);
120static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
121				   struct nameidata *n);
122#else
123static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode);
124static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry);
125#endif
126static int yaffs_link(struct dentry *old_dentry, struct inode *dir,
127		      struct dentry *dentry);
128static int yaffs_unlink(struct inode *dir, struct dentry *dentry);
129static int yaffs_symlink(struct inode *dir, struct dentry *dentry,
130			 const char *symname);
131static int yaffs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
132
133#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
134static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
135		       dev_t dev);
136#else
137static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
138		       int dev);
139#endif
140static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry,
141			struct inode *new_dir, struct dentry *new_dentry);
142static int yaffs_setattr(struct dentry *dentry, struct iattr *attr);
143
144#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
145static int yaffs_sync_fs(struct super_block *sb, int wait);
146static void yaffs_write_super(struct super_block *sb);
147#else
148static int yaffs_sync_fs(struct super_block *sb);
149static int yaffs_write_super(struct super_block *sb);
150#endif
151
152#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
153static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf);
154#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
155static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf);
156#else
157static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
158#endif
159static void yaffs_read_inode(struct inode *inode);
160
161static void yaffs_put_inode(struct inode *inode);
162static void yaffs_delete_inode(struct inode *);
163static void yaffs_clear_inode(struct inode *);
164
165static int yaffs_readpage(struct file *file, struct page *page);
166#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))
167static int yaffs_writepage(struct page *page, struct writeback_control *wbc);
168#else
169static int yaffs_writepage(struct page *page);
170#endif
171static int yaffs_prepare_write(struct file *f, struct page *pg,
172			       unsigned offset, unsigned to);
173static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset,
174			      unsigned to);
175
176static int yaffs_readlink(struct dentry *dentry, char __user * buffer,
177			  int buflen);
178#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
179static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
180#else
181static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd);
182#endif
183
184static 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
191static 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
203static struct inode_operations yaffs_file_inode_operations = {
204	.setattr = yaffs_setattr,
205};
206
207static struct inode_operations yaffs_symlink_inode_operations = {
208	.readlink = yaffs_readlink,
209	.follow_link = yaffs_follow_link,
210	.setattr = yaffs_setattr,
211};
212
213static 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
226static struct file_operations yaffs_dir_operations = {
227	.read = generic_read_dir,
228	.readdir = yaffs_readdir,
229	.fsync = yaffs_sync_object,
230};
231
232static 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
243static void yaffs_GrossLock(yaffs_Device * dev)
244{
245	T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs locking\n"));
246
247	down(&dev->grossLock);
248}
249
250static void yaffs_GrossUnlock(yaffs_Device * dev)
251{
252	T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs unlocking\n"));
253	up(&dev->grossLock);
254
255}
256
257static 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))
280static void *yaffs_follow_link(struct dentry *dentry, struct nameidata *nd)
281#else
282static 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);
303out:
304#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,13))
305	return ERR_PTR (ret);
306#else
307	return ret;
308#endif
309}
310
311struct 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
319static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry,
320				   struct nameidata *n)
321#else
322static 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 */
382static 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 */
391static 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 */
430static 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))
453static int yaffs_file_flush(struct file *file, fl_owner_t id)
454#else
455static 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
475static 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
529static 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
536static 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))
544static int yaffs_writepage(struct page *page, struct writeback_control *wbc)
545#else
546static 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
617static 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
629static 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
666static 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
769struct 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
800static 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
857static 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))
950static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode,
951		       dev_t rdev)
952#else
953static 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
1042static 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))
1057static int yaffs_create(struct inode *dir, struct dentry *dentry, int mode,
1058			struct nameidata *n)
1059#else
1060static 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
1067static 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 */
1097static 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
1140static 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
1172static 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 */
1195static 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
1248static 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))
1276static 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))
1281static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf)
1282{
1283	yaffs_Device *dev = yaffs_SuperToDevice(sb);
1284#else
1285static 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
1326static 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))
1347static void yaffs_write_super(struct super_block *sb)
1348#else
1349static 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))
1361static int yaffs_sync_fs(struct super_block *sb, int wait)
1362#else
1363static 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
1374static 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
1396static LIST_HEAD(yaffs_dev_list);
1397
1398static 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
1429static 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
1442static 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
1451static 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))
1746static 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))
1753static 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
1762static 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
1772static 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
1780static 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
1786static 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))
1794static 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))
1801static 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
1809static 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
1819static 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
1827static 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
1833static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super,
1834		      FS_REQUIRES_DEV);
1835#endif
1836
1837#endif				/* CONFIG_YAFFS_YAFFS2 */
1838
1839static struct proc_dir_entry *my_proc_entry;
1840
1841static 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
1879static 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
1927static 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
1953static 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 */
2035struct file_system_to_install {
2036	struct file_system_type *fst;
2037	int installed;
2038};
2039
2040static 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
2050static 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
2099static 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
2121module_init(init_yaffs_fs)
2122module_exit(exit_yaffs_fs)
2123
2124MODULE_DESCRIPTION("YAFFS2 - a NAND specific flash file system");
2125MODULE_AUTHOR("Charles Manning, Aleph One Ltd., 2002-2006");
2126MODULE_LICENSE("GPL");
2127