NFSv4.1: Fix umount when filelayout DS is also the MDS
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 14 Jun 2012 17:08:38 +0000 (13:08 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Mon, 18 Jun 2012 12:45:16 +0000 (08:45 -0400)
Currently there is a 'chicken and egg' issue when the DS is also the mounted
MDS. The nfs_match_client() reference from nfs4_set_ds_client bumps the
cl_count, the nfs_client is not freed at umount, and nfs4_deviceid_purge_client
is not called to dereference the MDS usage of a deviceid which holds a
reference to the DS nfs_client.  The result is the umount program returns,
but the nfs_client is not freed, and the cl_session hearbeat continues.

The MDS (and all other nfs mounts) lose their last nfs_client reference in
nfs_free_server when the last nfs_server (fsid) is umounted.
The file layout DS lose their last nfs_client reference in destroy_ds
when the last deviceid referencing the data server is put and destroy_ds is
called. This is triggered by a call to nfs4_deviceid_purge_client which
removes references to a pNFS deviceid used by an MDS mount.

The fix is to track how many pnfs enabled filesystems are mounted from
this server, and then to purge the device id cache once that count reaches
zero.

Reported-by: Jorge Mora <Jorge.Mora@netapp.com>
Reported-by: Andy Adamson <andros@netapp.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/client.c
fs/nfs/pnfs.c
include/linux/nfs_fs_sb.h

index 17ba6b9956593ccac90c094b486840bd2fc427cd..f005b5bebdc73bba4d548d134699dd4f00c471ca 100644 (file)
@@ -207,7 +207,6 @@ error_0:
 static void nfs4_shutdown_session(struct nfs_client *clp)
 {
        if (nfs4_has_session(clp)) {
-               nfs4_deviceid_purge_client(clp);
                nfs4_destroy_session(clp->cl_session);
                nfs4_destroy_clientid(clp);
        }
index b8323aa7b54384af8f51b84b3077d98b8f22d951..bdf7e52943c8ef982e91a9092ee08ecac2a84e77 100644 (file)
@@ -80,6 +80,9 @@ unset_pnfs_layoutdriver(struct nfs_server *nfss)
        if (nfss->pnfs_curr_ld) {
                if (nfss->pnfs_curr_ld->clear_layoutdriver)
                        nfss->pnfs_curr_ld->clear_layoutdriver(nfss);
+               /* Decrement the MDS count. Purge the deviceid cache if zero */
+               if (atomic_dec_and_test(&nfss->nfs_client->cl_mds_count))
+                       nfs4_deviceid_purge_client(nfss->nfs_client);
                module_put(nfss->pnfs_curr_ld->owner);
        }
        nfss->pnfs_curr_ld = NULL;
@@ -127,6 +130,8 @@ set_pnfs_layoutdriver(struct nfs_server *server, const struct nfs_fh *mntfh,
                module_put(ld_type->owner);
                goto out_no_driver;
        }
+       /* Bump the MDS count */
+       atomic_inc(&server->nfs_client->cl_mds_count);
 
        dprintk("%s: pNFS module for %u set\n", __func__, id);
        return;
index fbb78fb09bd25c925d65207643bf61da614167d8..f58325a1d8fbe290fb8a7eb6e4ddc060ef553f91 100644 (file)
@@ -25,6 +25,7 @@ struct nfs41_impl_id;
  */
 struct nfs_client {
        atomic_t                cl_count;
+       atomic_t                cl_mds_count;
        int                     cl_cons_state;  /* current construction state (-ve: init error) */
 #define NFS_CS_READY           0               /* ready to be used */
 #define NFS_CS_INITING         1               /* busy initialising */