Blame view
fs/nfs/getroot.c
6.59 KB
54ceac451 NFS: Share NFS su... |
1 2 3 4 5 6 7 8 9 10 |
/* getroot.c: get the root dentry for an NFS mount * * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ |
54ceac451 NFS: Share NFS su... |
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <linux/module.h> #include <linux/init.h> #include <linux/time.h> #include <linux/kernel.h> #include <linux/mm.h> #include <linux/string.h> #include <linux/stat.h> #include <linux/errno.h> #include <linux/unistd.h> #include <linux/sunrpc/clnt.h> #include <linux/sunrpc/stats.h> #include <linux/nfs_fs.h> #include <linux/nfs_mount.h> #include <linux/nfs4_mount.h> #include <linux/lockd/bind.h> |
54ceac451 NFS: Share NFS su... |
27 28 29 30 31 |
#include <linux/seq_file.h> #include <linux/mount.h> #include <linux/nfs_idmap.h> #include <linux/vfs.h> #include <linux/namei.h> |
738a35195 NFS: Secure the r... |
32 |
#include <linux/security.h> |
54ceac451 NFS: Share NFS su... |
33 34 35 36 37 38 39 40 41 |
#include <asm/system.h> #include <asm/uaccess.h> #include "nfs4_fs.h" #include "delegation.h" #include "internal.h" #define NFSDBG_FACILITY NFSDBG_CLIENT |
54ceac451 NFS: Share NFS su... |
42 43 |
/* |
b09b9417d NFS: Fix the usta... |
44 45 46 47 48 49 50 51 52 53 54 55 |
* Set the superblock root dentry. * Note that this function frees the inode in case of error. */ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *inode) { /* The mntroot acts as the dummy root dentry for this superblock */ if (sb->s_root == NULL) { sb->s_root = d_alloc_root(inode); if (sb->s_root == NULL) { iput(inode); return -ENOMEM; } |
7de9c6ee3 new helper: ihold() |
56 |
ihold(inode); |
a10db50a4 NFS: Fix an Oops ... |
57 58 59 60 61 62 63 64 |
/* * Ensure that this dentry is invisible to d_find_alias(). * Otherwise, it may be spliced into the tree by * d_materialise_unique if a parent directory from the same * filesystem gets mounted at a later time. * This again causes shrink_dcache_for_umount_subtree() to * Oops, since the test for IS_ROOT() will fail. */ |
873feea09 fs: dcache per-in... |
65 |
spin_lock(&sb->s_root->d_inode->i_lock); |
b23fb0a60 fs: scale inode a... |
66 |
spin_lock(&sb->s_root->d_lock); |
a10db50a4 NFS: Fix an Oops ... |
67 |
list_del_init(&sb->s_root->d_alias); |
b23fb0a60 fs: scale inode a... |
68 |
spin_unlock(&sb->s_root->d_lock); |
873feea09 fs: dcache per-in... |
69 |
spin_unlock(&sb->s_root->d_inode->i_lock); |
b09b9417d NFS: Fix the usta... |
70 71 72 73 74 |
} return 0; } /* |
54ceac451 NFS: Share NFS su... |
75 76 |
* get an NFS2/NFS3 root dentry from the root filehandle */ |
0d5839ad0 nfs: propagate de... |
77 78 |
struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, const char *devname) |
54ceac451 NFS: Share NFS su... |
79 80 81 |
{ struct nfs_server *server = NFS_SB(sb); struct nfs_fsinfo fsinfo; |
8bac9db9c NFSv4: Reduce sta... |
82 |
struct dentry *ret; |
54ceac451 NFS: Share NFS su... |
83 |
struct inode *inode; |
b1942c5f8 nfs: store devnam... |
84 |
void *name = kstrdup(devname, GFP_KERNEL); |
54ceac451 NFS: Share NFS su... |
85 |
int error; |
b1942c5f8 nfs: store devnam... |
86 87 |
if (!name) return ERR_PTR(-ENOMEM); |
54ceac451 NFS: Share NFS su... |
88 |
/* get the actual root for this mount */ |
8bac9db9c NFSv4: Reduce sta... |
89 |
fsinfo.fattr = nfs_alloc_fattr(); |
b1942c5f8 nfs: store devnam... |
90 91 |
if (fsinfo.fattr == NULL) { kfree(name); |
8bac9db9c NFSv4: Reduce sta... |
92 |
return ERR_PTR(-ENOMEM); |
b1942c5f8 nfs: store devnam... |
93 |
} |
54ceac451 NFS: Share NFS su... |
94 95 96 97 98 |
error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); if (error < 0) { dprintk("nfs_get_root: getattr error = %d ", -error); |
8bac9db9c NFSv4: Reduce sta... |
99 100 |
ret = ERR_PTR(error); goto out; |
54ceac451 NFS: Share NFS su... |
101 102 103 104 105 106 |
} inode = nfs_fhget(sb, mntfh, fsinfo.fattr); if (IS_ERR(inode)) { dprintk("nfs_get_root: get root inode failed "); |
8bac9db9c NFSv4: Reduce sta... |
107 108 |
ret = ERR_CAST(inode); goto out; |
54ceac451 NFS: Share NFS su... |
109 |
} |
b09b9417d NFS: Fix the usta... |
110 |
error = nfs_superblock_set_dummy_root(sb, inode); |
8bac9db9c NFSv4: Reduce sta... |
111 112 113 114 |
if (error != 0) { ret = ERR_PTR(error); goto out; } |
b09b9417d NFS: Fix the usta... |
115 |
|
54ceac451 NFS: Share NFS su... |
116 117 118 119 |
/* root dentries normally start off anonymous and get spliced in later * if the dentry tree reaches them; however if the dentry already * exists, we'll pick it up at this point and use it as the root */ |
8bac9db9c NFSv4: Reduce sta... |
120 121 |
ret = d_obtain_alias(inode); if (IS_ERR(ret)) { |
54ceac451 NFS: Share NFS su... |
122 123 |
dprintk("nfs_get_root: get root dentry failed "); |
8bac9db9c NFSv4: Reduce sta... |
124 |
goto out; |
54ceac451 NFS: Share NFS su... |
125 |
} |
8bac9db9c NFSv4: Reduce sta... |
126 |
security_d_instantiate(ret, inode); |
b1942c5f8 nfs: store devnam... |
127 128 129 130 131 132 |
spin_lock(&ret->d_lock); if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { ret->d_fsdata = name; name = NULL; } spin_unlock(&ret->d_lock); |
8bac9db9c NFSv4: Reduce sta... |
133 |
out: |
b1942c5f8 nfs: store devnam... |
134 135 |
if (name) kfree(name); |
8bac9db9c NFSv4: Reduce sta... |
136 137 |
nfs_free_fattr(fsinfo.fattr); return ret; |
54ceac451 NFS: Share NFS su... |
138 139 140 |
} #ifdef CONFIG_NFS_V4 |
815409d22 NFSv4: Eliminate ... |
141 |
int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh) |
54ceac451 NFS: Share NFS su... |
142 143 |
{ struct nfs_fsinfo fsinfo; |
815409d22 NFSv4: Eliminate ... |
144 |
int ret = -ENOMEM; |
54ceac451 NFS: Share NFS su... |
145 |
|
815409d22 NFSv4: Eliminate ... |
146 147 |
dprintk("--> nfs4_get_rootfh() "); |
54ceac451 NFS: Share NFS su... |
148 |
|
815409d22 NFSv4: Eliminate ... |
149 150 151 |
fsinfo.fattr = nfs_alloc_fattr(); if (fsinfo.fattr == NULL) goto out; |
54ceac451 NFS: Share NFS su... |
152 153 154 155 |
/* Start by getting the root filehandle from the server */ ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); if (ret < 0) { |
815409d22 NFSv4: Eliminate ... |
156 157 158 |
dprintk("nfs4_get_rootfh: getroot error = %d ", -ret); goto out; |
54ceac451 NFS: Share NFS su... |
159 |
} |
f799bdb35 nfs4 use mandator... |
160 |
if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE) |
815409d22 NFSv4: Eliminate ... |
161 162 |
|| !S_ISDIR(fsinfo.fattr->mode)) { printk(KERN_ERR "nfs4_get_rootfh:" |
54ceac451 NFS: Share NFS su... |
163 164 |
" getroot encountered non-directory "); |
815409d22 NFSv4: Eliminate ... |
165 166 |
ret = -ENOTDIR; goto out; |
54ceac451 NFS: Share NFS su... |
167 |
} |
815409d22 NFSv4: Eliminate ... |
168 169 |
if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { printk(KERN_ERR "nfs4_get_rootfh:" |
54ceac451 NFS: Share NFS su... |
170 171 |
" getroot obtained referral "); |
815409d22 NFSv4: Eliminate ... |
172 173 |
ret = -EREMOTE; goto out; |
54ceac451 NFS: Share NFS su... |
174 |
} |
815409d22 NFSv4: Eliminate ... |
175 176 177 178 179 180 |
memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid)); out: nfs_free_fattr(fsinfo.fattr); dprintk("<-- nfs4_get_rootfh() = %d ", ret); return ret; |
54ceac451 NFS: Share NFS su... |
181 182 183 184 185 |
} /* * get an NFS4 root dentry from the root filehandle */ |
0d5839ad0 nfs: propagate de... |
186 187 |
struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh, const char *devname) |
54ceac451 NFS: Share NFS su... |
188 189 |
{ struct nfs_server *server = NFS_SB(sb); |
8bac9db9c NFSv4: Reduce sta... |
190 191 |
struct nfs_fattr *fattr = NULL; struct dentry *ret; |
54ceac451 NFS: Share NFS su... |
192 |
struct inode *inode; |
b1942c5f8 nfs: store devnam... |
193 |
void *name = kstrdup(devname, GFP_KERNEL); |
54ceac451 NFS: Share NFS su... |
194 195 196 197 |
int error; dprintk("--> nfs4_get_root() "); |
b1942c5f8 nfs: store devnam... |
198 199 |
if (!name) return ERR_PTR(-ENOMEM); |
54ceac451 NFS: Share NFS su... |
200 201 202 203 204 205 |
/* get the info about the server and filesystem */ error = nfs4_server_capabilities(server, mntfh); if (error < 0) { dprintk("nfs_get_root: getcaps error = %d ", -error); |
b1942c5f8 nfs: store devnam... |
206 |
kfree(name); |
54ceac451 NFS: Share NFS su... |
207 208 |
return ERR_PTR(error); } |
8bac9db9c NFSv4: Reduce sta... |
209 |
fattr = nfs_alloc_fattr(); |
b1942c5f8 nfs: store devnam... |
210 211 212 213 |
if (fattr == NULL) { kfree(name); return ERR_PTR(-ENOMEM); } |
8bac9db9c NFSv4: Reduce sta... |
214 |
|
54ceac451 NFS: Share NFS su... |
215 |
/* get the actual root for this mount */ |
8bac9db9c NFSv4: Reduce sta... |
216 |
error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); |
54ceac451 NFS: Share NFS su... |
217 218 219 |
if (error < 0) { dprintk("nfs_get_root: getattr error = %d ", -error); |
8bac9db9c NFSv4: Reduce sta... |
220 221 |
ret = ERR_PTR(error); goto out; |
54ceac451 NFS: Share NFS su... |
222 |
} |
4667058b7 nfs4: Fix NULL de... |
223 224 225 |
if (fattr->valid & NFS_ATTR_FATTR_FSID && !nfs_fsid_equal(&server->fsid, &fattr->fsid)) memcpy(&server->fsid, &fattr->fsid, sizeof(server->fsid)); |
8bac9db9c NFSv4: Reduce sta... |
226 |
inode = nfs_fhget(sb, mntfh, fattr); |
54ceac451 NFS: Share NFS su... |
227 228 229 |
if (IS_ERR(inode)) { dprintk("nfs_get_root: get root inode failed "); |
8bac9db9c NFSv4: Reduce sta... |
230 231 |
ret = ERR_CAST(inode); goto out; |
54ceac451 NFS: Share NFS su... |
232 |
} |
b09b9417d NFS: Fix the usta... |
233 |
error = nfs_superblock_set_dummy_root(sb, inode); |
8bac9db9c NFSv4: Reduce sta... |
234 235 236 237 |
if (error != 0) { ret = ERR_PTR(error); goto out; } |
b09b9417d NFS: Fix the usta... |
238 |
|
54ceac451 NFS: Share NFS su... |
239 240 241 242 |
/* root dentries normally start off anonymous and get spliced in later * if the dentry tree reaches them; however if the dentry already * exists, we'll pick it up at this point and use it as the root */ |
8bac9db9c NFSv4: Reduce sta... |
243 244 |
ret = d_obtain_alias(inode); if (IS_ERR(ret)) { |
54ceac451 NFS: Share NFS su... |
245 246 |
dprintk("nfs_get_root: get root dentry failed "); |
8bac9db9c NFSv4: Reduce sta... |
247 |
goto out; |
54ceac451 NFS: Share NFS su... |
248 |
} |
8bac9db9c NFSv4: Reduce sta... |
249 |
security_d_instantiate(ret, inode); |
b1942c5f8 nfs: store devnam... |
250 251 252 253 254 255 |
spin_lock(&ret->d_lock); if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { ret->d_fsdata = name; name = NULL; } spin_unlock(&ret->d_lock); |
8bac9db9c NFSv4: Reduce sta... |
256 |
out: |
b1942c5f8 nfs: store devnam... |
257 258 |
if (name) kfree(name); |
8bac9db9c NFSv4: Reduce sta... |
259 |
nfs_free_fattr(fattr); |
54ceac451 NFS: Share NFS su... |
260 261 |
dprintk("<-- nfs4_get_root() "); |
8bac9db9c NFSv4: Reduce sta... |
262 |
return ret; |
54ceac451 NFS: Share NFS su... |
263 264 265 |
} #endif /* CONFIG_NFS_V4 */ |