LCOV - code coverage report
Current view: top level - fs/exportfs - expfs.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 198 0.0 %
Date: 2023-08-24 13:40:31 Functions: 0 12 0.0 %

          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...) pr_debug(fmt, ##args)
      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             :         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             :         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             :         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             :         struct dentry *parent;
     125             :         struct dentry *tmp;
     126             :         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("get_parent of %lu failed, err %ld\n",
     136             :                         dentry->d_inode->i_ino, PTR_ERR(parent));
     137             :                 return parent;
     138             :         }
     139             : 
     140             :         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             :                 goto out_reconnected;
     145           0 :         if (err)
     146             :                 goto out_err;
     147           0 :         dprintk("%s: found name: %s\n", __func__, nbuf);
     148           0 :         tmp = lookup_one_unlocked(mnt_idmap(mnt), nbuf, parent, strlen(nbuf));
     149           0 :         if (IS_ERR(tmp)) {
     150           0 :                 dprintk("lookup failed: %ld\n", 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             :                 err = -ESTALE;
     167             :                 goto out_err;
     168             :         }
     169             :         return parent;
     170             : 
     171             : out_err:
     172           0 :         dput(parent);
     173           0 :         return ERR_PTR(err);
     174             : 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             :                 return ERR_PTR(-ESTALE);
     191           0 :         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             :         struct dentry *dentry, *parent;
     215             : 
     216             :         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 bool 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             : 
     257           0 :         buf->sequence++;
     258           0 :         if (buf->ino == ino && len <= NAME_MAX) {
     259           0 :                 memcpy(buf->name, name, len);
     260           0 :                 buf->name[len] = '\0';
     261           0 :                 buf->found = 1;
     262           0 :                 return false;   // no more
     263             :         }
     264             :         return true;
     265             : }
     266             : 
     267             : /**
     268             :  * get_name - default export_operations->get_name function
     269             :  * @path:   the directory in which to find a name
     270             :  * @name:   a pointer to a %NAME_MAX+1 char buffer to store the name
     271             :  * @child:  the dentry for the child directory.
     272             :  *
     273             :  * calls readdir on the parent until it finds an entry with
     274             :  * the same inode number as the child, and returns that.
     275             :  */
     276           0 : static int get_name(const struct path *path, char *name, struct dentry *child)
     277             : {
     278           0 :         const struct cred *cred = current_cred();
     279           0 :         struct inode *dir = path->dentry->d_inode;
     280             :         int error;
     281             :         struct file *file;
     282             :         struct kstat stat;
     283           0 :         struct path child_path = {
     284           0 :                 .mnt = path->mnt,
     285             :                 .dentry = child,
     286             :         };
     287           0 :         struct getdents_callback buffer = {
     288             :                 .ctx.actor = filldir_one,
     289             :                 .name = name,
     290             :         };
     291             : 
     292           0 :         error = -ENOTDIR;
     293           0 :         if (!dir || !S_ISDIR(dir->i_mode))
     294             :                 goto out;
     295           0 :         error = -EINVAL;
     296           0 :         if (!dir->i_fop)
     297             :                 goto out;
     298             :         /*
     299             :          * inode->i_ino is unsigned long, kstat->ino is u64, so the
     300             :          * former would be insufficient on 32-bit hosts when the
     301             :          * filesystem supports 64-bit inode numbers.  So we need to
     302             :          * actually call ->getattr, not just read i_ino:
     303             :          */
     304           0 :         error = vfs_getattr_nosec(&child_path, &stat,
     305             :                                   STATX_INO, AT_STATX_SYNC_AS_STAT);
     306           0 :         if (error)
     307             :                 return error;
     308           0 :         buffer.ino = stat.ino;
     309             :         /*
     310             :          * Open the directory ...
     311             :          */
     312           0 :         file = dentry_open(path, O_RDONLY, cred);
     313           0 :         error = PTR_ERR(file);
     314           0 :         if (IS_ERR(file))
     315             :                 goto out;
     316             : 
     317           0 :         error = -EINVAL;
     318           0 :         if (!file->f_op->iterate && !file->f_op->iterate_shared)
     319             :                 goto out_close;
     320             : 
     321           0 :         buffer.sequence = 0;
     322             :         while (1) {
     323           0 :                 int old_seq = buffer.sequence;
     324             : 
     325           0 :                 error = iterate_dir(file, &buffer.ctx);
     326           0 :                 if (buffer.found) {
     327             :                         error = 0;
     328             :                         break;
     329             :                 }
     330             : 
     331           0 :                 if (error < 0)
     332             :                         break;
     333             : 
     334           0 :                 error = -ENOENT;
     335           0 :                 if (old_seq == buffer.sequence)
     336             :                         break;
     337             :         }
     338             : 
     339             : out_close:
     340           0 :         fput(file);
     341             : out:
     342             :         return error;
     343             : }
     344             : 
     345             : /**
     346             :  * export_encode_fh - default export_operations->encode_fh function
     347             :  * @inode:   the object to encode
     348             :  * @fid:     where to store the file handle fragment
     349             :  * @max_len: maximum length to store there
     350             :  * @parent:  parent directory inode, if wanted
     351             :  *
     352             :  * This default encode_fh function assumes that the 32 inode number
     353             :  * is suitable for locating an inode, and that the generation number
     354             :  * can be used to check that it is still valid.  It places them in the
     355             :  * filehandle fragment where export_decode_fh expects to find them.
     356             :  */
     357             : static int export_encode_fh(struct inode *inode, struct fid *fid,
     358             :                 int *max_len, struct inode *parent)
     359             : {
     360           0 :         int len = *max_len;
     361           0 :         int type = FILEID_INO32_GEN;
     362             : 
     363           0 :         if (parent && (len < 4)) {
     364           0 :                 *max_len = 4;
     365             :                 return FILEID_INVALID;
     366           0 :         } else if (len < 2) {
     367           0 :                 *max_len = 2;
     368             :                 return FILEID_INVALID;
     369             :         }
     370             : 
     371           0 :         len = 2;
     372           0 :         fid->i32.ino = inode->i_ino;
     373           0 :         fid->i32.gen = inode->i_generation;
     374           0 :         if (parent) {
     375           0 :                 fid->i32.parent_ino = parent->i_ino;
     376           0 :                 fid->i32.parent_gen = parent->i_generation;
     377           0 :                 len = 4;
     378           0 :                 type = FILEID_INO32_GEN_PARENT;
     379             :         }
     380           0 :         *max_len = len;
     381             :         return type;
     382             : }
     383             : 
     384             : /**
     385             :  * exportfs_encode_inode_fh - encode a file handle from inode
     386             :  * @inode:   the object to encode
     387             :  * @fid:     where to store the file handle fragment
     388             :  * @max_len: maximum length to store there
     389             :  * @flags:   properties of the requested file handle
     390             :  *
     391             :  * Returns an enum fid_type or a negative errno.
     392             :  */
     393           0 : int exportfs_encode_inode_fh(struct inode *inode, struct fid *fid,
     394             :                              int *max_len, struct inode *parent, int flags)
     395             : {
     396           0 :         const struct export_operations *nop = inode->i_sb->s_export_op;
     397             : 
     398             :         /*
     399             :          * If a decodeable file handle was requested, we need to make sure that
     400             :          * filesystem can decode file handles.
     401             :          */
     402           0 :         if (nop && !(flags & EXPORT_FH_FID) && !nop->fh_to_dentry)
     403             :                 return -EOPNOTSUPP;
     404             : 
     405           0 :         if (nop && nop->encode_fh)
     406           0 :                 return nop->encode_fh(inode, fid->raw, max_len, parent);
     407             : 
     408           0 :         return export_encode_fh(inode, fid, max_len, parent);
     409             : }
     410             : EXPORT_SYMBOL_GPL(exportfs_encode_inode_fh);
     411             : 
     412             : /**
     413             :  * exportfs_encode_fh - encode a file handle from dentry
     414             :  * @dentry:  the object to encode
     415             :  * @fid:     where to store the file handle fragment
     416             :  * @max_len: maximum length to store there
     417             :  * @flags:   properties of the requested file handle
     418             :  *
     419             :  * Returns an enum fid_type or a negative errno.
     420             :  */
     421           0 : int exportfs_encode_fh(struct dentry *dentry, struct fid *fid, int *max_len,
     422             :                        int flags)
     423             : {
     424             :         int error;
     425           0 :         struct dentry *p = NULL;
     426           0 :         struct inode *inode = dentry->d_inode, *parent = NULL;
     427             : 
     428           0 :         if ((flags & EXPORT_FH_CONNECTABLE) && !S_ISDIR(inode->i_mode)) {
     429           0 :                 p = dget_parent(dentry);
     430             :                 /*
     431             :                  * note that while p might've ceased to be our parent already,
     432             :                  * it's still pinned by and still positive.
     433             :                  */
     434           0 :                 parent = p->d_inode;
     435             :         }
     436             : 
     437           0 :         error = exportfs_encode_inode_fh(inode, fid, max_len, parent, flags);
     438           0 :         dput(p);
     439             : 
     440           0 :         return error;
     441             : }
     442             : EXPORT_SYMBOL_GPL(exportfs_encode_fh);
     443             : 
     444             : struct dentry *
     445           0 : exportfs_decode_fh_raw(struct vfsmount *mnt, struct fid *fid, int fh_len,
     446             :                        int fileid_type,
     447             :                        int (*acceptable)(void *, struct dentry *),
     448             :                        void *context)
     449             : {
     450           0 :         const struct export_operations *nop = mnt->mnt_sb->s_export_op;
     451             :         struct dentry *result, *alias;
     452             :         char nbuf[NAME_MAX+1];
     453             :         int err;
     454             : 
     455             :         /*
     456             :          * Try to get any dentry for the given file handle from the filesystem.
     457             :          */
     458           0 :         if (!nop || !nop->fh_to_dentry)
     459             :                 return ERR_PTR(-ESTALE);
     460           0 :         result = nop->fh_to_dentry(mnt->mnt_sb, fid, fh_len, fileid_type);
     461           0 :         if (IS_ERR_OR_NULL(result))
     462             :                 return result;
     463             : 
     464             :         /*
     465             :          * If no acceptance criteria was specified by caller, a disconnected
     466             :          * dentry is also accepatable. Callers may use this mode to query if
     467             :          * file handle is stale or to get a reference to an inode without
     468             :          * risking the high overhead caused by directory reconnect.
     469             :          */
     470           0 :         if (!acceptable)
     471             :                 return result;
     472             : 
     473           0 :         if (d_is_dir(result)) {
     474             :                 /*
     475             :                  * This request is for a directory.
     476             :                  *
     477             :                  * On the positive side there is only one dentry for each
     478             :                  * directory inode.  On the negative side this implies that we
     479             :                  * to ensure our dentry is connected all the way up to the
     480             :                  * filesystem root.
     481             :                  */
     482           0 :                 if (result->d_flags & DCACHE_DISCONNECTED) {
     483           0 :                         err = reconnect_path(mnt, result, nbuf);
     484           0 :                         if (err)
     485             :                                 goto err_result;
     486             :                 }
     487             : 
     488           0 :                 if (!acceptable(context, result)) {
     489             :                         err = -EACCES;
     490             :                         goto err_result;
     491             :                 }
     492             : 
     493             :                 return result;
     494             :         } else {
     495             :                 /*
     496             :                  * It's not a directory.  Life is a little more complicated.
     497             :                  */
     498             :                 struct dentry *target_dir, *nresult;
     499             : 
     500             :                 /*
     501             :                  * See if either the dentry we just got from the filesystem
     502             :                  * or any alias for it is acceptable.  This is always true
     503             :                  * if this filesystem is exported without the subtreecheck
     504             :                  * option.  If the filesystem is exported with the subtree
     505             :                  * check option there's a fair chance we need to look at
     506             :                  * the parent directory in the file handle and make sure
     507             :                  * it's connected to the filesystem root.
     508             :                  */
     509           0 :                 alias = find_acceptable_alias(result, acceptable, context);
     510           0 :                 if (alias)
     511             :                         return alias;
     512             : 
     513             :                 /*
     514             :                  * Try to extract a dentry for the parent directory from the
     515             :                  * file handle.  If this fails we'll have to give up.
     516             :                  */
     517           0 :                 err = -ESTALE;
     518           0 :                 if (!nop->fh_to_parent)
     519             :                         goto err_result;
     520             : 
     521           0 :                 target_dir = nop->fh_to_parent(mnt->mnt_sb, fid,
     522             :                                 fh_len, fileid_type);
     523           0 :                 if (!target_dir)
     524             :                         goto err_result;
     525           0 :                 err = PTR_ERR(target_dir);
     526           0 :                 if (IS_ERR(target_dir))
     527             :                         goto err_result;
     528             : 
     529             :                 /*
     530             :                  * And as usual we need to make sure the parent directory is
     531             :                  * connected to the filesystem root.  The VFS really doesn't
     532             :                  * like disconnected directories..
     533             :                  */
     534           0 :                 err = reconnect_path(mnt, target_dir, nbuf);
     535           0 :                 if (err) {
     536           0 :                         dput(target_dir);
     537           0 :                         goto err_result;
     538             :                 }
     539             : 
     540             :                 /*
     541             :                  * Now that we've got both a well-connected parent and a
     542             :                  * dentry for the inode we're after, make sure that our
     543             :                  * inode is actually connected to the parent.
     544             :                  */
     545           0 :                 err = exportfs_get_name(mnt, target_dir, nbuf, result);
     546           0 :                 if (err) {
     547           0 :                         dput(target_dir);
     548           0 :                         goto err_result;
     549             :                 }
     550             : 
     551           0 :                 inode_lock(target_dir->d_inode);
     552           0 :                 nresult = lookup_one(mnt_idmap(mnt), nbuf,
     553           0 :                                      target_dir, strlen(nbuf));
     554           0 :                 if (!IS_ERR(nresult)) {
     555           0 :                         if (unlikely(nresult->d_inode != result->d_inode)) {
     556           0 :                                 dput(nresult);
     557           0 :                                 nresult = ERR_PTR(-ESTALE);
     558             :                         }
     559             :                 }
     560           0 :                 inode_unlock(target_dir->d_inode);
     561             :                 /*
     562             :                  * At this point we are done with the parent, but it's pinned
     563             :                  * by the child dentry anyway.
     564             :                  */
     565           0 :                 dput(target_dir);
     566             : 
     567           0 :                 if (IS_ERR(nresult)) {
     568           0 :                         err = PTR_ERR(nresult);
     569           0 :                         goto err_result;
     570             :                 }
     571           0 :                 dput(result);
     572           0 :                 result = nresult;
     573             : 
     574             :                 /*
     575             :                  * And finally make sure the dentry is actually acceptable
     576             :                  * to NFSD.
     577             :                  */
     578           0 :                 alias = find_acceptable_alias(result, acceptable, context);
     579           0 :                 if (!alias) {
     580             :                         err = -EACCES;
     581             :                         goto err_result;
     582             :                 }
     583             : 
     584             :                 return alias;
     585             :         }
     586             : 
     587             :  err_result:
     588           0 :         dput(result);
     589           0 :         return ERR_PTR(err);
     590             : }
     591             : EXPORT_SYMBOL_GPL(exportfs_decode_fh_raw);
     592             : 
     593           0 : struct dentry *exportfs_decode_fh(struct vfsmount *mnt, struct fid *fid,
     594             :                                   int fh_len, int fileid_type,
     595             :                                   int (*acceptable)(void *, struct dentry *),
     596             :                                   void *context)
     597             : {
     598             :         struct dentry *ret;
     599             : 
     600           0 :         ret = exportfs_decode_fh_raw(mnt, fid, fh_len, fileid_type,
     601             :                                      acceptable, context);
     602           0 :         if (IS_ERR_OR_NULL(ret)) {
     603           0 :                 if (ret == ERR_PTR(-ENOMEM))
     604             :                         return ret;
     605           0 :                 return ERR_PTR(-ESTALE);
     606             :         }
     607             :         return ret;
     608             : }
     609             : EXPORT_SYMBOL_GPL(exportfs_decode_fh);
     610             : 
     611             : MODULE_LICENSE("GPL");

Generated by: LCOV version 1.14