Skip to content

Commit 0e65a32

Browse files
olgakorn1Olga Kornievskaia
authored and
Olga Kornievskaia
committed
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 <[email protected]>
1 parent fefa1a8 commit 0e65a32

File tree

5 files changed

+75
-27
lines changed

5 files changed

+75
-27
lines changed

fs/nfs/nfs42proc.c

+47-21
Original file line numberDiff line numberDiff line change
@@ -153,22 +153,26 @@ int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
153153
}
154154

155155
static int handle_async_copy(struct nfs42_copy_res *res,
156-
struct nfs_server *server,
156+
struct nfs_server *dst_server,
157+
struct nfs_server *src_server,
157158
struct file *src,
158159
struct file *dst,
159-
nfs4_stateid *src_stateid)
160+
nfs4_stateid *src_stateid,
161+
bool *restart)
160162
{
161163
struct nfs4_copy_state *copy, *tmp_copy;
162164
int status = NFS4_OK;
163165
bool found_pending = false;
164-
struct nfs_open_context *ctx = nfs_file_open_context(dst);
166+
struct nfs_open_context *dst_ctx = nfs_file_open_context(dst);
167+
struct nfs_open_context *src_ctx = nfs_file_open_context(src);
165168

166169
copy = kzalloc(sizeof(struct nfs4_copy_state), GFP_NOFS);
167170
if (!copy)
168171
return -ENOMEM;
169172

170-
spin_lock(&server->nfs_client->cl_lock);
171-
list_for_each_entry(tmp_copy, &server->nfs_client->pending_cb_stateids,
173+
spin_lock(&dst_server->nfs_client->cl_lock);
174+
list_for_each_entry(tmp_copy,
175+
&dst_server->nfs_client->pending_cb_stateids,
172176
copies) {
173177
if (memcmp(&res->write_res.stateid, &tmp_copy->stateid,
174178
NFS4_STATEID_SIZE))
@@ -178,27 +182,40 @@ static int handle_async_copy(struct nfs42_copy_res *res,
178182
break;
179183
}
180184
if (found_pending) {
181-
spin_unlock(&server->nfs_client->cl_lock);
185+
spin_unlock(&dst_server->nfs_client->cl_lock);
182186
kfree(copy);
183187
copy = tmp_copy;
184188
goto out;
185189
}
186190

187191
memcpy(&copy->stateid, &res->write_res.stateid, NFS4_STATEID_SIZE);
188192
init_completion(&copy->completion);
189-
copy->parent_state = ctx->state;
193+
copy->parent_dst_state = dst_ctx->state;
194+
copy->parent_src_state = src_ctx->state;
195+
196+
list_add_tail(&copy->copies, &dst_server->ss_copies);
197+
spin_unlock(&dst_server->nfs_client->cl_lock);
190198

191-
list_add_tail(&copy->copies, &server->ss_copies);
192-
spin_unlock(&server->nfs_client->cl_lock);
199+
if (dst_server != src_server) {
200+
spin_lock(&src_server->nfs_client->cl_lock);
201+
list_add_tail(&copy->src_copies, &src_server->ss_copies);
202+
spin_unlock(&src_server->nfs_client->cl_lock);
203+
}
193204

194205
status = wait_for_completion_interruptible(&copy->completion);
195-
spin_lock(&server->nfs_client->cl_lock);
206+
spin_lock(&dst_server->nfs_client->cl_lock);
196207
list_del_init(&copy->copies);
197-
spin_unlock(&server->nfs_client->cl_lock);
208+
spin_unlock(&dst_server->nfs_client->cl_lock);
209+
if (dst_server != src_server) {
210+
spin_lock(&src_server->nfs_client->cl_lock);
211+
list_del_init(&copy->src_copies);
212+
spin_unlock(&src_server->nfs_client->cl_lock);
213+
}
198214
if (status == -ERESTARTSYS) {
199215
goto out_cancel;
200-
} else if (copy->flags) {
216+
} else if (copy->flags || copy->error == NFS4ERR_PARTNER_NO_AUTH) {
201217
status = -EAGAIN;
218+
*restart = true;
202219
goto out_cancel;
203220
}
204221
out:
@@ -247,15 +264,18 @@ static ssize_t _nfs42_proc_copy(struct file *src,
247264
struct nfs42_copy_args *args,
248265
struct nfs42_copy_res *res,
249266
struct nl4_server *nss,
250-
nfs4_stateid *cnr_stateid)
267+
nfs4_stateid *cnr_stateid,
268+
bool *restart)
251269
{
252270
struct rpc_message msg = {
253271
.rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_COPY],
254272
.rpc_argp = args,
255273
.rpc_resp = res,
256274
};
257275
struct inode *dst_inode = file_inode(dst);
258-
struct nfs_server *server = NFS_SERVER(dst_inode);
276+
struct inode *src_inode = file_inode(src);
277+
struct nfs_server *dst_server = NFS_SERVER(dst_inode);
278+
struct nfs_server *src_server = NFS_SERVER(src_inode);
259279
loff_t pos_src = args->src_pos;
260280
loff_t pos_dst = args->dst_pos;
261281
size_t count = args->count;
@@ -291,13 +311,15 @@ static ssize_t _nfs42_proc_copy(struct file *src,
291311
if (!res->commit_res.verf)
292312
return -ENOMEM;
293313
}
314+
set_bit(NFS_CLNT_SRC_SSC_COPY_STATE,
315+
&src_lock->open_context->state->flags);
294316
set_bit(NFS_CLNT_DST_SSC_COPY_STATE,
295317
&dst_lock->open_context->state->flags);
296318

297-
status = nfs4_call_sync(server->client, server, &msg,
319+
status = nfs4_call_sync(dst_server->client, dst_server, &msg,
298320
&args->seq_args, &res->seq_res, 0);
299321
if (status == -ENOTSUPP)
300-
server->caps &= ~NFS_CAP_COPY;
322+
dst_server->caps &= ~NFS_CAP_COPY;
301323
if (status)
302324
goto out;
303325

@@ -309,8 +331,8 @@ static ssize_t _nfs42_proc_copy(struct file *src,
309331
}
310332

311333
if (!res->synchronous) {
312-
status = handle_async_copy(res, server, src, dst,
313-
&args->src_stateid);
334+
status = handle_async_copy(res, dst_server, src_server, src,
335+
dst, &args->src_stateid, restart);
314336
if (status)
315337
return status;
316338
}
@@ -358,6 +380,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
358380
.stateid = &args.dst_stateid,
359381
};
360382
ssize_t err, err2;
383+
bool restart = false;
361384

362385
src_lock = nfs_get_lock_context(nfs_file_open_context(src));
363386
if (IS_ERR(src_lock))
@@ -378,7 +401,7 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
378401
err = _nfs42_proc_copy(src, src_lock,
379402
dst, dst_lock,
380403
&args, &res,
381-
nss, cnr_stateid);
404+
nss, cnr_stateid, &restart);
382405
inode_unlock(file_inode(dst));
383406

384407
if (err >= 0)
@@ -388,8 +411,11 @@ ssize_t nfs42_proc_copy(struct file *src, loff_t pos_src,
388411
err = -EOPNOTSUPP;
389412
break;
390413
} else if (err == -EAGAIN) {
391-
dst_exception.retry = 1;
392-
continue;
414+
if (!restart) {
415+
dst_exception.retry = 1;
416+
continue;
417+
}
418+
break;
393419
} else if (err == -NFS4ERR_OFFLOAD_NO_REQS && !args.sync) {
394420
args.sync = true;
395421
dst_exception.retry = 1;

fs/nfs/nfs4_fs.h

+1
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ enum {
168168
NFS_STATE_CHANGE_WAIT, /* A state changing operation is outstanding */
169169
#ifdef CONFIG_NFS_V4_2
170170
NFS_CLNT_DST_SSC_COPY_STATE, /* dst server open state on client*/
171+
NFS_CLNT_SRC_SSC_COPY_STATE, /* src server open state on client*/
171172
NFS_SRV_SSC_COPY_STATE, /* ssc state on the dst server */
172173
#endif /* CONFIG_NFS_V4_2 */
173174
};

fs/nfs/nfs4file.c

+3
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
146146
return -EOPNOTSUPP;
147147
if (file_inode(file_in) == file_inode(file_out))
148148
return -EOPNOTSUPP;
149+
retry:
149150
if (!nfs42_files_from_same_server(file_in, file_out)) {
150151
cn_resp = kzalloc(sizeof(struct nfs42_copy_notify_res),
151152
GFP_NOFS);
@@ -164,6 +165,8 @@ static ssize_t __nfs4_copy_file_range(struct file *file_in, loff_t pos_in,
164165
nss, cnrs);
165166
out:
166167
kfree(cn_resp);
168+
if (ret == -EAGAIN)
169+
goto retry;
167170
return ret;
168171
}
169172

fs/nfs/nfs4state.c

+21-5
Original file line numberDiff line numberDiff line change
@@ -1556,16 +1556,32 @@ static void nfs42_complete_copies(struct nfs4_state_owner *sp, struct nfs4_state
15561556
{
15571557
struct nfs4_copy_state *copy;
15581558

1559-
if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags))
1559+
if (!test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
1560+
!test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags))
15601561
return;
15611562

15621563
spin_lock(&sp->so_server->nfs_client->cl_lock);
15631564
list_for_each_entry(copy, &sp->so_server->ss_copies, copies) {
1564-
if (!nfs4_stateid_match_other(&state->stateid, &copy->parent_state->stateid))
1565-
continue;
1565+
if ((test_bit(NFS_CLNT_DST_SSC_COPY_STATE, &state->flags) &&
1566+
!nfs4_stateid_match_other(&state->stateid,
1567+
&copy->parent_dst_state->stateid)))
1568+
continue;
15661569
copy->flags = 1;
1567-
complete(&copy->completion);
1568-
break;
1570+
if (test_and_clear_bit(NFS_CLNT_DST_SSC_COPY_STATE,
1571+
&state->flags)) {
1572+
clear_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags);
1573+
complete(&copy->completion);
1574+
}
1575+
}
1576+
list_for_each_entry(copy, &sp->so_server->ss_copies, src_copies) {
1577+
if ((test_bit(NFS_CLNT_SRC_SSC_COPY_STATE, &state->flags) &&
1578+
!nfs4_stateid_match_other(&state->stateid,
1579+
&copy->parent_src_state->stateid)))
1580+
continue;
1581+
copy->flags = 1;
1582+
if (test_and_clear_bit(NFS_CLNT_DST_SSC_COPY_STATE,
1583+
&state->flags))
1584+
complete(&copy->completion);
15691585
}
15701586
spin_unlock(&sp->so_server->nfs_client->cl_lock);
15711587
}

include/linux/nfs_fs.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -189,13 +189,15 @@ struct nfs_inode {
189189

190190
struct nfs4_copy_state {
191191
struct list_head copies;
192+
struct list_head src_copies;
192193
nfs4_stateid stateid;
193194
struct completion completion;
194195
uint64_t count;
195196
struct nfs_writeverf verf;
196197
int error;
197198
int flags;
198-
struct nfs4_state *parent_state;
199+
struct nfs4_state *parent_src_state;
200+
struct nfs4_state *parent_dst_state;
199201
};
200202

201203
/*

0 commit comments

Comments
 (0)