mirror of
https://github.com/torvalds/linux.git
synced 2026-05-31 10:33:41 +02:00
NFSv4: Don't free slots prematurely if requesting a directory delegation
When requesting a directory delegation, it is imperative to hold the
slot until the delegation state has been recorded. Otherwise, if a
recall comes in, the call to referring_call_exists() will assume the
processing is done, and when it doesn't find a delegation, it will
assume it has been returned.
Fixes: 156b094829 ("NFS: Request a directory delegation on ACCESS, CREATE, and UNLINK")
Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com>
This commit is contained in:
parent
105c2db247
commit
3f77eda548
|
|
@ -4494,6 +4494,25 @@ static bool should_request_dir_deleg(struct inode *inode)
|
|||
}
|
||||
#endif /* CONFIG_NFS_V4_1 */
|
||||
|
||||
static void nfs4_call_getattr_prepare(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs4_call_sync_data *data = calldata;
|
||||
nfs4_setup_sequence(data->seq_server->nfs_client, data->seq_args,
|
||||
data->seq_res, task);
|
||||
}
|
||||
|
||||
static void nfs4_call_getattr_done(struct rpc_task *task, void *calldata)
|
||||
{
|
||||
struct nfs4_call_sync_data *data = calldata;
|
||||
|
||||
nfs4_sequence_process(task, data->seq_res);
|
||||
}
|
||||
|
||||
static const struct rpc_call_ops nfs4_call_getattr_ops = {
|
||||
.rpc_call_prepare = nfs4_call_getattr_prepare,
|
||||
.rpc_call_done = nfs4_call_getattr_done,
|
||||
};
|
||||
|
||||
static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
|
||||
struct nfs_fattr *fattr, struct inode *inode)
|
||||
{
|
||||
|
|
@ -4511,16 +4530,26 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
|
|||
.rpc_argp = &args,
|
||||
.rpc_resp = &res,
|
||||
};
|
||||
struct nfs4_call_sync_data data = {
|
||||
.seq_server = server,
|
||||
.seq_args = &args.seq_args,
|
||||
.seq_res = &res.seq_res,
|
||||
};
|
||||
struct rpc_task_setup task_setup = {
|
||||
.rpc_client = server->client,
|
||||
.rpc_message = &msg,
|
||||
.callback_ops = &nfs4_call_getattr_ops,
|
||||
.callback_data = &data,
|
||||
};
|
||||
struct nfs4_gdd_res gdd_res;
|
||||
unsigned short task_flags = 0;
|
||||
int status;
|
||||
|
||||
if (nfs4_has_session(server->nfs_client))
|
||||
task_flags = RPC_TASK_MOVEABLE;
|
||||
task_setup.flags = RPC_TASK_MOVEABLE;
|
||||
|
||||
/* Is this is an attribute revalidation, subject to softreval? */
|
||||
if (inode && (server->flags & NFS_MOUNT_SOFTREVAL))
|
||||
task_flags |= RPC_TASK_TIMEOUT;
|
||||
task_setup.flags |= RPC_TASK_TIMEOUT;
|
||||
|
||||
args.get_dir_deleg = should_request_dir_deleg(inode);
|
||||
if (args.get_dir_deleg)
|
||||
|
|
@ -4530,22 +4559,24 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
|
|||
nfs_fattr_init(fattr);
|
||||
nfs4_init_sequence(&args.seq_args, &res.seq_res, 0, 0);
|
||||
|
||||
status = nfs4_do_call_sync(server->client, server, &msg,
|
||||
&args.seq_args, &res.seq_res, task_flags);
|
||||
status = nfs4_call_sync_custom(&task_setup);
|
||||
|
||||
if (args.get_dir_deleg) {
|
||||
switch (status) {
|
||||
case 0:
|
||||
if (gdd_res.status != GDD4_OK)
|
||||
break;
|
||||
status = nfs_inode_set_delegation(
|
||||
inode, current_cred(), FMODE_READ,
|
||||
&gdd_res.deleg, 0, NFS4_OPEN_DELEGATE_READ);
|
||||
nfs_inode_set_delegation(inode, current_cred(),
|
||||
FMODE_READ, &gdd_res.deleg, 0,
|
||||
NFS4_OPEN_DELEGATE_READ);
|
||||
break;
|
||||
case -ENOTSUPP:
|
||||
case -EOPNOTSUPP:
|
||||
server->caps &= ~NFS_CAP_DIR_DELEG;
|
||||
}
|
||||
}
|
||||
|
||||
nfs4_sequence_free_slot(&res.seq_res);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user