Commit 54ceac4515986030c2502960be620198dd8fe25b

Authored by David Howells
Committed by Trond Myklebust
1 parent cf6d7b5de8

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>

Showing 18 changed files with 1655 additions and 956 deletions Side-by-side Diff

... ... @@ -4,7 +4,7 @@
4 4  
5 5 obj-$(CONFIG_NFS_FS) += nfs.o
6 6  
7   -nfs-y := client.o dir.o file.o inode.o super.o nfs2xdr.o \
  7 +nfs-y := client.o dir.o file.o getroot.o inode.o super.o nfs2xdr.o \
8 8 pagelist.o proc.o read.o symlink.o unlink.o \
9 9 write.o namespace.o
10 10 nfs-$(CONFIG_ROOT_NFS) += nfsroot.o mount_clnt.o
... ... @@ -48,6 +48,7 @@
48 48  
49 49 static DEFINE_SPINLOCK(nfs_client_lock);
50 50 static LIST_HEAD(nfs_client_list);
  51 +static LIST_HEAD(nfs_volume_list);
51 52 static DECLARE_WAIT_QUEUE_HEAD(nfs_client_active_wq);
52 53  
53 54 /*
... ... @@ -268,9 +269,9 @@
268 269 * Look up a client by IP address and protocol version
269 270 * - creates a new record if one doesn't yet exist
270 271 */
271   -struct nfs_client *nfs_get_client(const char *hostname,
272   - const struct sockaddr_in *addr,
273   - int nfsversion)
  272 +static struct nfs_client *nfs_get_client(const char *hostname,
  273 + const struct sockaddr_in *addr,
  274 + int nfsversion)
274 275 {
275 276 struct nfs_client *clp, *new = NULL;
276 277 int error;
... ... @@ -340,6 +341,8 @@
340 341 return ERR_PTR(error);
341 342 }
342 343  
  344 + BUG_ON(clp->cl_cons_state != NFS_CS_READY);
  345 +
343 346 dprintk("--> nfs_get_client() = %p [share]\n", clp);
344 347 return clp;
345 348 }
... ... @@ -347,7 +350,7 @@
347 350 /*
348 351 * Mark a server as ready or failed
349 352 */
350   -void nfs_mark_client_ready(struct nfs_client *clp, int state)
  353 +static void nfs_mark_client_ready(struct nfs_client *clp, int state)
351 354 {
352 355 clp->cl_cons_state = state;
353 356 wake_up_all(&nfs_client_active_wq);
... ... @@ -389,10 +392,10 @@
389 392 /*
390 393 * Create an RPC client handle
391 394 */
392   -int nfs_create_rpc_client(struct nfs_client *clp, int proto,
393   - unsigned int timeo,
394   - unsigned int retrans,
395   - rpc_authflavor_t flavor)
  395 +static int nfs_create_rpc_client(struct nfs_client *clp, int proto,
  396 + unsigned int timeo,
  397 + unsigned int retrans,
  398 + rpc_authflavor_t flavor)
396 399 {
397 400 struct rpc_timeout timeparms;
398 401 struct rpc_xprt *xprt = NULL;
... ... @@ -428,5 +431,721 @@
428 431 clnt->cl_softrtry = 1;
429 432 clp->cl_rpcclient = clnt;
430 433 return 0;
  434 +}
  435 +
  436 +/*
  437 + * Version 2 or 3 client destruction
  438 + */
  439 +static void nfs_destroy_server(struct nfs_server *server)
  440 +{
  441 + if (!IS_ERR(server->client_acl))
  442 + rpc_shutdown_client(server->client_acl);
  443 +
  444 + if (!(server->flags & NFS_MOUNT_NONLM))
  445 + lockd_down(); /* release rpc.lockd */
  446 +}
  447 +
  448 +/*
  449 + * Version 2 or 3 lockd setup
  450 + */
  451 +static int nfs_start_lockd(struct nfs_server *server)
  452 +{
  453 + int error = 0;
  454 +
  455 + if (server->nfs_client->cl_nfsversion > 3)
  456 + goto out;
  457 + if (server->flags & NFS_MOUNT_NONLM)
  458 + goto out;
  459 + error = lockd_up();
  460 + if (error < 0)
  461 + server->flags |= NFS_MOUNT_NONLM;
  462 + else
  463 + server->destroy = nfs_destroy_server;
  464 +out:
  465 + return error;
  466 +}
  467 +
  468 +/*
  469 + * Initialise an NFSv3 ACL client connection
  470 + */
  471 +#ifdef CONFIG_NFS_V3_ACL
  472 +static void nfs_init_server_aclclient(struct nfs_server *server)
  473 +{
  474 + if (server->nfs_client->cl_nfsversion != 3)
  475 + goto out_noacl;
  476 + if (server->flags & NFS_MOUNT_NOACL)
  477 + goto out_noacl;
  478 +
  479 + server->client_acl = rpc_bind_new_program(server->client, &nfsacl_program, 3);
  480 + if (IS_ERR(server->client_acl))
  481 + goto out_noacl;
  482 +
  483 + /* No errors! Assume that Sun nfsacls are supported */
  484 + server->caps |= NFS_CAP_ACLS;
  485 + return;
  486 +
  487 +out_noacl:
  488 + server->caps &= ~NFS_CAP_ACLS;
  489 +}
  490 +#else
  491 +static inline void nfs_init_server_aclclient(struct nfs_server *server)
  492 +{
  493 + server->flags &= ~NFS_MOUNT_NOACL;
  494 + server->caps &= ~NFS_CAP_ACLS;
  495 +}
  496 +#endif
  497 +
  498 +/*
  499 + * Create a general RPC client
  500 + */
  501 +static int nfs_init_server_rpcclient(struct nfs_server *server, rpc_authflavor_t pseudoflavour)
  502 +{
  503 + struct nfs_client *clp = server->nfs_client;
  504 +
  505 + server->client = rpc_clone_client(clp->cl_rpcclient);
  506 + if (IS_ERR(server->client)) {
  507 + dprintk("%s: couldn't create rpc_client!\n", __FUNCTION__);
  508 + return PTR_ERR(server->client);
  509 + }
  510 +
  511 + if (pseudoflavour != clp->cl_rpcclient->cl_auth->au_flavor) {
  512 + struct rpc_auth *auth;
  513 +
  514 + auth = rpcauth_create(pseudoflavour, server->client);
  515 + if (IS_ERR(auth)) {
  516 + dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
  517 + return PTR_ERR(auth);
  518 + }
  519 + }
  520 + server->client->cl_softrtry = 0;
  521 + if (server->flags & NFS_MOUNT_SOFT)
  522 + server->client->cl_softrtry = 1;
  523 +
  524 + server->client->cl_intr = 0;
  525 + if (server->flags & NFS4_MOUNT_INTR)
  526 + server->client->cl_intr = 1;
  527 +
  528 + return 0;
  529 +}
  530 +
  531 +/*
  532 + * Initialise an NFS2 or NFS3 client
  533 + */
  534 +static int nfs_init_client(struct nfs_client *clp, const struct nfs_mount_data *data)
  535 +{
  536 + int proto = (data->flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
  537 + int error;
  538 +
  539 + if (clp->cl_cons_state == NFS_CS_READY) {
  540 + /* the client is already initialised */
  541 + dprintk("<-- nfs_init_client() = 0 [already %p]\n", clp);
  542 + return 0;
  543 + }
  544 +
  545 + /* Check NFS protocol revision and initialize RPC op vector */
  546 + clp->rpc_ops = &nfs_v2_clientops;
  547 +#ifdef CONFIG_NFS_V3
  548 + if (clp->cl_nfsversion == 3)
  549 + clp->rpc_ops = &nfs_v3_clientops;
  550 +#endif
  551 + /*
  552 + * Create a client RPC handle for doing FSSTAT with UNIX auth only
  553 + * - RFC 2623, sec 2.3.2
  554 + */
  555 + error = nfs_create_rpc_client(clp, proto, data->timeo, data->retrans,
  556 + RPC_AUTH_UNIX);
  557 + if (error < 0)
  558 + goto error;
  559 + nfs_mark_client_ready(clp, NFS_CS_READY);
  560 + return 0;
  561 +
  562 +error:
  563 + nfs_mark_client_ready(clp, error);
  564 + dprintk("<-- nfs_init_client() = xerror %d\n", error);
  565 + return error;
  566 +}
  567 +
  568 +/*
  569 + * Create a version 2 or 3 client
  570 + */
  571 +static int nfs_init_server(struct nfs_server *server, const struct nfs_mount_data *data)
  572 +{
  573 + struct nfs_client *clp;
  574 + int error, nfsvers = 2;
  575 +
  576 + dprintk("--> nfs_init_server()\n");
  577 +
  578 +#ifdef CONFIG_NFS_V3
  579 + if (data->flags & NFS_MOUNT_VER3)
  580 + nfsvers = 3;
  581 +#endif
  582 +
  583 + /* Allocate or find a client reference we can use */
  584 + clp = nfs_get_client(data->hostname, &data->addr, nfsvers);
  585 + if (IS_ERR(clp)) {
  586 + dprintk("<-- nfs_init_server() = error %ld\n", PTR_ERR(clp));
  587 + return PTR_ERR(clp);
  588 + }
  589 +
  590 + error = nfs_init_client(clp, data);
  591 + if (error < 0)
  592 + goto error;
  593 +
  594 + server->nfs_client = clp;
  595 +
  596 + /* Initialise the client representation from the mount data */
  597 + server->flags = data->flags & NFS_MOUNT_FLAGMASK;
  598 +
  599 + if (data->rsize)
  600 + server->rsize = nfs_block_size(data->rsize, NULL);
  601 + if (data->wsize)
  602 + server->wsize = nfs_block_size(data->wsize, NULL);
  603 +
  604 + server->acregmin = data->acregmin * HZ;
  605 + server->acregmax = data->acregmax * HZ;
  606 + server->acdirmin = data->acdirmin * HZ;
  607 + server->acdirmax = data->acdirmax * HZ;
  608 +
  609 + /* Start lockd here, before we might error out */
  610 + error = nfs_start_lockd(server);
  611 + if (error < 0)
  612 + goto error;
  613 +
  614 + error = nfs_init_server_rpcclient(server, data->pseudoflavor);
  615 + if (error < 0)
  616 + goto error;
  617 +
  618 + server->namelen = data->namlen;
  619 + /* Create a client RPC handle for the NFSv3 ACL management interface */
  620 + nfs_init_server_aclclient(server);
  621 + if (clp->cl_nfsversion == 3) {
  622 + if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
  623 + server->namelen = NFS3_MAXNAMLEN;
  624 + server->caps |= NFS_CAP_READDIRPLUS;
  625 + } else {
  626 + if (server->namelen == 0 || server->namelen > NFS2_MAXNAMLEN)
  627 + server->namelen = NFS2_MAXNAMLEN;
  628 + }
  629 +
  630 + dprintk("<-- nfs_init_server() = 0 [new %p]\n", clp);
  631 + return 0;
  632 +
  633 +error:
  634 + server->nfs_client = NULL;
  635 + nfs_put_client(clp);
  636 + dprintk("<-- nfs_init_server() = xerror %d\n", error);
  637 + return error;
  638 +}
  639 +
  640 +/*
  641 + * Load up the server record from information gained in an fsinfo record
  642 + */
  643 +static void nfs_server_set_fsinfo(struct nfs_server *server, struct nfs_fsinfo *fsinfo)
  644 +{
  645 + unsigned long max_rpc_payload;
  646 +
  647 + /* Work out a lot of parameters */
  648 + if (server->rsize == 0)
  649 + server->rsize = nfs_block_size(fsinfo->rtpref, NULL);
  650 + if (server->wsize == 0)
  651 + server->wsize = nfs_block_size(fsinfo->wtpref, NULL);
  652 +
  653 + if (fsinfo->rtmax >= 512 && server->rsize > fsinfo->rtmax)
  654 + server->rsize = nfs_block_size(fsinfo->rtmax, NULL);
  655 + if (fsinfo->wtmax >= 512 && server->wsize > fsinfo->wtmax)
  656 + server->wsize = nfs_block_size(fsinfo->wtmax, NULL);
  657 +
  658 + max_rpc_payload = nfs_block_size(rpc_max_payload(server->client), NULL);
  659 + if (server->rsize > max_rpc_payload)
  660 + server->rsize = max_rpc_payload;
  661 + if (server->rsize > NFS_MAX_FILE_IO_SIZE)
  662 + server->rsize = NFS_MAX_FILE_IO_SIZE;
  663 + server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
  664 + server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
  665 +
  666 + if (server->wsize > max_rpc_payload)
  667 + server->wsize = max_rpc_payload;
  668 + if (server->wsize > NFS_MAX_FILE_IO_SIZE)
  669 + server->wsize = NFS_MAX_FILE_IO_SIZE;
  670 + server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
  671 + server->wtmult = nfs_block_bits(fsinfo->wtmult, NULL);
  672 +
  673 + server->dtsize = nfs_block_size(fsinfo->dtpref, NULL);
  674 + if (server->dtsize > PAGE_CACHE_SIZE)
  675 + server->dtsize = PAGE_CACHE_SIZE;
  676 + if (server->dtsize > server->rsize)
  677 + server->dtsize = server->rsize;
  678 +
  679 + if (server->flags & NFS_MOUNT_NOAC) {
  680 + server->acregmin = server->acregmax = 0;
  681 + server->acdirmin = server->acdirmax = 0;
  682 + }
  683 +
  684 + server->maxfilesize = fsinfo->maxfilesize;
  685 +
  686 + /* We're airborne Set socket buffersize */
  687 + rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100);
  688 +}
  689 +
  690 +/*
  691 + * Probe filesystem information, including the FSID on v2/v3
  692 + */
  693 +static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
  694 +{
  695 + struct nfs_fsinfo fsinfo;
  696 + struct nfs_client *clp = server->nfs_client;
  697 + int error;
  698 +
  699 + dprintk("--> nfs_probe_fsinfo()\n");
  700 +
  701 + if (clp->rpc_ops->set_capabilities != NULL) {
  702 + error = clp->rpc_ops->set_capabilities(server, mntfh);
  703 + if (error < 0)
  704 + goto out_error;
  705 + }
  706 +
  707 + fsinfo.fattr = fattr;
  708 + nfs_fattr_init(fattr);
  709 + error = clp->rpc_ops->fsinfo(server, mntfh, &fsinfo);
  710 + if (error < 0)
  711 + goto out_error;
  712 +
  713 + nfs_server_set_fsinfo(server, &fsinfo);
  714 +
  715 + /* Get some general file system info */
  716 + if (server->namelen == 0) {
  717 + struct nfs_pathconf pathinfo;
  718 +
  719 + pathinfo.fattr = fattr;
  720 + nfs_fattr_init(fattr);
  721 +
  722 + if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0)
  723 + server->namelen = pathinfo.max_namelen;
  724 + }
  725 +
  726 + dprintk("<-- nfs_probe_fsinfo() = 0\n");
  727 + return 0;
  728 +
  729 +out_error:
  730 + dprintk("nfs_probe_fsinfo: error = %d\n", -error);
  731 + return error;
  732 +}
  733 +
  734 +/*
  735 + * Copy useful information when duplicating a server record
  736 + */
  737 +static void nfs_server_copy_userdata(struct nfs_server *target, struct nfs_server *source)
  738 +{
  739 + target->flags = source->flags;
  740 + target->acregmin = source->acregmin;
  741 + target->acregmax = source->acregmax;
  742 + target->acdirmin = source->acdirmin;
  743 + target->acdirmax = source->acdirmax;
  744 + target->caps = source->caps;
  745 +}
  746 +
  747 +/*
  748 + * Allocate and initialise a server record
  749 + */
  750 +static struct nfs_server *nfs_alloc_server(void)
  751 +{
  752 + struct nfs_server *server;
  753 +
  754 + server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
  755 + if (!server)
  756 + return NULL;
  757 +
  758 + server->client = server->client_acl = ERR_PTR(-EINVAL);
  759 +
  760 + /* Zero out the NFS state stuff */
  761 + INIT_LIST_HEAD(&server->client_link);
  762 + INIT_LIST_HEAD(&server->master_link);
  763 +
  764 + server->io_stats = nfs_alloc_iostats();
  765 + if (!server->io_stats) {
  766 + kfree(server);
  767 + return NULL;
  768 + }
  769 +
  770 + return server;
  771 +}
  772 +
  773 +/*
  774 + * Free up a server record
  775 + */
  776 +void nfs_free_server(struct nfs_server *server)
  777 +{
  778 + dprintk("--> nfs_free_server()\n");
  779 +
  780 + spin_lock(&nfs_client_lock);
  781 + list_del(&server->client_link);
  782 + list_del(&server->master_link);
  783 + spin_unlock(&nfs_client_lock);
  784 +
  785 + if (server->destroy != NULL)
  786 + server->destroy(server);
  787 + if (!IS_ERR(server->client))
  788 + rpc_shutdown_client(server->client);
  789 +
  790 + nfs_put_client(server->nfs_client);
  791 +
  792 + nfs_free_iostats(server->io_stats);
  793 + kfree(server);
  794 + nfs_release_automount_timer();
  795 + dprintk("<-- nfs_free_server()\n");
  796 +}
  797 +
  798 +/*
  799 + * Create a version 2 or 3 volume record
  800 + * - keyed on server and FSID
  801 + */
  802 +struct nfs_server *nfs_create_server(const struct nfs_mount_data *data,
  803 + struct nfs_fh *mntfh)
  804 +{
  805 + struct nfs_server *server;
  806 + struct nfs_fattr fattr;
  807 + int error;
  808 +
  809 + server = nfs_alloc_server();
  810 + if (!server)
  811 + return ERR_PTR(-ENOMEM);
  812 +
  813 + /* Get a client representation */
  814 + error = nfs_init_server(server, data);
  815 + if (error < 0)
  816 + goto error;
  817 +
  818 + BUG_ON(!server->nfs_client);
  819 + BUG_ON(!server->nfs_client->rpc_ops);
  820 + BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
  821 +
  822 + /* Probe the root fh to retrieve its FSID */
  823 + error = nfs_probe_fsinfo(server, mntfh, &fattr);
  824 + if (error < 0)
  825 + goto error;
  826 + if (!(fattr.valid & NFS_ATTR_FATTR)) {
  827 + error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
  828 + if (error < 0) {
  829 + dprintk("nfs_create_server: getattr error = %d\n", -error);
  830 + goto error;
  831 + }
  832 + }
  833 + memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
  834 +
  835 + dprintk("Server FSID: %llx:%llx\n", server->fsid.major, server->fsid.minor);
  836 +
  837 + BUG_ON(!server->nfs_client);
  838 + BUG_ON(!server->nfs_client->rpc_ops);
  839 + BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
  840 +
  841 + spin_lock(&nfs_client_lock);
  842 + list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
  843 + list_add_tail(&server->master_link, &nfs_volume_list);
  844 + spin_unlock(&nfs_client_lock);
  845 +
  846 + server->mount_time = jiffies;
  847 + return server;
  848 +
  849 +error:
  850 + nfs_free_server(server);
  851 + return ERR_PTR(error);
  852 +}
  853 +
  854 +#ifdef CONFIG_NFS_V4
  855 +/*
  856 + * Initialise an NFS4 client record
  857 + */
  858 +static int nfs4_init_client(struct nfs_client *clp,
  859 + int proto, int timeo, int retrans,
  860 + rpc_authflavor_t authflavour)
  861 +{
  862 + int error;
  863 +
  864 + if (clp->cl_cons_state == NFS_CS_READY) {
  865 + /* the client is initialised already */
  866 + dprintk("<-- nfs4_init_client() = 0 [already %p]\n", clp);
  867 + return 0;
  868 + }
  869 +
  870 + /* Check NFS protocol revision and initialize RPC op vector */
  871 + clp->rpc_ops = &nfs_v4_clientops;
  872 +
  873 + error = nfs_create_rpc_client(clp, proto, timeo, retrans, authflavour);
  874 + if (error < 0)
  875 + goto error;
  876 +
  877 + error = nfs_idmap_new(clp);
  878 + if (error < 0) {
  879 + dprintk("%s: failed to create idmapper. Error = %d\n",
  880 + __FUNCTION__, error);
  881 + __set_bit(NFS_CS_IDMAP, &clp->cl_res_state);
  882 + goto error;
  883 + }
  884 +
  885 + nfs_mark_client_ready(clp, NFS_CS_READY);
  886 + return 0;
  887 +
  888 +error:
  889 + nfs_mark_client_ready(clp, error);
  890 + dprintk("<-- nfs4_init_client() = xerror %d\n", error);
  891 + return error;
  892 +}
  893 +
  894 +/*
  895 + * Set up an NFS4 client
  896 + */
  897 +static int nfs4_set_client(struct nfs_server *server,
  898 + const char *hostname, const struct sockaddr_in *addr,
  899 + rpc_authflavor_t authflavour,
  900 + int proto, int timeo, int retrans)
  901 +{
  902 + struct nfs_client *clp;
  903 + int error;
  904 +
  905 + dprintk("--> nfs4_set_client()\n");
  906 +
  907 + /* Allocate or find a client reference we can use */
  908 + clp = nfs_get_client(hostname, addr, 4);
  909 + if (IS_ERR(clp)) {
  910 + error = PTR_ERR(clp);
  911 + goto error;
  912 + }
  913 + error = nfs4_init_client(clp, proto, timeo, retrans, authflavour);
  914 + if (error < 0)
  915 + goto error_put;
  916 +
  917 + server->nfs_client = clp;
  918 + dprintk("<-- nfs4_set_client() = 0 [new %p]\n", clp);
  919 + return 0;
  920 +
  921 +error_put:
  922 + nfs_put_client(clp);
  923 +error:
  924 + dprintk("<-- nfs4_set_client() = xerror %d\n", error);
  925 + return error;
  926 +}
  927 +
  928 +/*
  929 + * Create a version 4 volume record
  930 + */
  931 +static int nfs4_init_server(struct nfs_server *server,
  932 + const struct nfs4_mount_data *data, rpc_authflavor_t authflavour)
  933 +{
  934 + int error;
  935 +
  936 + dprintk("--> nfs4_init_server()\n");
  937 +
  938 + /* Initialise the client representation from the mount data */
  939 + server->flags = data->flags & NFS_MOUNT_FLAGMASK;
  940 + server->caps |= NFS_CAP_ATOMIC_OPEN;
  941 +
  942 + if (data->rsize)
  943 + server->rsize = nfs_block_size(data->rsize, NULL);
  944 + if (data->wsize)
  945 + server->wsize = nfs_block_size(data->wsize, NULL);
  946 +
  947 + server->acregmin = data->acregmin * HZ;
  948 + server->acregmax = data->acregmax * HZ;
  949 + server->acdirmin = data->acdirmin * HZ;
  950 + server->acdirmax = data->acdirmax * HZ;
  951 +
  952 + error = nfs_init_server_rpcclient(server, authflavour);
  953 +
  954 + /* Done */
  955 + dprintk("<-- nfs4_init_server() = %d\n", error);
  956 + return error;
  957 +}
  958 +
  959 +/*
  960 + * Create a version 4 volume record
  961 + * - keyed on server and FSID
  962 + */
  963 +struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *data,
  964 + const char *hostname,
  965 + const struct sockaddr_in *addr,
  966 + const char *mntpath,
  967 + const char *ip_addr,
  968 + rpc_authflavor_t authflavour,
  969 + struct nfs_fh *mntfh)
  970 +{
  971 + struct nfs_fattr fattr;
  972 + struct nfs_server *server;
  973 + int error;
  974 +
  975 + dprintk("--> nfs4_create_server()\n");
  976 +
  977 + server = nfs_alloc_server();
  978 + if (!server)
  979 + return ERR_PTR(-ENOMEM);
  980 +
  981 + /* Get a client record */
  982 + error = nfs4_set_client(server, hostname, addr, authflavour,
  983 + data->proto, data->timeo, data->retrans);
  984 + if (error < 0)
  985 + goto error;
  986 +
  987 + /* set up the general RPC client */
  988 + error = nfs4_init_server(server, data, authflavour);
  989 + if (error < 0)
  990 + goto error;
  991 +
  992 + BUG_ON(!server->nfs_client);
  993 + BUG_ON(!server->nfs_client->rpc_ops);
  994 + BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
  995 +
  996 + /* Probe the root fh to retrieve its FSID */
  997 + error = nfs4_path_walk(server, mntfh, mntpath);
  998 + if (error < 0)
  999 + goto error;
  1000 +
  1001 + dprintk("Server FSID: %llx:%llx\n", server->fsid.major, server->fsid.minor);
  1002 + dprintk("Mount FH: %d\n", mntfh->size);
  1003 +
  1004 + error = nfs_probe_fsinfo(server, mntfh, &fattr);
  1005 + if (error < 0)
  1006 + goto error;
  1007 +
  1008 + BUG_ON(!server->nfs_client);
  1009 + BUG_ON(!server->nfs_client->rpc_ops);
  1010 + BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
  1011 +
  1012 + spin_lock(&nfs_client_lock);
  1013 + list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
  1014 + list_add_tail(&server->master_link, &nfs_volume_list);
  1015 + spin_unlock(&nfs_client_lock);
  1016 +
  1017 + server->mount_time = jiffies;
  1018 + dprintk("<-- nfs4_create_server() = %p\n", server);
  1019 + return server;
  1020 +
  1021 +error:
  1022 + nfs_free_server(server);
  1023 + dprintk("<-- nfs4_create_server() = error %d\n", error);
  1024 + return ERR_PTR(error);
  1025 +}
  1026 +
  1027 +/*
  1028 + * Create an NFS4 referral server record
  1029 + */
  1030 +struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *data,
  1031 + struct nfs_fh *fh)
  1032 +{
  1033 + struct nfs_client *parent_client;
  1034 + struct nfs_server *server, *parent_server;
  1035 + struct nfs_fattr fattr;
  1036 + int error;
  1037 +
  1038 + dprintk("--> nfs4_create_referral_server()\n");
  1039 +
  1040 + server = nfs_alloc_server();
  1041 + if (!server)
  1042 + return ERR_PTR(-ENOMEM);
  1043 +
  1044 + parent_server = NFS_SB(data->sb);
  1045 + parent_client = parent_server->nfs_client;
  1046 +
  1047 + /* Get a client representation.
  1048 + * Note: NFSv4 always uses TCP, */
  1049 + error = nfs4_set_client(server, data->hostname, data->addr,
  1050 + data->authflavor,
  1051 + parent_server->client->cl_xprt->prot,
  1052 + parent_client->retrans_timeo,
  1053 + parent_client->retrans_count);
  1054 +
  1055 + /* Initialise the client representation from the parent server */
  1056 + nfs_server_copy_userdata(server, parent_server);
  1057 + server->caps |= NFS_CAP_ATOMIC_OPEN;
  1058 +
  1059 + error = nfs_init_server_rpcclient(server, data->authflavor);
  1060 + if (error < 0)
  1061 + goto error;
  1062 +
  1063 + BUG_ON(!server->nfs_client);
  1064 + BUG_ON(!server->nfs_client->rpc_ops);
  1065 + BUG_ON(!server->nfs_client->rpc_ops->file_inode_ops);
  1066 +
  1067 + /* probe the filesystem info for this server filesystem */
  1068 + error = nfs_probe_fsinfo(server, fh, &fattr);
  1069 + if (error < 0)
  1070 + goto error;
  1071 +
  1072 + dprintk("Referral FSID: %llx:%llx\n",
  1073 + server->fsid.major, server->fsid.minor);
  1074 +
  1075 + spin_lock(&nfs_client_lock);
  1076 + list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
  1077 + list_add_tail(&server->master_link, &nfs_volume_list);
  1078 + spin_unlock(&nfs_client_lock);
  1079 +
  1080 + server->mount_time = jiffies;
  1081 +
  1082 + dprintk("<-- nfs_create_referral_server() = %p\n", server);
  1083 + return server;
  1084 +
  1085 +error:
  1086 + nfs_free_server(server);
  1087 + dprintk("<-- nfs4_create_referral_server() = error %d\n", error);
  1088 + return ERR_PTR(error);
  1089 +}
  1090 +
  1091 +#endif /* CONFIG_NFS_V4 */
  1092 +
  1093 +/*
  1094 + * Clone an NFS2, NFS3 or NFS4 server record
  1095 + */
  1096 +struct nfs_server *nfs_clone_server(struct nfs_server *source,
  1097 + struct nfs_fh *fh,
  1098 + struct nfs_fattr *fattr)
  1099 +{
  1100 + struct nfs_server *server;
  1101 + struct nfs_fattr fattr_fsinfo;
  1102 + int error;
  1103 +
  1104 + dprintk("--> nfs_clone_server(,%llx:%llx,)\n",
  1105 + fattr->fsid.major, fattr->fsid.minor);
  1106 +
  1107 + server = nfs_alloc_server();
  1108 + if (!server)
  1109 + return ERR_PTR(-ENOMEM);
  1110 +
  1111 + /* Copy data from the source */
  1112 + server->nfs_client = source->nfs_client;
  1113 + atomic_inc(&server->nfs_client->cl_count);
  1114 + nfs_server_copy_userdata(server, source);
  1115 +
  1116 + server->fsid = fattr->fsid;
  1117 +
  1118 + error = nfs_init_server_rpcclient(server, source->client->cl_auth->au_flavor);
  1119 + if (error < 0)
  1120 + goto out_free_server;
  1121 + if (!IS_ERR(source->client_acl))
  1122 + nfs_init_server_aclclient(server);
  1123 +
  1124 + /* probe the filesystem info for this server filesystem */
  1125 + error = nfs_probe_fsinfo(server, fh, &fattr_fsinfo);
  1126 + if (error < 0)
  1127 + goto out_free_server;
  1128 +
  1129 + dprintk("Cloned FSID: %llx:%llx\n",
  1130 + server->fsid.major, server->fsid.minor);
  1131 +
  1132 + error = nfs_start_lockd(server);
  1133 + if (error < 0)
  1134 + goto out_free_server;
  1135 +
  1136 + spin_lock(&nfs_client_lock);
  1137 + list_add_tail(&server->client_link, &server->nfs_client->cl_superblocks);
  1138 + list_add_tail(&server->master_link, &nfs_volume_list);
  1139 + spin_unlock(&nfs_client_lock);
  1140 +
  1141 + server->mount_time = jiffies;
  1142 +
  1143 + dprintk("<-- nfs_clone_server() = %p\n", server);
  1144 + return server;
  1145 +
  1146 +out_free_server:
  1147 + nfs_free_server(server);
  1148 + dprintk("<-- nfs_clone_server() = error %d\n", error);
  1149 + return ERR_PTR(error);
431 1150 }
... ... @@ -31,6 +31,7 @@
31 31 #include <linux/pagemap.h>
32 32 #include <linux/smp_lock.h>
33 33 #include <linux/namei.h>
  34 +#include <linux/mount.h>
34 35  
35 36 #include "nfs4_fs.h"
36 37 #include "delegation.h"
37 38  
... ... @@ -870,14 +871,14 @@
870 871 return (nd->intent.open.flags & O_EXCL) != 0;
871 872 }
872 873  
873   -static inline int nfs_reval_fsid(struct inode *dir,
874   - struct nfs_fh *fh, struct nfs_fattr *fattr)
  874 +static inline int nfs_reval_fsid(struct vfsmount *mnt, struct inode *dir,
  875 + struct nfs_fh *fh, struct nfs_fattr *fattr)
875 876 {
876 877 struct nfs_server *server = NFS_SERVER(dir);
877 878  
878 879 if (!nfs_fsid_equal(&server->fsid, &fattr->fsid))
879 880 /* Revalidate fsid on root dir */
880   - return __nfs_revalidate_inode(server, dir->i_sb->s_root->d_inode);
  881 + return __nfs_revalidate_inode(server, mnt->mnt_root->d_inode);
881 882 return 0;
882 883 }
883 884  
... ... @@ -913,7 +914,7 @@
913 914 res = ERR_PTR(error);
914 915 goto out_unlock;
915 916 }
916   - error = nfs_reval_fsid(dir, &fhandle, &fattr);
  917 + error = nfs_reval_fsid(nd->mnt, dir, &fhandle, &fattr);
917 918 if (error < 0) {
918 919 res = ERR_PTR(error);
919 920 goto out_unlock;
920 921  
... ... @@ -922,8 +923,9 @@
922 923 res = (struct dentry *)inode;
923 924 if (IS_ERR(res))
924 925 goto out_unlock;
  926 +
925 927 no_entry:
926   - res = d_add_unique(dentry, inode);
  928 + res = d_materialise_unique(dentry, inode);
927 929 if (res != NULL)
928 930 dentry = res;
929 931 nfs_renew_times(dentry);
930 932  
... ... @@ -1117,11 +1119,13 @@
1117 1119 dput(dentry);
1118 1120 return NULL;
1119 1121 }
1120   - alias = d_add_unique(dentry, inode);
  1122 +
  1123 + alias = d_materialise_unique(dentry, inode);
1121 1124 if (alias != NULL) {
1122 1125 dput(dentry);
1123 1126 dentry = alias;
1124 1127 }
  1128 +
1125 1129 nfs_renew_times(dentry);
1126 1130 nfs_set_verifier(dentry, nfs_save_change_attribute(dir));
1127 1131 return dentry;
  1 +/* getroot.c: get the root dentry for an NFS mount
  2 + *
  3 + * Copyright (C) 2006 Red Hat, Inc. All Rights Reserved.
  4 + * Written by David Howells (dhowells@redhat.com)
  5 + *
  6 + * This program is free software; you can redistribute it and/or
  7 + * modify it under the terms of the GNU General Public License
  8 + * as published by the Free Software Foundation; either version
  9 + * 2 of the License, or (at your option) any later version.
  10 + */
  11 +
  12 +#include <linux/config.h>
  13 +#include <linux/module.h>
  14 +#include <linux/init.h>
  15 +
  16 +#include <linux/time.h>
  17 +#include <linux/kernel.h>
  18 +#include <linux/mm.h>
  19 +#include <linux/string.h>
  20 +#include <linux/stat.h>
  21 +#include <linux/errno.h>
  22 +#include <linux/unistd.h>
  23 +#include <linux/sunrpc/clnt.h>
  24 +#include <linux/sunrpc/stats.h>
  25 +#include <linux/nfs_fs.h>
  26 +#include <linux/nfs_mount.h>
  27 +#include <linux/nfs4_mount.h>
  28 +#include <linux/lockd/bind.h>
  29 +#include <linux/smp_lock.h>
  30 +#include <linux/seq_file.h>
  31 +#include <linux/mount.h>
  32 +#include <linux/nfs_idmap.h>
  33 +#include <linux/vfs.h>
  34 +#include <linux/namei.h>
  35 +#include <linux/namespace.h>
  36 +
  37 +#include <asm/system.h>
  38 +#include <asm/uaccess.h>
  39 +
  40 +#include "nfs4_fs.h"
  41 +#include "delegation.h"
  42 +#include "internal.h"
  43 +
  44 +#define NFSDBG_FACILITY NFSDBG_CLIENT
  45 +#define NFS_PARANOIA 1
  46 +
  47 +/*
  48 + * get an NFS2/NFS3 root dentry from the root filehandle
  49 + */
  50 +struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh)
  51 +{
  52 + struct nfs_server *server = NFS_SB(sb);
  53 + struct nfs_fsinfo fsinfo;
  54 + struct nfs_fattr fattr;
  55 + struct dentry *mntroot;
  56 + struct inode *inode;
  57 + int error;
  58 +
  59 + /* create a dummy root dentry with dummy inode for this superblock */
  60 + if (!sb->s_root) {
  61 + struct nfs_fh dummyfh;
  62 + struct dentry *root;
  63 + struct inode *iroot;
  64 +
  65 + memset(&dummyfh, 0, sizeof(dummyfh));
  66 + memset(&fattr, 0, sizeof(fattr));
  67 + nfs_fattr_init(&fattr);
  68 + fattr.valid = NFS_ATTR_FATTR;
  69 + fattr.type = NFDIR;
  70 + fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
  71 + fattr.nlink = 2;
  72 +
  73 + iroot = nfs_fhget(sb, &dummyfh, &fattr);
  74 + if (IS_ERR(iroot))
  75 + return ERR_PTR(PTR_ERR(iroot));
  76 +
  77 + root = d_alloc_root(iroot);
  78 + if (!root) {
  79 + iput(iroot);
  80 + return ERR_PTR(-ENOMEM);
  81 + }
  82 +
  83 + sb->s_root = root;
  84 + }
  85 +
  86 + /* get the actual root for this mount */
  87 + fsinfo.fattr = &fattr;
  88 +
  89 + error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
  90 + if (error < 0) {
  91 + dprintk("nfs_get_root: getattr error = %d\n", -error);
  92 + return ERR_PTR(error);
  93 + }
  94 +
  95 + inode = nfs_fhget(sb, mntfh, fsinfo.fattr);
  96 + if (IS_ERR(inode)) {
  97 + dprintk("nfs_get_root: get root inode failed\n");
  98 + return ERR_PTR(PTR_ERR(inode));
  99 + }
  100 +
  101 + /* root dentries normally start off anonymous and get spliced in later
  102 + * if the dentry tree reaches them; however if the dentry already
  103 + * exists, we'll pick it up at this point and use it as the root
  104 + */
  105 + mntroot = d_alloc_anon(inode);
  106 + if (!mntroot) {
  107 + iput(inode);
  108 + dprintk("nfs_get_root: get root dentry failed\n");
  109 + return ERR_PTR(-ENOMEM);
  110 + }
  111 +
  112 + if (!mntroot->d_op)
  113 + mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
  114 +
  115 + return mntroot;
  116 +}
  117 +
  118 +#ifdef CONFIG_NFS_V4
  119 +
  120 +/*
  121 + * Do a simple pathwalk from the root FH of the server to the nominated target
  122 + * of the mountpoint
  123 + * - give error on symlinks
  124 + * - give error on ".." occurring in the path
  125 + * - follow traversals
  126 + */
  127 +int nfs4_path_walk(struct nfs_server *server,
  128 + struct nfs_fh *mntfh,
  129 + const char *path)
  130 +{
  131 + struct nfs_fsinfo fsinfo;
  132 + struct nfs_fattr fattr;
  133 + struct nfs_fh lastfh;
  134 + struct qstr name;
  135 + int ret;
  136 + //int referral_count = 0;
  137 +
  138 + dprintk("--> nfs4_path_walk(,,%s)\n", path);
  139 +
  140 + fsinfo.fattr = &fattr;
  141 + nfs_fattr_init(&fattr);
  142 +
  143 + if (*path++ != '/') {
  144 + dprintk("nfs4_get_root: Path does not begin with a slash\n");
  145 + return -EINVAL;
  146 + }
  147 +
  148 + /* Start by getting the root filehandle from the server */
  149 + ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo);
  150 + if (ret < 0) {
  151 + dprintk("nfs4_get_root: getroot error = %d\n", -ret);
  152 + return ret;
  153 + }
  154 +
  155 + if (fattr.type != NFDIR) {
  156 + printk(KERN_ERR "nfs4_get_root:"
  157 + " getroot encountered non-directory\n");
  158 + return -ENOTDIR;
  159 + }
  160 +
  161 + if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
  162 + printk(KERN_ERR "nfs4_get_root:"
  163 + " getroot obtained referral\n");
  164 + return -EREMOTE;
  165 + }
  166 +
  167 +next_component:
  168 + dprintk("Next: %s\n", path);
  169 +
  170 + /* extract the next bit of the path */
  171 + if (!*path)
  172 + goto path_walk_complete;
  173 +
  174 + name.name = path;
  175 + while (*path && *path != '/')
  176 + path++;
  177 + name.len = path - (const char *) name.name;
  178 +
  179 +eat_dot_dir:
  180 + while (*path == '/')
  181 + path++;
  182 +
  183 + if (path[0] == '.' && (path[1] == '/' || !path[1])) {
  184 + path += 2;
  185 + goto eat_dot_dir;
  186 + }
  187 +
  188 + if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2])
  189 + ) {
  190 + printk(KERN_ERR "nfs4_get_root:"
  191 + " Mount path contains reference to \"..\"\n");
  192 + return -EINVAL;
  193 + }
  194 +
  195 + /* lookup the next FH in the sequence */
  196 + memcpy(&lastfh, mntfh, sizeof(lastfh));
  197 +
  198 + dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path);
  199 +
  200 + ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name,
  201 + mntfh, &fattr);
  202 + if (ret < 0) {
  203 + dprintk("nfs4_get_root: getroot error = %d\n", -ret);
  204 + return ret;
  205 + }
  206 +
  207 + if (fattr.type != NFDIR) {
  208 + printk(KERN_ERR "nfs4_get_root:"
  209 + " lookupfh encountered non-directory\n");
  210 + return -ENOTDIR;
  211 + }
  212 +
  213 + if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) {
  214 + printk(KERN_ERR "nfs4_get_root:"
  215 + " lookupfh obtained referral\n");
  216 + return -EREMOTE;
  217 + }
  218 +
  219 + goto next_component;
  220 +
  221 +path_walk_complete:
  222 + memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid));
  223 + dprintk("<-- nfs4_path_walk() = 0\n");
  224 + return 0;
  225 +}
  226 +
  227 +/*
  228 + * get an NFS4 root dentry from the root filehandle
  229 + */
  230 +struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh)
  231 +{
  232 + struct nfs_server *server = NFS_SB(sb);
  233 + struct nfs_fattr fattr;
  234 + struct dentry *mntroot;
  235 + struct inode *inode;
  236 + int error;
  237 +
  238 + dprintk("--> nfs4_get_root()\n");
  239 +
  240 + /* create a dummy root dentry with dummy inode for this superblock */
  241 + if (!sb->s_root) {
  242 + struct nfs_fh dummyfh;
  243 + struct dentry *root;
  244 + struct inode *iroot;
  245 +
  246 + memset(&dummyfh, 0, sizeof(dummyfh));
  247 + memset(&fattr, 0, sizeof(fattr));
  248 + nfs_fattr_init(&fattr);
  249 + fattr.valid = NFS_ATTR_FATTR;
  250 + fattr.type = NFDIR;
  251 + fattr.mode = S_IFDIR | S_IRUSR | S_IWUSR;
  252 + fattr.nlink = 2;
  253 +
  254 + iroot = nfs_fhget(sb, &dummyfh, &fattr);
  255 + if (IS_ERR(iroot))
  256 + return ERR_PTR(PTR_ERR(iroot));
  257 +
  258 + root = d_alloc_root(iroot);
  259 + if (!root) {
  260 + iput(iroot);
  261 + return ERR_PTR(-ENOMEM);
  262 + }
  263 +
  264 + sb->s_root = root;
  265 + }
  266 +
  267 + /* get the info about the server and filesystem */
  268 + error = nfs4_server_capabilities(server, mntfh);
  269 + if (error < 0) {
  270 + dprintk("nfs_get_root: getcaps error = %d\n",
  271 + -error);
  272 + return ERR_PTR(error);
  273 + }
  274 +
  275 + /* get the actual root for this mount */
  276 + error = server->nfs_client->rpc_ops->getattr(server, mntfh, &fattr);
  277 + if (error < 0) {
  278 + dprintk("nfs_get_root: getattr error = %d\n", -error);
  279 + return ERR_PTR(error);
  280 + }
  281 +
  282 + inode = nfs_fhget(sb, mntfh, &fattr);
  283 + if (IS_ERR(inode)) {
  284 + dprintk("nfs_get_root: get root inode failed\n");
  285 + return ERR_PTR(PTR_ERR(inode));
  286 + }
  287 +
  288 + /* root dentries normally start off anonymous and get spliced in later
  289 + * if the dentry tree reaches them; however if the dentry already
  290 + * exists, we'll pick it up at this point and use it as the root
  291 + */
  292 + mntroot = d_alloc_anon(inode);
  293 + if (!mntroot) {
  294 + iput(inode);
  295 + dprintk("nfs_get_root: get root dentry failed\n");
  296 + return ERR_PTR(-ENOMEM);
  297 + }
  298 +
  299 + if (!mntroot->d_op)
  300 + mntroot->d_op = server->nfs_client->rpc_ops->dentry_ops;
  301 +
  302 + dprintk("<-- nfs4_get_root()\n");
  303 + return mntroot;
  304 +}
  305 +
  306 +#endif /* CONFIG_NFS_V4 */
... ... @@ -114,8 +114,7 @@
114 114 struct idmap *idmap;
115 115 int error;
116 116  
117   - if (clp->cl_idmap != NULL)
118   - return 0;
  117 + BUG_ON(clp->cl_idmap != NULL);
119 118  
120 119 if ((idmap = kzalloc(sizeof(*idmap), GFP_KERNEL)) == NULL)
121 120 return -ENOMEM;
... ... @@ -1020,7 +1020,7 @@
1020 1020 out_fileid:
1021 1021 printk(KERN_ERR "NFS: server %s error: fileid changed\n"
1022 1022 "fsid %s: expected fileid 0x%Lx, got 0x%Lx\n",
1023   - NFS_SERVER(inode)->hostname, inode->i_sb->s_id,
  1023 + NFS_SERVER(inode)->nfs_client->cl_hostname, inode->i_sb->s_id,
1024 1024 (long long)nfsi->fileid, (long long)fattr->fileid);
1025 1025 goto out_err;
1026 1026 }
... ... @@ -4,6 +4,18 @@
4 4  
5 5 #include <linux/mount.h>
6 6  
  7 +struct nfs_string;
  8 +struct nfs_mount_data;
  9 +struct nfs4_mount_data;
  10 +
  11 +/* Maximum number of readahead requests
  12 + * FIXME: this should really be a sysctl so that users may tune it to suit
  13 + * their needs. People that do NFS over a slow network, might for
  14 + * instance want to reduce it to something closer to 1 for improved
  15 + * interactive response.
  16 + */
  17 +#define NFS_MAX_READAHEAD (RPC_DEF_SLOT_TABLE - 1)
  18 +
7 19 struct nfs_clone_mount {
8 20 const struct super_block *sb;
9 21 const struct dentry *dentry;
10 22  
... ... @@ -16,12 +28,25 @@
16 28 };
17 29  
18 30 /* client.c */
  31 +extern struct rpc_program nfs_program;
  32 +
19 33 extern void nfs_put_client(struct nfs_client *);
20 34 extern struct nfs_client *nfs_find_client(const struct sockaddr_in *, int);
21   -extern struct nfs_client *nfs_get_client(const char *, const struct sockaddr_in *, int);
22   -extern void nfs_mark_client_ready(struct nfs_client *, int);
23   -extern int nfs_create_rpc_client(struct nfs_client *, int, unsigned int,
24   - unsigned int, rpc_authflavor_t);
  35 +extern struct nfs_server *nfs_create_server(const struct nfs_mount_data *,
  36 + struct nfs_fh *);
  37 +extern struct nfs_server *nfs4_create_server(const struct nfs4_mount_data *,
  38 + const char *,
  39 + const struct sockaddr_in *,
  40 + const char *,
  41 + const char *,
  42 + rpc_authflavor_t,
  43 + struct nfs_fh *);
  44 +extern struct nfs_server *nfs4_create_referral_server(struct nfs_clone_mount *,
  45 + struct nfs_fh *);
  46 +extern void nfs_free_server(struct nfs_server *server);
  47 +extern struct nfs_server *nfs_clone_server(struct nfs_server *,
  48 + struct nfs_fh *,
  49 + struct nfs_fattr *);
25 50  
26 51 /* nfs4namespace.c */
27 52 #ifdef CONFIG_NFS_V4
28 53  
... ... @@ -89,10 +114,10 @@
89 114 #endif
90 115  
91 116 /* super.c */
92   -extern struct file_system_type nfs_referral_nfs4_fs_type;
93   -extern struct file_system_type clone_nfs_fs_type;
  117 +extern struct file_system_type nfs_xdev_fs_type;
94 118 #ifdef CONFIG_NFS_V4
95   -extern struct file_system_type clone_nfs4_fs_type;
  119 +extern struct file_system_type nfs4_xdev_fs_type;
  120 +extern struct file_system_type nfs4_referral_fs_type;
96 121 #endif
97 122  
98 123 extern struct rpc_stat nfs_rpcstat;
99 124  
100 125  
101 126  
102 127  
... ... @@ -101,28 +126,30 @@
101 126 extern void __exit unregister_nfs_fs(void);
102 127  
103 128 /* namespace.c */
104   -extern char *nfs_path(const char *base, const struct dentry *dentry,
  129 +extern char *nfs_path(const char *base,
  130 + const struct dentry *droot,
  131 + const struct dentry *dentry,
105 132 char *buffer, ssize_t buflen);
106 133  
107   -/*
108   - * Determine the mount path as a string
109   - */
  134 +/* getroot.c */
  135 +extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *);
110 136 #ifdef CONFIG_NFS_V4
111   -static inline char *
112   -nfs4_path(const struct dentry *dentry, char *buffer, ssize_t buflen)
113   -{
114   - return nfs_path(NFS_SB(dentry->d_sb)->mnt_path, dentry, buffer, buflen);
115   -}
  137 +extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *);
  138 +
  139 +extern int nfs4_path_walk(struct nfs_server *server,
  140 + struct nfs_fh *mntfh,
  141 + const char *path);
116 142 #endif
117 143  
118 144 /*
119 145 * Determine the device name as a string
120 146 */
121 147 static inline char *nfs_devname(const struct vfsmount *mnt_parent,
122   - const struct dentry *dentry,
123   - char *buffer, ssize_t buflen)
  148 + const struct dentry *dentry,
  149 + char *buffer, ssize_t buflen)
124 150 {
125   - return nfs_path(mnt_parent->mnt_devname, dentry, buffer, buflen);
  151 + return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root,
  152 + dentry, buffer, buflen);
126 153 }
127 154  
128 155 /*
... ... @@ -177,22 +204,5 @@
177 204 sb->s_maxbytes = (loff_t)maxfilesize;
178 205 if (sb->s_maxbytes > MAX_LFS_FILESIZE || sb->s_maxbytes <= 0)
179 206 sb->s_maxbytes = MAX_LFS_FILESIZE;
180   -}
181   -
182   -/*
183   - * Check if the string represents a "valid" IPv4 address
184   - */
185   -static inline int valid_ipaddr4(const char *buf)
186   -{
187   - int rc, count, in[4];
188   -
189   - rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
190   - if (rc != 4)
191   - return -EINVAL;
192   - for (count = 0; count < 4; count++) {
193   - if (in[count] > 255)
194   - return -EINVAL;
195   - }
196   - return 0;
197 207 }
... ... @@ -2,6 +2,7 @@
2 2 * linux/fs/nfs/namespace.c
3 3 *
4 4 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
  5 + * - Modified by David Howells <dhowells@redhat.com>
5 6 *
6 7 * NFS namespace
7 8 */
... ... @@ -28,6 +29,7 @@
28 29 /*
29 30 * nfs_path - reconstruct the path given an arbitrary dentry
30 31 * @base - arbitrary string to prepend to the path
  32 + * @droot - pointer to root dentry for mountpoint
31 33 * @dentry - pointer to dentry
32 34 * @buffer - result buffer
33 35 * @buflen - length of buffer
... ... @@ -38,7 +40,9 @@
38 40 * This is mainly for use in figuring out the path on the
39 41 * server side when automounting on top of an existing partition.
40 42 */
41   -char *nfs_path(const char *base, const struct dentry *dentry,
  43 +char *nfs_path(const char *base,
  44 + const struct dentry *droot,
  45 + const struct dentry *dentry,
42 46 char *buffer, ssize_t buflen)
43 47 {
44 48 char *end = buffer+buflen;
... ... @@ -47,7 +51,7 @@
47 51 *--end = '\0';
48 52 buflen--;
49 53 spin_lock(&dcache_lock);
50   - while (!IS_ROOT(dentry)) {
  54 + while (!IS_ROOT(dentry) && dentry != droot) {
51 55 namelen = dentry->d_name.len;
52 56 buflen -= namelen + 1;
53 57 if (buflen < 0)
54 58  
... ... @@ -96,12 +100,13 @@
96 100 struct nfs_fattr fattr;
97 101 int err;
98 102  
  103 + dprintk("--> nfs_follow_mountpoint()\n");
  104 +
99 105 BUG_ON(IS_ROOT(dentry));
100 106 dprintk("%s: enter\n", __FUNCTION__);
101 107 dput(nd->dentry);
102 108 nd->dentry = dget(dentry);
103   - if (d_mountpoint(nd->dentry))
104   - goto out_follow;
  109 +
105 110 /* Look it up again */
106 111 parent = dget_parent(nd->dentry);
107 112 err = server->nfs_client->rpc_ops->lookup(parent->d_inode,
... ... @@ -134,6 +139,8 @@
134 139 schedule_delayed_work(&nfs_automount_task, nfs_mountpoint_expiry_timeout);
135 140 out:
136 141 dprintk("%s: done, returned %d\n", __FUNCTION__, err);
  142 +
  143 + dprintk("<-- nfs_follow_mountpoint() = %d\n", err);
137 144 return ERR_PTR(err);
138 145 out_err:
139 146 path_release(nd);
140 147  
141 148  
... ... @@ -183,14 +190,14 @@
183 190 switch (server->nfs_client->cl_nfsversion) {
184 191 case 2:
185 192 case 3:
186   - mnt = vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
  193 + mnt = vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
187 194 break;
188 195 case 4:
189   - mnt = vfs_kern_mount(&clone_nfs4_fs_type, 0, devname, mountdata);
  196 + mnt = vfs_kern_mount(&nfs4_xdev_fs_type, 0, devname, mountdata);
190 197 }
191 198 return mnt;
192 199 #else
193   - return vfs_kern_mount(&clone_nfs_fs_type, 0, devname, mountdata);
  200 + return vfs_kern_mount(&nfs_xdev_fs_type, 0, devname, mountdata);
194 201 #endif
195 202 }
196 203  
... ... @@ -216,6 +223,8 @@
216 223 char *page = (char *) __get_free_page(GFP_USER);
217 224 char *devname;
218 225  
  226 + dprintk("--> nfs_do_submount()\n");
  227 +
219 228 dprintk("%s: submounting on %s/%s\n", __FUNCTION__,
220 229 dentry->d_parent->d_name.name,
221 230 dentry->d_name.name);
... ... @@ -230,6 +239,8 @@
230 239 free_page((unsigned long)page);
231 240 out:
232 241 dprintk("%s: done\n", __FUNCTION__);
  242 +
  243 + dprintk("<-- nfs_do_submount() = %p\n", mnt);
233 244 return mnt;
234 245 }
... ... @@ -81,7 +81,7 @@
81 81 }
82 82  
83 83 /*
84   - * Bare-bones access to getattr: this is for nfs_read_super.
  84 + * Bare-bones access to getattr: this is for nfs_get_root/nfs_get_sb
85 85 */
86 86 static int
87 87 nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
... ... @@ -188,8 +188,6 @@
188 188 extern void nfs4_renew_state(void *);
189 189  
190 190 /* nfs4state.c */
191   -extern void init_nfsv4_state(struct nfs_server *);
192   -extern void destroy_nfsv4_state(struct nfs_server *);
193 191 struct rpc_cred *nfs4_get_renew_cred(struct nfs_client *clp);
194 192 extern u32 nfs4_alloc_lockowner_id(struct nfs_client *);
195 193  
... ... @@ -224,10 +222,6 @@
224 222  
225 223 #else
226 224  
227   -#define init_nfsv4_state(server) do { } while (0)
228   -#define destroy_nfsv4_state(server) do { } while (0)
229   -#define nfs4_put_state_owner(inode, owner) do { } while (0)
230   -#define nfs4_put_open_state(state) do { } while (0)
231 225 #define nfs4_close_state(a, b) do { } while (0)
232 226  
233 227 #endif /* CONFIG_NFS_V4 */
fs/nfs/nfs4namespace.c
... ... @@ -2,6 +2,7 @@
2 2 * linux/fs/nfs/nfs4namespace.c
3 3 *
4 4 * Copyright (C) 2005 Trond Myklebust <Trond.Myklebust@netapp.com>
  5 + * - Modified by David Howells <dhowells@redhat.com>
5 6 *
6 7 * NFSv4 namespace
7 8 */
8 9  
... ... @@ -47,7 +48,69 @@
47 48 return ERR_PTR(-ENAMETOOLONG);
48 49 }
49 50  
  51 +/*
  52 + * Determine the mount path as a string
  53 + */
  54 +static char *nfs4_path(const struct vfsmount *mnt_parent,
  55 + const struct dentry *dentry,
  56 + char *buffer, ssize_t buflen)
  57 +{
  58 + const char *srvpath;
50 59  
  60 + srvpath = strchr(mnt_parent->mnt_devname, ':');
  61 + if (srvpath)
  62 + srvpath++;
  63 + else
  64 + srvpath = mnt_parent->mnt_devname;
  65 +
  66 + return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen);
  67 +}
  68 +
  69 +/*
  70 + * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we
  71 + * believe to be the server path to this dentry
  72 + */
  73 +static int nfs4_validate_fspath(const struct vfsmount *mnt_parent,
  74 + const struct dentry *dentry,
  75 + const struct nfs4_fs_locations *locations,
  76 + char *page, char *page2)
  77 +{
  78 + const char *path, *fs_path;
  79 +
  80 + path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE);
  81 + if (IS_ERR(path))
  82 + return PTR_ERR(path);
  83 +
  84 + fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
  85 + if (IS_ERR(fs_path))
  86 + return PTR_ERR(fs_path);
  87 +
  88 + if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
  89 + dprintk("%s: path %s does not begin with fsroot %s\n",
  90 + __FUNCTION__, path, fs_path);
  91 + return -ENOENT;
  92 + }
  93 +
  94 + return 0;
  95 +}
  96 +
  97 +/*
  98 + * Check if the string represents a "valid" IPv4 address
  99 + */
  100 +static inline int valid_ipaddr4(const char *buf)
  101 +{
  102 + int rc, count, in[4];
  103 +
  104 + rc = sscanf(buf, "%d.%d.%d.%d", &in[0], &in[1], &in[2], &in[3]);
  105 + if (rc != 4)
  106 + return -EINVAL;
  107 + for (count = 0; count < 4; count++) {
  108 + if (in[count] > 255)
  109 + return -EINVAL;
  110 + }
  111 + return 0;
  112 +}
  113 +
51 114 /**
52 115 * nfs_follow_referral - set up mountpoint when hitting a referral on moved error
53 116 * @mnt_parent - mountpoint of parent directory
54 117  
... ... @@ -68,10 +131,9 @@
68 131 .dentry = dentry,
69 132 .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor,
70 133 };
71   - char *page, *page2;
72   - char *path, *fs_path;
  134 + char *page = NULL, *page2 = NULL;
73 135 char *devname;
74   - int loc, s;
  136 + int loc, s, error;
75 137  
76 138 if (locations == NULL || locations->nlocations <= 0)
77 139 goto out;
78 140  
79 141  
80 142  
81 143  
82 144  
... ... @@ -79,31 +141,25 @@
79 141 dprintk("%s: referral at %s/%s\n", __FUNCTION__,
80 142 dentry->d_parent->d_name.name, dentry->d_name.name);
81 143  
82   - /* Ensure fs path is a prefix of current dentry path */
83 144 page = (char *) __get_free_page(GFP_USER);
84   - if (page == NULL)
  145 + if (!page)
85 146 goto out;
  147 +
86 148 page2 = (char *) __get_free_page(GFP_USER);
87   - if (page2 == NULL)
  149 + if (!page2)
88 150 goto out;
89 151  
90   - path = nfs4_path(dentry, page, PAGE_SIZE);
91   - if (IS_ERR(path))
92   - goto out_free;
93   -
94   - fs_path = nfs4_pathname_string(&locations->fs_path, page2, PAGE_SIZE);
95   - if (IS_ERR(fs_path))
96   - goto out_free;
97   -
98   - if (strncmp(path, fs_path, strlen(fs_path)) != 0) {
99   - dprintk("%s: path %s does not begin with fsroot %s\n", __FUNCTION__, path, fs_path);
100   - goto out_free;
  152 + /* Ensure fs path is a prefix of current dentry path */
  153 + error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2);
  154 + if (error < 0) {
  155 + mnt = ERR_PTR(error);
  156 + goto out;
101 157 }
102 158  
103 159 devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE);
104 160 if (IS_ERR(devname)) {
105 161 mnt = (struct vfsmount *)devname;
106   - goto out_free;
  162 + goto out;
107 163 }
108 164  
109 165 loc = 0;
... ... @@ -140,7 +196,7 @@
140 196 addr.sin_port = htons(NFS_PORT);
141 197 mountdata.addr = &addr;
142 198  
143   - mnt = vfs_kern_mount(&nfs_referral_nfs4_fs_type, 0, devname, &mountdata);
  199 + mnt = vfs_kern_mount(&nfs4_referral_fs_type, 0, devname, &mountdata);
144 200 if (!IS_ERR(mnt)) {
145 201 break;
146 202 }
147 203  
... ... @@ -149,10 +205,9 @@
149 205 loc++;
150 206 }
151 207  
152   -out_free:
153   - free_page((unsigned long)page);
154   - free_page((unsigned long)page2);
155 208 out:
  209 + free_page((unsigned long) page);
  210 + free_page((unsigned long) page2);
156 211 dprintk("%s: done\n", __FUNCTION__);
157 212 return mnt;
158 213 }
... ... @@ -165,7 +220,7 @@
165 220 */
166 221 struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry)
167 222 {
168   - struct vfsmount *mnt = ERR_PTR(-ENOENT);
  223 + struct vfsmount *mnt = ERR_PTR(-ENOMEM);
169 224 struct dentry *parent;
170 225 struct nfs4_fs_locations *fs_locations = NULL;
171 226 struct page *page;
172 227  
173 228  
... ... @@ -183,11 +238,16 @@
183 238 goto out_free;
184 239  
185 240 /* Get locations */
  241 + mnt = ERR_PTR(-ENOENT);
  242 +
186 243 parent = dget_parent(dentry);
187   - dprintk("%s: getting locations for %s/%s\n", __FUNCTION__, parent->d_name.name, dentry->d_name.name);
  244 + dprintk("%s: getting locations for %s/%s\n",
  245 + __FUNCTION__, parent->d_name.name, dentry->d_name.name);
  246 +
188 247 err = nfs4_proc_fs_locations(parent->d_inode, dentry, fs_locations, page);
189 248 dput(parent);
190   - if (err != 0 || fs_locations->nlocations <= 0 ||
  249 + if (err != 0 ||
  250 + fs_locations->nlocations <= 0 ||
191 251 fs_locations->fs_path.ncomponents <= 0)
192 252 goto out_free;
193 253  
... ... @@ -1393,70 +1393,19 @@
1393 1393 return err;
1394 1394 }
1395 1395  
  1396 +/*
  1397 + * get the file handle for the "/" directory on the server
  1398 + */
1396 1399 static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
1397   - struct nfs_fsinfo *info)
  1400 + struct nfs_fsinfo *info)
1398 1401 {
1399   - struct nfs_fattr * fattr = info->fattr;
1400   - unsigned char * p;
1401   - struct qstr q;
1402   - struct nfs4_lookup_arg args = {
1403   - .dir_fh = fhandle,
1404   - .name = &q,
1405   - .bitmask = nfs4_fattr_bitmap,
1406   - };
1407   - struct nfs4_lookup_res res = {
1408   - .server = server,
1409   - .fattr = fattr,
1410   - .fh = fhandle,
1411   - };
1412   - struct rpc_message msg = {
1413   - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOOKUP],
1414   - .rpc_argp = &args,
1415   - .rpc_resp = &res,
1416   - };
1417 1402 int status;
1418 1403  
1419   - /*
1420   - * Now we do a separate LOOKUP for each component of the mount path.
1421   - * The LOOKUPs are done separately so that we can conveniently
1422   - * catch an ERR_WRONGSEC if it occurs along the way...
1423   - */
1424 1404 status = nfs4_lookup_root(server, fhandle, info);
1425   - if (status)
1426   - goto out;
1427   -
1428   - p = server->mnt_path;
1429   - for (;;) {
1430   - struct nfs4_exception exception = { };
1431   -
1432   - while (*p == '/')
1433   - p++;
1434   - if (!*p)
1435   - break;
1436   - q.name = p;
1437   - while (*p && (*p != '/'))
1438   - p++;
1439   - q.len = p - q.name;
1440   -
1441   - do {
1442   - nfs_fattr_init(fattr);
1443   - status = nfs4_handle_exception(server,
1444   - rpc_call_sync(server->client, &msg, 0),
1445   - &exception);
1446   - } while (exception.retry);
1447   - if (status == 0)
1448   - continue;
1449   - if (status == -ENOENT) {
1450   - printk(KERN_NOTICE "NFS: mount path %s does not exist!\n", server->mnt_path);
1451   - printk(KERN_NOTICE "NFS: suggestion: try mounting '/' instead.\n");
1452   - }
1453   - break;
1454   - }
1455 1405 if (status == 0)
1456 1406 status = nfs4_server_capabilities(server, fhandle);
1457 1407 if (status == 0)
1458 1408 status = nfs4_do_fsinfo(server, fhandle, info);
1459   -out:
1460 1409 return nfs4_map_errors(status);
1461 1410 }
1462 1411  
... ... @@ -127,26 +127,13 @@
127 127 void
128 128 nfs4_renewd_prepare_shutdown(struct nfs_server *server)
129 129 {
130   - struct nfs_client *clp = server->nfs_client;
131   -
132   - if (!clp)
133   - return;
134 130 flush_scheduled_work();
135   - down_write(&clp->cl_sem);
136   - if (!list_empty(&server->nfs4_siblings))
137   - list_del_init(&server->nfs4_siblings);
138   - up_write(&clp->cl_sem);
139 131 }
140 132  
141   -/* Must be called with clp->cl_sem locked for writes */
142 133 void
143 134 nfs4_kill_renewd(struct nfs_client *clp)
144 135 {
145 136 down_read(&clp->cl_sem);
146   - if (!list_empty(&clp->cl_superblocks)) {
147   - up_read(&clp->cl_sem);
148   - return;
149   - }
150 137 cancel_delayed_work(&clp->cl_renewd);
151 138 up_read(&clp->cl_sem);
152 139 flush_scheduled_work();
... ... @@ -58,24 +58,6 @@
58 58  
59 59 static LIST_HEAD(nfs4_clientid_list);
60 60  
61   -void
62   -init_nfsv4_state(struct nfs_server *server)
63   -{
64   - server->nfs_client = NULL;
65   - INIT_LIST_HEAD(&server->nfs4_siblings);
66   -}
67   -
68   -void
69   -destroy_nfsv4_state(struct nfs_server *server)
70   -{
71   - kfree(server->mnt_path);
72   - server->mnt_path = NULL;
73   - if (server->nfs_client) {
74   - nfs_put_client(server->nfs_client);
75   - server->nfs_client = NULL;
76   - }
77   -}
78   -
79 61 static int nfs4_init_client(struct nfs_client *clp, struct rpc_cred *cred)
80 62 {
81 63 int status = nfs4_proc_setclientid(clp, NFS4_CALLBACK,
... ... @@ -171,7 +171,7 @@
171 171 rdata->args.offset = page_offset(page) + rdata->args.pgbase;
172 172  
173 173 dprintk("NFS: nfs_proc_read(%s, (%s/%Ld), %Lu, %u)\n",
174   - NFS_SERVER(inode)->hostname,
  174 + NFS_SERVER(inode)->nfs_client->cl_hostname,
175 175 inode->i_sb->s_id,
176 176 (long long)NFS_FILEID(inode),
177 177 (unsigned long long)rdata->args.pgbase,
Changes suppressed. Click to show
... ... @@ -13,6 +13,11 @@
13 13 *
14 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 23 #include <linux/config.h>
19 24  
... ... @@ -52,20 +57,12 @@
52 57  
53 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   -
63 60 static void nfs_umount_begin(struct vfsmount *, int);
64 61 static int nfs_statfs(struct dentry *, struct kstatfs *);
65 62 static int nfs_show_options(struct seq_file *, struct vfsmount *);
66 63 static int nfs_show_stats(struct seq_file *, struct vfsmount *);
67 64 static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *);
68   -static int nfs_clone_nfs_sb(struct file_system_type *fs_type,
  65 +static int nfs_xdev_get_sb(struct file_system_type *fs_type,
69 66 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
70 67 static void nfs_kill_super(struct super_block *);
71 68  
72 69  
... ... @@ -77,10 +74,10 @@
77 74 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
78 75 };
79 76  
80   -struct file_system_type clone_nfs_fs_type = {
  77 +struct file_system_type nfs_xdev_fs_type = {
81 78 .owner = THIS_MODULE,
82 79 .name = "nfs",
83   - .get_sb = nfs_clone_nfs_sb,
  80 + .get_sb = nfs_xdev_get_sb,
84 81 .kill_sb = nfs_kill_super,
85 82 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
86 83 };
... ... @@ -99,10 +96,10 @@
99 96 #ifdef CONFIG_NFS_V4
100 97 static int nfs4_get_sb(struct file_system_type *fs_type,
101 98 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
102   -static int nfs_clone_nfs4_sb(struct file_system_type *fs_type,
103   - int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
104   -static int nfs_referral_nfs4_sb(struct file_system_type *fs_type,
105   - int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
  99 +static int nfs4_xdev_get_sb(struct file_system_type *fs_type,
  100 + int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
  101 +static int nfs4_referral_get_sb(struct file_system_type *fs_type,
  102 + int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt);
106 103 static void nfs4_kill_super(struct super_block *sb);
107 104  
108 105 static struct file_system_type nfs4_fs_type = {
109 106  
110 107  
111 108  
... ... @@ -113,18 +110,18 @@
113 110 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
114 111 };
115 112  
116   -struct file_system_type clone_nfs4_fs_type = {
  113 +struct file_system_type nfs4_xdev_fs_type = {
117 114 .owner = THIS_MODULE,
118 115 .name = "nfs4",
119   - .get_sb = nfs_clone_nfs4_sb,
  116 + .get_sb = nfs4_xdev_get_sb,
120 117 .kill_sb = nfs4_kill_super,
121 118 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
122 119 };
123 120  
124   -struct file_system_type nfs_referral_nfs4_fs_type = {
  121 +struct file_system_type nfs4_referral_fs_type = {
125 122 .owner = THIS_MODULE,
126 123 .name = "nfs4",
127   - .get_sb = nfs_referral_nfs4_sb,
  124 + .get_sb = nfs4_referral_get_sb,
128 125 .kill_sb = nfs4_kill_super,
129 126 .fs_flags = FS_ODD_RENAME|FS_REVAL_DOT|FS_BINARY_MOUNTDATA,
130 127 };
... ... @@ -345,7 +342,7 @@
345 342 nfs_show_mount_options(m, nfss, 0);
346 343  
347 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 347 return 0;
351 348 }
352 349  
353 350  
354 351  
355 352  
356 353  
357 354  
358 355  
359 356  
360 357  
361 358  
362 359  
363 360  
364 361  
365 362  
366 363  
367 364  
368 365  
369 366  
370 367  
371 368  
372 369  
373 370  
374 371  
375 372  
376 373  
377 374  
378 375  
379 376  
380 377  
381 378  
382 379  
383 380  
384 381  
385 382  
386 383  
387 384  
388 385  
389 386  
390 387  
391 388  
392 389  
393 390  
394 391  
395 392  
396 393  
397 394  
398 395  
399 396  
400 397  
401 398  
402 399  
403 400  
404 401  
405 402  
406 403  
407 404  
408 405  
409 406  
410 407  
411 408  
412 409  
413 410  
414 411  
415 412  
416 413  
417 414  
418 415  
419 416  
420 417  
421 418  
422 419  
423 420  
424 421  
425 422  
426 423  
427 424  
428 425  
429 426  
430 427  
431 428  
432 429  
433 430  
434 431  
... ... @@ -429,714 +426,351 @@
429 426  
430 427 /*
431 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 */
434 431 static void nfs_umount_begin(struct vfsmount *vfsmnt, int flags)
435 432 {
436   - struct nfs_server *server;
437   - struct rpc_clnt *rpc;
438   -
439 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 */
455   -static struct inode *
456   -nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh, struct nfs_fsinfo *fsinfo)
  440 +static int nfs_validate_mount_data(struct nfs_mount_data *data,
  441 + struct nfs_fh *mntfh)
457 442 {
458   - struct nfs_server *server = NFS_SB(sb);
459   - int error;
460   -
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);
  443 + if (data == NULL) {
  444 + dprintk("%s: missing data argument\n", __FUNCTION__);
  445 + return -EINVAL;
465 446 }
466 447  
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   - */
474   -static int
475   -nfs_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;
  448 + if (data->version <= 0 || data->version > NFS_MOUNT_VERSION) {
  449 + dprintk("%s: bad mount version\n", __FUNCTION__);
  450 + return -EINVAL;
505 451 }
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   - }
511   - sb->s_root->d_op = server->nfs_client->rpc_ops->dentry_ops;
512 452  
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   -
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;
  453 + switch (data->version) {
  454 + case 1:
  455 + data->namlen = 0;
  456 + case 2:
  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));
559 478 }
560   - server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD;
561 479  
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. */
571   -out_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   -/*
579   - * Create an RPC client handle.
580   - */
581   -static struct rpc_clnt *
582   -nfs_create_client(struct nfs_server *server, const struct nfs_mount_data *data)
583   -{
584   - struct nfs_client *clp;
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));
  480 +#ifndef CONFIG_NFS_V3
  481 + /* If NFSv3 is not compiled in, return -EPROTONOSUPPORT */
  482 + if (data->flags & NFS_MOUNT_VER3) {
  483 + dprintk("%s: NFSv3 not compiled into kernel\n", __FUNCTION__);
  484 + return -EPROTONOSUPPORT;
599 485 }
  486 +#endif /* CONFIG_NFS_V3 */
600 487  
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);
  488 + /* We now require that the mount process passes the remote address */
  489 + if (data->addr.sin_addr.s_addr == INADDR_ANY) {
  490 + dprintk("%s: mount program didn't pass remote address!\n",
  491 + __FUNCTION__);
  492 + return -EINVAL;
622 493 }
623 494  
624   - /* create an nfs_server-specific client */
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   - }
  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;
631 500  
632   - if (data->pseudoflavor != clp->cl_rpcclient->cl_auth->au_flavor) {
633   - struct rpc_auth *auth;
634   -
635   - 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   - }
  501 + if (mntfh->size > sizeof(mntfh->data)) {
  502 + dprintk("%s: invalid root filehandle\n", __FUNCTION__);
  503 + return -EINVAL;
640 504 }
641 505  
642   - server->nfs_client = clp;
643   - return clnt;
  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);
644 510  
645   -client_init_error:
646   - nfs_mark_client_ready(clp, err);
647   - nfs_put_client(clp);
648   - return ERR_PTR(err);
  511 + return 0;
649 512 }
650 513  
651 514 /*
652   - * Clone a server record
  515 + * Initialise the common bits of the superblock
653 516 */
654   -static struct nfs_server *nfs_clone_server(struct super_block *sb, struct nfs_clone_mount *data)
  517 +static inline void nfs_initialise_sb(struct super_block *sb)
655 518 {
656 519 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 520  
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;
  521 + sb->s_magic = NFS_SUPER_MAGIC;
666 522  
667   - server->client_acl = ERR_PTR(-EINVAL);
668   - server->io_stats = nfs_alloc_iostats();
669   - if (server->io_stats == NULL)
670   - goto out;
  523 + /* We probably want something more informative here */
  524 + snprintf(sb->s_id, sizeof(sb->s_id),
  525 + "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev));
671 526  
672   - server->client = rpc_clone_client(parent->client);
673   - if (IS_ERR((err = server->client)))
674   - goto out;
  527 + if (sb->s_blocksize == 0)
  528 + sb->s_blocksize = nfs_block_bits(server->wsize,
  529 + &sb->s_blocksize_bits);
675 530  
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;
693   -out_put_root:
694   - iput(root_inode);
695   -out:
696   - return err;
  531 + if (server->flags & NFS_MOUNT_NOAC)
  532 + sb->s_flags |= MS_SYNCHRONOUS;
  533 +
  534 + nfs_super_set_maxbytes(sb, server->maxfilesize);
697 535 }
698 536  
699 537 /*
700   - * Copy an existing superblock and attach revised data
  538 + * Finish setting up an NFS2/3 superblock
701 539 */
702   -static 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)
  540 +static void nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data)
706 541 {
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;
  542 + struct nfs_server *server = NFS_SB(sb);
713 543  
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);
  544 + sb->s_blocksize_bits = 0;
  545 + sb->s_blocksize = 0;
  546 + if (data->bsize)
  547 + sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
725 548  
726   - sb = fill_sb(server, data);
727   - if (IS_ERR(sb)) {
728   - error = PTR_ERR(sb);
729   - goto free_hostname;
  549 + if (server->flags & NFS_MOUNT_VER3) {
  550 + /* The VFS shouldn't apply the umask to mode bits. We will do
  551 + * so ourselves when necessary.
  552 + */
  553 + sb->s_flags |= MS_POSIXACL;
  554 + sb->s_time_gran = 1;
730 555 }
731 556  
732   - if (sb->s_root)
733   - goto out_share;
734   -
735   - server = fill_server(sb, data);
736   - if (IS_ERR(server)) {
737   - error = PTR_ERR(server);
738   - goto out_deactivate;
739   - }
740   - return simple_set_mnt(mnt, sb);
741   -out_deactivate:
742   - up_write(&sb->s_umount);
743   - deactivate_super(sb);
744   - return error;
745   -out_share:
746   - kfree(server->hostname);
747   - nfs_put_client(server->nfs_client);
748   - kfree(server);
749   - return simple_set_mnt(mnt, sb);
750   -free_hostname:
751   - kfree(server->hostname);
752   -free_server:
753   - nfs_put_client(server->nfs_client);
754   - kfree(server);
755   -out_err:
756   - return error;
  557 + sb->s_op = &nfs_sops;
  558 + nfs_initialise_sb(sb);
757 559 }
758 560  
759 561 /*
760   - * Set up an 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.
  562 + * Finish setting up a cloned NFS2/3 superblock
766 563 */
767   -static int
768   -nfs_fill_super(struct super_block *sb, struct nfs_mount_data *data, int silent)
  564 +static void nfs_clone_super(struct super_block *sb,
  565 + const struct super_block *old_sb)
769 566 {
770   - struct nfs_server *server;
771   - rpc_authflavor_t authflavor;
  567 + struct nfs_server *server = NFS_SB(sb);
772 568  
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;
  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;
783 572  
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 573 if (server->flags & NFS_MOUNT_VER3) {
812   -#ifdef CONFIG_NFS_V3_ACL
813   - if (!(server->flags & NFS_MOUNT_NOACL)) {
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.
  574 + /* The VFS shouldn't apply the umask to mode bits. We will do
  575 + * so ourselves when necessary.
825 576 */
826 577 sb->s_flags |= MS_POSIXACL;
827   - if (server->namelen == 0 || server->namelen > NFS3_MAXNAMLEN)
828   - server->namelen = NFS3_MAXNAMLEN;
829 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;
836   - return nfs_sb_init(sb, authflavor);
  581 + sb->s_op = old_sb->s_op;
  582 + nfs_initialise_sb(sb);
837 583 }
838 584  
839   -static int nfs_set_super(struct super_block *s, void *data)
  585 +static int nfs_set_super(struct super_block *s, void *_server)
840 586 {
841   - s->s_fs_info = data;
842   - return set_anon_super(s, data);
  587 + struct nfs_server *server = _server;
  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  
845 597 static int nfs_compare_super(struct super_block *sb, void *data)
846 598 {
847   - struct nfs_server *server = data;
848   - struct nfs_server *old = NFS_SB(sb);
  599 + struct nfs_server *server = data, *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 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 604 return 0;
854   - return !nfs_compare_fh(&old->fh, &server->fh);
  605 + return 1;
855 606 }
856 607  
857 608 static int nfs_get_sb(struct file_system_type *fs_type,
858 609 int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
859 610 {
860   - int error;
861 611 struct nfs_server *server = NULL;
862 612 struct super_block *s;
863   - struct nfs_fh *root;
  613 + struct nfs_fh mntfh;
864 614 struct nfs_mount_data *data = raw_data;
  615 + struct dentry *mntroot;
  616 + int error;
865 617  
866   - error = -EINVAL;
867   - if (data == NULL) {
868   - dprintk("%s: missing data argument\n", __FUNCTION__);
869   - goto out_err_noserver;
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 */
  618 + /* Validate the mount data */
  619 + error = nfs_validate_mount_data(data, &mntfh);
  620 + if (error < 0)
  621 + return error;
907 622  
908   - error = -ENOMEM;
909   - server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
910   - if (!server)
  623 + /* Get a volume representation */
  624 + server = nfs_create_server(data, &mntfh);
  625 + if (IS_ERR(server)) {
  626 + error = PTR_ERR(server);
911 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 628 }
926   - memcpy(root->data, data->root.data, root->size);
927 629  
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   - }
935   -
  630 + /* Get a superblock - note that we may end up sharing one that already exists */
936 631 s = sget(fs_type, nfs_compare_super, nfs_set_super, server);
937 632 if (IS_ERR(s)) {
938 633 error = PTR_ERR(s);
939   - goto out_err;
  634 + goto out_err_nosb;
940 635 }
941 636  
942   - if (s->s_root)
943   - goto out_share;
  637 + if (s->s_fs_info != server) {
  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);
948   - if (error) {
949   - up_write(&s->s_umount);
950   - deactivate_super(s);
951   - return error;
  648 + mntroot = nfs_get_root(s, &mntfh);
  649 + if (IS_ERR(mntroot)) {
  650 + error = PTR_ERR(mntroot);
  651 + goto error_splat_super;
952 652 }
  653 +
953 654 s->s_flags |= MS_ACTIVE;
954   - return simple_set_mnt(mnt, s);
  655 + mnt->mnt_sb = s;
  656 + mnt->mnt_root = mntroot;
  657 + return 0;
955 658  
956   -out_share:
957   - kfree(server);
958   - return simple_set_mnt(mnt, s);
959   -
960   -out_err:
961   - kfree(server);
  659 +out_err_nosb:
  660 + nfs_free_server(server);
962 661 out_err_noserver:
963 662 return error;
  663 +
  664 +error_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 + */
966 673 static void nfs_kill_super(struct super_block *s)
967 674 {
968 675 struct nfs_server *server = NFS_SB(s);
969 676  
970 677 kill_anon_super(s);
971   -
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();
  678 + nfs_free_server(server);
985 679 }
986 680  
987   -static struct super_block *nfs_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data)
  681 +/*
  682 + * Clone an NFS2/3 server record on xdev traversal (FSID-change)
  683 + */
  684 +static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags,
  685 + const char *dev_name, void *raw_data,
  686 + struct vfsmount *mnt)
988 687 {
989   - struct super_block *sb;
990   -
991   - server->fsid = data->fattr->fsid;
992   - nfs_copy_fh(&server->fh, data->fh);
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   -
999   -static 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   -{
1002 688 struct nfs_clone_mount *data = raw_data;
1003   - return nfs_clone_generic_sb(data, nfs_clone_sb, nfs_clone_server, mnt);
1004   -}
  689 + struct super_block *s;
  690 + struct nfs_server *server;
  691 + struct dentry *mntroot;
  692 + int error;
1005 693  
1006   -#ifdef CONFIG_NFS_V4
1007   -static 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;
  694 + dprintk("--> nfs_xdev_get_sb()\n");
1013 695  
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);
  696 + /* create a new volume representation */
  697 + server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
  698 + if (IS_ERR(server)) {
  699 + error = PTR_ERR(server);
  700 + goto out_err_noserver;
1018 701 }
1019 702  
1020   - /* Now create transport and client */
1021   - if (clp->cl_cons_state == NFS_CS_INITING) {
1022   - clp->rpc_ops = &nfs_v4_clientops;
  703 + /* Get a superblock - note that we may end up sharing one that already exists */
  704 + s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
  705 + if (IS_ERR(s)) {
  706 + error = PTR_ERR(s);
  707 + goto out_err_nosb;
  708 + }
1023 709  
1024   - err = nfs_create_rpc_client(clp, proto, timeo, retrans, flavor);
1025   - if (err < 0)
1026   - goto client_init_error;
  710 + if (s->s_fs_info != server) {
  711 + nfs_free_server(server);
  712 + server = NULL;
  713 + }
1027 714  
1028   - memcpy(clp->cl_ipaddr, server->ip_addr, sizeof(clp->cl_ipaddr));
1029   - err = nfs_idmap_new(clp);
1030   - if (err < 0) {
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);
  715 + if (!s->s_root) {
  716 + /* initial superblock/root creation */
  717 + s->s_flags = flags;
  718 + nfs_clone_super(s, data->sb);
1037 719 }
1038 720  
1039   - clnt = rpc_clone_client(clp->cl_rpcclient);
1040   -
1041   - if (IS_ERR(clnt)) {
1042   - dprintk("%s: cannot create RPC client. Error = %d\n",
1043   - __FUNCTION__, err);
1044   - return clnt;
  721 + mntroot = nfs_get_root(s, data->fh);
  722 + if (IS_ERR(mntroot)) {
  723 + error = PTR_ERR(mntroot);
  724 + goto error_splat_super;
1045 725 }
1046 726  
1047   - if (clnt->cl_auth->au_flavor != flavor) {
1048   - struct rpc_auth *auth;
  727 + s->s_flags |= MS_ACTIVE;
  728 + mnt->mnt_sb = s;
  729 + mnt->mnt_root = mntroot;
1049 730  
1050   - auth = rpcauth_create(flavor, clnt);
1051   - if (IS_ERR(auth)) {
1052   - dprintk("%s: couldn't create credcache!\n", __FUNCTION__);
1053   - return (struct rpc_clnt *)auth;
1054   - }
1055   - }
  731 + dprintk("<-- nfs_xdev_get_sb() = 0\n");
  732 + return 0;
1056 733  
1057   - server->nfs_client = clp;
1058   - down_write(&clp->cl_sem);
1059   - list_add_tail(&server->nfs4_siblings, &clp->cl_superblocks);
1060   - up_write(&clp->cl_sem);
1061   - return clnt;
  734 +out_err_nosb:
  735 + nfs_free_server(server);
  736 +out_err_noserver:
  737 + dprintk("<-- nfs_xdev_get_sb() = %d [error]\n", error);
  738 + return error;
1062 739  
1063   -client_init_error:
1064   - nfs_mark_client_ready(clp, err);
1065   - nfs_put_client(clp);
1066   - return ERR_PTR(err);
  740 +error_splat_super:
  741 + up_write(&s->s_umount);
  742 + deactivate_super(s);
  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 */
1072   -static int nfs4_fill_super(struct super_block *sb, struct nfs4_mount_data *data, int silent)
  752 +static void nfs4_clone_super(struct super_block *sb,
  753 + const struct super_block *old_sb)
1073 754 {
1074   - struct nfs_server *server;
1075   - rpc_authflavor_t authflavour;
1076   - int err = -EIO;
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   -
  755 + sb->s_blocksize_bits = old_sb->s_blocksize_bits;
  756 + sb->s_blocksize = old_sb->s_blocksize;
  757 + sb->s_maxbytes = old_sb->s_maxbytes;
1117 758 sb->s_time_gran = 1;
1118   -
1119   - sb->s_op = &nfs4_sops;
1120   - err = nfs_sb_init(sb, authflavour);
1121   -
1122   - out_fail:
1123   - return err;
  759 + sb->s_op = old_sb->s_op;
  760 + nfs_initialise_sb(sb);
1124 761 }
1125 762  
1126   -static int nfs4_compare_super(struct super_block *sb, void *data)
  763 +/*
  764 + * Set up an NFS4 superblock
  765 + */
  766 +static void nfs4_fill_super(struct super_block *sb)
1127 767 {
1128   - struct nfs_server *server = data;
1129   - struct nfs_server *old = NFS_SB(sb);
1130   -
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;
  768 + sb->s_time_gran = 1;
  769 + sb->s_op = &nfs4_sops;
  770 + nfs_initialise_sb(sb);
1136 771 }
1137 772  
1138   -static void *
1139   -nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
  773 +static void *nfs_copy_user_string(char *dst, struct nfs_string *src, int maxlen)
1140 774 {
1141 775 void *p = NULL;
1142 776  
1143 777  
1144 778  
1145 779  
... ... @@ -1157,14 +791,22 @@
1157 791 return dst;
1158 792 }
1159 793  
  794 +/*
  795 + * Get the superblock for an NFS4 mountpoint
  796 + */
1160 797 static int nfs4_get_sb(struct file_system_type *fs_type,
1161 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 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 808 void *p;
  809 + int error;
1168 810  
1169 811 if (data == NULL) {
1170 812 dprintk("%s: missing data argument\n", __FUNCTION__);
1171 813  
1172 814  
1173 815  
1174 816  
1175 817  
1176 818  
1177 819  
1178 820  
1179 821  
1180 822  
1181 823  
1182 824  
1183 825  
1184 826  
... ... @@ -1175,75 +817,107 @@
1175 817 return -EINVAL;
1176 818 }
1177 819  
1178   - server = kzalloc(sizeof(struct nfs_server), GFP_KERNEL);
1179   - if (!server)
1180   - return -ENOMEM;
1181   - /* Zero out the NFS state stuff */
1182   - init_nfsv4_state(server);
1183   - server->client = server->client_acl = ERR_PTR(-EINVAL);
  820 + /* We now require that the mount process passes the remote address */
  821 + if (data->host_addrlen != sizeof(addr))
  822 + return -EINVAL;
1184 823  
  824 + if (copy_from_user(&addr, data->host_addr, sizeof(addr)))
  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 + }
  851 +
1185 852 p = nfs_copy_user_string(NULL, &data->hostname, 256);
1186 853 if (IS_ERR(p))
1187 854 goto out_err;
1188   - server->hostname = p;
  855 + hostname = p;
1189 856  
1190 857 p = nfs_copy_user_string(NULL, &data->mnt_path, 1024);
1191 858 if (IS_ERR(p))
1192 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,
1196   - sizeof(server->ip_addr) - 1);
  862 + dprintk("MNTPATH: %s\n", mntpath);
  863 +
  864 + p = nfs_copy_user_string(ip_addr, &data->client_addr,
  865 + sizeof(ip_addr) - 1);
1197 866 if (IS_ERR(p))
1198 867 goto out_err;
1199 868  
1200   - /* We now require that the mount process passes the remote address */
1201   - if (data->host_addrlen != sizeof(server->addr)) {
1202   - error = -EINVAL;
1203   - goto out_free;
  869 + /* Get a volume representation */
  870 + server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr,
  871 + authflavour, &mntfh);
  872 + if (IS_ERR(server)) {
  873 + error = PTR_ERR(server);
  874 + goto out_err_noserver;
1204 875 }
1205   - if (copy_from_user(&server->addr, data->host_addr, sizeof(server->addr))) {
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   - }
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 879 if (IS_ERR(s)) {
1219 880 error = PTR_ERR(s);
1220 881 goto out_free;
1221 882 }
1222 883  
1223   - if (s->s_root) {
1224   - kfree(server->mnt_path);
1225   - kfree(server->hostname);
1226   - kfree(server);
1227   - return simple_set_mnt(mnt, s);
  884 + if (!s->s_root) {
  885 + /* initial superblock/root creation */
  886 + s->s_flags = flags;
  887 +
  888 + nfs4_fill_super(s);
  889 + } else {
  890 + nfs_free_server(server);
1228 891 }
1229 892  
1230   - s->s_flags = flags;
1231   -
1232   - error = nfs4_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
1233   - if (error) {
1234   - up_write(&s->s_umount);
1235   - deactivate_super(s);
1236   - return error;
  893 + mntroot = nfs4_get_root(s, &mntfh);
  894 + if (IS_ERR(mntroot)) {
  895 + error = PTR_ERR(mntroot);
  896 + goto error_splat_super;
1237 897 }
  898 +
1238 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 +
1240 906 out_err:
1241 907 error = PTR_ERR(p);
  908 + goto out_err_noserver;
  909 +
1242 910 out_free:
1243   - kfree(server->mnt_path);
1244   - kfree(server->hostname);
1245   - kfree(server);
  911 + nfs_free_server(server);
  912 +out_err_noserver:
  913 + kfree(mntpath);
  914 + kfree(hostname);
1246 915 return error;
  916 +
  917 +error_splat_super:
  918 + up_write(&s->s_umount);
  919 + deactivate_super(s);
  920 + goto out_err_noserver;
1247 921 }
1248 922  
1249 923 static void nfs4_kill_super(struct super_block *sb)
1250 924  
1251 925  
1252 926  
1253 927  
1254 928  
1255 929  
1256 930  
1257 931  
1258 932  
1259 933  
1260 934  
1261 935  
1262 936  
1263 937  
1264 938  
1265 939  
1266 940  
1267 941  
1268 942  
1269 943  
1270 944  
... ... @@ -1254,134 +928,141 @@
1254 928 kill_anon_super(sb);
1255 929  
1256 930 nfs4_renewd_prepare_shutdown(server);
1257   -
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();
  931 + nfs_free_server(server);
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 */
1272   -static inline char *nfs4_dup_path(const struct dentry *dentry)
  937 +static 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);
1275   - char *path;
  941 + struct nfs_clone_mount *data = raw_data;
  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);
1278   - if (!IS_ERR(path)) {
1279   - int len = PAGE_SIZE + page - path;
1280   - char *tmp = path;
  947 + dprintk("--> nfs4_xdev_get_sb()\n");
1281 948  
1282   - path = kmalloc(len, GFP_KERNEL);
1283   - if (path)
1284   - memcpy(path, tmp, len);
1285   - else
1286   - path = ERR_PTR(-ENOMEM);
  949 + /* create a new volume representation */
  950 + server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr);
  951 + if (IS_ERR(server)) {
  952 + error = PTR_ERR(server);
  953 + goto out_err_noserver;
1287 954 }
1288   - free_page((unsigned long)page);
1289   - return path;
1290   -}
1291 955  
1292   -static struct super_block *nfs4_clone_sb(struct nfs_server *server, struct nfs_clone_mount *data)
1293   -{
1294   - const struct dentry *dentry = data->dentry;
1295   - struct nfs_client *clp = server->nfs_client;
1296   - struct super_block *sb;
  956 + /* Get a superblock - note that we may end up sharing one that already exists */
  957 + s = sget(&nfs_fs_type, nfs_compare_super, nfs_set_super, server);
  958 + if (IS_ERR(s)) {
  959 + error = PTR_ERR(s);
  960 + goto out_err_nosb;
  961 + }
1297 962  
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;
  963 + if (s->s_fs_info != server) {
  964 + nfs_free_server(server);
  965 + server = NULL;
1304 966 }
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 967  
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;
1314   -free_path:
1315   - kfree(server->mnt_path);
1316   -err:
1317   - server->mnt_path = NULL;
1318   - return sb;
  968 + if (!s->s_root) {
  969 + /* initial superblock/root creation */
  970 + s->s_flags = flags;
  971 + nfs4_clone_super(s, data->sb);
  972 + }
  973 +
  974 + mntroot = nfs4_get_root(s, data->fh);
  975 + if (IS_ERR(mntroot)) {
  976 + error = PTR_ERR(mntroot);
  977 + goto error_splat_super;
  978 + }
  979 +
  980 + s->s_flags |= MS_ACTIVE;
  981 + mnt->mnt_sb = s;
  982 + mnt->mnt_root = mntroot;
  983 +
  984 + dprintk("<-- nfs4_xdev_get_sb() = 0\n");
  985 + return 0;
  986 +
  987 +out_err_nosb:
  988 + nfs_free_server(server);
  989 +out_err_noserver:
  990 + dprintk("<-- nfs4_xdev_get_sb() = %d [error]\n", error);
  991 + return error;
  992 +
  993 +error_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;
1319 998 }
1320 999  
1321   -static int nfs_clone_nfs4_sb(struct file_system_type *fs_type,
1322   - int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
  1000 +/*
  1001 + * Create an NFS4 server record on referral traversal
  1002 + */
  1003 +static 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)
1323 1006 {
1324 1007 struct nfs_clone_mount *data = raw_data;
1325   - return nfs_clone_generic_sb(data, nfs4_clone_sb, nfs_clone_server, mnt);
1326   -}
  1008 + struct super_block *s;
  1009 + struct nfs_server *server;
  1010 + struct dentry *mntroot;
  1011 + struct nfs_fh mntfh;
  1012 + int error;
1327 1013  
1328   -static struct super_block *nfs4_referral_sb(struct nfs_server *server, struct nfs_clone_mount *data)
1329   -{
1330   - struct super_block *sb = ERR_PTR(-ENOMEM);
1331   - int len;
  1014 + dprintk("--> nfs4_referral_get_sb()\n");
1332 1015  
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));
  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 + }
1339 1022  
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;
1344   -free_path:
1345   - kfree(server->mnt_path);
1346   -err:
1347   - server->mnt_path = NULL;
1348   - return sb;
1349   -}
  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 + }
1350 1029  
1351   -static struct nfs_server *nfs4_referral_server(struct super_block *sb, struct nfs_clone_mount *data)
1352   -{
1353   - struct nfs_server *server = NFS_SB(sb);
1354   - int proto, timeo, retrans;
1355   - void *err;
  1030 + if (s->s_fs_info != server) {
  1031 + nfs_free_server(server);
  1032 + server = NULL;
  1033 + }
1356 1034  
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;
  1035 + if (!s->s_root) {
  1036 + /* initial superblock/root creation */
  1037 + s->s_flags = flags;
  1038 + nfs4_fill_super(s);
  1039 + }
1362 1040  
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;
  1041 + mntroot = nfs4_get_root(s, data->fh);
  1042 + if (IS_ERR(mntroot)) {
  1043 + error = PTR_ERR(mntroot);
  1044 + goto error_splat_super;
  1045 + }
1369 1046  
1370   - sb->s_time_gran = 1;
1371   - sb->s_op = &nfs4_sops;
1372   - err = ERR_PTR(nfs_sb_init(sb, data->authflavor));
1373   - if (!IS_ERR(err))
1374   - return server;
1375   -out_err:
1376   - return (struct nfs_server *)err;
1377   -}
  1047 + s->s_flags |= MS_ACTIVE;
  1048 + mnt->mnt_sb = s;
  1049 + mnt->mnt_root = mntroot;
1378 1050  
1379   -static int nfs_referral_nfs4_sb(struct file_system_type *fs_type,
1380   - int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt)
1381   -{
1382   - struct nfs_clone_mount *data = raw_data;
1383   - return nfs_clone_generic_sb(data, nfs4_referral_sb, nfs4_referral_server, mnt);
  1051 + dprintk("<-- nfs4_referral_get_sb() = 0\n");
  1052 + return 0;
  1053 +
  1054 +out_err_nosb:
  1055 + nfs_free_server(server);
  1056 +out_err_noserver:
  1057 + dprintk("<-- nfs4_referral_get_sb() = %d [error]\n", error);
  1058 + return error;
  1059 +
  1060 +error_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 */
... ... @@ -1273,7 +1273,7 @@
1273 1273 if (time_before(complain, jiffies)) {
1274 1274 dprintk("NFS: faulty NFS server %s:"
1275 1275 " (committed = %d) != (stable = %d)\n",
1276   - NFS_SERVER(data->inode)->hostname,
  1276 + NFS_SERVER(data->inode)->nfs_client->cl_hostname,
1277 1277 resp->verf->committed, argp->stable);
1278 1278 complain = jiffies + 300 * HZ;
1279 1279 }
include/linux/nfs_fs_sb.h
... ... @@ -51,7 +51,6 @@
51 51 unsigned long cl_lease_time;
52 52 unsigned long cl_last_renewal;
53 53 struct work_struct cl_renewd;
54   - struct work_struct cl_recoverd;
55 54  
56 55 struct rpc_wait_queue cl_rpcwaitq;
57 56  
... ... @@ -74,6 +73,10 @@
74 73 */
75 74 struct nfs_server {
76 75 struct nfs_client * nfs_client; /* shared client and NFS4 state */
  76 + struct list_head client_link; /* List of other nfs_server structs
  77 + * that share the same client
  78 + */
  79 + struct list_head master_link; /* link in master servers list */
77 80 struct rpc_clnt * client; /* RPC client handle */
78 81 struct rpc_clnt * client_acl; /* ACL RPC client handle */
79 82 struct nfs_iostats * io_stats; /* I/O statistics */
80 83  
81 84  
82 85  
... ... @@ -92,20 +95,13 @@
92 95 unsigned int acdirmin;
93 96 unsigned int acdirmax;
94 97 unsigned int namelen;
95   - char * hostname; /* remote hostname */
96   - struct nfs_fh fh;
97   - struct sockaddr_in addr;
  98 +
98 99 struct nfs_fsid fsid;
  100 + __u64 maxfilesize; /* maximum file size */
99 101 unsigned long mount_time; /* when this fs was mounted */
  102 + dev_t s_dev; /* superblock dev numbers */
  103 +
100 104 #ifdef CONFIG_NFS_V4
101   - /* Our own IP address, as a null-terminated string.
102   - * This is used to generate the clientid, and the callback address.
103   - */
104   - char ip_addr[16];
105   - char * mnt_path;
106   - struct list_head nfs4_siblings; /* List of other nfs_server structs
107   - * that share the same clientid
108   - */
109 105 u32 attr_bitmask[2];/* V4 bitmask representing the set
110 106 of attributes supported on this
111 107 filesystem */
... ... @@ -113,6 +109,7 @@
113 109 that are supported on this
114 110 filesystem */
115 111 #endif
  112 + void (*destroy)(struct nfs_server *);
116 113 };
117 114  
118 115 /* Server capabilities */