Skip to content

Commit 47320fb

Browse files
Al ViroChristoph Hellwig
authored andcommitted
configfs: new object reprsenting tree fragments
Refcounted, hangs of configfs_dirent, created by operations that add fragments to configfs tree (mkdir and configfs_register_{subsystem,group}). Will be used in the next commit to provide exclusion between fragment removal and ->show/->store calls. Signed-off-by: Al Viro <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent f19e4ed commit 47320fb

File tree

3 files changed

+97
-27
lines changed

3 files changed

+97
-27
lines changed

fs/configfs/configfs_internal.h

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@
2020
#include <linux/list.h>
2121
#include <linux/spinlock.h>
2222

23+
struct configfs_fragment {
24+
atomic_t frag_count;
25+
struct rw_semaphore frag_sem;
26+
bool frag_dead;
27+
};
28+
29+
void put_fragment(struct configfs_fragment *);
30+
struct configfs_fragment *get_fragment(struct configfs_fragment *);
31+
2332
struct configfs_dirent {
2433
atomic_t s_count;
2534
int s_dependent_count;
@@ -34,6 +43,7 @@ struct configfs_dirent {
3443
#ifdef CONFIG_LOCKDEP
3544
int s_depth;
3645
#endif
46+
struct configfs_fragment *s_frag;
3747
};
3848

3949
#define CONFIGFS_ROOT 0x0001
@@ -61,8 +71,8 @@ extern int configfs_create(struct dentry *, umode_t mode, void (*init)(struct in
6171
extern int configfs_create_file(struct config_item *, const struct configfs_attribute *);
6272
extern int configfs_create_bin_file(struct config_item *,
6373
const struct configfs_bin_attribute *);
64-
extern int configfs_make_dirent(struct configfs_dirent *,
65-
struct dentry *, void *, umode_t, int);
74+
extern int configfs_make_dirent(struct configfs_dirent *, struct dentry *,
75+
void *, umode_t, int, struct configfs_fragment *);
6676
extern int configfs_dirent_is_ready(struct configfs_dirent *);
6777

6878
extern void configfs_hash_and_remove(struct dentry * dir, const char * name);
@@ -137,6 +147,7 @@ static inline void release_configfs_dirent(struct configfs_dirent * sd)
137147
{
138148
if (!(sd->s_type & CONFIGFS_ROOT)) {
139149
kfree(sd->s_iattr);
150+
put_fragment(sd->s_frag);
140151
kmem_cache_free(configfs_dir_cachep, sd);
141152
}
142153
}

fs/configfs/dir.c

Lines changed: 82 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,38 @@ configfs_adjust_dir_dirent_depth_after_populate(struct configfs_dirent *sd)
151151

152152
#endif /* CONFIG_LOCKDEP */
153153

154+
static struct configfs_fragment *new_fragment(void)
155+
{
156+
struct configfs_fragment *p;
157+
158+
p = kmalloc(sizeof(struct configfs_fragment), GFP_KERNEL);
159+
if (p) {
160+
atomic_set(&p->frag_count, 1);
161+
init_rwsem(&p->frag_sem);
162+
p->frag_dead = false;
163+
}
164+
return p;
165+
}
166+
167+
void put_fragment(struct configfs_fragment *frag)
168+
{
169+
if (frag && atomic_dec_and_test(&frag->frag_count))
170+
kfree(frag);
171+
}
172+
173+
struct configfs_fragment *get_fragment(struct configfs_fragment *frag)
174+
{
175+
if (likely(frag))
176+
atomic_inc(&frag->frag_count);
177+
return frag;
178+
}
179+
154180
/*
155181
* Allocates a new configfs_dirent and links it to the parent configfs_dirent
156182
*/
157183
static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *parent_sd,
158-
void *element, int type)
184+
void *element, int type,
185+
struct configfs_fragment *frag)
159186
{
160187
struct configfs_dirent * sd;
161188

@@ -175,6 +202,7 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent *paren
175202
kmem_cache_free(configfs_dir_cachep, sd);
176203
return ERR_PTR(-ENOENT);
177204
}
205+
sd->s_frag = get_fragment(frag);
178206
list_add(&sd->s_sibling, &parent_sd->s_children);
179207
spin_unlock(&configfs_dirent_lock);
180208

@@ -209,11 +237,11 @@ static int configfs_dirent_exists(struct configfs_dirent *parent_sd,
209237

210238
int configfs_make_dirent(struct configfs_dirent * parent_sd,
211239
struct dentry * dentry, void * element,
212-
umode_t mode, int type)
240+
umode_t mode, int type, struct configfs_fragment *frag)
213241
{
214242
struct configfs_dirent * sd;
215243

216-
sd = configfs_new_dirent(parent_sd, element, type);
244+
sd = configfs_new_dirent(parent_sd, element, type, frag);
217245
if (IS_ERR(sd))
218246
return PTR_ERR(sd);
219247

@@ -260,7 +288,8 @@ static void init_symlink(struct inode * inode)
260288
* until it is validated by configfs_dir_set_ready()
261289
*/
262290

263-
static int configfs_create_dir(struct config_item *item, struct dentry *dentry)
291+
static int configfs_create_dir(struct config_item *item, struct dentry *dentry,
292+
struct configfs_fragment *frag)
264293
{
265294
int error;
266295
umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO;
@@ -273,7 +302,8 @@ static int configfs_create_dir(struct config_item *item, struct dentry *dentry)
273302
return error;
274303

275304
error = configfs_make_dirent(p->d_fsdata, dentry, item, mode,
276-
CONFIGFS_DIR | CONFIGFS_USET_CREATING);
305+
CONFIGFS_DIR | CONFIGFS_USET_CREATING,
306+
frag);
277307
if (unlikely(error))
278308
return error;
279309

@@ -338,9 +368,10 @@ int configfs_create_link(struct configfs_symlink *sl,
338368
{
339369
int err = 0;
340370
umode_t mode = S_IFLNK | S_IRWXUGO;
371+
struct configfs_dirent *p = parent->d_fsdata;
341372

342-
err = configfs_make_dirent(parent->d_fsdata, dentry, sl, mode,
343-
CONFIGFS_ITEM_LINK);
373+
err = configfs_make_dirent(p, dentry, sl, mode,
374+
CONFIGFS_ITEM_LINK, p->s_frag);
344375
if (!err) {
345376
err = configfs_create(dentry, mode, init_symlink);
346377
if (err) {
@@ -599,7 +630,8 @@ static int populate_attrs(struct config_item *item)
599630

600631
static int configfs_attach_group(struct config_item *parent_item,
601632
struct config_item *item,
602-
struct dentry *dentry);
633+
struct dentry *dentry,
634+
struct configfs_fragment *frag);
603635
static void configfs_detach_group(struct config_item *item);
604636

605637
static void detach_groups(struct config_group *group)
@@ -647,7 +679,8 @@ static void detach_groups(struct config_group *group)
647679
* try using vfs_mkdir. Just a thought.
648680
*/
649681
static int create_default_group(struct config_group *parent_group,
650-
struct config_group *group)
682+
struct config_group *group,
683+
struct configfs_fragment *frag)
651684
{
652685
int ret;
653686
struct configfs_dirent *sd;
@@ -663,7 +696,7 @@ static int create_default_group(struct config_group *parent_group,
663696
d_add(child, NULL);
664697

665698
ret = configfs_attach_group(&parent_group->cg_item,
666-
&group->cg_item, child);
699+
&group->cg_item, child, frag);
667700
if (!ret) {
668701
sd = child->d_fsdata;
669702
sd->s_type |= CONFIGFS_USET_DEFAULT;
@@ -677,13 +710,14 @@ static int create_default_group(struct config_group *parent_group,
677710
return ret;
678711
}
679712

680-
static int populate_groups(struct config_group *group)
713+
static int populate_groups(struct config_group *group,
714+
struct configfs_fragment *frag)
681715
{
682716
struct config_group *new_group;
683717
int ret = 0;
684718

685719
list_for_each_entry(new_group, &group->default_groups, group_entry) {
686-
ret = create_default_group(group, new_group);
720+
ret = create_default_group(group, new_group, frag);
687721
if (ret) {
688722
detach_groups(group);
689723
break;
@@ -797,11 +831,12 @@ static void link_group(struct config_group *parent_group, struct config_group *g
797831
*/
798832
static int configfs_attach_item(struct config_item *parent_item,
799833
struct config_item *item,
800-
struct dentry *dentry)
834+
struct dentry *dentry,
835+
struct configfs_fragment *frag)
801836
{
802837
int ret;
803838

804-
ret = configfs_create_dir(item, dentry);
839+
ret = configfs_create_dir(item, dentry, frag);
805840
if (!ret) {
806841
ret = populate_attrs(item);
807842
if (ret) {
@@ -831,12 +866,13 @@ static void configfs_detach_item(struct config_item *item)
831866

832867
static int configfs_attach_group(struct config_item *parent_item,
833868
struct config_item *item,
834-
struct dentry *dentry)
869+
struct dentry *dentry,
870+
struct configfs_fragment *frag)
835871
{
836872
int ret;
837873
struct configfs_dirent *sd;
838874

839-
ret = configfs_attach_item(parent_item, item, dentry);
875+
ret = configfs_attach_item(parent_item, item, dentry, frag);
840876
if (!ret) {
841877
sd = dentry->d_fsdata;
842878
sd->s_type |= CONFIGFS_USET_DIR;
@@ -852,7 +888,7 @@ static int configfs_attach_group(struct config_item *parent_item,
852888
*/
853889
inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD);
854890
configfs_adjust_dir_dirent_depth_before_populate(sd);
855-
ret = populate_groups(to_config_group(item));
891+
ret = populate_groups(to_config_group(item), frag);
856892
if (ret) {
857893
configfs_detach_item(item);
858894
d_inode(dentry)->i_flags |= S_DEAD;
@@ -1247,6 +1283,7 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
12471283
struct configfs_dirent *sd;
12481284
const struct config_item_type *type;
12491285
struct module *subsys_owner = NULL, *new_item_owner = NULL;
1286+
struct configfs_fragment *frag;
12501287
char *name;
12511288

12521289
sd = dentry->d_parent->d_fsdata;
@@ -1265,6 +1302,12 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
12651302
goto out;
12661303
}
12671304

1305+
frag = new_fragment();
1306+
if (!frag) {
1307+
ret = -ENOMEM;
1308+
goto out;
1309+
}
1310+
12681311
/* Get a working ref for the duration of this function */
12691312
parent_item = configfs_get_config_item(dentry->d_parent);
12701313
type = parent_item->ci_type;
@@ -1367,9 +1410,9 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
13671410
spin_unlock(&configfs_dirent_lock);
13681411

13691412
if (group)
1370-
ret = configfs_attach_group(parent_item, item, dentry);
1413+
ret = configfs_attach_group(parent_item, item, dentry, frag);
13711414
else
1372-
ret = configfs_attach_item(parent_item, item, dentry);
1415+
ret = configfs_attach_item(parent_item, item, dentry, frag);
13731416

13741417
spin_lock(&configfs_dirent_lock);
13751418
sd->s_type &= ~CONFIGFS_USET_IN_MKDIR;
@@ -1406,6 +1449,7 @@ static int configfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode
14061449
* reference.
14071450
*/
14081451
config_item_put(parent_item);
1452+
put_fragment(frag);
14091453

14101454
out:
14111455
return ret;
@@ -1574,7 +1618,7 @@ static int configfs_dir_open(struct inode *inode, struct file *file)
15741618
*/
15751619
err = -ENOENT;
15761620
if (configfs_dirent_is_ready(parent_sd)) {
1577-
file->private_data = configfs_new_dirent(parent_sd, NULL, 0);
1621+
file->private_data = configfs_new_dirent(parent_sd, NULL, 0, NULL);
15781622
if (IS_ERR(file->private_data))
15791623
err = PTR_ERR(file->private_data);
15801624
else
@@ -1732,29 +1776,36 @@ int configfs_register_group(struct config_group *parent_group,
17321776
{
17331777
struct configfs_subsystem *subsys = parent_group->cg_subsys;
17341778
struct dentry *parent;
1779+
struct configfs_fragment *frag;
17351780
int ret;
17361781

1782+
frag = new_fragment();
1783+
if (!frag)
1784+
return -ENOMEM;
1785+
17371786
mutex_lock(&subsys->su_mutex);
17381787
link_group(parent_group, group);
17391788
mutex_unlock(&subsys->su_mutex);
17401789

17411790
parent = parent_group->cg_item.ci_dentry;
17421791

17431792
inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
1744-
ret = create_default_group(parent_group, group);
1793+
ret = create_default_group(parent_group, group, frag);
17451794
if (ret)
17461795
goto err_out;
17471796

17481797
spin_lock(&configfs_dirent_lock);
17491798
configfs_dir_set_ready(group->cg_item.ci_dentry->d_fsdata);
17501799
spin_unlock(&configfs_dirent_lock);
17511800
inode_unlock(d_inode(parent));
1801+
put_fragment(frag);
17521802
return 0;
17531803
err_out:
17541804
inode_unlock(d_inode(parent));
17551805
mutex_lock(&subsys->su_mutex);
17561806
unlink_group(group);
17571807
mutex_unlock(&subsys->su_mutex);
1808+
put_fragment(frag);
17581809
return ret;
17591810
}
17601811
EXPORT_SYMBOL(configfs_register_group);
@@ -1842,10 +1893,17 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
18421893
struct dentry *dentry;
18431894
struct dentry *root;
18441895
struct configfs_dirent *sd;
1896+
struct configfs_fragment *frag;
1897+
1898+
frag = new_fragment();
1899+
if (!frag)
1900+
return -ENOMEM;
18451901

18461902
root = configfs_pin_fs();
1847-
if (IS_ERR(root))
1903+
if (IS_ERR(root)) {
1904+
put_fragment(frag);
18481905
return PTR_ERR(root);
1906+
}
18491907

18501908
if (!group->cg_item.ci_name)
18511909
group->cg_item.ci_name = group->cg_item.ci_namebuf;
@@ -1861,7 +1919,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
18611919
d_add(dentry, NULL);
18621920

18631921
err = configfs_attach_group(sd->s_element, &group->cg_item,
1864-
dentry);
1922+
dentry, frag);
18651923
if (err) {
18661924
BUG_ON(d_inode(dentry));
18671925
d_drop(dentry);
@@ -1879,6 +1937,7 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys)
18791937
unlink_group(group);
18801938
configfs_release_fs();
18811939
}
1940+
put_fragment(frag);
18821941

18831942
return err;
18841943
}

fs/configfs/file.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -488,7 +488,7 @@ int configfs_create_file(struct config_item * item, const struct configfs_attrib
488488

489489
inode_lock_nested(d_inode(dir), I_MUTEX_NORMAL);
490490
error = configfs_make_dirent(parent_sd, NULL, (void *) attr, mode,
491-
CONFIGFS_ITEM_ATTR);
491+
CONFIGFS_ITEM_ATTR, parent_sd->s_frag);
492492
inode_unlock(d_inode(dir));
493493

494494
return error;
@@ -510,7 +510,7 @@ int configfs_create_bin_file(struct config_item *item,
510510

511511
inode_lock_nested(dir->d_inode, I_MUTEX_NORMAL);
512512
error = configfs_make_dirent(parent_sd, NULL, (void *) bin_attr, mode,
513-
CONFIGFS_ITEM_BIN_ATTR);
513+
CONFIGFS_ITEM_BIN_ATTR, parent_sd->s_frag);
514514
inode_unlock(dir->d_inode);
515515

516516
return error;

0 commit comments

Comments
 (0)