]> git.hungrycats.org Git - linux/commitdiff
NFSv4: Preparation for the server reboot recovery code.
authorTrond Myklebust <trond.myklebust@fys.uio.no>
Sat, 7 Feb 2004 15:57:57 +0000 (16:57 +0100)
committerTrond Myklebust <trond.myklebust@fys.uio.no>
Sat, 7 Feb 2004 15:57:57 +0000 (16:57 +0100)
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c
include/linux/nfs4.h
include/linux/nfs_fs.h
include/linux/nfs_xdr.h

index 8e8ac9cc08f6da9989b5402c8d12844b3cf11a71..5e52e7d218f8886c0ad51ec86b1012ac0275f5c5 100644 (file)
@@ -458,6 +458,54 @@ process_cinfo(struct nfs4_change_info *info, struct nfs_fattr *fattr)
        }
 }
 
+/*
+ * OPEN_RECLAIM:
+ *     reclaim state on the server after a reboot.
+ *     Assumes caller is holding the sp->so_sem
+ */
+int
+nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *state)
+{
+       struct inode *inode = state->inode;
+       struct nfs_server *server = NFS_SERVER(inode);
+       struct nfs_fattr fattr = {
+               .valid = 0,
+       };
+       struct nfs4_change_info d_cinfo;
+       struct nfs4_getattr     f_getattr = {
+               .gt_bmval       = nfs4_fattr_bitmap,
+               .gt_attrs       = &fattr,
+       };
+
+       struct nfs_open_reclaimargs o_arg = {
+               .fh = NFS_FH(inode),
+               .seqid = sp->so_seqid,
+               .id = sp->so_id,
+               .share_access = state->state,
+               .clientid = server->nfs4_state->cl_clientid,
+               .claim = NFS4_OPEN_CLAIM_PREVIOUS,
+               .f_getattr = &f_getattr,
+       };
+       struct nfs_openres o_res = {
+               .cinfo = &d_cinfo,
+               .f_getattr = &f_getattr,
+               .server = server,       /* Grrr */
+       };
+       struct rpc_message msg = {
+               .rpc_proc       = &nfs4_procedures[NFSPROC4_CLNT_OPEN_RECLAIM],
+               .rpc_argp       = &o_arg,
+               .rpc_resp       = &o_res,
+               .rpc_cred       = sp->so_cred,
+       };
+       int status;
+
+       status = rpc_call_sync(server->client, &msg, 0);
+       nfs4_increment_seqid(status, sp);
+       /* Update the inode attributes */
+       nfs_refresh_inode(inode, &fattr);
+       return status;
+}
+
 struct nfs4_state *
 nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *sattr, struct rpc_cred *cred)
 {
@@ -523,10 +571,9 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
        o_arg.id = sp->so_id;
 
        status = rpc_call_sync(server->client, &msg, 0);
-       if (status) {
-               goto out_up;
-       }
        nfs4_increment_seqid(status, sp);
+       if (status)
+               goto out_up;
        process_cinfo(&d_cinfo, &d_attr);
        nfs_refresh_inode(dir, &d_attr);
 
@@ -555,9 +602,9 @@ nfs4_do_open(struct inode *dir, struct qstr *name, int flags, struct iattr *satt
 
                memcpy(&oc_arg.stateid, &o_res.stateid, sizeof(oc_arg.stateid));
                status = rpc_call_sync(server->client, &msg, 0);
+               nfs4_increment_seqid(status, sp);
                if (status)
                        goto out_up;
-               nfs4_increment_seqid(status, sp);
                memcpy(&state->stateid, &oc_res.stateid, sizeof(state->stateid));
        } else
                memcpy(&state->stateid, &o_res.stateid, sizeof(state->stateid));
index 3bdb3a016e25862fc2a9b44555182fc2820d787a..8738414bd8ea11625da7aa1912cb7c62ffa83539 100644 (file)
@@ -382,6 +382,95 @@ nfs4_increment_seqid(int status, struct nfs4_state_owner *sp)
                sp->so_seqid++;
 }
 
+static int reclaimer(void *);
+struct reclaimer_args {
+       struct nfs4_client *clp;
+       struct completion complete;
+};
+
+/*
+ * State recovery routine
+ */
+void
+nfs4_recover_state(struct nfs4_client *clp)
+{
+       struct reclaimer_args args = {
+               .clp = clp,
+       };
+       init_completion(&args.complete);
+
+       down_read(&clp->cl_sem);
+       if (kernel_thread(reclaimer, &args, CLONE_KERNEL) < 0)
+               goto out_failed;
+       wait_for_completion(&args.complete);
+       return;
+out_failed:
+       up_read(&clp->cl_sem);
+}
+
+static void
+nfs4_reclaim_open_state(struct nfs4_state_owner *sp)
+{
+       struct nfs4_state *state;
+       int status;
+
+       list_for_each_entry(state, &sp->so_states, open_states) {
+               status = nfs4_open_reclaim(sp, state);
+               if (status) {
+                       /*
+                        * Open state on this file cannot be recovered
+                        * All we can do is revert to using the zero stateid.
+                        */
+                       memset(state->stateid.data, 0,
+                                       sizeof(state->stateid.data));
+                       /* Mark the file as being 'closed' */
+                       state->state = 0;
+               }
+       }
+}
+
+static int
+reclaimer(void *ptr)
+{
+       struct reclaimer_args *args = (struct reclaimer_args *)ptr;
+       struct nfs4_client *clp = args->clp;
+       struct nfs4_state_owner *sp;
+       int status;
+
+       daemonize("%u.%u.%u.%u-reclaim", NIPQUAD(clp->cl_addr));
+       allow_signal(SIGKILL);
+
+       complete(&args->complete);
+
+       /* Are there any NFS mounts out there? */
+       if (list_empty(&clp->cl_superblocks))
+               goto out;
+       status = nfs4_proc_setclientid(clp, 0, 0);
+       if (status)
+               goto out_error;
+       status = nfs4_proc_setclientid_confirm(clp);
+       if (status)
+               goto out_error;
+       spin_lock(&clp->cl_lock);
+       list_for_each_entry(sp, &clp->cl_state_owners, so_list) {
+               atomic_inc(&sp->so_count);
+               spin_unlock(&clp->cl_lock);
+               down(&sp->so_sema);
+               nfs4_reclaim_open_state(sp);
+               up(&sp->so_sema);
+               nfs4_put_state_owner(sp);
+               spin_lock(&clp->cl_lock);
+       }
+       spin_unlock(&clp->cl_lock);
+out:
+       up_read(&clp->cl_sem);
+       return 0;
+out_error:
+       printk(KERN_WARNING "Error: state recovery failed on NFSv4 server %u.%u.%u.%u\n",
+                               NIPQUAD(clp->cl_addr.s_addr));
+       goto out;
+}
+
 /*
  * Local variables:
  *  c-basic-offset: 8
index 67a8e7cf403b8fc829ca974676f3e463d450454b..16296618a2313183e1112842398268cb9450ed33 100644 (file)
@@ -166,6 +166,16 @@ static int nfs_stat_to_errno(int);
 #define NFS4_dec_open_confirm_sz        compound_decode_hdr_maxsz + \
                                         decode_putfh_maxsz + \
                                         op_decode_hdr_maxsz + 4
+#define NFS4_enc_open_reclaim_sz       compound_encode_hdr_maxsz + \
+                                       encode_putfh_maxsz + \
+                                       op_encode_hdr_maxsz + \
+                                       11 + \
+                                       encode_getattr_maxsz
+#define NFS4_dec_open_reclaim_sz       compound_decode_hdr_maxsz + \
+                                       decode_putfh_maxsz + \
+                                       op_decode_hdr_maxsz + \
+                                       4 + 5 + 2 + 3 + \
+                                       decode_getattr_maxsz
 #define NFS4_enc_close_sz       compound_encode_hdr_maxsz + \
                                 encode_putfh_maxsz + \
                                 op_encode_hdr_maxsz + 5
@@ -666,6 +676,41 @@ encode_open_confirm(struct xdr_stream *xdr, struct nfs_open_confirmargs *arg)
 }
 
 
+static int
+encode_open_reclaim(struct xdr_stream *xdr, struct nfs_open_reclaimargs *arg)
+{
+       uint32_t *p;
+
+ /*
+ * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4,
+ * owner 4, opentype 4, claim 4, delegation_type 4 = 44
+ */
+       RESERVE_SPACE(44);
+       WRITE32(OP_OPEN);
+       WRITE32(arg->seqid);
+       switch (arg->share_access) {
+               case FMODE_READ:
+                       WRITE32(NFS4_SHARE_ACCESS_READ);
+                       break;
+               case FMODE_WRITE:
+                       WRITE32(NFS4_SHARE_ACCESS_WRITE);
+                       break;
+               case FMODE_READ|FMODE_WRITE:
+                       WRITE32(NFS4_SHARE_ACCESS_BOTH);
+                       break;
+               default:
+                       BUG();
+       }
+       WRITE32(0);                  /* for linux, share_deny = 0 always */
+       WRITE64(arg->clientid);
+       WRITE32(4);
+       WRITE32(arg->id);
+       WRITE32(NFS4_OPEN_NOCREATE);
+       WRITE32(NFS4_OPEN_CLAIM_PREVIOUS);
+       WRITE32(NFS4_OPEN_DELEGATE_NONE);
+       return 0;
+}
+
 static int
 encode_putfh(struct xdr_stream *xdr, struct nfs_fh *fh)
 {
@@ -1058,6 +1103,32 @@ out:
        return status;
 }
 
+/*
+ * Encode an OPEN request
+ */
+static int
+nfs4_xdr_enc_open_reclaim(struct rpc_rqst *req, uint32_t *p,
+               struct nfs_open_reclaimargs *args)
+{
+       struct xdr_stream xdr;
+       struct compound_hdr hdr = {
+               .nops   = 3,
+       };
+       int status;
+
+       xdr_init_encode(&xdr, &req->rq_snd_buf, p);
+       encode_compound_hdr(&xdr, &hdr);
+       status = encode_putfh(&xdr, args->fh);
+       if (status)
+               goto out;
+       status = encode_open_reclaim(&xdr, args);
+       if (status)
+               goto out;
+       status = encode_getattr(&xdr, args->f_getattr);
+out:
+       return status;
+}
+
 
 /*
  * Encode a READ request
@@ -2417,6 +2488,31 @@ out:
         return status;
 }
 
+/*
+ * Decode OPEN_RECLAIM response
+ */
+static int
+nfs4_xdr_dec_open_reclaim(struct rpc_rqst *rqstp, uint32_t *p, struct nfs_openres *res)
+{
+        struct xdr_stream xdr;
+        struct compound_hdr hdr;
+        int status;
+
+        xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
+        status = decode_compound_hdr(&xdr, &hdr);
+        if (status)
+                goto out;
+        status = decode_putfh(&xdr);
+        if (status)
+                goto out;
+        status = decode_open(&xdr, res);
+        if (status)
+                goto out;
+        status = decode_getattr(&xdr, res->f_getattr, res->server);
+out:
+        return status;
+}
+
 /*
  * Decode SETATTR response
  */
@@ -2730,6 +2826,7 @@ struct rpc_procinfo       nfs4_procedures[] = {
   PROC(COMMIT,         enc_commit,     dec_commit),
   PROC(OPEN,           enc_open,       dec_open),
   PROC(OPEN_CONFIRM,   enc_open_confirm,       dec_open_confirm),
+  PROC(OPEN_RECLAIM,   enc_open_reclaim,       dec_open_reclaim),
   PROC(CLOSE,          enc_close,      dec_close),
   PROC(SETATTR,                enc_setattr,    dec_setattr),
   PROC(FSINFO,         enc_fsinfo,     dec_fsinfo),
index f56601a5825dfd8139d19fe4af59a6bada040780..a6f2d563b60515aa556e06aa2fd770c0de5a32e9 100644 (file)
@@ -289,6 +289,7 @@ enum {
        NFSPROC4_CLNT_COMMIT,
        NFSPROC4_CLNT_OPEN,
        NFSPROC4_CLNT_OPEN_CONFIRM,
+       NFSPROC4_CLNT_OPEN_RECLAIM,
        NFSPROC4_CLNT_CLOSE,
        NFSPROC4_CLNT_SETATTR,
        NFSPROC4_CLNT_FSINFO,
index a005c999ce43993defdfe4b552a6d00ebc40685e..b43412088372654a3d8d46aede3d89d5b5915926 100644 (file)
@@ -554,6 +554,7 @@ struct nfs4_state {
 /* nfs4proc.c */
 extern int nfs4_proc_setclientid(struct nfs4_client *, u32, unsigned short);
 extern int nfs4_proc_setclientid_confirm(struct nfs4_client *);
+extern int nfs4_open_reclaim(struct nfs4_state_owner *, struct nfs4_state *);
 extern int nfs4_proc_async_renew(struct nfs4_client *);
 extern int nfs4_do_close(struct inode *, struct nfs4_state *);
 
@@ -572,6 +573,7 @@ extern void nfs4_put_state_owner(struct nfs4_state_owner *);
 extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
 extern void nfs4_put_open_state(struct nfs4_state *);
 extern void nfs4_increment_seqid(int status, struct nfs4_state_owner *sp);
+extern void nfs4_recover_state(struct nfs4_client *);
 
 struct nfs4_mount_data;
 #else
index 244a430f83ef0a6db642e9ea0683f787b2d3b021..242b50436d926068d71445a0f3bc07d95233ffcf 100644 (file)
@@ -133,6 +133,19 @@ struct nfs_open_confirmres {
        nfs4_stateid            stateid;
 };
 
+/*
+ * Arguments to the open_reclaim call.
+ */
+struct nfs_open_reclaimargs {
+       struct nfs_fh *         fh;
+       __u64                   clientid;
+       __u32                   seqid;
+       __u32                   id;
+       __u32                   share_access;
+       __u32                   claim;
+       struct nfs4_getattr *   f_getattr;
+};
+
 /*
  * Arguments to the close call.
  */