NFS client bugfixes for Linux 5.3

Highlights include:
 
 Stable fixes:
 - NFSv4: Ensure we check the return value of update_open_stateid() so we
   correctly track active open state.
 - NFSv4: Fix for delegation state recovery to ensure we recover all open
   modes that are active.
 - NFSv4: Fix an Oops in nfs4_do_setattr
 
 Bugfixes:
 - NFS: Fix regression whereby fscache errors are appearing on 'nofsc' mounts
 - NFSv4: Fix a potential sleep while atomic in nfs4_do_reclaim()
 - NFSv4: Fix a credential refcount leak in nfs41_check_delegation_stateid
 - pNFS: Report errors from the call to nfs4_select_rw_stateid()
 - NFSv4: Various other delegation and open stateid recovery fixes
 - NFSv4: Fix state recovery behaviour when server connection times out
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEESQctxSBg8JpV8KqEZwvnipYKAPIFAl1LKhEACgkQZwvnipYK
 APIAuw/9HnKwnJYKvkAv/Pg2eBQZAgwjchc/uPsfteSPr8PMFS889rsqvDoGrAI4
 VjZRh7Jsp/FPAlLzZKCnLF/fxKE83qxgS3MP14of9IoRv2gznsW7jexy48AhU/5t
 Ae4Wgu3GJJ0IIrr8hbrkJRkBUoYUMLguCNNaZC7LDLzEVQ0wNDAVpdsZ+gdnCcrw
 zhnFnz72p2h95tfL5QkJ+OYrAu4ikdlSjx2oOdLsUGFEAnTehpUPd3DPDiCQbctx
 zPHSGukj+8tsPJ+EUVuj7ouDJqTDyMFVe1eKRJWMIq22bUAM1GBtVVMw8uFXJi5i
 9WFUJIezHhkh3Hdx82ptUmt3u1hRuSolaKDICeIR2Kob0gUArqk0KR7upgVMS3Fn
 INm/c4Zsqsa1ABevQTLWqz+nVPUPRFGmEZfjvBwkmYlkKnqbjWxXQRkROt8UJS3O
 3vfK1hUEIUyt4uI2yHusru5nIQ3pv/h1WAwpfuSQFw+nEvC6YcssECz8uOhKEnEr
 UWnUxRP66YVL4L+VAsajzAArBDQ8cUU3bv6q0x2IEWA8CHHy0BH1MGM6cumVW8YQ
 rwj0KqR4+aH0u5g8EpOkODAJfuxo10oJi6MNlr2+OSn60tdmi/P1K8eg4ERODqya
 vGqgftjTfmViYfoaWpt2NDqAbKOu4wXovb6jWqbP2lUsh+ttojg=
 =IXqc
 -----END PGP SIGNATURE-----

Merge tag 'nfs-for-5.3-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs

Pull NFS client fixes from Trond Myklebust:
 "Highlights include:

  Stable fixes:

   - NFSv4: Ensure we check the return value of update_open_stateid() so
     we correctly track active open state.

   - NFSv4: Fix for delegation state recovery to ensure we recover all
     open modes that are active.

   - NFSv4: Fix an Oops in nfs4_do_setattr

  Fixes:

   - NFS: Fix regression whereby fscache errors are appearing on 'nofsc'
     mounts

   - NFSv4: Fix a potential sleep while atomic in nfs4_do_reclaim()

   - NFSv4: Fix a credential refcount leak in nfs41_check_delegation_stateid

   - pNFS: Report errors from the call to nfs4_select_rw_stateid()

   - NFSv4: Various other delegation and open stateid recovery fixes

   - NFSv4: Fix state recovery behaviour when server connection times
     out"

* tag 'nfs-for-5.3-2' of git://git.linux-nfs.org/projects/trondmy/linux-nfs:
  NFSv4: Ensure state recovery handles ETIMEDOUT correctly
  NFS: Fix regression whereby fscache errors are appearing on 'nofsc' mounts
  NFSv4: Fix an Oops in nfs4_do_setattr
  NFSv4: Fix a potential sleep while atomic in nfs4_do_reclaim()
  NFSv4: Check the return value of update_open_stateid()
  NFSv4.1: Only reap expired delegations
  NFSv4.1: Fix open stateid recovery
  NFSv4: Report the error from nfs4_select_rw_stateid()
  NFSv4: When recovering state fails with EAGAIN, retry the same recovery
  NFSv4: Print an error in the syslog when state is marked as irrecoverable
  NFSv4: Fix delegation state recovery
  NFSv4: Fix a credential refcount leak in nfs41_check_delegation_stateid
This commit is contained in:
Linus Torvalds 2019-08-08 14:47:19 -07:00
commit b678c568c5
10 changed files with 136 additions and 76 deletions

View File

@ -153,7 +153,7 @@ static int nfs_delegation_claim_opens(struct inode *inode,
/* Block nfs4_proc_unlck */
mutex_lock(&sp->so_delegreturn_mutex);
seq = raw_seqcount_begin(&sp->so_reclaim_seqcount);
err = nfs4_open_delegation_recall(ctx, state, stateid, type);
err = nfs4_open_delegation_recall(ctx, state, stateid);
if (!err)
err = nfs_delegation_claim_locks(state, stateid);
if (!err && read_seqcount_retry(&sp->so_reclaim_seqcount, seq))
@ -1046,6 +1046,22 @@ void nfs_test_expired_all_delegations(struct nfs_client *clp)
nfs4_schedule_state_manager(clp);
}
static void
nfs_delegation_test_free_expired(struct inode *inode,
nfs4_stateid *stateid,
const struct cred *cred)
{
struct nfs_server *server = NFS_SERVER(inode);
const struct nfs4_minor_version_ops *ops = server->nfs_client->cl_mvops;
int status;
if (!cred)
return;
status = ops->test_and_free_expired(server, stateid, cred);
if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
nfs_remove_bad_delegation(inode, stateid);
}
/**
* nfs_reap_expired_delegations - reap expired delegations
* @clp: nfs_client to process
@ -1057,7 +1073,6 @@ void nfs_test_expired_all_delegations(struct nfs_client *clp)
*/
void nfs_reap_expired_delegations(struct nfs_client *clp)
{
const struct nfs4_minor_version_ops *ops = clp->cl_mvops;
struct nfs_delegation *delegation;
struct nfs_server *server;
struct inode *inode;
@ -1088,11 +1103,7 @@ void nfs_reap_expired_delegations(struct nfs_client *clp)
nfs4_stateid_copy(&stateid, &delegation->stateid);
clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags);
rcu_read_unlock();
if (cred != NULL &&
ops->test_and_free_expired(server, &stateid, cred) < 0) {
nfs_revoke_delegation(inode, &stateid);
nfs_inode_find_state_and_recover(inode, &stateid);
}
nfs_delegation_test_free_expired(inode, &stateid, cred);
put_cred(cred);
if (nfs4_server_rebooted(clp)) {
nfs_inode_mark_test_expired_delegation(server,inode);

View File

@ -63,7 +63,7 @@ void nfs_reap_expired_delegations(struct nfs_client *clp);
/* NFSv4 delegation-related procedures */
int nfs4_proc_delegreturn(struct inode *inode, const struct cred *cred, const nfs4_stateid *stateid, int issync);
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid, fmode_t type);
int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid);
int nfs4_lock_delegation_recall(struct file_lock *fl, struct nfs4_state *state, const nfs4_stateid *stateid);
bool nfs4_copy_delegation_stateid(struct inode *inode, fmode_t flags, nfs4_stateid *dst, const struct cred **cred);
bool nfs4_refresh_delegation_stateid(nfs4_stateid *dst, struct inode *inode);

View File

@ -114,6 +114,10 @@ void nfs_fscache_get_super_cookie(struct super_block *sb, const char *uniq, int
struct rb_node **p, *parent;
int diff;
nfss->fscache_key = NULL;
nfss->fscache = NULL;
if (!(nfss->options & NFS_OPTION_FSCACHE))
return;
if (!uniq) {
uniq = "";
ulen = 1;
@ -226,10 +230,11 @@ void nfs_fscache_release_super_cookie(struct super_block *sb)
void nfs_fscache_init_inode(struct inode *inode)
{
struct nfs_fscache_inode_auxdata auxdata;
struct nfs_server *nfss = NFS_SERVER(inode);
struct nfs_inode *nfsi = NFS_I(inode);
nfsi->fscache = NULL;
if (!S_ISREG(inode->i_mode))
if (!(nfss->fscache && S_ISREG(inode->i_mode)))
return;
memset(&auxdata, 0, sizeof(auxdata));

View File

@ -182,7 +182,7 @@ static inline void nfs_fscache_wait_on_invalidate(struct inode *inode)
*/
static inline const char *nfs_server_fscache_state(struct nfs_server *server)
{
if (server->fscache && (server->options & NFS_OPTION_FSCACHE))
if (server->fscache)
return "yes";
return "no ";
}

View File

@ -465,7 +465,8 @@ static inline void nfs4_schedule_session_recovery(struct nfs4_session *session,
extern struct nfs4_state_owner *nfs4_get_state_owner(struct nfs_server *, const struct cred *, gfp_t);
extern void nfs4_put_state_owner(struct nfs4_state_owner *);
extern void nfs4_purge_state_owners(struct nfs_server *);
extern void nfs4_purge_state_owners(struct nfs_server *, struct list_head *);
extern void nfs4_free_state_owners(struct list_head *head);
extern struct nfs4_state * nfs4_get_open_state(struct inode *, struct nfs4_state_owner *);
extern void nfs4_put_open_state(struct nfs4_state *);
extern void nfs4_close_state(struct nfs4_state *, fmode_t);

View File

@ -758,9 +758,12 @@ int nfs41_walk_client_list(struct nfs_client *new,
static void nfs4_destroy_server(struct nfs_server *server)
{
LIST_HEAD(freeme);
nfs_server_return_all_delegations(server);
unset_pnfs_layoutdriver(server);
nfs4_purge_state_owners(server);
nfs4_purge_state_owners(server, &freeme);
nfs4_free_state_owners(&freeme);
}
/*

View File

@ -1683,6 +1683,14 @@ static void nfs_state_set_open_stateid(struct nfs4_state *state,
write_sequnlock(&state->seqlock);
}
static void nfs_state_clear_open_state_flags(struct nfs4_state *state)
{
clear_bit(NFS_O_RDWR_STATE, &state->flags);
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
clear_bit(NFS_OPEN_STATE, &state->flags);
}
static void nfs_state_set_delegation(struct nfs4_state *state,
const nfs4_stateid *deleg_stateid,
fmode_t fmode)
@ -1907,8 +1915,9 @@ _nfs4_opendata_reclaim_to_nfs4_state(struct nfs4_opendata *data)
if (data->o_res.delegation_type != 0)
nfs4_opendata_check_deleg(data, state);
update:
update_open_stateid(state, &data->o_res.stateid, NULL,
data->o_arg.fmode);
if (!update_open_stateid(state, &data->o_res.stateid,
NULL, data->o_arg.fmode))
return ERR_PTR(-EAGAIN);
refcount_inc(&state->count);
return state;
@ -1973,8 +1982,11 @@ _nfs4_opendata_to_nfs4_state(struct nfs4_opendata *data)
if (data->o_res.delegation_type != 0)
nfs4_opendata_check_deleg(data, state);
update_open_stateid(state, &data->o_res.stateid, NULL,
data->o_arg.fmode);
if (!update_open_stateid(state, &data->o_res.stateid,
NULL, data->o_arg.fmode)) {
nfs4_put_open_state(state);
state = ERR_PTR(-EAGAIN);
}
out:
nfs_release_seqid(data->o_arg.seqid);
return state;
@ -2074,13 +2086,7 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
{
int ret;
/* Don't trigger recovery in nfs_test_and_clear_all_open_stateid */
clear_bit(NFS_O_RDWR_STATE, &state->flags);
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
/* memory barrier prior to reading state->n_* */
clear_bit(NFS_DELEGATED_STATE, &state->flags);
clear_bit(NFS_OPEN_STATE, &state->flags);
smp_rmb();
ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
if (ret != 0)
@ -2156,6 +2162,8 @@ static int nfs4_open_reclaim(struct nfs4_state_owner *sp, struct nfs4_state *sta
ctx = nfs4_state_find_open_context(state);
if (IS_ERR(ctx))
return -EAGAIN;
clear_bit(NFS_DELEGATED_STATE, &state->flags);
nfs_state_clear_open_state_flags(state);
ret = nfs4_do_open_reclaim(ctx, state);
put_nfs_open_context(ctx);
return ret;
@ -2171,18 +2179,17 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
case -ENOENT:
case -EAGAIN:
case -ESTALE:
case -ETIMEDOUT:
break;
case -NFS4ERR_BADSESSION:
case -NFS4ERR_BADSLOT:
case -NFS4ERR_BAD_HIGH_SLOT:
case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
case -NFS4ERR_DEADSESSION:
set_bit(NFS_DELEGATED_STATE, &state->flags);
nfs4_schedule_session_recovery(server->nfs_client->cl_session, err);
return -EAGAIN;
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_STALE_STATEID:
set_bit(NFS_DELEGATED_STATE, &state->flags);
/* Don't recall a delegation if it was lost */
nfs4_schedule_lease_recovery(server->nfs_client);
return -EAGAIN;
@ -2203,7 +2210,6 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
return -EAGAIN;
case -NFS4ERR_DELAY:
case -NFS4ERR_GRACE:
set_bit(NFS_DELEGATED_STATE, &state->flags);
ssleep(1);
return -EAGAIN;
case -ENOMEM:
@ -2219,8 +2225,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
}
int nfs4_open_delegation_recall(struct nfs_open_context *ctx,
struct nfs4_state *state, const nfs4_stateid *stateid,
fmode_t type)
struct nfs4_state *state, const nfs4_stateid *stateid)
{
struct nfs_server *server = NFS_SERVER(state->inode);
struct nfs4_opendata *opendata;
@ -2231,20 +2236,23 @@ int nfs4_open_delegation_recall(struct nfs_open_context *ctx,
if (IS_ERR(opendata))
return PTR_ERR(opendata);
nfs4_stateid_copy(&opendata->o_arg.u.delegation, stateid);
nfs_state_clear_delegation(state);
switch (type & (FMODE_READ|FMODE_WRITE)) {
case FMODE_READ|FMODE_WRITE:
case FMODE_WRITE:
if (!test_bit(NFS_O_RDWR_STATE, &state->flags)) {
err = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE);
if (err)
break;
goto out;
}
if (!test_bit(NFS_O_WRONLY_STATE, &state->flags)) {
err = nfs4_open_recover_helper(opendata, FMODE_WRITE);
if (err)
break;
/* Fall through */
case FMODE_READ:
err = nfs4_open_recover_helper(opendata, FMODE_READ);
goto out;
}
if (!test_bit(NFS_O_RDONLY_STATE, &state->flags)) {
err = nfs4_open_recover_helper(opendata, FMODE_READ);
if (err)
goto out;
}
nfs_state_clear_delegation(state);
out:
nfs4_opendata_put(opendata);
return nfs4_handle_delegation_recall_error(server, state, stateid, NULL, err);
}
@ -2492,6 +2500,7 @@ static int nfs4_run_open_task(struct nfs4_opendata *data,
if (!ctx) {
nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1, 1);
data->is_recover = true;
task_setup_data.flags |= RPC_TASK_TIMEOUT;
} else {
nfs4_init_sequence(&o_arg->seq_args, &o_res->seq_res, 1, 0);
pnfs_lgopen_prepare(data, ctx);
@ -2698,6 +2707,7 @@ static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
{
/* NFSv4.0 doesn't allow for delegation recovery on open expire */
nfs40_clear_delegation_stateid(state);
nfs_state_clear_open_state_flags(state);
return nfs4_open_expired(sp, state);
}
@ -2740,13 +2750,13 @@ static int nfs41_test_and_free_expired_stateid(struct nfs_server *server,
return -NFS4ERR_EXPIRED;
}
static void nfs41_check_delegation_stateid(struct nfs4_state *state)
static int nfs41_check_delegation_stateid(struct nfs4_state *state)
{
struct nfs_server *server = NFS_SERVER(state->inode);
nfs4_stateid stateid;
struct nfs_delegation *delegation;
const struct cred *cred = NULL;
int status;
int status, ret = NFS_OK;
/* Get the delegation credential for use by test/free_stateid */
rcu_read_lock();
@ -2754,20 +2764,15 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
if (delegation == NULL) {
rcu_read_unlock();
nfs_state_clear_delegation(state);
return;
return NFS_OK;
}
nfs4_stateid_copy(&stateid, &delegation->stateid);
if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
rcu_read_unlock();
nfs_state_clear_delegation(state);
return;
}
if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED,
&delegation->flags)) {
rcu_read_unlock();
return;
return NFS_OK;
}
if (delegation->cred)
@ -2777,9 +2782,24 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
trace_nfs4_test_delegation_stateid(state, NULL, status);
if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
nfs_finish_clear_delegation_stateid(state, &stateid);
else
ret = status;
if (delegation->cred)
put_cred(cred);
return ret;
}
static void nfs41_delegation_recover_stateid(struct nfs4_state *state)
{
nfs4_stateid tmp;
if (test_bit(NFS_DELEGATED_STATE, &state->flags) &&
nfs4_copy_delegation_stateid(state->inode, state->state,
&tmp, NULL) &&
nfs4_stateid_match_other(&state->stateid, &tmp))
nfs_state_set_delegation(state, &tmp, state->state);
else
nfs_state_clear_delegation(state);
}
/**
@ -2849,21 +2869,12 @@ static int nfs41_check_open_stateid(struct nfs4_state *state)
const struct cred *cred = state->owner->so_cred;
int status;
if (test_bit(NFS_OPEN_STATE, &state->flags) == 0) {
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0) {
if (nfs4_have_delegation(state->inode, state->state))
return NFS_OK;
return -NFS4ERR_OPENMODE;
}
if (test_bit(NFS_OPEN_STATE, &state->flags) == 0)
return -NFS4ERR_BAD_STATEID;
}
status = nfs41_test_and_free_expired_stateid(server, stateid, cred);
trace_nfs4_test_open_stateid(state, NULL, status);
if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) {
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
clear_bit(NFS_O_RDWR_STATE, &state->flags);
clear_bit(NFS_OPEN_STATE, &state->flags);
nfs_state_clear_open_state_flags(state);
stateid->type = NFS4_INVALID_STATEID_TYPE;
return status;
}
@ -2876,7 +2887,11 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
{
int status;
nfs41_check_delegation_stateid(state);
status = nfs41_check_delegation_stateid(state);
if (status != NFS_OK)
return status;
nfs41_delegation_recover_stateid(state);
status = nfs41_check_expired_locks(state);
if (status != NFS_OK)
return status;
@ -3201,7 +3216,7 @@ static int _nfs4_do_setattr(struct inode *inode,
if (nfs4_copy_delegation_stateid(inode, FMODE_WRITE, &arg->stateid, &delegation_cred)) {
/* Use that stateid */
} else if (ctx != NULL) {
} else if (ctx != NULL && ctx->state) {
struct nfs_lock_context *l_ctx;
if (!nfs4_valid_open_stateid(ctx->state))
return -EBADF;

View File

@ -624,24 +624,39 @@ void nfs4_put_state_owner(struct nfs4_state_owner *sp)
/**
* nfs4_purge_state_owners - Release all cached state owners
* @server: nfs_server with cached state owners to release
* @head: resulting list of state owners
*
* Called at umount time. Remaining state owners will be on
* the LRU with ref count of zero.
* Note that the state owners are not freed, but are added
* to the list @head, which can later be used as an argument
* to nfs4_free_state_owners.
*/
void nfs4_purge_state_owners(struct nfs_server *server)
void nfs4_purge_state_owners(struct nfs_server *server, struct list_head *head)
{
struct nfs_client *clp = server->nfs_client;
struct nfs4_state_owner *sp, *tmp;
LIST_HEAD(doomed);
spin_lock(&clp->cl_lock);
list_for_each_entry_safe(sp, tmp, &server->state_owners_lru, so_lru) {
list_move(&sp->so_lru, &doomed);
list_move(&sp->so_lru, head);
nfs4_remove_state_owner_locked(sp);
}
spin_unlock(&clp->cl_lock);
}
list_for_each_entry_safe(sp, tmp, &doomed, so_lru) {
/**
* nfs4_purge_state_owners - Release all cached state owners
* @head: resulting list of state owners
*
* Frees a list of state owners that was generated by
* nfs4_purge_state_owners
*/
void nfs4_free_state_owners(struct list_head *head)
{
struct nfs4_state_owner *sp, *tmp;
list_for_each_entry_safe(sp, tmp, head, so_lru) {
list_del(&sp->so_lru);
nfs4_free_state_owner(sp);
}
@ -1463,7 +1478,7 @@ void nfs_inode_find_state_and_recover(struct inode *inode,
nfs4_schedule_state_manager(clp);
}
static void nfs4_state_mark_open_context_bad(struct nfs4_state *state)
static void nfs4_state_mark_open_context_bad(struct nfs4_state *state, int err)
{
struct inode *inode = state->inode;
struct nfs_inode *nfsi = NFS_I(inode);
@ -1474,6 +1489,8 @@ static void nfs4_state_mark_open_context_bad(struct nfs4_state *state)
if (ctx->state != state)
continue;
set_bit(NFS_CONTEXT_BAD, &ctx->flags);
pr_warn("NFSv4: state recovery failed for open file %pd2, "
"error = %d\n", ctx->dentry, err);
}
rcu_read_unlock();
}
@ -1481,7 +1498,7 @@ static void nfs4_state_mark_open_context_bad(struct nfs4_state *state)
static void nfs4_state_mark_recovery_failed(struct nfs4_state *state, int error)
{
set_bit(NFS_STATE_RECOVERY_FAILED, &state->flags);
nfs4_state_mark_open_context_bad(state);
nfs4_state_mark_open_context_bad(state, error);
}
@ -1512,6 +1529,7 @@ static int nfs4_reclaim_locks(struct nfs4_state *state, const struct nfs4_state_
switch (status) {
case 0:
break;
case -ETIMEDOUT:
case -ESTALE:
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_STALE_STATEID:
@ -1605,6 +1623,7 @@ static int __nfs4_reclaim_open_state(struct nfs4_state_owner *sp, struct nfs4_st
static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs4_state_recovery_ops *ops)
{
struct nfs4_state *state;
unsigned int loop = 0;
int status = 0;
/* Note: we rely on the sp->so_states list being ordered
@ -1631,8 +1650,10 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
switch (status) {
default:
if (status >= 0)
if (status >= 0) {
loop = 0;
break;
}
printk(KERN_ERR "NFS: %s: unhandled error %d\n", __func__, status);
/* Fall through */
case -ENOENT:
@ -1646,6 +1667,10 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
break;
case -EAGAIN:
ssleep(1);
if (loop++ < 10) {
set_bit(ops->state_flag_bit, &state->flags);
break;
}
/* Fall through */
case -NFS4ERR_ADMIN_REVOKED:
case -NFS4ERR_STALE_STATEID:
@ -1658,11 +1683,13 @@ static int nfs4_reclaim_open_state(struct nfs4_state_owner *sp, const struct nfs
case -NFS4ERR_EXPIRED:
case -NFS4ERR_NO_GRACE:
nfs4_state_mark_reclaim_nograce(sp->so_server->nfs_client, state);
/* Fall through */
case -NFS4ERR_STALE_CLIENTID:
case -NFS4ERR_BADSESSION:
case -NFS4ERR_BADSLOT:
case -NFS4ERR_BAD_HIGH_SLOT:
case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
case -ETIMEDOUT:
goto out_err;
}
nfs4_put_open_state(state);
@ -1856,12 +1883,13 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov
struct nfs4_state_owner *sp;
struct nfs_server *server;
struct rb_node *pos;
LIST_HEAD(freeme);
int status = 0;
restart:
rcu_read_lock();
list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) {
nfs4_purge_state_owners(server);
nfs4_purge_state_owners(server, &freeme);
spin_lock(&clp->cl_lock);
for (pos = rb_first(&server->state_owners);
pos != NULL;
@ -1890,6 +1918,7 @@ static int nfs4_do_reclaim(struct nfs_client *clp, const struct nfs4_state_recov
spin_unlock(&clp->cl_lock);
}
rcu_read_unlock();
nfs4_free_state_owners(&freeme);
return 0;
}
@ -1945,7 +1974,6 @@ static int nfs4_handle_reclaim_lease_error(struct nfs_client *clp, int status)
return -EPERM;
case -EACCES:
case -NFS4ERR_DELAY:
case -ETIMEDOUT:
case -EAGAIN:
ssleep(1);
break;
@ -2574,7 +2602,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
}
/* Now recover expired state... */
if (test_and_clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
if (test_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state)) {
section = "reclaim nograce";
status = nfs4_do_reclaim(clp,
clp->cl_mvops->nograce_recovery_ops);
@ -2582,6 +2610,7 @@ static void nfs4_state_manager(struct nfs_client *clp)
continue;
if (status < 0)
goto out_error;
clear_bit(NFS4CLNT_RECLAIM_NOGRACE, &clp->cl_state);
}
nfs4_end_drain_session(clp);

View File

@ -1903,12 +1903,6 @@ pnfs_update_layout(struct inode *ino,
goto out_unlock;
}
if (!nfs4_valid_open_stateid(ctx->state)) {
trace_pnfs_update_layout(ino, pos, count, iomode, lo, lseg,
PNFS_UPDATE_LAYOUT_INVALID_OPEN);
goto out_unlock;
}
/*
* Choose a stateid for the LAYOUTGET. If we don't have a layout
* stateid, or it has been invalidated, then we must use the open
@ -1939,6 +1933,7 @@ pnfs_update_layout(struct inode *ino,
iomode == IOMODE_RW ? FMODE_WRITE : FMODE_READ,
NULL, &stateid, NULL);
if (status != 0) {
lseg = ERR_PTR(status);
trace_pnfs_update_layout(ino, pos, count,
iomode, lo, lseg,
PNFS_UPDATE_LAYOUT_INVALID_OPEN);

View File

@ -2260,6 +2260,7 @@ nfs_compare_remount_data(struct nfs_server *nfss,
data->acdirmin != nfss->acdirmin / HZ ||
data->acdirmax != nfss->acdirmax / HZ ||
data->timeo != (10U * nfss->client->cl_timeout->to_initval / HZ) ||
(data->options & NFS_OPTION_FSCACHE) != (nfss->options & NFS_OPTION_FSCACHE) ||
data->nfs_server.port != nfss->port ||
data->nfs_server.addrlen != nfss->nfs_client->cl_addrlen ||
!rpc_cmp_addr((struct sockaddr *)&data->nfs_server.address,