Skip to content

Commit 84147f4

Browse files
Seamus ConnorChristoph Hellwig
authored andcommitted
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 <sconnor@purestorage.com> Reviewed-by: Joel Becker <jlbec@evilplan.org> Signed-off-by: Christoph Hellwig <hch@lst.de>
1 parent 8312c87 commit 84147f4

File tree

2 files changed

+34
-10
lines changed

2 files changed

+34
-10
lines changed

fs/configfs/configfs_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@ struct configfs_dirent {
5555
#define CONFIGFS_USET_IN_MKDIR 0x0200
5656
#define CONFIGFS_USET_CREATING 0x0400
5757
#define CONFIGFS_NOT_PINNED (CONFIGFS_ITEM_ATTR | CONFIGFS_ITEM_BIN_ATTR)
58+
#define CONFIGFS_PINNED \
59+
(CONFIGFS_ROOT | CONFIGFS_DIR | CONFIGFS_ITEM_LINK)
5860

5961
extern struct mutex configfs_symlink_mutex;
6062
extern spinlock_t configfs_dirent_lock;

fs/configfs/dir.c

Lines changed: 32 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,17 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *paren
207207
return ERR_PTR(-ENOENT);
208208
}
209209
sd->s_frag = get_fragment(frag);
210-
list_add(&sd->s_sibling, &parent_sd->s_children);
210+
211+
/*
212+
* configfs_lookup scans only for unpinned items. s_children is
213+
* partitioned so that configfs_lookup can bail out early.
214+
* CONFIGFS_PINNED and CONFIGFS_NOT_PINNED are not symmetrical. readdir
215+
* cursors still need to be inserted at the front of the list.
216+
*/
217+
if (sd->s_type & CONFIGFS_PINNED)
218+
list_add_tail(&sd->s_sibling, &parent_sd->s_children);
219+
else
220+
list_add(&sd->s_sibling, &parent_sd->s_children);
211221
spin_unlock(&configfs_dirent_lock);
212222

213223
return sd;
@@ -220,10 +230,11 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *paren
220230
*
221231
* called with parent inode's i_mutex held
222232
*/
223-
static int configfs_dirent_exists(struct configfs_dirent *parent_sd,
224-
const unsigned char *new)
233+
static int configfs_dirent_exists(struct dentry *dentry)
225234
{
226-
struct configfs_dirent * sd;
235+
struct configfs_dirent *parent_sd = dentry->d_parent->d_fsdata;
236+
const unsigned char *new = dentry->d_name.name;
237+
struct configfs_dirent *sd;
227238

228239
list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
229240
if (sd->s_element) {
@@ -289,10 +300,6 @@ static int configfs_create_dir(struct config_item *item, struct dentry *dentry,
289300

290301
BUG_ON(!item);
291302

292-
error = configfs_dirent_exists(p->d_fsdata, dentry->d_name.name);
293-
if (unlikely(error))
294-
return error;
295-
296303
error = configfs_make_dirent(p->d_fsdata, dentry, item, mode,
297304
CONFIGFS_DIR | CONFIGFS_USET_CREATING,
298305
frag);
@@ -451,6 +458,18 @@ static struct dentry * configfs_lookup(struct inode *dir,
451458

452459
spin_lock(&configfs_dirent_lock);
453460
list_for_each_entry(sd, &parent_sd->s_children, s_sibling) {
461+
462+
/*
463+
* s_children is partitioned, see configfs_new_dirent. The first
464+
* pinned item indicates we can stop scanning.
465+
*/
466+
if (sd->s_type & CONFIGFS_PINNED)
467+
break;
468+
469+
/*
470+
* Note: CONFIGFS_PINNED and CONFIGFS_NOT_PINNED are asymmetric.
471+
* there may be a readdir cursor in this list
472+
*/
454473
if ((sd->s_type & CONFIGFS_NOT_PINNED) &&
455474
!strcmp(configfs_get_name(sd), dentry->d_name.name)) {
456475
struct configfs_attribute *attr = sd->s_element;
@@ -1885,8 +1904,11 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
18851904
if (dentry) {
18861905
d_add(dentry, NULL);
18871906

1888-
err = configfs_attach_group(sd->s_element, &group->cg_item,
1889-
dentry, frag);
1907+
err = configfs_dirent_exists(dentry);
1908+
if (!err)
1909+
err = configfs_attach_group(sd->s_element,
1910+
&group->cg_item,
1911+
dentry, frag);
18901912
if (err) {
18911913
BUG_ON(d_inode(dentry));
18921914
d_drop(dentry);

0 commit comments

Comments
 (0)