📄 yaffs_fs.c
字号:
* Create a link... */static int yaffs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry){ struct inode *inode = old_dentry->d_inode; yaffs_Object *obj = NULL; yaffs_Object *link = NULL; yaffs_Device *dev; T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_link\n")); obj = yaffs_InodeToObject(inode); dev = obj->myDev; yaffs_GrossLock(dev); if (!S_ISDIR(inode->i_mode)) /* Don't link directories */ { link = yaffs_Link(yaffs_InodeToObject(dir), dentry->d_name.name, obj); } if (link) { old_dentry->d_inode->i_nlink = yaffs_GetObjectLinkCount(obj); d_instantiate(dentry, old_dentry->d_inode); atomic_inc(&old_dentry->d_inode->i_count); T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_link link count %d i_count %d\n", old_dentry->d_inode->i_nlink, atomic_read(&old_dentry->d_inode->i_count))); } yaffs_GrossUnlock(dev); if (link) { return 0; } return -EPERM;}static int yaffs_symlink(struct inode *dir, struct dentry *dentry, const char *symname){ yaffs_Object *obj; yaffs_Device *dev; uid_t uid = current->fsuid; gid_t gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid; T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_symlink\n")); dev = yaffs_InodeToObject(dir)->myDev; yaffs_GrossLock(dev); obj = yaffs_MknodSymLink(yaffs_InodeToObject(dir), dentry->d_name.name, S_IFLNK | S_IRWXUGO, uid, gid, symname); yaffs_GrossUnlock(dev); if (obj) { struct inode *inode; inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj); d_instantiate(dentry, inode); T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink created OK\n")); return 0; } else { T(YAFFS_TRACE_OS, (KERN_DEBUG "symlink not created\n")); } return -ENOMEM;}static int yaffs_sync_object(struct file *file, struct dentry *dentry, int datasync){ yaffs_Object *obj; yaffs_Device *dev; obj = yaffs_DentryToObject(dentry); dev = obj->myDev; T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_sync_object\n")); yaffs_GrossLock(dev); yaffs_FlushFile(obj, 1); yaffs_GrossUnlock(dev); return 0;}/* * The VFS layer already does all the dentry stuff for rename. * * NB: POSIX says you can rename an object over an old object of the same name */static int yaffs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry){ yaffs_Device *dev; int retVal = YAFFS_FAIL; yaffs_Object *target; T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_rename\n")); dev = yaffs_InodeToObject(old_dir)->myDev; yaffs_GrossLock(dev); /* Check if the target is an existing directory that is not empty. */ target = yaffs_FindObjectByName(yaffs_InodeToObject(new_dir), new_dentry->d_name.name); if (target && target->variantType == YAFFS_OBJECT_TYPE_DIRECTORY && !list_empty(&target->variant.directoryVariant.children)) { T(YAFFS_TRACE_OS, (KERN_DEBUG "target is non-empty dir\n")); retVal = YAFFS_FAIL; } else { /* Now does unlinking internally using shadowing mechanism */ T(YAFFS_TRACE_OS, (KERN_DEBUG "calling yaffs_RenameObject\n")); retVal = yaffs_RenameObject(yaffs_InodeToObject(old_dir), old_dentry->d_name.name, yaffs_InodeToObject(new_dir), new_dentry->d_name.name); } yaffs_GrossUnlock(dev); if (retVal == YAFFS_OK) { if(target) { new_dentry->d_inode->i_nlink--; mark_inode_dirty(new_dentry->d_inode); } return 0; } else { return -ENOTEMPTY; }}static int yaffs_setattr(struct dentry *dentry, struct iattr *attr){ struct inode *inode = dentry->d_inode; int error; yaffs_Device *dev; T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_setattr of object %d\n", yaffs_InodeToObject(inode)->objectId)); if ((error = inode_change_ok(inode, attr)) == 0) { dev = yaffs_InodeToObject(inode)->myDev; yaffs_GrossLock(dev); if (yaffs_SetAttributes(yaffs_InodeToObject(inode), attr) == YAFFS_OK) { error = 0; } else { error = -EPERM; } yaffs_GrossUnlock(dev); if (!error) error = inode_setattr(inode, attr); } return error;}#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);#elsestatic int yaffs_statfs(struct super_block *sb, struct statfs *buf){ yaffs_Device *dev = yaffs_SuperToDevice(sb);#endif T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_statfs\n")); yaffs_GrossLock(dev); buf->f_type = YAFFS_MAGIC; buf->f_bsize = sb->s_blocksize; buf->f_namelen = 255; if (sb->s_blocksize > dev->nDataBytesPerChunk) { buf->f_blocks = (dev->endBlock - dev->startBlock + 1) * dev->nChunksPerBlock / (sb->s_blocksize / dev->nDataBytesPerChunk); buf->f_bfree = yaffs_GetNumberOfFreeChunks(dev) / (sb->s_blocksize / dev->nDataBytesPerChunk); } else { buf->f_blocks = (dev->endBlock - dev->startBlock + 1) * dev->nChunksPerBlock * (dev->nDataBytesPerChunk / sb->s_blocksize); buf->f_bfree = yaffs_GetNumberOfFreeChunks(dev) * (dev->nDataBytesPerChunk / sb->s_blocksize); } buf->f_files = 0; buf->f_ffree = 0; buf->f_bavail = buf->f_bfree; yaffs_GrossUnlock(dev); 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)#elsestatic 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)#elsestatic 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 * we had to release the lock to prevent deadlocks, so * need to lock again. */ yaffs_Object *obj; yaffs_Device *dev = yaffs_SuperToDevice(inode->i_sb); T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_read_inode for %d\n", (int)inode->i_ino)); yaffs_GrossLock(dev); obj = yaffs_FindObjectByNumber(dev, inode->i_ino); yaffs_FillInodeFromObject(inode, obj); yaffs_GrossUnlock(dev);}static LIST_HEAD(yaffs_dev_list);#if 0 // not usedstatic int yaffs_remount_fs(struct super_block *sb, int *flags, char *data){ yaffs_Device *dev = yaffs_SuperToDevice(sb); if( *flags & MS_RDONLY ) { struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_remount_fs: %s: RO\n", dev->name )); yaffs_GrossLock(dev); yaffs_FlushEntireDeviceCache(dev); yaffs_CheckpointSave(dev); if (mtd->sync) mtd->sync(mtd); yaffs_GrossUnlock(dev); } else { T(YAFFS_TRACE_OS, (KERN_DEBUG "yaffs_remount_fs: %s: RW\n", dev->name )); } return 0;}#endifstatic 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); yaffs_CheckpointSave(dev); if (dev->putSuperFunc) { dev->putSuperFunc(sb); } yaffs_Deinitialise(dev); yaffs_GrossUnlock(dev); /* we assume this is protected by lock_kernel() in mount/umount */ list_del(&dev->devList); if(dev->spareBuffer){ YFREE(dev->spareBuffer); dev->spareBuffer = NULL; } kfree(dev);}static void yaffs_MTDPutSuper(struct super_block *sb){ struct mtd_info *mtd = yaffs_SuperToDevice(sb)->genericDevice; if (mtd->sync) { mtd->sync(mtd); } put_mtd_device(mtd);}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;}typedef struct { int inband_tags; int skip_checkpoint_read; int skip_checkpoint_write; int no_cache;} yaffs_options;#define MAX_OPT_LEN 20static int yaffs_parse_options(yaffs_options *options, const char *options_str){ char cur_opt[MAX_OPT_LEN+1]; int p; int error = 0; /* Parse through the options which is a comma seperated list */ while(options_str && *options_str && !error){ memset(cur_opt,0,MAX_OPT_LEN+1); p = 0; while(*options_str && *options_str != ','){ if(p < MAX_OPT_LEN){ cur_opt[p] = *options_str; p++; } options_str++; } if(!strcmp(cur_opt,"inband-tags")) options->inband_tags = 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; else if(!strcmp(cur_opt,"no-checkpoint-write")) options->skip_checkpoint_write = 1; else if(!strcmp(cur_opt,"no-checkpoint")){ options->skip_checkpoint_read = 1; options->skip_checkpoint_write = 1; } else { printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",cur_opt); error = 1; } } return error;}static struct super_block *yaffs_internal_read_super(int yaffsVersion, struct super_block *sb, void *data, int silent){ int nBlocks; struct inode *inode = NULL; struct dentry *root; yaffs_Device *dev = 0; char devname_buf[BDEVNAME_SIZE + 1]; struct mtd_info *mtd; int err; char *data_str = (char *)data; yaffs_options options; sb->s_magic = YAFFS_MAGIC; sb->s_op = &yaffs_super_ops; if (!sb) printk(KERN_INFO "yaffs: sb is NULL\n"); else if (!sb->s_dev) printk(KERN_INFO "yaffs: sb->s_dev is NULL\n"); else if (!yaffs_devname(sb, devname_buf)) printk(KERN_INFO "yaffs: devname is NULL\n"); else printk(KERN_INFO "yaffs: dev is %d name is \"%s\"\n", sb->s_dev, yaffs_devname(sb, devname_buf)); if(!data_str) data_str = ""; printk(KERN_INFO "yaffs: passed flags \"%s\"\n",data_str); memset(&options,0,sizeof(options)); if(yaffs_parse_options(&options,data_str)){ /* Option parsing failed */ return NULL; } sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; T(YAFFS_TRACE_OS, ("yaffs_read_super: Using yaffs%d\n", yaffsVersion)); T(YAFFS_TRACE_OS, ("yaffs_read_super: block size %d\n", (int)(sb->s_blocksize)));#ifdef CONFIG_YAFFS_DISABLE_WRITE_VERIFY T(YAFFS_TRACE_OS, ("yaffs: Write verification disabled. All guarantees " "null and void\n"));#endif T(YAFFS_TRACE_ALWAYS, ("yaffs: Attempting MTD mount on %u.%u, " "\"%s\"\n", MAJOR(sb->s_dev), MINOR(sb->s_dev), yaffs_devname(sb, devname_buf))); /* Check it's an mtd device..... */ if (MAJOR(sb->s_dev) != MTD_BLOCK_MAJOR) { return NULL; /* This isn't an mtd device */ } /* Get the device */ mtd = get_mtd_device(NULL, MINOR(sb->s_dev)); if (!mtd) { T(YAFFS_TRACE_ALWAYS, ("yaffs: MTD device #%u doesn't appear to exist\n", MINOR(sb->s_dev))); return NULL; } /* Check it's NAND */ if (mtd->type != MTD_NANDFLASH) { T(YAFFS_TRACE_ALWAYS, ("yaffs: MTD device is not NAND it's type %d\n", mtd->type)); return NULL; } T(YAFFS_TRACE_OS, (" erase %p\n", mtd->erase)); T(YAFFS_TRACE_OS, (" read %p\n", mtd->read)); T(YAFFS_TRACE_OS, (" write %p\n", mtd->write)); T(YAFFS_TRACE_OS, (" readoob %p\n", mtd->read_oob)); 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)); T(YAFFS_TRACE_OS, (" %s %d\n", WRITE_SIZE_STR, WRITE_SIZE(mtd))); 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)); #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) { /* Check for version 2 style functions */ if (!mtd->erase || !mtd->block_isbad || !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 ||
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -