Commit 4768e9b18dc63719209c68920d4ae52dc49b6161
Committed by
Mark Fasheh
1 parent
dacdd0e047
Exists in
master
and in
20 other branches
[PATCH] configfs: Fix symlink() to a removing item
The rule for configfs symlinks is that symlinks always point to valid config_items, and prevent the target from being removed. However, configfs_symlink() only checks that it can grab a reference on the target item, without ensuring that it remains alive until the symlink is correctly attached. This patch makes configfs_symlink() fail whenever the target is being removed, using the CONFIGFS_USET_DROPPING flag set by configfs_detach_prep() and protected by configfs_dirent_lock. This patch introduces a similar (weird?) behavior as with mkdir failures making rmdir fail: if symlink() races with rmdir() of the parent directory (or its youngest user-created ancestor if parent is a default group) or rmdir() of the target directory, and then fails in configfs_create(), this can make the racing rmdir() fail despite the concerned directory having no user-created entry (resp. no symlink pointing to it or one of its default groups) in the end. This behavior is fixed in later patches. Signed-off-by: Louis Rilling <louis.rilling@kerlabs.com> Signed-off-by: Joel Becker <joel.becker@oracle.com> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Showing 2 changed files with 13 additions and 7 deletions Side-by-side Diff
fs/configfs/dir.c
... | ... | @@ -370,6 +370,9 @@ |
370 | 370 | struct configfs_dirent *sd; |
371 | 371 | int ret; |
372 | 372 | |
373 | + /* Mark that we're trying to drop the group */ | |
374 | + parent_sd->s_type |= CONFIGFS_USET_DROPPING; | |
375 | + | |
373 | 376 | ret = -EBUSY; |
374 | 377 | if (!list_empty(&parent_sd->s_links)) |
375 | 378 | goto out; |
... | ... | @@ -385,8 +388,6 @@ |
385 | 388 | *wait_mutex = &sd->s_dentry->d_inode->i_mutex; |
386 | 389 | return -EAGAIN; |
387 | 390 | } |
388 | - /* Mark that we're trying to drop the group */ | |
389 | - sd->s_type |= CONFIGFS_USET_DROPPING; | |
390 | 391 | |
391 | 392 | /* |
392 | 393 | * Yup, recursive. If there's a problem, blame |
393 | 394 | |
... | ... | @@ -414,12 +415,11 @@ |
414 | 415 | struct configfs_dirent *parent_sd = dentry->d_fsdata; |
415 | 416 | struct configfs_dirent *sd; |
416 | 417 | |
417 | - list_for_each_entry(sd, &parent_sd->s_children, s_sibling) { | |
418 | - if (sd->s_type & CONFIGFS_USET_DEFAULT) { | |
418 | + parent_sd->s_type &= ~CONFIGFS_USET_DROPPING; | |
419 | + | |
420 | + list_for_each_entry(sd, &parent_sd->s_children, s_sibling) | |
421 | + if (sd->s_type & CONFIGFS_USET_DEFAULT) | |
419 | 422 | configfs_detach_rollback(sd->s_dentry); |
420 | - sd->s_type &= ~CONFIGFS_USET_DROPPING; | |
421 | - } | |
422 | - } | |
423 | 423 | } |
424 | 424 | |
425 | 425 | static void detach_attrs(struct config_item * item) |
fs/configfs/symlink.c
... | ... | @@ -78,6 +78,12 @@ |
78 | 78 | if (sl) { |
79 | 79 | sl->sl_target = config_item_get(item); |
80 | 80 | spin_lock(&configfs_dirent_lock); |
81 | + if (target_sd->s_type & CONFIGFS_USET_DROPPING) { | |
82 | + spin_unlock(&configfs_dirent_lock); | |
83 | + config_item_put(item); | |
84 | + kfree(sl); | |
85 | + return -ENOENT; | |
86 | + } | |
81 | 87 | list_add(&sl->sl_list, &target_sd->s_links); |
82 | 88 | spin_unlock(&configfs_dirent_lock); |
83 | 89 | ret = configfs_create_link(sl, parent_item->ci_dentry, |