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