From 8312c879e10cd2c29739f875a9f743db13a583b5 Mon Sep 17 00:00:00 2001 From: "Dr. David Alan Gilbert" Date: Thu, 10 Oct 2024 21:56:55 +0100 Subject: [PATCH 1/2] configfs: remove unused configfs_hash_and_remove configfs_hash_and_remove() has been unused since it was added in 2005 by commit 7063fbf22611 ("[PATCH] configfs: User-driven configuration filesystem") Remove it. Signed-off-by: Dr. David Alan Gilbert Signed-off-by: Christoph Hellwig --- fs/configfs/configfs_internal.h | 2 -- fs/configfs/inode.c | 25 ------------------------- 2 files changed, 27 deletions(-) diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index e710a1782382..5c20e83315bc 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h @@ -73,8 +73,6 @@ extern int configfs_make_dirent(struct configfs_dirent *, struct dentry *, void *, umode_t, int, struct configfs_fragment *); extern int configfs_dirent_is_ready(struct configfs_dirent *); -extern void configfs_hash_and_remove(struct dentry * dir, const char * name); - extern const unsigned char * configfs_get_name(struct configfs_dirent *sd); extern void configfs_drop_dentry(struct configfs_dirent *sd, struct dentry *parent); extern int configfs_setattr(struct mnt_idmap *idmap, diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index dcc22f593e43..1d2e3a5738d1 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -216,28 +216,3 @@ void configfs_drop_dentry(struct configfs_dirent * sd, struct dentry * parent) spin_unlock(&dentry->d_lock); } } - -void configfs_hash_and_remove(struct dentry * dir, const char * name) -{ - struct configfs_dirent * sd; - struct configfs_dirent * parent_sd = dir->d_fsdata; - - if (d_really_is_negative(dir)) - /* no inode means this hasn't been made visible yet */ - return; - - inode_lock(d_inode(dir)); - list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { - if (!sd->s_element) - continue; - if (!strcmp(configfs_get_name(sd), name)) { - spin_lock(&configfs_dirent_lock); - list_del_init(&sd->s_sibling); - spin_unlock(&configfs_dirent_lock); - configfs_drop_dentry(sd, dir); - configfs_put(sd); - break; - } - } - inode_unlock(d_inode(dir)); -} From 84147f4e84c4f4822006161c5ad43612ac906407 Mon Sep 17 00:00:00 2001 From: Seamus Connor Date: Thu, 14 Nov 2024 06:29:22 +0100 Subject: [PATCH 2/2] configfs: improve item creation performance As the size of a directory increases item creation slows down. Optimizing access to s_children removes this bottleneck. dirents are already pinned into the cache, there is no need to scan the s_children list looking for duplicate Items. The configfs_dirent_exists check is moved to a location where it is called only during subsystem initialization. d_lookup will only need to call configfs_lookup in the case where the item in question is not pinned to dcache. The only items not pinned to dcache are attributes. These are placed at the front of the s_children list, whilst pinned items are inserted at the back. configfs_lookup stops scanning when it encounters the first pinned entry in s_children. The assumption of the above optimizations is that there will be few attributes, but potentially many Items in a given directory. Signed-off-by: Seamus Connor Reviewed-by: Joel Becker Signed-off-by: Christoph Hellwig --- fs/configfs/configfs_internal.h | 2 ++ fs/configfs/dir.c | 42 +++++++++++++++++++++++++-------- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index 5c20e83315bc..0b969d0eb8ff 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h @@ -55,6 +55,8 @@ struct configfs_dirent { #define CONFIGFS_USET_IN_MKDIR 0x0200 #define CONFIGFS_USET_CREATING 0x0400 #define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR | CONFIGFS_ITEM_BIN_ATTR) +#define CONFIGFS_PINNED \ + (CONFIGFS_ROOT | CONFIGFS_DIR | CONFIGFS_ITEM_LINK) extern struct mutex configfs_symlink_mutex; extern spinlock_t configfs_dirent_lock; diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 43d6bde1adcc..7d10278db30d 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -207,7 +207,17 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *paren return ERR_PTR(-ENOENT); } sd->s_frag = get_fragment(frag); - list_add(&sd->s_sibling, &parent_sd->s_children); + + /* + * configfs_lookup scans only for unpinned items. s_children is + * partitioned so that configfs_lookup can bail out early. + * CONFIGFS_PINNED and CONFIGFS_NOT_PINNED are not symmetrical. readdir + * cursors still need to be inserted at the front of the list. + */ + if (sd->s_type & CONFIGFS_PINNED) + list_add_tail(&sd->s_sibling, &parent_sd->s_children); + else + list_add(&sd->s_sibling, &parent_sd->s_children); spin_unlock(&configfs_dirent_lock); return sd; @@ -220,10 +230,11 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *paren * * called with parent inode's i_mutex held */ -static int configfs_dirent_exists(struct configfs_dirent *parent_sd, - const unsigned char *new) +static int configfs_dirent_exists(struct dentry *dentry) { - struct configfs_dirent * sd; + struct configfs_dirent *parent_sd = dentry->d_parent->d_fsdata; + const unsigned char *new = dentry->d_name.name; + struct configfs_dirent *sd; list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { if (sd->s_element) { @@ -289,10 +300,6 @@ static int configfs_create_dir(struct config_item *item, struct dentry *dentry, BUG_ON(!item); - error = configfs_dirent_exists(p->d_fsdata, dentry->d_name.name); - if (unlikely(error)) - return error; - error = configfs_make_dirent(p->d_fsdata, dentry, item, mode, CONFIGFS_DIR | CONFIGFS_USET_CREATING, frag); @@ -451,6 +458,18 @@ static struct dentry * configfs_lookup(struct inode *dir, spin_lock(&configfs_dirent_lock); list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { + + /* + * s_children is partitioned, see configfs_new_dirent. The first + * pinned item indicates we can stop scanning. + */ + if (sd->s_type & CONFIGFS_PINNED) + break; + + /* + * Note: CONFIGFS_PINNED and CONFIGFS_NOT_PINNED are asymmetric. + * there may be a readdir cursor in this list + */ if ((sd->s_type & CONFIGFS_NOT_PINNED) && !strcmp(configfs_get_name(sd), dentry->d_name.name)) { struct configfs_attribute *attr = sd->s_element; @@ -1885,8 +1904,11 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) if (dentry) { d_add(dentry, NULL); - err = configfs_attach_group(sd->s_element, &group->cg_item, - dentry, frag); + err = configfs_dirent_exists(dentry); + if (!err) + err = configfs_attach_group(sd->s_element, + &group->cg_item, + dentry, frag); if (err) { BUG_ON(d_inode(dentry)); d_drop(dentry);