Skip to content

Commit b0841ee

Browse files
Al ViroChristoph Hellwig
authored andcommitted
configfs: provide exclusion between IO and removals
Make sure that attribute methods are not called after the item has been removed from the tree. To do so, we * at the point of no return in removals, grab ->frag_sem exclusive and mark the fragment dead. * call the methods of attributes with ->frag_sem taken shared and only after having verified that the fragment is still alive. The main benefit is for method instances - they are guaranteed that the objects they are accessing *and* all ancestors are still there. Another win is that we don't need to bother with extra refcount on config_item when opening a file - the item will be alive for as long as it stays in the tree, and we won't touch it/attributes/any associated data after it's been removed from the tree. Signed-off-by: Al Viro <[email protected]> Signed-off-by: Christoph Hellwig <[email protected]>
1 parent 47320fb commit b0841ee

File tree

2 files changed

+80
-18
lines changed

2 files changed

+80
-18
lines changed

fs/configfs/dir.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1461,6 +1461,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
14611461
struct config_item *item;
14621462
struct configfs_subsystem *subsys;
14631463
struct configfs_dirent *sd;
1464+
struct configfs_fragment *frag;
14641465
struct module *subsys_owner = NULL, *dead_item_owner = NULL;
14651466
int ret;
14661467

@@ -1518,6 +1519,16 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry)
15181519
}
15191520
} while (ret == -EAGAIN);
15201521

1522+
frag = sd->s_frag;
1523+
if (down_write_killable(&frag->frag_sem)) {
1524+
spin_lock(&configfs_dirent_lock);
1525+
configfs_detach_rollback(dentry);
1526+
spin_unlock(&configfs_dirent_lock);
1527+
return -EINTR;
1528+
}
1529+
frag->frag_dead = true;
1530+
up_write(&frag->frag_sem);
1531+
15211532
/* Get a working ref for the duration of this function */
15221533
item = configfs_get_config_item(dentry);
15231534

@@ -1821,6 +1832,12 @@ void configfs_unregister_group(struct config_group *group)
18211832
struct configfs_subsystem *subsys = group->cg_subsys;
18221833
struct dentry *dentry = group->cg_item.ci_dentry;
18231834
struct dentry *parent = group->cg_item.ci_parent->ci_dentry;
1835+
struct configfs_dirent *sd = dentry->d_fsdata;
1836+
struct configfs_fragment *frag = sd->s_frag;
1837+
1838+
down_write(&frag->frag_sem);
1839+
frag->frag_dead = true;
1840+
up_write(&frag->frag_sem);
18241841

18251842
inode_lock_nested(d_inode(parent), I_MUTEX_PARENT);
18261843
spin_lock(&configfs_dirent_lock);
@@ -1947,12 +1964,18 @@ void configfs_unregister_subsystem(struct configfs_subsystem *subsys)
19471964
struct config_group *group = &subsys->su_group;
19481965
struct dentry *dentry = group->cg_item.ci_dentry;
19491966
struct dentry *root = dentry->d_sb->s_root;
1967+
struct configfs_dirent *sd = dentry->d_fsdata;
1968+
struct configfs_fragment *frag = sd->s_frag;
19501969

19511970
if (dentry->d_parent != root) {
19521971
pr_err("Tried to unregister non-subsystem!\n");
19531972
return;
19541973
}
19551974

1975+
down_write(&frag->frag_sem);
1976+
frag->frag_dead = true;
1977+
up_write(&frag->frag_sem);
1978+
19561979
inode_lock_nested(d_inode(root),
19571980
I_MUTEX_PARENT);
19581981
inode_lock_nested(d_inode(dentry), I_MUTEX_CHILD);

fs/configfs/file.c

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,32 @@ struct configfs_buffer {
4848
};
4949
};
5050

51+
static inline struct configfs_fragment *to_frag(struct file *file)
52+
{
53+
struct configfs_dirent *sd = file->f_path.dentry->d_fsdata;
54+
55+
return sd->s_frag;
56+
}
5157

52-
static int fill_read_buffer(struct configfs_buffer * buffer)
58+
static int fill_read_buffer(struct file *file, struct configfs_buffer *buffer)
5359
{
54-
ssize_t count;
60+
struct configfs_fragment *frag = to_frag(file);
61+
ssize_t count = -ENOENT;
5562

5663
if (!buffer->page)
5764
buffer->page = (char *) get_zeroed_page(GFP_KERNEL);
5865
if (!buffer->page)
5966
return -ENOMEM;
6067

61-
count = buffer->attr->show(buffer->item, buffer->page);
68+
down_read(&frag->frag_sem);
69+
if (!frag->frag_dead)
70+
count = buffer->attr->show(buffer->item, buffer->page);
71+
up_read(&frag->frag_sem);
72+
6273
if (count < 0)
6374
return count;
6475
if (WARN_ON_ONCE(count > (ssize_t)SIMPLE_ATTR_SIZE))
6576
return -EIO;
66-
6777
buffer->needs_read_fill = 0;
6878
buffer->count = count;
6979
return 0;
@@ -96,7 +106,7 @@ configfs_read_file(struct file *file, char __user *buf, size_t count, loff_t *pp
96106

97107
mutex_lock(&buffer->mutex);
98108
if (buffer->needs_read_fill) {
99-
retval = fill_read_buffer(buffer);
109+
retval = fill_read_buffer(file, buffer);
100110
if (retval)
101111
goto out;
102112
}
@@ -133,6 +143,7 @@ static ssize_t
133143
configfs_read_bin_file(struct file *file, char __user *buf,
134144
size_t count, loff_t *ppos)
135145
{
146+
struct configfs_fragment *frag = to_frag(file);
136147
struct configfs_buffer *buffer = file->private_data;
137148
ssize_t retval = 0;
138149
ssize_t len = min_t(size_t, count, PAGE_SIZE);
@@ -148,7 +159,12 @@ configfs_read_bin_file(struct file *file, char __user *buf,
148159

149160
if (buffer->needs_read_fill) {
150161
/* perform first read with buf == NULL to get extent */
151-
len = buffer->bin_attr->read(buffer->item, NULL, 0);
162+
down_read(&frag->frag_sem);
163+
if (!frag->frag_dead)
164+
len = buffer->bin_attr->read(buffer->item, NULL, 0);
165+
else
166+
len = -ENOENT;
167+
up_read(&frag->frag_sem);
152168
if (len <= 0) {
153169
retval = len;
154170
goto out;
@@ -168,8 +184,13 @@ configfs_read_bin_file(struct file *file, char __user *buf,
168184
buffer->bin_buffer_size = len;
169185

170186
/* perform second read to fill buffer */
171-
len = buffer->bin_attr->read(buffer->item,
172-
buffer->bin_buffer, len);
187+
down_read(&frag->frag_sem);
188+
if (!frag->frag_dead)
189+
len = buffer->bin_attr->read(buffer->item,
190+
buffer->bin_buffer, len);
191+
else
192+
len = -ENOENT;
193+
up_read(&frag->frag_sem);
173194
if (len < 0) {
174195
retval = len;
175196
vfree(buffer->bin_buffer);
@@ -220,9 +241,16 @@ fill_write_buffer(struct configfs_buffer * buffer, const char __user * buf, size
220241
}
221242

222243
static int
223-
flush_write_buffer(struct configfs_buffer *buffer, size_t count)
244+
flush_write_buffer(struct file *file, struct configfs_buffer *buffer, size_t count)
224245
{
225-
return buffer->attr->store(buffer->item, buffer->page, count);
246+
struct configfs_fragment *frag = to_frag(file);
247+
int res = -ENOENT;
248+
249+
down_read(&frag->frag_sem);
250+
if (!frag->frag_dead)
251+
res = buffer->attr->store(buffer->item, buffer->page, count);
252+
up_read(&frag->frag_sem);
253+
return res;
226254
}
227255

228256

@@ -252,7 +280,7 @@ configfs_write_file(struct file *file, const char __user *buf, size_t count, lof
252280
mutex_lock(&buffer->mutex);
253281
len = fill_write_buffer(buffer, buf, count);
254282
if (len > 0)
255-
len = flush_write_buffer(buffer, len);
283+
len = flush_write_buffer(file, buffer, len);
256284
if (len > 0)
257285
*ppos += len;
258286
mutex_unlock(&buffer->mutex);
@@ -328,6 +356,7 @@ configfs_write_bin_file(struct file *file, const char __user *buf,
328356
static int __configfs_open_file(struct inode *inode, struct file *file, int type)
329357
{
330358
struct dentry *dentry = file->f_path.dentry;
359+
struct configfs_fragment *frag = to_frag(file);
331360
struct configfs_attribute *attr;
332361
struct configfs_buffer *buffer;
333362
int error;
@@ -337,8 +366,13 @@ static int __configfs_open_file(struct inode *inode, struct file *file, int type
337366
if (!buffer)
338367
goto out;
339368

369+
error = -ENOENT;
370+
down_read(&frag->frag_sem);
371+
if (unlikely(frag->frag_dead))
372+
goto out_free_buffer;
373+
340374
error = -EINVAL;
341-
buffer->item = configfs_get_config_item(dentry->d_parent);
375+
buffer->item = to_item(dentry->d_parent);
342376
if (!buffer->item)
343377
goto out_free_buffer;
344378

@@ -396,13 +430,15 @@ static int __configfs_open_file(struct inode *inode, struct file *file, int type
396430
buffer->read_in_progress = false;
397431
buffer->write_in_progress = false;
398432
file->private_data = buffer;
433+
up_read(&frag->frag_sem);
399434
return 0;
400435

401436
out_put_module:
402437
module_put(buffer->owner);
403438
out_put_item:
404439
config_item_put(buffer->item);
405440
out_free_buffer:
441+
up_read(&frag->frag_sem);
406442
kfree(buffer);
407443
out:
408444
return error;
@@ -412,8 +448,6 @@ static int configfs_release(struct inode *inode, struct file *filp)
412448
{
413449
struct configfs_buffer *buffer = filp->private_data;
414450

415-
if (buffer->item)
416-
config_item_put(buffer->item);
417451
module_put(buffer->owner);
418452
if (buffer->page)
419453
free_page((unsigned long)buffer->page);
@@ -439,12 +473,17 @@ static int configfs_release_bin_file(struct inode *inode, struct file *file)
439473
buffer->read_in_progress = false;
440474

441475
if (buffer->write_in_progress) {
476+
struct configfs_fragment *frag = to_frag(file);
442477
buffer->write_in_progress = false;
443478

444-
/* result of ->release() is ignored */
445-
buffer->bin_attr->write(buffer->item, buffer->bin_buffer,
446-
buffer->bin_buffer_size);
447-
479+
down_read(&frag->frag_sem);
480+
if (!frag->frag_dead) {
481+
/* result of ->release() is ignored */
482+
buffer->bin_attr->write(buffer->item,
483+
buffer->bin_buffer,
484+
buffer->bin_buffer_size);
485+
}
486+
up_read(&frag->frag_sem);
448487
/* vfree on NULL is safe */
449488
vfree(buffer->bin_buffer);
450489
buffer->bin_buffer = NULL;

0 commit comments

Comments
 (0)