|
@@ -99,8 +99,8 @@ static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred,
|
|
#ifdef CONFIG_NFS_V4_1
|
|
#ifdef CONFIG_NFS_V4_1
|
|
static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *,
|
|
static int nfs41_test_stateid(struct nfs_server *, nfs4_stateid *,
|
|
struct rpc_cred *);
|
|
struct rpc_cred *);
|
|
-static int nfs41_free_stateid(struct nfs_server *, nfs4_stateid *,
|
|
|
|
- struct rpc_cred *);
|
|
|
|
|
|
+static int nfs41_free_stateid(struct nfs_server *, const nfs4_stateid *,
|
|
|
|
+ struct rpc_cred *, bool);
|
|
#endif
|
|
#endif
|
|
|
|
|
|
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
|
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
|
@@ -328,6 +328,33 @@ static void nfs4_setup_readdir(u64 cookie, __be32 *verifier, struct dentry *dent
|
|
kunmap_atomic(start);
|
|
kunmap_atomic(start);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void nfs4_test_and_free_stateid(struct nfs_server *server,
|
|
|
|
+ nfs4_stateid *stateid,
|
|
|
|
+ struct rpc_cred *cred)
|
|
|
|
+{
|
|
|
|
+ const struct nfs4_minor_version_ops *ops = server->nfs_client->cl_mvops;
|
|
|
|
+
|
|
|
|
+ ops->test_and_free_expired(server, stateid, cred);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void __nfs4_free_revoked_stateid(struct nfs_server *server,
|
|
|
|
+ nfs4_stateid *stateid,
|
|
|
|
+ struct rpc_cred *cred)
|
|
|
|
+{
|
|
|
|
+ stateid->type = NFS4_REVOKED_STATEID_TYPE;
|
|
|
|
+ nfs4_test_and_free_stateid(server, stateid, cred);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void nfs4_free_revoked_stateid(struct nfs_server *server,
|
|
|
|
+ const nfs4_stateid *stateid,
|
|
|
|
+ struct rpc_cred *cred)
|
|
|
|
+{
|
|
|
|
+ nfs4_stateid tmp;
|
|
|
|
+
|
|
|
|
+ nfs4_stateid_copy(&tmp, stateid);
|
|
|
|
+ __nfs4_free_revoked_stateid(server, &tmp, cred);
|
|
|
|
+}
|
|
|
|
+
|
|
static long nfs4_update_delay(long *timeout)
|
|
static long nfs4_update_delay(long *timeout)
|
|
{
|
|
{
|
|
long ret;
|
|
long ret;
|
|
@@ -370,13 +397,23 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
|
|
exception->delay = 0;
|
|
exception->delay = 0;
|
|
exception->recovering = 0;
|
|
exception->recovering = 0;
|
|
exception->retry = 0;
|
|
exception->retry = 0;
|
|
|
|
+
|
|
|
|
+ if (stateid == NULL && state != NULL)
|
|
|
|
+ stateid = &state->stateid;
|
|
|
|
+
|
|
switch(errorcode) {
|
|
switch(errorcode) {
|
|
case 0:
|
|
case 0:
|
|
return 0;
|
|
return 0;
|
|
- case -NFS4ERR_OPENMODE:
|
|
|
|
case -NFS4ERR_DELEG_REVOKED:
|
|
case -NFS4ERR_DELEG_REVOKED:
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
|
|
+ case -NFS4ERR_EXPIRED:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
|
|
+ if (inode != NULL && stateid != NULL) {
|
|
|
|
+ nfs_inode_find_state_and_recover(inode,
|
|
|
|
+ stateid);
|
|
|
|
+ goto wait_on_recovery;
|
|
|
|
+ }
|
|
|
|
+ case -NFS4ERR_OPENMODE:
|
|
if (inode) {
|
|
if (inode) {
|
|
int err;
|
|
int err;
|
|
|
|
|
|
@@ -395,12 +432,6 @@ static int nfs4_do_handle_exception(struct nfs_server *server,
|
|
if (ret < 0)
|
|
if (ret < 0)
|
|
break;
|
|
break;
|
|
goto wait_on_recovery;
|
|
goto wait_on_recovery;
|
|
- case -NFS4ERR_EXPIRED:
|
|
|
|
- if (state != NULL) {
|
|
|
|
- ret = nfs4_schedule_stateid_recovery(server, state);
|
|
|
|
- if (ret < 0)
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
case -NFS4ERR_STALE_STATEID:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
case -NFS4ERR_STALE_CLIENTID:
|
|
case -NFS4ERR_STALE_CLIENTID:
|
|
nfs4_schedule_lease_recovery(clp);
|
|
nfs4_schedule_lease_recovery(clp);
|
|
@@ -616,6 +647,7 @@ int nfs40_setup_sequence(struct nfs4_slot_table *tbl,
|
|
}
|
|
}
|
|
spin_unlock(&tbl->slot_tbl_lock);
|
|
spin_unlock(&tbl->slot_tbl_lock);
|
|
|
|
|
|
|
|
+ slot->privileged = args->sa_privileged ? 1 : 0;
|
|
args->sa_slot = slot;
|
|
args->sa_slot = slot;
|
|
res->sr_slot = slot;
|
|
res->sr_slot = slot;
|
|
|
|
|
|
@@ -723,12 +755,20 @@ static int nfs41_sequence_process(struct rpc_task *task,
|
|
/* Check the SEQUENCE operation status */
|
|
/* Check the SEQUENCE operation status */
|
|
switch (res->sr_status) {
|
|
switch (res->sr_status) {
|
|
case 0:
|
|
case 0:
|
|
|
|
+ /* If previous op on slot was interrupted and we reused
|
|
|
|
+ * the seq# and got a reply from the cache, then retry
|
|
|
|
+ */
|
|
|
|
+ if (task->tk_status == -EREMOTEIO && interrupted) {
|
|
|
|
+ ++slot->seq_nr;
|
|
|
|
+ goto retry_nowait;
|
|
|
|
+ }
|
|
/* Update the slot's sequence and clientid lease timer */
|
|
/* Update the slot's sequence and clientid lease timer */
|
|
slot->seq_done = 1;
|
|
slot->seq_done = 1;
|
|
clp = session->clp;
|
|
clp = session->clp;
|
|
do_renew_lease(clp, res->sr_timestamp);
|
|
do_renew_lease(clp, res->sr_timestamp);
|
|
/* Check sequence flags */
|
|
/* Check sequence flags */
|
|
- nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags);
|
|
|
|
|
|
+ nfs41_handle_sequence_flag_errors(clp, res->sr_status_flags,
|
|
|
|
+ !!slot->privileged);
|
|
nfs41_update_target_slotid(slot->table, slot, res);
|
|
nfs41_update_target_slotid(slot->table, slot, res);
|
|
break;
|
|
break;
|
|
case 1:
|
|
case 1:
|
|
@@ -875,6 +915,7 @@ int nfs41_setup_sequence(struct nfs4_session *session,
|
|
}
|
|
}
|
|
spin_unlock(&tbl->slot_tbl_lock);
|
|
spin_unlock(&tbl->slot_tbl_lock);
|
|
|
|
|
|
|
|
+ slot->privileged = args->sa_privileged ? 1 : 0;
|
|
args->sa_slot = slot;
|
|
args->sa_slot = slot;
|
|
|
|
|
|
dprintk("<-- %s slotid=%u seqid=%u\n", __func__,
|
|
dprintk("<-- %s slotid=%u seqid=%u\n", __func__,
|
|
@@ -1353,6 +1394,19 @@ static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
|
|
nfs4_state_set_mode_locked(state, state->state | fmode);
|
|
nfs4_state_set_mode_locked(state, state->state | fmode);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#ifdef CONFIG_NFS_V4_1
|
|
|
|
+static bool nfs_open_stateid_recover_openmode(struct nfs4_state *state)
|
|
|
|
+{
|
|
|
|
+ if (state->n_rdonly && !test_bit(NFS_O_RDONLY_STATE, &state->flags))
|
|
|
|
+ return true;
|
|
|
|
+ if (state->n_wronly && !test_bit(NFS_O_WRONLY_STATE, &state->flags))
|
|
|
|
+ return true;
|
|
|
|
+ if (state->n_rdwr && !test_bit(NFS_O_RDWR_STATE, &state->flags))
|
|
|
|
+ return true;
|
|
|
|
+ return false;
|
|
|
|
+}
|
|
|
|
+#endif /* CONFIG_NFS_V4_1 */
|
|
|
|
+
|
|
static void nfs_test_and_clear_all_open_stateid(struct nfs4_state *state)
|
|
static void nfs_test_and_clear_all_open_stateid(struct nfs4_state *state)
|
|
{
|
|
{
|
|
struct nfs_client *clp = state->owner->so_server->nfs_client;
|
|
struct nfs_client *clp = state->owner->so_server->nfs_client;
|
|
@@ -1369,11 +1423,12 @@ static void nfs_test_and_clear_all_open_stateid(struct nfs4_state *state)
|
|
}
|
|
}
|
|
|
|
|
|
static bool nfs_need_update_open_stateid(struct nfs4_state *state,
|
|
static bool nfs_need_update_open_stateid(struct nfs4_state *state,
|
|
- nfs4_stateid *stateid)
|
|
|
|
|
|
+ const nfs4_stateid *stateid, nfs4_stateid *freeme)
|
|
{
|
|
{
|
|
if (test_and_set_bit(NFS_OPEN_STATE, &state->flags) == 0)
|
|
if (test_and_set_bit(NFS_OPEN_STATE, &state->flags) == 0)
|
|
return true;
|
|
return true;
|
|
if (!nfs4_stateid_match_other(stateid, &state->open_stateid)) {
|
|
if (!nfs4_stateid_match_other(stateid, &state->open_stateid)) {
|
|
|
|
+ nfs4_stateid_copy(freeme, &state->open_stateid);
|
|
nfs_test_and_clear_all_open_stateid(state);
|
|
nfs_test_and_clear_all_open_stateid(state);
|
|
return true;
|
|
return true;
|
|
}
|
|
}
|
|
@@ -1437,7 +1492,9 @@ static void nfs_clear_open_stateid(struct nfs4_state *state,
|
|
nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
|
|
nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
|
|
}
|
|
}
|
|
|
|
|
|
-static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
|
|
|
|
|
|
+static void nfs_set_open_stateid_locked(struct nfs4_state *state,
|
|
|
|
+ const nfs4_stateid *stateid, fmode_t fmode,
|
|
|
|
+ nfs4_stateid *freeme)
|
|
{
|
|
{
|
|
switch (fmode) {
|
|
switch (fmode) {
|
|
case FMODE_READ:
|
|
case FMODE_READ:
|
|
@@ -1449,14 +1506,18 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *
|
|
case FMODE_READ|FMODE_WRITE:
|
|
case FMODE_READ|FMODE_WRITE:
|
|
set_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
set_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
}
|
|
}
|
|
- if (!nfs_need_update_open_stateid(state, stateid))
|
|
|
|
|
|
+ if (!nfs_need_update_open_stateid(state, stateid, freeme))
|
|
return;
|
|
return;
|
|
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
|
|
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
|
|
nfs4_stateid_copy(&state->stateid, stateid);
|
|
nfs4_stateid_copy(&state->stateid, stateid);
|
|
nfs4_stateid_copy(&state->open_stateid, stateid);
|
|
nfs4_stateid_copy(&state->open_stateid, stateid);
|
|
}
|
|
}
|
|
|
|
|
|
-static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, const nfs4_stateid *deleg_stateid, fmode_t fmode)
|
|
|
|
|
|
+static void __update_open_stateid(struct nfs4_state *state,
|
|
|
|
+ const nfs4_stateid *open_stateid,
|
|
|
|
+ const nfs4_stateid *deleg_stateid,
|
|
|
|
+ fmode_t fmode,
|
|
|
|
+ nfs4_stateid *freeme)
|
|
{
|
|
{
|
|
/*
|
|
/*
|
|
* Protect the call to nfs4_state_set_mode_locked and
|
|
* Protect the call to nfs4_state_set_mode_locked and
|
|
@@ -1469,16 +1530,22 @@ static void __update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_s
|
|
set_bit(NFS_DELEGATED_STATE, &state->flags);
|
|
set_bit(NFS_DELEGATED_STATE, &state->flags);
|
|
}
|
|
}
|
|
if (open_stateid != NULL)
|
|
if (open_stateid != NULL)
|
|
- nfs_set_open_stateid_locked(state, open_stateid, fmode);
|
|
|
|
|
|
+ nfs_set_open_stateid_locked(state, open_stateid, fmode, freeme);
|
|
write_sequnlock(&state->seqlock);
|
|
write_sequnlock(&state->seqlock);
|
|
update_open_stateflags(state, fmode);
|
|
update_open_stateflags(state, fmode);
|
|
spin_unlock(&state->owner->so_lock);
|
|
spin_unlock(&state->owner->so_lock);
|
|
}
|
|
}
|
|
|
|
|
|
-static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stateid, nfs4_stateid *delegation, fmode_t fmode)
|
|
|
|
|
|
+static int update_open_stateid(struct nfs4_state *state,
|
|
|
|
+ const nfs4_stateid *open_stateid,
|
|
|
|
+ const nfs4_stateid *delegation,
|
|
|
|
+ fmode_t fmode)
|
|
{
|
|
{
|
|
|
|
+ struct nfs_server *server = NFS_SERVER(state->inode);
|
|
|
|
+ struct nfs_client *clp = server->nfs_client;
|
|
struct nfs_inode *nfsi = NFS_I(state->inode);
|
|
struct nfs_inode *nfsi = NFS_I(state->inode);
|
|
struct nfs_delegation *deleg_cur;
|
|
struct nfs_delegation *deleg_cur;
|
|
|
|
+ nfs4_stateid freeme = {0};
|
|
int ret = 0;
|
|
int ret = 0;
|
|
|
|
|
|
fmode &= (FMODE_READ|FMODE_WRITE);
|
|
fmode &= (FMODE_READ|FMODE_WRITE);
|
|
@@ -1500,7 +1567,8 @@ static int update_open_stateid(struct nfs4_state *state, nfs4_stateid *open_stat
|
|
goto no_delegation_unlock;
|
|
goto no_delegation_unlock;
|
|
|
|
|
|
nfs_mark_delegation_referenced(deleg_cur);
|
|
nfs_mark_delegation_referenced(deleg_cur);
|
|
- __update_open_stateid(state, open_stateid, &deleg_cur->stateid, fmode);
|
|
|
|
|
|
+ __update_open_stateid(state, open_stateid, &deleg_cur->stateid,
|
|
|
|
+ fmode, &freeme);
|
|
ret = 1;
|
|
ret = 1;
|
|
no_delegation_unlock:
|
|
no_delegation_unlock:
|
|
spin_unlock(&deleg_cur->lock);
|
|
spin_unlock(&deleg_cur->lock);
|
|
@@ -1508,11 +1576,14 @@ no_delegation:
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
|
|
|
|
if (!ret && open_stateid != NULL) {
|
|
if (!ret && open_stateid != NULL) {
|
|
- __update_open_stateid(state, open_stateid, NULL, fmode);
|
|
|
|
|
|
+ __update_open_stateid(state, open_stateid, NULL, fmode, &freeme);
|
|
ret = 1;
|
|
ret = 1;
|
|
}
|
|
}
|
|
if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
|
|
if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
|
|
- nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
|
|
|
|
|
|
+ nfs4_schedule_state_manager(clp);
|
|
|
|
+ if (freeme.type != 0)
|
|
|
|
+ nfs4_test_and_free_stateid(server, &freeme,
|
|
|
|
+ state->owner->so_cred);
|
|
|
|
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
@@ -1889,7 +1960,6 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
|
|
case -NFS4ERR_STALE_CLIENTID:
|
|
case -NFS4ERR_STALE_CLIENTID:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
set_bit(NFS_DELEGATED_STATE, &state->flags);
|
|
set_bit(NFS_DELEGATED_STATE, &state->flags);
|
|
- case -NFS4ERR_EXPIRED:
|
|
|
|
/* Don't recall a delegation if it was lost */
|
|
/* Don't recall a delegation if it was lost */
|
|
nfs4_schedule_lease_recovery(server->nfs_client);
|
|
nfs4_schedule_lease_recovery(server->nfs_client);
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
@@ -1901,6 +1971,7 @@ static int nfs4_handle_delegation_recall_error(struct nfs_server *server, struct
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
case -NFS4ERR_DELEG_REVOKED:
|
|
case -NFS4ERR_DELEG_REVOKED:
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
|
|
+ case -NFS4ERR_EXPIRED:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
case -NFS4ERR_OPENMODE:
|
|
case -NFS4ERR_OPENMODE:
|
|
nfs_inode_find_state_and_recover(state->inode,
|
|
nfs_inode_find_state_and_recover(state->inode,
|
|
@@ -2382,9 +2453,10 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta
|
|
return ret;
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
-static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state)
|
|
|
|
|
|
+static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state,
|
|
|
|
+ const nfs4_stateid *stateid)
|
|
{
|
|
{
|
|
- nfs_remove_bad_delegation(state->inode);
|
|
|
|
|
|
+ nfs_remove_bad_delegation(state->inode, stateid);
|
|
write_seqlock(&state->seqlock);
|
|
write_seqlock(&state->seqlock);
|
|
nfs4_stateid_copy(&state->stateid, &state->open_stateid);
|
|
nfs4_stateid_copy(&state->stateid, &state->open_stateid);
|
|
write_sequnlock(&state->seqlock);
|
|
write_sequnlock(&state->seqlock);
|
|
@@ -2394,7 +2466,7 @@ static void nfs_finish_clear_delegation_stateid(struct nfs4_state *state)
|
|
static void nfs40_clear_delegation_stateid(struct nfs4_state *state)
|
|
static void nfs40_clear_delegation_stateid(struct nfs4_state *state)
|
|
{
|
|
{
|
|
if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL)
|
|
if (rcu_access_pointer(NFS_I(state->inode)->delegation) != NULL)
|
|
- nfs_finish_clear_delegation_stateid(state);
|
|
|
|
|
|
+ nfs_finish_clear_delegation_stateid(state, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
|
|
static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
|
|
@@ -2404,7 +2476,45 @@ static int nfs40_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
|
|
return nfs4_open_expired(sp, state);
|
|
return nfs4_open_expired(sp, state);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int nfs40_test_and_free_expired_stateid(struct nfs_server *server,
|
|
|
|
+ nfs4_stateid *stateid,
|
|
|
|
+ struct rpc_cred *cred)
|
|
|
|
+{
|
|
|
|
+ return -NFS4ERR_BAD_STATEID;
|
|
|
|
+}
|
|
|
|
+
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
|
|
+static int nfs41_test_and_free_expired_stateid(struct nfs_server *server,
|
|
|
|
+ nfs4_stateid *stateid,
|
|
|
|
+ struct rpc_cred *cred)
|
|
|
|
+{
|
|
|
|
+ int status;
|
|
|
|
+
|
|
|
|
+ switch (stateid->type) {
|
|
|
|
+ default:
|
|
|
|
+ break;
|
|
|
|
+ case NFS4_INVALID_STATEID_TYPE:
|
|
|
|
+ case NFS4_SPECIAL_STATEID_TYPE:
|
|
|
|
+ return -NFS4ERR_BAD_STATEID;
|
|
|
|
+ case NFS4_REVOKED_STATEID_TYPE:
|
|
|
|
+ goto out_free;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ status = nfs41_test_stateid(server, stateid, cred);
|
|
|
|
+ switch (status) {
|
|
|
|
+ case -NFS4ERR_EXPIRED:
|
|
|
|
+ case -NFS4ERR_ADMIN_REVOKED:
|
|
|
|
+ case -NFS4ERR_DELEG_REVOKED:
|
|
|
|
+ break;
|
|
|
|
+ default:
|
|
|
|
+ return status;
|
|
|
|
+ }
|
|
|
|
+out_free:
|
|
|
|
+ /* Ack the revoked state to the server */
|
|
|
|
+ nfs41_free_stateid(server, stateid, cred, true);
|
|
|
|
+ return -NFS4ERR_EXPIRED;
|
|
|
|
+}
|
|
|
|
+
|
|
static void nfs41_check_delegation_stateid(struct nfs4_state *state)
|
|
static void nfs41_check_delegation_stateid(struct nfs4_state *state)
|
|
{
|
|
{
|
|
struct nfs_server *server = NFS_SERVER(state->inode);
|
|
struct nfs_server *server = NFS_SERVER(state->inode);
|
|
@@ -2422,22 +2532,67 @@ static void nfs41_check_delegation_stateid(struct nfs4_state *state)
|
|
}
|
|
}
|
|
|
|
|
|
nfs4_stateid_copy(&stateid, &delegation->stateid);
|
|
nfs4_stateid_copy(&stateid, &delegation->stateid);
|
|
|
|
+ if (test_bit(NFS_DELEGATION_REVOKED, &delegation->flags)) {
|
|
|
|
+ rcu_read_unlock();
|
|
|
|
+ nfs_finish_clear_delegation_stateid(state, &stateid);
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (!test_and_clear_bit(NFS_DELEGATION_TEST_EXPIRED, &delegation->flags)) {
|
|
|
|
+ rcu_read_unlock();
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+
|
|
cred = get_rpccred(delegation->cred);
|
|
cred = get_rpccred(delegation->cred);
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
- status = nfs41_test_stateid(server, &stateid, cred);
|
|
|
|
|
|
+ status = nfs41_test_and_free_expired_stateid(server, &stateid, cred);
|
|
trace_nfs4_test_delegation_stateid(state, NULL, status);
|
|
trace_nfs4_test_delegation_stateid(state, NULL, status);
|
|
-
|
|
|
|
- if (status != NFS_OK) {
|
|
|
|
- /* Free the stateid unless the server explicitly
|
|
|
|
- * informs us the stateid is unrecognized. */
|
|
|
|
- if (status != -NFS4ERR_BAD_STATEID)
|
|
|
|
- nfs41_free_stateid(server, &stateid, cred);
|
|
|
|
- nfs_finish_clear_delegation_stateid(state);
|
|
|
|
- }
|
|
|
|
|
|
+ if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID)
|
|
|
|
+ nfs_finish_clear_delegation_stateid(state, &stateid);
|
|
|
|
|
|
put_rpccred(cred);
|
|
put_rpccred(cred);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+/**
|
|
|
|
+ * nfs41_check_expired_locks - possibly free a lock stateid
|
|
|
|
+ *
|
|
|
|
+ * @state: NFSv4 state for an inode
|
|
|
|
+ *
|
|
|
|
+ * Returns NFS_OK if recovery for this stateid is now finished.
|
|
|
|
+ * Otherwise a negative NFS4ERR value is returned.
|
|
|
|
+ */
|
|
|
|
+static int nfs41_check_expired_locks(struct nfs4_state *state)
|
|
|
|
+{
|
|
|
|
+ int status, ret = NFS_OK;
|
|
|
|
+ struct nfs4_lock_state *lsp;
|
|
|
|
+ struct nfs_server *server = NFS_SERVER(state->inode);
|
|
|
|
+
|
|
|
|
+ if (!test_bit(LK_STATE_IN_USE, &state->flags))
|
|
|
|
+ goto out;
|
|
|
|
+ list_for_each_entry(lsp, &state->lock_states, ls_locks) {
|
|
|
|
+ if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
|
|
|
|
+ struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
|
|
|
|
+
|
|
|
|
+ status = nfs41_test_and_free_expired_stateid(server,
|
|
|
|
+ &lsp->ls_stateid,
|
|
|
|
+ cred);
|
|
|
|
+ trace_nfs4_test_lock_stateid(state, lsp, status);
|
|
|
|
+ if (status == -NFS4ERR_EXPIRED ||
|
|
|
|
+ status == -NFS4ERR_BAD_STATEID) {
|
|
|
|
+ clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
|
|
|
|
+ lsp->ls_stateid.type = NFS4_INVALID_STATEID_TYPE;
|
|
|
|
+ if (!recover_lost_locks)
|
|
|
|
+ set_bit(NFS_LOCK_LOST, &lsp->ls_flags);
|
|
|
|
+ } else if (status != NFS_OK) {
|
|
|
|
+ ret = status;
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+out:
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* nfs41_check_open_stateid - possibly free an open stateid
|
|
* nfs41_check_open_stateid - possibly free an open stateid
|
|
*
|
|
*
|
|
@@ -2453,26 +2608,28 @@ static int nfs41_check_open_stateid(struct nfs4_state *state)
|
|
struct rpc_cred *cred = state->owner->so_cred;
|
|
struct rpc_cred *cred = state->owner->so_cred;
|
|
int status;
|
|
int status;
|
|
|
|
|
|
- /* If a state reset has been done, test_stateid is unneeded */
|
|
|
|
- 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))
|
|
|
|
|
|
+ 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;
|
|
|
|
+ }
|
|
return -NFS4ERR_BAD_STATEID;
|
|
return -NFS4ERR_BAD_STATEID;
|
|
-
|
|
|
|
- status = nfs41_test_stateid(server, stateid, cred);
|
|
|
|
|
|
+ }
|
|
|
|
+ status = nfs41_test_and_free_expired_stateid(server, stateid, cred);
|
|
trace_nfs4_test_open_stateid(state, NULL, status);
|
|
trace_nfs4_test_open_stateid(state, NULL, status);
|
|
- if (status != NFS_OK) {
|
|
|
|
- /* Free the stateid unless the server explicitly
|
|
|
|
- * informs us the stateid is unrecognized. */
|
|
|
|
- if (status != -NFS4ERR_BAD_STATEID)
|
|
|
|
- nfs41_free_stateid(server, stateid, cred);
|
|
|
|
-
|
|
|
|
|
|
+ if (status == -NFS4ERR_EXPIRED || status == -NFS4ERR_BAD_STATEID) {
|
|
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
clear_bit(NFS_OPEN_STATE, &state->flags);
|
|
clear_bit(NFS_OPEN_STATE, &state->flags);
|
|
|
|
+ stateid->type = NFS4_INVALID_STATEID_TYPE;
|
|
}
|
|
}
|
|
- return status;
|
|
|
|
|
|
+ if (status != NFS_OK)
|
|
|
|
+ return status;
|
|
|
|
+ if (nfs_open_stateid_recover_openmode(state))
|
|
|
|
+ return -NFS4ERR_OPENMODE;
|
|
|
|
+ return NFS_OK;
|
|
}
|
|
}
|
|
|
|
|
|
static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
|
|
static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state)
|
|
@@ -2480,6 +2637,9 @@ static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *st
|
|
int status;
|
|
int status;
|
|
|
|
|
|
nfs41_check_delegation_stateid(state);
|
|
nfs41_check_delegation_stateid(state);
|
|
|
|
+ status = nfs41_check_expired_locks(state);
|
|
|
|
+ if (status != NFS_OK)
|
|
|
|
+ return status;
|
|
status = nfs41_check_open_stateid(state);
|
|
status = nfs41_check_open_stateid(state);
|
|
if (status != NFS_OK)
|
|
if (status != NFS_OK)
|
|
status = nfs4_open_expired(sp, state);
|
|
status = nfs4_open_expired(sp, state);
|
|
@@ -2537,6 +2697,8 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata,
|
|
goto out;
|
|
goto out;
|
|
if (server->caps & NFS_CAP_POSIX_LOCK)
|
|
if (server->caps & NFS_CAP_POSIX_LOCK)
|
|
set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
|
|
set_bit(NFS_STATE_POSIX_LOCKS, &state->flags);
|
|
|
|
+ if (opendata->o_res.rflags & NFS4_OPEN_RESULT_MAY_NOTIFY_LOCK)
|
|
|
|
+ set_bit(NFS_STATE_MAY_NOTIFY_LOCK, &state->flags);
|
|
|
|
|
|
dentry = opendata->dentry;
|
|
dentry = opendata->dentry;
|
|
if (d_really_is_negative(dentry)) {
|
|
if (d_really_is_negative(dentry)) {
|
|
@@ -2899,9 +3061,12 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
|
|
break;
|
|
break;
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
|
|
+ case -NFS4ERR_EXPIRED:
|
|
|
|
+ nfs4_free_revoked_stateid(server,
|
|
|
|
+ &calldata->arg.stateid,
|
|
|
|
+ task->tk_msg.rpc_cred);
|
|
case -NFS4ERR_OLD_STATEID:
|
|
case -NFS4ERR_OLD_STATEID:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
- case -NFS4ERR_EXPIRED:
|
|
|
|
if (!nfs4_stateid_match(&calldata->arg.stateid,
|
|
if (!nfs4_stateid_match(&calldata->arg.stateid,
|
|
&state->open_stateid)) {
|
|
&state->open_stateid)) {
|
|
rpc_restart_call_prepare(task);
|
|
rpc_restart_call_prepare(task);
|
|
@@ -4312,7 +4477,7 @@ static int nfs4_proc_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, s
|
|
if (error == 0) {
|
|
if (error == 0) {
|
|
/* block layout checks this! */
|
|
/* block layout checks this! */
|
|
server->pnfs_blksize = fsinfo->blksize;
|
|
server->pnfs_blksize = fsinfo->blksize;
|
|
- set_pnfs_layoutdriver(server, fhandle, fsinfo->layouttype);
|
|
|
|
|
|
+ set_pnfs_layoutdriver(server, fhandle, fsinfo);
|
|
}
|
|
}
|
|
|
|
|
|
return error;
|
|
return error;
|
|
@@ -4399,24 +4564,25 @@ static bool nfs4_error_stateid_expired(int err)
|
|
return false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
-void __nfs4_read_done_cb(struct nfs_pgio_header *hdr)
|
|
|
|
-{
|
|
|
|
- nfs_invalidate_atime(hdr->inode);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_header *hdr)
|
|
static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_header *hdr)
|
|
{
|
|
{
|
|
struct nfs_server *server = NFS_SERVER(hdr->inode);
|
|
struct nfs_server *server = NFS_SERVER(hdr->inode);
|
|
|
|
|
|
trace_nfs4_read(hdr, task->tk_status);
|
|
trace_nfs4_read(hdr, task->tk_status);
|
|
- if (nfs4_async_handle_error(task, server,
|
|
|
|
- hdr->args.context->state,
|
|
|
|
- NULL) == -EAGAIN) {
|
|
|
|
- rpc_restart_call_prepare(task);
|
|
|
|
- return -EAGAIN;
|
|
|
|
|
|
+ if (task->tk_status < 0) {
|
|
|
|
+ struct nfs4_exception exception = {
|
|
|
|
+ .inode = hdr->inode,
|
|
|
|
+ .state = hdr->args.context->state,
|
|
|
|
+ .stateid = &hdr->args.stateid,
|
|
|
|
+ };
|
|
|
|
+ task->tk_status = nfs4_async_handle_exception(task,
|
|
|
|
+ server, task->tk_status, &exception);
|
|
|
|
+ if (exception.retry) {
|
|
|
|
+ rpc_restart_call_prepare(task);
|
|
|
|
+ return -EAGAIN;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
|
|
|
|
- __nfs4_read_done_cb(hdr);
|
|
|
|
if (task->tk_status > 0)
|
|
if (task->tk_status > 0)
|
|
renew_lease(server, hdr->timestamp);
|
|
renew_lease(server, hdr->timestamp);
|
|
return 0;
|
|
return 0;
|
|
@@ -4445,6 +4611,8 @@ static int nfs4_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr)
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
if (nfs4_read_stateid_changed(task, &hdr->args))
|
|
if (nfs4_read_stateid_changed(task, &hdr->args))
|
|
return -EAGAIN;
|
|
return -EAGAIN;
|
|
|
|
+ if (task->tk_status > 0)
|
|
|
|
+ nfs_invalidate_atime(hdr->inode);
|
|
return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) :
|
|
return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) :
|
|
nfs4_read_done_cb(task, hdr);
|
|
nfs4_read_done_cb(task, hdr);
|
|
}
|
|
}
|
|
@@ -4482,11 +4650,19 @@ static int nfs4_write_done_cb(struct rpc_task *task,
|
|
struct inode *inode = hdr->inode;
|
|
struct inode *inode = hdr->inode;
|
|
|
|
|
|
trace_nfs4_write(hdr, task->tk_status);
|
|
trace_nfs4_write(hdr, task->tk_status);
|
|
- if (nfs4_async_handle_error(task, NFS_SERVER(inode),
|
|
|
|
- hdr->args.context->state,
|
|
|
|
- NULL) == -EAGAIN) {
|
|
|
|
- rpc_restart_call_prepare(task);
|
|
|
|
- return -EAGAIN;
|
|
|
|
|
|
+ if (task->tk_status < 0) {
|
|
|
|
+ struct nfs4_exception exception = {
|
|
|
|
+ .inode = hdr->inode,
|
|
|
|
+ .state = hdr->args.context->state,
|
|
|
|
+ .stateid = &hdr->args.stateid,
|
|
|
|
+ };
|
|
|
|
+ task->tk_status = nfs4_async_handle_exception(task,
|
|
|
|
+ NFS_SERVER(inode), task->tk_status,
|
|
|
|
+ &exception);
|
|
|
|
+ if (exception.retry) {
|
|
|
|
+ rpc_restart_call_prepare(task);
|
|
|
|
+ return -EAGAIN;
|
|
|
|
+ }
|
|
}
|
|
}
|
|
if (task->tk_status >= 0) {
|
|
if (task->tk_status >= 0) {
|
|
renew_lease(NFS_SERVER(inode), hdr->timestamp);
|
|
renew_lease(NFS_SERVER(inode), hdr->timestamp);
|
|
@@ -5123,12 +5299,14 @@ static void nfs4_init_boot_verifier(const struct nfs_client *clp,
|
|
if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
|
|
if (test_bit(NFS4CLNT_PURGE_STATE, &clp->cl_state)) {
|
|
/* An impossible timestamp guarantees this value
|
|
/* An impossible timestamp guarantees this value
|
|
* will never match a generated boot time. */
|
|
* will never match a generated boot time. */
|
|
- verf[0] = 0;
|
|
|
|
- verf[1] = cpu_to_be32(NSEC_PER_SEC + 1);
|
|
|
|
|
|
+ verf[0] = cpu_to_be32(U32_MAX);
|
|
|
|
+ verf[1] = cpu_to_be32(U32_MAX);
|
|
} else {
|
|
} else {
|
|
struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
|
|
struct nfs_net *nn = net_generic(clp->cl_net, nfs_net_id);
|
|
- verf[0] = cpu_to_be32(nn->boot_time.tv_sec);
|
|
|
|
- verf[1] = cpu_to_be32(nn->boot_time.tv_nsec);
|
|
|
|
|
|
+ u64 ns = ktime_to_ns(nn->boot_time);
|
|
|
|
+
|
|
|
|
+ verf[0] = cpu_to_be32(ns >> 32);
|
|
|
|
+ verf[1] = cpu_to_be32(ns);
|
|
}
|
|
}
|
|
memcpy(bootverf->data, verf, sizeof(bootverf->data));
|
|
memcpy(bootverf->data, verf, sizeof(bootverf->data));
|
|
}
|
|
}
|
|
@@ -5393,10 +5571,13 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata)
|
|
renew_lease(data->res.server, data->timestamp);
|
|
renew_lease(data->res.server, data->timestamp);
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
case -NFS4ERR_DELEG_REVOKED:
|
|
case -NFS4ERR_DELEG_REVOKED:
|
|
|
|
+ case -NFS4ERR_EXPIRED:
|
|
|
|
+ nfs4_free_revoked_stateid(data->res.server,
|
|
|
|
+ data->args.stateid,
|
|
|
|
+ task->tk_msg.rpc_cred);
|
|
case -NFS4ERR_BAD_STATEID:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
case -NFS4ERR_OLD_STATEID:
|
|
case -NFS4ERR_OLD_STATEID:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
- case -NFS4ERR_EXPIRED:
|
|
|
|
task->tk_status = 0;
|
|
task->tk_status = 0;
|
|
if (data->roc)
|
|
if (data->roc)
|
|
pnfs_roc_set_barrier(data->inode, data->roc_barrier);
|
|
pnfs_roc_set_barrier(data->inode, data->roc_barrier);
|
|
@@ -5528,22 +5709,6 @@ int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-#define NFS4_LOCK_MINTIMEOUT (1 * HZ)
|
|
|
|
-#define NFS4_LOCK_MAXTIMEOUT (30 * HZ)
|
|
|
|
-
|
|
|
|
-/*
|
|
|
|
- * sleep, with exponential backoff, and retry the LOCK operation.
|
|
|
|
- */
|
|
|
|
-static unsigned long
|
|
|
|
-nfs4_set_lock_task_retry(unsigned long timeout)
|
|
|
|
-{
|
|
|
|
- freezable_schedule_timeout_killable_unsafe(timeout);
|
|
|
|
- timeout <<= 1;
|
|
|
|
- if (timeout > NFS4_LOCK_MAXTIMEOUT)
|
|
|
|
- return NFS4_LOCK_MAXTIMEOUT;
|
|
|
|
- return timeout;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
|
|
static int _nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request)
|
|
{
|
|
{
|
|
struct inode *inode = state->inode;
|
|
struct inode *inode = state->inode;
|
|
@@ -5600,11 +5765,6 @@ static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
-static int do_vfs_lock(struct inode *inode, struct file_lock *fl)
|
|
|
|
-{
|
|
|
|
- return locks_lock_inode_wait(inode, fl);
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
struct nfs4_unlockdata {
|
|
struct nfs4_unlockdata {
|
|
struct nfs_locku_args arg;
|
|
struct nfs_locku_args arg;
|
|
struct nfs_locku_res res;
|
|
struct nfs_locku_res res;
|
|
@@ -5657,14 +5817,18 @@ static void nfs4_locku_done(struct rpc_task *task, void *data)
|
|
switch (task->tk_status) {
|
|
switch (task->tk_status) {
|
|
case 0:
|
|
case 0:
|
|
renew_lease(calldata->server, calldata->timestamp);
|
|
renew_lease(calldata->server, calldata->timestamp);
|
|
- do_vfs_lock(calldata->lsp->ls_state->inode, &calldata->fl);
|
|
|
|
|
|
+ locks_lock_inode_wait(calldata->lsp->ls_state->inode, &calldata->fl);
|
|
if (nfs4_update_lock_stateid(calldata->lsp,
|
|
if (nfs4_update_lock_stateid(calldata->lsp,
|
|
&calldata->res.stateid))
|
|
&calldata->res.stateid))
|
|
break;
|
|
break;
|
|
|
|
+ case -NFS4ERR_ADMIN_REVOKED:
|
|
|
|
+ case -NFS4ERR_EXPIRED:
|
|
|
|
+ nfs4_free_revoked_stateid(calldata->server,
|
|
|
|
+ &calldata->arg.stateid,
|
|
|
|
+ task->tk_msg.rpc_cred);
|
|
case -NFS4ERR_BAD_STATEID:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
case -NFS4ERR_OLD_STATEID:
|
|
case -NFS4ERR_OLD_STATEID:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
- case -NFS4ERR_EXPIRED:
|
|
|
|
if (!nfs4_stateid_match(&calldata->arg.stateid,
|
|
if (!nfs4_stateid_match(&calldata->arg.stateid,
|
|
&calldata->lsp->ls_stateid))
|
|
&calldata->lsp->ls_stateid))
|
|
rpc_restart_call_prepare(task);
|
|
rpc_restart_call_prepare(task);
|
|
@@ -5765,7 +5929,7 @@ static int nfs4_proc_unlck(struct nfs4_state *state, int cmd, struct file_lock *
|
|
mutex_lock(&sp->so_delegreturn_mutex);
|
|
mutex_lock(&sp->so_delegreturn_mutex);
|
|
/* Exclude nfs4_reclaim_open_stateid() - note nesting! */
|
|
/* Exclude nfs4_reclaim_open_stateid() - note nesting! */
|
|
down_read(&nfsi->rwsem);
|
|
down_read(&nfsi->rwsem);
|
|
- if (do_vfs_lock(inode, request) == -ENOENT) {
|
|
|
|
|
|
+ if (locks_lock_inode_wait(inode, request) == -ENOENT) {
|
|
up_read(&nfsi->rwsem);
|
|
up_read(&nfsi->rwsem);
|
|
mutex_unlock(&sp->so_delegreturn_mutex);
|
|
mutex_unlock(&sp->so_delegreturn_mutex);
|
|
goto out;
|
|
goto out;
|
|
@@ -5906,7 +6070,7 @@ static void nfs4_lock_done(struct rpc_task *task, void *calldata)
|
|
data->timestamp);
|
|
data->timestamp);
|
|
if (data->arg.new_lock) {
|
|
if (data->arg.new_lock) {
|
|
data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
|
|
data->fl.fl_flags &= ~(FL_SLEEP | FL_ACCESS);
|
|
- if (do_vfs_lock(lsp->ls_state->inode, &data->fl) < 0) {
|
|
|
|
|
|
+ if (locks_lock_inode_wait(lsp->ls_state->inode, &data->fl) < 0) {
|
|
rpc_restart_call_prepare(task);
|
|
rpc_restart_call_prepare(task);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
@@ -5965,6 +6129,7 @@ static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_
|
|
{
|
|
{
|
|
switch (error) {
|
|
switch (error) {
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
|
|
+ case -NFS4ERR_EXPIRED:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
|
|
lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
|
|
if (new_lock_owner != 0 ||
|
|
if (new_lock_owner != 0 ||
|
|
@@ -5973,7 +6138,6 @@ static void nfs4_handle_setlk_error(struct nfs_server *server, struct nfs4_lock_
|
|
break;
|
|
break;
|
|
case -NFS4ERR_STALE_STATEID:
|
|
case -NFS4ERR_STALE_STATEID:
|
|
lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
|
|
lsp->ls_seqid.flags &= ~NFS_SEQID_CONFIRMED;
|
|
- case -NFS4ERR_EXPIRED:
|
|
|
|
nfs4_schedule_lease_recovery(server->nfs_client);
|
|
nfs4_schedule_lease_recovery(server->nfs_client);
|
|
};
|
|
};
|
|
}
|
|
}
|
|
@@ -6083,52 +6247,19 @@ out:
|
|
}
|
|
}
|
|
|
|
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
#if defined(CONFIG_NFS_V4_1)
|
|
-/**
|
|
|
|
- * nfs41_check_expired_locks - possibly free a lock stateid
|
|
|
|
- *
|
|
|
|
- * @state: NFSv4 state for an inode
|
|
|
|
- *
|
|
|
|
- * Returns NFS_OK if recovery for this stateid is now finished.
|
|
|
|
- * Otherwise a negative NFS4ERR value is returned.
|
|
|
|
- */
|
|
|
|
-static int nfs41_check_expired_locks(struct nfs4_state *state)
|
|
|
|
-{
|
|
|
|
- int status, ret = -NFS4ERR_BAD_STATEID;
|
|
|
|
- struct nfs4_lock_state *lsp;
|
|
|
|
- struct nfs_server *server = NFS_SERVER(state->inode);
|
|
|
|
-
|
|
|
|
- list_for_each_entry(lsp, &state->lock_states, ls_locks) {
|
|
|
|
- if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) {
|
|
|
|
- struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
|
|
|
|
-
|
|
|
|
- status = nfs41_test_stateid(server,
|
|
|
|
- &lsp->ls_stateid,
|
|
|
|
- cred);
|
|
|
|
- trace_nfs4_test_lock_stateid(state, lsp, status);
|
|
|
|
- if (status != NFS_OK) {
|
|
|
|
- /* Free the stateid unless the server
|
|
|
|
- * informs us the stateid is unrecognized. */
|
|
|
|
- if (status != -NFS4ERR_BAD_STATEID)
|
|
|
|
- nfs41_free_stateid(server,
|
|
|
|
- &lsp->ls_stateid,
|
|
|
|
- cred);
|
|
|
|
- clear_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags);
|
|
|
|
- ret = status;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
-
|
|
|
|
- return ret;
|
|
|
|
-}
|
|
|
|
-
|
|
|
|
static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
|
|
static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request)
|
|
{
|
|
{
|
|
- int status = NFS_OK;
|
|
|
|
|
|
+ struct nfs4_lock_state *lsp;
|
|
|
|
+ int status;
|
|
|
|
|
|
- if (test_bit(LK_STATE_IN_USE, &state->flags))
|
|
|
|
- status = nfs41_check_expired_locks(state);
|
|
|
|
- if (status != NFS_OK)
|
|
|
|
- status = nfs4_lock_expired(state, request);
|
|
|
|
|
|
+ status = nfs4_set_lock_state(state, request);
|
|
|
|
+ if (status != 0)
|
|
|
|
+ return status;
|
|
|
|
+ lsp = request->fl_u.nfs4_fl.owner;
|
|
|
|
+ if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) ||
|
|
|
|
+ test_bit(NFS_LOCK_LOST, &lsp->ls_flags))
|
|
|
|
+ return 0;
|
|
|
|
+ status = nfs4_lock_expired(state, request);
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
@@ -6138,17 +6269,10 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
|
|
struct nfs_inode *nfsi = NFS_I(state->inode);
|
|
struct nfs_inode *nfsi = NFS_I(state->inode);
|
|
struct nfs4_state_owner *sp = state->owner;
|
|
struct nfs4_state_owner *sp = state->owner;
|
|
unsigned char fl_flags = request->fl_flags;
|
|
unsigned char fl_flags = request->fl_flags;
|
|
- int status = -ENOLCK;
|
|
|
|
|
|
+ int status;
|
|
|
|
|
|
- if ((fl_flags & FL_POSIX) &&
|
|
|
|
- !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags))
|
|
|
|
- goto out;
|
|
|
|
- /* Is this a delegated open? */
|
|
|
|
- status = nfs4_set_lock_state(state, request);
|
|
|
|
- if (status != 0)
|
|
|
|
- goto out;
|
|
|
|
request->fl_flags |= FL_ACCESS;
|
|
request->fl_flags |= FL_ACCESS;
|
|
- status = do_vfs_lock(state->inode, request);
|
|
|
|
|
|
+ status = locks_lock_inode_wait(state->inode, request);
|
|
if (status < 0)
|
|
if (status < 0)
|
|
goto out;
|
|
goto out;
|
|
mutex_lock(&sp->so_delegreturn_mutex);
|
|
mutex_lock(&sp->so_delegreturn_mutex);
|
|
@@ -6157,7 +6281,7 @@ static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock
|
|
/* Yes: cache locks! */
|
|
/* Yes: cache locks! */
|
|
/* ...but avoid races with delegation recall... */
|
|
/* ...but avoid races with delegation recall... */
|
|
request->fl_flags = fl_flags & ~FL_SLEEP;
|
|
request->fl_flags = fl_flags & ~FL_SLEEP;
|
|
- status = do_vfs_lock(state->inode, request);
|
|
|
|
|
|
+ status = locks_lock_inode_wait(state->inode, request);
|
|
up_read(&nfsi->rwsem);
|
|
up_read(&nfsi->rwsem);
|
|
mutex_unlock(&sp->so_delegreturn_mutex);
|
|
mutex_unlock(&sp->so_delegreturn_mutex);
|
|
goto out;
|
|
goto out;
|
|
@@ -6188,12 +6312,124 @@ static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+#define NFS4_LOCK_MINTIMEOUT (1 * HZ)
|
|
|
|
+#define NFS4_LOCK_MAXTIMEOUT (30 * HZ)
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+nfs4_retry_setlk_simple(struct nfs4_state *state, int cmd,
|
|
|
|
+ struct file_lock *request)
|
|
|
|
+{
|
|
|
|
+ int status = -ERESTARTSYS;
|
|
|
|
+ unsigned long timeout = NFS4_LOCK_MINTIMEOUT;
|
|
|
|
+
|
|
|
|
+ while(!signalled()) {
|
|
|
|
+ status = nfs4_proc_setlk(state, cmd, request);
|
|
|
|
+ if ((status != -EAGAIN) || IS_SETLK(cmd))
|
|
|
|
+ break;
|
|
|
|
+ freezable_schedule_timeout_interruptible(timeout);
|
|
|
|
+ timeout *= 2;
|
|
|
|
+ timeout = min_t(unsigned long, NFS4_LOCK_MAXTIMEOUT, timeout);
|
|
|
|
+ status = -ERESTARTSYS;
|
|
|
|
+ }
|
|
|
|
+ return status;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+#ifdef CONFIG_NFS_V4_1
|
|
|
|
+struct nfs4_lock_waiter {
|
|
|
|
+ struct task_struct *task;
|
|
|
|
+ struct inode *inode;
|
|
|
|
+ struct nfs_lowner *owner;
|
|
|
|
+ bool notified;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+nfs4_wake_lock_waiter(wait_queue_t *wait, unsigned int mode, int flags, void *key)
|
|
|
|
+{
|
|
|
|
+ int ret;
|
|
|
|
+ struct cb_notify_lock_args *cbnl = key;
|
|
|
|
+ struct nfs4_lock_waiter *waiter = wait->private;
|
|
|
|
+ struct nfs_lowner *lowner = &cbnl->cbnl_owner,
|
|
|
|
+ *wowner = waiter->owner;
|
|
|
|
+
|
|
|
|
+ /* Only wake if the callback was for the same owner */
|
|
|
|
+ if (lowner->clientid != wowner->clientid ||
|
|
|
|
+ lowner->id != wowner->id ||
|
|
|
|
+ lowner->s_dev != wowner->s_dev)
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ /* Make sure it's for the right inode */
|
|
|
|
+ if (nfs_compare_fh(NFS_FH(waiter->inode), &cbnl->cbnl_fh))
|
|
|
|
+ return 0;
|
|
|
|
+
|
|
|
|
+ waiter->notified = true;
|
|
|
|
+
|
|
|
|
+ /* override "private" so we can use default_wake_function */
|
|
|
|
+ wait->private = waiter->task;
|
|
|
|
+ ret = autoremove_wake_function(wait, mode, flags, key);
|
|
|
|
+ wait->private = waiter;
|
|
|
|
+ return ret;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static int
|
|
|
|
+nfs4_retry_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
|
|
|
|
+{
|
|
|
|
+ int status = -ERESTARTSYS;
|
|
|
|
+ unsigned long flags;
|
|
|
|
+ struct nfs4_lock_state *lsp = request->fl_u.nfs4_fl.owner;
|
|
|
|
+ struct nfs_server *server = NFS_SERVER(state->inode);
|
|
|
|
+ struct nfs_client *clp = server->nfs_client;
|
|
|
|
+ wait_queue_head_t *q = &clp->cl_lock_waitq;
|
|
|
|
+ struct nfs_lowner owner = { .clientid = clp->cl_clientid,
|
|
|
|
+ .id = lsp->ls_seqid.owner_id,
|
|
|
|
+ .s_dev = server->s_dev };
|
|
|
|
+ struct nfs4_lock_waiter waiter = { .task = current,
|
|
|
|
+ .inode = state->inode,
|
|
|
|
+ .owner = &owner,
|
|
|
|
+ .notified = false };
|
|
|
|
+ wait_queue_t wait;
|
|
|
|
+
|
|
|
|
+ /* Don't bother with waitqueue if we don't expect a callback */
|
|
|
|
+ if (!test_bit(NFS_STATE_MAY_NOTIFY_LOCK, &state->flags))
|
|
|
|
+ return nfs4_retry_setlk_simple(state, cmd, request);
|
|
|
|
+
|
|
|
|
+ init_wait(&wait);
|
|
|
|
+ wait.private = &waiter;
|
|
|
|
+ wait.func = nfs4_wake_lock_waiter;
|
|
|
|
+ add_wait_queue(q, &wait);
|
|
|
|
+
|
|
|
|
+ while(!signalled()) {
|
|
|
|
+ status = nfs4_proc_setlk(state, cmd, request);
|
|
|
|
+ if ((status != -EAGAIN) || IS_SETLK(cmd))
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ status = -ERESTARTSYS;
|
|
|
|
+ spin_lock_irqsave(&q->lock, flags);
|
|
|
|
+ if (waiter.notified) {
|
|
|
|
+ spin_unlock_irqrestore(&q->lock, flags);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ set_current_state(TASK_INTERRUPTIBLE);
|
|
|
|
+ spin_unlock_irqrestore(&q->lock, flags);
|
|
|
|
+
|
|
|
|
+ freezable_schedule_timeout_interruptible(NFS4_LOCK_MAXTIMEOUT);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ finish_wait(q, &wait);
|
|
|
|
+ return status;
|
|
|
|
+}
|
|
|
|
+#else /* !CONFIG_NFS_V4_1 */
|
|
|
|
+static inline int
|
|
|
|
+nfs4_retry_setlk(struct nfs4_state *state, int cmd, struct file_lock *request)
|
|
|
|
+{
|
|
|
|
+ return nfs4_retry_setlk_simple(state, cmd, request);
|
|
|
|
+}
|
|
|
|
+#endif
|
|
|
|
+
|
|
static int
|
|
static int
|
|
nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
|
|
nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
|
|
{
|
|
{
|
|
struct nfs_open_context *ctx;
|
|
struct nfs_open_context *ctx;
|
|
struct nfs4_state *state;
|
|
struct nfs4_state *state;
|
|
- unsigned long timeout = NFS4_LOCK_MINTIMEOUT;
|
|
|
|
int status;
|
|
int status;
|
|
|
|
|
|
/* verify open state */
|
|
/* verify open state */
|
|
@@ -6220,6 +6456,11 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
|
|
|
|
|
|
if (state == NULL)
|
|
if (state == NULL)
|
|
return -ENOLCK;
|
|
return -ENOLCK;
|
|
|
|
+
|
|
|
|
+ if ((request->fl_flags & FL_POSIX) &&
|
|
|
|
+ !test_bit(NFS_STATE_POSIX_LOCKS, &state->flags))
|
|
|
|
+ return -ENOLCK;
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Don't rely on the VFS having checked the file open mode,
|
|
* Don't rely on the VFS having checked the file open mode,
|
|
* since it won't do this for flock() locks.
|
|
* since it won't do this for flock() locks.
|
|
@@ -6234,16 +6475,11 @@ nfs4_proc_lock(struct file *filp, int cmd, struct file_lock *request)
|
|
return -EBADF;
|
|
return -EBADF;
|
|
}
|
|
}
|
|
|
|
|
|
- do {
|
|
|
|
- status = nfs4_proc_setlk(state, cmd, request);
|
|
|
|
- if ((status != -EAGAIN) || IS_SETLK(cmd))
|
|
|
|
- break;
|
|
|
|
- timeout = nfs4_set_lock_task_retry(timeout);
|
|
|
|
- status = -ERESTARTSYS;
|
|
|
|
- if (signalled())
|
|
|
|
- break;
|
|
|
|
- } while(status < 0);
|
|
|
|
- return status;
|
|
|
|
|
|
+ status = nfs4_set_lock_state(state, request);
|
|
|
|
+ if (status != 0)
|
|
|
|
+ return status;
|
|
|
|
+
|
|
|
|
+ return nfs4_retry_setlk(state, cmd, request);
|
|
}
|
|
}
|
|
|
|
|
|
int nfs4_lock_delegation_recall(struct file_lock *fl, 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)
|
|
@@ -7104,75 +7340,161 @@ static int nfs4_sp4_select_mode(struct nfs_client *clp,
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+struct nfs41_exchange_id_data {
|
|
|
|
+ struct nfs41_exchange_id_res res;
|
|
|
|
+ struct nfs41_exchange_id_args args;
|
|
|
|
+ struct rpc_xprt *xprt;
|
|
|
|
+ int rpc_status;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static void nfs4_exchange_id_done(struct rpc_task *task, void *data)
|
|
|
|
+{
|
|
|
|
+ struct nfs41_exchange_id_data *cdata =
|
|
|
|
+ (struct nfs41_exchange_id_data *)data;
|
|
|
|
+ struct nfs_client *clp = cdata->args.client;
|
|
|
|
+ int status = task->tk_status;
|
|
|
|
+
|
|
|
|
+ trace_nfs4_exchange_id(clp, status);
|
|
|
|
+
|
|
|
|
+ if (status == 0)
|
|
|
|
+ status = nfs4_check_cl_exchange_flags(cdata->res.flags);
|
|
|
|
+
|
|
|
|
+ if (cdata->xprt && status == 0) {
|
|
|
|
+ status = nfs4_detect_session_trunking(clp, &cdata->res,
|
|
|
|
+ cdata->xprt);
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (status == 0)
|
|
|
|
+ status = nfs4_sp4_select_mode(clp, &cdata->res.state_protect);
|
|
|
|
+
|
|
|
|
+ if (status == 0) {
|
|
|
|
+ clp->cl_clientid = cdata->res.clientid;
|
|
|
|
+ clp->cl_exchange_flags = cdata->res.flags;
|
|
|
|
+ /* Client ID is not confirmed */
|
|
|
|
+ if (!(cdata->res.flags & EXCHGID4_FLAG_CONFIRMED_R)) {
|
|
|
|
+ clear_bit(NFS4_SESSION_ESTABLISHED,
|
|
|
|
+ &clp->cl_session->session_state);
|
|
|
|
+ clp->cl_seqid = cdata->res.seqid;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ kfree(clp->cl_serverowner);
|
|
|
|
+ clp->cl_serverowner = cdata->res.server_owner;
|
|
|
|
+ cdata->res.server_owner = NULL;
|
|
|
|
+
|
|
|
|
+ /* use the most recent implementation id */
|
|
|
|
+ kfree(clp->cl_implid);
|
|
|
|
+ clp->cl_implid = cdata->res.impl_id;
|
|
|
|
+ cdata->res.impl_id = NULL;
|
|
|
|
+
|
|
|
|
+ if (clp->cl_serverscope != NULL &&
|
|
|
|
+ !nfs41_same_server_scope(clp->cl_serverscope,
|
|
|
|
+ cdata->res.server_scope)) {
|
|
|
|
+ dprintk("%s: server_scope mismatch detected\n",
|
|
|
|
+ __func__);
|
|
|
|
+ set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state);
|
|
|
|
+ kfree(clp->cl_serverscope);
|
|
|
|
+ clp->cl_serverscope = NULL;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (clp->cl_serverscope == NULL) {
|
|
|
|
+ clp->cl_serverscope = cdata->res.server_scope;
|
|
|
|
+ cdata->res.server_scope = NULL;
|
|
|
|
+ }
|
|
|
|
+ /* Save the EXCHANGE_ID verifier session trunk tests */
|
|
|
|
+ memcpy(clp->cl_confirm.data, cdata->args.verifier->data,
|
|
|
|
+ sizeof(clp->cl_confirm.data));
|
|
|
|
+ }
|
|
|
|
+out:
|
|
|
|
+ cdata->rpc_status = status;
|
|
|
|
+ return;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void nfs4_exchange_id_release(void *data)
|
|
|
|
+{
|
|
|
|
+ struct nfs41_exchange_id_data *cdata =
|
|
|
|
+ (struct nfs41_exchange_id_data *)data;
|
|
|
|
+
|
|
|
|
+ nfs_put_client(cdata->args.client);
|
|
|
|
+ if (cdata->xprt) {
|
|
|
|
+ xprt_put(cdata->xprt);
|
|
|
|
+ rpc_clnt_xprt_switch_put(cdata->args.client->cl_rpcclient);
|
|
|
|
+ }
|
|
|
|
+ kfree(cdata->res.impl_id);
|
|
|
|
+ kfree(cdata->res.server_scope);
|
|
|
|
+ kfree(cdata->res.server_owner);
|
|
|
|
+ kfree(cdata);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static const struct rpc_call_ops nfs4_exchange_id_call_ops = {
|
|
|
|
+ .rpc_call_done = nfs4_exchange_id_done,
|
|
|
|
+ .rpc_release = nfs4_exchange_id_release,
|
|
|
|
+};
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* _nfs4_proc_exchange_id()
|
|
* _nfs4_proc_exchange_id()
|
|
*
|
|
*
|
|
* Wrapper for EXCHANGE_ID operation.
|
|
* Wrapper for EXCHANGE_ID operation.
|
|
*/
|
|
*/
|
|
static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
|
|
static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
|
|
- u32 sp4_how)
|
|
|
|
|
|
+ u32 sp4_how, struct rpc_xprt *xprt)
|
|
{
|
|
{
|
|
nfs4_verifier verifier;
|
|
nfs4_verifier verifier;
|
|
- struct nfs41_exchange_id_args args = {
|
|
|
|
- .verifier = &verifier,
|
|
|
|
- .client = clp,
|
|
|
|
-#ifdef CONFIG_NFS_V4_1_MIGRATION
|
|
|
|
- .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER |
|
|
|
|
- EXCHGID4_FLAG_BIND_PRINC_STATEID |
|
|
|
|
- EXCHGID4_FLAG_SUPP_MOVED_MIGR,
|
|
|
|
-#else
|
|
|
|
- .flags = EXCHGID4_FLAG_SUPP_MOVED_REFER |
|
|
|
|
- EXCHGID4_FLAG_BIND_PRINC_STATEID,
|
|
|
|
-#endif
|
|
|
|
- };
|
|
|
|
- struct nfs41_exchange_id_res res = {
|
|
|
|
- 0
|
|
|
|
- };
|
|
|
|
- int status;
|
|
|
|
struct rpc_message msg = {
|
|
struct rpc_message msg = {
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID],
|
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_EXCHANGE_ID],
|
|
- .rpc_argp = &args,
|
|
|
|
- .rpc_resp = &res,
|
|
|
|
.rpc_cred = cred,
|
|
.rpc_cred = cred,
|
|
};
|
|
};
|
|
|
|
+ struct rpc_task_setup task_setup_data = {
|
|
|
|
+ .rpc_client = clp->cl_rpcclient,
|
|
|
|
+ .callback_ops = &nfs4_exchange_id_call_ops,
|
|
|
|
+ .rpc_message = &msg,
|
|
|
|
+ .flags = RPC_TASK_ASYNC | RPC_TASK_TIMEOUT,
|
|
|
|
+ };
|
|
|
|
+ struct nfs41_exchange_id_data *calldata;
|
|
|
|
+ struct rpc_task *task;
|
|
|
|
+ int status = -EIO;
|
|
|
|
+
|
|
|
|
+ if (!atomic_inc_not_zero(&clp->cl_count))
|
|
|
|
+ goto out;
|
|
|
|
+
|
|
|
|
+ status = -ENOMEM;
|
|
|
|
+ calldata = kzalloc(sizeof(*calldata), GFP_NOFS);
|
|
|
|
+ if (!calldata)
|
|
|
|
+ goto out;
|
|
|
|
|
|
- nfs4_init_boot_verifier(clp, &verifier);
|
|
|
|
|
|
+ if (!xprt)
|
|
|
|
+ nfs4_init_boot_verifier(clp, &verifier);
|
|
|
|
|
|
status = nfs4_init_uniform_client_string(clp);
|
|
status = nfs4_init_uniform_client_string(clp);
|
|
if (status)
|
|
if (status)
|
|
- goto out;
|
|
|
|
|
|
+ goto out_calldata;
|
|
|
|
|
|
dprintk("NFS call exchange_id auth=%s, '%s'\n",
|
|
dprintk("NFS call exchange_id auth=%s, '%s'\n",
|
|
clp->cl_rpcclient->cl_auth->au_ops->au_name,
|
|
clp->cl_rpcclient->cl_auth->au_ops->au_name,
|
|
clp->cl_owner_id);
|
|
clp->cl_owner_id);
|
|
|
|
|
|
- res.server_owner = kzalloc(sizeof(struct nfs41_server_owner),
|
|
|
|
- GFP_NOFS);
|
|
|
|
- if (unlikely(res.server_owner == NULL)) {
|
|
|
|
- status = -ENOMEM;
|
|
|
|
- goto out;
|
|
|
|
- }
|
|
|
|
|
|
+ calldata->res.server_owner = kzalloc(sizeof(struct nfs41_server_owner),
|
|
|
|
+ GFP_NOFS);
|
|
|
|
+ status = -ENOMEM;
|
|
|
|
+ if (unlikely(calldata->res.server_owner == NULL))
|
|
|
|
+ goto out_calldata;
|
|
|
|
|
|
- res.server_scope = kzalloc(sizeof(struct nfs41_server_scope),
|
|
|
|
|
|
+ calldata->res.server_scope = kzalloc(sizeof(struct nfs41_server_scope),
|
|
GFP_NOFS);
|
|
GFP_NOFS);
|
|
- if (unlikely(res.server_scope == NULL)) {
|
|
|
|
- status = -ENOMEM;
|
|
|
|
|
|
+ if (unlikely(calldata->res.server_scope == NULL))
|
|
goto out_server_owner;
|
|
goto out_server_owner;
|
|
- }
|
|
|
|
|
|
|
|
- res.impl_id = kzalloc(sizeof(struct nfs41_impl_id), GFP_NOFS);
|
|
|
|
- if (unlikely(res.impl_id == NULL)) {
|
|
|
|
- status = -ENOMEM;
|
|
|
|
|
|
+ calldata->res.impl_id = kzalloc(sizeof(struct nfs41_impl_id), GFP_NOFS);
|
|
|
|
+ if (unlikely(calldata->res.impl_id == NULL))
|
|
goto out_server_scope;
|
|
goto out_server_scope;
|
|
- }
|
|
|
|
|
|
|
|
switch (sp4_how) {
|
|
switch (sp4_how) {
|
|
case SP4_NONE:
|
|
case SP4_NONE:
|
|
- args.state_protect.how = SP4_NONE;
|
|
|
|
|
|
+ calldata->args.state_protect.how = SP4_NONE;
|
|
break;
|
|
break;
|
|
|
|
|
|
case SP4_MACH_CRED:
|
|
case SP4_MACH_CRED:
|
|
- args.state_protect = nfs4_sp4_mach_cred_request;
|
|
|
|
|
|
+ calldata->args.state_protect = nfs4_sp4_mach_cred_request;
|
|
break;
|
|
break;
|
|
|
|
|
|
default:
|
|
default:
|
|
@@ -7181,56 +7503,42 @@ static int _nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred,
|
|
status = -EINVAL;
|
|
status = -EINVAL;
|
|
goto out_impl_id;
|
|
goto out_impl_id;
|
|
}
|
|
}
|
|
|
|
+ if (xprt) {
|
|
|
|
+ calldata->xprt = xprt;
|
|
|
|
+ task_setup_data.rpc_xprt = xprt;
|
|
|
|
+ task_setup_data.flags =
|
|
|
|
+ RPC_TASK_SOFT|RPC_TASK_SOFTCONN|RPC_TASK_ASYNC;
|
|
|
|
+ calldata->args.verifier = &clp->cl_confirm;
|
|
|
|
+ } else {
|
|
|
|
+ calldata->args.verifier = &verifier;
|
|
|
|
+ }
|
|
|
|
+ calldata->args.client = clp;
|
|
|
|
+#ifdef CONFIG_NFS_V4_1_MIGRATION
|
|
|
|
+ calldata->args.flags = EXCHGID4_FLAG_SUPP_MOVED_REFER |
|
|
|
|
+ EXCHGID4_FLAG_BIND_PRINC_STATEID |
|
|
|
|
+ EXCHGID4_FLAG_SUPP_MOVED_MIGR,
|
|
|
|
+#else
|
|
|
|
+ calldata->args.flags = EXCHGID4_FLAG_SUPP_MOVED_REFER |
|
|
|
|
+ EXCHGID4_FLAG_BIND_PRINC_STATEID,
|
|
|
|
+#endif
|
|
|
|
+ msg.rpc_argp = &calldata->args;
|
|
|
|
+ msg.rpc_resp = &calldata->res;
|
|
|
|
+ task_setup_data.callback_data = calldata;
|
|
|
|
|
|
- status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT);
|
|
|
|
- trace_nfs4_exchange_id(clp, status);
|
|
|
|
- if (status == 0)
|
|
|
|
- status = nfs4_check_cl_exchange_flags(res.flags);
|
|
|
|
-
|
|
|
|
- if (status == 0)
|
|
|
|
- status = nfs4_sp4_select_mode(clp, &res.state_protect);
|
|
|
|
-
|
|
|
|
- if (status == 0) {
|
|
|
|
- clp->cl_clientid = res.clientid;
|
|
|
|
- clp->cl_exchange_flags = res.flags;
|
|
|
|
- /* Client ID is not confirmed */
|
|
|
|
- if (!(res.flags & EXCHGID4_FLAG_CONFIRMED_R)) {
|
|
|
|
- clear_bit(NFS4_SESSION_ESTABLISHED,
|
|
|
|
- &clp->cl_session->session_state);
|
|
|
|
- clp->cl_seqid = res.seqid;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- kfree(clp->cl_serverowner);
|
|
|
|
- clp->cl_serverowner = res.server_owner;
|
|
|
|
- res.server_owner = NULL;
|
|
|
|
-
|
|
|
|
- /* use the most recent implementation id */
|
|
|
|
- kfree(clp->cl_implid);
|
|
|
|
- clp->cl_implid = res.impl_id;
|
|
|
|
- res.impl_id = NULL;
|
|
|
|
-
|
|
|
|
- if (clp->cl_serverscope != NULL &&
|
|
|
|
- !nfs41_same_server_scope(clp->cl_serverscope,
|
|
|
|
- res.server_scope)) {
|
|
|
|
- dprintk("%s: server_scope mismatch detected\n",
|
|
|
|
- __func__);
|
|
|
|
- set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state);
|
|
|
|
- kfree(clp->cl_serverscope);
|
|
|
|
- clp->cl_serverscope = NULL;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (clp->cl_serverscope == NULL) {
|
|
|
|
- clp->cl_serverscope = res.server_scope;
|
|
|
|
- res.server_scope = NULL;
|
|
|
|
- }
|
|
|
|
|
|
+ task = rpc_run_task(&task_setup_data);
|
|
|
|
+ if (IS_ERR(task)) {
|
|
|
|
+ status = PTR_ERR(task);
|
|
|
|
+ goto out_impl_id;
|
|
}
|
|
}
|
|
|
|
|
|
-out_impl_id:
|
|
|
|
- kfree(res.impl_id);
|
|
|
|
-out_server_scope:
|
|
|
|
- kfree(res.server_scope);
|
|
|
|
-out_server_owner:
|
|
|
|
- kfree(res.server_owner);
|
|
|
|
|
|
+ if (!xprt) {
|
|
|
|
+ status = rpc_wait_for_completion_task(task);
|
|
|
|
+ if (!status)
|
|
|
|
+ status = calldata->rpc_status;
|
|
|
|
+ } else /* session trunking test */
|
|
|
|
+ status = calldata->rpc_status;
|
|
|
|
+
|
|
|
|
+ rpc_put_task(task);
|
|
out:
|
|
out:
|
|
if (clp->cl_implid != NULL)
|
|
if (clp->cl_implid != NULL)
|
|
dprintk("NFS reply exchange_id: Server Implementation ID: "
|
|
dprintk("NFS reply exchange_id: Server Implementation ID: "
|
|
@@ -7240,6 +7548,16 @@ out:
|
|
clp->cl_implid->date.nseconds);
|
|
clp->cl_implid->date.nseconds);
|
|
dprintk("NFS reply exchange_id: %d\n", status);
|
|
dprintk("NFS reply exchange_id: %d\n", status);
|
|
return status;
|
|
return status;
|
|
|
|
+
|
|
|
|
+out_impl_id:
|
|
|
|
+ kfree(calldata->res.impl_id);
|
|
|
|
+out_server_scope:
|
|
|
|
+ kfree(calldata->res.server_scope);
|
|
|
|
+out_server_owner:
|
|
|
|
+ kfree(calldata->res.server_owner);
|
|
|
|
+out_calldata:
|
|
|
|
+ kfree(calldata);
|
|
|
|
+ goto out;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -7262,14 +7580,45 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred)
|
|
/* try SP4_MACH_CRED if krb5i/p */
|
|
/* try SP4_MACH_CRED if krb5i/p */
|
|
if (authflavor == RPC_AUTH_GSS_KRB5I ||
|
|
if (authflavor == RPC_AUTH_GSS_KRB5I ||
|
|
authflavor == RPC_AUTH_GSS_KRB5P) {
|
|
authflavor == RPC_AUTH_GSS_KRB5P) {
|
|
- status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED);
|
|
|
|
|
|
+ status = _nfs4_proc_exchange_id(clp, cred, SP4_MACH_CRED, NULL);
|
|
if (!status)
|
|
if (!status)
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
/* try SP4_NONE */
|
|
/* try SP4_NONE */
|
|
- return _nfs4_proc_exchange_id(clp, cred, SP4_NONE);
|
|
|
|
|
|
+ return _nfs4_proc_exchange_id(clp, cred, SP4_NONE, NULL);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+/**
|
|
|
|
+ * nfs4_test_session_trunk
|
|
|
|
+ *
|
|
|
|
+ * This is an add_xprt_test() test function called from
|
|
|
|
+ * rpc_clnt_setup_test_and_add_xprt.
|
|
|
|
+ *
|
|
|
|
+ * The rpc_xprt_switch is referrenced by rpc_clnt_setup_test_and_add_xprt
|
|
|
|
+ * and is dereferrenced in nfs4_exchange_id_release
|
|
|
|
+ *
|
|
|
|
+ * Upon success, add the new transport to the rpc_clnt
|
|
|
|
+ *
|
|
|
|
+ * @clnt: struct rpc_clnt to get new transport
|
|
|
|
+ * @xprt: the rpc_xprt to test
|
|
|
|
+ * @data: call data for _nfs4_proc_exchange_id.
|
|
|
|
+ */
|
|
|
|
+int nfs4_test_session_trunk(struct rpc_clnt *clnt, struct rpc_xprt *xprt,
|
|
|
|
+ void *data)
|
|
|
|
+{
|
|
|
|
+ struct nfs4_add_xprt_data *adata = (struct nfs4_add_xprt_data *)data;
|
|
|
|
+ u32 sp4_how;
|
|
|
|
+
|
|
|
|
+ dprintk("--> %s try %s\n", __func__,
|
|
|
|
+ xprt->address_strings[RPC_DISPLAY_ADDR]);
|
|
|
|
+
|
|
|
|
+ sp4_how = (adata->clp->cl_sp4_flags == 0 ? SP4_NONE : SP4_MACH_CRED);
|
|
|
|
+
|
|
|
|
+ /* Test connection for session trunking. Async exchange_id call */
|
|
|
|
+ return _nfs4_proc_exchange_id(adata->clp, adata->cred, sp4_how, xprt);
|
|
}
|
|
}
|
|
|
|
+EXPORT_SYMBOL_GPL(nfs4_test_session_trunk);
|
|
|
|
|
|
static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
|
|
static int _nfs4_proc_destroy_clientid(struct nfs_client *clp,
|
|
struct rpc_cred *cred)
|
|
struct rpc_cred *cred)
|
|
@@ -7463,7 +7812,7 @@ static void nfs4_init_channel_attrs(struct nfs41_create_session_args *args,
|
|
args->bc_attrs.max_resp_sz = max_bc_payload;
|
|
args->bc_attrs.max_resp_sz = max_bc_payload;
|
|
args->bc_attrs.max_resp_sz_cached = 0;
|
|
args->bc_attrs.max_resp_sz_cached = 0;
|
|
args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS;
|
|
args->bc_attrs.max_ops = NFS4_MAX_BACK_CHANNEL_OPS;
|
|
- args->bc_attrs.max_reqs = NFS41_BC_MAX_CALLBACKS;
|
|
|
|
|
|
+ args->bc_attrs.max_reqs = min_t(unsigned short, max_session_cb_slots, 1);
|
|
|
|
|
|
dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u "
|
|
dprintk("%s: Back Channel : max_rqst_sz=%u max_resp_sz=%u "
|
|
"max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n",
|
|
"max_resp_sz_cached=%u max_ops=%u max_reqs=%u\n",
|
|
@@ -7510,10 +7859,9 @@ static int nfs4_verify_back_channel_attrs(struct nfs41_create_session_args *args
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
|
|
if (rcvd->max_resp_sz_cached > sent->max_resp_sz_cached)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- /* These would render the backchannel useless: */
|
|
|
|
- if (rcvd->max_ops != sent->max_ops)
|
|
|
|
|
|
+ if (rcvd->max_ops > sent->max_ops)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
- if (rcvd->max_reqs != sent->max_reqs)
|
|
|
|
|
|
+ if (rcvd->max_reqs > sent->max_reqs)
|
|
return -EINVAL;
|
|
return -EINVAL;
|
|
out:
|
|
out:
|
|
return 0;
|
|
return 0;
|
|
@@ -7982,6 +8330,8 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
|
|
case -NFS4ERR_RECALLCONFLICT:
|
|
case -NFS4ERR_RECALLCONFLICT:
|
|
status = -ERECALLCONFLICT;
|
|
status = -ERECALLCONFLICT;
|
|
break;
|
|
break;
|
|
|
|
+ case -NFS4ERR_DELEG_REVOKED:
|
|
|
|
+ case -NFS4ERR_ADMIN_REVOKED:
|
|
case -NFS4ERR_EXPIRED:
|
|
case -NFS4ERR_EXPIRED:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
case -NFS4ERR_BAD_STATEID:
|
|
exception->timeout = 0;
|
|
exception->timeout = 0;
|
|
@@ -7993,6 +8343,7 @@ nfs4_layoutget_handle_exception(struct rpc_task *task,
|
|
&lgp->args.ctx->state->stateid)) {
|
|
&lgp->args.ctx->state->stateid)) {
|
|
spin_unlock(&inode->i_lock);
|
|
spin_unlock(&inode->i_lock);
|
|
exception->state = lgp->args.ctx->state;
|
|
exception->state = lgp->args.ctx->state;
|
|
|
|
+ exception->stateid = &lgp->args.stateid;
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -8591,6 +8942,24 @@ static int _nfs41_test_stateid(struct nfs_server *server,
|
|
return -res.status;
|
|
return -res.status;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void nfs4_handle_delay_or_session_error(struct nfs_server *server,
|
|
|
|
+ int err, struct nfs4_exception *exception)
|
|
|
|
+{
|
|
|
|
+ exception->retry = 0;
|
|
|
|
+ switch(err) {
|
|
|
|
+ case -NFS4ERR_DELAY:
|
|
|
|
+ case -NFS4ERR_RETRY_UNCACHED_REP:
|
|
|
|
+ nfs4_handle_exception(server, err, exception);
|
|
|
|
+ break;
|
|
|
|
+ case -NFS4ERR_BADSESSION:
|
|
|
|
+ case -NFS4ERR_BADSLOT:
|
|
|
|
+ case -NFS4ERR_BAD_HIGH_SLOT:
|
|
|
|
+ case -NFS4ERR_CONN_NOT_BOUND_TO_SESSION:
|
|
|
|
+ case -NFS4ERR_DEADSESSION:
|
|
|
|
+ nfs4_do_handle_exception(server, err, exception);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
/**
|
|
/**
|
|
* nfs41_test_stateid - perform a TEST_STATEID operation
|
|
* nfs41_test_stateid - perform a TEST_STATEID operation
|
|
*
|
|
*
|
|
@@ -8610,9 +8979,7 @@ static int nfs41_test_stateid(struct nfs_server *server,
|
|
int err;
|
|
int err;
|
|
do {
|
|
do {
|
|
err = _nfs41_test_stateid(server, stateid, cred);
|
|
err = _nfs41_test_stateid(server, stateid, cred);
|
|
- if (err != -NFS4ERR_DELAY)
|
|
|
|
- break;
|
|
|
|
- nfs4_handle_exception(server, err, &exception);
|
|
|
|
|
|
+ nfs4_handle_delay_or_session_error(server, err, &exception);
|
|
} while (exception.retry);
|
|
} while (exception.retry);
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
@@ -8657,7 +9024,7 @@ static const struct rpc_call_ops nfs41_free_stateid_ops = {
|
|
};
|
|
};
|
|
|
|
|
|
static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
|
|
static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
|
|
- nfs4_stateid *stateid,
|
|
|
|
|
|
+ const nfs4_stateid *stateid,
|
|
struct rpc_cred *cred,
|
|
struct rpc_cred *cred,
|
|
bool privileged)
|
|
bool privileged)
|
|
{
|
|
{
|
|
@@ -8687,7 +9054,7 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
|
|
|
|
|
|
msg.rpc_argp = &data->args;
|
|
msg.rpc_argp = &data->args;
|
|
msg.rpc_resp = &data->res;
|
|
msg.rpc_resp = &data->res;
|
|
- nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0);
|
|
|
|
|
|
+ nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1);
|
|
if (privileged)
|
|
if (privileged)
|
|
nfs4_set_sequence_privileged(&data->args.seq_args);
|
|
nfs4_set_sequence_privileged(&data->args.seq_args);
|
|
|
|
|
|
@@ -8700,38 +9067,31 @@ static struct rpc_task *_nfs41_free_stateid(struct nfs_server *server,
|
|
* @server: server / transport on which to perform the operation
|
|
* @server: server / transport on which to perform the operation
|
|
* @stateid: state ID to release
|
|
* @stateid: state ID to release
|
|
* @cred: credential
|
|
* @cred: credential
|
|
|
|
+ * @is_recovery: set to true if this call needs to be privileged
|
|
*
|
|
*
|
|
- * Returns NFS_OK if the server freed "stateid". Otherwise a
|
|
|
|
- * negative NFS4ERR value is returned.
|
|
|
|
|
|
+ * Note: this function is always asynchronous.
|
|
*/
|
|
*/
|
|
static int nfs41_free_stateid(struct nfs_server *server,
|
|
static int nfs41_free_stateid(struct nfs_server *server,
|
|
- nfs4_stateid *stateid,
|
|
|
|
- struct rpc_cred *cred)
|
|
|
|
|
|
+ const nfs4_stateid *stateid,
|
|
|
|
+ struct rpc_cred *cred,
|
|
|
|
+ bool is_recovery)
|
|
{
|
|
{
|
|
struct rpc_task *task;
|
|
struct rpc_task *task;
|
|
- int ret;
|
|
|
|
|
|
|
|
- task = _nfs41_free_stateid(server, stateid, cred, true);
|
|
|
|
|
|
+ task = _nfs41_free_stateid(server, stateid, cred, is_recovery);
|
|
if (IS_ERR(task))
|
|
if (IS_ERR(task))
|
|
return PTR_ERR(task);
|
|
return PTR_ERR(task);
|
|
- ret = rpc_wait_for_completion_task(task);
|
|
|
|
- if (!ret)
|
|
|
|
- ret = task->tk_status;
|
|
|
|
rpc_put_task(task);
|
|
rpc_put_task(task);
|
|
- return ret;
|
|
|
|
|
|
+ return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
static void
|
|
nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
|
|
nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp)
|
|
{
|
|
{
|
|
- struct rpc_task *task;
|
|
|
|
struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
|
|
struct rpc_cred *cred = lsp->ls_state->owner->so_cred;
|
|
|
|
|
|
- task = _nfs41_free_stateid(server, &lsp->ls_stateid, cred, false);
|
|
|
|
|
|
+ nfs41_free_stateid(server, &lsp->ls_stateid, cred, false);
|
|
nfs4_free_lock_state(server, lsp);
|
|
nfs4_free_lock_state(server, lsp);
|
|
- if (IS_ERR(task))
|
|
|
|
- return;
|
|
|
|
- rpc_put_task(task);
|
|
|
|
}
|
|
}
|
|
|
|
|
|
static bool nfs41_match_stateid(const nfs4_stateid *s1,
|
|
static bool nfs41_match_stateid(const nfs4_stateid *s1,
|
|
@@ -8835,6 +9195,7 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = {
|
|
.match_stateid = nfs4_match_stateid,
|
|
.match_stateid = nfs4_match_stateid,
|
|
.find_root_sec = nfs4_find_root_sec,
|
|
.find_root_sec = nfs4_find_root_sec,
|
|
.free_lock_state = nfs4_release_lockowner,
|
|
.free_lock_state = nfs4_release_lockowner,
|
|
|
|
+ .test_and_free_expired = nfs40_test_and_free_expired_stateid,
|
|
.alloc_seqid = nfs_alloc_seqid,
|
|
.alloc_seqid = nfs_alloc_seqid,
|
|
.call_sync_ops = &nfs40_call_sync_ops,
|
|
.call_sync_ops = &nfs40_call_sync_ops,
|
|
.reboot_recovery_ops = &nfs40_reboot_recovery_ops,
|
|
.reboot_recovery_ops = &nfs40_reboot_recovery_ops,
|
|
@@ -8862,7 +9223,9 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = {
|
|
.match_stateid = nfs41_match_stateid,
|
|
.match_stateid = nfs41_match_stateid,
|
|
.find_root_sec = nfs41_find_root_sec,
|
|
.find_root_sec = nfs41_find_root_sec,
|
|
.free_lock_state = nfs41_free_lock_state,
|
|
.free_lock_state = nfs41_free_lock_state,
|
|
|
|
+ .test_and_free_expired = nfs41_test_and_free_expired_stateid,
|
|
.alloc_seqid = nfs_alloc_no_seqid,
|
|
.alloc_seqid = nfs_alloc_no_seqid,
|
|
|
|
+ .session_trunk = nfs4_test_session_trunk,
|
|
.call_sync_ops = &nfs41_call_sync_ops,
|
|
.call_sync_ops = &nfs41_call_sync_ops,
|
|
.reboot_recovery_ops = &nfs41_reboot_recovery_ops,
|
|
.reboot_recovery_ops = &nfs41_reboot_recovery_ops,
|
|
.nograce_recovery_ops = &nfs41_nograce_recovery_ops,
|
|
.nograce_recovery_ops = &nfs41_nograce_recovery_ops,
|
|
@@ -8891,7 +9254,9 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
|
|
.find_root_sec = nfs41_find_root_sec,
|
|
.find_root_sec = nfs41_find_root_sec,
|
|
.free_lock_state = nfs41_free_lock_state,
|
|
.free_lock_state = nfs41_free_lock_state,
|
|
.call_sync_ops = &nfs41_call_sync_ops,
|
|
.call_sync_ops = &nfs41_call_sync_ops,
|
|
|
|
+ .test_and_free_expired = nfs41_test_and_free_expired_stateid,
|
|
.alloc_seqid = nfs_alloc_no_seqid,
|
|
.alloc_seqid = nfs_alloc_no_seqid,
|
|
|
|
+ .session_trunk = nfs4_test_session_trunk,
|
|
.reboot_recovery_ops = &nfs41_reboot_recovery_ops,
|
|
.reboot_recovery_ops = &nfs41_reboot_recovery_ops,
|
|
.nograce_recovery_ops = &nfs41_nograce_recovery_ops,
|
|
.nograce_recovery_ops = &nfs41_nograce_recovery_ops,
|
|
.state_renewal_ops = &nfs41_state_renewal_ops,
|
|
.state_renewal_ops = &nfs41_state_renewal_ops,
|