Skip to content

Commit

Permalink
configfs: improve item creation performance
Browse files Browse the repository at this point in the history
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 <[email protected]>
Reviewed-by: Joel Becker <[email protected]>
Signed-off-by: Christoph Hellwig <[email protected]>
  • Loading branch information
Seamus Connor authored and Christoph Hellwig committed Nov 14, 2024
1 parent 8312c87 commit 84147f4
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 10 deletions.
2 changes: 2 additions & 0 deletions fs/configfs/configfs_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
42 changes: 32 additions & 10 deletions fs/configfs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 84147f4

Please sign in to comment.