aboutsummaryrefslogtreecommitdiffstats
path: root/fs/nfs/super.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-08-22 20:06:13 -0400
committerTrond Myklebust <Trond.Myklebust@netapp.com>2006-09-22 23:24:37 -0400
commit54ceac4515986030c2502960be620198dd8fe25b (patch)
treeb4ae4305c5652c0fe883ef5ea3243da91dbd2b34 /fs/nfs/super.c
parentcf6d7b5de8535a9f0088c5cc28ee2dae87371b4a (diff)
NFS: Share NFS superblocks per-protocol per-server per-FSID
The attached patch makes NFS share superblocks between mounts from the same server and FSID over the same protocol. It does this by creating each superblock with a false root and returning the real root dentry in the vfsmount presented by get_sb(). The root dentry set starts off as an anonymous dentry if we don't already have the dentry for its inode, otherwise it simply returns the dentry we already have. We may thus end up with several trees of dentries in the superblock, and if at some later point one of anonymous tree roots is discovered by normal filesystem activity to be located in another tree within the superblock, the anonymous root is named and materialises attached to the second tree at the appropriate point. Why do it this way? Why not pass an extra argument to the mount() syscall to indicate the subpath and then pathwalk from the server root to the desired directory? You can't guarantee this will work for two reasons: (1) The root and intervening nodes may not be accessible to the client. With NFS2 and NFS3, for instance, mountd is called on the server to get the filehandle for the tip of a path. mountd won't give us handles for anything we don't have permission to access, and so we can't set up NFS inodes for such nodes, and so can't easily set up dentries (we'd have to have ghost inodes or something). With this patch we don't actually create dentries until we get handles from the server that we can use to set up their inodes, and we don't actually bind them into the tree until we know for sure where they go. (2) Inaccessible symbolic links. If we're asked to mount two exports from the server, eg: mount warthog:/warthog/aaa/xxx /mmm mount warthog:/warthog/bbb/yyy /nnn We may not be able to access anything nearer the root than xxx and yyy, but we may find out later that /mmm/www/yyy, say, is actually the same directory as the one mounted on /nnn. What we might then find out, for example, is that /warthog/bbb was actually a symbolic link to /warthog/aaa/xxx/www, but we can't actually determine that by talking to the server until /warthog is made available by NFS. This would lead to having constructed an errneous dentry tree which we can't easily fix. We can end up with a dentry marked as a directory when it should actually be a symlink, or we could end up with an apparently hardlinked directory. With this patch we need not make assumptions about the type of a dentry for which we can't retrieve information, nor need we assume we know its place in the grand scheme of things until we actually see that place. This patch reduces the possibility of aliasing in the inode and page caches for inodes that may be accessed by more than one NFS export. It also reduces the number of superblocks required for NFS where there are many NFS exports being used from a server (home directory server + autofs for example). This in turn makes it simpler to do local caching of network filesystems, as it can then be guaranteed that there won't be links from multiple inodes in separate superblocks to the same cache file. Obviously, cache aliasing between different levels of NFS protocol could still be a problem, but at least that gives us another key to use when indexing the cache. This patch makes the following changes: (1) The server record construction/destruction has been abstracted out into its own set of functions to make things easier to get right. These have been moved into fs/nfs/client.c. All the code in fs/nfs/client.c has to do with the management of connections to servers, and doesn't touch superblocks in any way; the remaining code in fs/nfs/super.c has to do with VFS superblock management. (2) The sequence of events undertaken by NFS mount is now reordered: (a) A volume representation (struct nfs_server) is allocated. (b) A server representation (struct nfs_client) is acquired. This may be allocated or shared, and is keyed on server address, port and NFS version. (c) If allocated, the client representation is initialised. The state member variable of nfs_client is used to prevent a race during initialisation from two mounts. (d) For NFS4 a simple pathwalk is performed, walking from FH to FH to find the root filehandle for the mount (fs/nfs/getroot.c). For NFS2/3 we are given the root FH in advance. (e) The volume FSID is probed for on the root FH. (f) The volume representation is initialised from the FSINFO record retrieved on the root FH. (g) sget() is called to acquire a superblock. This may be allocated or shared, keyed on client pointer and FSID. (h) If allocated, the superblock is initialised. (i) If the superblock is shared, then the new nfs_server record is discarded. (j) The root dentry for this mount is looked up from the root FH. (k) The root dentry for this mount is assigned to the vfsmount. (3) nfs_readdir_lookup() creates dentries for each of the entries readdir() returns; this function now attaches disconnected trees from alternate roots that happen to be discovered attached to a directory being read (in the same way nfs_lookup() is made to do for lookup ops). The new d_materialise_unique() function is now used to do this, thus permitting the whole thing to be done under one set of locks, and thus avoiding any race between mount and lookup operations on the same directory. (4) The client management code uses a new debug facility: NFSDBG_CLIENT which is set by echoing 1024 to /proc/net/sunrpc/nfs_debug. (5) Clone mounts are now called xdev mounts. (6) Use the dentry passed to the statfs() op as the handle for retrieving fs statistics rather than the root dentry of the superblock (which is now a dummy). Signed-Off-By: David Howells <dhowells@redhat.com> Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'fs/nfs/super.c')
-rw-r--r--fs/nfs/super.c1207
1 files changed, 444 insertions, 763 deletions
diff --git a/fs/nfs/super.c b/fs/nfs/super.c
index 5842d510d732..867b5dcd3a40 100644
--- a/fs/nfs/super.c
+++ b/fs/nfs/super.c
@@ -13,6 +13,11 @@
13 * 13 *
14 * Split from inode.c by David Howells <dhowells@redhat.com> 14 * Split from inode.c by David Howells <dhowells@redhat.com>
15 * 15 *
16 * - superblocks are indexed on server only - all inodes, dentries, etc. associated with a
17 * particular server are held in the same superblock
18 * - NFS superblocks can have several effective roots to the dentry tree
19 * - directory type roots are spliced into the tree when a path from one root reaches the root
20 * of another (see nfs_lookup())
16 */ 21 */
17 22
18#include <linux/config.h> 23#include <linux/config.h>
@@ -52,20 +57,12 @@
52 57
53#define NFSDBG_FACILITY NFSDBG_VFS 58#define NFSDBG_FACILITY NFSDBG_VFS
54 59
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
63static void nfs_umount_begin(struct vfsmount *, int); 60static void nfs_umount_begin(struct vfsmount *, int);
64static int nfs_statfs(struct dentry *, struct kstatfs *); 61static int nfs_statfs(struct dentry *, struct kstatfs *);
65static int nfs_show_options(struct seq_file *, struct vfsmount *); 62static int nfs_show_options(struct seq_file *, struct vfsmount *);
66static int nfs_show_stats(struct seq_file *, struct vfsmount *); 63static int nfs_show_stats(struct seq_file *, struct vfsmount *);
67static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); 64static 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, 65static int nfs_xdev_get_sb(struct file_system_type *fs_type,
69 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 66 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
70static void nfs_kill_super(struct super_block *); 67static void nfs_kill_super(struct super_block *);
71 68
@@ -77,10 +74,10 @@ static struct file_system_type nfs_fs_type = {
77 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 74 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
78}; 75};
79 76
80struct file_system_type clone_nfs_fs_type = { 77struct file_system_type nfs_xdev_fs_type = {
81 .owner = THIS_MODULE, 78 .owner = THIS_MODULE,
82 .name = "nfs", 79 .name = "nfs",
83 .get_sb = nfs_clone_nfs_sb, 80 .get_sb = nfs_xdev_get_sb,
84 .kill_sb = nfs_kill_super, 81 .kill_sb = nfs_kill_super,
85 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 82 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
86}; 83};
@@ -99,10 +96,10 @@ static struct super_operations nfs_sops = {
99#ifdef CONFIG_NFS_V4 96#ifdef CONFIG_NFS_V4
100static int nfs4_get_sb(struct file_system_type *fs_type, 97static int nfs4_get_sb(struct file_system_type *fs_type,
101 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 98 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
102static int nfs_clone_nfs4_sb(struct file_system_type *fs_type, 99static int nfs4_xdev_get_sb(struct file_system_type *fs_type,
103 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 100 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
104static int nfs_referral_nfs4_sb(struct file_system_type *fs_type, 101static int nfs4_referral_get_sb(struct file_system_type *fs_type,
105 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); 102 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
106static void nfs4_kill_super(struct super_block *sb); 103static void nfs4_kill_super(struct super_block *sb);
107 104
108static struct file_system_type nfs4_fs_type = { 105static struct file_system_type nfs4_fs_type = {
@@ -113,18 +110,18 @@ static struct file_system_type nfs4_fs_type = {
113 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 110 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
114}; 111};
115 112
116struct file_system_type clone_nfs4_fs_type = { 113struct file_system_type nfs4_xdev_fs_type = {
117 .owner = THIS_MODULE, 114 .owner = THIS_MODULE,
118 .name = "nfs4", 115 .name = "nfs4",
119 .get_sb = nfs_clone_nfs4_sb, 116 .get_sb = nfs4_xdev_get_sb,
120 .kill_sb = nfs4_kill_super, 117 .kill_sb = nfs4_kill_super,
121 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 118 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
122}; 119};
123 120
124struct file_system_type nfs_referral_nfs4_fs_type = { 121struct file_system_type nfs4_referral_fs_type = {
125 .owner = THIS_MODULE, 122 .owner = THIS_MODULE,
126 .name = "nfs4", 123 .name = "nfs4",
127 .get_sb = nfs_referral_nfs4_sb, 124 .get_sb = nfs4_referral_get_sb,
128 .kill_sb = nfs4_kill_super, 125 .kill_sb = nfs4_kill_super,
129 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, 126 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
130}; 127};
@@ -345,7 +342,7 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt)
345 nfs_show_mount_options(m, nfss, 0); 342 nfs_show_mount_options(m, nfss, 0);
346 343
347 seq_puts(m, ",addr="); 344 seq_puts(m, ",addr=");
348 seq_escape(m, nfss->hostname, " \t\n\\"); 345 seq_escape(m, nfss->nfs_client->cl_hostname, " \t\n\\");
349 346
350 return 0; 347 return 0;
351} 348}
@@ -429,714 +426,351 @@ static int nfs_show_stats(struct seq_file *m, struct vfsmount *mnt)
429 426
430/* 427/*
431 * Begin unmount by attempting to remove all automounted mountpoints we added 428 * Begin unmount by attempting to remove all automounted mountpoints we added
432 * in response to traversals 429 * in response to xdev traversals and referrals
433 */ 430 */
434static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags) 431static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
435{ 432{
436 struct nfs_server *server;
437 struct rpc_clnt *rpc;
438
439 shrink_submounts(vfsmnt, &nfs_automount_list); 433 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} 434}
451 435
452/* 436/*
453 * Obtain the root inode of the file system. 437 * Validate the NFS2/NFS3 mount data
438 * - fills in the mount root filehandle
454 */ 439 */
455static struct inode * 440static int nfs_validate_mount_data(struct nfs_mount_data *data,
456nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo) 441 struct nfs_fh *mntfh)
457{ 442{
458 struct nfs_server *server = NFS_SB(sb); 443 if (data == NULL) {
459 int error; 444 dprintk("%s: missing data argument\n", __FUNCTION__);
460 445 return -EINVAL;
461 error = server->nfs_client->rpc_ops->getroot(server, rootfh, fsinfo);
462 if (error < 0) {
463 dprintk("nfs_get_root: getattr error = %d\n", -error);
464 return ERR_PTR(error);
465 } 446 }
466 447
467 server->fsid = fsinfo->fattr->fsid; 448 if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
468 return nfs_fhget(sb, rootfh, fsinfo->fattr); 449 dprintk("%s: bad mount version\n", __FUNCTION__);
469} 450 return -EINVAL;
470 451 }
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 452
500 root_inode = nfs_get_root(sb, &server->fh, &fsinfo); 453 switch (data->version) {
501 /* Did getting the root inode fail? */ 454 case 1:
502 if (IS_ERR(root_inode)) { 455 data->namlen = 0;
503 no_root_error = PTR_ERR(root_inode); 456 case 2:
504 goto out_no_root; 457 data->bsize = 0;
458 case 3:
459 if (data->flags & NFS_MOUNT_VER3) {
460 dprintk("%s: mount structure version %d does not support NFSv3\n",
461 __FUNCTION__,
462 data->version);
463 return -EINVAL;
464 }
465 data->root.size = NFS2_FHSIZE;
466 memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
467 case 4:
468 if (data->flags & NFS_MOUNT_SECFLAVOUR) {
469 dprintk("%s: mount structure version %d does not support strong security\n",
470 __FUNCTION__,
471 data->version);
472 return -EINVAL;
473 }
474 /* Fill in pseudoflavor for mount version < 5 */
475 data->pseudoflavor = RPC_AUTH_UNIX;
476 case 5:
477 memset(data->context, 0, sizeof(data->context));
505 } 478 }
506 sb->s_root = d_alloc_root(root_inode); 479
507 if (!sb->s_root) { 480#ifndef CONFIG_NFS_V3
508 no_root_error = -ENOMEM; 481 /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
509 goto out_no_root; 482 if (data->flags & NFS_MOUNT_VER3) {
483 dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
484 return -EPROTONOSUPPORT;
510 } 485 }
511 sb->s_root->d_op = server->nfs_client->rpc_ops->dentry_ops; 486#endif /* CONFIG_NFS_V3 */
512
513 /* mount time stamp, in seconds */
514 server->mount_time = jiffies;
515
516 /* Get some general file system info */
517 if (server->namelen == 0 &&
518 server->nfs_client->rpc_ops->pathconf(server, &server->fh, &pathinfo) >= 0)
519 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 487
544 if (sb->s_blocksize == 0) 488 /* We now require that the mount process passes the remote address */
545 sb->s_blocksize = nfs_block_bits(server->wsize, 489 if (data->addr.sin_addr.s_addr == INADDR_ANY) {
546 &sb->s_blocksize_bits); 490 dprintk("%s: mount program didn't pass remote address!\n",
547 server->wtmult = nfs_block_bits(fsinfo.wtmult, NULL); 491 __FUNCTION__);
548 492 return -EINVAL;
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 } 493 }
560 server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
561 494
562 nfs_super_set_maxbytes(sb, fsinfo.maxfilesize); 495 /* Prepare the root filehandle */
496 if (data->flags & NFS_MOUNT_VER3)
497 mntfh->size = data->root.size;
498 else
499 mntfh->size = NFS2_FHSIZE;
563 500
564 server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0; 501 if (mntfh->size > sizeof(mntfh->data)) {
565 server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0; 502 dprintk("%s: invalid root filehandle\n", __FUNCTION__);
503 return -EINVAL;
504 }
505
506 memcpy(mntfh->data, data->root.data, mntfh->size);
507 if (mntfh->size < sizeof(mntfh->data))
508 memset(mntfh->data + mntfh->size, 0,
509 sizeof(mntfh->data) - mntfh->size);
566 510
567 /* We're airborne Set socket buffersize */
568 rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
569 return 0; 511 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} 512}
577 513
578/* 514/*
579 * Create an RPC client handle. 515 * Initialise the common bits of the superblock
580 */ 516 */
581static struct rpc_clnt * 517static inline void nfs_initialise_sb(struct super_block *sb)
582nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
583{ 518{
584 struct nfs_client *clp; 519 struct nfs_server *server = NFS_SB(sb);
585 struct rpc_clnt *clnt;
586 int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
587 int nfsversion = 2;
588 int err;
589
590#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);
596 if (!clp) {
597 dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
598 return ERR_PTR(PTR_ERR(clp));
599 }
600
601 if (clp->cl_cons_state == NFS_CS_INITING) {
602 /* Check NFS protocol revision and initialize RPC op
603 * vector and file handle pool. */
604#ifdef CONFIG_NFS_V3
605 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 }
611#else
612 clp->rpc_ops = &nfs_v2_clientops;
613#endif
614
615 /* 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);
622 }
623 520
624 /* create an nfs_server-specific client */ 521 sb->s_magic = NFS_SUPER_MAGIC;
625 clnt = rpc_clone_client(clp->cl_rpcclient);
626 if (IS_ERR(clnt)) {
627 dprintk("%s: couldn't create rpc_client!\n", __FUNCTION__);
628 nfs_put_client(clp);
629 return ERR_PTR(PTR_ERR(clnt));
630 }
631 522
632 if (data->pseudoflavor != clp->cl_rpcclient->cl_auth->au_flavor) { 523 /* We probably want something more informative here */
633 struct rpc_auth *auth; 524 snprintf(sb->s_id, sizeof(sb->s_id),
525 "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
634 526
635 auth = rpcauth_create(data->pseudoflavor, server->client); 527 if (sb->s_blocksize == 0)
636 if (IS_ERR(auth)) { 528 sb->s_blocksize = nfs_block_bits(server->wsize,
637 dprintk("%s: couldn't create credcache!\n", __FUNCTION__); 529 &sb->s_blocksize_bits);
638 return ERR_PTR(PTR_ERR(auth));
639 }
640 }
641 530
642 server->nfs_client = clp; 531 if (server->flags & NFS_MOUNT_NOAC)
643 return clnt; 532 sb->s_flags |= MS_SYNCHRONOUS;
644 533
645client_init_error: 534 nfs_super_set_maxbytes(sb, server->maxfilesize);
646 nfs_mark_client_ready(clp, err);
647 nfs_put_client(clp);
648 return ERR_PTR(err);
649} 535}
650 536
651/* 537/*
652 * Clone a server record 538 * Finish setting up an NFS2/3 superblock
653 */ 539 */
654static struct nfs_server *nfs_clone_server(struct super_block *sb, struct nfs_clone_mount *data) 540static void nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data)
655{ 541{
656 struct nfs_server *server = NFS_SB(sb); 542 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
667 server->client_acl = ERR_PTR(-EINVAL);
668 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
676 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);
690 sb->s_root->d_op = server->nfs_client->rpc_ops->dentry_ops;
691 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 */
702static int nfs_clone_generic_sb(struct nfs_clone_mount *data,
703 struct super_block *(*fill_sb)(struct nfs_server *, struct nfs_clone_mount *),
704 struct nfs_server *(*fill_server)(struct super_block *, struct nfs_clone_mount *),
705 struct vfsmount *mnt)
706{
707 struct nfs_server *server;
708 struct nfs_server *parent = NFS_SB(data->sb);
709 struct super_block *sb = ERR_PTR(-EINVAL);
710 char *hostname;
711 int error = -ENOMEM;
712 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));
718 atomic_inc(&server->nfs_client->cl_count);
719 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);
725
726 sb = fill_sb(server, data);
727 if (IS_ERR(sb)) {
728 error = PTR_ERR(sb);
729 goto free_hostname;
730 }
731 543
732 if (sb->s_root) 544 sb->s_blocksize_bits = 0;
733 goto out_share; 545 sb->s_blocksize = 0;
546 if (data->bsize)
547 sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
734 548
735 server = fill_server(sb, data); 549 if (server->flags & NFS_MOUNT_VER3) {
736 if (IS_ERR(server)) { 550 /* The VFS shouldn't apply the umask to mode bits. We will do
737 error = PTR_ERR(server); 551 * so ourselves when necessary.
738 goto out_deactivate; 552 */
553 sb->s_flags |= MS_POSIXACL;
554 sb->s_time_gran = 1;
739 } 555 }
740 return simple_set_mnt(mnt, sb); 556
741out_deactivate: 557 sb->s_op = &nfs_sops;
742 up_write(&sb->s_umount); 558 nfs_initialise_sb(sb);
743 deactivate_super(sb);
744 return error;
745out_share:
746 kfree(server->hostname);
747 nfs_put_client(server->nfs_client);
748 kfree(server);
749 return simple_set_mnt(mnt, sb);
750free_hostname:
751 kfree(server->hostname);
752free_server:
753 nfs_put_client(server->nfs_client);
754 kfree(server);
755out_err:
756 return error;
757} 559}
758 560
759/* 561/*
760 * Set up an NFS2/3 superblock 562 * Finish setting up a cloned NFS2/3 superblock
761 *
762 * The way this works is that the mount process passes a structure
763 * in the data argument which contains the server's IP address
764 * and the root file handle obtained from the server's mount
765 * daemon. We stash these away in the private superblock fields.
766 */ 563 */
767static int 564static void nfs_clone_super(struct super_block *sb,
768nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent) 565 const struct super_block *old_sb)
769{ 566{
770 struct nfs_server *server; 567 struct nfs_server *server = NFS_SB(sb);
771 rpc_authflavor_t authflavor; 568
569 sb->s_blocksize_bits = old_sb->s_blocksize_bits;
570 sb->s_blocksize = old_sb->s_blocksize;
571 sb->s_maxbytes = old_sb->s_maxbytes;
772 572
773 server = NFS_SB(sb);
774 sb->s_blocksize_bits = 0;
775 sb->s_blocksize = 0;
776 if (data->bsize)
777 sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
778 if (data->rsize)
779 server->rsize = nfs_block_size(data->rsize, NULL);
780 if (data->wsize)
781 server->wsize = nfs_block_size(data->wsize, NULL);
782 server->flags = data->flags & NFS_MOUNT_FLAGMASK;
783
784 server->acregmin = data->acregmin*HZ;
785 server->acregmax = data->acregmax*HZ;
786 server->acdirmin = data->acdirmin*HZ;
787 server->acdirmax = data->acdirmax*HZ;
788
789 /* Start lockd here, before we might error out */
790 if (!(server->flags & NFS_MOUNT_NONLM))
791 lockd_up();
792
793 server->namelen = data->namlen;
794 server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
795 if (!server->hostname)
796 return -ENOMEM;
797 strcpy(server->hostname, data->hostname);
798
799 /* Fill in pseudoflavor for mount version < 5 */
800 if (!(data->flags & NFS_MOUNT_SECFLAVOUR))
801 data->pseudoflavor = RPC_AUTH_UNIX;
802 authflavor = data->pseudoflavor; /* save for sb_init() */
803 /* XXX maybe we want to add a server->pseudoflavor field */
804
805 /* Create RPC client handles */
806 server->client = nfs_create_client(server, data);
807 if (IS_ERR(server->client))
808 return PTR_ERR(server->client);
809
810 /* RFC 2623, sec 2.3.2 */
811 if (server->flags & NFS_MOUNT_VER3) { 573 if (server->flags & NFS_MOUNT_VER3) {
812#ifdef CONFIG_NFS_V3_ACL 574 /* The VFS shouldn't apply the umask to mode bits. We will do
813 if (!(server->flags & NFS_MOUNT_NOACL)) { 575 * so ourselves when necessary.
814 server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
815 /* No errors! Assume that Sun nfsacls are supported */
816 if (!IS_ERR(server->client_acl))
817 server->caps |= NFS_CAP_ACLS;
818 }
819#else
820 server->flags &= ~NFS_MOUNT_NOACL;
821#endif /* CONFIG_NFS_V3_ACL */
822 /*
823 * The VFS shouldn't apply the umask to mode bits. We will
824 * do so ourselves when necessary.
825 */ 576 */
826 sb->s_flags |= MS_POSIXACL; 577 sb->s_flags |= MS_POSIXACL;
827 if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
828 server->namelen = NFS3_MAXNAMLEN;
829 sb->s_time_gran = 1; 578 sb->s_time_gran = 1;
830 } else {
831 if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
832 server->namelen = NFS2_MAXNAMLEN;
833 } 579 }
834 580
835 sb->s_op = &nfs_sops; 581 sb->s_op = old_sb->s_op;
836 return nfs_sb_init(sb, authflavor); 582 nfs_initialise_sb(sb);
837} 583}
838 584
839static int nfs_set_super(struct super_block *s, void *data) 585static int nfs_set_super(struct super_block *s, void *_server)
840{ 586{
841 s->s_fs_info = data; 587 struct nfs_server *server = _server;
842 return set_anon_super(s, data); 588 int ret;
589
590 s->s_fs_info = server;
591 ret = set_anon_super(s, server);
592 if (ret == 0)
593 server->s_dev = s->s_dev;
594 return ret;
843} 595}
844 596
845static int nfs_compare_super(struct super_block *sb, void *data) 597static int nfs_compare_super(struct super_block *sb, void *data)
846{ 598{
847 struct nfs_server *server = data; 599 struct nfs_server *server = data, *old = NFS_SB(sb);
848 struct nfs_server *old = NFS_SB(sb);
849 600
850 if (old->addr.sin_addr.s_addr != server->addr.sin_addr.s_addr) 601 if (old->nfs_client != server->nfs_client)
851 return 0; 602 return 0;
852 if (old->addr.sin_port != server->addr.sin_port) 603 if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0)
853 return 0; 604 return 0;
854 return !nfs_compare_fh(&old->fh, &server->fh); 605 return 1;
855} 606}
856 607
857static int nfs_get_sb(struct file_system_type *fs_type, 608static int nfs_get_sb(struct file_system_type *fs_type,
858 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) 609 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
859{ 610{
860 int error;
861 struct nfs_server *server = NULL; 611 struct nfs_server *server = NULL;
862 struct super_block *s; 612 struct super_block *s;
863 struct nfs_fh *root; 613 struct nfs_fh mntfh;
864 struct nfs_mount_data *data = raw_data; 614 struct nfs_mount_data *data = raw_data;
615 struct dentry *mntroot;
616 int error;
865 617
866 error = -EINVAL; 618 /* Validate the mount data */
867 if (data == NULL) { 619 error = nfs_validate_mount_data(data, &mntfh);
868 dprintk("%s: missing data argument\n", __FUNCTION__); 620 if (error < 0)
869 goto out_err_noserver; 621 return error;
870 }
871 if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
872 dprintk("%s: bad mount version\n", __FUNCTION__);
873 goto out_err_noserver;
874 }
875 switch (data->version) {
876 case 1:
877 data->namlen = 0;
878 case 2:
879 data->bsize = 0;
880 case 3:
881 if (data->flags & NFS_MOUNT_VER3) {
882 dprintk("%s: mount structure version %d does not support NFSv3\n",
883 __FUNCTION__,
884 data->version);
885 goto out_err_noserver;
886 }
887 data->root.size = NFS2_FHSIZE;
888 memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE);
889 case 4:
890 if (data->flags & NFS_MOUNT_SECFLAVOUR) {
891 dprintk("%s: mount structure version %d does not support strong security\n",
892 __FUNCTION__,
893 data->version);
894 goto out_err_noserver;
895 }
896 case 5:
897 memset(data->context, 0, sizeof(data->context));
898 }
899#ifndef CONFIG_NFS_V3
900 /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
901 error = -EPROTONOSUPPORT;
902 if (data->flags & NFS_MOUNT_VER3) {
903 dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
904 goto out_err_noserver;
905 }
906#endif /* CONFIG_NFS_V3 */
907 622
908 error = -ENOMEM; 623 /* Get a volume representation */
909 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); 624 server = nfs_create_server(data, &mntfh);
910 if (!server) 625 if (IS_ERR(server)) {
626 error = PTR_ERR(server);
911 goto out_err_noserver; 627 goto out_err_noserver;
912 /* Zero out the NFS state stuff */
913 init_nfsv4_state(server);
914 server->client = server->client_acl = ERR_PTR(-EINVAL);
915
916 root = &server->fh;
917 if (data->flags & NFS_MOUNT_VER3)
918 root->size = data->root.size;
919 else
920 root->size = NFS2_FHSIZE;
921 error = -EINVAL;
922 if (root->size > sizeof(root->data)) {
923 dprintk("%s: invalid root filehandle\n", __FUNCTION__);
924 goto out_err;
925 }
926 memcpy(root->data, data->root.data, root->size);
927
928 /* We now require that the mount process passes the remote address */
929 memcpy(&server->addr, &data->addr, sizeof(server->addr));
930 if (server->addr.sin_addr.s_addr == INADDR_ANY) {
931 dprintk("%s: mount program didn't pass remote address!\n",
932 __FUNCTION__);
933 goto out_err;
934 } 628 }
935 629
630 /* Get a superblock - note that we may end up sharing one that already exists */
936 s = sget(fs_type, nfs_compare_super, nfs_set_super, server); 631 s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
937 if (IS_ERR(s)) { 632 if (IS_ERR(s)) {
938 error = PTR_ERR(s); 633 error = PTR_ERR(s);
939 goto out_err; 634 goto out_err_nosb;
940 } 635 }
941 636
942 if (s->s_root) 637 if (s->s_fs_info != server) {
943 goto out_share; 638 nfs_free_server(server);
639 server = NULL;
640 }
944 641
945 s->s_flags = flags; 642 if (!s->s_root) {
643 /* initial superblock/root creation */
644 s->s_flags = flags;
645 nfs_fill_super(s, data);
646 }
946 647
947 error = nfs_fill_super(s, data, flags & MS_SILENT ? 1 : 0); 648 mntroot = nfs_get_root(s, &mntfh);
948 if (error) { 649 if (IS_ERR(mntroot)) {
949 up_write(&s->s_umount); 650 error = PTR_ERR(mntroot);
950 deactivate_super(s); 651 goto error_splat_super;
951 return error;
952 } 652 }
953 s->s_flags |= MS_ACTIVE;
954 return simple_set_mnt(mnt, s);
955 653
956out_share: 654 s->s_flags |= MS_ACTIVE;
957 kfree(server); 655 mnt->mnt_sb = s;
958 return simple_set_mnt(mnt, s); 656 mnt->mnt_root = mntroot;
657 return 0;
959 658
960out_err: 659out_err_nosb:
961 kfree(server); 660 nfs_free_server(server);
962out_err_noserver: 661out_err_noserver:
963 return error; 662 return error;
663
664error_splat_super:
665 up_write(&s->s_umount);
666 deactivate_super(s);
667 return error;
964} 668}
965 669
670/*
671 * Destroy an NFS2/3 superblock
672 */
966static void nfs_kill_super(struct super_block *s) 673static void nfs_kill_super(struct super_block *s)
967{ 674{
968 struct nfs_server *server = NFS_SB(s); 675 struct nfs_server *server = NFS_SB(s);
969 676
970 kill_anon_super(s); 677 kill_anon_super(s);
971 678 nfs_free_server(server);
972 if (!IS_ERR(server->client))
973 rpc_shutdown_client(server->client);
974 if (!IS_ERR(server->client_acl))
975 rpc_shutdown_client(server->client_acl);
976
977 if (!(server->flags & NFS_MOUNT_NONLM))
978 lockd_down(); /* release rpc.lockd */
979
980 nfs_free_iostats(server->io_stats);
981 kfree(server->hostname);
982 nfs_put_client(server->nfs_client);
983 kfree(server);
984 nfs_release_automount_timer();
985} 679}
986 680
987static struct super_block *nfs_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data) 681/*
988{ 682 * Clone an NFS2/3 server record on xdev traversal (FSID-change)
989 struct super_block *sb; 683 */
990 684static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
991 server->fsid = data->fattr->fsid; 685 const char *dev_name, void *raw_data,
992 nfs_copy_fh(&server->fh, data->fh); 686 struct vfsmount *mnt)
993 sb = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
994 if (!IS_ERR(sb) && sb->s_root == NULL && !(server->flags & NFS_MOUNT_NONLM))
995 lockd_up();
996 return sb;
997}
998
999static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
1000 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
1001{ 687{
1002 struct nfs_clone_mount *data = raw_data; 688 struct nfs_clone_mount *data = raw_data;
1003 return nfs_clone_generic_sb(data, nfs_clone_sb, nfs_clone_server, mnt); 689 struct super_block *s;
1004} 690 struct nfs_server *server;
691 struct dentry *mntroot;
692 int error;
1005 693
1006#ifdef CONFIG_NFS_V4 694 dprintk("--> nfs_xdev_get_sb()\n");
1007static struct rpc_clnt *nfs4_create_client(struct nfs_server *server,
1008 int timeo, int retrans, int proto, rpc_authflavor_t flavor)
1009{
1010 struct nfs_client *clp;
1011 struct rpc_clnt *clnt = NULL;
1012 int err = -EIO;
1013
1014 clp = nfs_get_client(server->hostname, &server->addr, 4);
1015 if (!clp) {
1016 dprintk("%s: failed to create NFS4 client.\n", __FUNCTION__);
1017 return ERR_PTR(err);
1018 }
1019 695
1020 /* Now create transport and client */ 696 /* create a new volume representation */
1021 if (clp->cl_cons_state == NFS_CS_INITING) { 697 server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
1022 clp->rpc_ops = &nfs_v4_clientops; 698 if (IS_ERR(server)) {
699 error = PTR_ERR(server);
700 goto out_err_noserver;
701 }
1023 702
1024 err = nfs_create_rpc_client(clp, proto, timeo, retrans, flavor); 703 /* Get a superblock - note that we may end up sharing one that already exists */
1025 if (err < 0) 704 s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
1026 goto client_init_error; 705 if (IS_ERR(s)) {
706 error = PTR_ERR(s);
707 goto out_err_nosb;
708 }
1027 709
1028 memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr)); 710 if (s->s_fs_info != server) {
1029 err = nfs_idmap_new(clp); 711 nfs_free_server(server);
1030 if (err < 0) { 712 server = NULL;
1031 dprintk("%s: failed to create idmapper.\n",
1032 __FUNCTION__);
1033 goto client_init_error;
1034 }
1035 __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
1036 nfs_mark_client_ready(clp, 0);
1037 } 713 }
1038 714
1039 clnt = rpc_clone_client(clp->cl_rpcclient); 715 if (!s->s_root) {
716 /* initial superblock/root creation */
717 s->s_flags = flags;
718 nfs_clone_super(s, data->sb);
719 }
1040 720
1041 if (IS_ERR(clnt)) { 721 mntroot = nfs_get_root(s, data->fh);
1042 dprintk("%s: cannot create RPC client. Error = %d\n", 722 if (IS_ERR(mntroot)) {
1043 __FUNCTION__, err); 723 error = PTR_ERR(mntroot);
1044 return clnt; 724 goto error_splat_super;
1045 } 725 }
1046 726
1047 if (clnt->cl_auth->au_flavor != flavor) { 727 s->s_flags |= MS_ACTIVE;
1048 struct rpc_auth *auth; 728 mnt->mnt_sb = s;
729 mnt->mnt_root = mntroot;
1049 730
1050 auth = rpcauth_create(flavor, clnt); 731 dprintk("<-- nfs_xdev_get_sb() = 0\n");
1051 if (IS_ERR(auth)) { 732 return 0;
1052 dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
1053 return (struct rpc_clnt *)auth;
1054 }
1055 }
1056 733
1057 server->nfs_client = clp; 734out_err_nosb:
1058 down_write(&clp->cl_sem); 735 nfs_free_server(server);
1059 list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks); 736out_err_noserver:
1060 up_write(&clp->cl_sem); 737 dprintk("<-- nfs_xdev_get_sb() = %d [error]\n", error);
1061 return clnt; 738 return error;
1062 739
1063client_init_error: 740error_splat_super:
1064 nfs_mark_client_ready(clp, err); 741 up_write(&s->s_umount);
1065 nfs_put_client(clp); 742 deactivate_super(s);
1066 return ERR_PTR(err); 743 dprintk("<-- nfs_xdev_get_sb() = %d [splat]\n", error);
744 return error;
1067} 745}
1068 746
747#ifdef CONFIG_NFS_V4
748
1069/* 749/*
1070 * Set up an NFS4 superblock 750 * Finish setting up a cloned NFS4 superblock
1071 */ 751 */
1072static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent) 752static void nfs4_clone_super(struct super_block *sb,
753 const struct super_block *old_sb)
1073{ 754{
1074 struct nfs_server *server; 755 sb->s_blocksize_bits = old_sb->s_blocksize_bits;
1075 rpc_authflavor_t authflavour; 756 sb->s_blocksize = old_sb->s_blocksize;
1076 int err = -EIO; 757 sb->s_maxbytes = old_sb->s_maxbytes;
1077
1078 sb->s_blocksize_bits = 0;
1079 sb->s_blocksize = 0;
1080 server = NFS_SB(sb);
1081 if (data->rsize != 0)
1082 server->rsize = nfs_block_size(data->rsize, NULL);
1083 if (data->wsize != 0)
1084 server->wsize = nfs_block_size(data->wsize, NULL);
1085 server->flags = data->flags & NFS_MOUNT_FLAGMASK;
1086 server->caps = NFS_CAP_ATOMIC_OPEN;
1087
1088 server->acregmin = data->acregmin*HZ;
1089 server->acregmax = data->acregmax*HZ;
1090 server->acdirmin = data->acdirmin*HZ;
1091 server->acdirmax = data->acdirmax*HZ;
1092
1093 /* Now create transport and client */
1094 authflavour = RPC_AUTH_UNIX;
1095 if (data->auth_flavourlen != 0) {
1096 if (data->auth_flavourlen != 1) {
1097 dprintk("%s: Invalid number of RPC auth flavours %d.\n",
1098 __FUNCTION__, data->auth_flavourlen);
1099 err = -EINVAL;
1100 goto out_fail;
1101 }
1102 if (copy_from_user(&authflavour, data->auth_flavours, sizeof(authflavour))) {
1103 err = -EFAULT;
1104 goto out_fail;
1105 }
1106 }
1107
1108 server->client = nfs4_create_client(server, data->timeo, data->retrans,
1109 data->proto, authflavour);
1110 if (IS_ERR(server->client)) {
1111 err = PTR_ERR(server->client);
1112 dprintk("%s: cannot create RPC client. Error = %d\n",
1113 __FUNCTION__, err);
1114 goto out_fail;
1115 }
1116
1117 sb->s_time_gran = 1; 758 sb->s_time_gran = 1;
1118 759 sb->s_op = old_sb->s_op;
1119 sb->s_op = &nfs4_sops; 760 nfs_initialise_sb(sb);
1120 err = nfs_sb_init(sb, authflavour);
1121
1122 out_fail:
1123 return err;
1124} 761}
1125 762
1126static int nfs4_compare_super(struct super_block *sb, void *data) 763/*
764 * Set up an NFS4 superblock
765 */
766static void nfs4_fill_super(struct super_block *sb)
1127{ 767{
1128 struct nfs_server *server = data; 768 sb->s_time_gran = 1;
1129 struct nfs_server *old = NFS_SB(sb); 769 sb->s_op = &nfs4_sops;
1130 770 nfs_initialise_sb(sb);
1131 if (strcmp(server->hostname, old->hostname) != 0)
1132 return 0;
1133 if (strcmp(server->mnt_path, old->mnt_path) != 0)
1134 return 0;
1135 return 1;
1136} 771}
1137 772
1138static void * 773static void *nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
1139nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
1140{ 774{
1141 void *p = NULL; 775 void *p = NULL;
1142 776
@@ -1157,14 +791,22 @@ nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
1157 return dst; 791 return dst;
1158} 792}
1159 793
794/*
795 * Get the superblock for an NFS4 mountpoint
796 */
1160static int nfs4_get_sb(struct file_system_type *fs_type, 797static int nfs4_get_sb(struct file_system_type *fs_type,
1161 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) 798 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
1162{ 799{
1163 int error;
1164 struct nfs_server *server;
1165 struct super_block *s;
1166 struct nfs4_mount_data *data = raw_data; 800 struct nfs4_mount_data *data = raw_data;
801 struct super_block *s;
802 struct nfs_server *server;
803 struct sockaddr_in addr;
804 rpc_authflavor_t authflavour;
805 struct nfs_fh mntfh;
806 struct dentry *mntroot;
807 char *mntpath = NULL, *hostname = NULL, ip_addr[16];
1167 void *p; 808 void *p;
809 int error;
1168 810
1169 if (data == NULL) { 811 if (data == NULL) {
1170 dprintk("%s: missing data argument\n", __FUNCTION__); 812 dprintk("%s: missing data argument\n", __FUNCTION__);
@@ -1175,75 +817,107 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
1175 return -EINVAL; 817 return -EINVAL;
1176 } 818 }
1177 819
1178 server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL); 820 /* We now require that the mount process passes the remote address */
1179 if (!server) 821 if (data->host_addrlen != sizeof(addr))
1180 return -ENOMEM; 822 return -EINVAL;
1181 /* Zero out the NFS state stuff */ 823
1182 init_nfsv4_state(server); 824 if (copy_from_user(&addr, data->host_addr, sizeof(addr)))
1183 server->client = server->client_acl = ERR_PTR(-EINVAL); 825 return -EFAULT;
826
827 if (addr.sin_family != AF_INET ||
828 addr.sin_addr.s_addr == INADDR_ANY
829 ) {
830 dprintk("%s: mount program didn't pass remote IP address!\n",
831 __FUNCTION__);
832 return -EINVAL;
833 }
834
835 /* Grab the authentication type */
836 authflavour = RPC_AUTH_UNIX;
837 if (data->auth_flavourlen != 0) {
838 if (data->auth_flavourlen != 1) {
839 dprintk("%s: Invalid number of RPC auth flavours %d.\n",
840 __FUNCTION__, data->auth_flavourlen);
841 error = -EINVAL;
842 goto out_err_noserver;
843 }
844
845 if (copy_from_user(&authflavour, data->auth_flavours,
846 sizeof(authflavour))) {
847 error = -EFAULT;
848 goto out_err_noserver;
849 }
850 }
1184 851
1185 p = nfs_copy_user_string(NULL, &data->hostname, 256); 852 p = nfs_copy_user_string(NULL, &data->hostname, 256);
1186 if (IS_ERR(p)) 853 if (IS_ERR(p))
1187 goto out_err; 854 goto out_err;
1188 server->hostname = p; 855 hostname = p;
1189 856
1190 p = nfs_copy_user_string(NULL, &data->mnt_path, 1024); 857 p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
1191 if (IS_ERR(p)) 858 if (IS_ERR(p))
1192 goto out_err; 859 goto out_err;
1193 server->mnt_path = p; 860 mntpath = p;
1194 861
1195 p = nfs_copy_user_string(server->ip_addr, &data->client_addr, 862 dprintk("MNTPATH: %s\n", mntpath);
1196 sizeof(server->ip_addr) - 1); 863
864 p = nfs_copy_user_string(ip_addr, &data->client_addr,
865 sizeof(ip_addr) - 1);
1197 if (IS_ERR(p)) 866 if (IS_ERR(p))
1198 goto out_err; 867 goto out_err;
1199 868
1200 /* We now require that the mount process passes the remote address */ 869 /* Get a volume representation */
1201 if (data->host_addrlen != sizeof(server->addr)) { 870 server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr,
1202 error = -EINVAL; 871 authflavour, &mntfh);
1203 goto out_free; 872 if (IS_ERR(server)) {
1204 } 873 error = PTR_ERR(server);
1205 if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) { 874 goto out_err_noserver;
1206 error = -EFAULT;
1207 goto out_free;
1208 }
1209 if (server->addr.sin_family != AF_INET ||
1210 server->addr.sin_addr.s_addr == INADDR_ANY) {
1211 dprintk("%s: mount program didn't pass remote IP address!\n",
1212 __FUNCTION__);
1213 error = -EINVAL;
1214 goto out_free;
1215 } 875 }
1216 876
1217 s = sget(fs_type, nfs4_compare_super, nfs_set_super, server); 877 /* Get a superblock - note that we may end up sharing one that already exists */
878 s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
1218 if (IS_ERR(s)) { 879 if (IS_ERR(s)) {
1219 error = PTR_ERR(s); 880 error = PTR_ERR(s);
1220 goto out_free; 881 goto out_free;
1221 } 882 }
1222 883
1223 if (s->s_root) { 884 if (!s->s_root) {
1224 kfree(server->mnt_path); 885 /* initial superblock/root creation */
1225 kfree(server->hostname); 886 s->s_flags = flags;
1226 kfree(server);
1227 return simple_set_mnt(mnt, s);
1228 }
1229 887
1230 s->s_flags = flags; 888 nfs4_fill_super(s);
889 } else {
890 nfs_free_server(server);
891 }
1231 892
1232 error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0); 893 mntroot = nfs4_get_root(s, &mntfh);
1233 if (error) { 894 if (IS_ERR(mntroot)) {
1234 up_write(&s->s_umount); 895 error = PTR_ERR(mntroot);
1235 deactivate_super(s); 896 goto error_splat_super;
1236 return error;
1237 } 897 }
898
1238 s->s_flags |= MS_ACTIVE; 899 s->s_flags |= MS_ACTIVE;
1239 return simple_set_mnt(mnt, s); 900 mnt->mnt_sb = s;
901 mnt->mnt_root = mntroot;
902 kfree(mntpath);
903 kfree(hostname);
904 return 0;
905
1240out_err: 906out_err:
1241 error = PTR_ERR(p); 907 error = PTR_ERR(p);
908 goto out_err_noserver;
909
1242out_free: 910out_free:
1243 kfree(server->mnt_path); 911 nfs_free_server(server);
1244 kfree(server->hostname); 912out_err_noserver:
1245 kfree(server); 913 kfree(mntpath);
914 kfree(hostname);
1246 return error; 915 return error;
916
917error_splat_super:
918 up_write(&s->s_umount);
919 deactivate_super(s);
920 goto out_err_noserver;
1247} 921}
1248 922
1249static void nfs4_kill_super(struct super_block *sb) 923static void nfs4_kill_super(struct super_block *sb)
@@ -1254,133 +928,140 @@ static void nfs4_kill_super(struct super_block *sb)
1254 kill_anon_super(sb); 928 kill_anon_super(sb);
1255 929
1256 nfs4_renewd_prepare_shutdown(server); 930 nfs4_renewd_prepare_shutdown(server);
1257 931 nfs_free_server(server);
1258 if (server->client != NULL && !IS_ERR(server->client))
1259 rpc_shutdown_client(server->client);
1260
1261 destroy_nfsv4_state(server);
1262
1263 nfs_free_iostats(server->io_stats);
1264 kfree(server->hostname);
1265 kfree(server);
1266 nfs_release_automount_timer();
1267} 932}
1268 933
1269/* 934/*
1270 * Constructs the SERVER-side path 935 * Clone an NFS4 server record on xdev traversal (FSID-change)
1271 */ 936 */
1272static inline char *nfs4_dup_path(const struct dentry *dentry) 937static int nfs4_xdev_get_sb(struct file_system_type *fs_type, int flags,
938 const char *dev_name, void *raw_data,
939 struct vfsmount *mnt)
1273{ 940{
1274 char *page = (char *) __get_free_page(GFP_USER); 941 struct nfs_clone_mount *data = raw_data;
1275 char *path; 942 struct super_block *s;
943 struct nfs_server *server;
944 struct dentry *mntroot;
945 int error;
1276 946
1277 path = nfs4_path(dentry, page, PAGE_SIZE); 947 dprintk("--> nfs4_xdev_get_sb()\n");
1278 if (!IS_ERR(path)) {
1279 int len = PAGE_SIZE + page - path;
1280 char *tmp = path;
1281 948
1282 path = kmalloc(len, GFP_KERNEL); 949 /* create a new volume representation */
1283 if (path) 950 server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
1284 memcpy(path, tmp, len); 951 if (IS_ERR(server)) {
1285 else 952 error = PTR_ERR(server);
1286 path = ERR_PTR(-ENOMEM); 953 goto out_err_noserver;
1287 } 954 }
1288 free_page((unsigned long)page);
1289 return path;
1290}
1291 955
1292static struct super_block *nfs4_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data) 956 /* Get a superblock - note that we may end up sharing one that already exists */
1293{ 957 s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
1294 const struct dentry *dentry = data->dentry; 958 if (IS_ERR(s)) {
1295 struct nfs_client *clp = server->nfs_client; 959 error = PTR_ERR(s);
1296 struct super_block *sb; 960 goto out_err_nosb;
1297
1298 server->fsid = data->fattr->fsid;
1299 nfs_copy_fh(&server->fh, data->fh);
1300 server->mnt_path = nfs4_dup_path(dentry);
1301 if (IS_ERR(server->mnt_path)) {
1302 sb = (struct super_block *)server->mnt_path;
1303 goto err;
1304 } 961 }
1305 sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
1306 if (IS_ERR(sb) || sb->s_root)
1307 goto free_path;
1308 nfs4_server_capabilities(server, &server->fh);
1309
1310 down_write(&clp->cl_sem);
1311 list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
1312 up_write(&clp->cl_sem);
1313 return sb;
1314free_path:
1315 kfree(server->mnt_path);
1316err:
1317 server->mnt_path = NULL;
1318 return sb;
1319}
1320 962
1321static int nfs_clone_nfs4_sb(struct file_system_type *fs_type, 963 if (s->s_fs_info != server) {
1322 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) 964 nfs_free_server(server);
1323{ 965 server = NULL;
1324 struct nfs_clone_mount *data = raw_data; 966 }
1325 return nfs_clone_generic_sb(data, nfs4_clone_sb, nfs_clone_server, mnt);
1326}
1327 967
1328static struct super_block *nfs4_referral_sb(struct nfs_server *server, struct nfs_clone_mount *data) 968 if (!s->s_root) {
1329{ 969 /* initial superblock/root creation */
1330 struct super_block *sb = ERR_PTR(-ENOMEM); 970 s->s_flags = flags;
1331 int len; 971 nfs4_clone_super(s, data->sb);
1332 972 }
1333 len = strlen(data->mnt_path) + 1;
1334 server->mnt_path = kmalloc(len, GFP_KERNEL);
1335 if (server->mnt_path == NULL)
1336 goto err;
1337 memcpy(server->mnt_path, data->mnt_path, len);
1338 memcpy(&server->addr, data->addr, sizeof(struct sockaddr_in));
1339
1340 sb = sget(&nfs4_fs_type, nfs4_compare_super, nfs_set_super, server);
1341 if (IS_ERR(sb) || sb->s_root)
1342 goto free_path;
1343 return sb;
1344free_path:
1345 kfree(server->mnt_path);
1346err:
1347 server->mnt_path = NULL;
1348 return sb;
1349}
1350 973
1351static struct nfs_server *nfs4_referral_server(struct super_block *sb, struct nfs_clone_mount *data) 974 mntroot = nfs4_get_root(s, data->fh);
1352{ 975 if (IS_ERR(mntroot)) {
1353 struct nfs_server *server = NFS_SB(sb); 976 error = PTR_ERR(mntroot);
1354 int proto, timeo, retrans; 977 goto error_splat_super;
1355 void *err; 978 }
1356
1357 proto = IPPROTO_TCP;
1358 /* Since we are following a referral and there may be alternatives,
1359 set the timeouts and retries to low values */
1360 timeo = 2;
1361 retrans = 1;
1362
1363 nfs_put_client(server->nfs_client);
1364 server->nfs_client = NULL;
1365 server->client = nfs4_create_client(server, timeo, retrans, proto,
1366 data->authflavor);
1367 if (IS_ERR((err = server->client)))
1368 goto out_err;
1369 979
1370 sb->s_time_gran = 1; 980 s->s_flags |= MS_ACTIVE;
1371 sb->s_op = &nfs4_sops; 981 mnt->mnt_sb = s;
1372 err = ERR_PTR(nfs_sb_init(sb, data->authflavor)); 982 mnt->mnt_root = mntroot;
1373 if (!IS_ERR(err)) 983
1374 return server; 984 dprintk("<-- nfs4_xdev_get_sb() = 0\n");
1375out_err: 985 return 0;
1376 return (struct nfs_server *)err; 986
987out_err_nosb:
988 nfs_free_server(server);
989out_err_noserver:
990 dprintk("<-- nfs4_xdev_get_sb() = %d [error]\n", error);
991 return error;
992
993error_splat_super:
994 up_write(&s->s_umount);
995 deactivate_super(s);
996 dprintk("<-- nfs4_xdev_get_sb() = %d [splat]\n", error);
997 return error;
1377} 998}
1378 999
1379static int nfs_referral_nfs4_sb(struct file_system_type *fs_type, 1000/*
1380 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) 1001 * Create an NFS4 server record on referral traversal
1002 */
1003static int nfs4_referral_get_sb(struct file_system_type *fs_type, int flags,
1004 const char *dev_name, void *raw_data,
1005 struct vfsmount *mnt)
1381{ 1006{
1382 struct nfs_clone_mount *data = raw_data; 1007 struct nfs_clone_mount *data = raw_data;
1383 return nfs_clone_generic_sb(data, nfs4_referral_sb, nfs4_referral_server, mnt); 1008 struct super_block *s;
1009 struct nfs_server *server;
1010 struct dentry *mntroot;
1011 struct nfs_fh mntfh;
1012 int error;
1013
1014 dprintk("--> nfs4_referral_get_sb()\n");
1015
1016 /* create a new volume representation */
1017 server = nfs4_create_referral_server(data, &mntfh);
1018 if (IS_ERR(server)) {
1019 error = PTR_ERR(server);
1020 goto out_err_noserver;
1021 }
1022
1023 /* Get a superblock - note that we may end up sharing one that already exists */
1024 s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
1025 if (IS_ERR(s)) {
1026 error = PTR_ERR(s);
1027 goto out_err_nosb;
1028 }
1029
1030 if (s->s_fs_info != server) {
1031 nfs_free_server(server);
1032 server = NULL;
1033 }
1034
1035 if (!s->s_root) {
1036 /* initial superblock/root creation */
1037 s->s_flags = flags;
1038 nfs4_fill_super(s);
1039 }
1040
1041 mntroot = nfs4_get_root(s, data->fh);
1042 if (IS_ERR(mntroot)) {
1043 error = PTR_ERR(mntroot);
1044 goto error_splat_super;
1045 }
1046
1047 s->s_flags |= MS_ACTIVE;
1048 mnt->mnt_sb = s;
1049 mnt->mnt_root = mntroot;
1050
1051 dprintk("<-- nfs4_referral_get_sb() = 0\n");
1052 return 0;
1053
1054out_err_nosb:
1055 nfs_free_server(server);
1056out_err_noserver:
1057 dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error);
1058 return error;
1059
1060error_splat_super:
1061 up_write(&s->s_umount);
1062 deactivate_super(s);
1063 dprintk("<-- nfs4_referral_get_sb() = %d [splat]\n", error);
1064 return error;
1384} 1065}
1385 1066
1386#endif 1067#endif /* CONFIG_NFS_V4 */