NFSv4: Clean up nfs4_select_rw_stateid()
authorTrond Myklebust <Trond.Myklebust@netapp.com>
Thu, 8 Mar 2012 22:42:01 +0000 (17:42 -0500)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Fri, 9 Mar 2012 03:38:55 +0000 (22:38 -0500)
Ensure that we select delegation stateids first, then
lock stateids and then open stateids.

Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
fs/nfs/nfs4_fs.h
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4xdr.c

index d1989e3f23c3dbeba1d2daf92713921b9b80573f..b47bdb9c1612f893140dabe86e233707b36723a3 100644 (file)
@@ -330,7 +330,8 @@ extern void nfs41_handle_server_scope(struct nfs_client *,
                                      struct server_scope **);
 extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp);
 extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl);
-extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t);
+extern void nfs4_select_rw_stateid(nfs4_stateid *, struct nfs4_state *,
+               fmode_t, fl_owner_t, pid_t);
 
 extern struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask);
 extern int nfs_wait_on_sequence(struct nfs_seqid *seqid, struct rpc_task *task);
index 3578ad36a5b813705cce576413b2bfd08d5ea6c0..3bf5593741eeb97a4c64de8e68214cffdf5dbb60 100644 (file)
@@ -1929,10 +1929,12 @@ static int _nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
 
        nfs_fattr_init(fattr);
 
-       if (nfs4_copy_delegation_stateid(&arg.stateid, inode, FMODE_WRITE)) {
+       if (state != NULL) {
+               nfs4_select_rw_stateid(&arg.stateid, state, FMODE_WRITE,
+                               current->files, current->tgid);
+       } else if (nfs4_copy_delegation_stateid(&arg.stateid, inode,
+                               FMODE_WRITE)) {
                /* Use that stateid */
-       } else if (state != NULL) {
-               nfs4_select_rw_stateid(&arg.stateid, state, current->files, current->tgid);
        } else
                nfs4_stateid_copy(&arg.stateid, &zero_stateid);
 
index 7adc46b4c7f83203970a796813fbd2d3307f2807..de44804d9864e5814005e760f59471087f03ef0e 100644 (file)
@@ -886,28 +886,49 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl)
        return 0;
 }
 
-/*
- * Byte-range lock aware utility to initialize the stateid of read/write
- * requests.
- */
-void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid)
+static bool nfs4_copy_lock_stateid(nfs4_stateid *dst, struct nfs4_state *state,
+               fl_owner_t fl_owner, pid_t fl_pid)
 {
        struct nfs4_lock_state *lsp;
-       int seq;
+       bool ret = false;
 
-       do {
-               seq = read_seqbegin(&state->seqlock);
-               nfs4_stateid_copy(dst, &state->stateid);
-       } while (read_seqretry(&state->seqlock, seq));
        if (test_bit(LK_STATE_IN_USE, &state->flags) == 0)
-               return;
+               goto out;
 
        spin_lock(&state->state_lock);
        lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE);
-       if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0)
+       if (lsp != NULL && (lsp->ls_flags & NFS_LOCK_INITIALIZED) != 0) {
                nfs4_stateid_copy(dst, &lsp->ls_stateid);
+               ret = true;
+       }
        spin_unlock(&state->state_lock);
        nfs4_put_lock_state(lsp);
+out:
+       return ret;
+}
+
+static void nfs4_copy_open_stateid(nfs4_stateid *dst, struct nfs4_state *state)
+{
+       int seq;
+
+       do {
+               seq = read_seqbegin(&state->seqlock);
+               nfs4_stateid_copy(dst, &state->stateid);
+       } while (read_seqretry(&state->seqlock, seq));
+}
+
+/*
+ * Byte-range lock aware utility to initialize the stateid of read/write
+ * requests.
+ */
+void nfs4_select_rw_stateid(nfs4_stateid *dst, struct nfs4_state *state,
+               fmode_t fmode, fl_owner_t fl_owner, pid_t fl_pid)
+{
+       if (nfs4_copy_delegation_stateid(dst, state->inode, fmode))
+               return;
+       if (nfs4_copy_lock_stateid(dst, state, fl_owner, fl_pid))
+               return;
+       nfs4_copy_open_stateid(dst, state);
 }
 
 struct nfs_seqid *nfs_alloc_seqid(struct nfs_seqid_counter *counter, gfp_t gfp_mask)
index e4bb8e6409a7504d2443b96e7b8618a2d32a700c..f7e064d997f6fbe6367da03cefa30a1c62451da6 100644 (file)
@@ -1491,12 +1491,17 @@ static void encode_putrootfh(struct xdr_stream *xdr, struct compound_hdr *hdr)
        encode_op_hdr(xdr, OP_PUTROOTFH, decode_putrootfh_maxsz, hdr);
 }
 
-static void encode_open_stateid(struct xdr_stream *xdr, const struct nfs_open_context *ctx, const struct nfs_lock_context *l_ctx, int zero_seqid)
+static void encode_open_stateid(struct xdr_stream *xdr,
+               const struct nfs_open_context *ctx,
+               const struct nfs_lock_context *l_ctx,
+               fmode_t fmode,
+               int zero_seqid)
 {
        nfs4_stateid stateid;
 
        if (ctx->state != NULL) {
-               nfs4_select_rw_stateid(&stateid, ctx->state, l_ctx->lockowner, l_ctx->pid);
+               nfs4_select_rw_stateid(&stateid, ctx->state,
+                               fmode, l_ctx->lockowner, l_ctx->pid);
                if (zero_seqid)
                        stateid.seqid = 0;
                encode_nfs4_stateid(xdr, &stateid);
@@ -1510,7 +1515,7 @@ static void encode_read(struct xdr_stream *xdr, const struct nfs_readargs *args,
 
        encode_op_hdr(xdr, OP_READ, decode_read_maxsz, hdr);
        encode_open_stateid(xdr, args->context, args->lock_context,
-                      hdr->minorversion);
+                       FMODE_READ, hdr->minorversion);
 
        p = reserve_space(xdr, 12);
        p = xdr_encode_hyper(p, args->offset);
@@ -1648,7 +1653,7 @@ static void encode_write(struct xdr_stream *xdr, const struct nfs_writeargs *arg
 
        encode_op_hdr(xdr, OP_WRITE, decode_write_maxsz, hdr);
        encode_open_stateid(xdr, args->context, args->lock_context,
-                      hdr->minorversion);
+                       FMODE_WRITE, hdr->minorversion);
 
        p = reserve_space(xdr, 16);
        p = xdr_encode_hyper(p, args->offset);