diff options
author | Paul Mundt <lethal@linux-sh.org> | 2011-01-13 01:06:28 -0500 |
---|---|---|
committer | Paul Mundt <lethal@linux-sh.org> | 2011-01-13 01:06:28 -0500 |
commit | f43dc23d5ea91fca257be02138a255f02d98e806 (patch) | |
tree | b29722f6e965316e90ac97abf79923ced250dc21 /fs/nfs/getroot.c | |
parent | f8e53553f452dcbf67cb89c8cba63a1cd6eb4cc0 (diff) | |
parent | 4162cf64973df51fc885825bc9ca4d055891c49f (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.c | 201 |
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); | ||
125 | out: | ||
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 | /* | 132 | int 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 | */ | ||
133 | int 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 | |||
172 | next_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 | |||
187 | eat_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)); | 166 | out: |
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 | |||
231 | path_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: | |||
240 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | 175 | struct 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 | ||
233 | out: | ||
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 */ |