Bogus dir.c file introduced at top level.
Hi Tiejun,
This merge:
commit a8fa94e0f2ab665f9aa665195618178b61ed8304
Merge: 9561a89 b28a960
Author: Tejun Heo <[email protected]>
Date: Mon Feb 10 19:34:30 2014 -0500
Merge branch 'master' into driver-core-next-test-merge-rc2
introduces a bogus copy of fs/kernfs/dir.c at the top level of the tree. Seen in the Feb19th linux-next tree.
Thanks,
Paul.
(cc'ing Greg)
Quoted 9 lines · Paul Gortmaker
Hi Tiejun,
This merge:
commit
a8fa94e0f2ab665f9aa665195618178b61ed8304
Merge: 9561a89 b28a960
Author: Tejun Heo <[email protected]>
Date: Mon Feb 10 19:34:30 2014 -0500
Quoted 4 lines
Merge branch 'master' into driver-core-next-test-merge-rc2
introduces a bogus copy of
fs/kernfs/dir.cat the top level of the tree. Seen in the Feb19th linux-next tree.
Gees, sorry about that. Wrong git-add, I guess. Unfortunately, the commit seems to be buried under other commits already. I'll send a patch to remove the file soon.
Thanks.
Signature · 1 line
tejun
PATCH 1/1 kernfs: remove duplicate dir.c at the top dir
a8fa94e0f2ab ("Merge branch 'master' into driver-core-next-test-merge-rc2") mistakenly introduced a duplicate dir.c at the top directory. Remove it.
--- dir.c | 1248 ------------------------------------------------------------------ 1 file changed, 1248 deletions(-)
dir.c deleted +0 -1248
@@ -1,1248 +0,0 @@ -/* -* fs/kernfs/dir.c - kernfs directory implementation -* -* Copyright (c) 2001-3 Patrick Mochel -* Copyright (c) 2007 SUSE Linux Products GmbH -* Copyright (c) 2007, 2013 Tejun Heo <[email protected]> -* -* This file is released under the GPLv2. -*/ - -#include <linux/sched.h> -#include <linux/fs.h> -#include <linux/namei.h> -#include <linux/idr.h> -#include <linux/slab.h> -#include <linux/security.h> -#include <linux/hash.h> - -#include "kernfs-internal.h" - -DEFINE_MUTEX (kernfs_mutex); - -#define rb_to_kn (X ) rb_entry((X), struct kernfs_node, rb) - -static bool kernfs_active (struct kernfs_node *kn) -{ -lockdep_assert_held (&kernfs_mutex); -return atomic_read (&kn->active) >=0 ; -} - -static bool kernfs_lockdep (struct kernfs_node *kn) -{ -#ifdef CONFIG_DEBUG_LOCK_ALLOC -return kn->flags &KERNFS_LOCKDEP ; -#else -return false; -#endif -} - -/** -* kernfs_name_hash -* @name: Null terminated string to hash -* @ns: Namespace tag to hash -* -* Returns 31 bit hash of ns + name (so it fits in an off_t ) -*/ -static unsigned int kernfs_name_hash (const char *name,const void *ns) -{ -unsigned long hash =init_name_hash (); -unsigned int len =strlen (name); -while (len--) - hash =partial_name_hash (*name++, hash); - hash = (end_name_hash (hash) ^hash_ptr ((void *)ns,31 )); - hash &=0x7fffffffU ; -/* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */ -if (hash <1 ) - hash +=2 ; -if (hash >=INT_MAX ) - hash =INT_MAX -1 ; -return hash; -} - -static int kernfs_name_compare (unsigned int hash,const char *name, -const void *ns,const struct kernfs_node *kn) -{ -if (hash != kn->hash) -return hash - kn->hash; -if (ns != kn->ns) -return ns - kn->ns; -return strcmp (name, kn->name); -} - -static int kernfs_sd_compare (const struct kernfs_node *left, -const struct kernfs_node *right) -{ -return kernfs_name_compare (left->hash, left->name, left->ns, right); -} - -/** -* kernfs_link_sibling - link kernfs_node into sibling rbtree -* @kn: kernfs_node of interest -* -* Link @kn into its sibling rbtree which starts from -* @kn->parent->dir.children. -* -* Locking: -* mutex_lock(kernfs_mutex) -* -* RETURNS: -* 0 on susccess -EEXIST on failure. -*/ -static int kernfs_link_sibling (struct kernfs_node *kn) -{ -struct rb_node **node = &kn->parent->dir.children.rb_node; -struct rb_node *parent =NULL ; - -if (kernfs_type (kn) ==KERNFS_DIR ) - kn->parent->dir.subdirs++; - -while (*node) { -struct kernfs_node *pos; -int result; - - pos =rb_to_kn (*node); - parent = *node; - result =kernfs_sd_compare (kn, pos); -if (result <0 ) - node = &pos->rb.rb_left; -else if (result >0 ) - node = &pos->rb.rb_right; -else -return -EEXIST ; - } -/* add new node and rebalance the tree */ -rb_link_node (&kn->rb, parent, node); -rb_insert_color (&kn->rb, &kn->parent->dir.children); -return 0 ; -} - -/** -* kernfs_unlink_sibling - unlink kernfs_node from sibling rbtree -* @kn: kernfs_node of interest -* -* Try to unlink @kn from its sibling rbtree which starts from -* kn->parent->dir.children. Returns %true if @kn was actually -* removed, %false if @kn wasn't on the rbtree. -* -* Locking: -* mutex_lock(kernfs_mutex) -*/ -static bool kernfs_unlink_sibling (struct kernfs_node *kn) -{ -if (RB_EMPTY_NODE (&kn->rb)) -return false; - -if (kernfs_type (kn) ==KERNFS_DIR ) - kn->parent->dir.subdirs--; - -rb_erase (&kn->rb, &kn->parent->dir.children); -RB_CLEAR_NODE (&kn->rb); -return true; -} - -/** -* kernfs_get_active - get an active reference to kernfs_node -* @kn: kernfs_node to get an active reference to -* -* Get an active reference of @kn. This function is noop if @kn -* is NULL. -* -* RETURNS: -* Pointer to @kn on success, NULL on failure. -*/ -struct kernfs_node *kernfs_get_active (struct kernfs_node *kn) -{ -if (unlikely (!kn)) -return NULL ; - -if (!atomic_inc_unless_negative (&kn->active)) -return NULL ; - -if (kernfs_lockdep (kn)) -rwsem_acquire_read (&kn->dep_map,0 ,1 , _RET_IP_); -return kn; -} - -/** -* kernfs_put_active - put an active reference to kernfs_node -* @kn: kernfs_node to put an active reference to -* -* Put an active reference to @kn. This function is noop if @kn -* is NULL. -*/ -void kernfs_put_active (struct kernfs_node *kn) -{ -struct kernfs_root *root =kernfs_root (kn); -int v; - -if (unlikely (!kn)) -return ; - -if (kernfs_lockdep (kn)) -rwsem_release (&kn->dep_map,1 , _RET_IP_); - v =atomic_dec_return (&kn->active); -if (likely (v !=KN_DEACTIVATED_BIAS )) -return ; - -wake_up_all (&root->deactivate_waitq); -} - -/** -* kernfs_drain - drain kernfs_node -* @kn: kernfs_node to drain -* -* Drain existing usages and nuke all existing mmaps of @kn. Mutiple -* removers may invoke this function concurrently on @kn and all will -* return after draining is complete. -*/ -static void kernfs_drain (struct kernfs_node *kn) - __releases(&kernfs_mutex) __acquires(&kernfs_mutex) -{ -struct kernfs_root *root =kernfs_root (kn); - -lockdep_assert_held (&kernfs_mutex); -WARN_ON_ONCE (kernfs_active (kn)); - -mutex_unlock (&kernfs_mutex); - -if (kernfs_lockdep (kn)) { -rwsem_acquire (&kn->dep_map,0 ,0 , _RET_IP_); -if (atomic_read (&kn->active) !=KN_DEACTIVATED_BIAS ) -lock_contended (&kn->dep_map, _RET_IP_); - } - -/* but everyone should wait for draining */ -wait_event (root->deactivate_waitq, -atomic_read (&kn->active) ==KN_DEACTIVATED_BIAS ); - -if (kernfs_lockdep (kn)) { -lock_acquired (&kn->dep_map, _RET_IP_); -rwsem_release (&kn->dep_map,1 , _RET_IP_); - } - -kernfs_unmap_bin_file (kn); - -mutex_lock (&kernfs_mutex); -} - -/** -* kernfs_get - get a reference count on a kernfs_node -* @kn: the target kernfs_node -*/ -void kernfs_get (struct kernfs_node *kn) -{ -if (kn) { -WARN_ON (!atomic_read (&kn->count)); -atomic_inc (&kn->count); - } -} -EXPORT_SYMBOL_GPL (kernfs_get); - -/** -* kernfs_put - put a reference count on a kernfs_node -* @kn: the target kernfs_node -* -* Put a reference count of @kn and destroy it if it reached zero. -*/ -void kernfs_put (struct kernfs_node *kn) -{ -struct kernfs_node *parent; -struct kernfs_root *root; - -if (!kn || !atomic_dec_and_test (&kn->count)) -return ; - root =kernfs_root (kn); - repeat: -/* -* Moving/renaming is always done while holding reference. -* kn->parent won't change beneath us. -*/ - parent = kn->parent; - -WARN_ONCE (atomic_read (&kn->active) !=KN_DEACTIVATED_BIAS , -"kernfs_put: %s/%s: released with incorrect active_ref %d\n" , - parent ? parent->name :"" , kn->name,atomic_read (&kn->active)); - -if (kernfs_type (kn) ==KERNFS_LINK ) -kernfs_put (kn->symlink.target_kn); -if (!(kn->flags &KERNFS_STATIC_NAME )) -kfree (kn->name); -if (kn->iattr) { -if (kn->iattr->ia_secdata) -security_release_secctx (kn->iattr->ia_secdata, - kn->iattr->ia_secdata_len); -simple_xattrs_free (&kn->iattr->xattrs); - } -kfree (kn->iattr); -ida_simple_remove (&root->ino_ida, kn->ino); -kmem_cache_free (kernfs_node_cache, kn); - - kn = parent; -if (kn) { -if (atomic_dec_and_test (&kn->count)) - goto repeat; - }else { -/* just released the root kn, free @root too */ -ida_destroy (&root->ino_ida); -kfree (root); - } -} -EXPORT_SYMBOL_GPL (kernfs_put); - -static int kernfs_dop_revalidate (struct dentry *dentry,unsigned int flags) -{ -struct kernfs_node *kn; - -if (flags &LOOKUP_RCU ) -return -ECHILD ; - -/* Always perform fresh lookup for negatives */ -if (!dentry->d_inode) - goto out_bad_unlocked; - - kn = dentry->d_fsdata; -mutex_lock (&kernfs_mutex); - -/* The kernfs node has been deactivated */ -if (!kernfs_active (kn)) - goto out_bad; - -/* The kernfs node has been moved? */ -if (dentry->d_parent->d_fsdata != kn->parent) - goto out_bad; - -/* The kernfs node has been renamed */ -if (strcmp (dentry->d_name.name, kn->name) !=0 ) - goto out_bad; - -/* The kernfs node has been moved to a different namespace */ -if (kn->parent &&kernfs_ns_enabled (kn->parent) && -kernfs_info (dentry->d_sb)->ns != kn->ns) - goto out_bad; - -mutex_unlock (&kernfs_mutex); -out_valid: -return 1 ; -out_bad: -mutex_unlock (&kernfs_mutex); -out_bad_unlocked: -/* -* @dentry doesn't match the underlying kernfs node, drop the -* dentry and force lookup. If we have submounts we must allow the -* vfs caches to lie about the state of the filesystem to prevent -* leaks and other nasty things, so use check_submounts_and_drop() -* instead of d_drop(). -*/ -if (check_submounts_and_drop (dentry) !=0 ) - goto out_valid; - -return 0 ; -} - -static void kernfs_dop_release (struct dentry *dentry) -{ -kernfs_put (dentry->d_fsdata); -} - -const struct dentry_operations kernfs_dops = { - .d_revalidate = kernfs_dop_revalidate, - .d_release = kernfs_dop_release, -}; - -static struct kernfs_node *__kernfs_new_node (struct kernfs_root *root, -const char *name,umode_t mode, -unsigned flags) -{ -char *dup_name =NULL ; -struct kernfs_node *kn; -int ret; - -if (!(flags &KERNFS_STATIC_NAME )) { - name = dup_name =kstrdup (name,GFP_KERNEL ); -if (!name) -return NULL ; - } - - kn =kmem_cache_zalloc (kernfs_node_cache,GFP_KERNEL ); -if (!kn) - goto err_out1; - - ret =ida_simple_get (&root->ino_ida,1 ,0 ,GFP_KERNEL ); -if (ret <0 ) - goto err_out2; - kn->ino = ret; - -atomic_set (&kn->count,1 ); -atomic_set (&kn->active,KN_DEACTIVATED_BIAS ); -RB_CLEAR_NODE (&kn->rb); - - kn->name = name; - kn->mode = mode; - kn->flags = flags; - -return kn; - - err_out2: -kmem_cache_free (kernfs_node_cache, kn); - err_out1: -kfree (dup_name); -return NULL ; -} - -struct kernfs_node *kernfs_new_node (struct kernfs_node *parent, -const char *name,umode_t mode, -unsigned flags) -{ -struct kernfs_node *kn; - - kn =__kernfs_new_node (kernfs_root (parent), name, mode, flags); -if (kn) { -kernfs_get (parent); - kn->parent = parent; - } -return kn; -} - -/** -* kernfs_add_one - add kernfs_node to parent without warning -* @kn: kernfs_node to be added -* -* The caller must already have initialized @kn->parent. This -* function increments nlink of the parent's inode if @kn is a -* directory and link into the children list of the parent. -* -* RETURNS: -* 0 on success, -EEXIST if entry with the given name already -* exists. -*/ -int kernfs_add_one (struct kernfs_node *kn) -{ -struct kernfs_node *parent = kn->parent; -struct kernfs_iattrs *ps_iattr; -bool has_ns; -int ret; - -mutex_lock (&kernfs_mutex); - - ret = -EINVAL ; - has_ns =kernfs_ns_enabled (parent); -if (WARN (has_ns != (bool )kn->ns,KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n" , - has_ns ?"required" :"invalid" , parent->name, kn->name)) - goto out_unlock; - -if (kernfs_type (parent) !=KERNFS_DIR ) - goto out_unlock; - - ret = -ENOENT ; -if ((parent->flags &KERNFS_ACTIVATED ) && !kernfs_active (parent)) - goto out_unlock; - - kn->hash =kernfs_name_hash (kn->name, kn->ns); - - ret =kernfs_link_sibling (kn); -if (ret) - goto out_unlock; - -/* Update timestamps on the parent */ - ps_iattr = parent->iattr; -if (ps_iattr) { -struct iattr *ps_iattrs = &ps_iattr->ia_iattr; - ps_iattrs->ia_ctime = ps_iattrs->ia_mtime =CURRENT_TIME ; - } - -mutex_unlock (&kernfs_mutex); - -/* -* Activate the new node unless CREATE_DEACTIVATED is requested. -* If not activated here, the kernfs user is responsible for -* activating the node with kernfs_activate(). A node which hasn't -* been activated is not visible to userland and its removal won't -* trigger deactivation. -*/ -if (!(kernfs_root (kn)->flags &KERNFS_ROOT_CREATE_DEACTIVATED )) -kernfs_activate (kn); -return 0 ; - -out_unlock: -mutex_unlock (&kernfs_mutex); -return ret; -} - -/** -* kernfs_find_ns - find kernfs_node with the given name -* @parent: kernfs_node to search under -* @name: name to look for -* @ns: the namespace tag to use -* -* Look for kernfs_node with name @name under @parent. Returns pointer to -* the found kernfs_node on success, %NULL on failure. -*/ -static struct kernfs_node *kernfs_find_ns (struct kernfs_node *parent, -const unsigned char *name, -const void *ns) -{ -struct rb_node *node = parent->dir.children.rb_node; -bool has_ns =kernfs_ns_enabled (parent); -unsigned int hash; - -lockdep_assert_held (&kernfs_mutex); - -if (has_ns != (bool )ns) { -WARN (1 ,KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n" , - has_ns ?"required" :"invalid" , parent->name, name); -return NULL ; - } - - hash =kernfs_name_hash (name, ns); -while (node) { -struct kernfs_node *kn; -int result; - - kn =rb_to_kn (node); - result =kernfs_name_compare (hash, name, ns, kn); -if (result <0 ) - node = node->rb_left; -else if (result >0 ) - node = node->rb_right; -else -return kn; - } -return NULL ; -} - -/** -* kernfs_find_and_get_ns - find and get kernfs_node with the given name -* @parent: kernfs_node to search under -* @name: name to look for -* @ns: the namespace tag to use -* -* Look for kernfs_node with name @name under @parent and get a reference -* if found. This function may sleep and returns pointer to the found -* kernfs_node on success, %NULL on failure. -*/ -struct kernfs_node *kernfs_find_and_get_ns (struct kernfs_node *parent, -const char *name,const void *ns) -{ -struct kernfs_node *kn; - -mutex_lock (&kernfs_mutex); - kn =kernfs_find_ns (parent, name, ns); -kernfs_get (kn); -mutex_unlock (&kernfs_mutex); - -return kn; -} -EXPORT_SYMBOL_GPL (kernfs_find_and_get_ns); - -/** -* kernfs_create_root - create a new kernfs hierarchy -* @scops: optional syscall operations for the hierarchy -* @priv: opaque data associated with the new directory -* -* Returns the root of the new hierarchy on success, ERR_PTR() value on -* failure. -*/ -struct kernfs_root *kernfs_create_root (struct kernfs_syscall_ops *scops, -void *priv) -{ -struct kernfs_root *root; -struct kernfs_node *kn; - - root =kzalloc (sizeof (*root),GFP_KERNEL ); -if (!root) -return ERR_PTR (-ENOMEM ); - -ida_init (&root->ino_ida); - - kn =__kernfs_new_node (root,"" ,S_IFDIR |S_IRUGO |S_IXUGO , -KERNFS_DIR ); -if (!kn) { -ida_destroy (&root->ino_ida); -kfree (root); -return ERR_PTR (-ENOMEM ); - } - -kernfs_activate (kn); - kn->priv = priv; - kn->dir.root = root; - - root->syscall_ops = scops; - root->kn = kn; -init_waitqueue_head (&root->deactivate_waitq); - -return root; -} - -/** -* kernfs_destroy_root - destroy a kernfs hierarchy -* @root: root of the hierarchy to destroy -* -* Destroy the hierarchy anchored at @root by removing all existing -* directories and destroying @root. -*/ -void kernfs_destroy_root (struct kernfs_root *root) -{ -kernfs_remove (root->kn);/* will also free @root */ -} - -/** -* kernfs_create_dir_ns - create a directory -* @parent: parent in which to create a new directory -* @name: name of the new directory -* @mode: mode of the new directory -* @priv: opaque data associated with the new directory -* @ns: optional namespace tag of the directory -* -* Returns the created node on success, ERR_PTR() value on failure. -*/ -struct kernfs_node *kernfs_create_dir_ns (struct kernfs_node *parent, -const char *name,umode_t mode, -void *priv,const void *ns) -{ -struct kernfs_node *kn; -int rc; - -/* allocate */ - kn =kernfs_new_node (parent, name, mode |S_IFDIR ,KERNFS_DIR ); -if (!kn) -return ERR_PTR (-ENOMEM ); - - kn->dir.root = parent->dir.root; - kn->ns = ns; - kn->priv = priv; - -/* link in */ - rc =kernfs_add_one (kn); -if (!rc) -return kn; - -kernfs_put (kn); -return ERR_PTR (rc); -} - -static struct dentry *kernfs_iop_lookup (struct inode *dir, -struct dentry *dentry, -unsigned int flags) -{ -struct dentry *ret; -struct kernfs_node *parent = dentry->d_parent->d_fsdata; -struct kernfs_node *kn; -struct inode *inode; -const void *ns =NULL ; - -mutex_lock (&kernfs_mutex); - -if (kernfs_ns_enabled (parent)) - ns =kernfs_info (dir->i_sb)->ns; - - kn =kernfs_find_ns (parent, dentry->d_name.name, ns); - -/* no such entry */ -if (!kn || !kernfs_active (kn)) { - ret =NULL ; - goto out_unlock; - } -kernfs_get (kn); - dentry->d_fsdata = kn; - -/* attach dentry and inode */ - inode =kernfs_get_inode (dir->i_sb, kn); -if (!inode) { - ret =ERR_PTR (-ENOMEM ); - goto out_unlock; - } - -/* instantiate and hash dentry */ - ret =d_materialise_unique (dentry, inode); - out_unlock: -mutex_unlock (&kernfs_mutex); -return ret; -} - -static int kernfs_iop_mkdir (struct inode *dir,struct dentry *dentry, -umode_t mode) -{ -struct kernfs_node *parent = dir->i_private; -struct kernfs_syscall_ops *scops =kernfs_root (parent)->syscall_ops; -int ret; - -if (!scops || !scops->mkdir) -return -EPERM ; - -if (!kernfs_get_active (parent)) -return -ENODEV ; - - ret = scops->mkdir (parent, dentry->d_name.name, mode); - -kernfs_put_active (parent); -return ret; -} - -static int kernfs_iop_rmdir (struct inode *dir,struct dentry *dentry) -{ -struct kernfs_node *kn = dentry->d_fsdata; -struct kernfs_syscall_ops *scops =kernfs_root (kn)->syscall_ops; -int ret; - -if (!scops || !scops->rmdir) -return -EPERM ; - -if (!kernfs_get_active (kn)) -return -ENODEV ; - - ret = scops->rmdir (kn); - -kernfs_put_active (kn); -return ret; -} - -static int kernfs_iop_rename (struct inode *old_dir,struct dentry *old_dentry, -struct inode *new_dir,struct dentry *new_dentry) -{ -struct kernfs_node *kn = old_dentry->d_fsdata; -struct kernfs_node *new_parent = new_dir->i_private; -struct kernfs_syscall_ops *scops =kernfs_root (kn)->syscall_ops; -int ret; - -if (!scops || !scops->rename) -return -EPERM ; - -if (!kernfs_get_active (kn)) -return -ENODEV ; - -if (!kernfs_get_active (new_parent)) { -kernfs_put_active (kn); -return -ENODEV ; - } - - ret = scops->rename (kn, new_parent, new_dentry->d_name.name); - -kernfs_put_active (new_parent); -kernfs_put_active (kn); -return ret; -} - -const struct inode_operations kernfs_dir_iops = { - .lookup = kernfs_iop_lookup, - .permission = kernfs_iop_permission, - .setattr = kernfs_iop_setattr, - .getattr = kernfs_iop_getattr, - .setxattr = kernfs_iop_setxattr, - .removexattr = kernfs_iop_removexattr, - .getxattr = kernfs_iop_getxattr, - .listxattr = kernfs_iop_listxattr, - - .mkdir = kernfs_iop_mkdir, - .rmdir = kernfs_iop_rmdir, - .rename = kernfs_iop_rename, -}; - -static struct kernfs_node *kernfs_leftmost_descendant (struct kernfs_node *pos) -{ -struct kernfs_node *last; - -while (true) { -struct rb_node *rbn; - - last = pos; - -if (kernfs_type (pos) !=KERNFS_DIR ) -break ; - - rbn =rb_first (&pos->dir.children); -if (!rbn) -break ; - - pos =rb_to_kn (rbn); - } - -return last; -} - -/** -* kernfs_next_descendant_post - find the next descendant for post-order walk -* @pos: the current position (%NULL to initiate traversal) -* @root: kernfs_node whose descendants to walk -* -* Find the next descendant to visit for post-order traversal of @root's -* descendants. @root is included in the iteration and the last node to be -* visited. -*/ -static struct kernfs_node *kernfs_next_descendant_post (struct kernfs_node *pos, -struct kernfs_node *root) -{ -struct rb_node *rbn; - -lockdep_assert_held (&kernfs_mutex); - -/* if first iteration, visit leftmost descendant which may be root */ -if (!pos) -return kernfs_leftmost_descendant (root); - -/* if we visited @root, we're done */ -if (pos == root) -return NULL ; - -/* if there's an unvisited sibling, visit its leftmost descendant */ - rbn =rb_next (&pos->rb); -if (rbn) -return kernfs_leftmost_descendant (rb_to_kn (rbn)); - -/* no sibling left, visit parent */ -return pos->parent; -} - -/** -* kernfs_activate - activate a node which started deactivated -* @kn: kernfs_node whose subtree is to be activated -* -* If the root has KERNFS_ROOT_CREATE_DEACTIVATED set, a newly created node -* needs to be explicitly activated. A node which hasn't been activated -* isn't visible to userland and deactivation is skipped during its -* removal. This is useful to construct atomic init sequences where -* creation of multiple nodes should either succeed or fail atomically. -* -* The caller is responsible for ensuring that this function is not called -* after kernfs_remove*() is invoked on @kn. -*/ -void kernfs_activate (struct kernfs_node *kn) -{ -struct kernfs_node *pos; - -mutex_lock (&kernfs_mutex); - - pos =NULL ; -while ((pos =kernfs_next_descendant_post (pos, kn))) { -if (!pos || (pos->flags &KERNFS_ACTIVATED )) -continue ; - -WARN_ON_ONCE (pos->parent &&RB_EMPTY_NODE (&pos->rb)); -WARN_ON_ONCE (atomic_read (&pos->active) !=KN_DEACTIVATED_BIAS ); - -atomic_sub (KN_DEACTIVATED_BIAS , &pos->active); - pos->flags |=KERNFS_ACTIVATED ; - } - -mutex_unlock (&kernfs_mutex); -} - -static void __kernfs_remove (struct kernfs_node *kn) -{ -struct kernfs_node *pos; - -lockdep_assert_held (&kernfs_mutex); - -/* -* Short-circuit if @kn has already finished removal. This is for -* kernfs_remove_self() which plays with active ref after removal. -*/ -if (!kn ||RB_EMPTY_NODE (&kn->rb)) -return ; - -pr_debug ("kernfs %s: removing\n" , kn->name); - -/* prevent any new usage under @kn by deactivating all nodes */ - pos =NULL ; -while ((pos =kernfs_next_descendant_post (pos, kn))) -if (kernfs_active (pos)) -atomic_add (KN_DEACTIVATED_BIAS , &pos->active); - -/* deactivate and unlink the subtree node-by-node */ -do { - pos =kernfs_leftmost_descendant (kn); - -/* -* kernfs_drain() drops kernfs_mutex temporarily and @pos's -* base ref could have been put by someone else by the time -* the function returns. Make sure it doesn't go away -* underneath us. -*/ -kernfs_get (pos); - -/* -* Drain iff @kn was activated. This avoids draining and -* its lockdep annotations for nodes which have never been -* activated and allows embedding kernfs_remove() in create -* error paths without worrying about draining. -*/ -if (kn->flags &KERNFS_ACTIVATED ) -kernfs_drain (pos); -else -WARN_ON_ONCE (atomic_read (&kn->active) !=KN_DEACTIVATED_BIAS ); - -/* -* kernfs_unlink_sibling() succeeds once per node. Use it -* to decide who's responsible for cleanups. -*/ -if (!pos->parent ||kernfs_unlink_sibling (pos)) { -struct kernfs_iattrs *ps_iattr = - pos->parent ? pos->parent->iattr :NULL ; - -/* update timestamps on the parent */ -if (ps_iattr) { - ps_iattr->ia_iattr.ia_ctime =CURRENT_TIME ; - ps_iattr->ia_iattr.ia_mtime =CURRENT_TIME ; - } - -kernfs_put (pos); - } - -kernfs_put (pos); - }while (pos != kn); -} - -/** -* 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); -} - -/** -* kernfs_break_active_protection - break out of active protection -* @kn: the self kernfs_node -* -* The caller must be running off of a kernfs operation which is invoked -* with an active reference - e.g. one of kernfs_ops. Each invocation of -* this function must also be matched with an invocation of -* kernfs_unbreak_active_protection(). -* -* This function releases the active reference of @kn the caller is -* holding. Once this function is called, @kn may be removed at any point -* and the caller is solely responsible for ensuring that the objects it -* dereferences are accessible. -*/ -void kernfs_break_active_protection (struct kernfs_node *kn) -{ -/* -* Take out ourself out of the active ref dependency chain. If -* we're called without an active ref, lockdep will complain. -*/ -kernfs_put_active (kn); -} - -/** -* kernfs_unbreak_active_protection - undo kernfs_break_active_protection() -* @kn: the self kernfs_node -* -* If kernfs_break_active_protection() was called, this function must be -* invoked before finishing the kernfs operation. Note that while this -* function restores the active reference, it doesn't and can't actually -* restore the active protection - @kn may already or be in the process of -* being removed. Once kernfs_break_active_protection() is invoked, that -* protection is irreversibly gone for the kernfs operation instance. -* -* While this function may be called at any point after -* kernfs_break_active_protection() is invoked, its most useful location -* would be right before the enclosing kernfs operation returns. -*/ -void kernfs_unbreak_active_protection (struct kernfs_node *kn) -{ -/* -* @kn->active could be in any state; however, the increment we do -* here will be undone as soon as the enclosing kernfs operation -* finishes and this temporary bump can't break anything. If @kn -* is alive, nothing changes. If @kn is being deactivated, the -* soon-to-follow put will either finish deactivation or restore -* deactivated state. If @kn is already removed, the temporary -* bump is guaranteed to be gone before @kn is released. -*/ -atomic_inc (&kn->active); -if (kernfs_lockdep (kn)) -rwsem_acquire (&kn->dep_map,0 ,1 , _RET_IP_); -} - -/** -* 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_rename_ns - move and rename a kernfs_node -* @kn: target node -* @new_parent: new parent to put @sd under -* @new_name: new name -* @new_ns: new namespace tag -*/ -int kernfs_rename_ns (struct kernfs_node *kn,struct kernfs_node *new_parent, -const char *new_name,const void *new_ns) -{ -int error; - -mutex_lock (&kernfs_mutex); - - error = -ENOENT ; -if (!kernfs_active (kn) || !kernfs_active (new_parent)) - goto out; - - error =0 ; -if ((kn->parent == new_parent) && (kn->ns == new_ns) && - (strcmp (kn->name, new_name) ==0 )) - goto out;/* nothing to rename */ - - error = -EEXIST ; -if (kernfs_find_ns (new_parent, new_name, new_ns)) - goto out; - -/* rename kernfs_node */ -if (strcmp (kn->name, new_name) !=0 ) { - error = -ENOMEM ; - new_name =kstrdup (new_name,GFP_KERNEL ); -if (!new_name) - goto out; - -if (kn->flags &KERNFS_STATIC_NAME ) - kn->flags &= ~KERNFS_STATIC_NAME ; -else -kfree (kn->name); - - kn->name = new_name; - } - -/* -* Move to the appropriate place in the appropriate directories rbtree. -*/ -kernfs_unlink_sibling (kn); -kernfs_get (new_parent); -kernfs_put (kn->parent); - kn->ns = new_ns; - kn->hash =kernfs_name_hash (kn->name, kn->ns); - kn->parent = new_parent; -kernfs_link_sibling (kn); - - error =0 ; - out: -mutex_unlock (&kernfs_mutex); -return error; -} - -/* Relationship between s_mode and the DT_xxx types */ -static inline unsigned char dt_type (struct kernfs_node *kn) -{ -return (kn->mode >>12 ) &15 ; -} - -static int kernfs_dir_fop_release (struct inode *inode,struct file *filp) -{ -kernfs_put (filp->private_data); -return 0 ; -} - -static struct kernfs_node *kernfs_dir_pos (const void *ns, -struct kernfs_node *parent,loff_t hash,struct kernfs_node *pos) -{ -if (pos) { -int valid =kernfs_active (pos) && - pos->parent == parent && hash == pos->hash; -kernfs_put (pos); -if (!valid) - pos =NULL ; - } -if (!pos && (hash >1 ) && (hash <INT_MAX )) { -struct rb_node *node = parent->dir.children.rb_node; -while (node) { - pos =rb_to_kn (node); - -if (hash < pos->hash) - node = node->rb_left; -else if (hash > pos->hash) - node = node->rb_right; -else -break ; - } - } -/* Skip over entries which are dying/dead or in the wrong namespace */ -while (pos && (!kernfs_active (pos) || pos->ns != ns)) { -struct rb_node *node =rb_next (&pos->rb); -if (!node) - pos =NULL ; -else - pos =rb_to_kn (node); - } -return pos; -} - -static struct kernfs_node *kernfs_dir_next_pos (const void *ns, -struct kernfs_node *parent,ino_t ino,struct kernfs_node *pos) -{ - pos =kernfs_dir_pos (ns, parent, ino, pos); -if (pos) -do { -struct rb_node *node =rb_next (&pos->rb); -if (!node) - pos =NULL ; -else - pos =rb_to_kn (node); - }while (pos && (!kernfs_active (pos) || pos->ns != ns)); -return pos; -} - -static int kernfs_fop_readdir (struct file *file,struct dir_context *ctx) -{ -struct dentry *dentry = file->f_path.dentry; -struct kernfs_node *parent = dentry->d_fsdata; -struct kernfs_node *pos = file->private_data; -const void *ns =NULL ; - -if (!dir_emit_dots (file, ctx)) -return 0 ; -mutex_lock (&kernfs_mutex); - -if (kernfs_ns_enabled (parent)) - ns =kernfs_info (dentry->d_sb)->ns; - -for (pos =kernfs_dir_pos (ns, parent, ctx->pos, pos); - pos; - pos =kernfs_dir_next_pos (ns, parent, ctx->pos, pos)) { -const char *name = pos->name; -unsigned int type =dt_type (pos); -int len =strlen (name); -ino_t ino = pos->ino; - - ctx->pos = pos->hash; - file->private_data = pos; -kernfs_get (pos); - -mutex_unlock (&kernfs_mutex); -if (!dir_emit (ctx, name, len, ino, type)) -return 0 ; -mutex_lock (&kernfs_mutex); - } -mutex_unlock (&kernfs_mutex); - file->private_data =NULL ; - ctx->pos =INT_MAX ; -return 0 ; -} - -static loff_t kernfs_dir_fop_llseek (struct file *file,loff_t offset, -int whence) -{ -struct inode *inode =file_inode (file); -loff_t ret; - -mutex_lock (&inode->i_mutex); - ret =generic_file_llseek (file, offset, whence); -mutex_unlock (&inode->i_mutex); - -return ret; -} - -const struct file_operations kernfs_dir_fops = { - .read = generic_read_dir, - .iterate = kernfs_fop_readdir, - .release = kernfs_dir_fop_release, - .llseek = kernfs_dir_fop_llseek, -};