NFSv4.1: Don't cache deviceids that have no notifications
authorTrond Myklebust <trond.myklebust@primarydata.com>
Mon, 9 Mar 2015 18:48:32 +0000 (14:48 -0400)
committerTrond Myklebust <trond.myklebust@primarydata.com>
Fri, 27 Mar 2015 16:32:24 +0000 (12:32 -0400)
The spec says that once all layouts that reference a given deviceid
have been returned, then we are only allowed to continue to cache
the deviceid if the metadata server supports notifications.

Signed-off-by: Trond Myklebust <trond.myklebust@primarydata.com>
fs/nfs/nfs4proc.c
fs/nfs/pnfs.h
fs/nfs/pnfs_dev.c

index ba8b2b5e98a165d22a103bad909f4ba7ac5944b7..9ff8c63c9cac29189cbe40259b1d6bd27a749a77 100644 (file)
@@ -7962,6 +7962,8 @@ _nfs4_proc_getdeviceinfo(struct nfs_server *server,
        status = nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0);
        if (res.notification & ~args.notify_types)
                dprintk("%s: unsupported notification\n", __func__);
+       if (res.notification != args.notify_types)
+               pdev->nocache = 1;
 
        dprintk("<-- %s status=%d\n", __func__, status);
 
index a1fc16c971a7f98c8e2ca963fe13899013226f1e..b5654e8da936733f6ef85b2130a9ae24fabad462 100644 (file)
@@ -203,6 +203,7 @@ struct pnfs_device {
        struct page **pages;
        unsigned int  pgbase;
        unsigned int  pglen;    /* reply buffer length */
+       unsigned char nocache : 1;/* May not be cached */
 };
 
 #define NFS4_PNFS_GETDEVLIST_MAXNUM 16
@@ -291,6 +292,7 @@ void pnfs_error_mark_layout_for_return(struct inode *inode,
 enum {
        NFS_DEVICEID_INVALID = 0,       /* set when MDS clientid recalled */
        NFS_DEVICEID_UNAVAILABLE,       /* device temporarily unavailable */
+       NFS_DEVICEID_NOCACHE,           /* device may not be cached */
 };
 
 /* pnfs_dev.c */
index 7e07f4ba482268410bf970cd0664f61a642f92ad..2961fcd7a2df9292bf4f611287c2e48bdfe31ad2 100644 (file)
@@ -149,6 +149,8 @@ nfs4_get_device_info(struct nfs_server *server,
         */
        d = server->pnfs_curr_ld->alloc_deviceid_node(server, pdev,
                        gfp_flags);
+       if (d && pdev->nocache)
+               set_bit(NFS_DEVICEID_NOCACHE, &d->flags);
 
 out_free_pages:
        for (i = 0; i < max_pages; i++)
@@ -235,6 +237,7 @@ nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld,
                return;
        }
        hlist_del_init_rcu(&d->node);
+       clear_bit(NFS_DEVICEID_NOCACHE, &d->flags);
        spin_unlock(&nfs4_deviceid_lock);
 
        /* balance the initial ref set in pnfs_insert_deviceid */
@@ -269,6 +272,11 @@ EXPORT_SYMBOL_GPL(nfs4_init_deviceid_node);
 bool
 nfs4_put_deviceid_node(struct nfs4_deviceid_node *d)
 {
+       if (test_bit(NFS_DEVICEID_NOCACHE, &d->flags)) {
+               if (atomic_add_unless(&d->ref, -1, 2))
+                       return false;
+               nfs4_delete_deviceid(d->ld, d->nfs_client, &d->deviceid);
+       }
        if (!atomic_dec_and_test(&d->ref))
                return false;
        d->ld->free_deviceid_node(d);
@@ -312,6 +320,7 @@ _deviceid_purge_client(const struct nfs_client *clp, long hash)
                if (d->nfs_client == clp && atomic_read(&d->ref)) {
                        hlist_del_init_rcu(&d->node);
                        hlist_add_head(&d->tmpnode, &tmp);
+                       clear_bit(NFS_DEVICEID_NOCACHE, &d->flags);
                }
        rcu_read_unlock();
        spin_unlock(&nfs4_deviceid_lock);