Signed-off-by: Sascha Hauer <s.hauer@xxxxxxxxxxxxxx> --- fs/ubifs/Kconfig | 3 - fs/ubifs/Makefile | 2 +- fs/ubifs/dir.c | 410 ++++++++++++++++++++++++++++++++++++++++++++++ fs/ubifs/super.c | 153 ++--------------- fs/ubifs/ubifs.c | 341 +------------------------------------- fs/ubifs/ubifs.h | 7 +- 6 files changed, 432 insertions(+), 484 deletions(-) create mode 100644 fs/ubifs/dir.c diff --git a/fs/ubifs/Kconfig b/fs/ubifs/Kconfig index 9aa0172289..889a2be97a 100644 --- a/fs/ubifs/Kconfig +++ b/fs/ubifs/Kconfig @@ -1,9 +1,6 @@ menuconfig FS_UBIFS bool depends on MTD_UBI - select FS_LEGACY -# Due to duplicate definition of iput - depends on BROKEN prompt "ubifs support" if FS_UBIFS diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile index e39ae3b0fd..44ef1b561c 100644 --- a/fs/ubifs/Makefile +++ b/fs/ubifs/Makefile @@ -1,4 +1,4 @@ obj-y += ubifs.o io.o super.o sb.o master.o lpt.o -obj-y += lpt_commit.o scan.o lprops.o +obj-y += lpt_commit.o scan.o lprops.o dir.o obj-y += tnc.o tnc_misc.o debug.o crc16.o budget.o obj-y += log.o orphan.o recovery.o replay.o gc.o diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c new file mode 100644 index 0000000000..e90bdb8348 --- /dev/null +++ b/fs/ubifs/dir.c @@ -0,0 +1,410 @@ +/* * This file is part of UBIFS. + * + * Copyright (C) 2006-2008 Nokia Corporation. + * Copyright (C) 2006, 2007 University of Szeged, Hungary + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 as published by + * the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: Artem Bityutskiy (Битюцкий Артём) + * Adrian Hunter + * Zoltan Sogor + */ + +/* + * This file implements directory operations. + * + * All FS operations in this file allocate budget before writing anything to the + * media. If they fail to allocate it, the error is returned. The only + * exceptions are 'ubifs_unlink()' and 'ubifs_rmdir()' which keep working even + * if they unable to allocate the budget, because deletion %-ENOSPC failure is + * not what users are usually ready to get. UBIFS budgeting subsystem has some + * space reserved for these purposes. + * + * All operations in this file write all inodes which they change straight + * away, instead of marking them dirty. For example, 'ubifs_link()' changes + * @i_size of the parent inode and writes the parent inode together with the + * target inode. This was done to simplify file-system recovery which would + * otherwise be very difficult to do. The only exception is rename which marks + * the re-named inode dirty (because its @i_ctime is updated) but does not + * write it, but just marks it as dirty. + */ + +#include "ubifs.h" + +/** + * inherit_flags - inherit flags of the parent inode. + * @dir: parent inode + * @mode: new inode mode flags + * + * This is a helper function for 'ubifs_new_inode()' which inherits flag of the + * parent directory inode @dir. UBIFS inodes inherit the following flags: + * o %UBIFS_COMPR_FL, which is useful to switch compression on/of on + * sub-directory basis; + * o %UBIFS_SYNC_FL - useful for the same reasons; + * o %UBIFS_DIRSYNC_FL - similar, but relevant only to directories. + * + * This function returns the inherited flags. + */ +static int inherit_flags(const struct inode *dir, umode_t mode) +{ + int flags; + const struct ubifs_inode *ui = ubifs_inode(dir); + + if (!S_ISDIR(dir->i_mode)) + /* + * The parent is not a directory, which means that an extended + * attribute inode is being created. No flags. + */ + return 0; + + flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL); + if (!S_ISDIR(mode)) + /* The "DIRSYNC" flag only applies to directories */ + flags &= ~UBIFS_DIRSYNC_FL; + return flags; +} + +/** + * ubifs_new_inode - allocate new UBIFS inode object. + * @c: UBIFS file-system description object + * @dir: parent directory inode + * @mode: inode mode flags + * + * This function finds an unused inode number, allocates new inode and + * initializes it. Returns new inode in case of success and an error code in + * case of failure. + */ +struct inode *ubifs_new_inode(struct ubifs_info *c, const struct inode *dir, + umode_t mode) +{ + struct inode *inode; + struct ubifs_inode *ui; + + inode = new_inode(c->vfs_sb); + ui = ubifs_inode(inode); + if (!inode) + return ERR_PTR(-ENOMEM); + + /* + * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and + * marking them dirty in file write path (see 'file_update_time()'). + * UBIFS has to fully control "clean <-> dirty" transitions of inodes + * to make budgeting work. + */ + inode->i_flags |= S_NOCMTIME; + + switch (mode & S_IFMT) { + case S_IFREG: + inode->i_op = &ubifs_file_inode_operations; + inode->i_fop = &ubifs_file_operations; + break; + case S_IFDIR: + inode->i_op = &ubifs_dir_inode_operations; + inode->i_fop = &ubifs_dir_operations; + inode->i_size = ui->ui_size = UBIFS_INO_NODE_SZ; + break; + case S_IFLNK: + inode->i_op = &ubifs_symlink_inode_operations; + break; + case S_IFSOCK: + case S_IFIFO: + case S_IFBLK: + case S_IFCHR: + inode->i_op = &ubifs_file_inode_operations; + break; + default: + BUG(); + } + + ui->flags = inherit_flags(dir, mode); + ubifs_set_inode_flags(inode); + if (S_ISREG(mode)) + ui->compr_type = c->default_compr; + else + ui->compr_type = UBIFS_COMPR_NONE; + ui->synced_i_size = 0; + + spin_lock(&c->cnt_lock); + /* Inode number overflow is currently not supported */ + if (c->highest_inum >= INUM_WARN_WATERMARK) { + if (c->highest_inum >= INUM_WATERMARK) { + spin_unlock(&c->cnt_lock); + ubifs_err(c, "out of inode numbers"); + iput(inode); + return ERR_PTR(-EINVAL); + } + ubifs_warn(c, "running out of inode numbers (current %lu, max %u)", + (unsigned long)c->highest_inum, INUM_WATERMARK); + } + + inode->i_ino = ++c->highest_inum; + /* + * The creation sequence number remains with this inode for its + * lifetime. All nodes for this inode have a greater sequence number, + * and so it is possible to distinguish obsolete nodes belonging to a + * previous incarnation of the same inode number - for example, for the + * purpose of rebuilding the index. + */ + ui->creat_sqnum = ++c->max_sqnum; + spin_unlock(&c->cnt_lock); + return inode; +} + +static int dbg_check_name(const struct ubifs_info *c, + const struct ubifs_dent_node *dent, + const struct qstr *nm) +{ + if (!dbg_is_chk_gen(c)) + return 0; + if (le16_to_cpu(dent->nlen) != nm->len) + return -EINVAL; + if (memcmp(dent->name, nm->name, nm->len)) + return -EINVAL; + return 0; +} + +static struct dentry *ubifs_lookup(struct inode *dir, struct dentry *dentry, + unsigned int flags) +{ + int err; + union ubifs_key key; + struct inode *inode = NULL; + struct ubifs_dent_node *dent; + struct ubifs_info *c = dir->i_sb->s_fs_info; + + dbg_gen("'%pd' in dir ino %lu", dentry, dir->i_ino); + + if (dentry->d_name.len > UBIFS_MAX_NLEN) + return ERR_PTR(-ENAMETOOLONG); + + dent = kmalloc(UBIFS_MAX_DENT_NODE_SZ, GFP_NOFS); + if (!dent) + return ERR_PTR(-ENOMEM); + + dent_key_init(c, &key, dir->i_ino, &dentry->d_name); + + err = ubifs_tnc_lookup_nm(c, &key, dent, &dentry->d_name); + if (err) { + if (err == -ENOENT) { + dbg_gen("not found"); + goto done; + } + goto out; + } + + if (dbg_check_name(c, dent, &dentry->d_name)) { + err = -EINVAL; + goto out; + } + + inode = ubifs_iget(dir->i_sb, le64_to_cpu(dent->inum)); + if (IS_ERR(inode)) { + /* + * This should not happen. Probably the file-system needs + * checking. + */ + err = PTR_ERR(inode); + ubifs_err(c, "dead directory entry '%pd', error %d", + dentry, err); + ubifs_ro_mode(c, err); + goto out; + } + +done: + kfree(dent); + /* + * Note, d_splice_alias() would be required instead if we supported + * NFS. + */ + d_add(dentry, inode); + return NULL; + +out: + kfree(dent); + return ERR_PTR(err); +} + +/** + * vfs_dent_type - get VFS directory entry type. + * @type: UBIFS directory entry type + * + * This function converts UBIFS directory entry type into VFS directory entry + * type. + */ +static unsigned int vfs_dent_type(uint8_t type) +{ + switch (type) { + case UBIFS_ITYPE_REG: + return DT_REG; + case UBIFS_ITYPE_DIR: + return DT_DIR; + case UBIFS_ITYPE_LNK: + return DT_LNK; + case UBIFS_ITYPE_BLK: + return DT_BLK; + case UBIFS_ITYPE_CHR: + return DT_CHR; + case UBIFS_ITYPE_FIFO: + return DT_FIFO; + case UBIFS_ITYPE_SOCK: + return DT_SOCK; + default: + BUG(); + } + return 0; +} + +/* + * The classical Unix view for directory is that it is a linear array of + * (name, inode number) entries. Linux/VFS assumes this model as well. + * Particularly, 'readdir()' call wants us to return a directory entry offset + * which later may be used to continue 'readdir()'ing the directory or to + * 'seek()' to that specific direntry. Obviously UBIFS does not really fit this + * model because directory entries are identified by keys, which may collide. + * + * UBIFS uses directory entry hash value for directory offsets, so + * 'seekdir()'/'telldir()' may not always work because of possible key + * collisions. But UBIFS guarantees that consecutive 'readdir()' calls work + * properly by means of saving full directory entry name in the private field + * of the file description object. + * + * This means that UBIFS cannot support NFS which requires full + * 'seekdir()'/'telldir()' support. + */ +static int ubifs_readdir(struct file *file, struct dir_context *ctx) +{ + int err = 0; + struct qstr nm; + union ubifs_key key; + struct ubifs_dent_node *dent; + struct dentry *dentry = file->f_path.dentry; + struct inode *dir = d_inode(dentry); + struct ubifs_info *c = dir->i_sb->s_fs_info; + + dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, ctx->pos); + + if (ctx->pos > UBIFS_S_KEY_HASH_MASK || ctx->pos == 2) + /* + * The directory was seek'ed to a senseless position or there + * are no more entries. + */ + return 0; + + if (file->f_version == 0) { + /* + * The file was seek'ed, which means that @file->private_data + * is now invalid. This may also be just the first + * 'ubifs_readdir()' invocation, in which case + * @file->private_data is NULL, and the below code is + * basically a no-op. + */ + kfree(file->private_data); + file->private_data = NULL; + } + + /* + * 'generic_file_llseek()' unconditionally sets @file->f_version to + * zero, and we use this for detecting whether the file was seek'ed. + */ + file->f_version = 1; + + /* File positions 0 and 1 correspond to "." and ".." */ + if (ctx->pos < 2) { + ubifs_assert(!file->private_data); + dir_emit_dots(file, ctx); + + /* Find the first entry in TNC and save it */ + lowest_dent_key(c, &key, dir->i_ino); + nm.name = NULL; + dent = ubifs_tnc_next_ent(c, &key, &nm); + if (IS_ERR(dent)) { + err = PTR_ERR(dent); + goto out; + } + + ctx->pos = key_hash_flash(c, &dent->key); + file->private_data = dent; + } + + dent = file->private_data; + if (!dent) { + /* + * The directory was seek'ed to and is now readdir'ed. + * Find the entry corresponding to @ctx->pos or the closest one. + */ + dent_key_init_hash(c, &key, dir->i_ino, ctx->pos); + nm.name = NULL; + dent = ubifs_tnc_next_ent(c, &key, &nm); + if (IS_ERR(dent)) { + err = PTR_ERR(dent); + goto out; + } + ctx->pos = key_hash_flash(c, &dent->key); + file->private_data = dent; + } + + while (1) { + dbg_gen("feed '%s', ino %llu, new f_pos %#x", + dent->name, (unsigned long long)le64_to_cpu(dent->inum), + key_hash_flash(c, &dent->key)); + ubifs_assert(le64_to_cpu(dent->ch.sqnum) > + ubifs_inode(dir)->creat_sqnum); + + nm.len = le16_to_cpu(dent->nlen); + dir_emit(ctx, dent->name, nm.len, + le64_to_cpu(dent->inum), + vfs_dent_type(dent->type)); + + /* Switch to the next entry */ + key_read(c, &dent->key, &key); + nm.name = dent->name; + dent = ubifs_tnc_next_ent(c, &key, &nm); + if (IS_ERR(dent)) { + err = PTR_ERR(dent); + goto out; + } + + kfree(file->private_data); + ctx->pos = key_hash_flash(c, &dent->key); + file->private_data = dent; + cond_resched(); + } + +out: + kfree(file->private_data); + file->private_data = NULL; + + if (err != -ENOENT) + ubifs_err(c, "cannot find next direntry, error %d", err); + else + /* + * -ENOENT is a non-fatal error in this context, the TNC uses + * it to indicate that the cursor moved past the current directory + * and readdir() has to stop. + */ + err = 0; + + + /* 2 is a special value indicating that there are no more direntries */ + ctx->pos = 2; + return err; +} + +const struct inode_operations ubifs_dir_inode_operations = { + .lookup = ubifs_lookup, +}; + +const struct file_operations ubifs_dir_operations = { + .iterate = ubifs_readdir, +}; diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index b4eb76202b..abf8ef63c9 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -30,6 +30,7 @@ #include <common.h> #include <init.h> +#include <fs.h> #include <malloc.h> #include <linux/bug.h> #include <linux/log2.h> @@ -49,8 +50,6 @@ struct vfsmount; struct super_block *ubifs_sb; LIST_HEAD(super_blocks); -static struct inode *inodes_locked_down[INODE_LOCKED_MAX]; - int set_anon_super(struct super_block *s, void *data) { return 0; @@ -84,39 +83,6 @@ int ubifs_iput(struct inode *inode) return 0; } -/* - * Lock (save) inode in inode array for readback after recovery - */ -void iput(struct inode *inode) -{ - int i; - struct inode *ino; - - /* - * Search end of list - */ - for (i = 0; i < INODE_LOCKED_MAX; i++) { - if (inodes_locked_down[i] == NULL) - break; - } - - if (i >= INODE_LOCKED_MAX) { - dbg_gen("Error, can't lock (save) more inodes while recovery!!!"); - return; - } - - /* - * Allocate and use new inode - */ - ino = (struct inode *)kzalloc(sizeof(struct ubifs_inode), 0); - memcpy(ino, inode, sizeof(struct ubifs_inode)); - - /* - * Finally save inode in array - */ - inodes_locked_down[i] = ino; -} - /* from fs/inode.c */ /** * clear_nlink - directly zero an inode's link count @@ -231,6 +197,9 @@ static int validate_inode(struct ubifs_info *c, const struct inode *inode) return err; } +const struct inode_operations ubifs_file_inode_operations; +const struct file_operations ubifs_file_operations; + struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) { int err; @@ -239,35 +208,9 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) struct ubifs_info *c = sb->s_fs_info; struct inode *inode; struct ubifs_inode *ui; -#ifdef __BAREBOX__ - int i; -#endif dbg_gen("inode %lu", inum); -#ifdef __BAREBOX__ - /* - * U-Boot special handling of locked down inodes via recovery - * e.g. ubifs_recover_size() - */ - for (i = 0; i < INODE_LOCKED_MAX; i++) { - /* - * Exit on last entry (NULL), inode not found in list - */ - if (inodes_locked_down[i] == NULL) - break; - - if (inodes_locked_down[i]->i_ino == inum) { - /* - * We found the locked down inode in our array, - * so just return this pointer instead of creating - * a new one. - */ - return inodes_locked_down[i]; - } - } -#endif - inode = iget_locked(sb, inum); if (!inode) return ERR_PTR(-ENOMEM); @@ -315,10 +258,8 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) if (err) goto out_invalid; -#ifndef __BAREBOX__ switch (inode->i_mode & S_IFMT) { case S_IFREG: - inode->i_mapping->a_ops = &ubifs_file_address_operations; inode->i_op = &ubifs_file_inode_operations; inode->i_fop = &ubifs_file_operations; if (ui->xattr) { @@ -343,7 +284,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) } break; case S_IFLNK: - inode->i_op = &ubifs_symlink_inode_operations; + inode->i_op = &simple_symlink_inode_operations; if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) { err = 12; goto out_invalid; @@ -357,60 +298,10 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) ((char *)ui->data)[ui->data_len] = '\0'; inode->i_link = ui->data; break; - case S_IFBLK: - case S_IFCHR: - { - dev_t rdev; - union ubifs_dev_desc *dev; - - ui->data = kmalloc(sizeof(union ubifs_dev_desc), GFP_NOFS); - if (!ui->data) { - err = -ENOMEM; - goto out_ino; - } - - dev = (union ubifs_dev_desc *)ino->data; - if (ui->data_len == sizeof(dev->new)) - rdev = new_decode_dev(le32_to_cpu(dev->new)); - else if (ui->data_len == sizeof(dev->huge)) - rdev = huge_decode_dev(le64_to_cpu(dev->huge)); - else { - err = 13; - goto out_invalid; - } - memcpy(ui->data, ino->data, ui->data_len); - inode->i_op = &ubifs_file_inode_operations; - init_special_inode(inode, inode->i_mode, rdev); - break; - } - case S_IFSOCK: - case S_IFIFO: - inode->i_op = &ubifs_file_inode_operations; - init_special_inode(inode, inode->i_mode, 0); - if (ui->data_len != 0) { - err = 14; - goto out_invalid; - } - break; default: err = 15; goto out_invalid; } -#else - if ((inode->i_mode & S_IFMT) == S_IFLNK) { - if (ui->data_len <= 0 || ui->data_len > UBIFS_MAX_INO_DATA) { - err = 12; - goto out_invalid; - } - ui->data = kmalloc(ui->data_len + 1, GFP_NOFS); - if (!ui->data) { - err = -ENOMEM; - goto out_ino; - } - memcpy(ui->data, ino->data, ui->data_len); - ((char *)ui->data)[ui->data_len] = '\0'; - } -#endif kfree(ino); #ifndef __BAREBOX__ @@ -447,22 +338,15 @@ static struct inode *ubifs_alloc_inode(struct super_block *sb) return &ui->vfs_inode; }; -#ifndef __BAREBOX__ -static void ubifs_i_callback(struct rcu_head *head) -{ - struct inode *inode = container_of(head, struct inode, i_rcu); - struct ubifs_inode *ui = ubifs_inode(inode); - kmem_cache_free(ubifs_inode_slab, ui); -} - static void ubifs_destroy_inode(struct inode *inode) { struct ubifs_inode *ui = ubifs_inode(inode); kfree(ui->data); - call_rcu(&inode->i_rcu, ubifs_i_callback); + kfree(ui); } +#ifndef __BAREBOX__ /* * Note, Linux write-back code calls this without 'i_mutex'. */ @@ -1330,15 +1214,9 @@ static int mount_ubifs(struct ubifs_info *c) long long x, y; size_t sz; - c->ro_mount = !!(c->vfs_sb->s_flags & MS_RDONLY); + c->ro_mount = true; /* Suppress error messages while probing if MS_SILENT is set */ c->probing = !!(c->vfs_sb->s_flags & MS_SILENT); -#ifdef __BAREBOX__ - if (!c->ro_mount) { - printf("UBIFS: only ro mode in Barebox allowed.\n"); - return -EACCES; - } -#endif err = init_constants_early(c); if (err) @@ -2099,8 +1977,8 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) const struct super_operations ubifs_super_operations = { .alloc_inode = ubifs_alloc_inode, -#ifndef __BAREBOX__ .destroy_inode = ubifs_destroy_inode, +#ifndef __BAREBOX__ .put_super = ubifs_put_super, .write_inode = ubifs_write_inode, .evict_inode = ubifs_evict_inode, @@ -2298,15 +2176,11 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) goto out_umount; } -#ifndef __BAREBOX__ sb->s_root = d_make_root(root); if (!sb->s_root) { err = -ENOMEM; goto out_umount; } -#else - sb->s_root = NULL; -#endif mutex_unlock(&c->umount_mutex); return 0; @@ -2680,13 +2554,14 @@ MODULE_AUTHOR("Artem Bityutskiy, Adrian Hunter"); MODULE_DESCRIPTION("UBIFS - UBI File System"); #endif -struct super_block *ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent) +int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent) { + struct fs_device_d *fsdev = dev_to_fs_device(dev); struct super_block *sb; struct ubifs_info *c; int err; - sb = alloc_super(NULL, MS_RDONLY | MS_ACTIVE | MS_NOATIME); + sb = &fsdev->sb; c = alloc_ubifs_info(ubi); c->dev = dev; @@ -2712,9 +2587,9 @@ struct super_block *ubifs_get_super(struct device_d *dev, struct ubi_volume_desc goto out; } - return sb; + return 0; out: kfree(c); kfree(sb); - return ERR_PTR(err); + return err; } diff --git a/fs/ubifs/ubifs.c b/fs/ubifs/ubifs.c index a525b044b8..f9b4f4babc 100644 --- a/fs/ubifs/ubifs.c +++ b/fs/ubifs/ubifs.c @@ -269,161 +269,6 @@ int __init ubifs_compressors_init(void) return 0; } -/* - * ubifsls... - */ - -static int ubifs_finddir(struct super_block *sb, char *dirname, - unsigned long root_inum, unsigned long *inum) -{ - int err; - struct qstr nm; - union ubifs_key key; - struct ubifs_dent_node *dent; - struct ubifs_info *c; - struct file *file; - struct dentry *dentry; - struct inode *dir; - int ret = 0; - - file = kzalloc(sizeof(struct file), 0); - dentry = kzalloc(sizeof(struct dentry), 0); - dir = kzalloc(sizeof(struct inode), 0); - if (!file || !dentry || !dir) { - printf("%s: Error, no memory for malloc!\n", __func__); - err = -ENOMEM; - goto out; - } - - dir->i_sb = sb; - file->f_path.dentry = dentry; - file->f_path.dentry->d_parent = dentry; - file->f_path.dentry->d_inode = dir; - file->f_path.dentry->d_inode->i_ino = root_inum; - c = sb->s_fs_info; - - dbg_gen("dir ino %lu, f_pos %#llx", dir->i_ino, file->f_pos); - - /* Find the first entry in TNC and save it */ - lowest_dent_key(c, &key, dir->i_ino); - nm.name = NULL; - dent = ubifs_tnc_next_ent(c, &key, &nm); - if (IS_ERR(dent)) { - err = PTR_ERR(dent); - goto out; - } - - file->f_pos = key_hash_flash(c, &dent->key); - file->private_data = dent; - - while (1) { - dbg_gen("feed '%s', ino %llu, new f_pos %#x", - dent->name, (unsigned long long)le64_to_cpu(dent->inum), - key_hash_flash(c, &dent->key)); - ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(dir)->creat_sqnum); - - nm.len = le16_to_cpu(dent->nlen); - if ((strncmp(dirname, (char *)dent->name, nm.len) == 0) && - (strlen(dirname) == nm.len)) { - *inum = le64_to_cpu(dent->inum); - ret = 1; - goto out_free; - } - - /* Switch to the next entry */ - key_read(c, &dent->key, &key); - nm.name = (char *)dent->name; - dent = ubifs_tnc_next_ent(c, &key, &nm); - if (IS_ERR(dent)) { - err = PTR_ERR(dent); - goto out; - } - - kfree(file->private_data); - file->f_pos = key_hash_flash(c, &dent->key); - file->private_data = dent; - cond_resched(); - } - -out: - if (err != -ENOENT) - dbg_gen("cannot find next direntry, error %d", err); - -out_free: - if (file->private_data) - kfree(file->private_data); - if (file) - free(file); - if (dentry) - free(dentry); - if (dir) - free(dir); - - return ret; -} - -static unsigned long ubifs_findfile(struct super_block *sb, const char *filename) -{ - int ret; - char *next; - char fpath[128]; - char *name = fpath; - unsigned long root_inum = 1; - unsigned long inum; - - strcpy(fpath, filename); - - /* Remove all leading slashes */ - while (*name == '/') - name++; - - /* - * Handle root-direcoty ('/') - */ - inum = root_inum; - if (!name || *name == '\0') - return inum; - - for (;;) { - struct inode *inode; - struct ubifs_inode *ui; - - /* Extract the actual part from the pathname. */ - next = strchr(name, '/'); - if (next) { - /* Remove all leading slashes. */ - while (*next == '/') - *(next++) = '\0'; - } - - ret = ubifs_finddir(sb, name, root_inum, &inum); - if (!ret) - return 0; - inode = ubifs_iget(sb, inum); - - if (IS_ERR(inode)) - return 0; - ui = ubifs_inode(inode); - - /* - * Check if directory with this name exists - */ - - /* Found the node! */ - if (!next || *next == '\0') - return inum; - - root_inum = inum; - name = next; - } - - return 0; -} - -/* - * ubifsload... - */ - /* file.c */ static inline void *kmap(struct page *page) @@ -487,18 +332,8 @@ struct ubifs_file { static int ubifs_open(struct device_d *dev, FILE *file, const char *filename) { - struct ubifs_priv *priv = dev->priv; - struct inode *inode; + struct inode *inode = file->f_inode; struct ubifs_file *uf; - unsigned long inum; - - inum = ubifs_findfile(priv->sb, filename); - if (!inum) - return -ENOENT; - - inode = ubifs_iget(priv->sb, inum); - if (IS_ERR(inode)) - return -ENOENT; uf = xzalloc(sizeof(*uf)); @@ -516,9 +351,6 @@ static int ubifs_open(struct device_d *dev, FILE *file, const char *filename) static int ubifs_close(struct device_d *dev, FILE *f) { struct ubifs_file *uf = f->priv; - struct inode *inode = uf->inode; - - ubifs_iput(inode); free(uf->buf); free(uf->dn); @@ -596,163 +428,6 @@ static loff_t ubifs_lseek(struct device_d *dev, FILE *f, loff_t pos) return pos; } -struct ubifs_dir { - struct file file; - struct dentry dentry; - struct inode inode; - DIR dir; - union ubifs_key key; - struct ubifs_dent_node *dent; - struct ubifs_priv *priv; - struct qstr nm; -}; - -static DIR *ubifs_opendir(struct device_d *dev, const char *pathname) -{ - struct ubifs_priv *priv = dev->priv; - struct ubifs_dir *dir; - struct file *file; - struct dentry *dentry; - struct inode *inode; - unsigned long inum; - struct ubifs_info *c = priv->sb->s_fs_info; - - inum = ubifs_findfile(priv->sb, pathname); - if (!inum) - return NULL; - - inode = ubifs_iget(priv->sb, inum); - if (IS_ERR(inode)) - return NULL; - - ubifs_iput(inode); - - dir = xzalloc(sizeof(*dir)); - - dir->priv = priv; - - file = &dir->file; - dentry = &dir->dentry; - inode = &dir->inode; - - inode->i_sb = priv->sb; - file->f_path.dentry = dentry; - file->f_path.dentry->d_parent = dentry; - file->f_path.dentry->d_inode = inode; - file->f_path.dentry->d_inode->i_ino = inum; - file->f_pos = 1; - - /* Find the first entry in TNC and save it */ - lowest_dent_key(c, &dir->key, inode->i_ino); - - return &dir->dir; -} - -static struct dirent *ubifs_readdir(struct device_d *dev, DIR *_dir) -{ - struct ubifs_dir *dir = container_of(_dir, struct ubifs_dir, dir); - struct ubifs_info *c = dir->priv->sb->s_fs_info; - struct ubifs_dent_node *dent; - struct qstr *nm = &dir->nm; - struct file *file = &dir->file; - - dent = ubifs_tnc_next_ent(c, &dir->key, nm); - if (IS_ERR(dent)) - return NULL; - - debug("feed '%s', ino %llu, new f_pos %#x\n", - dent->name, (unsigned long long)le64_to_cpu(dent->inum), - key_hash_flash(c, &dent->key)); - - ubifs_assert(le64_to_cpu(dent->ch.sqnum) > ubifs_inode(&dir->inode)->creat_sqnum); - - key_read(c, &dent->key, &dir->key); - file->f_pos = key_hash_flash(c, &dent->key); - file->private_data = dent; - - nm->len = le16_to_cpu(dent->nlen); - nm->name = dent->name; - - strcpy(_dir->d.d_name, dent->name); - - free(dir->dent); - dir->dent = dent; - - return &_dir->d; -} - -static int ubifs_closedir(struct device_d *dev, DIR *_dir) -{ - struct ubifs_dir *dir = container_of(_dir, struct ubifs_dir, dir); - - free(dir->dent); - free(dir); - - return 0; -} - -static int ubifs_stat(struct device_d *dev, const char *filename, struct stat *s) -{ - struct ubifs_priv *priv = dev->priv; - struct inode *inode; - unsigned long inum; - - inum = ubifs_findfile(priv->sb, filename); - if (!inum) - return -ENOENT; - - inode = ubifs_iget(priv->sb, inum); - if (IS_ERR(inode)) - return -ENOENT; - - s->st_size = inode->i_size; - s->st_mode = inode->i_mode; - - ubifs_iput(inode); - - return 0; -} - -static char *ubifs_symlink(struct inode *inode) -{ - struct ubifs_inode *ui; - char *symlink; - - ui = ubifs_inode(inode); - symlink = malloc(ui->data_len + 1); - - memcpy(symlink, ui->data, ui->data_len); - symlink[ui->data_len] = '\0'; - - return symlink; -} - -static int ubifs_readlink(struct device_d *dev, const char *pathname, char *buf, - size_t bufsz) -{ - struct ubifs_priv *priv = dev->priv; - struct inode *inode; - char *symlink; - int len; - unsigned long inum; - - inum = ubifs_findfile(priv->sb, pathname); - if (!inum) - return -ENOENT; - - inode = ubifs_iget(priv->sb, inum); - if (!inode) - return -ENOENT; - - symlink = ubifs_symlink(inode); - - len = min(bufsz, strlen(symlink)); - memcpy(buf, symlink, len); - free(symlink); - - return 0; -} - void ubifs_set_rootarg(struct ubifs_priv *priv, struct fs_device_d *fsdev) { struct ubi_volume_info vi = {}; @@ -795,11 +470,11 @@ static int ubifs_probe(struct device_d *dev) goto err_free; } - priv->sb = ubifs_get_super(dev, priv->ubi, 0); - if (IS_ERR(priv->sb)) { - ret = PTR_ERR(priv->sb); + ret = ubifs_get_super(dev, priv->ubi, 0); + if (ret) goto err; - } + + priv->sb = &fsdev->sb; ubifs_set_rootarg(priv, fsdev); @@ -821,7 +496,6 @@ static void ubifs_remove(struct device_d *dev) ubi_close_volume(priv->ubi); free(c); - free(sb); free(priv); } @@ -831,11 +505,6 @@ static struct fs_driver_d ubifs_driver = { .close = ubifs_close, .read = ubifs_read, .lseek = ubifs_lseek, - .opendir = ubifs_opendir, - .readdir = ubifs_readdir, - .closedir = ubifs_closedir, - .stat = ubifs_stat, - .readlink = ubifs_readlink, .type = filetype_ubifs, .flags = 0, .drv = { diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 22b24a1161..4c4c927de9 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -36,6 +36,7 @@ #include <lzo.h> #include <crc.h> #include <linux/fs.h> +#include <linux/stat.h> #include <linux/sched.h> #include <linux/ctype.h> #include <linux/time.h> @@ -49,11 +50,9 @@ #define crc32(seed, data, length) crc32_no_comp(seed, (unsigned char const *)data, length) -struct dentry; struct file; struct iattr; struct kstat; -struct vfsmount; extern struct super_block *ubifs_sb; @@ -72,8 +71,6 @@ struct page { struct inode *inode; }; -void iput(struct inode *inode); - struct kmem_cache { int sz; }; struct kmem_cache *get_mem(int element_sz); @@ -1901,7 +1898,7 @@ int ubifs_decompress(const struct ubifs_info *c, const void *buf, int len, #ifdef __BAREBOX__ void ubifs_umount(struct ubifs_info *c); -struct super_block *ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent); +int ubifs_get_super(struct device_d *dev, struct ubi_volume_desc *ubi, int silent); #endif #endif /* !__UBIFS_H__ */ -- 2.17.1 _______________________________________________ barebox mailing list barebox@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/barebox