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