LCOV - code coverage report
Current view: top level - fs/exportfs - expfs.c (source / functions) Hit Total Coverage
Test: combined.info Lines: 24 238 10.1 %
Date: 2022-04-01 14:35:51 Functions: 2 11 18.2 %
Branches: 7 146 4.8 %

           Branch data     Line data    Source code
       1                 :            : // SPDX-License-Identifier: GPL-2.0-only
       2                 :            : /*
       3                 :            :  * Copyright (C) Neil Brown 2002
       4                 :            :  * Copyright (C) Christoph Hellwig 2007
       5                 :            :  *
       6                 :            :  * This file contains the code mapping from inodes to NFS file handles,
       7                 :            :  * and for mapping back from file handles to dentries.
       8                 :            :  *
       9                 :            :  * For details on why we do all the strange and hairy things in here
      10                 :            :  * take a look at Documentation/filesystems/nfs/exporting.rst.
      11                 :            :  */
      12                 :            : #include <linux/exportfs.h>
      13                 :            : #include <linux/fs.h>
      14                 :            : #include <linux/file.h>
      15                 :            : #include <linux/module.h>
      16                 :            : #include <linux/mount.h>
      17                 :            : #include <linux/namei.h>
      18                 :            : #include <linux/sched.h>
      19                 :            : #include <linux/cred.h>
      20                 :            : 
      21                 :            : #define dprintk(fmt, args...) do{}while(0)
      22                 :            : 
      23                 :            : 
      24                 :            : static int get_name(const struct path *path, char *name, struct dentry *child);
      25                 :            : 
      26                 :            : 
      27                 :          0 : static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir,
      28                 :            :                 char *name, struct dentry *child)
      29                 :            : {
      30                 :          0 :         const struct export_operations *nop = dir->d_sb->s_export_op;
      31                 :          0 :         struct path path = {.mnt = mnt, .dentry = dir};
      32                 :            : 
      33         [ #  # ]:          0 :         if (nop->get_name)
      34                 :          0 :                 return nop->get_name(dir, name, child);
      35                 :            :         else
      36                 :          0 :                 return get_name(&path, name, child);
      37                 :            : }
      38                 :            : 
      39                 :            : /*
      40                 :            :  * Check if the dentry or any of it's aliases is acceptable.
      41                 :            :  */
      42                 :            : static struct dentry *
      43                 :          0 : find_acceptable_alias(struct dentry *result,
      44                 :            :                 int (*acceptable)(void *context, struct dentry *dentry),
      45                 :            :                 void *context)
      46                 :            : {
      47                 :          0 :         struct dentry *dentry, *toput = NULL;
      48                 :          0 :         struct inode *inode;
      49                 :            : 
      50         [ #  # ]:          0 :         if (acceptable(context, result))
      51                 :            :                 return result;
      52                 :            : 
      53                 :          0 :         inode = result->d_inode;
      54                 :          0 :         spin_lock(&inode->i_lock);
      55   [ #  #  #  # ]:          0 :         hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
      56                 :          0 :                 dget(dentry);
      57                 :          0 :                 spin_unlock(&inode->i_lock);
      58         [ #  # ]:          0 :                 if (toput)
      59                 :          0 :                         dput(toput);
      60   [ #  #  #  # ]:          0 :                 if (dentry != result && acceptable(context, dentry)) {
      61                 :          0 :                         dput(result);
      62                 :          0 :                         return dentry;
      63                 :            :                 }
      64                 :          0 :                 spin_lock(&inode->i_lock);
      65         [ #  # ]:          0 :                 toput = dentry;
      66                 :            :         }
      67                 :          0 :         spin_unlock(&inode->i_lock);
      68                 :            : 
      69         [ #  # ]:          0 :         if (toput)
      70                 :          0 :                 dput(toput);
      71                 :            :         return NULL;
      72                 :            : }
      73                 :            : 
      74                 :          0 : static bool dentry_connected(struct dentry *dentry)
      75                 :            : {
      76         [ #  # ]:          0 :         dget(dentry);
      77         [ #  # ]:          0 :         while (dentry->d_flags & DCACHE_DISCONNECTED) {
      78                 :          0 :                 struct dentry *parent = dget_parent(dentry);
      79                 :            : 
      80                 :          0 :                 dput(dentry);
      81         [ #  # ]:          0 :                 if (dentry == parent) {
      82                 :          0 :                         dput(parent);
      83                 :          0 :                         return false;
      84                 :            :                 }
      85                 :            :                 dentry = parent;
      86                 :            :         }
      87                 :          0 :         dput(dentry);
      88                 :          0 :         return true;
      89                 :            : }
      90                 :            : 
      91                 :          0 : static void clear_disconnected(struct dentry *dentry)
      92                 :            : {
      93         [ #  # ]:          0 :         dget(dentry);
      94         [ #  # ]:          0 :         while (dentry->d_flags & DCACHE_DISCONNECTED) {
      95                 :          0 :                 struct dentry *parent = dget_parent(dentry);
      96                 :            : 
      97         [ #  # ]:          0 :                 WARN_ON_ONCE(IS_ROOT(dentry));
      98                 :            : 
      99                 :          0 :                 spin_lock(&dentry->d_lock);
     100                 :          0 :                 dentry->d_flags &= ~DCACHE_DISCONNECTED;
     101                 :          0 :                 spin_unlock(&dentry->d_lock);
     102                 :            : 
     103                 :          0 :                 dput(dentry);
     104                 :          0 :                 dentry = parent;
     105                 :            :         }
     106                 :          0 :         dput(dentry);
     107                 :          0 : }
     108                 :            : 
     109                 :            : /*
     110                 :            :  * Reconnect a directory dentry with its parent.
     111                 :            :  *
     112                 :            :  * This can return a dentry, or NULL, or an error.
     113                 :            :  *
     114                 :            :  * In the first case the returned dentry is the parent of the given
     115                 :            :  * dentry, and may itself need to be reconnected to its parent.
     116                 :            :  *
     117                 :            :  * In the NULL case, a concurrent VFS operation has either renamed or
     118                 :            :  * removed this directory.  The concurrent operation has reconnected our
     119                 :            :  * dentry, so we no longer need to.
     120                 :            :  */
     121                 :          0 : static struct dentry *reconnect_one(struct vfsmount *mnt,
     122                 :            :                 struct dentry *dentry, char *nbuf)
     123                 :            : {
     124                 :          0 :         struct dentry *parent;
     125                 :          0 :         struct dentry *tmp;
     126                 :          0 :         int err;
     127                 :            : 
     128                 :          0 :         parent = ERR_PTR(-EACCES);
     129                 :          0 :         inode_lock(dentry->d_inode);
     130         [ #  # ]:          0 :         if (mnt->mnt_sb->s_export_op->get_parent)
     131                 :          0 :                 parent = mnt->mnt_sb->s_export_op->get_parent(dentry);
     132                 :          0 :         inode_unlock(dentry->d_inode);
     133                 :            : 
     134         [ #  # ]:          0 :         if (IS_ERR(parent)) {
     135                 :            :                 dprintk("%s: get_parent of %ld failed, err %d\n",
     136                 :            :                         __func__, dentry->d_inode->i_ino, PTR_ERR(parent));
     137                 :            :                 return parent;
     138                 :            :         }
     139                 :            : 
     140                 :          0 :         dprintk("%s: find name of %lu in %lu\n", __func__,
     141                 :            :                 dentry->d_inode->i_ino, parent->d_inode->i_ino);
     142                 :          0 :         err = exportfs_get_name(mnt, parent, nbuf, dentry);
     143         [ #  # ]:          0 :         if (err == -ENOENT)
     144                 :          0 :                 goto out_reconnected;
     145         [ #  # ]:          0 :         if (err)
     146                 :          0 :                 goto out_err;
     147                 :          0 :         dprintk("%s: found name: %s\n", __func__, nbuf);
     148                 :          0 :         tmp = lookup_one_len_unlocked(nbuf, parent, strlen(nbuf));
     149         [ #  # ]:          0 :         if (IS_ERR(tmp)) {
     150                 :          0 :                 dprintk("%s: lookup failed: %d\n", __func__, PTR_ERR(tmp));
     151                 :          0 :                 err = PTR_ERR(tmp);
     152                 :          0 :                 goto out_err;
     153                 :            :         }
     154         [ #  # ]:          0 :         if (tmp != dentry) {
     155                 :            :                 /*
     156                 :            :                  * Somebody has renamed it since exportfs_get_name();
     157                 :            :                  * great, since it could've only been renamed if it
     158                 :            :                  * got looked up and thus connected, and it would
     159                 :            :                  * remain connected afterwards.  We are done.
     160                 :            :                  */
     161                 :          0 :                 dput(tmp);
     162                 :          0 :                 goto out_reconnected;
     163                 :            :         }
     164                 :          0 :         dput(tmp);
     165         [ #  # ]:          0 :         if (IS_ROOT(dentry)) {
     166                 :          0 :                 err = -ESTALE;
     167                 :          0 :                 goto out_err;
     168                 :            :         }
     169                 :            :         return parent;
     170                 :            : 
     171                 :          0 : out_err:
     172                 :          0 :         dput(parent);
     173                 :          0 :         return ERR_PTR(err);
     174                 :          0 : out_reconnected:
     175                 :          0 :         dput(parent);
     176                 :            :         /*
     177                 :            :          * Someone must have renamed our entry into another parent, in
     178                 :            :          * which case it has been reconnected by the rename.
     179                 :            :          *
     180                 :            :          * Or someone removed it entirely, in which case filehandle
     181                 :            :          * lookup will succeed but the directory is now IS_DEAD and
     182                 :            :          * subsequent operations on it will fail.
     183                 :            :          *
     184                 :            :          * Alternatively, maybe there was no race at all, and the
     185                 :            :          * filesystem is just corrupt and gave us a parent that doesn't
     186                 :            :          * actually contain any entry pointing to this inode.  So,
     187                 :            :          * double check that this worked and return -ESTALE if not:
     188                 :            :          */
     189         [ #  # ]:          0 :         if (!dentry_connected(dentry))
     190                 :          0 :                 return ERR_PTR(-ESTALE);
     191                 :            :         return NULL;
     192                 :            : }
     193                 :            : 
     194                 :            : /*
     195                 :            :  * Make sure target_dir is fully connected to the dentry tree.
     196                 :            :  *
     197                 :            :  * On successful return, DCACHE_DISCONNECTED will be cleared on
     198                 :            :  * target_dir, and target_dir->d_parent->...->d_parent will reach the
     199                 :            :  * root of the filesystem.
     200                 :            :  *
     201                 :            :  * Whenever DCACHE_DISCONNECTED is unset, target_dir is fully connected.
     202                 :            :  * But the converse is not true: target_dir may have DCACHE_DISCONNECTED
     203                 :            :  * set but already be connected.  In that case we'll verify the
     204                 :            :  * connection to root and then clear the flag.
     205                 :            :  *
     206                 :            :  * Note that target_dir could be removed by a concurrent operation.  In
     207                 :            :  * that case reconnect_path may still succeed with target_dir fully
     208                 :            :  * connected, but further operations using the filehandle will fail when
     209                 :            :  * necessary (due to S_DEAD being set on the directory).
     210                 :            :  */
     211                 :            : static int
     212                 :          0 : reconnect_path(struct vfsmount *mnt, struct dentry *target_dir, char *nbuf)
     213                 :            : {
     214                 :          0 :         struct dentry *dentry, *parent;
     215                 :            : 
     216         [ #  # ]:          0 :         dentry = dget(target_dir);
     217                 :            : 
     218         [ #  # ]:          0 :         while (dentry->d_flags & DCACHE_DISCONNECTED) {
     219         [ #  # ]:          0 :                 BUG_ON(dentry == mnt->mnt_sb->s_root);
     220                 :            : 
     221         [ #  # ]:          0 :                 if (IS_ROOT(dentry))
     222                 :          0 :                         parent = reconnect_one(mnt, dentry, nbuf);
     223                 :            :                 else
     224                 :          0 :                         parent = dget_parent(dentry);
     225                 :            : 
     226         [ #  # ]:          0 :                 if (!parent)
     227                 :            :                         break;
     228                 :          0 :                 dput(dentry);
     229         [ #  # ]:          0 :                 if (IS_ERR(parent))
     230                 :          0 :                         return PTR_ERR(parent);
     231                 :            :                 dentry = parent;
     232                 :            :         }
     233                 :          0 :         dput(dentry);
     234                 :          0 :         clear_disconnected(target_dir);
     235                 :          0 :         return 0;
     236                 :            : }
     237                 :            : 
     238                 :            : struct getdents_callback {
     239                 :            :         struct dir_context ctx;
     240                 :            :         char *name;             /* name that was found. It already points to a
     241                 :            :                                    buffer NAME_MAX+1 is size */
     242                 :            :         u64 ino;                /* the inum we are looking for */
     243                 :            :         int found;              /* inode matched? */
     244                 :            :         int sequence;           /* sequence counter */
     245                 :            : };
     246                 :            : 
     247                 :            : /*
     248                 :            :  * A rather strange filldir function to capture
     249                 :            :  * the name matching the specified inode number.
     250                 :            :  */
     251                 :          0 : static int filldir_one(struct dir_context *ctx, const char *name, int len,
     252                 :            :                         loff_t pos, u64 ino, unsigned int d_type)
     253                 :            : {
     254                 :          0 :         struct getdents_callback *buf =
     255                 :          0 :                 container_of(ctx, struct getdents_callback, ctx);
     256                 :          0 :         int result = 0;
     257                 :            : 
     258                 :          0 :         buf->sequence++;
     259   [ #  #  #  # ]:          0 :         if (buf->ino == ino && len <= NAME_MAX) {
     260                 :          0 :                 memcpy(buf->name, name, len);
     261                 :          0 :                 buf->name[len] = '\0';
     262                 :          0 :                 buf->found = 1;
     263                 :          0 :                 result = -1;
     264                 :            :         }
     265                 :          0 :         return result;
     266                 :            : }
     267                 :            : 
     268                 :            : /**
     269                 :            :  * get_name - default export_operations->get_name function
     270                 :            :  * @path:   the directory in which to find a name
     271                 :            :  * @name:   a pointer to a %NAME_MAX+1 char buffer to store the name
     272                 :            :  * @child:  the dentry for the child directory.
     273                 :            :  *
     274                 :            :  * calls readdir on the parent until it finds an entry with
     275                 :            :  * the same inode number as the child, and returns that.
     276                 :            :  */
     277                 :          0 : static int get_name(const struct path *path, char *name, struct dentry *child)
     278                 :            : {
     279         [ #  # ]:          0 :         const struct cred *cred = current_cred();
     280                 :          0 :         struct inode *dir = path->dentry->d_inode;
     281                 :          0 :         int error;
     282                 :          0 :         struct file *file;
     283                 :          0 :         struct kstat stat;
     284                 :          0 :         struct path child_path = {
     285                 :          0 :                 .mnt = path->mnt,
     286                 :            :                 .dentry = child,
     287                 :            :         };
     288                 :          0 :         struct getdents_callback buffer = {
     289                 :            :                 .ctx.actor = filldir_one,
     290                 :            :                 .name = name,
     291                 :            :         };
     292                 :            : 
     293                 :          0 :         error = -ENOTDIR;
     294   [ #  #  #  # ]:          0 :         if (!dir || !S_ISDIR(dir->i_mode))
     295                 :          0 :                 goto out;
     296                 :          0 :         error = -EINVAL;
     297         [ #  # ]:          0 :         if (!dir->i_fop)
     298                 :          0 :                 goto out;
     299                 :            :         /*
     300                 :            :          * inode->i_ino is unsigned long, kstat->ino is u64, so the
     301                 :            :          * former would be insufficient on 32-bit hosts when the
     302                 :            :          * filesystem supports 64-bit inode numbers.  So we need to
     303                 :            :          * actually call ->getattr, not just read i_ino:
     304                 :            :          */
     305                 :          0 :         error = vfs_getattr_nosec(&child_path, &stat,
     306                 :            :                                   STATX_INO, AT_STATX_SYNC_AS_STAT);
     307         [ #  # ]:          0 :         if (error)
     308                 :            :                 return error;
     309                 :          0 :         buffer.ino = stat.ino;
     310                 :            :         /*
     311                 :            :          * Open the directory ...
     312                 :            :          */
     313                 :          0 :         file = dentry_open(path, O_RDONLY, cred);
     314         [ #  # ]:          0 :         error = PTR_ERR(file);
     315         [ #  # ]:          0 :         if (IS_ERR(file))
     316                 :          0 :                 goto out;
     317                 :            : 
     318                 :          0 :         error = -EINVAL;
     319   [ #  #  #  # ]:          0 :         if (!file->f_op->iterate && !file->f_op->iterate_shared)
     320                 :          0 :                 goto out_close;
     321                 :            : 
     322                 :          0 :         buffer.sequence = 0;
     323                 :          0 :         while (1) {
     324                 :          0 :                 int old_seq = buffer.sequence;
     325                 :            : 
     326                 :          0 :                 error = iterate_dir(file, &buffer.ctx);
     327         [ #  # ]:          0 :                 if (buffer.found) {
     328                 :            :                         error = 0;
     329                 :            :                         break;
     330                 :            :                 }
     331                 :            : 
     332         [ #  # ]:          0 :                 if (error < 0)
     333                 :            :                         break;
     334                 :            : 
     335                 :          0 :                 error = -ENOENT;
     336         [ #  # ]:          0 :                 if (old_seq == buffer.sequence)
     337                 :            :                         break;
     338                 :            :         }
     339                 :            : 
     340                 :          0 : out_close:
     341                 :          0 :         fput(file);
     342                 :            : out:
     343                 :            :         return error;
     344                 :            : }
     345                 :            : 
     346                 :            : /**
     347                 :            :  * export_encode_fh - default export_operations->encode_fh function
     348                 :            :  * @inode:   the object to encode
     349                 :            :  * @fid:     where to store the file handle fragment
     350                 :            :  * @max_len: maximum length to store there
     351                 :            :  * @parent:  parent directory inode, if wanted
     352                 :            :  *
     353                 :            :  * This default encode_fh function assumes that the 32 inode number
     354                 :            :  * is suitable for locating an inode, and that the generation number
     355                 :            :  * can be used to check that it is still valid.  It places them in the
     356                 :            :  * filehandle fragment where export_decode_fh expects to find them.
     357                 :            :  */
     358                 :        441 : static int export_encode_fh(struct inode *inode, struct fid *fid,
     359                 :            :                 int *max_len, struct inode *parent)
     360                 :            : {
     361                 :        441 :         int len = *max_len;
     362                 :        441 :         int type = FILEID_INO32_GEN;
     363                 :            : 
     364                 :        441 :         if (parent && (len < 4)) {
     365                 :          0 :                 *max_len = 4;
     366                 :          0 :                 return FILEID_INVALID;
     367         [ -  + ]:        441 :         } else if (len < 2) {
     368                 :          0 :                 *max_len = 2;
     369                 :          0 :                 return FILEID_INVALID;
     370                 :            :         }
     371                 :            : 
     372                 :        441 :         len = 2;
     373                 :        441 :         fid->i32.ino = inode->i_ino;
     374                 :        441 :         fid->i32.gen = inode->i_generation;
     375         [ -  + ]:        441 :         if (parent) {
     376                 :          0 :                 fid->i32.parent_ino = parent->i_ino;
     377                 :          0 :                 fid->i32.parent_gen = parent->i_generation;
     378                 :          0 :                 len = 4;
     379                 :          0 :                 type = FILEID_INO32_GEN_PARENT;
     380                 :            :         }
     381                 :        441 :         *max_len = len;
     382                 :        441 :         return type;
     383                 :            : }
     384                 :            : 
     385                 :       1050 : int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
     386                 :            :                              int *max_len, struct inode *parent)
     387                 :            : {
     388                 :       1050 :         const struct export_operations *nop = inode->i_sb->s_export_op;
     389                 :            : 
     390   [ +  -  +  + ]:       1050 :         if (nop && nop->encode_fh)
     391                 :        609 :                 return nop->encode_fh(inode, fid->raw, max_len, parent);
     392                 :            : 
     393         [ -  + ]:        441 :         return export_encode_fh(inode, fid, max_len, parent);
     394                 :            : }
     395                 :            : EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
     396                 :            : 
     397                 :       1050 : int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
     398                 :            :                 int connectable)
     399                 :            : {
     400                 :       1050 :         int error;
     401                 :       1050 :         struct dentry *p = NULL;
     402                 :       1050 :         struct inode *inode = dentry->d_inode, *parent = NULL;
     403                 :            : 
     404   [ -  +  -  - ]:       1050 :         if (connectable && !S_ISDIR(inode->i_mode)) {
     405                 :          0 :                 p = dget_parent(dentry);
     406                 :            :                 /*
     407                 :            :                  * note that while p might've ceased to be our parent already,
     408                 :            :                  * it's still pinned by and still positive.
     409                 :            :                  */
     410                 :          0 :                 parent = p->d_inode;
     411                 :            :         }
     412                 :            : 
     413                 :       1050 :         error = exportfs_encode_inode_fh(inode, fid, max_len, parent);
     414                 :       1050 :         dput(p);
     415                 :            : 
     416                 :       1050 :         return error;
     417                 :            : }
     418                 :            : EXPORT_SYMBOL_GPL(exportfs_encode_fh);
     419                 :            : 
     420                 :          0 : struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
     421                 :            :                 int fh_len, int fileid_type,
     422                 :            :                 int (*acceptable)(void *, struct dentry *), void *context)
     423                 :            : {
     424                 :          0 :         const struct export_operations *nop = mnt->mnt_sb->s_export_op;
     425                 :          0 :         struct dentry *result, *alias;
     426                 :          0 :         char nbuf[NAME_MAX+1];
     427                 :          0 :         int err;
     428                 :            : 
     429                 :            :         /*
     430                 :            :          * Try to get any dentry for the given file handle from the filesystem.
     431                 :            :          */
     432   [ #  #  #  # ]:          0 :         if (!nop || !nop->fh_to_dentry)
     433                 :            :                 return ERR_PTR(-ESTALE);
     434                 :          0 :         result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
     435         [ #  # ]:          0 :         if (PTR_ERR(result) == -ENOMEM)
     436                 :            :                 return ERR_CAST(result);
     437   [ #  #  #  # ]:          0 :         if (IS_ERR_OR_NULL(result))
     438                 :            :                 return ERR_PTR(-ESTALE);
     439                 :            : 
     440                 :            :         /*
     441                 :            :          * If no acceptance criteria was specified by caller, a disconnected
     442                 :            :          * dentry is also accepatable. Callers may use this mode to query if
     443                 :            :          * file handle is stale or to get a reference to an inode without
     444                 :            :          * risking the high overhead caused by directory reconnect.
     445                 :            :          */
     446         [ #  # ]:          0 :         if (!acceptable)
     447                 :            :                 return result;
     448                 :            : 
     449   [ #  #  #  # ]:          0 :         if (d_is_dir(result)) {
     450                 :            :                 /*
     451                 :            :                  * This request is for a directory.
     452                 :            :                  *
     453                 :            :                  * On the positive side there is only one dentry for each
     454                 :            :                  * directory inode.  On the negative side this implies that we
     455                 :            :                  * to ensure our dentry is connected all the way up to the
     456                 :            :                  * filesystem root.
     457                 :            :                  */
     458         [ #  # ]:          0 :                 if (result->d_flags & DCACHE_DISCONNECTED) {
     459                 :          0 :                         err = reconnect_path(mnt, result, nbuf);
     460         [ #  # ]:          0 :                         if (err)
     461                 :          0 :                                 goto err_result;
     462                 :            :                 }
     463                 :            : 
     464         [ #  # ]:          0 :                 if (!acceptable(context, result)) {
     465                 :          0 :                         err = -EACCES;
     466                 :          0 :                         goto err_result;
     467                 :            :                 }
     468                 :            : 
     469                 :            :                 return result;
     470                 :            :         } else {
     471                 :            :                 /*
     472                 :            :                  * It's not a directory.  Life is a little more complicated.
     473                 :            :                  */
     474                 :          0 :                 struct dentry *target_dir, *nresult;
     475                 :            : 
     476                 :            :                 /*
     477                 :            :                  * See if either the dentry we just got from the filesystem
     478                 :            :                  * or any alias for it is acceptable.  This is always true
     479                 :            :                  * if this filesystem is exported without the subtreecheck
     480                 :            :                  * option.  If the filesystem is exported with the subtree
     481                 :            :                  * check option there's a fair chance we need to look at
     482                 :            :                  * the parent directory in the file handle and make sure
     483                 :            :                  * it's connected to the filesystem root.
     484                 :            :                  */
     485                 :          0 :                 alias = find_acceptable_alias(result, acceptable, context);
     486         [ #  # ]:          0 :                 if (alias)
     487                 :            :                         return alias;
     488                 :            : 
     489                 :            :                 /*
     490                 :            :                  * Try to extract a dentry for the parent directory from the
     491                 :            :                  * file handle.  If this fails we'll have to give up.
     492                 :            :                  */
     493                 :          0 :                 err = -ESTALE;
     494         [ #  # ]:          0 :                 if (!nop->fh_to_parent)
     495                 :          0 :                         goto err_result;
     496                 :            : 
     497                 :          0 :                 target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
     498                 :            :                                 fh_len, fileid_type);
     499         [ #  # ]:          0 :                 if (!target_dir)
     500                 :          0 :                         goto err_result;
     501         [ #  # ]:          0 :                 err = PTR_ERR(target_dir);
     502         [ #  # ]:          0 :                 if (IS_ERR(target_dir))
     503                 :          0 :                         goto err_result;
     504                 :            : 
     505                 :            :                 /*
     506                 :            :                  * And as usual we need to make sure the parent directory is
     507                 :            :                  * connected to the filesystem root.  The VFS really doesn't
     508                 :            :                  * like disconnected directories..
     509                 :            :                  */
     510                 :          0 :                 err = reconnect_path(mnt, target_dir, nbuf);
     511         [ #  # ]:          0 :                 if (err) {
     512                 :          0 :                         dput(target_dir);
     513                 :          0 :                         goto err_result;
     514                 :            :                 }
     515                 :            : 
     516                 :            :                 /*
     517                 :            :                  * Now that we've got both a well-connected parent and a
     518                 :            :                  * dentry for the inode we're after, make sure that our
     519                 :            :                  * inode is actually connected to the parent.
     520                 :            :                  */
     521                 :          0 :                 err = exportfs_get_name(mnt, target_dir, nbuf, result);
     522         [ #  # ]:          0 :                 if (err) {
     523                 :          0 :                         dput(target_dir);
     524                 :          0 :                         goto err_result;
     525                 :            :                 }
     526                 :            : 
     527                 :          0 :                 inode_lock(target_dir->d_inode);
     528                 :          0 :                 nresult = lookup_one_len(nbuf, target_dir, strlen(nbuf));
     529         [ #  # ]:          0 :                 if (!IS_ERR(nresult)) {
     530         [ #  # ]:          0 :                         if (unlikely(nresult->d_inode != result->d_inode)) {
     531                 :          0 :                                 dput(nresult);
     532                 :          0 :                                 nresult = ERR_PTR(-ESTALE);
     533                 :            :                         }
     534                 :            :                 }
     535                 :          0 :                 inode_unlock(target_dir->d_inode);
     536                 :            :                 /*
     537                 :            :                  * At this point we are done with the parent, but it's pinned
     538                 :            :                  * by the child dentry anyway.
     539                 :            :                  */
     540                 :          0 :                 dput(target_dir);
     541                 :            : 
     542         [ #  # ]:          0 :                 if (IS_ERR(nresult)) {
     543                 :          0 :                         err = PTR_ERR(nresult);
     544                 :          0 :                         goto err_result;
     545                 :            :                 }
     546                 :          0 :                 dput(result);
     547                 :          0 :                 result = nresult;
     548                 :            : 
     549                 :            :                 /*
     550                 :            :                  * And finally make sure the dentry is actually acceptable
     551                 :            :                  * to NFSD.
     552                 :            :                  */
     553                 :          0 :                 alias = find_acceptable_alias(result, acceptable, context);
     554         [ #  # ]:          0 :                 if (!alias) {
     555                 :          0 :                         err = -EACCES;
     556                 :          0 :                         goto err_result;
     557                 :            :                 }
     558                 :            : 
     559                 :            :                 return alias;
     560                 :            :         }
     561                 :            : 
     562                 :          0 :  err_result:
     563                 :          0 :         dput(result);
     564         [ #  # ]:          0 :         if (err != -ENOMEM)
     565                 :          0 :                 err = -ESTALE;
     566                 :          0 :         return ERR_PTR(err);
     567                 :            : }
     568                 :            : EXPORT_SYMBOL_GPL(exportfs_decode_fh);
     569                 :            : 
     570                 :            : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14