diff options
author | NeilBrown <neilb@cse.unsw.edu.au> | 2005-07-07 20:59:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-07-07 21:24:09 -0400 |
commit | bd9aac523b812d58e644fde5e59f5697fb9e3822 (patch) | |
tree | a3adb8ac833a8e776cca8df91e96f85aa28e81c6 | |
parent | 893f87701c9e5bd5610dfbb3f8bf1135f86d85cb (diff) |
[PATCH] nfsd4: fix open_reclaim seqid
The sequence number we store in the sequence id is the last one we received
from the client. So on the next operation we'll check that the client gives
us the next higher number.
We increment sequence id's at the last moment, in encode, so that we're sure
of knowing the right error return. (The decision to increment the sequence id
depends on the exact error returned.)
However on the *first* use of a sequence number, if we set the sequence number
to the one received from the client and then let the increment happen on
encode, we'll be left with a sequence number one to high.
For that reason, ENCODE_SEQID_OP_TAIL only increments the sequence id on
*confirmed* stateowners.
This creates a problem for open reclaims, which are confirmed on first use.
Therefore the open reclaim code, as a special exception, *decrements* the
sequence id, cancelling out the undesired increment on encode. But this
prevents the sequence id from ever being incremented in the case where
multiple reclaims are sent with the same openowner. Yuch!
We could add another exception to the open reclaim code, decrementing the
sequence id only if this is the first use of the open owner.
But it's simpler by far to modify the meaning of the op_seqid field: instead
of representing the previous value sent by the client, we take op_seqid, after
encoding, to represent the *next* sequence id that we expect from the client.
This eliminates the need for special-case handling of the first use of a
stateowner.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
Signed-off-by: Neil Brown <neilb@cse.unsw.edu.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | fs/nfsd/nfs4state.c | 15 | ||||
-rw-r--r-- | fs/nfsd/nfs4xdr.c | 3 |
2 files changed, 7 insertions, 11 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 74cd9bf3e0a1..f60bcad77f71 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -1483,7 +1483,7 @@ nfsd4_process_open1(struct nfsd4_open *open) | |||
1483 | if (sop) { | 1483 | if (sop) { |
1484 | open->op_stateowner = sop; | 1484 | open->op_stateowner = sop; |
1485 | /* check for replay */ | 1485 | /* check for replay */ |
1486 | if (open->op_seqid == sop->so_seqid){ | 1486 | if (open->op_seqid == sop->so_seqid - 1){ |
1487 | if (sop->so_replay.rp_buflen) | 1487 | if (sop->so_replay.rp_buflen) |
1488 | return NFSERR_REPLAY_ME; | 1488 | return NFSERR_REPLAY_ME; |
1489 | else { | 1489 | else { |
@@ -1498,7 +1498,7 @@ nfsd4_process_open1(struct nfsd4_open *open) | |||
1498 | goto renew; | 1498 | goto renew; |
1499 | } | 1499 | } |
1500 | } else if (sop->so_confirmed) { | 1500 | } else if (sop->so_confirmed) { |
1501 | if (open->op_seqid == sop->so_seqid + 1) | 1501 | if (open->op_seqid == sop->so_seqid) |
1502 | goto renew; | 1502 | goto renew; |
1503 | status = nfserr_bad_seqid; | 1503 | status = nfserr_bad_seqid; |
1504 | goto out; | 1504 | goto out; |
@@ -1684,13 +1684,11 @@ nfs4_upgrade_open(struct svc_rqst *rqstp, struct svc_fh *cur_fh, struct nfs4_sta | |||
1684 | } | 1684 | } |
1685 | 1685 | ||
1686 | 1686 | ||
1687 | /* decrement seqid on successful reclaim, it will be bumped in encode_open */ | ||
1688 | static void | 1687 | static void |
1689 | nfs4_set_claim_prev(struct nfsd4_open *open) | 1688 | nfs4_set_claim_prev(struct nfsd4_open *open) |
1690 | { | 1689 | { |
1691 | open->op_stateowner->so_confirmed = 1; | 1690 | open->op_stateowner->so_confirmed = 1; |
1692 | open->op_stateowner->so_client->cl_firststate = 1; | 1691 | open->op_stateowner->so_client->cl_firststate = 1; |
1693 | open->op_stateowner->so_seqid--; | ||
1694 | } | 1692 | } |
1695 | 1693 | ||
1696 | /* | 1694 | /* |
@@ -2234,7 +2232,7 @@ nfs4_preprocess_seqid_op(struct svc_fh *current_fh, u32 seqid, stateid_t *statei | |||
2234 | * For the moment, we ignore the possibility of | 2232 | * For the moment, we ignore the possibility of |
2235 | * generation number wraparound. | 2233 | * generation number wraparound. |
2236 | */ | 2234 | */ |
2237 | if (seqid != sop->so_seqid + 1) | 2235 | if (seqid != sop->so_seqid) |
2238 | goto check_replay; | 2236 | goto check_replay; |
2239 | 2237 | ||
2240 | if (sop->so_confirmed) { | 2238 | if (sop->so_confirmed) { |
@@ -2280,12 +2278,12 @@ no_nfs4_stateid: | |||
2280 | *sopp = sop; | 2278 | *sopp = sop; |
2281 | 2279 | ||
2282 | check_replay: | 2280 | check_replay: |
2283 | if (seqid == sop->so_seqid) { | 2281 | if (seqid == sop->so_seqid - 1) { |
2284 | printk("NFSD: preprocess_seqid_op: retransmission?\n"); | 2282 | printk("NFSD: preprocess_seqid_op: retransmission?\n"); |
2285 | /* indicate replay to calling function */ | 2283 | /* indicate replay to calling function */ |
2286 | status = NFSERR_REPLAY_ME; | 2284 | status = NFSERR_REPLAY_ME; |
2287 | } else { | 2285 | } else { |
2288 | printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid +1, seqid); | 2286 | printk("NFSD: preprocess_seqid_op: bad seqid (expected %d, got %d\n", sop->so_seqid, seqid); |
2289 | 2287 | ||
2290 | *sopp = NULL; | 2288 | *sopp = NULL; |
2291 | status = nfserr_bad_seqid; | 2289 | status = nfserr_bad_seqid; |
@@ -2608,7 +2606,6 @@ find_lockstateowner_str(struct inode *inode, clientid_t *clid, | |||
2608 | * occured. | 2606 | * occured. |
2609 | * | 2607 | * |
2610 | * strhashval = lock_ownerstr_hashval | 2608 | * strhashval = lock_ownerstr_hashval |
2611 | * so_seqid = lock->lk_new_lock_seqid - 1: it gets bumped in encode | ||
2612 | */ | 2609 | */ |
2613 | 2610 | ||
2614 | static struct nfs4_stateowner * | 2611 | static struct nfs4_stateowner * |
@@ -2633,7 +2630,7 @@ alloc_init_lock_stateowner(unsigned int strhashval, struct nfs4_client *clp, str | |||
2633 | sop->so_is_open_owner = 0; | 2630 | sop->so_is_open_owner = 0; |
2634 | sop->so_id = current_ownerid++; | 2631 | sop->so_id = current_ownerid++; |
2635 | sop->so_client = clp; | 2632 | sop->so_client = clp; |
2636 | sop->so_seqid = lock->lk_new_lock_seqid - 1; | 2633 | sop->so_seqid = lock->lk_new_lock_seqid; |
2637 | sop->so_confirmed = 1; | 2634 | sop->so_confirmed = 1; |
2638 | rp = &sop->so_replay; | 2635 | rp = &sop->so_replay; |
2639 | rp->rp_status = NFSERR_SERVERFAULT; | 2636 | rp->rp_status = NFSERR_SERVERFAULT; |
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c index 91fb171d2ace..5207068cde1a 100644 --- a/fs/nfsd/nfs4xdr.c +++ b/fs/nfsd/nfs4xdr.c | |||
@@ -1218,8 +1218,7 @@ nfsd4_decode_compound(struct nfsd4_compoundargs *argp) | |||
1218 | 1218 | ||
1219 | #define ENCODE_SEQID_OP_TAIL(stateowner) do { \ | 1219 | #define ENCODE_SEQID_OP_TAIL(stateowner) do { \ |
1220 | if (seqid_mutating_err(nfserr) && stateowner) { \ | 1220 | if (seqid_mutating_err(nfserr) && stateowner) { \ |
1221 | if (stateowner->so_confirmed) \ | 1221 | stateowner->so_seqid++; \ |
1222 | stateowner->so_seqid++; \ | ||
1223 | stateowner->so_replay.rp_status = nfserr; \ | 1222 | stateowner->so_replay.rp_status = nfserr; \ |
1224 | stateowner->so_replay.rp_buflen = \ | 1223 | stateowner->so_replay.rp_buflen = \ |
1225 | (((char *)(resp)->p - (char *)save)); \ | 1224 | (((char *)(resp)->p - (char *)save)); \ |