summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/nfsd/nfs4state.c73
-rw-r--r--fs/nfsd/nfs4xdr.c33
2 files changed, 101 insertions, 5 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c
index dfc6d946cdfe..24b6e0593184 100644
--- a/fs/nfsd/nfs4state.c
+++ b/fs/nfsd/nfs4state.c
@@ -1000,6 +1000,32 @@ error:
return status;
}
+static int
+check_slot_seqid(u32 seqid, struct nfsd4_slot *slot)
+{
+ dprintk("%s enter. seqid %d slot->sl_seqid %d\n", __func__, seqid,
+ slot->sl_seqid);
+
+ /* The slot is in use, and no response has been sent. */
+ if (slot->sl_inuse) {
+ if (seqid == slot->sl_seqid)
+ return nfserr_jukebox;
+ else
+ return nfserr_seq_misordered;
+ }
+ /* Normal */
+ if (likely(seqid == slot->sl_seqid + 1))
+ return nfs_ok;
+ /* Replay */
+ if (seqid == slot->sl_seqid)
+ return nfserr_replay_cache;
+ /* Wraparound */
+ if (seqid == 1 && (slot->sl_seqid + 1) == 0)
+ return nfs_ok;
+ /* Misordered replay or misordered new request */
+ return nfserr_seq_misordered;
+}
+
__be32
nfsd4_create_session(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate,
@@ -1017,11 +1043,54 @@ nfsd4_destroy_session(struct svc_rqst *r,
}
__be32
-nfsd4_sequence(struct svc_rqst *r,
+nfsd4_sequence(struct svc_rqst *rqstp,
struct nfsd4_compound_state *cstate,
struct nfsd4_sequence *seq)
{
- return -1; /* stub */
+ struct nfsd4_session *session;
+ struct nfsd4_slot *slot;
+ int status;
+
+ spin_lock(&sessionid_lock);
+ status = nfserr_badsession;
+ session = find_in_sessionid_hashtbl(&seq->sessionid);
+ if (!session)
+ goto out;
+
+ status = nfserr_badslot;
+ if (seq->slotid >= session->se_fnumslots)
+ goto out;
+
+ slot = &session->se_slots[seq->slotid];
+ dprintk("%s: slotid %d\n", __func__, seq->slotid);
+
+ status = check_slot_seqid(seq->seqid, slot);
+ if (status == nfserr_replay_cache) {
+ cstate->slot = slot;
+ cstate->session = session;
+ goto replay_cache;
+ }
+ if (status)
+ goto out;
+
+ /* Success! bump slot seqid */
+ slot->sl_inuse = true;
+ slot->sl_seqid = seq->seqid;
+
+ cstate->slot = slot;
+ cstate->session = session;
+
+replay_cache:
+ /* Renew the clientid on success and on replay.
+ * Hold a session reference until done processing the compound:
+ * nfsd4_put_session called only if the cstate slot is set.
+ */
+ renew_client(session->se_client);
+ nfsd4_get_session(session);
+out:
+ spin_unlock(&sessionid_lock);
+ dprintk("%s: return %d\n", __func__, ntohl(status));
+ return status;
}
__be32
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index bebf6d249069..8556575480ce 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1113,7 +1113,16 @@ static __be32
nfsd4_decode_sequence(struct nfsd4_compoundargs *argp,
struct nfsd4_sequence *seq)
{
- return nfserr_opnotsupp; /* stub */
+ DECODE_HEAD;
+
+ READ_BUF(NFS4_MAX_SESSIONID_LEN + 16);
+ COPYMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN);
+ READ32(seq->seqid);
+ READ32(seq->slotid);
+ READ32(seq->maxslots);
+ READ32(seq->cachethis);
+
+ DECODE_TAIL;
}
static __be32
@@ -2828,8 +2837,26 @@ static __be32
nfsd4_encode_sequence(struct nfsd4_compoundres *resp, int nfserr,
struct nfsd4_sequence *seq)
{
- /* stub */
- return nfserr;
+ ENCODE_HEAD;
+
+ if (nfserr)
+ return nfserr;
+
+ RESERVE_SPACE(NFS4_MAX_SESSIONID_LEN + 20);
+ WRITEMEM(seq->sessionid.data, NFS4_MAX_SESSIONID_LEN);
+ WRITE32(seq->seqid);
+ WRITE32(seq->slotid);
+ WRITE32(seq->maxslots);
+ /*
+ * FIXME: for now:
+ * target_maxslots = maxslots
+ * status_flags = 0
+ */
+ WRITE32(seq->maxslots);
+ WRITE32(0);
+
+ ADJUST_ARGS();
+ return 0;
}
static __be32