NFSv4: Be less aggressive about returning delegations for open files
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Wed, 3 Apr 2013 18:33:49 +0000 (14:33 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 5 Apr 2013 21:03:55 +0000 (17:03 -0400)
Currently, if the application that holds the file open isn't doing
I/O, we may end up returning the delegation. This means that we can
no longer cache the file as aggressively, and often also that we
multiply the state that both the server and the client needs to track.

This patch adds a check for open files to the routine that scans
for delegations that are unreferenced.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/delegation.c
fs/nfs/delegation.h

index fc8a213497a1d60f9341983a4ee1a244de474114..a377ea36381e8dbbfe2f57b792bb9b4fad397aed 100644 (file)
@@ -389,6 +389,24 @@ out:
        return err;
 }
 
+static bool nfs_delegation_need_return(struct nfs_delegation *delegation)
+{
+       bool ret = false;
+
+       if (test_and_clear_bit(NFS_DELEGATION_RETURN, &delegation->flags))
+               ret = true;
+       if (test_and_clear_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags) && !ret) {
+               struct inode *inode;
+
+               spin_lock(&delegation->lock);
+               inode = delegation->inode;
+               if (inode && list_empty(&NFS_I(inode)->open_files))
+                       ret = true;
+               spin_unlock(&delegation->lock);
+       }
+       return ret;
+}
+
 /**
  * nfs_client_return_marked_delegations - return previously marked delegations
  * @clp: nfs_client to process
@@ -411,8 +429,7 @@ restart:
        list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
                list_for_each_entry_rcu(delegation, &server->delegations,
                                                                super_list) {
-                       if (!test_and_clear_bit(NFS_DELEGATION_RETURN,
-                                                       &delegation->flags))
+                       if (!nfs_delegation_need_return(delegation))
                                continue;
                        inode = nfs_delegation_grab_inode(delegation);
                        if (inode == NULL)
@@ -471,6 +488,13 @@ int nfs4_inode_return_delegation(struct inode *inode)
        return err;
 }
 
+static void nfs_mark_return_if_closed_delegation(struct nfs_server *server,
+               struct nfs_delegation *delegation)
+{
+       set_bit(NFS_DELEGATION_RETURN_IF_CLOSED, &delegation->flags);
+       set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state);
+}
+
 static void nfs_mark_return_delegation(struct nfs_server *server,
                struct nfs_delegation *delegation)
 {
@@ -574,7 +598,7 @@ static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server)
        list_for_each_entry_rcu(delegation, &server->delegations, super_list) {
                if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags))
                        continue;
-               nfs_mark_return_delegation(server, delegation);
+               nfs_mark_return_if_closed_delegation(server, delegation);
        }
 }
 
index 88573d107502542263d1cfa9d5c97e3bcc4380b2..22f0a138e5514303b47634b242ff262516a36850 100644 (file)
@@ -28,6 +28,7 @@ struct nfs_delegation {
 enum {
        NFS_DELEGATION_NEED_RECLAIM = 0,
        NFS_DELEGATION_RETURN,
+       NFS_DELEGATION_RETURN_IF_CLOSED,
        NFS_DELEGATION_REFERENCED,
        NFS_DELEGATION_RETURNING,
 };