blob: 85583414a3ca2cfbd85053f6aec4eadce9b490bd [file] [log] [blame]
David Howellsf7b422b2006-06-09 09:34:33 -04001/*
2 * linux/fs/nfs/super.c
3 *
4 * Copyright (C) 1992 Rick Sladkey
5 *
6 * nfs superblock handling functions
7 *
8 * Modularised by Alan Cox <Alan.Cox@linux.org>, while hacking some
9 * experimental NFS changes. Modularisation taken straight from SYS5 fs.
10 *
11 * Change to nfs_read_super() to permit NFS mounts to multi-homed hosts.
12 * J.S.Peatfield@damtp.cam.ac.uk
13 *
14 * Split from inode.c by David Howells <dhowells@redhat.com>
15 *
16 */
17
18#include <linux/config.h>
19#include <linux/module.h>
20#include <linux/init.h>
21
22#include <linux/time.h>
23#include <linux/kernel.h>
24#include <linux/mm.h>
25#include <linux/string.h>
26#include <linux/stat.h>
27#include <linux/errno.h>
28#include <linux/unistd.h>
29#include <linux/sunrpc/clnt.h>
30#include <linux/sunrpc/stats.h>
31#include <linux/sunrpc/metrics.h>
32#include <linux/nfs_fs.h>
33#include <linux/nfs_mount.h>
34#include <linux/nfs4_mount.h>
35#include <linux/lockd/bind.h>
36#include <linux/smp_lock.h>
37#include <linux/seq_file.h>
38#include <linux/mount.h>
39#include <linux/nfs_idmap.h>
40#include <linux/vfs.h>
41#include <linux/inet.h>
42#include <linux/nfs_xdr.h>
43
44#include <asm/system.h>
45#include <asm/uaccess.h>
46
47#include "nfs4_fs.h"
48#include "callback.h"
49#include "delegation.h"
50#include "iostat.h"
51#include "internal.h"
52
53#define NFSDBG_FACILITY NFSDBG_VFS
54
55/* Maximum number of readahead requests
56 * FIXME: this should really be a sysctl so that users may tune it to suit
57 * their needs. People that do NFS over a slow network, might for
58 * instance want to reduce it to something closer to 1 for improved
59 * interactive response.
60 */
61#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
62
David Howellsf7b422b2006-06-09 09:34:33 -040063static void nfs_umount_begin(struct vfsmount *, int);
Trond Myklebust816724e2006-06-24 08:41:41 -040064static int nfs_statfs(struct dentry *, struct kstatfs *);
David Howellsf7b422b2006-06-09 09:34:33 -040065static int nfs_show_options(struct seq_file *, struct vfsmount *);
66static int nfs_show_stats(struct seq_file *, struct vfsmount *);
Trond Myklebust816724e2006-06-24 08:41:41 -040067static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *);
68static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
69 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
David Howellsf7b422b2006-06-09 09:34:33 -040070static void nfs_kill_super(struct super_block *);
71
72static struct file_system_type nfs_fs_type = {
73 .owner = THIS_MODULE,
74 .name = "nfs",
75 .get_sb = nfs_get_sb,
76 .kill_sb = nfs_kill_super,
77 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
78};
79
80struct file_system_type clone_nfs_fs_type = {
81 .owner = THIS_MODULE,
82 .name = "nfs",
83 .get_sb = nfs_clone_nfs_sb,
84 .kill_sb = nfs_kill_super,
85 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
86};
87
88static struct super_operations nfs_sops = {
89 .alloc_inode = nfs_alloc_inode,
90 .destroy_inode = nfs_destroy_inode,
91 .write_inode = nfs_write_inode,
92 .statfs = nfs_statfs,
93 .clear_inode = nfs_clear_inode,
94 .umount_begin = nfs_umount_begin,
95 .show_options = nfs_show_options,
96 .show_stats = nfs_show_stats,
97};
98
99#ifdef CONFIG_NFS_V4
Trond Myklebust816724e2006-06-24 08:41:41 -0400100static int nfs4_get_sb(struct file_system_type *fs_type,
101 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
102static int nfs_clone_nfs4_sb(struct file_system_type *fs_type,
103 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
104static int nfs_referral_nfs4_sb(struct file_system_type *fs_type,
105 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
David Howellsf7b422b2006-06-09 09:34:33 -0400106static void nfs4_kill_super(struct super_block *sb);
107
108static struct file_system_type nfs4_fs_type = {
109 .owner = THIS_MODULE,
110 .name = "nfs4",
111 .get_sb = nfs4_get_sb,
112 .kill_sb = nfs4_kill_super,
113 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
114};
115
116struct file_system_type clone_nfs4_fs_type = {
117 .owner = THIS_MODULE,
118 .name = "nfs4",
119 .get_sb = nfs_clone_nfs4_sb,
120 .kill_sb = nfs4_kill_super,
121 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
122};
123
124struct file_system_type nfs_referral_nfs4_fs_type = {
125 .owner = THIS_MODULE,
126 .name = "nfs4",
127 .get_sb = nfs_referral_nfs4_sb,
128 .kill_sb = nfs4_kill_super,
129 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
130};
131
132static struct super_operations nfs4_sops = {
133 .alloc_inode = nfs_alloc_inode,
134 .destroy_inode = nfs_destroy_inode,
135 .write_inode = nfs_write_inode,
136 .statfs = nfs_statfs,
137 .clear_inode = nfs4_clear_inode,
138 .umount_begin = nfs_umount_begin,
139 .show_options = nfs_show_options,
140 .show_stats = nfs_show_stats,
141};
142#endif
143
Trond Myklebust979df722006-07-25 11:28:19 -0400144static struct shrinker *acl_shrinker;
145
David Howellsf7b422b2006-06-09 09:34:33 -0400146/*
147 * Register the NFS filesystems
148 */
149int __init register_nfs_fs(void)
150{
151 int ret;
152
153 ret = register_filesystem(&nfs_fs_type);
154 if (ret < 0)
155 goto error_0;
156
157#ifdef CONFIG_NFS_V4
158 ret = nfs_register_sysctl();
159 if (ret < 0)
160 goto error_1;
161 ret = register_filesystem(&nfs4_fs_type);
162 if (ret < 0)
163 goto error_2;
164#endif
Trond Myklebust979df722006-07-25 11:28:19 -0400165 acl_shrinker = set_shrinker(DEFAULT_SEEKS, nfs_access_cache_shrinker);
David Howellsf7b422b2006-06-09 09:34:33 -0400166 return 0;
167
168#ifdef CONFIG_NFS_V4
169error_2:
170 nfs_unregister_sysctl();
171error_1:
172 unregister_filesystem(&nfs_fs_type);
173#endif
174error_0:
175 return ret;
176}
177
178/*
179 * Unregister the NFS filesystems
180 */
181void __exit unregister_nfs_fs(void)
182{
Trond Myklebust979df722006-07-25 11:28:19 -0400183 if (acl_shrinker != NULL)
184 remove_shrinker(acl_shrinker);
David Howellsf7b422b2006-06-09 09:34:33 -0400185#ifdef CONFIG_NFS_V4
186 unregister_filesystem(&nfs4_fs_type);
187 nfs_unregister_sysctl();
188#endif
189 unregister_filesystem(&nfs_fs_type);
190}
191
192/*
193 * Deliver file system statistics to userspace
194 */
Trond Myklebust816724e2006-06-24 08:41:41 -0400195static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf)
David Howellsf7b422b2006-06-09 09:34:33 -0400196{
David Howells0c7d90c2006-08-22 20:06:10 -0400197 struct nfs_server *server = NFS_SB(dentry->d_sb);
David Howellsf7b422b2006-06-09 09:34:33 -0400198 unsigned char blockbits;
199 unsigned long blockres;
David Howells0c7d90c2006-08-22 20:06:10 -0400200 struct nfs_fh *fh = NFS_FH(dentry->d_inode);
David Howellsf7b422b2006-06-09 09:34:33 -0400201 struct nfs_fattr fattr;
202 struct nfs_fsstat res = {
203 .fattr = &fattr,
204 };
205 int error;
206
207 lock_kernel();
208
David Howells8fa5c002006-08-22 20:06:12 -0400209 error = server->nfs_client->rpc_ops->statfs(server, fh, &res);
David Howellsf7b422b2006-06-09 09:34:33 -0400210 buf->f_type = NFS_SUPER_MAGIC;
211 if (error < 0)
212 goto out_err;
213
214 /*
215 * Current versions of glibc do not correctly handle the
216 * case where f_frsize != f_bsize. Eventually we want to
217 * report the value of wtmult in this field.
218 */
David Howells0c7d90c2006-08-22 20:06:10 -0400219 buf->f_frsize = dentry->d_sb->s_blocksize;
David Howellsf7b422b2006-06-09 09:34:33 -0400220
221 /*
222 * On most *nix systems, f_blocks, f_bfree, and f_bavail
223 * are reported in units of f_frsize. Linux hasn't had
224 * an f_frsize field in its statfs struct until recently,
225 * thus historically Linux's sys_statfs reports these
226 * fields in units of f_bsize.
227 */
David Howells0c7d90c2006-08-22 20:06:10 -0400228 buf->f_bsize = dentry->d_sb->s_blocksize;
229 blockbits = dentry->d_sb->s_blocksize_bits;
David Howellsf7b422b2006-06-09 09:34:33 -0400230 blockres = (1 << blockbits) - 1;
231 buf->f_blocks = (res.tbytes + blockres) >> blockbits;
232 buf->f_bfree = (res.fbytes + blockres) >> blockbits;
233 buf->f_bavail = (res.abytes + blockres) >> blockbits;
234
235 buf->f_files = res.tfiles;
236 buf->f_ffree = res.afiles;
237
238 buf->f_namelen = server->namelen;
239 out:
240 unlock_kernel();
241 return 0;
242
243 out_err:
244 dprintk("%s: statfs error = %d\n", __FUNCTION__, -error);
245 buf->f_bsize = buf->f_blocks = buf->f_bfree = buf->f_bavail = -1;
246 goto out;
247
248}
249
David Howells7d4e2742006-08-22 20:06:07 -0400250/*
251 * Map the security flavour number to a name
252 */
Trond Myklebust81039f12006-06-09 09:34:34 -0400253static const char *nfs_pseudoflavour_to_name(rpc_authflavor_t flavour)
254{
David Howells7d4e2742006-08-22 20:06:07 -0400255 static const struct {
Trond Myklebust81039f12006-06-09 09:34:34 -0400256 rpc_authflavor_t flavour;
257 const char *str;
258 } sec_flavours[] = {
259 { RPC_AUTH_NULL, "null" },
260 { RPC_AUTH_UNIX, "sys" },
261 { RPC_AUTH_GSS_KRB5, "krb5" },
262 { RPC_AUTH_GSS_KRB5I, "krb5i" },
263 { RPC_AUTH_GSS_KRB5P, "krb5p" },
264 { RPC_AUTH_GSS_LKEY, "lkey" },
265 { RPC_AUTH_GSS_LKEYI, "lkeyi" },
266 { RPC_AUTH_GSS_LKEYP, "lkeyp" },
267 { RPC_AUTH_GSS_SPKM, "spkm" },
268 { RPC_AUTH_GSS_SPKMI, "spkmi" },
269 { RPC_AUTH_GSS_SPKMP, "spkmp" },
270 { -1, "unknown" }
271 };
272 int i;
273
274 for (i=0; sec_flavours[i].flavour != -1; i++) {
275 if (sec_flavours[i].flavour == flavour)
276 break;
277 }
278 return sec_flavours[i].str;
279}
280
David Howellsf7b422b2006-06-09 09:34:33 -0400281/*
282 * Describe the mount options in force on this server representation
283 */
284static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, int showdefaults)
285{
David Howells509de812006-08-22 20:06:11 -0400286 static const struct proc_nfs_info {
David Howellsf7b422b2006-06-09 09:34:33 -0400287 int flag;
David Howells509de812006-08-22 20:06:11 -0400288 const char *str;
289 const char *nostr;
David Howellsf7b422b2006-06-09 09:34:33 -0400290 } nfs_info[] = {
291 { NFS_MOUNT_SOFT, ",soft", ",hard" },
292 { NFS_MOUNT_INTR, ",intr", "" },
293 { NFS_MOUNT_NOCTO, ",nocto", "" },
294 { NFS_MOUNT_NOAC, ",noac", "" },
295 { NFS_MOUNT_NONLM, ",nolock", "" },
296 { NFS_MOUNT_NOACL, ",noacl", "" },
297 { 0, NULL, NULL }
298 };
David Howells509de812006-08-22 20:06:11 -0400299 const struct proc_nfs_info *nfs_infop;
David Howells8fa5c002006-08-22 20:06:12 -0400300 struct nfs_client *clp = nfss->nfs_client;
David Howellsf7b422b2006-06-09 09:34:33 -0400301 char buf[12];
David Howells509de812006-08-22 20:06:11 -0400302 const char *proto;
David Howellsf7b422b2006-06-09 09:34:33 -0400303
David Howells8fa5c002006-08-22 20:06:12 -0400304 seq_printf(m, ",vers=%d", clp->rpc_ops->version);
David Howellsf7b422b2006-06-09 09:34:33 -0400305 seq_printf(m, ",rsize=%d", nfss->rsize);
306 seq_printf(m, ",wsize=%d", nfss->wsize);
307 if (nfss->acregmin != 3*HZ || showdefaults)
308 seq_printf(m, ",acregmin=%d", nfss->acregmin/HZ);
309 if (nfss->acregmax != 60*HZ || showdefaults)
310 seq_printf(m, ",acregmax=%d", nfss->acregmax/HZ);
311 if (nfss->acdirmin != 30*HZ || showdefaults)
312 seq_printf(m, ",acdirmin=%d", nfss->acdirmin/HZ);
313 if (nfss->acdirmax != 60*HZ || showdefaults)
314 seq_printf(m, ",acdirmax=%d", nfss->acdirmax/HZ);
315 for (nfs_infop = nfs_info; nfs_infop->flag; nfs_infop++) {
316 if (nfss->flags & nfs_infop->flag)
317 seq_puts(m, nfs_infop->str);
318 else
319 seq_puts(m, nfs_infop->nostr);
320 }
321 switch (nfss->client->cl_xprt->prot) {
322 case IPPROTO_TCP:
323 proto = "tcp";
324 break;
325 case IPPROTO_UDP:
326 proto = "udp";
327 break;
328 default:
329 snprintf(buf, sizeof(buf), "%u", nfss->client->cl_xprt->prot);
330 proto = buf;
331 }
332 seq_printf(m, ",proto=%s", proto);
David Howells5006a762006-08-22 20:06:12 -0400333 seq_printf(m, ",timeo=%lu", 10U * clp->retrans_timeo / HZ);
334 seq_printf(m, ",retrans=%u", clp->retrans_count);
Trond Myklebust81039f12006-06-09 09:34:34 -0400335 seq_printf(m, ",sec=%s", nfs_pseudoflavour_to_name(nfss->client->cl_auth->au_flavor));
David Howellsf7b422b2006-06-09 09:34:33 -0400336}
337
338/*
339 * Describe the mount options on this VFS mountpoint
340 */
341static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
342{
343 struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
344
345 nfs_show_mount_options(m, nfss, 0);
346
347 seq_puts(m, ",addr=");
348 seq_escape(m, nfss->hostname, " \t\n\\");
349
350 return 0;
351}
352
353/*
354 * Present statistical information for this VFS mountpoint
355 */
356static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
357{
358 int i, cpu;
359 struct nfs_server *nfss = NFS_SB(mnt->mnt_sb);
360 struct rpc_auth *auth = nfss->client->cl_auth;
361 struct nfs_iostats totals = { };
362
363 seq_printf(m, "statvers=%s", NFS_IOSTAT_VERS);
364
365 /*
366 * Display all mount option settings
367 */
368 seq_printf(m, "\n\topts:\t");
369 seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? "ro" : "rw");
370 seq_puts(m, mnt->mnt_sb->s_flags & MS_SYNCHRONOUS ? ",sync" : "");
371 seq_puts(m, mnt->mnt_sb->s_flags & MS_NOATIME ? ",noatime" : "");
372 seq_puts(m, mnt->mnt_sb->s_flags & MS_NODIRATIME ? ",nodiratime" : "");
373 nfs_show_mount_options(m, nfss, 1);
374
375 seq_printf(m, "\n\tage:\t%lu", (jiffies - nfss->mount_time) / HZ);
376
377 seq_printf(m, "\n\tcaps:\t");
378 seq_printf(m, "caps=0x%x", nfss->caps);
379 seq_printf(m, ",wtmult=%d", nfss->wtmult);
380 seq_printf(m, ",dtsize=%d", nfss->dtsize);
381 seq_printf(m, ",bsize=%d", nfss->bsize);
382 seq_printf(m, ",namelen=%d", nfss->namelen);
383
384#ifdef CONFIG_NFS_V4
David Howells8fa5c002006-08-22 20:06:12 -0400385 if (nfss->nfs_client->cl_nfsversion == 4) {
David Howellsf7b422b2006-06-09 09:34:33 -0400386 seq_printf(m, "\n\tnfsv4:\t");
387 seq_printf(m, "bm0=0x%x", nfss->attr_bitmask[0]);
388 seq_printf(m, ",bm1=0x%x", nfss->attr_bitmask[1]);
389 seq_printf(m, ",acl=0x%x", nfss->acl_bitmask);
390 }
391#endif
392
393 /*
394 * Display security flavor in effect for this mount
395 */
396 seq_printf(m, "\n\tsec:\tflavor=%d", auth->au_ops->au_flavor);
397 if (auth->au_flavor)
398 seq_printf(m, ",pseudoflavor=%d", auth->au_flavor);
399
400 /*
401 * Display superblock I/O counters
402 */
403 for_each_possible_cpu(cpu) {
404 struct nfs_iostats *stats;
405
406 preempt_disable();
407 stats = per_cpu_ptr(nfss->io_stats, cpu);
408
409 for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
410 totals.events[i] += stats->events[i];
411 for (i = 0; i < __NFSIOS_BYTESMAX; i++)
412 totals.bytes[i] += stats->bytes[i];
413
414 preempt_enable();
415 }
416
417 seq_printf(m, "\n\tevents:\t");
418 for (i = 0; i < __NFSIOS_COUNTSMAX; i++)
419 seq_printf(m, "%lu ", totals.events[i]);
420 seq_printf(m, "\n\tbytes:\t");
421 for (i = 0; i < __NFSIOS_BYTESMAX; i++)
422 seq_printf(m, "%Lu ", totals.bytes[i]);
423 seq_printf(m, "\n");
424
425 rpc_print_iostats(m, nfss->client);
426
427 return 0;
428}
429
430/*
431 * Begin unmount by attempting to remove all automounted mountpoints we added
432 * in response to traversals
433 */
434static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
435{
436 struct nfs_server *server;
437 struct rpc_clnt *rpc;
438
439 shrink_submounts(vfsmnt, &nfs_automount_list);
440 if (!(flags & MNT_FORCE))
441 return;
442 /* -EIO all pending I/O */
443 server = NFS_SB(vfsmnt->mnt_sb);
444 rpc = server->client;
445 if (!IS_ERR(rpc))
446 rpc_killall_tasks(rpc);
447 rpc = server->client_acl;
448 if (!IS_ERR(rpc))
449 rpc_killall_tasks(rpc);
450}
451
452/*
453 * Obtain the root inode of the file system.
454 */
455static struct inode *
456nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
457{
458 struct nfs_server *server = NFS_SB(sb);
459 int error;
460
David Howells8fa5c002006-08-22 20:06:12 -0400461 error = server->nfs_client->rpc_ops->getroot(server, rootfh, fsinfo);
David Howellsf7b422b2006-06-09 09:34:33 -0400462 if (error < 0) {
463 dprintk("nfs_get_root: getattr error = %d\n", -error);
464 return ERR_PTR(error);
465 }
466
467 server->fsid = fsinfo->fattr->fsid;
468 return nfs_fhget(sb, rootfh, fsinfo->fattr);
469}
470
471/*
472 * Do NFS version-independent mount processing, and sanity checking
473 */
474static int
475nfs_sb_init(struct super_block *sb, rpc_authflavor_t authflavor)
476{
477 struct nfs_server *server;
478 struct inode *root_inode;
479 struct nfs_fattr fattr;
480 struct nfs_fsinfo fsinfo = {
481 .fattr = &fattr,
482 };
483 struct nfs_pathconf pathinfo = {
484 .fattr = &fattr,
485 };
486 int no_root_error = 0;
487 unsigned long max_rpc_payload;
488
489 /* We probably want something more informative here */
490 snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
491
492 server = NFS_SB(sb);
493
494 sb->s_magic = NFS_SUPER_MAGIC;
495
496 server->io_stats = nfs_alloc_iostats();
497 if (server->io_stats == NULL)
498 return -ENOMEM;
499
500 root_inode = nfs_get_root(sb, &server->fh, &fsinfo);
501 /* Did getting the root inode fail? */
502 if (IS_ERR(root_inode)) {
503 no_root_error = PTR_ERR(root_inode);
504 goto out_no_root;
505 }
506 sb->s_root = d_alloc_root(root_inode);
507 if (!sb->s_root) {
508 no_root_error = -ENOMEM;
509 goto out_no_root;
510 }
David Howells8fa5c002006-08-22 20:06:12 -0400511 sb->s_root->d_op = server->nfs_client->rpc_ops->dentry_ops;
David Howellsf7b422b2006-06-09 09:34:33 -0400512
513 /* mount time stamp, in seconds */
514 server->mount_time = jiffies;
515
516 /* Get some general file system info */
517 if (server->namelen == 0 &&
David Howells8fa5c002006-08-22 20:06:12 -0400518 server->nfs_client->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
David Howellsf7b422b2006-06-09 09:34:33 -0400519 server->namelen = pathinfo.max_namelen;
520 /* Work out a lot of parameters */
521 if (server->rsize == 0)
522 server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
523 if (server->wsize == 0)
524 server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
525
526 if (fsinfo.rtmax >= 512 && server->rsize > fsinfo.rtmax)
527 server->rsize = nfs_block_size(fsinfo.rtmax, NULL);
528 if (fsinfo.wtmax >= 512 && server->wsize > fsinfo.wtmax)
529 server->wsize = nfs_block_size(fsinfo.wtmax, NULL);
530
531 max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
532 if (server->rsize > max_rpc_payload)
533 server->rsize = max_rpc_payload;
534 if (server->rsize > NFS_MAX_FILE_IO_SIZE)
535 server->rsize = NFS_MAX_FILE_IO_SIZE;
536 server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
537
538 if (server->wsize > max_rpc_payload)
539 server->wsize = max_rpc_payload;
540 if (server->wsize > NFS_MAX_FILE_IO_SIZE)
541 server->wsize = NFS_MAX_FILE_IO_SIZE;
542 server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
543
544 if (sb->s_blocksize == 0)
545 sb->s_blocksize = nfs_block_bits(server->wsize,
546 &sb->s_blocksize_bits);
547 server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL);
548
549 server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
550 if (server->dtsize > PAGE_CACHE_SIZE)
551 server->dtsize = PAGE_CACHE_SIZE;
552 if (server->dtsize > server->rsize)
553 server->dtsize = server->rsize;
554
555 if (server->flags & NFS_MOUNT_NOAC) {
556 server->acregmin = server->acregmax = 0;
557 server->acdirmin = server->acdirmax = 0;
558 sb->s_flags |= MS_SYNCHRONOUS;
559 }
560 server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
561
562 nfs_super_set_maxbytes(sb, fsinfo.maxfilesize);
563
564 server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0;
565 server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0;
566
567 /* We're airborne Set socket buffersize */
568 rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
569 return 0;
570 /* Yargs. It didn't work out. */
571out_no_root:
572 dprintk("nfs_sb_init: get root inode failed: errno %d\n", -no_root_error);
573 if (!IS_ERR(root_inode))
574 iput(root_inode);
575 return no_root_error;
576}
577
578/*
David Howellsf7b422b2006-06-09 09:34:33 -0400579 * Create an RPC client handle.
580 */
581static struct rpc_clnt *
582nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
583{
David Howells27951bd2006-08-22 20:06:11 -0400584 struct nfs_client *clp;
David Howells5006a762006-08-22 20:06:12 -0400585 struct rpc_clnt *clnt;
David Howellsf7b422b2006-06-09 09:34:33 -0400586 int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
David Howells8fa5c002006-08-22 20:06:12 -0400587 int nfsversion = 2;
David Howells5006a762006-08-22 20:06:12 -0400588 int err;
David Howellsf7b422b2006-06-09 09:34:33 -0400589
David Howells8fa5c002006-08-22 20:06:12 -0400590#ifdef CONFIG_NFS_V3
591 if (server->flags & NFS_MOUNT_VER3)
592 nfsversion = 3;
593#endif
594
595 clp = nfs_get_client(server->hostname, &server->addr, nfsversion);
David Howells27951bd2006-08-22 20:06:11 -0400596 if (!clp) {
597 dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
598 return ERR_PTR(PTR_ERR(clp));
599 }
600
David Howells5006a762006-08-22 20:06:12 -0400601 if (clp->cl_cons_state == NFS_CS_INITING) {
602 /* Check NFS protocol revision and initialize RPC op
603 * vector and file handle pool. */
David Howells8fa5c002006-08-22 20:06:12 -0400604#ifdef CONFIG_NFS_V3
David Howells5006a762006-08-22 20:06:12 -0400605 if (nfsversion == 3) {
606 clp->rpc_ops = &nfs_v3_clientops;
607 server->caps |= NFS_CAP_READDIRPLUS;
608 } else {
609 clp->rpc_ops = &nfs_v2_clientops;
610 }
David Howells8fa5c002006-08-22 20:06:12 -0400611#else
David Howells5006a762006-08-22 20:06:12 -0400612 clp->rpc_ops = &nfs_v2_clientops;
David Howells8fa5c002006-08-22 20:06:12 -0400613#endif
614
David Howells5006a762006-08-22 20:06:12 -0400615 /* create transport and client */
616 err = nfs_create_rpc_client(clp, proto, data->timeo,
617 data->retrans, RPC_AUTH_UNIX);
618 if (err < 0)
619 goto client_init_error;
620
621 nfs_mark_client_ready(clp, 0);
David Howellsf7b422b2006-06-09 09:34:33 -0400622 }
David Howells5006a762006-08-22 20:06:12 -0400623
624 /* create an nfs_server-specific client */
625 clnt = rpc_clone_client(clp->cl_rpcclient);
David Howellsf7b422b2006-06-09 09:34:33 -0400626 if (IS_ERR(clnt)) {
David Howells5006a762006-08-22 20:06:12 -0400627 dprintk("%s: couldn't create rpc_client!\n", __FUNCTION__);
628 nfs_put_client(clp);
629 return ERR_PTR(PTR_ERR(clnt));
David Howellsf7b422b2006-06-09 09:34:33 -0400630 }
631
David Howells5006a762006-08-22 20:06:12 -0400632 if (data->pseudoflavor != clp->cl_rpcclient->cl_auth->au_flavor) {
633 struct rpc_auth *auth;
David Howellsf7b422b2006-06-09 09:34:33 -0400634
David Howells5006a762006-08-22 20:06:12 -0400635 auth = rpcauth_create(data->pseudoflavor, server->client);
636 if (IS_ERR(auth)) {
637 dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
638 return ERR_PTR(PTR_ERR(auth));
639 }
640 }
641
David Howells27951bd2006-08-22 20:06:11 -0400642 server->nfs_client = clp;
David Howellsf7b422b2006-06-09 09:34:33 -0400643 return clnt;
644
David Howells5006a762006-08-22 20:06:12 -0400645client_init_error:
646 nfs_mark_client_ready(clp, err);
David Howells27951bd2006-08-22 20:06:11 -0400647 nfs_put_client(clp);
David Howells5006a762006-08-22 20:06:12 -0400648 return ERR_PTR(err);
David Howellsf7b422b2006-06-09 09:34:33 -0400649}
650
651/*
652 * Clone a server record
653 */
654static struct nfs_server *nfs_clone_server(struct super_block *sb, struct nfs_clone_mount *data)
655{
656 struct nfs_server *server = NFS_SB(sb);
657 struct nfs_server *parent = NFS_SB(data->sb);
658 struct inode *root_inode;
659 struct nfs_fsinfo fsinfo;
660 void *err = ERR_PTR(-ENOMEM);
661
662 sb->s_op = data->sb->s_op;
663 sb->s_blocksize = data->sb->s_blocksize;
664 sb->s_blocksize_bits = data->sb->s_blocksize_bits;
665 sb->s_maxbytes = data->sb->s_maxbytes;
666
David Howells5006a762006-08-22 20:06:12 -0400667 server->client_acl = ERR_PTR(-EINVAL);
David Howellsf7b422b2006-06-09 09:34:33 -0400668 server->io_stats = nfs_alloc_iostats();
669 if (server->io_stats == NULL)
670 goto out;
671
672 server->client = rpc_clone_client(parent->client);
673 if (IS_ERR((err = server->client)))
674 goto out;
675
David Howellsf7b422b2006-06-09 09:34:33 -0400676 if (!IS_ERR(parent->client_acl)) {
677 server->client_acl = rpc_clone_client(parent->client_acl);
678 if (IS_ERR((err = server->client_acl)))
679 goto out;
680 }
681 root_inode = nfs_fhget(sb, data->fh, data->fattr);
682 if (!root_inode)
683 goto out;
684 sb->s_root = d_alloc_root(root_inode);
685 if (!sb->s_root)
686 goto out_put_root;
687 fsinfo.fattr = data->fattr;
688 if (NFS_PROTO(root_inode)->fsinfo(server, data->fh, &fsinfo) == 0)
689 nfs_super_set_maxbytes(sb, fsinfo.maxfilesize);
David Howells8fa5c002006-08-22 20:06:12 -0400690 sb->s_root->d_op = server->nfs_client->rpc_ops->dentry_ops;
David Howellsf7b422b2006-06-09 09:34:33 -0400691 sb->s_flags |= MS_ACTIVE;
692 return server;
693out_put_root:
694 iput(root_inode);
695out:
696 return err;
697}
698
699/*
700 * Copy an existing superblock and attach revised data
701 */
Trond Myklebust816724e2006-06-24 08:41:41 -0400702static int nfs_clone_generic_sb(struct nfs_clone_mount *data,
David Howellsf7b422b2006-06-09 09:34:33 -0400703 struct super_block *(*fill_sb)(struct nfs_server *, struct nfs_clone_mount *),
Trond Myklebust816724e2006-06-24 08:41:41 -0400704 struct nfs_server *(*fill_server)(struct super_block *, struct nfs_clone_mount *),
705 struct vfsmount *mnt)
David Howellsf7b422b2006-06-09 09:34:33 -0400706{
707 struct nfs_server *server;
708 struct nfs_server *parent = NFS_SB(data->sb);
709 struct super_block *sb = ERR_PTR(-EINVAL);
David Howellsf7b422b2006-06-09 09:34:33 -0400710 char *hostname;
Trond Myklebust816724e2006-06-24 08:41:41 -0400711 int error = -ENOMEM;
David Howellsf7b422b2006-06-09 09:34:33 -0400712 int len;
713
714 server = kmalloc(sizeof(struct nfs_server), GFP_KERNEL);
715 if (server == NULL)
716 goto out_err;
717 memcpy(server, parent, sizeof(*server));
David Howells27951bd2006-08-22 20:06:11 -0400718 atomic_inc(&server->nfs_client->cl_count);
David Howellsf7b422b2006-06-09 09:34:33 -0400719 hostname = (data->hostname != NULL) ? data->hostname : parent->hostname;
720 len = strlen(hostname) + 1;
721 server->hostname = kmalloc(len, GFP_KERNEL);
722 if (server->hostname == NULL)
723 goto free_server;
724 memcpy(server->hostname, hostname, len);
Trond Myklebust816724e2006-06-24 08:41:41 -0400725 error = rpciod_up();
726 if (error != 0)
David Howellsf7b422b2006-06-09 09:34:33 -0400727 goto free_hostname;
728
729 sb = fill_sb(server, data);
Trond Myklebust816724e2006-06-24 08:41:41 -0400730 if (IS_ERR(sb)) {
731 error = PTR_ERR(sb);
David Howellsf7b422b2006-06-09 09:34:33 -0400732 goto kill_rpciod;
Trond Myklebust816724e2006-06-24 08:41:41 -0400733 }
David Howells5006a762006-08-22 20:06:12 -0400734
Trond Myklebust816724e2006-06-24 08:41:41 -0400735 if (sb->s_root)
736 goto out_rpciod_down;
David Howellsf7b422b2006-06-09 09:34:33 -0400737
738 server = fill_server(sb, data);
Trond Myklebust816724e2006-06-24 08:41:41 -0400739 if (IS_ERR(server)) {
740 error = PTR_ERR(server);
David Howellsf7b422b2006-06-09 09:34:33 -0400741 goto out_deactivate;
Trond Myklebust816724e2006-06-24 08:41:41 -0400742 }
743 return simple_set_mnt(mnt, sb);
David Howellsf7b422b2006-06-09 09:34:33 -0400744out_deactivate:
745 up_write(&sb->s_umount);
746 deactivate_super(sb);
Trond Myklebust816724e2006-06-24 08:41:41 -0400747 return error;
748out_rpciod_down:
749 rpciod_down();
750 kfree(server->hostname);
David Howells27951bd2006-08-22 20:06:11 -0400751 nfs_put_client(server->nfs_client);
Trond Myklebust816724e2006-06-24 08:41:41 -0400752 kfree(server);
753 return simple_set_mnt(mnt, sb);
David Howellsf7b422b2006-06-09 09:34:33 -0400754kill_rpciod:
755 rpciod_down();
756free_hostname:
757 kfree(server->hostname);
758free_server:
David Howells27951bd2006-08-22 20:06:11 -0400759 nfs_put_client(server->nfs_client);
David Howellsf7b422b2006-06-09 09:34:33 -0400760 kfree(server);
761out_err:
Trond Myklebust816724e2006-06-24 08:41:41 -0400762 return error;
David Howellsf7b422b2006-06-09 09:34:33 -0400763}
764
765/*
766 * Set up an NFS2/3 superblock
767 *
768 * The way this works is that the mount process passes a structure
769 * in the data argument which contains the server's IP address
770 * and the root file handle obtained from the server's mount
771 * daemon. We stash these away in the private superblock fields.
772 */
773static int
774nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
775{
776 struct nfs_server *server;
777 rpc_authflavor_t authflavor;
778
779 server = NFS_SB(sb);
780 sb->s_blocksize_bits = 0;
781 sb->s_blocksize = 0;
782 if (data->bsize)
783 sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
784 if (data->rsize)
785 server->rsize = nfs_block_size(data->rsize, NULL);
786 if (data->wsize)
787 server->wsize = nfs_block_size(data->wsize, NULL);
788 server->flags = data->flags & NFS_MOUNT_FLAGMASK;
789
790 server->acregmin = data->acregmin*HZ;
791 server->acregmax = data->acregmax*HZ;
792 server->acdirmin = data->acdirmin*HZ;
793 server->acdirmax = data->acdirmax*HZ;
794
795 /* Start lockd here, before we might error out */
796 if (!(server->flags & NFS_MOUNT_NONLM))
797 lockd_up();
798
799 server->namelen = data->namlen;
800 server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
801 if (!server->hostname)
802 return -ENOMEM;
803 strcpy(server->hostname, data->hostname);
804
David Howellsf7b422b2006-06-09 09:34:33 -0400805 /* Fill in pseudoflavor for mount version < 5 */
806 if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
807 data->pseudoflavor = RPC_AUTH_UNIX;
808 authflavor = data->pseudoflavor; /* save for sb_init() */
809 /* XXX maybe we want to add a server->pseudoflavor field */
810
811 /* Create RPC client handles */
812 server->client = nfs_create_client(server, data);
813 if (IS_ERR(server->client))
814 return PTR_ERR(server->client);
David Howells8fa5c002006-08-22 20:06:12 -0400815
David Howellsf7b422b2006-06-09 09:34:33 -0400816 /* RFC 2623, sec 2.3.2 */
David Howellsf7b422b2006-06-09 09:34:33 -0400817 if (server->flags & NFS_MOUNT_VER3) {
818#ifdef CONFIG_NFS_V3_ACL
819 if (!(server->flags & NFS_MOUNT_NOACL)) {
820 server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
821 /* No errors! Assume that Sun nfsacls are supported */
822 if (!IS_ERR(server->client_acl))
823 server->caps |= NFS_CAP_ACLS;
824 }
825#else
826 server->flags &= ~NFS_MOUNT_NOACL;
827#endif /* CONFIG_NFS_V3_ACL */
828 /*
829 * The VFS shouldn't apply the umask to mode bits. We will
830 * do so ourselves when necessary.
831 */
832 sb->s_flags |= MS_POSIXACL;
833 if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
834 server->namelen = NFS3_MAXNAMLEN;
835 sb->s_time_gran = 1;
836 } else {
837 if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
838 server->namelen = NFS2_MAXNAMLEN;
839 }
840
841 sb->s_op = &nfs_sops;
842 return nfs_sb_init(sb, authflavor);
843}
844
845static int nfs_set_super(struct super_block *s, void *data)
846{
847 s->s_fs_info = data;
848 return set_anon_super(s, data);
849}
850
851static int nfs_compare_super(struct super_block *sb, void *data)
852{
853 struct nfs_server *server = data;
854 struct nfs_server *old = NFS_SB(sb);
855
856 if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr)
857 return 0;
858 if (old->addr.sin_port != server->addr.sin_port)
859 return 0;
860 return !nfs_compare_fh(&old->fh, &server->fh);
861}
862
Trond Myklebust816724e2006-06-24 08:41:41 -0400863static int nfs_get_sb(struct file_system_type *fs_type,
864 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
David Howellsf7b422b2006-06-09 09:34:33 -0400865{
866 int error;
867 struct nfs_server *server = NULL;
868 struct super_block *s;
869 struct nfs_fh *root;
870 struct nfs_mount_data *data = raw_data;
871
Trond Myklebust816724e2006-06-24 08:41:41 -0400872 error = -EINVAL;
David Howellsf7b422b2006-06-09 09:34:33 -0400873 if (data == NULL) {
874 dprintk("%s: missing data argument\n", __FUNCTION__);
Trond Myklebust816724e2006-06-24 08:41:41 -0400875 goto out_err_noserver;
David Howellsf7b422b2006-06-09 09:34:33 -0400876 }
877 if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
878 dprintk("%s: bad mount version\n", __FUNCTION__);
Trond Myklebust816724e2006-06-24 08:41:41 -0400879 goto out_err_noserver;
David Howellsf7b422b2006-06-09 09:34:33 -0400880 }
881 switch (data->version) {
882 case 1:
883 data->namlen = 0;
884 case 2:
885 data->bsize = 0;
886 case 3:
887 if (data->flags & NFS_MOUNT_VER3) {
888 dprintk("%s: mount structure version %d does not support NFSv3\n",
889 __FUNCTION__,
890 data->version);
Trond Myklebust816724e2006-06-24 08:41:41 -0400891 goto out_err_noserver;
David Howellsf7b422b2006-06-09 09:34:33 -0400892 }
893 data->root.size = NFS2_FHSIZE;
894 memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
895 case 4:
896 if (data->flags & NFS_MOUNT_SECFLAVOUR) {
897 dprintk("%s: mount structure version %d does not support strong security\n",
898 __FUNCTION__,
899 data->version);
Trond Myklebust816724e2006-06-24 08:41:41 -0400900 goto out_err_noserver;
David Howellsf7b422b2006-06-09 09:34:33 -0400901 }
902 case 5:
903 memset(data->context, 0, sizeof(data->context));
904 }
905#ifndef CONFIG_NFS_V3
906 /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
Trond Myklebust816724e2006-06-24 08:41:41 -0400907 error = -EPROTONOSUPPORT;
David Howellsf7b422b2006-06-09 09:34:33 -0400908 if (data->flags & NFS_MOUNT_VER3) {
909 dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
Trond Myklebust816724e2006-06-24 08:41:41 -0400910 goto out_err_noserver;
David Howellsf7b422b2006-06-09 09:34:33 -0400911 }
912#endif /* CONFIG_NFS_V3 */
913
Trond Myklebust816724e2006-06-24 08:41:41 -0400914 error = -ENOMEM;
David Howellsf7b422b2006-06-09 09:34:33 -0400915 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
916 if (!server)
Trond Myklebust816724e2006-06-24 08:41:41 -0400917 goto out_err_noserver;
David Howellsf7b422b2006-06-09 09:34:33 -0400918 /* Zero out the NFS state stuff */
919 init_nfsv4_state(server);
David Howells5006a762006-08-22 20:06:12 -0400920 server->client = server->client_acl = ERR_PTR(-EINVAL);
David Howellsf7b422b2006-06-09 09:34:33 -0400921
922 root = &server->fh;
923 if (data->flags & NFS_MOUNT_VER3)
924 root->size = data->root.size;
925 else
926 root->size = NFS2_FHSIZE;
Trond Myklebust816724e2006-06-24 08:41:41 -0400927 error = -EINVAL;
David Howellsf7b422b2006-06-09 09:34:33 -0400928 if (root->size > sizeof(root->data)) {
929 dprintk("%s: invalid root filehandle\n", __FUNCTION__);
930 goto out_err;
931 }
932 memcpy(root->data, data->root.data, root->size);
933
934 /* We now require that the mount process passes the remote address */
935 memcpy(&server->addr, &data->addr, sizeof(server->addr));
936 if (server->addr.sin_addr.s_addr == INADDR_ANY) {
937 dprintk("%s: mount program didn't pass remote address!\n",
938 __FUNCTION__);
939 goto out_err;
940 }
941
942 /* Fire up rpciod if not yet running */
Trond Myklebust816724e2006-06-24 08:41:41 -0400943 error = rpciod_up();
944 if (error < 0) {
945 dprintk("%s: couldn't start rpciod! Error = %d\n",
946 __FUNCTION__, error);
David Howellsf7b422b2006-06-09 09:34:33 -0400947 goto out_err;
948 }
949
950 s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
Trond Myklebust816724e2006-06-24 08:41:41 -0400951 if (IS_ERR(s)) {
952 error = PTR_ERR(s);
953 goto out_err_rpciod;
954 }
955
956 if (s->s_root)
David Howellsf7b422b2006-06-09 09:34:33 -0400957 goto out_rpciod_down;
958
959 s->s_flags = flags;
960
961 error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
962 if (error) {
963 up_write(&s->s_umount);
964 deactivate_super(s);
Trond Myklebust816724e2006-06-24 08:41:41 -0400965 return error;
David Howellsf7b422b2006-06-09 09:34:33 -0400966 }
967 s->s_flags |= MS_ACTIVE;
Trond Myklebust816724e2006-06-24 08:41:41 -0400968 return simple_set_mnt(mnt, s);
969
David Howellsf7b422b2006-06-09 09:34:33 -0400970out_rpciod_down:
971 rpciod_down();
Trond Myklebust816724e2006-06-24 08:41:41 -0400972 kfree(server);
973 return simple_set_mnt(mnt, s);
974
975out_err_rpciod:
976 rpciod_down();
David Howellsf7b422b2006-06-09 09:34:33 -0400977out_err:
978 kfree(server);
Trond Myklebust816724e2006-06-24 08:41:41 -0400979out_err_noserver:
980 return error;
David Howellsf7b422b2006-06-09 09:34:33 -0400981}
982
983static void nfs_kill_super(struct super_block *s)
984{
985 struct nfs_server *server = NFS_SB(s);
986
987 kill_anon_super(s);
988
989 if (!IS_ERR(server->client))
990 rpc_shutdown_client(server->client);
David Howellsf7b422b2006-06-09 09:34:33 -0400991 if (!IS_ERR(server->client_acl))
992 rpc_shutdown_client(server->client_acl);
993
994 if (!(server->flags & NFS_MOUNT_NONLM))
995 lockd_down(); /* release rpc.lockd */
996
997 rpciod_down(); /* release rpciod */
998
999 nfs_free_iostats(server->io_stats);
1000 kfree(server->hostname);
David Howells27951bd2006-08-22 20:06:11 -04001001 nfs_put_client(server->nfs_client);
David Howellsf7b422b2006-06-09 09:34:33 -04001002 kfree(server);
1003 nfs_release_automount_timer();
1004}
1005
1006static struct super_block *nfs_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data)
1007{
1008 struct super_block *sb;
1009
1010 server->fsid = data->fattr->fsid;
1011 nfs_copy_fh(&server->fh, data->fh);
1012 sb = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
1013 if (!IS_ERR(sb) && sb->s_root == NULL && !(server->flags & NFS_MOUNT_NONLM))
1014 lockd_up();
1015 return sb;
1016}
1017
Trond Myklebust816724e2006-06-24 08:41:41 -04001018static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
1019 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
David Howellsf7b422b2006-06-09 09:34:33 -04001020{
1021 struct nfs_clone_mount *data = raw_data;
Trond Myklebust816724e2006-06-24 08:41:41 -04001022 return nfs_clone_generic_sb(data, nfs_clone_sb, nfs_clone_server, mnt);
David Howellsf7b422b2006-06-09 09:34:33 -04001023}
1024
1025#ifdef CONFIG_NFS_V4
1026static struct rpc_clnt *nfs4_create_client(struct nfs_server *server,
David Howells5006a762006-08-22 20:06:12 -04001027 int timeo, int retrans, int proto, rpc_authflavor_t flavor)
David Howellsf7b422b2006-06-09 09:34:33 -04001028{
David Howellsadfa6f92006-08-22 20:06:08 -04001029 struct nfs_client *clp;
David Howellsf7b422b2006-06-09 09:34:33 -04001030 struct rpc_clnt *clnt = NULL;
1031 int err = -EIO;
1032
David Howells24c8dbb2006-08-22 20:06:10 -04001033 clp = nfs_get_client(server->hostname, &server->addr, 4);
David Howellsf7b422b2006-06-09 09:34:33 -04001034 if (!clp) {
1035 dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
1036 return ERR_PTR(err);
1037 }
1038
1039 /* Now create transport and client */
David Howells24c8dbb2006-08-22 20:06:10 -04001040 if (clp->cl_cons_state == NFS_CS_INITING) {
David Howells8fa5c002006-08-22 20:06:12 -04001041 clp->rpc_ops = &nfs_v4_clientops;
1042
David Howells5006a762006-08-22 20:06:12 -04001043 err = nfs_create_rpc_client(clp, proto, timeo, retrans, flavor);
1044 if (err < 0)
David Howells24c8dbb2006-08-22 20:06:10 -04001045 goto client_init_error;
David Howells5006a762006-08-22 20:06:12 -04001046
David Howellsf7b422b2006-06-09 09:34:33 -04001047 memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
David Howells24c8dbb2006-08-22 20:06:10 -04001048 err = nfs_idmap_new(clp);
1049 if (err < 0) {
1050 dprintk("%s: failed to create idmapper.\n",
1051 __FUNCTION__);
1052 goto client_init_error;
1053 }
1054 __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
1055 nfs_mark_client_ready(clp, 0);
David Howellsf7b422b2006-06-09 09:34:33 -04001056 }
David Howells24c8dbb2006-08-22 20:06:10 -04001057
David Howellsf7b422b2006-06-09 09:34:33 -04001058 clnt = rpc_clone_client(clp->cl_rpcclient);
David Howellsf7b422b2006-06-09 09:34:33 -04001059
1060 if (IS_ERR(clnt)) {
1061 dprintk("%s: cannot create RPC client. Error = %d\n",
1062 __FUNCTION__, err);
1063 return clnt;
1064 }
1065
David Howellsf7b422b2006-06-09 09:34:33 -04001066 if (clnt->cl_auth->au_flavor != flavor) {
1067 struct rpc_auth *auth;
1068
1069 auth = rpcauth_create(flavor, clnt);
1070 if (IS_ERR(auth)) {
1071 dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
1072 return (struct rpc_clnt *)auth;
1073 }
1074 }
David Howells24c8dbb2006-08-22 20:06:10 -04001075
1076 server->nfs_client = clp;
1077 down_write(&clp->cl_sem);
1078 list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
1079 up_write(&clp->cl_sem);
David Howellsf7b422b2006-06-09 09:34:33 -04001080 return clnt;
1081
David Howells24c8dbb2006-08-22 20:06:10 -04001082client_init_error:
1083 nfs_mark_client_ready(clp, err);
1084 nfs_put_client(clp);
David Howellsf7b422b2006-06-09 09:34:33 -04001085 return ERR_PTR(err);
1086}
1087
1088/*
1089 * Set up an NFS4 superblock
1090 */
1091static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
1092{
1093 struct nfs_server *server;
David Howellsf7b422b2006-06-09 09:34:33 -04001094 rpc_authflavor_t authflavour;
1095 int err = -EIO;
1096
1097 sb->s_blocksize_bits = 0;
1098 sb->s_blocksize = 0;
1099 server = NFS_SB(sb);
1100 if (data->rsize != 0)
1101 server->rsize = nfs_block_size(data->rsize, NULL);
1102 if (data->wsize != 0)
1103 server->wsize = nfs_block_size(data->wsize, NULL);
1104 server->flags = data->flags & NFS_MOUNT_FLAGMASK;
1105 server->caps = NFS_CAP_ATOMIC_OPEN;
1106
1107 server->acregmin = data->acregmin*HZ;
1108 server->acregmax = data->acregmax*HZ;
1109 server->acdirmin = data->acdirmin*HZ;
1110 server->acdirmax = data->acdirmax*HZ;
1111
David Howellsf7b422b2006-06-09 09:34:33 -04001112 /* Now create transport and client */
1113 authflavour = RPC_AUTH_UNIX;
1114 if (data->auth_flavourlen != 0) {
1115 if (data->auth_flavourlen != 1) {
1116 dprintk("%s: Invalid number of RPC auth flavours %d.\n",
1117 __FUNCTION__, data->auth_flavourlen);
1118 err = -EINVAL;
1119 goto out_fail;
1120 }
1121 if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) {
1122 err = -EFAULT;
1123 goto out_fail;
1124 }
1125 }
1126
David Howells5006a762006-08-22 20:06:12 -04001127 server->client = nfs4_create_client(server, data->timeo, data->retrans,
1128 data->proto, authflavour);
David Howellsf7b422b2006-06-09 09:34:33 -04001129 if (IS_ERR(server->client)) {
1130 err = PTR_ERR(server->client);
1131 dprintk("%s: cannot create RPC client. Error = %d\n",
1132 __FUNCTION__, err);
1133 goto out_fail;
1134 }
1135
1136 sb->s_time_gran = 1;
1137
1138 sb->s_op = &nfs4_sops;
1139 err = nfs_sb_init(sb, authflavour);
1140
1141 out_fail:
1142 return err;
1143}
1144
1145static int nfs4_compare_super(struct super_block *sb, void *data)
1146{
1147 struct nfs_server *server = data;
1148 struct nfs_server *old = NFS_SB(sb);
1149
1150 if (strcmp(server->hostname, old->hostname) != 0)
1151 return 0;
1152 if (strcmp(server->mnt_path, old->mnt_path) != 0)
1153 return 0;
1154 return 1;
1155}
1156
1157static void *
1158nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
1159{
1160 void *p = NULL;
1161
1162 if (!src->len)
1163 return ERR_PTR(-EINVAL);
1164 if (src->len < maxlen)
1165 maxlen = src->len;
1166 if (dst == NULL) {
1167 p = dst = kmalloc(maxlen + 1, GFP_KERNEL);
1168 if (p == NULL)
1169 return ERR_PTR(-ENOMEM);
1170 }
1171 if (copy_from_user(dst, src->data, maxlen)) {
1172 kfree(p);
1173 return ERR_PTR(-EFAULT);
1174 }
1175 dst[maxlen] = '\0';
1176 return dst;
1177}
1178
Trond Myklebust816724e2006-06-24 08:41:41 -04001179static int nfs4_get_sb(struct file_system_type *fs_type,
1180 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
David Howellsf7b422b2006-06-09 09:34:33 -04001181{
1182 int error;
1183 struct nfs_server *server;
1184 struct super_block *s;
1185 struct nfs4_mount_data *data = raw_data;
1186 void *p;
1187
1188 if (data == NULL) {
1189 dprintk("%s: missing data argument\n", __FUNCTION__);
Trond Myklebust816724e2006-06-24 08:41:41 -04001190 return -EINVAL;
David Howellsf7b422b2006-06-09 09:34:33 -04001191 }
1192 if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) {
1193 dprintk("%s: bad mount version\n", __FUNCTION__);
Trond Myklebust816724e2006-06-24 08:41:41 -04001194 return -EINVAL;
David Howellsf7b422b2006-06-09 09:34:33 -04001195 }
1196
1197 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
1198 if (!server)
Trond Myklebust816724e2006-06-24 08:41:41 -04001199 return -ENOMEM;
David Howellsf7b422b2006-06-09 09:34:33 -04001200 /* Zero out the NFS state stuff */
1201 init_nfsv4_state(server);
David Howells5006a762006-08-22 20:06:12 -04001202 server->client = server->client_acl = ERR_PTR(-EINVAL);
David Howellsf7b422b2006-06-09 09:34:33 -04001203
1204 p = nfs_copy_user_string(NULL, &data->hostname, 256);
1205 if (IS_ERR(p))
1206 goto out_err;
1207 server->hostname = p;
1208
1209 p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
1210 if (IS_ERR(p))
1211 goto out_err;
1212 server->mnt_path = p;
1213
1214 p = nfs_copy_user_string(server->ip_addr, &data->client_addr,
1215 sizeof(server->ip_addr) - 1);
1216 if (IS_ERR(p))
1217 goto out_err;
1218
1219 /* We now require that the mount process passes the remote address */
1220 if (data->host_addrlen != sizeof(server->addr)) {
Trond Myklebust816724e2006-06-24 08:41:41 -04001221 error = -EINVAL;
David Howellsf7b422b2006-06-09 09:34:33 -04001222 goto out_free;
1223 }
1224 if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
Trond Myklebust816724e2006-06-24 08:41:41 -04001225 error = -EFAULT;
David Howellsf7b422b2006-06-09 09:34:33 -04001226 goto out_free;
1227 }
1228 if (server->addr.sin_family != AF_INET ||
1229 server->addr.sin_addr.s_addr == INADDR_ANY) {
1230 dprintk("%s: mount program didn't pass remote IP address!\n",
1231 __FUNCTION__);
Trond Myklebust816724e2006-06-24 08:41:41 -04001232 error = -EINVAL;
David Howellsf7b422b2006-06-09 09:34:33 -04001233 goto out_free;
1234 }
1235
David Howellsf7b422b2006-06-09 09:34:33 -04001236 s = sget(fs_type, nfs4_compare_super, nfs_set_super, server);
Trond Myklebust816724e2006-06-24 08:41:41 -04001237 if (IS_ERR(s)) {
1238 error = PTR_ERR(s);
David Howellsf7b422b2006-06-09 09:34:33 -04001239 goto out_free;
Trond Myklebust816724e2006-06-24 08:41:41 -04001240 }
1241
1242 if (s->s_root) {
1243 kfree(server->mnt_path);
1244 kfree(server->hostname);
1245 kfree(server);
1246 return simple_set_mnt(mnt, s);
1247 }
David Howellsf7b422b2006-06-09 09:34:33 -04001248
1249 s->s_flags = flags;
1250
1251 error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
1252 if (error) {
1253 up_write(&s->s_umount);
1254 deactivate_super(s);
Trond Myklebust816724e2006-06-24 08:41:41 -04001255 return error;
David Howellsf7b422b2006-06-09 09:34:33 -04001256 }
1257 s->s_flags |= MS_ACTIVE;
Trond Myklebust816724e2006-06-24 08:41:41 -04001258 return simple_set_mnt(mnt, s);
David Howellsf7b422b2006-06-09 09:34:33 -04001259out_err:
Trond Myklebust816724e2006-06-24 08:41:41 -04001260 error = PTR_ERR(p);
David Howellsf7b422b2006-06-09 09:34:33 -04001261out_free:
1262 kfree(server->mnt_path);
1263 kfree(server->hostname);
1264 kfree(server);
Trond Myklebust816724e2006-06-24 08:41:41 -04001265 return error;
David Howellsf7b422b2006-06-09 09:34:33 -04001266}
1267
1268static void nfs4_kill_super(struct super_block *sb)
1269{
1270 struct nfs_server *server = NFS_SB(sb);
1271
1272 nfs_return_all_delegations(sb);
1273 kill_anon_super(sb);
1274
1275 nfs4_renewd_prepare_shutdown(server);
1276
1277 if (server->client != NULL && !IS_ERR(server->client))
1278 rpc_shutdown_client(server->client);
1279
1280 destroy_nfsv4_state(server);
1281
David Howellsf7b422b2006-06-09 09:34:33 -04001282 nfs_free_iostats(server->io_stats);
1283 kfree(server->hostname);
1284 kfree(server);
1285 nfs_release_automount_timer();
1286}
1287
1288/*
1289 * Constructs the SERVER-side path
1290 */
1291static inline char *nfs4_dup_path(const struct dentry *dentry)
1292{
1293 char *page = (char *) __get_free_page(GFP_USER);
1294 char *path;
1295
1296 path = nfs4_path(dentry, page, PAGE_SIZE);
1297 if (!IS_ERR(path)) {
1298 int len = PAGE_SIZE + page - path;
1299 char *tmp = path;
1300
1301 path = kmalloc(len, GFP_KERNEL);
1302 if (path)
1303 memcpy(path, tmp, len);
1304 else
1305 path = ERR_PTR(-ENOMEM);
1306 }
1307 free_page((unsigned long)page);
1308 return path;
1309}
1310
1311static struct super_block *nfs4_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data)
1312{
1313 const struct dentry *dentry = data->dentry;
David Howells7539bba2006-08-22 20:06:09 -04001314 struct nfs_client *clp = server->nfs_client;
David Howellsf7b422b2006-06-09 09:34:33 -04001315 struct super_block *sb;
1316
1317 server->fsid = data->fattr->fsid;
1318 nfs_copy_fh(&server->fh, data->fh);
1319 server->mnt_path = nfs4_dup_path(dentry);
1320 if (IS_ERR(server->mnt_path)) {
1321 sb = (struct super_block *)server->mnt_path;
1322 goto err;
1323 }
1324 sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
1325 if (IS_ERR(sb) || sb->s_root)
1326 goto free_path;
1327 nfs4_server_capabilities(server, &server->fh);
1328
1329 down_write(&clp->cl_sem);
David Howellsf7b422b2006-06-09 09:34:33 -04001330 list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
1331 up_write(&clp->cl_sem);
1332 return sb;
1333free_path:
1334 kfree(server->mnt_path);
1335err:
1336 server->mnt_path = NULL;
1337 return sb;
1338}
1339
Trond Myklebust816724e2006-06-24 08:41:41 -04001340static int nfs_clone_nfs4_sb(struct file_system_type *fs_type,
1341 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
David Howellsf7b422b2006-06-09 09:34:33 -04001342{
1343 struct nfs_clone_mount *data = raw_data;
Trond Myklebust816724e2006-06-24 08:41:41 -04001344 return nfs_clone_generic_sb(data, nfs4_clone_sb, nfs_clone_server, mnt);
David Howellsf7b422b2006-06-09 09:34:33 -04001345}
1346
1347static struct super_block *nfs4_referral_sb(struct nfs_server *server, struct nfs_clone_mount *data)
1348{
1349 struct super_block *sb = ERR_PTR(-ENOMEM);
1350 int len;
1351
1352 len = strlen(data->mnt_path) + 1;
1353 server->mnt_path = kmalloc(len, GFP_KERNEL);
1354 if (server->mnt_path == NULL)
1355 goto err;
1356 memcpy(server->mnt_path, data->mnt_path, len);
1357 memcpy(&server->addr, data->addr, sizeof(struct sockaddr_in));
1358
1359 sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
1360 if (IS_ERR(sb) || sb->s_root)
1361 goto free_path;
1362 return sb;
1363free_path:
1364 kfree(server->mnt_path);
1365err:
1366 server->mnt_path = NULL;
1367 return sb;
1368}
1369
1370static struct nfs_server *nfs4_referral_server(struct super_block *sb, struct nfs_clone_mount *data)
1371{
1372 struct nfs_server *server = NFS_SB(sb);
David Howellsf7b422b2006-06-09 09:34:33 -04001373 int proto, timeo, retrans;
1374 void *err;
1375
1376 proto = IPPROTO_TCP;
1377 /* Since we are following a referral and there may be alternatives,
1378 set the timeouts and retries to low values */
1379 timeo = 2;
1380 retrans = 1;
David Howellsf7b422b2006-06-09 09:34:33 -04001381
David Howells27951bd2006-08-22 20:06:11 -04001382 nfs_put_client(server->nfs_client);
1383 server->nfs_client = NULL;
David Howells5006a762006-08-22 20:06:12 -04001384 server->client = nfs4_create_client(server, timeo, retrans, proto,
1385 data->authflavor);
David Howellsf7b422b2006-06-09 09:34:33 -04001386 if (IS_ERR((err = server->client)))
1387 goto out_err;
1388
1389 sb->s_time_gran = 1;
1390 sb->s_op = &nfs4_sops;
1391 err = ERR_PTR(nfs_sb_init(sb, data->authflavor));
1392 if (!IS_ERR(err))
1393 return server;
1394out_err:
1395 return (struct nfs_server *)err;
1396}
1397
Trond Myklebust816724e2006-06-24 08:41:41 -04001398static int nfs_referral_nfs4_sb(struct file_system_type *fs_type,
1399 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
David Howellsf7b422b2006-06-09 09:34:33 -04001400{
1401 struct nfs_clone_mount *data = raw_data;
Trond Myklebust816724e2006-06-24 08:41:41 -04001402 return nfs_clone_generic_sb(data, nfs4_referral_sb, nfs4_referral_server, mnt);
David Howellsf7b422b2006-06-09 09:34:33 -04001403}
1404
1405#endif