]> git.hungrycats.org Git - linux/commitdiff
NFSv4: Recover delegations on server reboot.
authorTrond Myklebust <trond.myklebust@fys.uio.no>
Mon, 23 Aug 2004 15:58:37 +0000 (11:58 -0400)
committerTrond Myklebust <trond.myklebust@fys.uio.no>
Mon, 23 Aug 2004 15:58:37 +0000 (11:58 -0400)
Signed-off-by: Trond Myklebust <trond.myklebust@fys.uio.no>
fs/nfs/delegation.c
fs/nfs/delegation.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c

index 25841e1b59904df3b3d33de2a68e509b19cf2385..2d8863790451f923ff74d041d3695ee8c095c153 100644 (file)
@@ -54,6 +54,24 @@ again:
        spin_unlock(&inode->i_lock);
 }
 
+/*
+ * Set up a delegation on an inode
+ */
+void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res)
+{
+       struct nfs_delegation *delegation = NFS_I(inode)->delegation;
+
+       if (delegation == NULL)
+               return;
+       memcpy(delegation->stateid.data, res->delegation.data,
+                       sizeof(delegation->stateid.data));
+       delegation->type = res->delegation_type;
+       delegation->maxsize = res->maxsize;
+       put_rpccred(cred);
+       delegation->cred = get_rpccred(cred);
+       delegation->flags &= ~NFS_DELEGATION_NEED_RECLAIM;
+}
+
 /*
  * Set up a delegation on an inode
  */
@@ -258,3 +276,37 @@ struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nf
        spin_unlock(&clp->cl_lock);
        return res;
 }
+
+/*
+ * Mark all delegations as needing to be reclaimed
+ */
+void nfs_delegation_mark_reclaim(struct nfs4_client *clp)
+{
+       struct nfs_delegation *delegation;
+       spin_lock(&clp->cl_lock);
+       list_for_each_entry(delegation, &clp->cl_delegations, super_list)
+               delegation->flags |= NFS_DELEGATION_NEED_RECLAIM;
+       spin_unlock(&clp->cl_lock);
+}
+
+/*
+ * Reap all unclaimed delegations after reboot recovery is done
+ */
+void nfs_delegation_reap_unclaimed(struct nfs4_client *clp)
+{
+       struct nfs_delegation *delegation, *n;
+       LIST_HEAD(head);
+       spin_lock(&clp->cl_lock);
+       list_for_each_entry_safe(delegation, n, &clp->cl_delegations, super_list) {
+               if ((delegation->flags & NFS_DELEGATION_NEED_RECLAIM) == 0)
+                       continue;
+               list_move(&delegation->super_list, &head);
+               NFS_I(delegation->inode)->delegation = NULL;
+       }
+       spin_unlock(&clp->cl_lock);
+       while(!list_empty(&head)) {
+               delegation = list_entry(head.next, struct nfs_delegation, super_list);
+               list_del(&delegation->super_list);
+               nfs_free_delegation(delegation);
+       }
+}
index e0c05d8ae2280ccd188cc7a898c06fb472b49142..be76feacb2f76e4b60c5319eca49f4ba95b423f8 100644 (file)
@@ -17,15 +17,22 @@ struct nfs_delegation {
        struct inode *inode;
        nfs4_stateid stateid;
        int type;
+#define NFS_DELEGATION_NEED_RECLAIM 1
+       long flags;
        loff_t maxsize;
 };
 
 int nfs_inode_set_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
+void nfs_inode_reclaim_delegation(struct inode *inode, struct rpc_cred *cred, struct nfs_openres *res);
 int nfs_inode_return_delegation(struct inode *inode);
 int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid);
 
 struct inode *nfs_delegation_find_inode(struct nfs4_client *clp, const struct nfs_fh *fhandle);
 void nfs_return_all_delegations(struct super_block *sb);
+
+void nfs_delegation_mark_reclaim(struct nfs4_client *clp);
+void nfs_delegation_reap_unclaimed(struct nfs4_client *clp);
+
 /* NFSv4 delegation-related procedures */
 int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid);
 int nfs4_open_delegation_recall(struct dentry *dentry, struct nfs4_state *state);
index 6cde8877714b53802eb8578c7adad1cb2f64594b..d1142a2304f98ef690484baaca6d799dc7b3785e 100644 (file)
@@ -196,6 +196,7 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
 {
        struct inode *inode = state->inode;
        struct nfs_server *server = NFS_SERVER(inode);
+       struct nfs_delegation *delegation = NFS_I(inode)->delegation;
        struct nfs_openargs o_arg = {
                .fh = NFS_FH(inode),
                .seqid = sp->so_seqid,
@@ -216,17 +217,27 @@ static int _nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *st
        };
        int status;
 
+       if (delegation != NULL) {
+               if (!(delegation->flags & NFS_DELEGATION_NEED_RECLAIM)) {
+                       memcpy(&state->stateid, &delegation->stateid,
+                                       sizeof(state->stateid));
+                       set_bit(NFS_DELEGATED_STATE, &state->flags);
+                       return 0;
+               }
+               o_arg.u.delegation_type = delegation->type;
+       }
        status = rpc_call_sync(server->client, &msg, 0);
        nfs4_increment_seqid(status, sp);
        if (status == 0) {
                memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
                if (o_res.delegation_type != 0) {
-                       nfs_inode_set_delegation(inode, sp->so_cred, &o_res);
+                       nfs_inode_reclaim_delegation(inode, sp->so_cred, &o_res);
                        /* Did the server issue an immediate delegation recall? */
                        if (o_res.do_recall)
                                nfs_async_inode_return_delegation(inode, &o_res.stateid);
                }
        }
+       clear_bit(NFS_DELEGATED_STATE, &state->flags);
        /* Ensure we update the inode attributes */
        NFS_CACHEINV(inode);
        return status;
index b62078d7f8110659f5bf1d9b2f7b336879249751..20068657e24b96825cc30483c776e3c1ef064a18 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/bitops.h>
 
 #include "callback.h"
+#include "delegation.h"
 
 #define OPENOWNER_POOL_SIZE    8
 
@@ -862,6 +863,8 @@ restart_loop:
        status = nfs4_init_client(clp);
        if (status)
                goto out_error;
+       /* Mark all delagations for reclaim */
+       nfs_delegation_mark_reclaim(clp);
        /* Note: list is protected by exclusive lock on cl->cl_sem */
        list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
                status = nfs4_reclaim_open_state(sp);
@@ -871,6 +874,7 @@ restart_loop:
                        goto out_error;
                }
        }
+       nfs_delegation_reap_unclaimed(clp);
 out:
        set_bit(NFS4CLNT_OK, &clp->cl_state);
        up_write(&clp->cl_sem);