diff options
-rw-r--r-- | fs/nfsd/nfs4state.c | 40 | ||||
-rw-r--r-- | include/linux/nfsd/state.h | 1 |
2 files changed, 28 insertions, 13 deletions
diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index d5555850cb64..3570a0d1133f 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c | |||
@@ -2000,10 +2000,7 @@ out: | |||
2000 | static inline __be32 | 2000 | static inline __be32 |
2001 | check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) | 2001 | check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) |
2002 | { | 2002 | { |
2003 | /* Trying to call delegreturn with a special stateid? Yuch: */ | 2003 | if (ONE_STATEID(stateid) && (flags & RD_STATE)) |
2004 | if (!(flags & (RD_STATE | WR_STATE))) | ||
2005 | return nfserr_bad_stateid; | ||
2006 | else if (ONE_STATEID(stateid) && (flags & RD_STATE)) | ||
2007 | return nfs_ok; | 2004 | return nfs_ok; |
2008 | else if (locks_in_grace()) { | 2005 | else if (locks_in_grace()) { |
2009 | /* Answer in remaining cases depends on existance of | 2006 | /* Answer in remaining cases depends on existance of |
@@ -2024,8 +2021,7 @@ check_special_stateids(svc_fh *current_fh, stateid_t *stateid, int flags) | |||
2024 | static inline int | 2021 | static inline int |
2025 | io_during_grace_disallowed(struct inode *inode, int flags) | 2022 | io_during_grace_disallowed(struct inode *inode, int flags) |
2026 | { | 2023 | { |
2027 | return locks_in_grace() && (flags & (RD_STATE | WR_STATE)) | 2024 | return locks_in_grace() && mandatory_lock(inode); |
2028 | && mandatory_lock(inode); | ||
2029 | } | 2025 | } |
2030 | 2026 | ||
2031 | static int check_stateid_generation(stateid_t *in, stateid_t *ref) | 2027 | static int check_stateid_generation(stateid_t *in, stateid_t *ref) |
@@ -2089,8 +2085,6 @@ nfs4_preprocess_stateid_op(struct svc_fh *current_fh, stateid_t *stateid, int fl | |||
2089 | if (status) | 2085 | if (status) |
2090 | goto out; | 2086 | goto out; |
2091 | renew_client(dp->dl_client); | 2087 | renew_client(dp->dl_client); |
2092 | if (flags & DELEG_RET) | ||
2093 | unhash_delegation(dp); | ||
2094 | if (filpp) | 2088 | if (filpp) |
2095 | *filpp = dp->dl_vfs_file; | 2089 | *filpp = dp->dl_vfs_file; |
2096 | } else { /* open or lock stateid */ | 2090 | } else { /* open or lock stateid */ |
@@ -2408,16 +2402,38 @@ __be32 | |||
2408 | nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, | 2402 | nfsd4_delegreturn(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, |
2409 | struct nfsd4_delegreturn *dr) | 2403 | struct nfsd4_delegreturn *dr) |
2410 | { | 2404 | { |
2405 | struct nfs4_delegation *dp; | ||
2406 | stateid_t *stateid = &dr->dr_stateid; | ||
2407 | struct inode *inode; | ||
2411 | __be32 status; | 2408 | __be32 status; |
2412 | 2409 | ||
2413 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) | 2410 | if ((status = fh_verify(rqstp, &cstate->current_fh, S_IFREG, 0))) |
2414 | goto out; | 2411 | return status; |
2412 | inode = cstate->current_fh.fh_dentry->d_inode; | ||
2415 | 2413 | ||
2416 | nfs4_lock_state(); | 2414 | nfs4_lock_state(); |
2417 | status = nfs4_preprocess_stateid_op(&cstate->current_fh, | 2415 | status = nfserr_bad_stateid; |
2418 | &dr->dr_stateid, DELEG_RET, NULL); | 2416 | if (ZERO_STATEID(stateid) || ONE_STATEID(stateid)) |
2419 | nfs4_unlock_state(); | 2417 | goto out; |
2418 | status = nfserr_stale_stateid; | ||
2419 | if (STALE_STATEID(stateid)) | ||
2420 | goto out; | ||
2421 | status = nfs_ok; | ||
2422 | if (!is_delegation_stateid(stateid)) | ||
2423 | goto out; | ||
2424 | status = nfserr_bad_stateid; | ||
2425 | dp = find_delegation_stateid(inode, stateid); | ||
2426 | if (!dp) | ||
2427 | goto out; | ||
2428 | status = check_stateid_generation(stateid, &dp->dl_stateid); | ||
2429 | if (status) | ||
2430 | goto out; | ||
2431 | renew_client(dp->dl_client); | ||
2432 | |||
2433 | unhash_delegation(dp); | ||
2420 | out: | 2434 | out: |
2435 | nfs4_unlock_state(); | ||
2436 | |||
2421 | return status; | 2437 | return status; |
2422 | } | 2438 | } |
2423 | 2439 | ||
diff --git a/include/linux/nfsd/state.h b/include/linux/nfsd/state.h index 1130d534bb63..c9311a1e2e1a 100644 --- a/include/linux/nfsd/state.h +++ b/include/linux/nfsd/state.h | |||
@@ -263,7 +263,6 @@ struct nfs4_stateid { | |||
263 | #define RD_STATE 0x00000010 | 263 | #define RD_STATE 0x00000010 |
264 | #define WR_STATE 0x00000020 | 264 | #define WR_STATE 0x00000020 |
265 | #define CLOSE_STATE 0x00000040 | 265 | #define CLOSE_STATE 0x00000040 |
266 | #define DELEG_RET 0x00000080 | ||
267 | 266 | ||
268 | #define seqid_mutating_err(err) \ | 267 | #define seqid_mutating_err(err) \ |
269 | (((err) != nfserr_stale_clientid) && \ | 268 | (((err) != nfserr_stale_clientid) && \ |