mirror of
https://github.com/torvalds/linux.git
synced 2024-11-22 12:11:40 +00:00
NFS: handle source server reboot
When the source server reboots after a server-to-server copy was issued, we need to retry the copy from COPY_NOTIFY. We need to detect that the source server rebooted and there is a copy waiting on a destination server and wake it up. Signed-off-by: Olga Kornievskaia <kolga@netapp.com>
This commit is contained in:
parent
fefa1a812a
commit
0e65a32c8a
@ -153,22 +153,26 @@ out_unlock:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int handle_async_copy(struct nfs42_copy_res *res,
|
static int handle_async_copy(struct nfs42_copy_res *res,
|
||||||
struct nfs_server *server,
|
struct nfs_server *dst_server,
|
||||||
|
struct nfs_server *src_server,
|
||||||
struct file *src,
|
struct file *src,
|
||||||
struct file *dst,
|
struct file *dst,
|
||||||
nfs4_stateid *src_stateid)
|
nfs4_stateid *src_stateid,
|
||||||
|
bool *restart)
|
||||||
{
|
{
|
||||||
struct nfs4_copy_state *copy, *tmp_copy;
|
struct nfs4_copy_state *copy, *tmp_copy;
|
||||||
int status = NFS4_OK;
|
int status = NFS4_OK;
|
||||||
bool found_pending = false;
|
bool found_pending = false;
|
||||||
struct nfs_open_context *ctx = nfs_file_open_context(dst);
|
struct nfs_open_context *dst_ctx = nfs_file_open_context(dst);
|
||||||
|
struct nfs_open_context *src_ctx = nfs_file_open_context(src);
|
||||||
|
|
||||||
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
|
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
|
||||||
if (!copy)
|
if (!copy)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
spin_lock(&server->nfs_client->cl_lock);
|
spin_lock(&dst_server->nfs_client->cl_lock);
|
||||||
list_for_each_entry(tmp_copy, &server->nfs_client->pending_cb_stateids,
|
list_for_each_entry(tmp_copy,
|
||||||
|
&dst_server->nfs_client->pending_cb_stateids,
|
||||||
copies) {
|
copies) {
|
||||||
if (memcmp(&res->write_res.stateid, &tmp_copy->stateid,
|
if (memcmp(&res->write_res.stateid, &tmp_copy->stateid,
|
||||||
NFS4_STATEID_SIZE))
|
NFS4_STATEID_SIZE))
|
||||||
@ -178,7 +182,7 @@ static int handle_async_copy(struct nfs42_copy_res *res,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (found_pending) {
|
if (found_pending) {
|
||||||
spin_unlock(&server->nfs_client->cl_lock);
|
spin_unlock(&dst_server->nfs_client->cl_lock);
|
||||||
kfree(copy);
|
kfree(copy);
|
||||||
copy = tmp_copy;
|
copy = tmp_copy;
|
||||||
goto out;
|
goto out;
|
||||||
@ -186,19 +190,32 @@ static int handle_async_copy(struct nfs42_copy_res *res,
|
|||||||
|
|
||||||
memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
|
memcpy(©->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
|
||||||
init_completion(©->completion);
|
init_completion(©->completion);
|
||||||
copy->parent_state = ctx->state;
|
copy->parent_dst_state = dst_ctx->state;
|
||||||
|
copy->parent_src_state = src_ctx->state;
|
||||||
|
|
||||||
list_add_tail(©->copies, &server->ss_copies);
|
list_add_tail(©->copies, &dst_server->ss_copies);
|
||||||
spin_unlock(&server->nfs_client->cl_lock);
|
spin_unlock(&dst_server->nfs_client->cl_lock);
|
||||||
|
|
||||||
|
if (dst_server != src_server) {
|
||||||
|
spin_lock(&src_server->nfs_client->cl_lock);
|
||||||
|
list_add_tail(©->src_copies, &src_server->ss_copies);
|
||||||
|
spin_unlock(&src_server->nfs_client->cl_lock);
|
||||||
|
}
|
||||||
|
|
||||||
status = wait_for_completion_interruptible(©->completion);
|
status = wait_for_completion_interruptible(©->completion);
|
||||||
spin_lock(&server->nfs_client->cl_lock);
|
spin_lock(&dst_server->nfs_client->cl_lock);
|
||||||
list_del_init(©->copies);
|
list_del_init(©->copies);
|
||||||
spin_unlock(&server->nfs_client->cl_lock);
|
spin_unlock(&dst_server->nfs_client->cl_lock);
|
||||||
|
if (dst_server != src_server) {
|
||||||
|
spin_lock(&src_server->nfs_client->cl_lock);
|
||||||
|
list_del_init(©->src_copies);
|
||||||
|
spin_unlock(&src_server->nfs_client->cl_lock);
|
||||||
|
}
|
||||||
if (status == -ERESTARTSYS) {
|
if (status == -ERESTARTSYS) {
|
||||||
goto out_cancel;
|
goto out_cancel;
|
||||||
} else if (copy->flags) {
|
} else if (copy->flags || copy->error == NFS4ERR_PARTNER_NO_AUTH) {
|
||||||
status = -EAGAIN;
|
status = -EAGAIN;
|
||||||
|
*restart = true;
|
||||||
goto out_cancel;
|
goto out_cancel;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
@ -247,7 +264,8 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
|||||||
struct nfs42_copy_args *args,
|
struct nfs42_copy_args *args,
|
||||||
struct nfs42_copy_res *res,
|
struct nfs42_copy_res *res,
|
||||||
struct nl4_server *nss,
|
struct nl4_server *nss,
|
||||||
nfs4_stateid *cnr_stateid)
|
nfs4_stateid *cnr_stateid,
|
||||||
|
bool *restart)
|
||||||
{
|
{
|
||||||
struct rpc_message msg = {
|
struct rpc_message msg = {
|
||||||
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
|
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
|
||||||
@ -255,7 +273,9 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
|||||||
.rpc_resp = res,
|
.rpc_resp = res,
|
||||||
};
|
};
|
||||||
struct inode *dst_inode = file_inode(dst);
|
struct inode *dst_inode = file_inode(dst);
|
||||||
struct nfs_server *server = NFS_SERVER(dst_inode);
|
struct inode *src_inode = file_inode(src);
|
||||||
|
struct nfs_server *dst_server = NFS_SERVER(dst_inode);
|
||||||
|
struct nfs_server *src_server = NFS_SERVER(src_inode);
|
||||||
loff_t pos_src = args->src_pos;
|
loff_t pos_src = args->src_pos;
|
||||||
loff_t pos_dst = args->dst_pos;
|
loff_t pos_dst = args->dst_pos;
|
||||||
size_t count = args->count;
|
size_t count = args->count;
|
||||||
@ -291,13 +311,15 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
|||||||
if (!res->commit_res.verf)
|
if (!res->commit_res.verf)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
set_bit(NFS_CLNT_SRC_SSC_COPY_STATE,
|
||||||
|
&src_lock->open_context->state->flags);
|
||||||
set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
|
set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
|
||||||
&dst_lock->open_context->state->flags);
|
&dst_lock->open_context->state->flags);
|
||||||
|
|
||||||
status = nfs4_call_sync(server->client, server, &msg,
|
status = nfs4_call_sync(dst_server->client, dst_server, &msg,
|
||||||
&args->seq_args, &res->seq_res, 0);
|
&args->seq_args, &res->seq_res, 0);
|
||||||
if (status == -ENOTSUPP)
|
if (status == -ENOTSUPP)
|
||||||
server->caps &= ~NFS_CAP_COPY;
|
dst_server->caps &= ~NFS_CAP_COPY;
|
||||||
if (status)
|
if (status)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
@ -309,8 +331,8 @@ static ssize_t _nfs42_proc_copy(struct file *src,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!res->synchronous) {
|
if (!res->synchronous) {
|
||||||
status = handle_async_copy(res, server, src, dst,
|
status = handle_async_copy(res, dst_server, src_server, src,
|
||||||
&args->src_stateid);
|
dst, &args->src_stateid, restart);
|
||||||
if (status)
|
if (status)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
@ -358,6 +380,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
|
|||||||
.stateid = &args.dst_stateid,
|
.stateid = &args.dst_stateid,
|
||||||
};
|
};
|
||||||
ssize_t err, err2;
|
ssize_t err, err2;
|
||||||
|
bool restart = false;
|
||||||
|
|
||||||
src_lock = nfs_get_lock_context(nfs_file_open_context(src));
|
src_lock = nfs_get_lock_context(nfs_file_open_context(src));
|
||||||
if (IS_ERR(src_lock))
|
if (IS_ERR(src_lock))
|
||||||
@ -378,7 +401,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
|
|||||||
err = _nfs42_proc_copy(src, src_lock,
|
err = _nfs42_proc_copy(src, src_lock,
|
||||||
dst, dst_lock,
|
dst, dst_lock,
|
||||||
&args, &res,
|
&args, &res,
|
||||||
nss, cnr_stateid);
|
nss, cnr_stateid, &restart);
|
||||||
inode_unlock(file_inode(dst));
|
inode_unlock(file_inode(dst));
|
||||||
|
|
||||||
if (err >= 0)
|
if (err >= 0)
|
||||||
@ -388,8 +411,11 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
|
|||||||
err = -EOPNOTSUPP;
|
err = -EOPNOTSUPP;
|
||||||
break;
|
break;
|
||||||
} else if (err == -EAGAIN) {
|
} else if (err == -EAGAIN) {
|
||||||
|
if (!restart) {
|
||||||
dst_exception.retry = 1;
|
dst_exception.retry = 1;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
} else if (err == -NFS4ERR_OFFLOAD_NO_REQS && !args.sync) {
|
} else if (err == -NFS4ERR_OFFLOAD_NO_REQS && !args.sync) {
|
||||||
args.sync = true;
|
args.sync = true;
|
||||||
dst_exception.retry = 1;
|
dst_exception.retry = 1;
|
||||||
|
@ -168,6 +168,7 @@ enum {
|
|||||||
NFS_STATE_CHANGE_WAIT, /* A state changing operation is outstanding */
|
NFS_STATE_CHANGE_WAIT, /* A state changing operation is outstanding */
|
||||||
#ifdef CONFIG_NFS_V4_2
|
#ifdef CONFIG_NFS_V4_2
|
||||||
NFS_CLNT_DST_SSC_COPY_STATE, /* dst server open state on client*/
|
NFS_CLNT_DST_SSC_COPY_STATE, /* dst server open state on client*/
|
||||||
|
NFS_CLNT_SRC_SSC_COPY_STATE, /* src server open state on client*/
|
||||||
NFS_SRV_SSC_COPY_STATE, /* ssc state on the dst server */
|
NFS_SRV_SSC_COPY_STATE, /* ssc state on the dst server */
|
||||||
#endif /* CONFIG_NFS_V4_2 */
|
#endif /* CONFIG_NFS_V4_2 */
|
||||||
};
|
};
|
||||||
|
@ -146,6 +146,7 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
if (file_inode(file_in) == file_inode(file_out))
|
if (file_inode(file_in) == file_inode(file_out))
|
||||||
return -EOPNOTSUPP;
|
return -EOPNOTSUPP;
|
||||||
|
retry:
|
||||||
if (!nfs42_files_from_same_server(file_in, file_out)) {
|
if (!nfs42_files_from_same_server(file_in, file_out)) {
|
||||||
cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
|
cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
|
||||||
GFP_NOFS);
|
GFP_NOFS);
|
||||||
@ -164,6 +165,8 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
|
|||||||
nss, cnrs);
|
nss, cnrs);
|
||||||
out:
|
out:
|
||||||
kfree(cn_resp);
|
kfree(cn_resp);
|
||||||
|
if (ret == -EAGAIN)
|
||||||
|
goto retry;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1556,16 +1556,32 @@ static void nfs42_complete_copies(struct nfs4_state_owner *sp, struct nfs4_state
|
|||||||
{
|
{
|
||||||
struct nfs4_copy_state *copy;
|
struct nfs4_copy_state *copy;
|
||||||
|
|
||||||
if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags))
|
if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
|
||||||
|
!test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
spin_lock(&sp->so_server->nfs_client->cl_lock);
|
spin_lock(&sp->so_server->nfs_client->cl_lock);
|
||||||
list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
|
list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
|
||||||
if (!nfs4_stateid_match_other(&state->stateid, ©->parent_state->stateid))
|
if ((test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
|
||||||
|
!nfs4_stateid_match_other(&state->stateid,
|
||||||
|
©->parent_dst_state->stateid)))
|
||||||
continue;
|
continue;
|
||||||
copy->flags = 1;
|
copy->flags = 1;
|
||||||
|
if (test_and_clear_bit(NFS_CLNT_DST_SSC_COPY_STATE,
|
||||||
|
&state->flags)) {
|
||||||
|
clear_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags);
|
||||||
|
complete(©->completion);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list_for_each_entry(copy, &sp->so_server->ss_copies, src_copies) {
|
||||||
|
if ((test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags) &&
|
||||||
|
!nfs4_stateid_match_other(&state->stateid,
|
||||||
|
©->parent_src_state->stateid)))
|
||||||
|
continue;
|
||||||
|
copy->flags = 1;
|
||||||
|
if (test_and_clear_bit(NFS_CLNT_DST_SSC_COPY_STATE,
|
||||||
|
&state->flags))
|
||||||
complete(©->completion);
|
complete(©->completion);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
spin_unlock(&sp->so_server->nfs_client->cl_lock);
|
spin_unlock(&sp->so_server->nfs_client->cl_lock);
|
||||||
}
|
}
|
||||||
|
@ -189,13 +189,15 @@ struct nfs_inode {
|
|||||||
|
|
||||||
struct nfs4_copy_state {
|
struct nfs4_copy_state {
|
||||||
struct list_head copies;
|
struct list_head copies;
|
||||||
|
struct list_head src_copies;
|
||||||
nfs4_stateid stateid;
|
nfs4_stateid stateid;
|
||||||
struct completion completion;
|
struct completion completion;
|
||||||
uint64_t count;
|
uint64_t count;
|
||||||
struct nfs_writeverf verf;
|
struct nfs_writeverf verf;
|
||||||
int error;
|
int error;
|
||||||
int flags;
|
int flags;
|
||||||
struct nfs4_state *parent_state;
|
struct nfs4_state *parent_src_state;
|
||||||
|
struct nfs4_state *parent_dst_state;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user