.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* -*- mode: c; c-basic-offset: 8; -*- |
---|
2 | 3 | * vim: noexpandtab sw=8 ts=8 sts=0: |
---|
3 | 4 | * |
---|
4 | 5 | * dir.c - Operations for configfs directories. |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or |
---|
7 | | - * modify it under the terms of the GNU General Public |
---|
8 | | - * License as published by the Free Software Foundation; either |
---|
9 | | - * version 2 of the License, or (at your option) any later version. |
---|
10 | | - * |
---|
11 | | - * This program is distributed in the hope that it will be useful, |
---|
12 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
13 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
---|
14 | | - * General Public License for more details. |
---|
15 | | - * |
---|
16 | | - * You should have received a copy of the GNU General Public |
---|
17 | | - * License along with this program; if not, write to the |
---|
18 | | - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
---|
19 | | - * Boston, MA 021110-1307, USA. |
---|
20 | 6 | * |
---|
21 | 7 | * Based on sysfs: |
---|
22 | 8 | * sysfs is Copyright (C) 2001, 2002, 2003 Patrick Mochel |
---|
.. | .. |
---|
27 | 13 | #undef DEBUG |
---|
28 | 14 | |
---|
29 | 15 | #include <linux/fs.h> |
---|
| 16 | +#include <linux/fsnotify.h> |
---|
30 | 17 | #include <linux/mount.h> |
---|
31 | 18 | #include <linux/module.h> |
---|
32 | 19 | #include <linux/slab.h> |
---|
.. | .. |
---|
35 | 22 | #include <linux/configfs.h> |
---|
36 | 23 | #include "configfs_internal.h" |
---|
37 | 24 | |
---|
38 | | -DECLARE_RWSEM(configfs_rename_sem); |
---|
39 | 25 | /* |
---|
40 | 26 | * Protects mutations of configfs_dirent linkage together with proper i_mutex |
---|
41 | 27 | * Also protects mutations of symlinks linkage to target configfs_dirent |
---|
.. | .. |
---|
212 | 198 | return ERR_PTR(-ENOMEM); |
---|
213 | 199 | |
---|
214 | 200 | atomic_set(&sd->s_count, 1); |
---|
215 | | - INIT_LIST_HEAD(&sd->s_links); |
---|
216 | 201 | INIT_LIST_HEAD(&sd->s_children); |
---|
217 | 202 | sd->s_element = element; |
---|
218 | 203 | sd->s_type = type; |
---|
.. | .. |
---|
274 | 259 | return 0; |
---|
275 | 260 | } |
---|
276 | 261 | |
---|
277 | | -static void init_dir(struct inode * inode) |
---|
| 262 | +static void configfs_remove_dirent(struct dentry *dentry) |
---|
278 | 263 | { |
---|
279 | | - inode->i_op = &configfs_dir_inode_operations; |
---|
280 | | - inode->i_fop = &configfs_dir_operations; |
---|
| 264 | + struct configfs_dirent *sd = dentry->d_fsdata; |
---|
281 | 265 | |
---|
282 | | - /* directory inodes start off with i_nlink == 2 (for "." entry) */ |
---|
283 | | - inc_nlink(inode); |
---|
284 | | -} |
---|
285 | | - |
---|
286 | | -static void configfs_init_file(struct inode * inode) |
---|
287 | | -{ |
---|
288 | | - inode->i_size = PAGE_SIZE; |
---|
289 | | - inode->i_fop = &configfs_file_operations; |
---|
290 | | -} |
---|
291 | | - |
---|
292 | | -static void configfs_init_bin_file(struct inode *inode) |
---|
293 | | -{ |
---|
294 | | - inode->i_size = 0; |
---|
295 | | - inode->i_fop = &configfs_bin_file_operations; |
---|
296 | | -} |
---|
297 | | - |
---|
298 | | -static void init_symlink(struct inode * inode) |
---|
299 | | -{ |
---|
300 | | - inode->i_op = &configfs_symlink_inode_operations; |
---|
| 266 | + if (!sd) |
---|
| 267 | + return; |
---|
| 268 | + spin_lock(&configfs_dirent_lock); |
---|
| 269 | + list_del_init(&sd->s_sibling); |
---|
| 270 | + spin_unlock(&configfs_dirent_lock); |
---|
| 271 | + configfs_put(sd); |
---|
301 | 272 | } |
---|
302 | 273 | |
---|
303 | 274 | /** |
---|
.. | .. |
---|
315 | 286 | int error; |
---|
316 | 287 | umode_t mode = S_IFDIR| S_IRWXU | S_IRUGO | S_IXUGO; |
---|
317 | 288 | struct dentry *p = dentry->d_parent; |
---|
| 289 | + struct inode *inode; |
---|
318 | 290 | |
---|
319 | 291 | BUG_ON(!item); |
---|
320 | 292 | |
---|
.. | .. |
---|
329 | 301 | return error; |
---|
330 | 302 | |
---|
331 | 303 | configfs_set_dir_dirent_depth(p->d_fsdata, dentry->d_fsdata); |
---|
332 | | - error = configfs_create(dentry, mode, init_dir); |
---|
333 | | - if (!error) { |
---|
334 | | - inc_nlink(d_inode(p)); |
---|
335 | | - item->ci_dentry = dentry; |
---|
336 | | - } else { |
---|
337 | | - struct configfs_dirent *sd = dentry->d_fsdata; |
---|
338 | | - if (sd) { |
---|
339 | | - spin_lock(&configfs_dirent_lock); |
---|
340 | | - list_del_init(&sd->s_sibling); |
---|
341 | | - spin_unlock(&configfs_dirent_lock); |
---|
342 | | - configfs_put(sd); |
---|
343 | | - } |
---|
344 | | - } |
---|
345 | | - return error; |
---|
| 304 | + inode = configfs_create(dentry, mode); |
---|
| 305 | + if (IS_ERR(inode)) |
---|
| 306 | + goto out_remove; |
---|
| 307 | + |
---|
| 308 | + inode->i_op = &configfs_dir_inode_operations; |
---|
| 309 | + inode->i_fop = &configfs_dir_operations; |
---|
| 310 | + /* directory inodes start off with i_nlink == 2 (for "." entry) */ |
---|
| 311 | + inc_nlink(inode); |
---|
| 312 | + d_instantiate(dentry, inode); |
---|
| 313 | + /* already hashed */ |
---|
| 314 | + dget(dentry); /* pin directory dentries in core */ |
---|
| 315 | + inc_nlink(d_inode(p)); |
---|
| 316 | + item->ci_dentry = dentry; |
---|
| 317 | + return 0; |
---|
| 318 | + |
---|
| 319 | +out_remove: |
---|
| 320 | + configfs_put(dentry->d_fsdata); |
---|
| 321 | + configfs_remove_dirent(dentry); |
---|
| 322 | + return PTR_ERR(inode); |
---|
346 | 323 | } |
---|
347 | 324 | |
---|
348 | 325 | /* |
---|
.. | .. |
---|
383 | 360 | return ret; |
---|
384 | 361 | } |
---|
385 | 362 | |
---|
386 | | -int configfs_create_link(struct configfs_symlink *sl, |
---|
387 | | - struct dentry *parent, |
---|
388 | | - struct dentry *dentry) |
---|
| 363 | +int configfs_create_link(struct configfs_dirent *target, struct dentry *parent, |
---|
| 364 | + struct dentry *dentry, char *body) |
---|
389 | 365 | { |
---|
390 | 366 | int err = 0; |
---|
391 | 367 | umode_t mode = S_IFLNK | S_IRWXUGO; |
---|
392 | 368 | struct configfs_dirent *p = parent->d_fsdata; |
---|
| 369 | + struct inode *inode; |
---|
393 | 370 | |
---|
394 | | - err = configfs_make_dirent(p, dentry, sl, mode, |
---|
395 | | - CONFIGFS_ITEM_LINK, p->s_frag); |
---|
396 | | - if (!err) { |
---|
397 | | - err = configfs_create(dentry, mode, init_symlink); |
---|
398 | | - if (err) { |
---|
399 | | - struct configfs_dirent *sd = dentry->d_fsdata; |
---|
400 | | - if (sd) { |
---|
401 | | - spin_lock(&configfs_dirent_lock); |
---|
402 | | - list_del_init(&sd->s_sibling); |
---|
403 | | - spin_unlock(&configfs_dirent_lock); |
---|
404 | | - configfs_put(sd); |
---|
405 | | - } |
---|
406 | | - } |
---|
407 | | - } |
---|
408 | | - return err; |
---|
| 371 | + err = configfs_make_dirent(p, dentry, target, mode, CONFIGFS_ITEM_LINK, |
---|
| 372 | + p->s_frag); |
---|
| 373 | + if (err) |
---|
| 374 | + return err; |
---|
| 375 | + |
---|
| 376 | + inode = configfs_create(dentry, mode); |
---|
| 377 | + if (IS_ERR(inode)) |
---|
| 378 | + goto out_remove; |
---|
| 379 | + |
---|
| 380 | + inode->i_link = body; |
---|
| 381 | + inode->i_op = &configfs_symlink_inode_operations; |
---|
| 382 | + d_instantiate(dentry, inode); |
---|
| 383 | + dget(dentry); /* pin link dentries in core */ |
---|
| 384 | + return 0; |
---|
| 385 | + |
---|
| 386 | +out_remove: |
---|
| 387 | + configfs_put(dentry->d_fsdata); |
---|
| 388 | + configfs_remove_dirent(dentry); |
---|
| 389 | + return PTR_ERR(inode); |
---|
409 | 390 | } |
---|
410 | 391 | |
---|
411 | 392 | static void remove_dir(struct dentry * d) |
---|
412 | 393 | { |
---|
413 | 394 | struct dentry * parent = dget(d->d_parent); |
---|
414 | | - struct configfs_dirent * sd; |
---|
415 | 395 | |
---|
416 | | - sd = d->d_fsdata; |
---|
417 | | - spin_lock(&configfs_dirent_lock); |
---|
418 | | - list_del_init(&sd->s_sibling); |
---|
419 | | - spin_unlock(&configfs_dirent_lock); |
---|
420 | | - configfs_put(sd); |
---|
| 396 | + configfs_remove_dirent(d); |
---|
| 397 | + |
---|
421 | 398 | if (d_really_is_positive(d)) |
---|
422 | 399 | simple_rmdir(d_inode(parent),d); |
---|
423 | 400 | |
---|
.. | .. |
---|
458 | 435 | static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * dentry) |
---|
459 | 436 | { |
---|
460 | 437 | struct configfs_attribute * attr = sd->s_element; |
---|
461 | | - int error; |
---|
| 438 | + struct inode *inode; |
---|
462 | 439 | |
---|
463 | 440 | spin_lock(&configfs_dirent_lock); |
---|
464 | 441 | dentry->d_fsdata = configfs_get(sd); |
---|
465 | 442 | sd->s_dentry = dentry; |
---|
466 | 443 | spin_unlock(&configfs_dirent_lock); |
---|
467 | 444 | |
---|
468 | | - error = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG, |
---|
469 | | - (sd->s_type & CONFIGFS_ITEM_BIN_ATTR) ? |
---|
470 | | - configfs_init_bin_file : |
---|
471 | | - configfs_init_file); |
---|
472 | | - if (error) |
---|
| 445 | + inode = configfs_create(dentry, (attr->ca_mode & S_IALLUGO) | S_IFREG); |
---|
| 446 | + if (IS_ERR(inode)) { |
---|
473 | 447 | configfs_put(sd); |
---|
474 | | - return error; |
---|
| 448 | + return PTR_ERR(inode); |
---|
| 449 | + } |
---|
| 450 | + if (sd->s_type & CONFIGFS_ITEM_BIN_ATTR) { |
---|
| 451 | + inode->i_size = 0; |
---|
| 452 | + inode->i_fop = &configfs_bin_file_operations; |
---|
| 453 | + } else { |
---|
| 454 | + inode->i_size = PAGE_SIZE; |
---|
| 455 | + inode->i_fop = &configfs_file_operations; |
---|
| 456 | + } |
---|
| 457 | + d_add(dentry, inode); |
---|
| 458 | + return 0; |
---|
475 | 459 | } |
---|
476 | 460 | |
---|
477 | 461 | static struct dentry * configfs_lookup(struct inode *dir, |
---|
.. | .. |
---|
541 | 525 | parent_sd->s_type |= CONFIGFS_USET_DROPPING; |
---|
542 | 526 | |
---|
543 | 527 | ret = -EBUSY; |
---|
544 | | - if (!list_empty(&parent_sd->s_links)) |
---|
| 528 | + if (parent_sd->s_links) |
---|
545 | 529 | goto out; |
---|
546 | 530 | |
---|
547 | 531 | ret = 0; |
---|
.. | .. |
---|
1194 | 1178 | |
---|
1195 | 1179 | /* |
---|
1196 | 1180 | * Release the dependent linkage. This is much simpler than |
---|
1197 | | - * configfs_depend_item() because we know that that the client driver is |
---|
| 1181 | + * configfs_depend_item() because we know that the client driver is |
---|
1198 | 1182 | * pinned, thus the subsystem is pinned, and therefore configfs is pinned. |
---|
1199 | 1183 | */ |
---|
1200 | 1184 | void configfs_undepend_item(struct config_item *target) |
---|
.. | .. |
---|
1435 | 1419 | else |
---|
1436 | 1420 | ret = configfs_attach_item(parent_item, item, dentry, frag); |
---|
1437 | 1421 | |
---|
| 1422 | + /* inherit uid/gid from process creating the directory */ |
---|
| 1423 | + if (!uid_eq(current_fsuid(), GLOBAL_ROOT_UID) || |
---|
| 1424 | + !gid_eq(current_fsgid(), GLOBAL_ROOT_GID)) { |
---|
| 1425 | + struct iattr ia = { |
---|
| 1426 | + .ia_uid = current_fsuid(), |
---|
| 1427 | + .ia_gid = current_fsgid(), |
---|
| 1428 | + .ia_valid = ATTR_UID | ATTR_GID, |
---|
| 1429 | + }; |
---|
| 1430 | + struct inode *inode = d_inode(dentry); |
---|
| 1431 | + inode->i_uid = ia.ia_uid; |
---|
| 1432 | + inode->i_gid = ia.ia_gid; |
---|
| 1433 | + /* the above manual assignments skip the permission checks */ |
---|
| 1434 | + configfs_setattr(dentry, &ia); |
---|
| 1435 | + } |
---|
| 1436 | + |
---|
1438 | 1437 | spin_lock(&configfs_dirent_lock); |
---|
1439 | 1438 | sd->s_type &= ~CONFIGFS_USET_IN_MKDIR; |
---|
1440 | 1439 | if (!ret) |
---|
.. | .. |
---|
1600 | 1599 | .setattr = configfs_setattr, |
---|
1601 | 1600 | }; |
---|
1602 | 1601 | |
---|
1603 | | -#if 0 |
---|
1604 | | -int configfs_rename_dir(struct config_item * item, const char *new_name) |
---|
1605 | | -{ |
---|
1606 | | - int error = 0; |
---|
1607 | | - struct dentry * new_dentry, * parent; |
---|
1608 | | - |
---|
1609 | | - if (!strcmp(config_item_name(item), new_name)) |
---|
1610 | | - return -EINVAL; |
---|
1611 | | - |
---|
1612 | | - if (!item->parent) |
---|
1613 | | - return -EINVAL; |
---|
1614 | | - |
---|
1615 | | - down_write(&configfs_rename_sem); |
---|
1616 | | - parent = item->parent->dentry; |
---|
1617 | | - |
---|
1618 | | - inode_lock(d_inode(parent)); |
---|
1619 | | - |
---|
1620 | | - new_dentry = lookup_one_len(new_name, parent, strlen(new_name)); |
---|
1621 | | - if (!IS_ERR(new_dentry)) { |
---|
1622 | | - if (d_really_is_negative(new_dentry)) { |
---|
1623 | | - error = config_item_set_name(item, "%s", new_name); |
---|
1624 | | - if (!error) { |
---|
1625 | | - d_add(new_dentry, NULL); |
---|
1626 | | - d_move(item->dentry, new_dentry); |
---|
1627 | | - } |
---|
1628 | | - else |
---|
1629 | | - d_delete(new_dentry); |
---|
1630 | | - } else |
---|
1631 | | - error = -EEXIST; |
---|
1632 | | - dput(new_dentry); |
---|
1633 | | - } |
---|
1634 | | - inode_unlock(d_inode(parent)); |
---|
1635 | | - up_write(&configfs_rename_sem); |
---|
1636 | | - |
---|
1637 | | - return error; |
---|
1638 | | -} |
---|
1639 | | -#endif |
---|
1640 | | - |
---|
1641 | 1602 | static int configfs_dir_open(struct inode *inode, struct file *file) |
---|
1642 | 1603 | { |
---|
1643 | 1604 | struct dentry * dentry = file->f_path.dentry; |
---|
.. | .. |
---|
1752 | 1713 | switch (whence) { |
---|
1753 | 1714 | case 1: |
---|
1754 | 1715 | offset += file->f_pos; |
---|
| 1716 | + fallthrough; |
---|
1755 | 1717 | case 0: |
---|
1756 | 1718 | if (offset >= 0) |
---|
1757 | 1719 | break; |
---|
| 1720 | + fallthrough; |
---|
1758 | 1721 | default: |
---|
1759 | 1722 | return -EINVAL; |
---|
1760 | 1723 | } |
---|
.. | .. |
---|
1867 | 1830 | configfs_detach_group(&group->cg_item); |
---|
1868 | 1831 | d_inode(dentry)->i_flags |= S_DEAD; |
---|
1869 | 1832 | dont_mount(dentry); |
---|
1870 | | - d_delete(dentry); |
---|
| 1833 | + d_drop(dentry); |
---|
| 1834 | + fsnotify_rmdir(d_inode(parent), dentry); |
---|
1871 | 1835 | inode_unlock(d_inode(parent)); |
---|
1872 | 1836 | |
---|
1873 | 1837 | dput(dentry); |
---|
.. | .. |
---|
2014 | 1978 | dont_mount(dentry); |
---|
2015 | 1979 | inode_unlock(d_inode(dentry)); |
---|
2016 | 1980 | |
---|
2017 | | - d_delete(dentry); |
---|
| 1981 | + d_drop(dentry); |
---|
| 1982 | + fsnotify_rmdir(d_inode(root), dentry); |
---|
2018 | 1983 | |
---|
2019 | 1984 | inode_unlock(d_inode(root)); |
---|
2020 | 1985 | |
---|