/*! 2016-06-04 study -ing */ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, const void *ns) { struct kernfs_addrm_cxt acxt; struct kernfs_node *kn; if (!parent) { WARN(1, KERN_WARNING "kernfs: can not remove '%s', no directory\n", name); return -ENOENT; } /*! acxt전체를 0으로 memset 후 mutex lock 건다. */ kernfs_addrm_start(&acxt); /*! name + ns 를 이용하여 원하는 kn을 찾는다. */ kn = kernfs_find_ns(parent, name, ns); /*! 찾으면 remove */ if (kn) __kernfs_remove(&acxt, kn); /*! kernelfs add-remove 끝내기 */ kernfs_addrm_finish(&acxt); if (kn) return 0; else return -ENOENT; }
/*! 2017. 1.07 study -ing */ void kernfs_remove(struct kernfs_node *kn) { struct kernfs_addrm_cxt acxt; kernfs_addrm_start(&acxt); __kernfs_remove(&acxt, kn); kernfs_addrm_finish(&acxt); }
/** * kernfs_remove_self - remove a kernfs_node from its own method * @kn: the self kernfs_node to remove * * The caller must be running off of a kernfs operation which is invoked * with an active reference - e.g. one of kernfs_ops. This can be used to * implement a file operation which deletes itself. * * For example, the "delete" file for a sysfs device directory can be * implemented by invoking kernfs_remove_self() on the "delete" file * itself. This function breaks the circular dependency of trying to * deactivate self while holding an active ref itself. It isn't necessary * to modify the usual removal path to use kernfs_remove_self(). The * "delete" implementation can simply invoke kernfs_remove_self() on self * before proceeding with the usual removal path. kernfs will ignore later * kernfs_remove() on self. * * kernfs_remove_self() can be called multiple times concurrently on the * same kernfs_node. Only the first one actually performs removal and * returns %true. All others will wait until the kernfs operation which * won self-removal finishes and return %false. Note that the losers wait * for the completion of not only the winning kernfs_remove_self() but also * the whole kernfs_ops which won the arbitration. This can be used to * guarantee, for example, all concurrent writes to a "delete" file to * finish only after the whole operation is complete. */ bool kernfs_remove_self(struct kernfs_node *kn) { bool ret; mutex_lock(&kernfs_mutex); kernfs_break_active_protection(kn); /* * SUICIDAL is used to arbitrate among competing invocations. Only * the first one will actually perform removal. When the removal * is complete, SUICIDED is set and the active ref is restored * while holding kernfs_mutex. The ones which lost arbitration * waits for SUICDED && drained which can happen only after the * enclosing kernfs operation which executed the winning instance * of kernfs_remove_self() finished. */ if (!(kn->flags & KERNFS_SUICIDAL)) { kn->flags |= KERNFS_SUICIDAL; __kernfs_remove(kn); kn->flags |= KERNFS_SUICIDED; ret = true; } else { wait_queue_head_t *waitq = &kernfs_root(kn)->deactivate_waitq; DEFINE_WAIT(wait); while (true) { prepare_to_wait(waitq, &wait, TASK_UNINTERRUPTIBLE); if ((kn->flags & KERNFS_SUICIDED) && atomic_read(&kn->active) == KN_DEACTIVATED_BIAS) break; mutex_unlock(&kernfs_mutex); schedule(); mutex_lock(&kernfs_mutex); } finish_wait(waitq, &wait); WARN_ON_ONCE(!RB_EMPTY_NODE(&kn->rb)); ret = false; } /* * This must be done while holding kernfs_mutex; otherwise, waiting * for SUICIDED && deactivated could finish prematurely. */ kernfs_unbreak_active_protection(kn); mutex_unlock(&kernfs_mutex); return ret; }
/** * kernfs_remove_by_name_ns - find a kernfs_node by name and remove it * @parent: parent of the target * @name: name of the kernfs_node to remove * @ns: namespace tag of the kernfs_node to remove * * Look for the kernfs_node with @name and @ns under @parent and remove it. * Returns 0 on success, -ENOENT if such entry doesn't exist. */ int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name, const void *ns) { struct kernfs_node *kn; if (!parent) { WARN(1, KERN_WARNING "kernfs: can not remove '%s', no directory\n", name); return -ENOENT; } mutex_lock(&kernfs_mutex); kn = kernfs_find_ns(parent, name, ns); if (kn) __kernfs_remove(kn); mutex_unlock(&kernfs_mutex); if (kn) return 0; else return -ENOENT; }
/** * kernfs_remove - remove a kernfs_node recursively * @kn: the kernfs_node to remove * * Remove @kn along with all its subdirectories and files. */ void kernfs_remove(struct kernfs_node *kn) { mutex_lock(&kernfs_mutex); __kernfs_remove(kn); mutex_unlock(&kernfs_mutex); }