aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/getroot.c
diff options
context:
space:
mode:
authorPaul Mundt <lethal@linux-sh.org>2011-01-13 01:06:28 -0500
committerPaul Mundt <lethal@linux-sh.org>2011-01-13 01:06:28 -0500
commitf43dc23d5ea91fca257be02138a255f02d98e806 (patch)
treeb29722f6e965316e90ac97abf79923ced250dc21 /fs/nfs/getroot.c
parentf8e53553f452dcbf67cb89c8cba63a1cd6eb4cc0 (diff)
parent4162cf64973df51fc885825bc9ca4d055891c49f (diff)
Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/torvalds/linux-2.6 into common/serial-rework
Conflicts: arch/sh/kernel/cpu/sh2/setup-sh7619.c arch/sh/kernel/cpu/sh2a/setup-mxg.c arch/sh/kernel/cpu/sh2a/setup-sh7201.c arch/sh/kernel/cpu/sh2a/setup-sh7203.c arch/sh/kernel/cpu/sh2a/setup-sh7206.c arch/sh/kernel/cpu/sh3/setup-sh7705.c arch/sh/kernel/cpu/sh3/setup-sh770x.c arch/sh/kernel/cpu/sh3/setup-sh7710.c arch/sh/kernel/cpu/sh3/setup-sh7720.c arch/sh/kernel/cpu/sh4/setup-sh4-202.c arch/sh/kernel/cpu/sh4/setup-sh7750.c arch/sh/kernel/cpu/sh4/setup-sh7760.c arch/sh/kernel/cpu/sh4a/setup-sh7343.c arch/sh/kernel/cpu/sh4a/setup-sh7366.c arch/sh/kernel/cpu/sh4a/setup-sh7722.c arch/sh/kernel/cpu/sh4a/setup-sh7723.c arch/sh/kernel/cpu/sh4a/setup-sh7724.c arch/sh/kernel/cpu/sh4a/setup-sh7763.c arch/sh/kernel/cpu/sh4a/setup-sh7770.c arch/sh/kernel/cpu/sh4a/setup-sh7780.c arch/sh/kernel/cpu/sh4a/setup-sh7785.c arch/sh/kernel/cpu/sh4a/setup-sh7786.c arch/sh/kernel/cpu/sh4a/setup-shx3.c arch/sh/kernel/cpu/sh5/setup-sh5.c drivers/serial/sh-sci.c drivers/serial/sh-sci.h include/linux/serial_sci.h
Diffstat (limited to 'fs/nfs/getroot.c')
-rw-r--r--fs/nfs/getroot.c201
1 files changed, 73 insertions, 128 deletions
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 46177cb87064..5596c6a2881e 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -30,7 +30,6 @@
30#include <linux/nfs_idmap.h> 30#include <linux/nfs_idmap.h>
31#include <linux/vfs.h> 31#include <linux/vfs.h>
32#include <linux/namei.h> 32#include <linux/namei.h>
33#include <linux/mnt_namespace.h>
34#include <linux/security.h> 33#include <linux/security.h>
35 34
36#include <asm/system.h> 35#include <asm/system.h>
@@ -55,8 +54,7 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
55 iput(inode); 54 iput(inode);
56 return -ENOMEM; 55 return -ENOMEM;
57 } 56 }
58 /* Circumvent igrab(): we know the inode is not being freed */ 57 ihold(inode);
59 atomic_inc(&inode->i_count);
60 /* 58 /*
61 * Ensure that this dentry is invisible to d_find_alias(). 59 * Ensure that this dentry is invisible to d_find_alias().
62 * Otherwise, it may be spliced into the tree by 60 * Otherwise, it may be spliced into the tree by
@@ -65,9 +63,11 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
65 * This again causes shrink_dcache_for_umount_subtree() to 63 * This again causes shrink_dcache_for_umount_subtree() to
66 * Oops, since the test for IS_ROOT() will fail. 64 * Oops, since the test for IS_ROOT() will fail.
67 */ 65 */
68 spin_lock(&dcache_lock); 66 spin_lock(&sb->s_root->d_inode->i_lock);
67 spin_lock(&sb->s_root->d_lock);
69 list_del_init(&sb->s_root->d_alias); 68 list_del_init(&sb->s_root->d_alias);
70 spin_unlock(&dcache_lock); 69 spin_unlock(&sb->s_root->d_lock);
70 spin_unlock(&sb->s_root->d_inode->i_lock);
71 } 71 }
72 return 0; 72 return 0;
73} 73}
@@ -79,159 +79,94 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
79{ 79{
80 struct nfs_server *server = NFS_SB(sb); 80 struct nfs_server *server = NFS_SB(sb);
81 struct nfs_fsinfo fsinfo; 81 struct nfs_fsinfo fsinfo;
82 struct nfs_fattr fattr; 82 struct dentry *ret;
83 struct dentry *mntroot;
84 struct inode *inode; 83 struct inode *inode;
85 int error; 84 int error;
86 85
87 /* get the actual root for this mount */ 86 /* get the actual root for this mount */
88 fsinfo.fattr = &fattr; 87 fsinfo.fattr = nfs_alloc_fattr();
88 if (fsinfo.fattr == NULL)
89 return ERR_PTR(-ENOMEM);
89 90
90 error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); 91 error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
91 if (error < 0) { 92 if (error < 0) {
92 dprintk("nfs_get_root: getattr error = %d\n", -error); 93 dprintk("nfs_get_root: getattr error = %d\n", -error);
93 return ERR_PTR(error); 94 ret = ERR_PTR(error);
95 goto out;
94 } 96 }
95 97
96 inode = nfs_fhget(sb, mntfh, fsinfo.fattr); 98 inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
97 if (IS_ERR(inode)) { 99 if (IS_ERR(inode)) {
98 dprintk("nfs_get_root: get root inode failed\n"); 100 dprintk("nfs_get_root: get root inode failed\n");
99 return ERR_CAST(inode); 101 ret = ERR_CAST(inode);
102 goto out;
100 } 103 }
101 104
102 error = nfs_superblock_set_dummy_root(sb, inode); 105 error = nfs_superblock_set_dummy_root(sb, inode);
103 if (error != 0) 106 if (error != 0) {
104 return ERR_PTR(error); 107 ret = ERR_PTR(error);
108 goto out;
109 }
105 110
106 /* root dentries normally start off anonymous and get spliced in later 111 /* root dentries normally start off anonymous and get spliced in later
107 * if the dentry tree reaches them; however if the dentry already 112 * if the dentry tree reaches them; however if the dentry already
108 * exists, we'll pick it up at this point and use it as the root 113 * exists, we'll pick it up at this point and use it as the root
109 */ 114 */
110 mntroot = d_obtain_alias(inode); 115 ret = d_obtain_alias(inode);
111 if (IS_ERR(mntroot)) { 116 if (IS_ERR(ret)) {
112 dprintk("nfs_get_root: get root dentry failed\n"); 117 dprintk("nfs_get_root: get root dentry failed\n");
113 return mntroot; 118 goto out;
114 } 119 }
115 120
116 security_d_instantiate(mntroot, inode); 121 security_d_instantiate(ret, inode);
117
118 if (!mntroot->d_op)
119 mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
120 122
121 return mntroot; 123 if (ret->d_op == NULL)
124 d_set_d_op(ret, server->nfs_client->rpc_ops->dentry_ops);
125out:
126 nfs_free_fattr(fsinfo.fattr);
127 return ret;
122} 128}
123 129
124#ifdef CONFIG_NFS_V4 130#ifdef CONFIG_NFS_V4
125 131
126/* 132int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh)
127 * Do a simple pathwalk from the root FH of the server to the nominated target
128 * of the mountpoint
129 * - give error on symlinks
130 * - give error on ".." occurring in the path
131 * - follow traversals
132 */
133int nfs4_path_walk(struct nfs_server *server,
134 struct nfs_fh *mntfh,
135 const char *path)
136{ 133{
137 struct nfs_fsinfo fsinfo; 134 struct nfs_fsinfo fsinfo;
138 struct nfs_fattr fattr; 135 int ret = -ENOMEM;
139 struct nfs_fh lastfh;
140 struct qstr name;
141 int ret;
142 136
143 dprintk("--> nfs4_path_walk(,,%s)\n", path); 137 dprintk("--> nfs4_get_rootfh()\n");
144 138
145 fsinfo.fattr = &fattr; 139 fsinfo.fattr = nfs_alloc_fattr();
146 nfs_fattr_init(&fattr); 140 if (fsinfo.fattr == NULL)
147 141 goto out;
148 /* Eat leading slashes */
149 while (*path == '/')
150 path++;
151 142
152 /* Start by getting the root filehandle from the server */ 143 /* Start by getting the root filehandle from the server */
153 ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); 144 ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
154 if (ret < 0) { 145 if (ret < 0) {
155 dprintk("nfs4_get_root: getroot error = %d\n", -ret); 146 dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret);
156 return ret; 147 goto out;
157 } 148 }
158 149
159 if (!S_ISDIR(fattr.mode)) { 150 if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_TYPE)
160 printk(KERN_ERR "nfs4_get_root:" 151 || !S_ISDIR(fsinfo.fattr->mode)) {
152 printk(KERN_ERR "nfs4_get_rootfh:"
161 " getroot encountered non-directory\n"); 153 " getroot encountered non-directory\n");
162 return -ENOTDIR; 154 ret = -ENOTDIR;
155 goto out;
163 } 156 }
164 157
165 /* FIXME: It is quite valid for the server to return a referral here */ 158 if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) {
166 if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { 159 printk(KERN_ERR "nfs4_get_rootfh:"
167 printk(KERN_ERR "nfs4_get_root:"
168 " getroot obtained referral\n"); 160 " getroot obtained referral\n");
169 return -EREMOTE; 161 ret = -EREMOTE;
170 } 162 goto out;
171
172next_component:
173 dprintk("Next: %s\n", path);
174
175 /* extract the next bit of the path */
176 if (!*path)
177 goto path_walk_complete;
178
179 name.name = path;
180 while (*path && *path != '/')
181 path++;
182 name.len = path - (const char *) name.name;
183
184 if (name.len > NFS4_MAXNAMLEN)
185 return -ENAMETOOLONG;
186
187eat_dot_dir:
188 while (*path == '/')
189 path++;
190
191 if (path[0] == '.' && (path[1] == '/' || !path[1])) {
192 path += 2;
193 goto eat_dot_dir;
194 }
195
196 /* FIXME: Why shouldn't the user be able to use ".." in the path? */
197 if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2])
198 ) {
199 printk(KERN_ERR "nfs4_get_root:"
200 " Mount path contains reference to \"..\"\n");
201 return -EINVAL;
202 } 163 }
203 164
204 /* lookup the next FH in the sequence */ 165 memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid));
205 memcpy(&lastfh, mntfh, sizeof(lastfh)); 166out:
206 167 nfs_free_fattr(fsinfo.fattr);
207 dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path); 168 dprintk("<-- nfs4_get_rootfh() = %d\n", ret);
208 169 return ret;
209 ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name,
210 mntfh, &fattr);
211 if (ret < 0) {
212 dprintk("nfs4_get_root: getroot error = %d\n", -ret);
213 return ret;
214 }
215
216 if (!S_ISDIR(fattr.mode)) {
217 printk(KERN_ERR "nfs4_get_root:"
218 " lookupfh encountered non-directory\n");
219 return -ENOTDIR;
220 }
221
222 /* FIXME: Referrals are quite valid here too */
223 if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
224 printk(KERN_ERR "nfs4_get_root:"
225 " lookupfh obtained referral\n");
226 return -EREMOTE;
227 }
228
229 goto next_component;
230
231path_walk_complete:
232 memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
233 dprintk("<-- nfs4_path_walk() = 0\n");
234 return 0;
235} 170}
236 171
237/* 172/*
@@ -240,8 +175,8 @@ path_walk_complete:
240struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) 175struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
241{ 176{
242 struct nfs_server *server = NFS_SB(sb); 177 struct nfs_server *server = NFS_SB(sb);
243 struct nfs_fattr fattr; 178 struct nfs_fattr *fattr = NULL;
244 struct dentry *mntroot; 179 struct dentry *ret;
245 struct inode *inode; 180 struct inode *inode;
246 int error; 181 int error;
247 182
@@ -255,40 +190,50 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
255 return ERR_PTR(error); 190 return ERR_PTR(error);
256 } 191 }
257 192
193 fattr = nfs_alloc_fattr();
194 if (fattr == NULL)
195 return ERR_PTR(-ENOMEM);;
196
258 /* get the actual root for this mount */ 197 /* get the actual root for this mount */
259 error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr); 198 error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr);
260 if (error < 0) { 199 if (error < 0) {
261 dprintk("nfs_get_root: getattr error = %d\n", -error); 200 dprintk("nfs_get_root: getattr error = %d\n", -error);
262 return ERR_PTR(error); 201 ret = ERR_PTR(error);
202 goto out;
263 } 203 }
264 204
265 inode = nfs_fhget(sb, mntfh, &fattr); 205 inode = nfs_fhget(sb, mntfh, fattr);
266 if (IS_ERR(inode)) { 206 if (IS_ERR(inode)) {
267 dprintk("nfs_get_root: get root inode failed\n"); 207 dprintk("nfs_get_root: get root inode failed\n");
268 return ERR_CAST(inode); 208 ret = ERR_CAST(inode);
209 goto out;
269 } 210 }
270 211
271 error = nfs_superblock_set_dummy_root(sb, inode); 212 error = nfs_superblock_set_dummy_root(sb, inode);
272 if (error != 0) 213 if (error != 0) {
273 return ERR_PTR(error); 214 ret = ERR_PTR(error);
215 goto out;
216 }
274 217
275 /* root dentries normally start off anonymous and get spliced in later 218 /* root dentries normally start off anonymous and get spliced in later
276 * if the dentry tree reaches them; however if the dentry already 219 * if the dentry tree reaches them; however if the dentry already
277 * exists, we'll pick it up at this point and use it as the root 220 * exists, we'll pick it up at this point and use it as the root
278 */ 221 */
279 mntroot = d_obtain_alias(inode); 222 ret = d_obtain_alias(inode);
280 if (IS_ERR(mntroot)) { 223 if (IS_ERR(ret)) {
281 dprintk("nfs_get_root: get root dentry failed\n"); 224 dprintk("nfs_get_root: get root dentry failed\n");
282 return mntroot; 225 goto out;
283 } 226 }
284 227
285 security_d_instantiate(mntroot, inode); 228 security_d_instantiate(ret, inode);
286 229
287 if (!mntroot->d_op) 230 if (ret->d_op == NULL)
288 mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops; 231 d_set_d_op(ret, server->nfs_client->rpc_ops->dentry_ops);
289 232
233out:
234 nfs_free_fattr(fattr);
290 dprintk("<-- nfs4_get_root()\n"); 235 dprintk("<-- nfs4_get_root()\n");
291 return mntroot; 236 return ret;
292} 237}
293 238
294#endif /* CONFIG_NFS_V4 */ 239#endif /* CONFIG_NFS_V4 */