X-Git-Url: http://www.aleph1.co.uk/gitweb/?p=yaffs2.git;a=blobdiff_plain;f=yaffs_fs.c;h=df0870d1afeb2d79765833944ce554774b2c5023;hp=09591117f4f50a91ed323402d8c90ac23d6838bd;hb=2ae22f05374b4cb19202ddaac9fc47458c732f0d;hpb=e1b8e63260986ab7afec3c379e7a320677c95846 diff --git a/yaffs_fs.c b/yaffs_fs.c index 0959111..df0870d 100644 --- a/yaffs_fs.c +++ b/yaffs_fs.c @@ -31,13 +31,15 @@ */ const char *yaffs_fs_c_version = - "$Id: yaffs_fs.c,v 1.46 2006-05-08 10:13:34 charles Exp $"; + "$Id: yaffs_fs.c,v 1.56 2007-01-19 04:07:48 charles Exp $"; extern const char *yaffs_guts_c_version; +#include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) #include +#endif #include #include -#include #include #include #include @@ -66,6 +68,11 @@ extern const char *yaffs_guts_c_version; #define BDEVNAME_SIZE 0 #define yaffs_devname(sb, buf) kdevname(sb->s_dev) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +/* added NCB 26/5/2006 for 2.4.25-vrs2-tcl1 kernel */ +#define __user +#endif + #endif #include @@ -84,7 +91,13 @@ unsigned yaffs_traceMask = YAFFS_TRACE_ALWAYS | /*#define T(x) printk x */ -#define yaffs_InodeToObject(iptr) ((yaffs_Object *)((iptr)->u.generic_ip)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) +#define yaffs_InodeToObjectLV(iptr) (iptr)->i_private +#else +#define yaffs_InodeToObjectLV(iptr) (iptr)->u.generic_ip +#endif + +#define yaffs_InodeToObject(iptr) ((yaffs_Object *)(yaffs_InodeToObjectLV(iptr))) #define yaffs_DentryToObject(dptr) yaffs_InodeToObject((dptr)->d_inode) #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) @@ -98,7 +111,11 @@ static void yaffs_put_super(struct super_block *sb); static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n, loff_t * pos); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +static int yaffs_file_flush(struct file *file, fl_owner_t id); +#else static int yaffs_file_flush(struct file *file); +#endif static int yaffs_sync_object(struct file *file, struct dentry *dentry, int datasync); @@ -132,7 +149,17 @@ static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry); static int yaffs_setattr(struct dentry *dentry, struct iattr *attr); -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +static int yaffs_sync_fs(struct super_block *sb, int wait); +static void yaffs_write_super(struct super_block *sb); +#else +static int yaffs_sync_fs(struct super_block *sb); +static int yaffs_write_super(struct super_block *sb); +#endif + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf); +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf); #else static int yaffs_statfs(struct super_block *sb, struct statfs *buf); @@ -170,8 +197,15 @@ static struct address_space_operations yaffs_file_address_operations = { }; static struct file_operations yaffs_file_operations = { +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)) + .read = do_sync_read, + .write = do_sync_write, + .aio_read = generic_file_aio_read, + .aio_write = generic_file_aio_write, +#else .read = generic_file_read, .write = generic_file_write, +#endif .mmap = generic_file_mmap, .flush = yaffs_file_flush, .fsync = yaffs_sync_object, @@ -217,6 +251,8 @@ static struct super_operations yaffs_super_ops = { .put_super = yaffs_put_super, .delete_inode = yaffs_delete_inode, .clear_inode = yaffs_clear_inode, + .sync_fs = yaffs_sync_fs, + .write_super = yaffs_write_super, }; static void yaffs_GrossLock(yaffs_Device * dev) @@ -387,7 +423,7 @@ static void yaffs_clear_inode(struct inode *inode) * the yaffs_Object. */ obj->myInode = NULL; - inode->u.generic_ip = NULL; + yaffs_InodeToObjectLV(inode) = NULL; /* If the object freeing was deferred, then the real * free happens now. @@ -428,7 +464,11 @@ static void yaffs_delete_inode(struct inode *inode) clear_inode(inode); } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +static int yaffs_file_flush(struct file *file, fl_owner_t id) +#else static int yaffs_file_flush(struct file *file) +#endif { yaffs_Object *obj = yaffs_DentryToObject(file->f_dentry); @@ -641,11 +681,47 @@ static int yaffs_commit_write(struct file *f, struct page *pg, unsigned offset, static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj) { if (inode && obj) { + + + /* Check mode against the variant type and attempt to repair if broken. */ + __u32 mode = obj->yst_mode; + switch( obj->variantType ){ + case YAFFS_OBJECT_TYPE_FILE : + if( ! S_ISREG(mode) ){ + obj->yst_mode &= ~S_IFMT; + obj->yst_mode |= S_IFREG; + } + + break; + case YAFFS_OBJECT_TYPE_SYMLINK : + if( ! S_ISLNK(mode) ){ + obj->yst_mode &= ~S_IFMT; + obj->yst_mode |= S_IFLNK; + } + + break; + case YAFFS_OBJECT_TYPE_DIRECTORY : + if( ! S_ISDIR(mode) ){ + obj->yst_mode &= ~S_IFMT; + obj->yst_mode |= S_IFDIR; + } + + break; + case YAFFS_OBJECT_TYPE_UNKNOWN : + case YAFFS_OBJECT_TYPE_HARDLINK : + case YAFFS_OBJECT_TYPE_SPECIAL : + default: + /* TODO? */ + break; + } + inode->i_ino = obj->objectId; inode->i_mode = obj->yst_mode; inode->i_uid = obj->yst_uid; inode->i_gid = obj->yst_gid; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)) inode->i_blksize = inode->i_sb->s_blocksize; +#endif #if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) inode->i_rdev = old_decode_dev(obj->yst_rdev); @@ -697,7 +773,8 @@ static void yaffs_FillInodeFromObject(struct inode *inode, yaffs_Object * obj) break; } - inode->u.generic_ip = obj; + yaffs_InodeToObjectLV(inode) = obj; + obj->myInode = inode; } else { @@ -905,6 +982,9 @@ static int yaffs_mknod(struct inode *dir, struct dentry *dentry, int mode, int error = -ENOSPC; uid_t uid = current->fsuid; gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; + + if((dir->i_mode & S_ISGID) && S_ISDIR(mode)) + mode |= S_ISGID; if (parent) { T(YAFFS_TRACE_OS, @@ -1210,14 +1290,21 @@ static int yaffs_setattr(struct dentry *dentry, struct iattr *attr) return error; } -#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +static int yaffs_statfs(struct dentry *dentry, struct kstatfs *buf) +{ + yaffs_Device *dev = yaffs_DentryToObject(dentry)->myDev; + struct super_block *sb = dentry->d_sb; +#elif (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0)) static int yaffs_statfs(struct super_block *sb, struct kstatfs *buf) +{ + yaffs_Device *dev = yaffs_SuperToDevice(sb); #else static int yaffs_statfs(struct super_block *sb, struct statfs *buf) -#endif { - yaffs_Device *dev = yaffs_SuperToDevice(sb); +#endif + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_statfs\n")); yaffs_GrossLock(dev); @@ -1225,23 +1312,23 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) buf->f_type = YAFFS_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_namelen = 255; - if (sb->s_blocksize > dev->nBytesPerChunk) { + if (sb->s_blocksize > dev->nDataBytesPerChunk) { buf->f_blocks = (dev->endBlock - dev->startBlock + 1) * dev->nChunksPerBlock / (sb->s_blocksize / - dev->nBytesPerChunk); + dev->nDataBytesPerChunk); buf->f_bfree = yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize / - dev->nBytesPerChunk); + dev->nDataBytesPerChunk); } else { buf->f_blocks = (dev->endBlock - dev->startBlock + - 1) * dev->nChunksPerBlock * (dev->nBytesPerChunk / + 1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk / sb->s_blocksize); buf->f_bfree = - yaffs_GetNumberOfFreeChunks(dev) * (dev->nBytesPerChunk / + yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk / sb->s_blocksize); } buf->f_files = 0; @@ -1252,6 +1339,56 @@ static int yaffs_statfs(struct super_block *sb, struct statfs *buf) return 0; } + +/** +static int yaffs_do_sync_fs(struct super_block *sb) +{ + + yaffs_Device *dev = yaffs_SuperToDevice(sb); + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_do_sync_fs\n")); + + if(sb->s_dirt) { + yaffs_GrossLock(dev); + + if(dev) + yaffs_CheckpointSave(dev); + + yaffs_GrossUnlock(dev); + + sb->s_dirt = 0; + } + return 0; +} +**/ + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +static void yaffs_write_super(struct super_block *sb) +#else +static int yaffs_write_super(struct super_block *sb) +#endif +{ + + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_write_super\n")); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18)) + return 0; /* yaffs_do_sync_fs(sb);*/ +#endif +} + + +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +static int yaffs_sync_fs(struct super_block *sb, int wait) +#else +static int yaffs_sync_fs(struct super_block *sb) +#endif +{ + + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_fs\n")); + + return 0; /* yaffs_do_sync_fs(sb);*/ + +} + + static void yaffs_read_inode(struct inode *inode) { /* NB This is called as a side effect of other functions, but @@ -1280,6 +1417,8 @@ static void yaffs_put_super(struct super_block *sb) { yaffs_Device *dev = yaffs_SuperToDevice(sb); + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_put_super\n")); + yaffs_GrossLock(dev); yaffs_FlushEntireDeviceCache(dev); @@ -1318,6 +1457,15 @@ static void yaffs_MTDPutSuper(struct super_block *sb) } +static void yaffs_MarkSuperBlockDirty(void *vsb) +{ + struct super_block *sb = (struct super_block *)vsb; + + T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_MarkSuperBlockDirty() sb = %p\n",sb)); +// if(sb) +// sb->s_dirt = 1; +} + static struct super_block *yaffs_internal_read_super(int yaffsVersion, struct super_block *sb, void *data, int silent) @@ -1387,7 +1535,11 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, T(YAFFS_TRACE_OS, (" writeoob %p\n", mtd->write_oob)); T(YAFFS_TRACE_OS, (" block_isbad %p\n", mtd->block_isbad)); T(YAFFS_TRACE_OS, (" block_markbad %p\n", mtd->block_markbad)); +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + T(YAFFS_TRACE_OS, (" writesize %d\n", mtd->writesize)); +#else T(YAFFS_TRACE_OS, (" oobblock %d\n", mtd->oobblock)); +#endif T(YAFFS_TRACE_OS, (" oobsize %d\n", mtd->oobsize)); T(YAFFS_TRACE_OS, (" erasesize %d\n", mtd->erasesize)); T(YAFFS_TRACE_OS, (" size %d\n", mtd->size)); @@ -1395,10 +1547,26 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, #ifdef CONFIG_YAFFS_AUTO_YAFFS2 if (yaffsVersion == 1 && +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + mtd->writesize >= 2048) { +#else mtd->oobblock >= 2048) { +#endif T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs2\n")); yaffsVersion = 2; } + + /* Added NCB 26/5/2006 for completeness */ + if (yaffsVersion == 2 && +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + mtd->writesize == 512) { +#else + mtd->oobblock == 512) { +#endif + T(YAFFS_TRACE_ALWAYS,("yaffs: auto selecting yaffs1\n")); + yaffsVersion = 1; + } + #endif if (yaffsVersion == 2) { @@ -1408,15 +1576,23 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, !mtd->block_markbad || !mtd->read || !mtd->write || +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + !mtd->read_oob || !mtd->write_oob) { +#else !mtd->write_ecc || !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { +#endif T(YAFFS_TRACE_ALWAYS, ("yaffs: MTD device does not support required " "functions\n"));; return NULL; } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + if (mtd->writesize < YAFFS_MIN_YAFFS2_CHUNK_SIZE || +#else if (mtd->oobblock < YAFFS_MIN_YAFFS2_CHUNK_SIZE || +#endif mtd->oobsize < YAFFS_MIN_YAFFS2_SPARE_SIZE) { T(YAFFS_TRACE_ALWAYS, ("yaffs: MTD device does not have the " @@ -1428,15 +1604,23 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, if (!mtd->erase || !mtd->read || !mtd->write || +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + !mtd->read_oob || !mtd->write_oob) { +#else !mtd->write_ecc || !mtd->read_ecc || !mtd->read_oob || !mtd->write_oob) { +#endif T(YAFFS_TRACE_ALWAYS, ("yaffs: MTD device does not support required " "functions\n"));; return NULL; } - if (mtd->oobblock != YAFFS_BYTES_PER_CHUNK || +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + if (mtd->writesize < YAFFS_BYTES_PER_CHUNK || +#else + if (mtd->oobblock < YAFFS_BYTES_PER_CHUNK || +#endif mtd->oobsize != YAFFS_BYTES_PER_SPARE) { T(YAFFS_TRACE_ALWAYS, ("yaffs: MTD device does not support have the " @@ -1473,7 +1657,7 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, dev->startBlock = 0; dev->endBlock = nBlocks - 1; dev->nChunksPerBlock = YAFFS_CHUNKS_PER_BLOCK; - dev->nBytesPerChunk = YAFFS_BYTES_PER_CHUNK; + dev->nDataBytesPerChunk = YAFFS_BYTES_PER_CHUNK; dev->nReservedBlocks = 5; dev->nShortOpCaches = 10; /* Enable short op caching */ @@ -1487,12 +1671,17 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, dev->queryNANDBlock = nandmtd2_QueryNANDBlock; dev->spareBuffer = YMALLOC(mtd->oobsize); dev->isYaffs2 = 1; - dev->nBytesPerChunk = mtd->oobblock; +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) + dev->nDataBytesPerChunk = mtd->writesize; + dev->nChunksPerBlock = mtd->erasesize / mtd->writesize; +#else + dev->nDataBytesPerChunk = mtd->oobblock; dev->nChunksPerBlock = mtd->erasesize / mtd->oobblock; +#endif nBlocks = mtd->size / mtd->erasesize; - dev->checkpointStartBlock = 0; - dev->checkpointEndBlock = 20; - dev->startBlock = dev->checkpointEndBlock + 1; + + dev->nCheckpointReservedBlocks = CONFIG_YAFFS_CHECKPOINT_RESERVED_BLOCKS; + dev->startBlock = 0; dev->endBlock = nBlocks - 1; } else { dev->writeChunkToNAND = nandmtd_WriteChunkToNAND; @@ -1504,6 +1693,10 @@ static struct super_block *yaffs_internal_read_super(int yaffsVersion, dev->initialiseNAND = nandmtd_InitialiseNAND; dev->putSuperFunc = yaffs_MTDPutSuper; + + dev->superBlock = (void *)sb; + dev->markSuperBlockDirty = yaffs_MarkSuperBlockDirty; + #ifndef CONFIG_YAFFS_DOES_ECC dev->useNANDECC = 1; @@ -1564,6 +1757,16 @@ static int yaffs_internal_read_super_mtd(struct super_block *sb, void *data, return yaffs_internal_read_super(1, sb, data, silent) ? 0 : -EINVAL; } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +static int yaffs_read_super(struct file_system_type *fs, + int flags, const char *dev_name, + void *data, struct vfsmount *mnt) +{ + + return get_sb_bdev(fs, flags, dev_name, data, + yaffs_internal_read_super_mtd, mnt); +} +#else static struct super_block *yaffs_read_super(struct file_system_type *fs, int flags, const char *dev_name, void *data) @@ -1572,6 +1775,7 @@ static struct super_block *yaffs_read_super(struct file_system_type *fs, return get_sb_bdev(fs, flags, dev_name, data, yaffs_internal_read_super_mtd); } +#endif static struct file_system_type yaffs_fs_type = { .owner = THIS_MODULE, @@ -1601,6 +1805,15 @@ static int yaffs2_internal_read_super_mtd(struct super_block *sb, void *data, return yaffs_internal_read_super(2, sb, data, silent) ? 0 : -EINVAL; } +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17)) +static int yaffs2_read_super(struct file_system_type *fs, + int flags, const char *dev_name, void *data, + struct vfsmount *mnt) +{ + return get_sb_bdev(fs, flags, dev_name, data, + yaffs2_internal_read_super_mtd, mnt); +} +#else static struct super_block *yaffs2_read_super(struct file_system_type *fs, int flags, const char *dev_name, void *data) @@ -1609,6 +1822,7 @@ static struct super_block *yaffs2_read_super(struct file_system_type *fs, return get_sb_bdev(fs, flags, dev_name, data, yaffs2_internal_read_super_mtd); } +#endif static struct file_system_type yaffs2_fs_type = { .owner = THIS_MODULE, @@ -1751,7 +1965,7 @@ static int yaffs_proc_write(struct file *file, const char *buf, char *end, *mask_name; int i; int done = 0; - int add, len; + int add, len = 0; int pos = 0; rg = yaffs_traceMask; @@ -1813,7 +2027,8 @@ static int yaffs_proc_write(struct file *file, const char *buf, } } - yaffs_traceMask = rg; + yaffs_traceMask = rg | YAFFS_TRACE_ALWAYS; + if (rg & YAFFS_TRACE_ALWAYS) { for (i = 0; mask_flags[i].mask_name != NULL; i++) { char flag;