From: Sascha Hauer <s.hauer@pengutronix.de>
To: Barebox List <barebox@lists.infradead.org>
Subject: [PATCH 05/10] fs: ubifs: Switch to dentry cache implementation
Date: Thu, 31 May 2018 17:04:37 +0200 [thread overview]
Message-ID: <20180531150442.16208-6-s.hauer@pengutronix.de> (raw)
In-Reply-To: <20180531150442.16208-1-s.hauer@pengutronix.de>
Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
---
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@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/barebox
next prev parent reply other threads:[~2018-05-31 15:05 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2018-05-31 15:04 [PATCH v2 00/10] dentry cache support Sascha Hauer
2018-05-31 15:04 ` [PATCH 01/10] fs: dentry cache implementation Sascha Hauer
2018-05-31 15:04 ` [PATCH 02/10] fs: ramfs: Switch to " Sascha Hauer
2018-05-31 15:04 ` [PATCH 03/10] fs: devfs: " Sascha Hauer
2018-05-31 15:04 ` [PATCH 04/10] fs: ext4: " Sascha Hauer
2018-05-31 15:04 ` Sascha Hauer [this message]
2018-05-31 15:04 ` [PATCH 06/10] fs: nfs: " Sascha Hauer
2018-05-31 15:04 ` [PATCH 07/10] fs: tftp: " Sascha Hauer
2018-05-31 15:04 ` [PATCH 08/10] fs: cramfs: " Sascha Hauer
2018-05-31 15:04 ` [PATCH 09/10] fs: squashfs: " Sascha Hauer
2018-05-31 15:04 ` [PATCH 10/10] block: Adjust cache sizes Sascha Hauer
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20180531150442.16208-6-s.hauer@pengutronix.de \
--to=s.hauer@pengutronix.de \
--cc=barebox@lists.infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox