root/fs/nfs/getroot.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. nfs_superblock_set_dummy_root
  2. nfs_get_root

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /* getroot.c: get the root dentry for an NFS mount
   3  *
   4  * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
   5  * Written by David Howells (dhowells@redhat.com)
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/init.h>
  10 
  11 #include <linux/time.h>
  12 #include <linux/kernel.h>
  13 #include <linux/mm.h>
  14 #include <linux/string.h>
  15 #include <linux/stat.h>
  16 #include <linux/errno.h>
  17 #include <linux/unistd.h>
  18 #include <linux/sunrpc/clnt.h>
  19 #include <linux/sunrpc/stats.h>
  20 #include <linux/nfs_fs.h>
  21 #include <linux/nfs_mount.h>
  22 #include <linux/lockd/bind.h>
  23 #include <linux/seq_file.h>
  24 #include <linux/mount.h>
  25 #include <linux/vfs.h>
  26 #include <linux/namei.h>
  27 #include <linux/security.h>
  28 
  29 #include <linux/uaccess.h>
  30 
  31 #include "internal.h"
  32 
  33 #define NFSDBG_FACILITY         NFSDBG_CLIENT
  34 
  35 /*
  36  * Set the superblock root dentry.
  37  * Note that this function frees the inode in case of error.
  38  */
  39 static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *inode)
  40 {
  41         /* The mntroot acts as the dummy root dentry for this superblock */
  42         if (sb->s_root == NULL) {
  43                 sb->s_root = d_make_root(inode);
  44                 if (sb->s_root == NULL)
  45                         return -ENOMEM;
  46                 ihold(inode);
  47                 /*
  48                  * Ensure that this dentry is invisible to d_find_alias().
  49                  * Otherwise, it may be spliced into the tree by
  50                  * d_splice_alias if a parent directory from the same
  51                  * filesystem gets mounted at a later time.
  52                  * This again causes shrink_dcache_for_umount_subtree() to
  53                  * Oops, since the test for IS_ROOT() will fail.
  54                  */
  55                 spin_lock(&d_inode(sb->s_root)->i_lock);
  56                 spin_lock(&sb->s_root->d_lock);
  57                 hlist_del_init(&sb->s_root->d_u.d_alias);
  58                 spin_unlock(&sb->s_root->d_lock);
  59                 spin_unlock(&d_inode(sb->s_root)->i_lock);
  60         }
  61         return 0;
  62 }
  63 
  64 /*
  65  * get an NFS2/NFS3 root dentry from the root filehandle
  66  */
  67 struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh,
  68                             const char *devname)
  69 {
  70         struct nfs_server *server = NFS_SB(sb);
  71         struct nfs_fsinfo fsinfo;
  72         struct dentry *ret;
  73         struct inode *inode;
  74         void *name = kstrdup(devname, GFP_KERNEL);
  75         int error;
  76 
  77         if (!name)
  78                 return ERR_PTR(-ENOMEM);
  79 
  80         /* get the actual root for this mount */
  81         fsinfo.fattr = nfs_alloc_fattr();
  82         if (fsinfo.fattr == NULL) {
  83                 kfree(name);
  84                 return ERR_PTR(-ENOMEM);
  85         }
  86 
  87         error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
  88         if (error < 0) {
  89                 dprintk("nfs_get_root: getattr error = %d\n", -error);
  90                 ret = ERR_PTR(error);
  91                 goto out;
  92         }
  93 
  94         inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL);
  95         if (IS_ERR(inode)) {
  96                 dprintk("nfs_get_root: get root inode failed\n");
  97                 ret = ERR_CAST(inode);
  98                 goto out;
  99         }
 100 
 101         error = nfs_superblock_set_dummy_root(sb, inode);
 102         if (error != 0) {
 103                 ret = ERR_PTR(error);
 104                 goto out;
 105         }
 106 
 107         /* root dentries normally start off anonymous and get spliced in later
 108          * if the dentry tree reaches them; however if the dentry already
 109          * exists, we'll pick it up at this point and use it as the root
 110          */
 111         ret = d_obtain_root(inode);
 112         if (IS_ERR(ret)) {
 113                 dprintk("nfs_get_root: get root dentry failed\n");
 114                 goto out;
 115         }
 116 
 117         security_d_instantiate(ret, inode);
 118         spin_lock(&ret->d_lock);
 119         if (IS_ROOT(ret) && !ret->d_fsdata &&
 120             !(ret->d_flags & DCACHE_NFSFS_RENAMED)) {
 121                 ret->d_fsdata = name;
 122                 name = NULL;
 123         }
 124         spin_unlock(&ret->d_lock);
 125 out:
 126         kfree(name);
 127         nfs_free_fattr(fsinfo.fattr);
 128         return ret;
 129 }

/* [<][>][^][v][top][bottom][index][help] */