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:
commit
b678c568c5
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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 ";
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue