|
@@ -1068,6 +1068,7 @@ static void nfs4_opendata_free(struct kref *kref)
|
|
|
dput(p->dentry);
|
|
|
nfs_sb_deactive(sb);
|
|
|
nfs_fattr_free_names(&p->f_attr);
|
|
|
+ kfree(p->f_attr.mdsthreshold);
|
|
|
kfree(p);
|
|
|
}
|
|
|
|
|
@@ -1137,12 +1138,71 @@ static void update_open_stateflags(struct nfs4_state *state, fmode_t fmode)
|
|
|
nfs4_state_set_mode_locked(state, state->state | fmode);
|
|
|
}
|
|
|
|
|
|
-static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
|
|
|
+static void nfs_test_and_clear_all_open_stateid(struct nfs4_state *state)
|
|
|
+{
|
|
|
+ struct nfs_client *clp = state->owner->so_server->nfs_client;
|
|
|
+ bool need_recover = false;
|
|
|
+
|
|
|
+ if (test_and_clear_bit(NFS_O_RDONLY_STATE, &state->flags) && state->n_rdonly)
|
|
|
+ need_recover = true;
|
|
|
+ if (test_and_clear_bit(NFS_O_WRONLY_STATE, &state->flags) && state->n_wronly)
|
|
|
+ need_recover = true;
|
|
|
+ if (test_and_clear_bit(NFS_O_RDWR_STATE, &state->flags) && state->n_rdwr)
|
|
|
+ need_recover = true;
|
|
|
+ if (need_recover)
|
|
|
+ nfs4_state_mark_reclaim_nograce(clp, state);
|
|
|
+}
|
|
|
+
|
|
|
+static bool nfs_need_update_open_stateid(struct nfs4_state *state,
|
|
|
+ nfs4_stateid *stateid)
|
|
|
+{
|
|
|
+ if (test_and_set_bit(NFS_OPEN_STATE, &state->flags) == 0)
|
|
|
+ return true;
|
|
|
+ if (!nfs4_stateid_match_other(stateid, &state->open_stateid)) {
|
|
|
+ nfs_test_and_clear_all_open_stateid(state);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ if (nfs4_stateid_is_newer(stateid, &state->open_stateid))
|
|
|
+ return true;
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static void nfs_clear_open_stateid_locked(struct nfs4_state *state,
|
|
|
+ nfs4_stateid *stateid, fmode_t fmode)
|
|
|
{
|
|
|
+ clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
|
+ switch (fmode & (FMODE_READ|FMODE_WRITE)) {
|
|
|
+ case FMODE_WRITE:
|
|
|
+ clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
|
+ break;
|
|
|
+ case FMODE_READ:
|
|
|
+ clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
|
+ break;
|
|
|
+ case 0:
|
|
|
+ clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
|
+ clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
|
+ clear_bit(NFS_OPEN_STATE, &state->flags);
|
|
|
+ }
|
|
|
+ if (stateid == NULL)
|
|
|
+ return;
|
|
|
+ if (!nfs_need_update_open_stateid(state, stateid))
|
|
|
+ return;
|
|
|
if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
|
|
|
nfs4_stateid_copy(&state->stateid, stateid);
|
|
|
nfs4_stateid_copy(&state->open_stateid, stateid);
|
|
|
- set_bit(NFS_OPEN_STATE, &state->flags);
|
|
|
+}
|
|
|
+
|
|
|
+static void nfs_clear_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
|
|
|
+{
|
|
|
+ write_seqlock(&state->seqlock);
|
|
|
+ nfs_clear_open_stateid_locked(state, stateid, fmode);
|
|
|
+ write_sequnlock(&state->seqlock);
|
|
|
+ if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
|
|
|
+ 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)
|
|
|
+{
|
|
|
switch (fmode) {
|
|
|
case FMODE_READ:
|
|
|
set_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
@@ -1153,13 +1213,11 @@ static void nfs_set_open_stateid_locked(struct nfs4_state *state, nfs4_stateid *
|
|
|
case FMODE_READ|FMODE_WRITE:
|
|
|
set_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
|
}
|
|
|
-}
|
|
|
-
|
|
|
-static void nfs_set_open_stateid(struct nfs4_state *state, nfs4_stateid *stateid, fmode_t fmode)
|
|
|
-{
|
|
|
- write_seqlock(&state->seqlock);
|
|
|
- nfs_set_open_stateid_locked(state, stateid, fmode);
|
|
|
- write_sequnlock(&state->seqlock);
|
|
|
+ if (!nfs_need_update_open_stateid(state, stateid))
|
|
|
+ return;
|
|
|
+ if (test_bit(NFS_DELEGATED_STATE, &state->flags) == 0)
|
|
|
+ nfs4_stateid_copy(&state->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)
|
|
@@ -1217,6 +1275,8 @@ no_delegation:
|
|
|
__update_open_stateid(state, open_stateid, NULL, fmode);
|
|
|
ret = 1;
|
|
|
}
|
|
|
+ if (test_bit(NFS_STATE_RECLAIM_NOGRACE, &state->flags))
|
|
|
+ nfs4_schedule_state_manager(state->owner->so_server->nfs_client);
|
|
|
|
|
|
return ret;
|
|
|
}
|
|
@@ -1450,12 +1510,15 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
|
|
|
struct nfs4_state *newstate;
|
|
|
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();
|
|
|
if (state->n_rdwr != 0) {
|
|
|
- clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
|
ret = nfs4_open_recover_helper(opendata, FMODE_READ|FMODE_WRITE, &newstate);
|
|
|
if (ret != 0)
|
|
|
return ret;
|
|
@@ -1463,7 +1526,6 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
|
|
|
return -ESTALE;
|
|
|
}
|
|
|
if (state->n_wronly != 0) {
|
|
|
- clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
|
ret = nfs4_open_recover_helper(opendata, FMODE_WRITE, &newstate);
|
|
|
if (ret != 0)
|
|
|
return ret;
|
|
@@ -1471,7 +1533,6 @@ static int nfs4_open_recover(struct nfs4_opendata *opendata, struct nfs4_state *
|
|
|
return -ESTALE;
|
|
|
}
|
|
|
if (state->n_rdonly != 0) {
|
|
|
- clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
|
ret = nfs4_open_recover_helper(opendata, FMODE_READ, &newstate);
|
|
|
if (ret != 0)
|
|
|
return ret;
|
|
@@ -2244,10 +2305,12 @@ static int _nfs4_do_open(struct inode *dir,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- if (ctx_th && server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
|
|
|
- opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
|
|
|
- if (!opendata->f_attr.mdsthreshold)
|
|
|
- goto err_free_label;
|
|
|
+ if (server->attr_bitmask[2] & FATTR4_WORD2_MDSTHRESHOLD) {
|
|
|
+ if (!opendata->f_attr.mdsthreshold) {
|
|
|
+ opendata->f_attr.mdsthreshold = pnfs_mdsthreshold_alloc();
|
|
|
+ if (!opendata->f_attr.mdsthreshold)
|
|
|
+ goto err_free_label;
|
|
|
+ }
|
|
|
opendata->o_arg.open_bitmap = &nfs4_pnfs_open_bitmap[0];
|
|
|
}
|
|
|
if (dentry->d_inode != NULL)
|
|
@@ -2275,11 +2338,10 @@ static int _nfs4_do_open(struct inode *dir,
|
|
|
if (opendata->file_created)
|
|
|
*opened |= FILE_CREATED;
|
|
|
|
|
|
- if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server))
|
|
|
+ if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) {
|
|
|
*ctx_th = opendata->f_attr.mdsthreshold;
|
|
|
- else
|
|
|
- kfree(opendata->f_attr.mdsthreshold);
|
|
|
- opendata->f_attr.mdsthreshold = NULL;
|
|
|
+ opendata->f_attr.mdsthreshold = NULL;
|
|
|
+ }
|
|
|
|
|
|
nfs4_label_free(olabel);
|
|
|
|
|
@@ -2289,7 +2351,6 @@ static int _nfs4_do_open(struct inode *dir,
|
|
|
err_free_label:
|
|
|
nfs4_label_free(olabel);
|
|
|
err_opendata_put:
|
|
|
- kfree(opendata->f_attr.mdsthreshold);
|
|
|
nfs4_opendata_put(opendata);
|
|
|
err_put_state_owner:
|
|
|
nfs4_put_state_owner(sp);
|
|
@@ -2479,26 +2540,6 @@ static void nfs4_free_closedata(void *data)
|
|
|
kfree(calldata);
|
|
|
}
|
|
|
|
|
|
-static void nfs4_close_clear_stateid_flags(struct nfs4_state *state,
|
|
|
- fmode_t fmode)
|
|
|
-{
|
|
|
- spin_lock(&state->owner->so_lock);
|
|
|
- clear_bit(NFS_O_RDWR_STATE, &state->flags);
|
|
|
- switch (fmode & (FMODE_READ|FMODE_WRITE)) {
|
|
|
- case FMODE_WRITE:
|
|
|
- clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
|
- break;
|
|
|
- case FMODE_READ:
|
|
|
- clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
|
- break;
|
|
|
- case 0:
|
|
|
- clear_bit(NFS_O_RDONLY_STATE, &state->flags);
|
|
|
- clear_bit(NFS_O_WRONLY_STATE, &state->flags);
|
|
|
- clear_bit(NFS_OPEN_STATE, &state->flags);
|
|
|
- }
|
|
|
- spin_unlock(&state->owner->so_lock);
|
|
|
-}
|
|
|
-
|
|
|
static void nfs4_close_done(struct rpc_task *task, void *data)
|
|
|
{
|
|
|
struct nfs4_closedata *calldata = data;
|
|
@@ -2517,9 +2558,9 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
|
|
|
if (calldata->roc)
|
|
|
pnfs_roc_set_barrier(state->inode,
|
|
|
calldata->roc_barrier);
|
|
|
- nfs_set_open_stateid(state, &calldata->res.stateid, 0);
|
|
|
+ nfs_clear_open_stateid(state, &calldata->res.stateid, 0);
|
|
|
renew_lease(server, calldata->timestamp);
|
|
|
- break;
|
|
|
+ goto out_release;
|
|
|
case -NFS4ERR_ADMIN_REVOKED:
|
|
|
case -NFS4ERR_STALE_STATEID:
|
|
|
case -NFS4ERR_OLD_STATEID:
|
|
@@ -2533,7 +2574,7 @@ static void nfs4_close_done(struct rpc_task *task, void *data)
|
|
|
goto out_release;
|
|
|
}
|
|
|
}
|
|
|
- nfs4_close_clear_stateid_flags(state, calldata->arg.fmode);
|
|
|
+ nfs_clear_open_stateid(state, NULL, calldata->arg.fmode);
|
|
|
out_release:
|
|
|
nfs_release_seqid(calldata->arg.seqid);
|
|
|
nfs_refresh_inode(calldata->inode, calldata->res.fattr);
|
|
@@ -3507,49 +3548,6 @@ static int nfs4_proc_rename_done(struct rpc_task *task, struct inode *old_dir,
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
-static int _nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
|
|
|
- struct inode *new_dir, struct qstr *new_name)
|
|
|
-{
|
|
|
- struct nfs_server *server = NFS_SERVER(old_dir);
|
|
|
- struct nfs_renameargs arg = {
|
|
|
- .old_dir = NFS_FH(old_dir),
|
|
|
- .new_dir = NFS_FH(new_dir),
|
|
|
- .old_name = old_name,
|
|
|
- .new_name = new_name,
|
|
|
- };
|
|
|
- struct nfs_renameres res = {
|
|
|
- .server = server,
|
|
|
- };
|
|
|
- struct rpc_message msg = {
|
|
|
- .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RENAME],
|
|
|
- .rpc_argp = &arg,
|
|
|
- .rpc_resp = &res,
|
|
|
- };
|
|
|
- int status = -ENOMEM;
|
|
|
-
|
|
|
- status = nfs4_call_sync(server->client, server, &msg, &arg.seq_args, &res.seq_res, 1);
|
|
|
- if (!status) {
|
|
|
- update_changeattr(old_dir, &res.old_cinfo);
|
|
|
- update_changeattr(new_dir, &res.new_cinfo);
|
|
|
- }
|
|
|
- return status;
|
|
|
-}
|
|
|
-
|
|
|
-static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name,
|
|
|
- struct inode *new_dir, struct qstr *new_name)
|
|
|
-{
|
|
|
- struct nfs4_exception exception = { };
|
|
|
- int err;
|
|
|
- do {
|
|
|
- err = _nfs4_proc_rename(old_dir, old_name,
|
|
|
- new_dir, new_name);
|
|
|
- trace_nfs4_rename(old_dir, old_name, new_dir, new_name, err);
|
|
|
- err = nfs4_handle_exception(NFS_SERVER(old_dir), err,
|
|
|
- &exception);
|
|
|
- } while (exception.retry);
|
|
|
- return err;
|
|
|
-}
|
|
|
-
|
|
|
static int _nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name)
|
|
|
{
|
|
|
struct nfs_server *server = NFS_SERVER(inode);
|
|
@@ -4884,6 +4882,20 @@ nfs4_init_uniform_client_string(const struct nfs_client *clp,
|
|
|
nodename);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * nfs4_callback_up_net() starts only "tcp" and "tcp6" callback
|
|
|
+ * services. Advertise one based on the address family of the
|
|
|
+ * clientaddr.
|
|
|
+ */
|
|
|
+static unsigned int
|
|
|
+nfs4_init_callback_netid(const struct nfs_client *clp, char *buf, size_t len)
|
|
|
+{
|
|
|
+ if (strchr(clp->cl_ipaddr, ':') != NULL)
|
|
|
+ return scnprintf(buf, len, "tcp6");
|
|
|
+ else
|
|
|
+ return scnprintf(buf, len, "tcp");
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* nfs4_proc_setclientid - Negotiate client ID
|
|
|
* @clp: state data structure
|
|
@@ -4925,12 +4937,10 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program,
|
|
|
setclientid.sc_name,
|
|
|
sizeof(setclientid.sc_name));
|
|
|
/* cb_client4 */
|
|
|
- rcu_read_lock();
|
|
|
- setclientid.sc_netid_len = scnprintf(setclientid.sc_netid,
|
|
|
- sizeof(setclientid.sc_netid), "%s",
|
|
|
- rpc_peeraddr2str(clp->cl_rpcclient,
|
|
|
- RPC_DISPLAY_NETID));
|
|
|
- rcu_read_unlock();
|
|
|
+ setclientid.sc_netid_len =
|
|
|
+ nfs4_init_callback_netid(clp,
|
|
|
+ setclientid.sc_netid,
|
|
|
+ sizeof(setclientid.sc_netid));
|
|
|
setclientid.sc_uaddr_len = scnprintf(setclientid.sc_uaddr,
|
|
|
sizeof(setclientid.sc_uaddr), "%s.%u.%u",
|
|
|
clp->cl_ipaddr, port >> 8, port & 255);
|
|
@@ -8408,7 +8418,6 @@ const struct nfs_rpc_ops nfs_v4_clientops = {
|
|
|
.unlink_setup = nfs4_proc_unlink_setup,
|
|
|
.unlink_rpc_prepare = nfs4_proc_unlink_rpc_prepare,
|
|
|
.unlink_done = nfs4_proc_unlink_done,
|
|
|
- .rename = nfs4_proc_rename,
|
|
|
.rename_setup = nfs4_proc_rename_setup,
|
|
|
.rename_rpc_prepare = nfs4_proc_rename_rpc_prepare,
|
|
|
.rename_done = nfs4_proc_rename_done,
|