]> git.ipfire.org Git - ipfire-2.x.git/blame - src/patches/suse-2.6.27.39/patches.fixes/nfs-03-NFSv4-Replace-nfs4_path_walk-with-VFS-path-lookup-in-private-namespace
Imported linux-2.6.27.39 suse/xen patches.
[ipfire-2.x.git] / src / patches / suse-2.6.27.39 / patches.fixes / nfs-03-NFSv4-Replace-nfs4_path_walk-with-VFS-path-lookup-in-private-namespace
CommitLineData
2cb7cef9
BS
1From c02d7adf8c5429727a98bad1d039bccad4c61c50 Mon Sep 17 00:00:00 2001
2From: Trond Myklebust <Trond.Myklebust@netapp.com>
3Date: Mon, 22 Jun 2009 15:09:14 -0400
4Subject: [PATCH 3/5] NFSv4: Replace nfs4_path_walk() with VFS path lookup in a private namespace
5
6As noted in the previous patch, the NFSv4 client mount code currently
7has several limitations. If the mount path contains symlinks, or
8referrals, or even if it just contains a '..', then the client code in
9nfs4_path_walk() will fail with an error.
10
11This patch replaces the nfs4_path_walk()-based lookup with a helper
12function that sets up a private namespace to represent the namespace on the
13server, then uses the ordinary VFS and NFS path lookup code to walk down the
14mount path in that namespace.
15
16Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
17Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
18Acked-by: NeilBrown <neilb@suse.de>
19---
20 fs/nfs/super.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++-------
21 1 file changed, 156 insertions(+), 20 deletions(-)
22
23--- linux-2.6.27-SLE11_BRANCH.orig/fs/nfs/super.c
24+++ linux-2.6.27-SLE11_BRANCH/fs/nfs/super.c
25@@ -42,6 +42,8 @@
26 #include <linux/smp_lock.h>
27 #include <linux/seq_file.h>
28 #include <linux/mount.h>
29+#include <linux/mnt_namespace.h>
30+#include <linux/namei.h>
31 #include <linux/nfs_idmap.h>
32 #include <linux/vfs.h>
33 #include <linux/inet.h>
34@@ -244,10 +246,14 @@ static const struct super_operations nfs
35 #ifdef CONFIG_NFS_V4
36 static int nfs4_get_sb(struct file_system_type *fs_type,
37 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
38+static int nfs4_remote_get_sb(struct file_system_type *fs_type,
39+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
40 static int nfs4_xdev_get_sb(struct file_system_type *fs_type,
41 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
42 static int nfs4_referral_get_sb(struct file_system_type *fs_type,
43 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
44+static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
45+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
46 static void nfs4_kill_super(struct super_block *sb);
47
48 static struct file_system_type nfs4_fs_type = {
49@@ -258,6 +264,14 @@ static struct file_system_type nfs4_fs_t
50 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
51 };
52
53+static struct file_system_type nfs4_remote_fs_type = {
54+ .owner = THIS_MODULE,
55+ .name = "nfs4",
56+ .get_sb = nfs4_remote_get_sb,
57+ .kill_sb = nfs4_kill_super,
58+ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
59+};
60+
61 struct file_system_type nfs4_xdev_fs_type = {
62 .owner = THIS_MODULE,
63 .name = "nfs4",
64@@ -266,6 +280,14 @@ struct file_system_type nfs4_xdev_fs_typ
65 .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
66 };
67
68+static struct file_system_type nfs4_remote_referral_fs_type = {
69+ .owner = THIS_MODULE,
70+ .name = "nfs4",
71+ .get_sb = nfs4_remote_referral_get_sb,
72+ .kill_sb = nfs4_kill_super,
73+ .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
74+};
75+
76 struct file_system_type nfs4_referral_fs_type = {
77 .owner = THIS_MODULE,
78 .name = "nfs4",
79@@ -2294,12 +2316,12 @@ out_no_client_address:
80 }
81
82 /*
83- * Get the superblock for an NFS4 mountpoint
84+ * Get the superblock for the NFS4 root partition
85 */
86-static int nfs4_get_sb(struct file_system_type *fs_type,
87+static int nfs4_remote_get_sb(struct file_system_type *fs_type,
88 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
89 {
90- struct nfs_parsed_mount_data *data;
91+ struct nfs_parsed_mount_data *data = raw_data;
92 struct super_block *s;
93 struct nfs_server *server;
94 struct nfs_fh *mntfh;
95@@ -2310,18 +2332,12 @@ static int nfs4_get_sb(struct file_syste
96 };
97 int error = -ENOMEM;
98
99- data = kzalloc(sizeof(*data), GFP_KERNEL);
100 mntfh = kzalloc(sizeof(*mntfh), GFP_KERNEL);
101 if (data == NULL || mntfh == NULL)
102 goto out_free_fh;
103
104 security_init_mnt_opts(&data->lsm_opts);
105
106- /* Validate the mount data */
107- error = nfs4_validate_mount_data(raw_data, data, dev_name);
108- if (error < 0)
109- goto out;
110-
111 /* Get a volume representation */
112 server = nfs4_create_server(data, mntfh);
113 if (IS_ERR(server)) {
114@@ -2334,7 +2350,7 @@ static int nfs4_get_sb(struct file_syste
115 compare_super = NULL;
116
117 /* Get a superblock - note that we may end up sharing one that already exists */
118- s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata);
119+ s = sget(&nfs4_fs_type, compare_super, nfs_set_super, &sb_mntdata);
120 if (IS_ERR(s)) {
121 error = PTR_ERR(s);
122 goto out_free;
123@@ -2370,13 +2386,9 @@ static int nfs4_get_sb(struct file_syste
124 error = 0;
125
126 out:
127- kfree(data->client_address);
128- kfree(data->nfs_server.export_path);
129- kfree(data->nfs_server.hostname);
130 security_free_mnt_opts(&data->lsm_opts);
131 out_free_fh:
132 kfree(mntfh);
133- kfree(data);
134 return error;
135
136 out_free:
137@@ -2391,6 +2403,101 @@ error_splat_super:
138 goto out;
139 }
140
141+static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type,
142+ int flags, void *data, const char *hostname)
143+{
144+ struct vfsmount *root_mnt;
145+ char *root_devname;
146+ size_t len;
147+
148+ len = strlen(hostname) + 3;
149+ root_devname = kmalloc(len, GFP_KERNEL);
150+ if (root_devname == NULL)
151+ return ERR_PTR(-ENOMEM);
152+ snprintf(root_devname, len, "%s:/", hostname);
153+ root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data);
154+ kfree(root_devname);
155+ return root_mnt;
156+}
157+
158+static int nfs_follow_remote_path(struct vfsmount *root_mnt,
159+ const char *export_path, struct vfsmount *mnt_target)
160+{
161+ struct mnt_namespace *ns_private;
162+ struct nameidata nd;
163+ struct super_block *s;
164+ int ret;
165+
166+ ns_private = create_mnt_ns(root_mnt);
167+ ret = PTR_ERR(ns_private);
168+ if (IS_ERR(ns_private))
169+ goto out_mntput;
170+
171+ ret = vfs_path_lookup(root_mnt->mnt_root, root_mnt,
172+ export_path, LOOKUP_FOLLOW, &nd);
173+
174+ put_mnt_ns(ns_private);
175+
176+ if (ret != 0)
177+ goto out_err;
178+
179+ s = nd.path.mnt->mnt_sb;
180+ atomic_inc(&s->s_active);
181+ mnt_target->mnt_sb = s;
182+ mnt_target->mnt_root = dget(nd.path.dentry);
183+
184+ path_put(&nd.path);
185+ down_write(&s->s_umount);
186+ return 0;
187+out_mntput:
188+ mntput(root_mnt);
189+out_err:
190+ return ret;
191+}
192+
193+/*
194+ * Get the superblock for an NFS4 mountpoint
195+ */
196+static int nfs4_get_sb(struct file_system_type *fs_type,
197+ int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
198+{
199+ struct nfs_parsed_mount_data *data;
200+ char *export_path;
201+ struct vfsmount *root_mnt;
202+ int error = -ENOMEM;
203+
204+ data = kzalloc(sizeof(*data), GFP_KERNEL);
205+ if (data == NULL)
206+ goto out_free_data;
207+
208+ /* Validate the mount data */
209+ error = nfs4_validate_mount_data(raw_data, data, dev_name);
210+ if (error < 0)
211+ goto out;
212+
213+ export_path = data->nfs_server.export_path;
214+ data->nfs_server.export_path = "/";
215+ root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, data,
216+ data->nfs_server.hostname);
217+ data->nfs_server.export_path = export_path;
218+
219+ error = PTR_ERR(root_mnt);
220+ if (IS_ERR(root_mnt))
221+ goto out;
222+
223+ error = nfs_follow_remote_path(root_mnt, export_path, mnt);
224+
225+out:
226+ kfree(data->client_address);
227+ kfree(data->nfs_server.export_path);
228+ kfree(data->nfs_server.hostname);
229+out_free_data:
230+ kfree(data);
231+ dprintk("<-- nfs4_get_sb() = %d%s\n", error,
232+ error != 0 ? " [error]" : "");
233+ return error;
234+}
235+
236 static void nfs4_kill_super(struct super_block *sb)
237 {
238 struct nfs_server *server = NFS_SB(sb);
239@@ -2486,12 +2593,9 @@ error_splat_super:
240 return error;
241 }
242
243-/*
244- * Create an NFS4 server record on referral traversal
245- */
246-static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
247- const char *dev_name, void *raw_data,
248- struct vfsmount *mnt)
249+static int nfs4_remote_referral_get_sb(struct file_system_type *fs_type,
250+ int flags, const char *dev_name, void *raw_data,
251+ struct vfsmount *mnt)
252 {
253 struct nfs_clone_mount *data = raw_data;
254 struct super_block *s;
255@@ -2571,4 +2675,36 @@ error_splat_super:
256 return error;
257 }
258
259+/*
260+ * Create an NFS4 server record on referral traversal
261+ */
262+static int nfs4_referral_get_sb(struct file_system_type *fs_type,
263+ int flags, const char *dev_name, void *raw_data,
264+ struct vfsmount *mnt)
265+{
266+ struct nfs_clone_mount *data = raw_data;
267+ char *export_path;
268+ struct vfsmount *root_mnt;
269+ int error;
270+
271+ dprintk("--> nfs4_referral_get_sb()\n");
272+
273+ export_path = data->mnt_path;
274+ data->mnt_path = "/";
275+
276+ root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type,
277+ flags, data, data->hostname);
278+ data->mnt_path = export_path;
279+
280+ error = PTR_ERR(root_mnt);
281+ if (IS_ERR(root_mnt))
282+ goto out;
283+
284+ error = nfs_follow_remote_path(root_mnt, export_path, mnt);
285+out:
286+ dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error,
287+ error != 0 ? " [error]" : "");
288+ return error;
289+}
290+
291 #endif /* CONFIG_NFS_V4 */