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