LCOV - code coverage report
Current view: top level - fs/kernfs - dir.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 246 353 69.7 %
Date: 2014-04-16 Functions: 31 37 83.8 %
Branches: 128 218 58.7 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * fs/kernfs/dir.c - kernfs directory implementation
       3                 :            :  *
       4                 :            :  * Copyright (c) 2001-3 Patrick Mochel
       5                 :            :  * Copyright (c) 2007 SUSE Linux Products GmbH
       6                 :            :  * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org>
       7                 :            :  *
       8                 :            :  * This file is released under the GPLv2.
       9                 :            :  */
      10                 :            : 
      11                 :            : #include <linux/fs.h>
      12                 :            : #include <linux/namei.h>
      13                 :            : #include <linux/idr.h>
      14                 :            : #include <linux/slab.h>
      15                 :            : #include <linux/security.h>
      16                 :            : #include <linux/hash.h>
      17                 :            : 
      18                 :            : #include "kernfs-internal.h"
      19                 :            : 
      20                 :            : DEFINE_MUTEX(kernfs_mutex);
      21                 :            : 
      22                 :            : #define rb_to_kn(X) rb_entry((X), struct kernfs_node, rb)
      23                 :            : 
      24                 :            : /**
      25                 :            :  *      kernfs_name_hash
      26                 :            :  *      @name: Null terminated string to hash
      27                 :            :  *      @ns:   Namespace tag to hash
      28                 :            :  *
      29                 :            :  *      Returns 31 bit hash of ns + name (so it fits in an off_t )
      30                 :            :  */
      31                 :          0 : static unsigned int kernfs_name_hash(const char *name, const void *ns)
      32                 :            : {
      33                 :            :         unsigned long hash = init_name_hash();
      34                 :      12093 :         unsigned int len = strlen(name);
      35         [ +  + ]:     106901 :         while (len--)
      36                 :      94808 :                 hash = partial_name_hash(*name++, hash);
      37                 :      12093 :         hash = (end_name_hash(hash) ^ hash_ptr((void *)ns, 31));
      38                 :      12093 :         hash &= 0x7fffffffU;
      39                 :            :         /* Reserve hash numbers 0, 1 and INT_MAX for magic directory entries */
      40         [ -  + ]:      12093 :         if (hash < 1)
      41                 :          0 :                 hash += 2;
      42         [ -  - ]:      12093 :         if (hash >= INT_MAX)
      43                 :            :                 hash = INT_MAX - 1;
      44                 :          0 :         return hash;
      45                 :            : }
      46                 :            : 
      47                 :          0 : static int kernfs_name_compare(unsigned int hash, const char *name,
      48                 :            :                                const void *ns, const struct kernfs_node *kn)
      49                 :            : {
      50         [ +  + ]:      36393 :         if (hash != kn->hash)
      51                 :      34844 :                 return hash - kn->hash;
      52         [ -  + ]:       1549 :         if (ns != kn->ns)
      53                 :          0 :                 return ns - kn->ns;
      54                 :       1549 :         return strcmp(name, kn->name);
      55                 :            : }
      56                 :            : 
      57                 :            : static int kernfs_sd_compare(const struct kernfs_node *left,
      58                 :            :                              const struct kernfs_node *right)
      59                 :            : {
      60                 :       6326 :         return kernfs_name_compare(left->hash, left->name, left->ns, right);
      61                 :            : }
      62                 :            : 
      63                 :            : /**
      64                 :            :  *      kernfs_link_sibling - link kernfs_node into sibling rbtree
      65                 :            :  *      @kn: kernfs_node of interest
      66                 :            :  *
      67                 :            :  *      Link @kn into its sibling rbtree which starts from
      68                 :            :  *      @kn->parent->dir.children.
      69                 :            :  *
      70                 :            :  *      Locking:
      71                 :            :  *      mutex_lock(kernfs_mutex)
      72                 :            :  *
      73                 :            :  *      RETURNS:
      74                 :            :  *      0 on susccess -EEXIST on failure.
      75                 :            :  */
      76                 :          0 : static int kernfs_link_sibling(struct kernfs_node *kn)
      77                 :            : {
      78                 :       1816 :         struct rb_node **node = &kn->parent->dir.children.rb_node;
      79                 :            :         struct rb_node *parent = NULL;
      80                 :            : 
      81         [ +  + ]:       1816 :         if (kernfs_type(kn) == KERNFS_DIR)
      82                 :       1816 :                 kn->parent->dir.subdirs++;
      83                 :            : 
      84         [ +  + ]:       8142 :         while (*node) {
      85                 :            :                 struct kernfs_node *pos;
      86                 :            :                 int result;
      87                 :            : 
      88                 :       6326 :                 pos = rb_to_kn(*node);
      89                 :            :                 parent = *node;
      90                 :            :                 result = kernfs_sd_compare(kn, pos);
      91         [ +  + ]:       8142 :                 if (result < 0)
      92                 :       2582 :                         node = &pos->rb.rb_left;
      93         [ +  - ]:       3744 :                 else if (result > 0)
      94                 :       6326 :                         node = &pos->rb.rb_right;
      95                 :            :                 else
      96                 :            :                         return -EEXIST;
      97                 :            :         }
      98                 :            :         /* add new node and rebalance the tree */
      99                 :       1816 :         rb_link_node(&kn->rb, parent, node);
     100                 :       1816 :         rb_insert_color(&kn->rb, &kn->parent->dir.children);
     101                 :       1816 :         return 0;
     102                 :            : }
     103                 :            : 
     104                 :            : /**
     105                 :            :  *      kernfs_unlink_sibling - unlink kernfs_node from sibling rbtree
     106                 :            :  *      @kn: kernfs_node of interest
     107                 :            :  *
     108                 :            :  *      Unlink @kn from its sibling rbtree which starts from
     109                 :            :  *      kn->parent->dir.children.
     110                 :            :  *
     111                 :            :  *      Locking:
     112                 :            :  *      mutex_lock(kernfs_mutex)
     113                 :            :  */
     114                 :          0 : static void kernfs_unlink_sibling(struct kernfs_node *kn)
     115                 :            : {
     116         [ +  + ]:       1016 :         if (kernfs_type(kn) == KERNFS_DIR)
     117                 :        156 :                 kn->parent->dir.subdirs--;
     118                 :            : 
     119                 :       1016 :         rb_erase(&kn->rb, &kn->parent->dir.children);
     120                 :       1016 : }
     121                 :            : 
     122                 :            : /**
     123                 :            :  *      kernfs_get_active - get an active reference to kernfs_node
     124                 :            :  *      @kn: kernfs_node to get an active reference to
     125                 :            :  *
     126                 :            :  *      Get an active reference of @kn.  This function is noop if @kn
     127                 :            :  *      is NULL.
     128                 :            :  *
     129                 :            :  *      RETURNS:
     130                 :            :  *      Pointer to @kn on success, NULL on failure.
     131                 :            :  */
     132                 :          0 : struct kernfs_node *kernfs_get_active(struct kernfs_node *kn)
     133                 :            : {
     134            [ + ]:       4199 :         if (unlikely(!kn))
     135                 :            :                 return NULL;
     136                 :            : 
     137            [ + ]:       8397 :         if (!atomic_inc_unless_negative(&kn->active))
     138                 :            :                 return NULL;
     139                 :            : 
     140                 :            :         if (kn->flags & KERNFS_LOCKDEP)
     141                 :            :                 rwsem_acquire_read(&kn->dep_map, 0, 1, _RET_IP_);
     142                 :       4200 :         return kn;
     143                 :            : }
     144                 :            : 
     145                 :            : /**
     146                 :            :  *      kernfs_put_active - put an active reference to kernfs_node
     147                 :            :  *      @kn: kernfs_node to put an active reference to
     148                 :            :  *
     149                 :            :  *      Put an active reference to @kn.  This function is noop if @kn
     150                 :            :  *      is NULL.
     151                 :            :  */
     152                 :          0 : void kernfs_put_active(struct kernfs_node *kn)
     153                 :            : {
     154                 :            :         int v;
     155                 :            : 
     156         [ +  - ]:       4200 :         if (unlikely(!kn))
     157                 :            :                 return;
     158                 :            : 
     159                 :            :         if (kn->flags & KERNFS_LOCKDEP)
     160                 :            :                 rwsem_release(&kn->dep_map, 1, _RET_IP_);
     161                 :       4200 :         v = atomic_dec_return(&kn->active);
     162         [ -  + ]:       4197 :         if (likely(v != KN_DEACTIVATED_BIAS))
     163                 :            :                 return;
     164                 :            : 
     165                 :            :         /*
     166                 :            :          * atomic_dec_return() is a mb(), we'll always see the updated
     167                 :            :          * kn->u.completion.
     168                 :            :          */
     169                 :          0 :         complete(kn->u.completion);
     170                 :            : }
     171                 :            : 
     172                 :            : /**
     173                 :            :  *      kernfs_deactivate - deactivate kernfs_node
     174                 :            :  *      @kn: kernfs_node to deactivate
     175                 :            :  *
     176                 :            :  *      Deny new active references and drain existing ones.
     177                 :            :  */
     178                 :          0 : static void kernfs_deactivate(struct kernfs_node *kn)
     179                 :            : {
     180                 :        987 :         DECLARE_COMPLETION_ONSTACK(wait);
     181                 :            :         int v;
     182                 :            : 
     183         [ -  + ]:        987 :         BUG_ON(!(kn->flags & KERNFS_REMOVED));
     184                 :            : 
     185         [ +  + ]:        987 :         if (!(kernfs_type(kn) & KERNFS_ACTIVE_REF))
     186                 :        256 :                 return;
     187                 :            : 
     188                 :        731 :         kn->u.completion = (void *)&wait;
     189                 :            : 
     190                 :            :         if (kn->flags & KERNFS_LOCKDEP)
     191                 :            :                 rwsem_acquire(&kn->dep_map, 0, 0, _RET_IP_);
     192                 :            :         /* atomic_add_return() is a mb(), put_active() will always see
     193                 :            :          * the updated kn->u.completion.
     194                 :            :          */
     195                 :        731 :         v = atomic_add_return(KN_DEACTIVATED_BIAS, &kn->active);
     196                 :            : 
     197         [ -  + ]:        731 :         if (v != KN_DEACTIVATED_BIAS) {
     198                 :            :                 if (kn->flags & KERNFS_LOCKDEP)
     199                 :            :                         lock_contended(&kn->dep_map, _RET_IP_);
     200                 :        731 :                 wait_for_completion(&wait);
     201                 :            :         }
     202                 :            : 
     203                 :            :         if (kn->flags & KERNFS_LOCKDEP) {
     204                 :            :                 lock_acquired(&kn->dep_map, _RET_IP_);
     205                 :            :                 rwsem_release(&kn->dep_map, 1, _RET_IP_);
     206                 :            :         }
     207                 :            : }
     208                 :            : 
     209                 :            : /**
     210                 :            :  * kernfs_get - get a reference count on a kernfs_node
     211                 :            :  * @kn: the target kernfs_node
     212                 :            :  */
     213                 :          0 : void kernfs_get(struct kernfs_node *kn)
     214                 :            : {
     215         [ +  - ]:       4745 :         if (kn) {
     216         [ -  + ]:       4745 :                 WARN_ON(!atomic_read(&kn->count));
     217                 :       4745 :                 atomic_inc(&kn->count);
     218                 :            :         }
     219                 :       4745 : }
     220                 :            : EXPORT_SYMBOL_GPL(kernfs_get);
     221                 :            : 
     222                 :            : /**
     223                 :            :  * kernfs_put - put a reference count on a kernfs_node
     224                 :            :  * @kn: the target kernfs_node
     225                 :            :  *
     226                 :            :  * Put a reference count of @kn and destroy it if it reached zero.
     227                 :            :  */
     228                 :          0 : void kernfs_put(struct kernfs_node *kn)
     229                 :            : {
     230                 :            :         struct kernfs_node *parent;
     231                 :            :         struct kernfs_root *root;
     232                 :            : 
     233   [ +  +  +  + ]:      29820 :         if (!kn || !atomic_dec_and_test(&kn->count))
     234                 :      19210 :                 return;
     235                 :            :         root = kernfs_root(kn);
     236                 :            :  repeat:
     237                 :            :         /* Moving/renaming is always done while holding reference.
     238                 :            :          * kn->parent won't change beneath us.
     239                 :            :          */
     240                 :        987 :         parent = kn->parent;
     241                 :            : 
     242 [ -  + ][ #  # ]:        987 :         WARN(!(kn->flags & KERNFS_REMOVED), "kernfs: free using entry: %s/%s\n",
     243                 :            :              parent ? parent->name : "", kn->name);
     244                 :            : 
     245         [ +  + ]:      20197 :         if (kernfs_type(kn) == KERNFS_LINK)
     246                 :        129 :                 kernfs_put(kn->symlink.target_kn);
     247         [ +  + ]:        987 :         if (!(kn->flags & KERNFS_STATIC_NAME))
     248                 :        256 :                 kfree(kn->name);
     249         [ +  + ]:        987 :         if (kn->iattr) {
     250         [ -  + ]:          2 :                 if (kn->iattr->ia_secdata)
     251                 :          0 :                         security_release_secctx(kn->iattr->ia_secdata,
     252                 :            :                                                 kn->iattr->ia_secdata_len);
     253                 :          2 :                 simple_xattrs_free(&kn->iattr->xattrs);
     254                 :            :         }
     255                 :        987 :         kfree(kn->iattr);
     256                 :        987 :         ida_simple_remove(&root->ino_ida, kn->ino);
     257                 :        987 :         kmem_cache_free(kernfs_node_cache, kn);
     258                 :            : 
     259                 :            :         kn = parent;
     260         [ +  - ]:        987 :         if (kn) {
     261         [ +  + ]:        987 :                 if (atomic_dec_and_test(&kn->count))
     262                 :            :                         goto repeat;
     263                 :            :         } else {
     264                 :            :                 /* just released the root kn, free @root too */
     265                 :          0 :                 ida_destroy(&root->ino_ida);
     266                 :          0 :                 kfree(root);
     267                 :            :         }
     268                 :            : }
     269                 :            : EXPORT_SYMBOL_GPL(kernfs_put);
     270                 :            : 
     271                 :          0 : static int kernfs_dop_revalidate(struct dentry *dentry, unsigned int flags)
     272                 :            : {
     273                 :            :         struct kernfs_node *kn;
     274                 :            : 
     275            [ + ]:      53452 :         if (flags & LOOKUP_RCU)
     276                 :            :                 return -ECHILD;
     277                 :            : 
     278                 :            :         /* Always perform fresh lookup for negatives */
     279         [ +  - ]:      53453 :         if (!dentry->d_inode)
     280                 :            :                 goto out_bad_unlocked;
     281                 :            : 
     282                 :      53453 :         kn = dentry->d_fsdata;
     283                 :      53453 :         mutex_lock(&kernfs_mutex);
     284                 :            : 
     285                 :            :         /* The kernfs node has been deleted */
     286         [ +  + ]:      53453 :         if (kn->flags & KERNFS_REMOVED)
     287                 :            :                 goto out_bad;
     288                 :            : 
     289                 :            :         /* The kernfs node has been moved? */
     290         [ +  - ]:      53436 :         if (dentry->d_parent->d_fsdata != kn->parent)
     291                 :            :                 goto out_bad;
     292                 :            : 
     293                 :            :         /* The kernfs node has been renamed */
     294         [ +  - ]:      53436 :         if (strcmp(dentry->d_name.name, kn->name) != 0)
     295                 :            :                 goto out_bad;
     296                 :            : 
     297                 :            :         /* The kernfs node has been moved to a different namespace */
     298 [ +  - ][ -  + ]:      53436 :         if (kn->parent && kernfs_ns_enabled(kn->parent) &&
                 [ #  # ]
     299                 :          0 :             kernfs_info(dentry->d_sb)->ns != kn->ns)
     300                 :            :                 goto out_bad;
     301                 :            : 
     302                 :      53436 :         mutex_unlock(&kernfs_mutex);
     303                 :            : out_valid:
     304                 :            :         return 1;
     305                 :            : out_bad:
     306                 :         17 :         mutex_unlock(&kernfs_mutex);
     307                 :            : out_bad_unlocked:
     308                 :            :         /*
     309                 :            :          * @dentry doesn't match the underlying kernfs node, drop the
     310                 :            :          * dentry and force lookup.  If we have submounts we must allow the
     311                 :            :          * vfs caches to lie about the state of the filesystem to prevent
     312                 :            :          * leaks and other nasty things, so use check_submounts_and_drop()
     313                 :            :          * instead of d_drop().
     314                 :            :          */
     315         [ -  + ]:         17 :         if (check_submounts_and_drop(dentry) != 0)
     316                 :            :                 goto out_valid;
     317                 :            : 
     318                 :            :         return 0;
     319                 :            : }
     320                 :            : 
     321                 :          0 : static void kernfs_dop_release(struct dentry *dentry)
     322                 :            : {
     323                 :      12654 :         kernfs_put(dentry->d_fsdata);
     324                 :      12654 : }
     325                 :            : 
     326                 :            : const struct dentry_operations kernfs_dops = {
     327                 :            :         .d_revalidate   = kernfs_dop_revalidate,
     328                 :            :         .d_release      = kernfs_dop_release,
     329                 :            : };
     330                 :            : 
     331                 :          0 : static struct kernfs_node *__kernfs_new_node(struct kernfs_root *root,
     332                 :            :                                              const char *name, umode_t mode,
     333                 :            :                                              unsigned flags)
     334                 :            : {
     335                 :            :         char *dup_name = NULL;
     336                 :            :         struct kernfs_node *kn;
     337                 :            :         int ret;
     338                 :            : 
     339         [ +  + ]:       1787 :         if (!(flags & KERNFS_STATIC_NAME)) {
     340                 :        821 :                 name = dup_name = kstrdup(name, GFP_KERNEL);
     341         [ +  - ]:        821 :                 if (!name)
     342                 :            :                         return NULL;
     343                 :            :         }
     344                 :            : 
     345                 :       1787 :         kn = kmem_cache_zalloc(kernfs_node_cache, GFP_KERNEL);
     346         [ +  - ]:       1787 :         if (!kn)
     347                 :            :                 goto err_out1;
     348                 :            : 
     349                 :       1787 :         ret = ida_simple_get(&root->ino_ida, 1, 0, GFP_KERNEL);
     350         [ +  - ]:       3574 :         if (ret < 0)
     351                 :            :                 goto err_out2;
     352                 :       1787 :         kn->ino = ret;
     353                 :            : 
     354                 :       1787 :         atomic_set(&kn->count, 1);
     355                 :       1787 :         atomic_set(&kn->active, 0);
     356                 :            : 
     357                 :       1787 :         kn->name = name;
     358                 :       1787 :         kn->mode = mode;
     359                 :       1787 :         kn->flags = flags | KERNFS_REMOVED;
     360                 :            : 
     361                 :       1787 :         return kn;
     362                 :            : 
     363                 :            :  err_out2:
     364                 :          0 :         kmem_cache_free(kernfs_node_cache, kn);
     365                 :            :  err_out1:
     366                 :          0 :         kfree(dup_name);
     367                 :          0 :         return NULL;
     368                 :            : }
     369                 :            : 
     370                 :          0 : struct kernfs_node *kernfs_new_node(struct kernfs_node *parent,
     371                 :            :                                     const char *name, umode_t mode,
     372                 :            :                                     unsigned flags)
     373                 :            : {
     374                 :            :         struct kernfs_node *kn;
     375                 :            : 
     376                 :       1787 :         kn = __kernfs_new_node(kernfs_root(parent), name, mode, flags);
     377         [ +  - ]:       1787 :         if (kn) {
     378                 :       1787 :                 kernfs_get(parent);
     379                 :       1787 :                 kn->parent = parent;
     380                 :            :         }
     381                 :       1787 :         return kn;
     382                 :            : }
     383                 :            : 
     384                 :            : /**
     385                 :            :  *      kernfs_addrm_start - prepare for kernfs_node add/remove
     386                 :            :  *      @acxt: pointer to kernfs_addrm_cxt to be used
     387                 :            :  *
     388                 :            :  *      This function is called when the caller is about to add or remove
     389                 :            :  *      kernfs_node.  This function acquires kernfs_mutex.  @acxt is used
     390                 :            :  *      to keep and pass context to other addrm functions.
     391                 :            :  *
     392                 :            :  *      LOCKING:
     393                 :            :  *      Kernel thread context (may sleep).  kernfs_mutex is locked on
     394                 :            :  *      return.
     395                 :            :  */
     396                 :          0 : void kernfs_addrm_start(struct kernfs_addrm_cxt *acxt)
     397                 :            :         __acquires(kernfs_mutex)
     398                 :            : {
     399                 :       2890 :         memset(acxt, 0, sizeof(*acxt));
     400                 :            : 
     401                 :       2890 :         mutex_lock(&kernfs_mutex);
     402                 :       1434 : }
     403                 :            : 
     404                 :            : /**
     405                 :            :  *      kernfs_add_one - add kernfs_node to parent without warning
     406                 :            :  *      @acxt: addrm context to use
     407                 :            :  *      @kn: kernfs_node to be added
     408                 :            :  *
     409                 :            :  *      The caller must already have initialized @kn->parent.  This
     410                 :            :  *      function increments nlink of the parent's inode if @kn is a
     411                 :            :  *      directory and link into the children list of the parent.
     412                 :            :  *
     413                 :            :  *      This function should be called between calls to
     414                 :            :  *      kernfs_addrm_start() and kernfs_addrm_finish() and should be passed
     415                 :            :  *      the same @acxt as passed to kernfs_addrm_start().
     416                 :            :  *
     417                 :            :  *      LOCKING:
     418                 :            :  *      Determined by kernfs_addrm_start().
     419                 :            :  *
     420                 :            :  *      RETURNS:
     421                 :            :  *      0 on success, -EEXIST if entry with the given name already
     422                 :            :  *      exists.
     423                 :            :  */
     424                 :          0 : int kernfs_add_one(struct kernfs_addrm_cxt *acxt, struct kernfs_node *kn)
     425                 :            : {
     426                 :       1787 :         struct kernfs_node *parent = kn->parent;
     427                 :            :         bool has_ns = kernfs_ns_enabled(parent);
     428                 :            :         struct kernfs_iattrs *ps_iattr;
     429                 :            :         int ret;
     430                 :            : 
     431         [ -  + ]:       1787 :         if (has_ns != (bool)kn->ns) {
     432         [ #  # ]:          0 :                 WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",
     433                 :            :                      has_ns ? "required" : "invalid", parent->name, kn->name);
     434                 :          0 :                 return -EINVAL;
     435                 :            :         }
     436                 :            : 
     437         [ +  - ]:       1787 :         if (kernfs_type(parent) != KERNFS_DIR)
     438                 :            :                 return -EINVAL;
     439                 :            : 
     440         [ +  - ]:       1787 :         if (parent->flags & KERNFS_REMOVED)
     441                 :            :                 return -ENOENT;
     442                 :            : 
     443                 :       1787 :         kn->hash = kernfs_name_hash(kn->name, kn->ns);
     444                 :            : 
     445                 :       1787 :         ret = kernfs_link_sibling(kn);
     446         [ +  - ]:       1787 :         if (ret)
     447                 :            :                 return ret;
     448                 :            : 
     449                 :            :         /* Update timestamps on the parent */
     450                 :       1787 :         ps_iattr = parent->iattr;
     451         [ -  + ]:       1787 :         if (ps_iattr) {
     452                 :          0 :                 struct iattr *ps_iattrs = &ps_iattr->ia_iattr;
     453                 :          0 :                 ps_iattrs->ia_ctime = ps_iattrs->ia_mtime = CURRENT_TIME;
     454                 :            :         }
     455                 :            : 
     456                 :            :         /* Mark the entry added into directory tree */
     457                 :       1787 :         kn->flags &= ~KERNFS_REMOVED;
     458                 :            : 
     459                 :       1787 :         return 0;
     460                 :            : }
     461                 :            : 
     462                 :            : /**
     463                 :            :  *      kernfs_remove_one - remove kernfs_node from parent
     464                 :            :  *      @acxt: addrm context to use
     465                 :            :  *      @kn: kernfs_node to be removed
     466                 :            :  *
     467                 :            :  *      Mark @kn removed and drop nlink of parent inode if @kn is a
     468                 :            :  *      directory.  @kn is unlinked from the children list.
     469                 :            :  *
     470                 :            :  *      This function should be called between calls to
     471                 :            :  *      kernfs_addrm_start() and kernfs_addrm_finish() and should be
     472                 :            :  *      passed the same @acxt as passed to kernfs_addrm_start().
     473                 :            :  *
     474                 :            :  *      LOCKING:
     475                 :            :  *      Determined by kernfs_addrm_start().
     476                 :            :  */
     477                 :          0 : static void kernfs_remove_one(struct kernfs_addrm_cxt *acxt,
     478                 :            :                               struct kernfs_node *kn)
     479                 :            : {
     480                 :            :         struct kernfs_iattrs *ps_iattr;
     481                 :            : 
     482                 :            :         /*
     483                 :            :          * Removal can be called multiple times on the same node.  Only the
     484                 :            :          * first invocation is effective and puts the base ref.
     485                 :            :          */
     486         [ +  - ]:        987 :         if (kn->flags & KERNFS_REMOVED)
     487                 :          0 :                 return;
     488                 :            : 
     489         [ +  - ]:        987 :         if (kn->parent) {
     490                 :        987 :                 kernfs_unlink_sibling(kn);
     491                 :            : 
     492                 :            :                 /* Update timestamps on the parent */
     493                 :        987 :                 ps_iattr = kn->parent->iattr;
     494         [ -  + ]:        987 :                 if (ps_iattr) {
     495                 :          0 :                         ps_iattr->ia_iattr.ia_ctime = CURRENT_TIME;
     496                 :          0 :                         ps_iattr->ia_iattr.ia_mtime = CURRENT_TIME;
     497                 :            :                 }
     498                 :            :         }
     499                 :            : 
     500                 :        987 :         kn->flags |= KERNFS_REMOVED;
     501                 :        987 :         kn->u.removed_list = acxt->removed;
     502                 :        987 :         acxt->removed = kn;
     503                 :            : }
     504                 :            : 
     505                 :            : /**
     506                 :            :  *      kernfs_addrm_finish - finish up kernfs_node add/remove
     507                 :            :  *      @acxt: addrm context to finish up
     508                 :            :  *
     509                 :            :  *      Finish up kernfs_node add/remove.  Resources acquired by
     510                 :            :  *      kernfs_addrm_start() are released and removed kernfs_nodes are
     511                 :            :  *      cleaned up.
     512                 :            :  *
     513                 :            :  *      LOCKING:
     514                 :            :  *      kernfs_mutex is released.
     515                 :            :  */
     516                 :          0 : void kernfs_addrm_finish(struct kernfs_addrm_cxt *acxt)
     517                 :            :         __releases(kernfs_mutex)
     518                 :            : {
     519                 :            :         /* release resources acquired by kernfs_addrm_start() */
     520                 :       2890 :         mutex_unlock(&kernfs_mutex);
     521                 :            : 
     522                 :            :         /* kill removed kernfs_nodes */
     523         [ +  + ]:       3877 :         while (acxt->removed) {
     524                 :            :                 struct kernfs_node *kn = acxt->removed;
     525                 :            : 
     526                 :        987 :                 acxt->removed = kn->u.removed_list;
     527                 :            : 
     528                 :        987 :                 kernfs_deactivate(kn);
     529                 :        987 :                 kernfs_unmap_bin_file(kn);
     530                 :        987 :                 kernfs_put(kn);
     531                 :            :         }
     532                 :       2890 : }
     533                 :            : 
     534                 :            : /**
     535                 :            :  * kernfs_find_ns - find kernfs_node with the given name
     536                 :            :  * @parent: kernfs_node to search under
     537                 :            :  * @name: name to look for
     538                 :            :  * @ns: the namespace tag to use
     539                 :            :  *
     540                 :            :  * Look for kernfs_node with name @name under @parent.  Returns pointer to
     541                 :            :  * the found kernfs_node on success, %NULL on failure.
     542                 :            :  */
     543                 :          0 : static struct kernfs_node *kernfs_find_ns(struct kernfs_node *parent,
     544                 :            :                                           const unsigned char *name,
     545                 :            :                                           const void *ns)
     546                 :            : {
     547                 :      10277 :         struct rb_node *node = parent->dir.children.rb_node;
     548                 :            :         bool has_ns = kernfs_ns_enabled(parent);
     549                 :            :         unsigned int hash;
     550                 :            : 
     551                 :            :         lockdep_assert_held(&kernfs_mutex);
     552                 :            : 
     553         [ -  + ]:      10277 :         if (has_ns != (bool)ns) {
     554         [ #  # ]:          0 :                 WARN(1, KERN_WARNING "kernfs: ns %s in '%s' for '%s'\n",
     555                 :            :                      has_ns ? "required" : "invalid", parent->name, name);
     556                 :          0 :                 return NULL;
     557                 :            :         }
     558                 :            : 
     559                 :      10277 :         hash = kernfs_name_hash(name, ns);
     560         [ +  + ]:      38795 :         while (node) {
     561                 :            :                 struct kernfs_node *kn;
     562                 :            :                 int result;
     563                 :            : 
     564                 :      30067 :                 kn = rb_to_kn(node);
     565                 :      30067 :                 result = kernfs_name_compare(hash, name, ns, kn);
     566         [ +  + ]:      40344 :                 if (result < 0)
     567                 :       9938 :                         node = node->rb_left;
     568         [ +  + ]:      20129 :                 else if (result > 0)
     569                 :      28518 :                         node = node->rb_right;
     570                 :            :                 else
     571                 :            :                         return kn;
     572                 :            :         }
     573                 :            :         return NULL;
     574                 :            : }
     575                 :            : 
     576                 :            : /**
     577                 :            :  * kernfs_find_and_get_ns - find and get kernfs_node with the given name
     578                 :            :  * @parent: kernfs_node to search under
     579                 :            :  * @name: name to look for
     580                 :            :  * @ns: the namespace tag to use
     581                 :            :  *
     582                 :            :  * Look for kernfs_node with name @name under @parent and get a reference
     583                 :            :  * if found.  This function may sleep and returns pointer to the found
     584                 :            :  * kernfs_node on success, %NULL on failure.
     585                 :            :  */
     586                 :          0 : struct kernfs_node *kernfs_find_and_get_ns(struct kernfs_node *parent,
     587                 :            :                                            const char *name, const void *ns)
     588                 :            : {
     589                 :            :         struct kernfs_node *kn;
     590                 :            : 
     591                 :        176 :         mutex_lock(&kernfs_mutex);
     592                 :        176 :         kn = kernfs_find_ns(parent, name, ns);
     593                 :        176 :         kernfs_get(kn);
     594                 :        176 :         mutex_unlock(&kernfs_mutex);
     595                 :            : 
     596                 :        176 :         return kn;
     597                 :            : }
     598                 :            : EXPORT_SYMBOL_GPL(kernfs_find_and_get_ns);
     599                 :            : 
     600                 :            : /**
     601                 :            :  * kernfs_create_root - create a new kernfs hierarchy
     602                 :            :  * @kdops: optional directory syscall operations for the hierarchy
     603                 :            :  * @priv: opaque data associated with the new directory
     604                 :            :  *
     605                 :            :  * Returns the root of the new hierarchy on success, ERR_PTR() value on
     606                 :            :  * failure.
     607                 :            :  */
     608                 :          0 : struct kernfs_root *kernfs_create_root(struct kernfs_dir_ops *kdops, void *priv)
     609                 :            : {
     610                 :            :         struct kernfs_root *root;
     611                 :            :         struct kernfs_node *kn;
     612                 :            : 
     613                 :            :         root = kzalloc(sizeof(*root), GFP_KERNEL);
     614         [ #  # ]:          0 :         if (!root)
     615                 :            :                 return ERR_PTR(-ENOMEM);
     616                 :            : 
     617                 :          0 :         ida_init(&root->ino_ida);
     618                 :            : 
     619                 :          0 :         kn = __kernfs_new_node(root, "", S_IFDIR | S_IRUGO | S_IXUGO,
     620                 :            :                                KERNFS_DIR);
     621         [ #  # ]:          0 :         if (!kn) {
     622                 :          0 :                 ida_destroy(&root->ino_ida);
     623                 :          0 :                 kfree(root);
     624                 :          0 :                 return ERR_PTR(-ENOMEM);
     625                 :            :         }
     626                 :            : 
     627                 :          0 :         kn->flags &= ~KERNFS_REMOVED;
     628                 :          0 :         kn->priv = priv;
     629                 :          0 :         kn->dir.root = root;
     630                 :            : 
     631                 :          0 :         root->dir_ops = kdops;
     632                 :          0 :         root->kn = kn;
     633                 :            : 
     634                 :          0 :         return root;
     635                 :            : }
     636                 :            : 
     637                 :            : /**
     638                 :            :  * kernfs_destroy_root - destroy a kernfs hierarchy
     639                 :            :  * @root: root of the hierarchy to destroy
     640                 :            :  *
     641                 :            :  * Destroy the hierarchy anchored at @root by removing all existing
     642                 :            :  * directories and destroying @root.
     643                 :            :  */
     644                 :          0 : void kernfs_destroy_root(struct kernfs_root *root)
     645                 :            : {
     646                 :          0 :         kernfs_remove(root->kn);     /* will also free @root */
     647                 :          0 : }
     648                 :            : 
     649                 :            : /**
     650                 :            :  * kernfs_create_dir_ns - create a directory
     651                 :            :  * @parent: parent in which to create a new directory
     652                 :            :  * @name: name of the new directory
     653                 :            :  * @mode: mode of the new directory
     654                 :            :  * @priv: opaque data associated with the new directory
     655                 :            :  * @ns: optional namespace tag of the directory
     656                 :            :  *
     657                 :            :  * Returns the created node on success, ERR_PTR() value on failure.
     658                 :            :  */
     659                 :          0 : struct kernfs_node *kernfs_create_dir_ns(struct kernfs_node *parent,
     660                 :            :                                          const char *name, umode_t mode,
     661                 :            :                                          void *priv, const void *ns)
     662                 :            : {
     663                 :            :         struct kernfs_addrm_cxt acxt;
     664                 :            :         struct kernfs_node *kn;
     665                 :            :         int rc;
     666                 :            : 
     667                 :            :         /* allocate */
     668                 :        353 :         kn = kernfs_new_node(parent, name, mode | S_IFDIR, KERNFS_DIR);
     669         [ +  - ]:        353 :         if (!kn)
     670                 :            :                 return ERR_PTR(-ENOMEM);
     671                 :            : 
     672                 :        353 :         kn->dir.root = parent->dir.root;
     673                 :        353 :         kn->ns = ns;
     674                 :        353 :         kn->priv = priv;
     675                 :            : 
     676                 :            :         /* link in */
     677                 :            :         kernfs_addrm_start(&acxt);
     678                 :        353 :         rc = kernfs_add_one(&acxt, kn);
     679                 :        353 :         kernfs_addrm_finish(&acxt);
     680                 :            : 
     681         [ -  + ]:        353 :         if (!rc)
     682                 :            :                 return kn;
     683                 :            : 
     684                 :          0 :         kernfs_put(kn);
     685                 :          0 :         return ERR_PTR(rc);
     686                 :            : }
     687                 :            : 
     688                 :          0 : static struct dentry *kernfs_iop_lookup(struct inode *dir,
     689                 :            :                                         struct dentry *dentry,
     690                 :            :                                         unsigned int flags)
     691                 :            : {
     692                 :            :         struct dentry *ret;
     693                 :      18192 :         struct kernfs_node *parent = dentry->d_parent->d_fsdata;
     694                 :            :         struct kernfs_node *kn;
     695                 :            :         struct inode *inode;
     696                 :            :         const void *ns = NULL;
     697                 :            : 
     698                 :       9096 :         mutex_lock(&kernfs_mutex);
     699                 :            : 
     700         [ -  + ]:       9096 :         if (kernfs_ns_enabled(parent))
     701                 :          0 :                 ns = kernfs_info(dir->i_sb)->ns;
     702                 :            : 
     703                 :       9096 :         kn = kernfs_find_ns(parent, dentry->d_name.name, ns);
     704                 :            : 
     705                 :            :         /* no such entry */
     706         [ +  + ]:       9096 :         if (!kn) {
     707                 :            :                 ret = NULL;
     708                 :            :                 goto out_unlock;
     709                 :            :         }
     710                 :        555 :         kernfs_get(kn);
     711                 :        555 :         dentry->d_fsdata = kn;
     712                 :            : 
     713                 :            :         /* attach dentry and inode */
     714                 :        555 :         inode = kernfs_get_inode(dir->i_sb, kn);
     715         [ +  - ]:        555 :         if (!inode) {
     716                 :            :                 ret = ERR_PTR(-ENOMEM);
     717                 :            :                 goto out_unlock;
     718                 :            :         }
     719                 :            : 
     720                 :            :         /* instantiate and hash dentry */
     721                 :        555 :         ret = d_materialise_unique(dentry, inode);
     722                 :            :  out_unlock:
     723                 :       9096 :         mutex_unlock(&kernfs_mutex);
     724                 :       9096 :         return ret;
     725                 :            : }
     726                 :            : 
     727                 :          0 : static int kernfs_iop_mkdir(struct inode *dir, struct dentry *dentry,
     728                 :            :                             umode_t mode)
     729                 :            : {
     730                 :          0 :         struct kernfs_node *parent = dir->i_private;
     731                 :          0 :         struct kernfs_dir_ops *kdops = kernfs_root(parent)->dir_ops;
     732                 :            : 
     733 [ #  # ][ #  # ]:          0 :         if (!kdops || !kdops->mkdir)
     734                 :            :                 return -EPERM;
     735                 :            : 
     736                 :          0 :         return kdops->mkdir(parent, dentry->d_name.name, mode);
     737                 :            : }
     738                 :            : 
     739                 :          0 : static int kernfs_iop_rmdir(struct inode *dir, struct dentry *dentry)
     740                 :            : {
     741                 :          0 :         struct kernfs_node *kn  = dentry->d_fsdata;
     742                 :          0 :         struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops;
     743                 :            : 
     744 [ #  # ][ #  # ]:          0 :         if (!kdops || !kdops->rmdir)
     745                 :            :                 return -EPERM;
     746                 :            : 
     747                 :          0 :         return kdops->rmdir(kn);
     748                 :            : }
     749                 :            : 
     750                 :          0 : static int kernfs_iop_rename(struct inode *old_dir, struct dentry *old_dentry,
     751                 :            :                              struct inode *new_dir, struct dentry *new_dentry)
     752                 :            : {
     753                 :          0 :         struct kernfs_node *kn  = old_dentry->d_fsdata;
     754                 :          0 :         struct kernfs_node *new_parent = new_dir->i_private;
     755                 :          0 :         struct kernfs_dir_ops *kdops = kernfs_root(kn)->dir_ops;
     756                 :            : 
     757 [ #  # ][ #  # ]:          0 :         if (!kdops || !kdops->rename)
     758                 :            :                 return -EPERM;
     759                 :            : 
     760                 :          0 :         return kdops->rename(kn, new_parent, new_dentry->d_name.name);
     761                 :            : }
     762                 :            : 
     763                 :            : const struct inode_operations kernfs_dir_iops = {
     764                 :            :         .lookup         = kernfs_iop_lookup,
     765                 :            :         .permission     = kernfs_iop_permission,
     766                 :            :         .setattr        = kernfs_iop_setattr,
     767                 :            :         .getattr        = kernfs_iop_getattr,
     768                 :            :         .setxattr       = kernfs_iop_setxattr,
     769                 :            :         .removexattr    = kernfs_iop_removexattr,
     770                 :            :         .getxattr       = kernfs_iop_getxattr,
     771                 :            :         .listxattr      = kernfs_iop_listxattr,
     772                 :            : 
     773                 :            :         .mkdir          = kernfs_iop_mkdir,
     774                 :            :         .rmdir          = kernfs_iop_rmdir,
     775                 :            :         .rename         = kernfs_iop_rename,
     776                 :            : };
     777                 :            : 
     778                 :        984 : static struct kernfs_node *kernfs_leftmost_descendant(struct kernfs_node *pos)
     779                 :            : {
     780                 :            :         struct kernfs_node *last;
     781                 :            : 
     782                 :            :         while (true) {
     783                 :            :                 struct rb_node *rbn;
     784                 :            : 
     785                 :            :                 last = pos;
     786                 :            : 
     787         [ +  + ]:        987 :                 if (kernfs_type(pos) != KERNFS_DIR)
     788                 :            :                         break;
     789                 :            : 
     790                 :        127 :                 rbn = rb_first(&pos->dir.children);
     791         [ +  + ]:        127 :                 if (!rbn)
     792                 :            :                         break;
     793                 :            : 
     794                 :          3 :                 pos = rb_to_kn(rbn);
     795                 :          3 :         }
     796                 :            : 
     797                 :          0 :         return last;
     798                 :            : }
     799                 :            : 
     800                 :            : /**
     801                 :            :  * kernfs_next_descendant_post - find the next descendant for post-order walk
     802                 :            :  * @pos: the current position (%NULL to initiate traversal)
     803                 :            :  * @root: kernfs_node whose descendants to walk
     804                 :            :  *
     805                 :            :  * Find the next descendant to visit for post-order traversal of @root's
     806                 :            :  * descendants.  @root is included in the iteration and the last node to be
     807                 :            :  * visited.
     808                 :            :  */
     809                 :          0 : static struct kernfs_node *kernfs_next_descendant_post(struct kernfs_node *pos,
     810                 :            :                                                        struct kernfs_node *root)
     811                 :            : {
     812                 :            :         struct rb_node *rbn;
     813                 :            : 
     814                 :            :         lockdep_assert_held(&kernfs_mutex);
     815                 :            : 
     816                 :            :         /* if first iteration, visit leftmost descendant which may be root */
     817         [ +  + ]:       1932 :         if (!pos)
     818                 :        945 :                 return kernfs_leftmost_descendant(root);
     819                 :            : 
     820                 :            :         /* if we visited @root, we're done */
     821         [ +  + ]:        987 :         if (pos == root)
     822                 :            :                 return NULL;
     823                 :            : 
     824                 :            :         /* if there's an unvisited sibling, visit its leftmost descendant */
     825                 :         42 :         rbn = rb_next(&pos->rb);
     826         [ +  + ]:       1974 :         if (rbn)
     827                 :         39 :                 return kernfs_leftmost_descendant(rb_to_kn(rbn));
     828                 :            : 
     829                 :            :         /* no sibling left, visit parent */
     830                 :          3 :         return pos->parent;
     831                 :            : }
     832                 :            : 
     833                 :          0 : static void __kernfs_remove(struct kernfs_addrm_cxt *acxt,
     834                 :            :                             struct kernfs_node *kn)
     835                 :            : {
     836                 :            :         struct kernfs_node *pos, *next;
     837                 :            : 
     838         [ +  - ]:        945 :         if (!kn)
     839                 :        945 :                 return;
     840                 :            : 
     841                 :            :         pr_debug("kernfs %s: removing\n", kn->name);
     842                 :            : 
     843                 :            :         next = NULL;
     844                 :            :         do {
     845                 :            :                 pos = next;
     846                 :       1932 :                 next = kernfs_next_descendant_post(pos, kn);
     847         [ +  + ]:       1932 :                 if (pos)
     848                 :        987 :                         kernfs_remove_one(acxt, pos);
     849         [ +  + ]:       2877 :         } while (next);
     850                 :            : }
     851                 :            : 
     852                 :            : /**
     853                 :            :  * kernfs_remove - remove a kernfs_node recursively
     854                 :            :  * @kn: the kernfs_node to remove
     855                 :            :  *
     856                 :            :  * Remove @kn along with all its subdirectories and files.
     857                 :            :  */
     858                 :          0 : void kernfs_remove(struct kernfs_node *kn)
     859                 :            : {
     860                 :            :         struct kernfs_addrm_cxt acxt;
     861                 :            : 
     862                 :            :         kernfs_addrm_start(&acxt);
     863                 :        127 :         __kernfs_remove(&acxt, kn);
     864                 :        127 :         kernfs_addrm_finish(&acxt);
     865                 :        127 : }
     866                 :            : 
     867                 :            : /**
     868                 :            :  * kernfs_remove_by_name_ns - find a kernfs_node by name and remove it
     869                 :            :  * @parent: parent of the target
     870                 :            :  * @name: name of the kernfs_node to remove
     871                 :            :  * @ns: namespace tag of the kernfs_node to remove
     872                 :            :  *
     873                 :            :  * Look for the kernfs_node with @name and @ns under @parent and remove it.
     874                 :            :  * Returns 0 on success, -ENOENT if such entry doesn't exist.
     875                 :            :  */
     876                 :          0 : int kernfs_remove_by_name_ns(struct kernfs_node *parent, const char *name,
     877                 :            :                              const void *ns)
     878                 :            : {
     879                 :            :         struct kernfs_addrm_cxt acxt;
     880                 :            :         struct kernfs_node *kn;
     881                 :            : 
     882         [ -  + ]:        976 :         if (!parent) {
     883                 :          0 :                 WARN(1, KERN_WARNING "kernfs: can not remove '%s', no directory\n",
     884                 :            :                         name);
     885                 :          0 :                 return -ENOENT;
     886                 :            :         }
     887                 :            : 
     888                 :            :         kernfs_addrm_start(&acxt);
     889                 :            : 
     890                 :        976 :         kn = kernfs_find_ns(parent, name, ns);
     891         [ +  + ]:        976 :         if (kn)
     892                 :        818 :                 __kernfs_remove(&acxt, kn);
     893                 :            : 
     894                 :        976 :         kernfs_addrm_finish(&acxt);
     895                 :            : 
     896         [ +  + ]:        976 :         if (kn)
     897                 :            :                 return 0;
     898                 :            :         else
     899                 :        158 :                 return -ENOENT;
     900                 :            : }
     901                 :            : 
     902                 :            : /**
     903                 :            :  * kernfs_rename_ns - move and rename a kernfs_node
     904                 :            :  * @kn: target node
     905                 :            :  * @new_parent: new parent to put @sd under
     906                 :            :  * @new_name: new name
     907                 :            :  * @new_ns: new namespace tag
     908                 :            :  */
     909                 :          0 : int kernfs_rename_ns(struct kernfs_node *kn, struct kernfs_node *new_parent,
     910                 :            :                      const char *new_name, const void *new_ns)
     911                 :            : {
     912                 :            :         int error;
     913                 :            : 
     914                 :         29 :         mutex_lock(&kernfs_mutex);
     915                 :            : 
     916                 :            :         error = -ENOENT;
     917         [ +  - ]:         29 :         if ((kn->flags | new_parent->flags) & KERNFS_REMOVED)
     918                 :            :                 goto out;
     919                 :            : 
     920                 :            :         error = 0;
     921 [ -  + ][ #  # ]:         29 :         if ((kn->parent == new_parent) && (kn->ns == new_ns) &&
                 [ #  # ]
     922                 :          0 :             (strcmp(kn->name, new_name) == 0))
     923                 :            :                 goto out;       /* nothing to rename */
     924                 :            : 
     925                 :            :         error = -EEXIST;
     926         [ +  - ]:         29 :         if (kernfs_find_ns(new_parent, new_name, new_ns))
     927                 :            :                 goto out;
     928                 :            : 
     929                 :            :         /* rename kernfs_node */
     930         [ -  + ]:         29 :         if (strcmp(kn->name, new_name) != 0) {
     931                 :            :                 error = -ENOMEM;
     932                 :          0 :                 new_name = kstrdup(new_name, GFP_KERNEL);
     933         [ #  # ]:          0 :                 if (!new_name)
     934                 :            :                         goto out;
     935                 :            : 
     936         [ #  # ]:          0 :                 if (kn->flags & KERNFS_STATIC_NAME)
     937                 :          0 :                         kn->flags &= ~KERNFS_STATIC_NAME;
     938                 :            :                 else
     939                 :          0 :                         kfree(kn->name);
     940                 :            : 
     941                 :          0 :                 kn->name = new_name;
     942                 :            :         }
     943                 :            : 
     944                 :            :         /*
     945                 :            :          * Move to the appropriate place in the appropriate directories rbtree.
     946                 :            :          */
     947                 :         29 :         kernfs_unlink_sibling(kn);
     948                 :         29 :         kernfs_get(new_parent);
     949                 :         29 :         kernfs_put(kn->parent);
     950                 :         29 :         kn->ns = new_ns;
     951                 :         29 :         kn->hash = kernfs_name_hash(kn->name, kn->ns);
     952                 :         29 :         kn->parent = new_parent;
     953                 :         29 :         kernfs_link_sibling(kn);
     954                 :            : 
     955                 :            :         error = 0;
     956                 :            :  out:
     957                 :         29 :         mutex_unlock(&kernfs_mutex);
     958                 :         29 :         return error;
     959                 :            : }
     960                 :            : 
     961                 :            : /* Relationship between s_mode and the DT_xxx types */
     962                 :            : static inline unsigned char dt_type(struct kernfs_node *kn)
     963                 :            : {
     964                 :        322 :         return (kn->mode >> 12) & 15;
     965                 :            : }
     966                 :            : 
     967                 :          0 : static int kernfs_dir_fop_release(struct inode *inode, struct file *filp)
     968                 :            : {
     969                 :         59 :         kernfs_put(filp->private_data);
     970                 :         59 :         return 0;
     971                 :            : }
     972                 :            : 
     973                 :          0 : static struct kernfs_node *kernfs_dir_pos(const void *ns,
     974                 :            :         struct kernfs_node *parent, loff_t hash, struct kernfs_node *pos)
     975                 :            : {
     976         [ +  + ]:        382 :         if (pos) {
     977         [ +  - ]:        322 :                 int valid = !(pos->flags & KERNFS_REMOVED) &&
     978 [ +  - ][ -  + ]:        644 :                         pos->parent == parent && hash == pos->hash;
     979                 :        322 :                 kernfs_put(pos);
     980         [ -  + ]:        322 :                 if (!valid)
     981                 :            :                         pos = NULL;
     982                 :            :         }
     983 [ +  + ][ +  + ]:        412 :         if (!pos && (hash > 1) && (hash < INT_MAX)) {
     984                 :         30 :                 struct rb_node *node = parent->dir.children.rb_node;
     985         [ +  + ]:        134 :                 while (node) {
     986                 :        104 :                         pos = rb_to_kn(node);
     987                 :            : 
     988         [ +  - ]:        104 :                         if (hash < pos->hash)
     989                 :        104 :                                 node = node->rb_left;
     990         [ #  # ]:          0 :                         else if (hash > pos->hash)
     991                 :        104 :                                 node = node->rb_right;
     992                 :            :                         else
     993                 :            :                                 break;
     994                 :            :                 }
     995                 :            :         }
     996                 :            :         /* Skip over entries in the wrong namespace */
     997 [ +  + ][ -  + ]:        382 :         while (pos && pos->ns != ns) {
     998                 :          0 :                 struct rb_node *node = rb_next(&pos->rb);
     999         [ #  # ]:          0 :                 if (!node)
    1000                 :            :                         pos = NULL;
    1001                 :            :                 else
    1002                 :          0 :                         pos = rb_to_kn(node);
    1003                 :            :         }
    1004                 :        382 :         return pos;
    1005                 :            : }
    1006                 :            : 
    1007                 :          0 : static struct kernfs_node *kernfs_dir_next_pos(const void *ns,
    1008                 :            :         struct kernfs_node *parent, ino_t ino, struct kernfs_node *pos)
    1009                 :            : {
    1010                 :        322 :         pos = kernfs_dir_pos(ns, parent, ino, pos);
    1011         [ +  - ]:        322 :         if (pos)
    1012                 :            :                 do {
    1013                 :        322 :                         struct rb_node *node = rb_next(&pos->rb);
    1014         [ +  + ]:        322 :                         if (!node)
    1015                 :            :                                 pos = NULL;
    1016                 :            :                         else
    1017                 :        292 :                                 pos = rb_to_kn(node);
    1018    [ + ][ -  + ]:        322 :                 } while (pos && pos->ns != ns);
    1019                 :          0 :         return pos;
    1020                 :            : }
    1021                 :            : 
    1022                 :          0 : static int kernfs_fop_readdir(struct file *file, struct dir_context *ctx)
    1023                 :            : {
    1024                 :         60 :         struct dentry *dentry = file->f_path.dentry;
    1025                 :        120 :         struct kernfs_node *parent = dentry->d_fsdata;
    1026                 :        382 :         struct kernfs_node *pos = file->private_data;
    1027                 :            :         const void *ns = NULL;
    1028                 :            : 
    1029         [ +  - ]:         60 :         if (!dir_emit_dots(file, ctx))
    1030                 :            :                 return 0;
    1031                 :         60 :         mutex_lock(&kernfs_mutex);
    1032                 :            : 
    1033         [ -  + ]:         60 :         if (kernfs_ns_enabled(parent))
    1034                 :          0 :                 ns = kernfs_info(dentry->d_sb)->ns;
    1035                 :            : 
    1036         [ +  + ]:        382 :         for (pos = kernfs_dir_pos(ns, parent, ctx->pos, pos);
    1037                 :            :              pos;
    1038                 :        322 :              pos = kernfs_dir_next_pos(ns, parent, ctx->pos, pos)) {
    1039                 :        322 :                 const char *name = pos->name;
    1040                 :        322 :                 unsigned int type = dt_type(pos);
    1041                 :        322 :                 int len = strlen(name);
    1042                 :        322 :                 ino_t ino = pos->ino;
    1043                 :            : 
    1044                 :        322 :                 ctx->pos = pos->hash;
    1045                 :        322 :                 file->private_data = pos;
    1046                 :        322 :                 kernfs_get(pos);
    1047                 :            : 
    1048                 :        322 :                 mutex_unlock(&kernfs_mutex);
    1049         [ +  - ]:        322 :                 if (!dir_emit(ctx, name, len, ino, type))
    1050                 :            :                         return 0;
    1051                 :        322 :                 mutex_lock(&kernfs_mutex);
    1052                 :            :         }
    1053                 :         60 :         mutex_unlock(&kernfs_mutex);
    1054                 :         60 :         file->private_data = NULL;
    1055                 :         60 :         ctx->pos = INT_MAX;
    1056                 :         60 :         return 0;
    1057                 :            : }
    1058                 :            : 
    1059                 :          0 : static loff_t kernfs_dir_fop_llseek(struct file *file, loff_t offset,
    1060                 :            :                                     int whence)
    1061                 :            : {
    1062                 :            :         struct inode *inode = file_inode(file);
    1063                 :            :         loff_t ret;
    1064                 :            : 
    1065                 :          0 :         mutex_lock(&inode->i_mutex);
    1066                 :          0 :         ret = generic_file_llseek(file, offset, whence);
    1067                 :          0 :         mutex_unlock(&inode->i_mutex);
    1068                 :            : 
    1069                 :          0 :         return ret;
    1070                 :            : }
    1071                 :            : 
    1072                 :            : const struct file_operations kernfs_dir_fops = {
    1073                 :            :         .read           = generic_read_dir,
    1074                 :            :         .iterate        = kernfs_fop_readdir,
    1075                 :            :         .release        = kernfs_dir_fop_release,
    1076                 :            :         .llseek         = kernfs_dir_fop_llseek,
    1077                 :            : };

Generated by: LCOV version 1.9