Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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 <viro@zeniv.linux.org.uk>
Signed-off-by: Christoph Hellwig <hch@lst.de>

authored by

Al Viro and committed by
Christoph Hellwig
b0841eef 47320fbe

+81 -19
+23
fs/configfs/dir.c
··· 1461 1461 struct config_item *item; 1462 1462 struct configfs_subsystem *subsys; 1463 1463 struct configfs_dirent *sd; 1464 + struct configfs_fragment *frag; 1464 1465 struct module *subsys_owner = NULL, *dead_item_owner = NULL; 1465 1466 int ret; 1466 1467 ··· 1518 1517 dput(wait); 1519 1518 } 1520 1519 } while (ret == -EAGAIN); 1520 + 1521 + frag = sd->s_frag; 1522 + if (down_write_killable(&frag->frag_sem)) { 1523 + spin_lock(&configfs_dirent_lock); 1524 + configfs_detach_rollback(dentry); 1525 + spin_unlock(&configfs_dirent_lock); 1526 + return -EINTR; 1527 + } 1528 + frag->frag_dead = true; 1529 + up_write(&frag->frag_sem); 1521 1530 1522 1531 /* Get a working ref for the duration of this function */ 1523 1532 item = configfs_get_config_item(dentry); ··· 1832 1821 struct configfs_subsystem *subsys = group->cg_subsys; 1833 1822 struct dentry *dentry = group->cg_item.ci_dentry; 1834 1823 struct dentry *parent = group->cg_item.ci_parent->ci_dentry; 1824 + struct configfs_dirent *sd = dentry->d_fsdata; 1825 + struct configfs_fragment *frag = sd->s_frag; 1826 + 1827 + down_write(&frag->frag_sem); 1828 + frag->frag_dead = true; 1829 + up_write(&frag->frag_sem); 1835 1830 1836 1831 inode_lock_nested(d_inode(parent), I_MUTEX_PARENT); 1837 1832 spin_lock(&configfs_dirent_lock); ··· 1964 1947 struct config_group *group = &subsys->su_group; 1965 1948 struct dentry *dentry = group->cg_item.ci_dentry; 1966 1949 struct dentry *root = dentry->d_sb->s_root; 1950 + struct configfs_dirent *sd = dentry->d_fsdata; 1951 + struct configfs_fragment *frag = sd->s_frag; 1967 1952 1968 1953 if (dentry->d_parent != root) { 1969 1954 pr_err("Tried to unregister non-subsystem!\n"); 1970 1955 return; 1971 1956 } 1957 + 1958 + down_write(&frag->frag_sem); 1959 + frag->frag_dead = true; 1960 + up_write(&frag->frag_sem); 1972 1961 1973 1962 inode_lock_nested(d_inode(root), 1974 1963 I_MUTEX_PARENT);
+58 -19
fs/configfs/file.c
··· 48 48 }; 49 49 }; 50 50 51 - 52 - static int fill_read_buffer(struct configfs_buffer * buffer) 51 + static inline struct configfs_fragment *to_frag(struct file *file) 53 52 { 54 - ssize_t count; 53 + struct configfs_dirent *sd = file->f_path.dentry->d_fsdata; 54 + 55 + return sd->s_frag; 56 + } 57 + 58 + static int fill_read_buffer(struct file *file, struct configfs_buffer *buffer) 59 + { 60 + struct configfs_fragment *frag = to_frag(file); 61 + ssize_t count = -ENOENT; 55 62 56 63 if (!buffer->page) 57 64 buffer->page = (char *) get_zeroed_page(GFP_KERNEL); 58 65 if (!buffer->page) 59 66 return -ENOMEM; 60 67 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 + 62 73 if (count < 0) 63 74 return count; 64 75 if (WARN_ON_ONCE(count > (ssize_t)SIMPLE_ATTR_SIZE)) 65 76 return -EIO; 66 - 67 77 buffer->needs_read_fill = 0; 68 78 buffer->count = count; 69 79 return 0; ··· 106 96 107 97 mutex_lock(&buffer->mutex); 108 98 if (buffer->needs_read_fill) { 109 - retval = fill_read_buffer(buffer); 99 + retval = fill_read_buffer(file, buffer); 110 100 if (retval) 111 101 goto out; 112 102 } ··· 143 133 configfs_read_bin_file(struct file *file, char __user *buf, 144 134 size_t count, loff_t *ppos) 145 135 { 136 + struct configfs_fragment *frag = to_frag(file); 146 137 struct configfs_buffer *buffer = file->private_data; 147 138 ssize_t retval = 0; 148 139 ssize_t len = min_t(size_t, count, PAGE_SIZE); ··· 159 148 160 149 if (buffer->needs_read_fill) { 161 150 /* perform first read with buf == NULL to get extent */ 162 - len = buffer->bin_attr->read(buffer->item, NULL, 0); 151 + down_read(&frag->frag_sem); 152 + if (!frag->frag_dead) 153 + len = buffer->bin_attr->read(buffer->item, NULL, 0); 154 + else 155 + len = -ENOENT; 156 + up_read(&frag->frag_sem); 163 157 if (len <= 0) { 164 158 retval = len; 165 159 goto out; ··· 184 168 buffer->bin_buffer_size = len; 185 169 186 170 /* perform second read to fill buffer */ 187 - len = buffer->bin_attr->read(buffer->item, 188 - buffer->bin_buffer, len); 171 + down_read(&frag->frag_sem); 172 + if (!frag->frag_dead) 173 + len = buffer->bin_attr->read(buffer->item, 174 + buffer->bin_buffer, len); 175 + else 176 + len = -ENOENT; 177 + up_read(&frag->frag_sem); 189 178 if (len < 0) { 190 179 retval = len; 191 180 vfree(buffer->bin_buffer); ··· 241 220 } 242 221 243 222 static int 244 - flush_write_buffer(struct configfs_buffer *buffer, size_t count) 223 + flush_write_buffer(struct file *file, struct configfs_buffer *buffer, size_t count) 245 224 { 246 - return buffer->attr->store(buffer->item, buffer->page, count); 225 + struct configfs_fragment *frag = to_frag(file); 226 + int res = -ENOENT; 227 + 228 + down_read(&frag->frag_sem); 229 + if (!frag->frag_dead) 230 + res = buffer->attr->store(buffer->item, buffer->page, count); 231 + up_read(&frag->frag_sem); 232 + return res; 247 233 } 248 234 249 235 ··· 280 252 mutex_lock(&buffer->mutex); 281 253 len = fill_write_buffer(buffer, buf, count); 282 254 if (len > 0) 283 - len = flush_write_buffer(buffer, len); 255 + len = flush_write_buffer(file, buffer, len); 284 256 if (len > 0) 285 257 *ppos += len; 286 258 mutex_unlock(&buffer->mutex); ··· 356 328 static int __configfs_open_file(struct inode *inode, struct file *file, int type) 357 329 { 358 330 struct dentry *dentry = file->f_path.dentry; 331 + struct configfs_fragment *frag = to_frag(file); 359 332 struct configfs_attribute *attr; 360 333 struct configfs_buffer *buffer; 361 334 int error; ··· 366 337 if (!buffer) 367 338 goto out; 368 339 340 + error = -ENOENT; 341 + down_read(&frag->frag_sem); 342 + if (unlikely(frag->frag_dead)) 343 + goto out_free_buffer; 344 + 369 345 error = -EINVAL; 370 - buffer->item = configfs_get_config_item(dentry->d_parent); 346 + buffer->item = to_item(dentry->d_parent); 371 347 if (!buffer->item) 372 348 goto out_free_buffer; 373 349 ··· 430 396 buffer->read_in_progress = false; 431 397 buffer->write_in_progress = false; 432 398 file->private_data = buffer; 399 + up_read(&frag->frag_sem); 433 400 return 0; 434 401 435 402 out_put_module: ··· 438 403 out_put_item: 439 404 config_item_put(buffer->item); 440 405 out_free_buffer: 406 + up_read(&frag->frag_sem); 441 407 kfree(buffer); 442 408 out: 443 409 return error; ··· 448 412 { 449 413 struct configfs_buffer *buffer = filp->private_data; 450 414 451 - if (buffer->item) 452 - config_item_put(buffer->item); 453 415 module_put(buffer->owner); 454 416 if (buffer->page) 455 417 free_page((unsigned long)buffer->page); ··· 473 439 buffer->read_in_progress = false; 474 440 475 441 if (buffer->write_in_progress) { 442 + struct configfs_fragment *frag = to_frag(file); 476 443 buffer->write_in_progress = false; 477 444 478 - /* result of ->release() is ignored */ 479 - buffer->bin_attr->write(buffer->item, buffer->bin_buffer, 480 - buffer->bin_buffer_size); 481 - 445 + down_read(&frag->frag_sem); 446 + if (!frag->frag_dead) { 447 + /* result of ->release() is ignored */ 448 + buffer->bin_attr->write(buffer->item, 449 + buffer->bin_buffer, 450 + buffer->bin_buffer_size); 451 + } 452 + up_read(&frag->frag_sem); 482 453 /* vfree on NULL is safe */ 483 454 vfree(buffer->bin_buffer); 484 455 buffer->bin_buffer = NULL;