X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_fs.c;h=dfa94a2955d0bec53a9af4a3d2d31129e2f1b7c6;hp=7c04ed3a3de175076f27be67fdb3d995a617cda6;hb=859e8e1d2c37dd6ac976640c2d52281002af2c44;hpb=b027e02d89da77f2977c2af70f661274be3c2228 diff --git a/yaffs_fs.c b/yaffs_fs.c index 7c04ed3..dfa94a2 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -32,7 +32,7 @@ */ const char *yaffs_fs_c_version = - "$Id: yaffs_fs.c,v 1.79 2009-03-17 01:12:00 wookey Exp $"; + "$Id: yaffs_fs.c,v 1.87 2009-11-11 02:11:13 charles Exp $"; extern const char *yaffs_guts_c_version; #include @@ -118,7 +118,7 @@ static uint32_t YCALCBLOCKS(uint64_t partition_size, uint32_t block_size) #include "yaffs_mtdif1.h" #include "yaffs_mtdif2.h" -unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS; +unsigned int yaffs_traceMask = YAFFS_TRACE_BAD_BLOCKS | YAFFS_TRACE_ALWAYS; unsigned int yaffs_wr_attempts = YAFFS_WR_ATTEMPTS; unsigned int yaffs_auto_checkpoint = 1; @@ -163,6 +163,11 @@ static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino); #define yaffs_SuperToDevice(sb) ((yaffs_Device *)sb->u.generic_sbp) #endif + +#define update_dir_time(dir) do {\ + (dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \ + } while(0) + static void yaffs_put_super(struct super_block *sb); static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, @@ -360,6 +365,54 @@ static const struct super_operations yaffs_super_ops = { .write_super = yaffs_write_super, }; +/* YAFFS uses two locks per yaffs_Device. + * dirLock: r/w lock Must be held when accessing directory structure. + * grossLock: Lock when accessing yaffs internals. + * + * Locking rules: + * If you're going to take dirLock then you must take if before + * taking grossLock. + * ie. Don't call yaffs_DirLockxxx() while holding grossLock. + * + * Todo: + * Investigate changing to mutexes etc and improve debugging. + */ +static void yaffs_DirLockInitialise(yaffs_Device *dev) +{ + init_rwsem(&dev->dirLock); +} + +static void yaffs_DirLockRead(yaffs_Device *dev) +{ + T(YAFFS_TRACE_OS, ("yaffs locking dir read %p\n", current)); + down_read(&dev->dirLock); + T(YAFFS_TRACE_OS, ("yaffs locked dir read %p\n", current)); +} + +static void yaffs_DirUnlockRead(yaffs_Device *dev) +{ + T(YAFFS_TRACE_OS, ("yaffs unlocking dir read %p\n", current)); + up_read(&dev->dirLock); +} + +static void yaffs_DirLockWrite(yaffs_Device *dev) +{ + T(YAFFS_TRACE_OS, ("yaffs locking dir write %p\n", current)); + down_write(&dev->dirLock); + T(YAFFS_TRACE_OS, ("yaffs locked dir write %p\n", current)); +} + +static void yaffs_DirUnlockWrite(yaffs_Device *dev) +{ + T(YAFFS_TRACE_OS, ("yaffs unlocking dir write %p\n", current)); + up_write(&dev->dirLock); +} + +static void yaffs_GrossLockInitialise(yaffs_Device *dev) +{ + init_MUTEX(&dev->grossLock); +} + static void yaffs_GrossLock(yaffs_Device *dev) { T(YAFFS_TRACE_OS, ("yaffs locking %p\n", current)); @@ -373,6 +426,7 @@ static void yaffs_GrossUnlock(yaffs_Device *dev) up(&dev->grossLock); } + static int yaffs_readlink(struct dentry *dentry, char __user *buffer, int buflen) { @@ -380,12 +434,14 @@ static int yaffs_readlink(struct dentry *dentry, char __user *buffer, int ret; yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; - + + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); if (!alias) return -ENOMEM; @@ -405,11 +461,13 @@ static int yaffs_follow_link(struct dentry *dentry, struct nameidata *nd) int ret; yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); alias = yaffs_GetSymlinkAlias(yaffs_DentryToObject(dentry)); yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); if (!alias) { ret = -ENOMEM; @@ -445,6 +503,7 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) yaffs_Device *dev = yaffs_InodeToObject(dir)->myDev; + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); T(YAFFS_TRACE_OS, @@ -458,6 +517,7 @@ static struct dentry *yaffs_lookup(struct inode *dir, struct dentry *dentry) /* Can't hold gross lock when calling yaffs_get_inode() */ yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); if (obj) { T(YAFFS_TRACE_OS, @@ -521,6 +581,7 @@ static void yaffs_clear_inode(struct inode *inode) if (obj) { dev = obj->myDev; + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); /* Clear the association between the inode and @@ -537,6 +598,7 @@ static void yaffs_clear_inode(struct inode *inode) yaffs_HandleDeferedFree(obj); yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); } } @@ -558,9 +620,11 @@ static void yaffs_delete_inode(struct inode *inode) if (obj) { dev = obj->myDev; + yaffs_DirLockWrite(dev); yaffs_GrossLock(dev); yaffs_DeleteObject(obj); yaffs_GrossUnlock(dev); + yaffs_DirUnlockWrite(dev); } #if (LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 13)) truncate_inode_pages(&inode->i_data, 0); @@ -582,11 +646,13 @@ static int yaffs_file_flush(struct file *file) ("yaffs_file_flush object %d (%s)\n", obj->objectId, obj->dirty ? "dirty" : "clean")); + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); - yaffs_FlushFile(obj, 1); + yaffs_FlushFile(obj, 1,0); yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); return 0; } @@ -619,6 +685,7 @@ static int yaffs_readpage_nolock(struct file *f, struct page *pg) pg_buf = kmap(pg); /* FIXME: Can kmap fail? */ + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); ret = yaffs_ReadDataFromFile(obj, pg_buf, @@ -626,6 +693,7 @@ static int yaffs_readpage_nolock(struct file *f, struct page *pg) PAGE_CACHE_SIZE); yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); if (ret >= 0) ret = 0; @@ -704,6 +772,7 @@ static int yaffs_writepage(struct page *page) buffer = kmap(page); obj = yaffs_InodeToObject(inode); + yaffs_DirLockRead(obj->myDev); yaffs_GrossLock(obj->myDev); T(YAFFS_TRACE_OS, @@ -721,6 +790,7 @@ static int yaffs_writepage(struct page *page) (int)obj->variant.fileVariant.fileSize, (int)inode->i_size)); yaffs_GrossUnlock(obj->myDev); + yaffs_DirUnlockRead(obj->myDev); kunmap(page); SetPageUptodate(page); @@ -746,7 +816,7 @@ static int yaffs_write_begin(struct file *filp, struct address_space *mapping, T(YAFFS_TRACE_OS, ("start yaffs_write_begin\n")); /* Get a page */ -#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 28) +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 28) pg = grab_cache_page_write_begin(mapping, index, flags); #else pg = __grab_cache_page(mapping, index); @@ -1036,6 +1106,7 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, dev = obj->myDev; + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); inode = f->f_dentry->d_inode; @@ -1075,7 +1146,9 @@ static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, } yaffs_GrossUnlock(dev); - return nWritten == 0 ? -ENOSPC : nWritten; + yaffs_DirUnlockRead(dev); + + return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten; } /* Space holding and freeing is done to ensure we have space available for write_begin/end */ @@ -1094,29 +1167,19 @@ static ssize_t yaffs_hold_space(struct file *f) dev = obj->myDev; + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); nFreeChunks = yaffs_GetNumberOfFreeChunks(dev); yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); return (nFreeChunks > 20) ? 1 : 0; } static void yaffs_release_space(struct file *f) { - yaffs_Object *obj; - yaffs_Device *dev; - - - obj = yaffs_DentryToObject(f->f_dentry); - - dev = obj->myDev; - - yaffs_GrossLock(dev); - - - yaffs_GrossUnlock(dev); } static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) @@ -1133,6 +1196,7 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) obj = yaffs_DentryToObject(f->f_dentry); dev = obj->myDev; + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); offset = f->f_pos; @@ -1143,8 +1207,14 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) T(YAFFS_TRACE_OS, ("yaffs_readdir: entry . ino %d \n", (int)inode->i_ino)); + + yaffs_GrossUnlock(dev); + if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0) goto out; + + yaffs_GrossLock(dev); + offset++; f->f_pos++; } @@ -1152,9 +1222,15 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) T(YAFFS_TRACE_OS, ("yaffs_readdir: entry .. ino %d \n", (int)f->f_dentry->d_parent->d_inode->i_ino)); + + yaffs_GrossUnlock(dev); + if (filldir(dirent, "..", 2, offset, f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) goto out; + + yaffs_GrossLock(dev); + offset++; f->f_pos++; } @@ -1181,22 +1257,26 @@ static int yaffs_readdir(struct file *f, void *dirent, filldir_t filldir) ("yaffs_readdir: %s inode %d\n", name, yaffs_GetObjectInode(l))); + yaffs_GrossUnlock(dev); + if (filldir(dirent, name, strlen(name), offset, yaffs_GetObjectInode(l), yaffs_GetObjectType(l)) < 0) - goto up_and_out; + goto out; + + yaffs_GrossLock(dev); offset++; f->f_pos++; } } -up_and_out: -out: yaffs_GrossUnlock(dev); +out: + yaffs_DirUnlockRead(dev); return 0; } @@ -1249,6 +1329,7 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev = parent->myDev; + yaffs_DirLockWrite(dev); yaffs_GrossLock(dev); switch (mode & S_IFMT) { @@ -1282,10 +1363,12 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, /* Can not call yaffs_get_inode() with gross lock held */ yaffs_GrossUnlock(dev); + yaffs_DirUnlockWrite(dev); if (obj) { inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj); d_instantiate(dentry, inode); + update_dir_time(dir); T(YAFFS_TRACE_OS, ("yaffs_mknod created object %d count = %d\n", obj->objectId, atomic_read(&inode->i_count))); @@ -1330,6 +1413,7 @@ static int yaffs_unlink(struct inode *dir, struct dentry *dentry) dev = yaffs_InodeToObject(dir)->myDev; + yaffs_DirLockWrite(dev); yaffs_GrossLock(dev); retVal = yaffs_Unlink(yaffs_InodeToObject(dir), dentry->d_name.name); @@ -1337,11 +1421,17 @@ static int yaffs_unlink(struct inode *dir, struct dentry *dentry) if (retVal == YAFFS_OK) { dentry->d_inode->i_nlink--; dir->i_version++; - yaffs_GrossUnlock(dev); + } + + yaffs_GrossUnlock(dev); + yaffs_DirUnlockWrite(dev); + + if( retVal == YAFFS_OK){ mark_inode_dirty(dentry->d_inode); + update_dir_time(dir); return 0; } - yaffs_GrossUnlock(dev); + return -ENOTEMPTY; } @@ -1361,6 +1451,7 @@ static int yaffs_link(struct dentry *old_dentry, struct inode *dir, obj = yaffs_InodeToObject(inode); dev = obj->myDev; + yaffs_DirLockWrite(dev); yaffs_GrossLock(dev); if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ @@ -1378,9 +1469,12 @@ static int yaffs_link(struct dentry *old_dentry, struct inode *dir, } yaffs_GrossUnlock(dev); + yaffs_DirUnlockWrite(dev); - if (link) + if (link){ + update_dir_time(dir); return 0; + } return -EPERM; } @@ -1396,16 +1490,19 @@ static int yaffs_symlink(struct inode *dir, struct dentry *dentry, T(YAFFS_TRACE_OS, ("yaffs_symlink\n")); dev = yaffs_InodeToObject(dir)->myDev; + yaffs_DirLockWrite(dev); yaffs_GrossLock(dev); obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name, S_IFLNK | S_IRWXUGO, uid, gid, symname); yaffs_GrossUnlock(dev); + yaffs_DirUnlockWrite(dev); if (obj) { struct inode *inode; inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); d_instantiate(dentry, inode); + update_dir_time(dir); T(YAFFS_TRACE_OS, ("symlink created OK\n")); return 0; } else { @@ -1427,9 +1524,11 @@ static int yaffs_sync_object(struct file *file, struct dentry *dentry, dev = obj->myDev; T(YAFFS_TRACE_OS, ("yaffs_sync_object\n")); + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); - yaffs_FlushFile(obj, 1); + yaffs_FlushFile(obj, 1, datasync); yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); return 0; } @@ -1448,6 +1547,7 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, T(YAFFS_TRACE_OS, ("yaffs_rename\n")); dev = yaffs_InodeToObject(old_dir)->myDev; + yaffs_DirLockWrite(dev); yaffs_GrossLock(dev); /* Check if the target is an existing directory that is not empty. */ @@ -1472,13 +1572,17 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, new_dentry->d_name.name); } yaffs_GrossUnlock(dev); + yaffs_DirUnlockWrite(dev); if (retVal == YAFFS_OK) { if (target) { new_dentry->d_inode->i_nlink--; mark_inode_dirty(new_dentry->d_inode); } - + + update_dir_time(old_dir); + if(old_dir != new_dir) + update_dir_time(new_dir); return 0; } else { return -ENOTEMPTY; @@ -1498,6 +1602,7 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) error = inode_change_ok(inode, attr); if (error == 0) { dev = yaffs_InodeToObject(inode)->myDev; + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) == YAFFS_OK) { @@ -1506,6 +1611,7 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) error = -EPERM; } yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); if (!error) error = inode_setattr(inode, attr); } @@ -1529,6 +1635,7 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) T(YAFFS_TRACE_OS, ("yaffs_statfs\n")); + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); buf->f_type = YAFFS_MAGIC; @@ -1579,10 +1686,26 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) buf->f_bavail = buf->f_bfree; yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); return 0; } + +static void yaffs_flush_sb_inodes(struct super_block *sb) +{ + struct inode *iptr; + yaffs_Object *obj; + + list_for_each_entry(iptr,&sb->s_inodes, i_sb_list){ + obj = yaffs_InodeToObject(iptr); + if(obj){ + T(YAFFS_TRACE_OS, ("flushing obj %d\n",obj->objectId)); + yaffs_FlushFile(obj,1,0); + } + } +} + static int yaffs_do_sync_fs(struct super_block *sb) { @@ -1590,14 +1713,17 @@ static int yaffs_do_sync_fs(struct super_block *sb) T(YAFFS_TRACE_OS, ("yaffs_do_sync_fs\n")); if (sb->s_dirt) { + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); if (dev) { yaffs_FlushEntireDeviceCache(dev); + yaffs_flush_sb_inodes(sb); yaffs_CheckpointSave(dev); } yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); sb->s_dirt = 0; } @@ -1657,6 +1783,7 @@ static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) * need to lock again. */ + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); obj = yaffs_FindObjectByNumber(dev, inode->i_ino); @@ -1664,6 +1791,7 @@ static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino) yaffs_FillInodeFromObject(inode, obj); yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); unlock_new_inode(inode); return inode; @@ -1684,6 +1812,7 @@ static void yaffs_read_inode(struct inode *inode) T(YAFFS_TRACE_OS, ("yaffs_read_inode for %d\n", (int)inode->i_ino)); + yaffs_DirLockRead(dev); yaffs_GrossLock(dev); obj = yaffs_FindObjectByNumber(dev, inode->i_ino); @@ -1691,6 +1820,7 @@ static void yaffs_read_inode(struct inode *inode) yaffs_FillInodeFromObject(inode, obj); yaffs_GrossUnlock(dev); + yaffs_DirUnlockRead(dev); } #endif @@ -1707,7 +1837,7 @@ static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) T(YAFFS_TRACE_OS, ("yaffs_remount_fs: %s: RO\n", dev->name)); - + yaffs_DirLockWrite(dev); yaffs_GrossLock(dev); yaffs_FlushEntireDeviceCache(dev); @@ -1718,6 +1848,7 @@ static int yaffs_remount_fs(struct super_block *sb, int *flags, char *data) mtd->sync(mtd); yaffs_GrossUnlock(dev); + yaffs_DirUnlockWrite(dev); } else { T(YAFFS_TRACE_OS, ("yaffs_remount_fs: %s: RW\n", dev->name)); @@ -1733,6 +1864,7 @@ static void yaffs_put_super(struct super_block *sb) T(YAFFS_TRACE_OS, ("yaffs_put_super\n")); + yaffs_DirLockWrite(dev); yaffs_GrossLock(dev); yaffs_FlushEntireDeviceCache(dev); @@ -1745,6 +1877,7 @@ static void yaffs_put_super(struct super_block *sb) yaffs_Deinitialise(dev); yaffs_GrossUnlock(dev); + yaffs_DirUnlockWrite(dev); /* we assume this is protected by lock_kernel() in mount/umount */ ylist_del(&dev->devList); @@ -1783,9 +1916,15 @@ typedef struct { int skip_checkpoint_read; int skip_checkpoint_write; int no_cache; + int tags_ecc_on; + int tags_ecc_overridden; + int lazy_loading_enabled; + int lazy_loading_overridden; + int empty_lost_and_found; + int empty_lost_and_found_overridden; } yaffs_options; -#define MAX_OPT_LEN 20 +#define MAX_OPT_LEN 30 static int yaffs_parse_options(yaffs_options *options, const char *options_str) { char cur_opt[MAX_OPT_LEN + 1]; @@ -1798,6 +1937,9 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str) memset(cur_opt, 0, MAX_OPT_LEN + 1); p = 0; + while(*options_str == ',') + options_str++; + while (*options_str && *options_str != ',') { if (p < MAX_OPT_LEN) { cur_opt[p] = *options_str; @@ -1808,7 +1950,25 @@ static int yaffs_parse_options(yaffs_options *options, const char *options_str) if (!strcmp(cur_opt, "inband-tags")) options->inband_tags = 1; - else if (!strcmp(cur_opt, "no-cache")) + else if (!strcmp(cur_opt, "tags-ecc-off")){ + options->tags_ecc_on = 0; + options->tags_ecc_overridden=1; + } else if (!strcmp(cur_opt, "tags-ecc-on")){ + options->tags_ecc_on = 1; + options->tags_ecc_overridden = 1; + } else if (!strcmp(cur_opt, "lazy-loading-off")){ + options->lazy_loading_enabled = 0; + options->lazy_loading_overridden=1; + } else if (!strcmp(cur_opt, "lazy-loading-on")){ + options->lazy_loading_enabled = 1; + options->lazy_loading_overridden = 1; + } else if (!strcmp(cur_opt, "empty-lost-and-found-off")){ + options->empty_lost_and_found = 0; + options->empty_lost_and_found_overridden=1; + } else if (!strcmp(cur_opt, "empty-lost-and-found-on")){ + options->empty_lost_and_found = 1; + options->empty_lost_and_found_overridden=1; + } else if (!strcmp(cur_opt, "no-cache")) options->no_cache = 1; else if (!strcmp(cur_opt, "no-checkpoint-read")) options->skip_checkpoint_read = 1; @@ -2024,6 +2184,24 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, dev->nShortOpCaches = (options.no_cache) ? 0 : 10; dev->inbandTags = options.inband_tags; +#ifdef CONFIG_YAFFS_DISABLE_LAZY_LOAD + dev->disableLazyLoad = 1; +#endif + if(options.lazy_loading_overridden) + dev->disableLazyLoad = !options.lazy_loading_enabled; + +#ifdef CONFIG_YAFFS_DISABLE_TAGS_ECC + dev->noTagsECC = 1; +#endif + if(options.tags_ecc_overridden) + dev->noTagsECC = !options.tags_ecc_on; + +#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND + dev->emptyLostAndFound = 1; +#endif + if(options.empty_lost_and_found_overridden) + dev->emptyLostAndFound = options.empty_lost_and_found; + /* ... and the functions. */ if (yaffsVersion == 2) { dev->writeChunkWithTagsToNAND = @@ -2083,9 +2261,11 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, /* we assume this is protected by lock_kernel() in mount/umount */ ylist_add_tail(&dev->devList, &yaffs_dev_list); + + yaffs_DirLockInitialise(dev); + yaffs_GrossLockInitialise(dev); - init_MUTEX(&dev->grossLock); - + yaffs_DirLockWrite(dev); yaffs_GrossLock(dev); err = yaffs_GutsInitialise(dev); @@ -2096,6 +2276,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, /* Release lock before yaffs_get_inode() */ yaffs_GrossUnlock(dev); + yaffs_DirUnlockWrite(dev); /* Create root inode */ if (err == YAFFS_OK) @@ -2224,7 +2405,7 @@ static DECLARE_FSTYPE(yaffs2_fs_type, "yaffs2", yaffs2_read_super, static struct proc_dir_entry *my_proc_entry; -static char *yaffs_dump_dev(char *buf, yaffs_Device * dev) +static char *yaffs_dump_dev_part0(char *buf, yaffs_Device * dev) { buf += sprintf(buf, "startBlock......... %d\n", dev->startBlock); buf += sprintf(buf, "endBlock........... %d\n", dev->endBlock); @@ -2259,9 +2440,19 @@ static char *yaffs_dump_dev(char *buf, yaffs_Device * dev) buf += sprintf(buf, "nUnlinkedFiles..... %d\n", dev->nUnlinkedFiles); buf += sprintf(buf, "nBackgroudDeletions %d\n", dev->nBackgroundDeletions); + + return buf; +} + + +static char *yaffs_dump_dev_part1(char *buf, yaffs_Device * dev) +{ buf += sprintf(buf, "useNANDECC......... %d\n", dev->useNANDECC); + buf += sprintf(buf, "noTagsECC.......... %d\n", dev->noTagsECC); buf += sprintf(buf, "isYaffs2........... %d\n", dev->isYaffs2); buf += sprintf(buf, "inbandTags......... %d\n", dev->inbandTags); + buf += sprintf(buf, "emptyLostAndFound.. %d\n", dev->emptyLostAndFound); + buf += sprintf(buf, "disableLazyLoad.... %d\n", dev->disableLazyLoad); return buf; } @@ -2284,27 +2475,35 @@ static int yaffs_proc_read(char *page, *(int *)start = 1; /* Print header first */ - if (step == 0) { + if (step == 0) buf += sprintf(buf, "YAFFS built:" __DATE__ " " __TIME__ "\n%s\n%s\n", yaffs_fs_c_version, yaffs_guts_c_version); - } - - /* hold lock_kernel while traversing yaffs_dev_list */ - lock_kernel(); - - /* Locate and print the Nth entry. Order N-squared but N is small. */ - ylist_for_each(item, &yaffs_dev_list) { - yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList); - if (n < step) { - n++; - continue; + else if (step == 1) + buf += sprintf(buf,"\n"); + else { + step-=2; + + /* hold lock_kernel while traversing yaffs_dev_list */ + lock_kernel(); + + /* Locate and print the Nth entry. Order N-squared but N is small. */ + ylist_for_each(item, &yaffs_dev_list) { + yaffs_Device *dev = ylist_entry(item, yaffs_Device, devList); + if (n < (step & ~1)) { + n+=2; + continue; + } + if((step & 1)==0){ + buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name); + buf = yaffs_dump_dev_part0(buf, dev); + } else + buf = yaffs_dump_dev_part1(buf, dev); + + break; } - buf += sprintf(buf, "\nDevice %d \"%s\"\n", n, dev->name); - buf = yaffs_dump_dev(buf, dev); - break; + unlock_kernel(); } - unlock_kernel(); return buf - page < count ? buf - page : count; } @@ -2349,7 +2548,7 @@ static struct { }; #define MAX_MASK_NAME_LENGTH 40 -static int yaffs_proc_write(struct file *file, const char *buf, +static int yaffs_proc_write_trace_options(struct file *file, const char *buf, unsigned long count, void *data) { unsigned rg = 0, mask_bitfield; @@ -2441,6 +2640,13 @@ static int yaffs_proc_write(struct file *file, const char *buf, return count; } + +static int yaffs_proc_write(struct file *file, const char *buf, + unsigned long count, void *data) +{ + return yaffs_proc_write_trace_options(file, buf, count, data); +} + /* Stuff to handle installation of file systems */ struct file_system_to_install { struct file_system_type *fst;