@@ -1757,19 +1757,46 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
#if defined(CONFIG_NFS_V4_1)
/**
- * nfs41_check_expired_stateid - does a state ID need recovery?
+ * nfs41_clear_delegation_stateid - possibly clear revoked delegation state ID
+ *
+ * @state: NFSv4 open state for an inode
+ */
+static void nfs41_clear_delegation_stateid(struct nfs4_state *state)
+{
+ struct nfs_server *server = NFS_SERVER(state->inode);
+ nfs4_stateid *stateid = &state->stateid;
+
+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) != 0)
+ switch (nfs41_test_stateid(server, stateid)) {
+ case NFS_OK:
+ /* delegation still OK, preserve it */
+ break;
+ case -NFS4ERR_ADMIN_REVOKED:
+ case -NFS4ERR_DELEG_REVOKED:
+ /* delegation was revoked, must free */
+ nfs41_free_stateid(server, stateid);
+ default:
+ clear_bit(NFS_DELEGATED_STATE, &state->flags);
+ }
+}
+
+/**
+ * nfs41_check_open_stateid - clear open state ID
*
* @state: NFSv4 open state for an inode
*
* Returns NFS_OK if recovery for this state ID is now finished.
* Otherwise a negative NFS4ERR value is returned.
*/
-static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *stateid, unsigned int flags)
+static int nfs41_check_open_stateid(struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(state->inode);
+ nfs4_stateid *stateid = &state->stateid;
int status = -NFS4ERR_BAD_STATEID;
- if (state->flags & flags) {
+ if ((test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0) ||
+ (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0) ||
+ (test_bit(NFS_O_RDWR_STATE, &state->flags) != 0)) {
status = nfs41_test_stateid(server, stateid);
switch (status) {
case NFS_OK:
@@ -1781,7 +1808,9 @@ static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *s
nfs41_free_stateid(server, stateid);
default:
/* anything else: just re-open it */
- state->flags &= ~flags;
+ clear_bit(NFS_O_RDONLY_STATE, &state->flags);
+ clear_bit(NFS_O_WRONLY_STATE, &state->flags);
+ clear_bit(NFS_O_RDWR_STATE, &state->flags);
}
}
return status;
@@ -1789,13 +1818,10 @@ static int nfs41_check_expired_stateid(struct nfs4_state *state, nfs4_stateid *s
static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
{
- int deleg_flags = 1 << NFS_DELEGATED_STATE;
- int open_flags = (1 << NFS_O_RDONLY_STATE) | (1 << NFS_O_WRONLY_STATE) | (1 << NFS_O_RDWR_STATE);
int status;
- nfs41_check_expired_stateid(state, &state->stateid, deleg_flags);
- status = nfs41_check_expired_stateid(state, &state->open_stateid,
- open_flags);
+ nfs41_clear_delegation_stateid(state);
+ status = nfs41_check_open_stateid(state);
if (status != NFS_OK)
status = nfs4_open_expired(sp, state);
Clean up: The logic for dealing with a delegation state ID and an open state ID is now sufficiently distinct that I've refactored nfs41_check_expired_stateid() into two separate functions. Instead of open-coded flag manipulation, use test_bit() and clear_bit() just like all other accessors of the state->flag field. This also eliminates several unnecessary implicit integer type conversions. Signed-off-by: Chuck Lever <chuck.lever@oracle.com> --- fs/nfs/nfs4proc.c | 44 +++++++++++++++++++++++++++++++++++--------- 1 files changed, 35 insertions(+), 9 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html