Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
54ceac45 DH |
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) | |
54ceac45 DH |
6 | */ |
7 | ||
54ceac45 DH |
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> | |
54ceac45 | 22 | #include <linux/lockd/bind.h> |
54ceac45 DH |
23 | #include <linux/seq_file.h> |
24 | #include <linux/mount.h> | |
54ceac45 DH |
25 | #include <linux/vfs.h> |
26 | #include <linux/namei.h> | |
738a3519 | 27 | #include <linux/security.h> |
54ceac45 | 28 | |
7c0f6ba6 | 29 | #include <linux/uaccess.h> |
54ceac45 | 30 | |
4e437e95 SK |
31 | #include "internal.h" |
32 | ||
54ceac45 | 33 | #define NFSDBG_FACILITY NFSDBG_CLIENT |
54ceac45 | 34 | |
b09b9417 TM |
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) { | |
48fde701 AV |
43 | sb->s_root = d_make_root(inode); |
44 | if (sb->s_root == NULL) | |
b09b9417 | 45 | return -ENOMEM; |
7de9c6ee | 46 | ihold(inode); |
a10db50a TM |
47 | /* |
48 | * Ensure that this dentry is invisible to d_find_alias(). | |
49 | * Otherwise, it may be spliced into the tree by | |
41d28bca | 50 | * d_splice_alias if a parent directory from the same |
a10db50a TM |
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 | */ | |
2b0143b5 | 55 | spin_lock(&d_inode(sb->s_root)->i_lock); |
b23fb0a6 | 56 | spin_lock(&sb->s_root->d_lock); |
946e51f2 | 57 | hlist_del_init(&sb->s_root->d_u.d_alias); |
b23fb0a6 | 58 | spin_unlock(&sb->s_root->d_lock); |
2b0143b5 | 59 | spin_unlock(&d_inode(sb->s_root)->i_lock); |
b09b9417 TM |
60 | } |
61 | return 0; | |
62 | } | |
63 | ||
54ceac45 DH |
64 | /* |
65 | * get an NFS2/NFS3 root dentry from the root filehandle | |
66 | */ | |
0d5839ad AV |
67 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, |
68 | const char *devname) | |
54ceac45 DH |
69 | { |
70 | struct nfs_server *server = NFS_SB(sb); | |
71 | struct nfs_fsinfo fsinfo; | |
8bac9db9 | 72 | struct dentry *ret; |
54ceac45 | 73 | struct inode *inode; |
b1942c5f | 74 | void *name = kstrdup(devname, GFP_KERNEL); |
54ceac45 DH |
75 | int error; |
76 | ||
b1942c5f AV |
77 | if (!name) |
78 | return ERR_PTR(-ENOMEM); | |
79 | ||
54ceac45 | 80 | /* get the actual root for this mount */ |
8bac9db9 | 81 | fsinfo.fattr = nfs_alloc_fattr(); |
b1942c5f AV |
82 | if (fsinfo.fattr == NULL) { |
83 | kfree(name); | |
8bac9db9 | 84 | return ERR_PTR(-ENOMEM); |
b1942c5f | 85 | } |
54ceac45 DH |
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); | |
8bac9db9 TM |
90 | ret = ERR_PTR(error); |
91 | goto out; | |
54ceac45 DH |
92 | } |
93 | ||
1775fd3e | 94 | inode = nfs_fhget(sb, mntfh, fsinfo.fattr, NULL); |
54ceac45 DH |
95 | if (IS_ERR(inode)) { |
96 | dprintk("nfs_get_root: get root inode failed\n"); | |
8bac9db9 TM |
97 | ret = ERR_CAST(inode); |
98 | goto out; | |
54ceac45 DH |
99 | } |
100 | ||
b09b9417 | 101 | error = nfs_superblock_set_dummy_root(sb, inode); |
8bac9db9 TM |
102 | if (error != 0) { |
103 | ret = ERR_PTR(error); | |
104 | goto out; | |
105 | } | |
b09b9417 | 106 | |
54ceac45 DH |
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 | */ | |
1a0a397e | 111 | ret = d_obtain_root(inode); |
8bac9db9 | 112 | if (IS_ERR(ret)) { |
54ceac45 | 113 | dprintk("nfs_get_root: get root dentry failed\n"); |
8bac9db9 | 114 | goto out; |
54ceac45 DH |
115 | } |
116 | ||
8bac9db9 | 117 | security_d_instantiate(ret, inode); |
b1942c5f | 118 | spin_lock(&ret->d_lock); |
4dfc7fdb KM |
119 | if (IS_ROOT(ret) && !ret->d_fsdata && |
120 | !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { | |
b1942c5f AV |
121 | ret->d_fsdata = name; |
122 | name = NULL; | |
123 | } | |
124 | spin_unlock(&ret->d_lock); | |
8bac9db9 | 125 | out: |
96aa1549 | 126 | kfree(name); |
8bac9db9 TM |
127 | nfs_free_fattr(fsinfo.fattr); |
128 | return ret; | |
54ceac45 | 129 | } |