aboutsummaryrefslogtreecommitdiffstats
path: root/fs/kernfs
diff options
context:
space:
mode:
authorTejun Heo <tj@kernel.org>2014-01-10 08:57:27 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2014-01-10 17:01:05 -0500
commit1ae06819c77cff1ea2833c94f8c093fe8a5c79db (patch)
tree3ce85dce35a4551915630164ee8b0da66f7a5c22 /fs/kernfs
parent9f010c2ad5194a4b682e747984477850fabd03be (diff)
kernfs, sysfs, driver-core: implement kernfs_remove_self() and its wrappers
Sometimes it's necessary to implement a node which wants to delete nodes including itself. This isn't straightforward because of kernfs active reference. While a file operation is in progress, an active reference is held and kernfs_remove() waits for all such references to drain before completing. For a self-deleting node, this is a deadlock as kernfs_remove() ends up waiting for an active reference that itself is sitting on top of. This currently is worked around in the sysfs layer using sysfs_schedule_callback() which makes such removals asynchronous. While it works, it's rather cumbersome and inherently breaks synchronicity of the operation - the file operation which triggered the operation may complete before the removal is finished (or even started) and the removal may fail asynchronously. If a removal operation is immmediately followed by another operation which expects the specific name to be available (e.g. removal followed by rename onto the same name), there's no way to make the latter operation reliable. The thing is there's no inherent reason for this to be asynchrnous. All that's necessary to do this synchronous is a dedicated operation which drops its own active ref and deactivates self. This patch implements kernfs_remove_self() and its wrappers in sysfs and driver core. kernfs_remove_self() is to be called from one of the file operations, drops the active ref and deactivates using __kernfs_deactivate_self(), removes the self node, and restores active ref to the dead node using __kernfs_reactivate_self() so that the ref is balanced afterwards. __kernfs_remove() is updated so that it takes an early exit if the target node is already fully removed so that the active ref restored by kernfs_remove_self() after removal doesn't confuse the deactivation path. This makes implementing self-deleting nodes very easy. The normal removal path doesn't even need to be changed to use kernfs_remove_self() for the self-deleting node. The method can invoke kernfs_remove_self() on itself before proceeding the normal removal path. kernfs_remove() invoked on the node by the normal deletion path will simply be ignored. This will replace sysfs_schedule_callback(). A subtle feature of sysfs_schedule_callback() is that it collapses multiple invocations - even if multiple removals are triggered, the removal callback is run only once. An equivalent effect can be achieved by testing the return value of kernfs_remove_self() - only the one which gets %true return value should proceed with actual deletion. All other instances of kernfs_remove_self() will wait till the enclosing kernfs operation which invoked the winning instance of kernfs_remove_self() finishes and then return %false. This trivially makes all users of kernfs_remove_self() automatically show correct synchronous behavior even when there are multiple concurrent operations - all "echo 1 > delete" instances will finish only after the whole operation is completed by one of the instances. v2: For !CONFIG_SYSFS, dummy version kernfs_remove_self() was missing and sysfs_remove_file_self() had incorrect return type. Fix it. Reported by kbuild test bot. v3: Updated to use __kernfs_{de|re}activate_self(). Signed-off-by: Tejun Heo <tj@kernel.org> Cc: Alan Stern <stern@rowland.harvard.edu> Cc: kbuild test robot <fengguang.wu@intel.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/kernfs')
-rw-r--r--fs/kernfs/dir.c72
1 files changed, 72 insertions, 0 deletions
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 1aeb57969bff..a8028be6cdb7 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -986,6 +986,78 @@ void kernfs_remove(struct kernfs_node *kn)
986} 986}
987 987
988/** 988/**
989 * kernfs_remove_self - remove a kernfs_node from its own method
990 * @kn: the self kernfs_node to remove
991 *
992 * The caller must be running off of a kernfs operation which is invoked
993 * with an active reference - e.g. one of kernfs_ops. This can be used to
994 * implement a file operation which deletes itself.
995 *
996 * For example, the "delete" file for a sysfs device directory can be
997 * implemented by invoking kernfs_remove_self() on the "delete" file
998 * itself. This function breaks the circular dependency of trying to
999 * deactivate self while holding an active ref itself. It isn't necessary
1000 * to modify the usual removal path to use kernfs_remove_self(). The
1001 * "delete" implementation can simply invoke kernfs_remove_self() on self
1002 * before proceeding with the usual removal path. kernfs will ignore later
1003 * kernfs_remove() on self.
1004 *
1005 * kernfs_remove_self() can be called multiple times concurrently on the
1006 * same kernfs_node. Only the first one actually performs removal and
1007 * returns %true. All others will wait until the kernfs operation which
1008 * won self-removal finishes and return %false. Note that the losers wait
1009 * for the completion of not only the winning kernfs_remove_self() but also
1010 * the whole kernfs_ops which won the arbitration. This can be used to
1011 * guarantee, for example, all concurrent writes to a "delete" file to
1012 * finish only after the whole operation is complete.
1013 */
1014bool kernfs_remove_self(struct kernfs_node *kn)
1015{
1016 bool ret;
1017
1018 mutex_lock(&kernfs_mutex);
1019 __kernfs_deactivate_self(kn);
1020
1021 /*
1022 * SUICIDAL is used to arbitrate among competing invocations. Only
1023 * the first one will actually perform removal. When the removal
1024 * is complete, SUICIDED is set and the active ref is restored
1025 * while holding kernfs_mutex. The ones which lost arbitration
1026 * waits for SUICDED && drained which can happen only after the
1027 * enclosing kernfs operation which executed the winning instance
1028 * of kernfs_remove_self() finished.
1029 */
1030 if (!(kn->flags & KERNFS_SUICIDAL)) {
1031 kn->flags |= KERNFS_SUICIDAL;
1032 __kernfs_remove(kn);
1033 kn->flags |= KERNFS_SUICIDED;
1034 ret = true;
1035 } else {
1036 wait_queue_head_t *waitq = &kernfs_root(kn)->deactivate_waitq;
1037 DEFINE_WAIT(wait);
1038
1039 while (true) {
1040 prepare_to_wait(waitq, &wait, TASK_UNINTERRUPTIBLE);
1041
1042 if ((kn->flags & KERNFS_SUICIDED) &&
1043 atomic_read(&kn->active) == KN_DEACTIVATED_BIAS)
1044 break;
1045
1046 mutex_unlock(&kernfs_mutex);
1047 schedule();
1048 mutex_lock(&kernfs_mutex);
1049 }
1050 finish_wait(waitq, &wait);
1051 WARN_ON_ONCE(!RB_EMPTY_NODE(&kn->rb));
1052 ret = false;
1053 }
1054
1055 __kernfs_reactivate_self(kn);
1056 mutex_unlock(&kernfs_mutex);
1057 return ret;
1058}
1059
1060/**
989 * kernfs_remove_by_name_ns - find a kernfs_node by name and remove it 1061 * kernfs_remove_by_name_ns - find a kernfs_node by name and remove it
990 * @parent: parent of the target 1062 * @parent: parent of the target
991 * @name: name of the kernfs_node to remove 1063 * @name: name of the kernfs_node to remove