diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-13 20:13:19 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-13 20:13:19 -0400 |
commit | 06b8ab55289345ab191bf4bf0e4acc6d4bdf293d (patch) | |
tree | 9af9215097e26c026f30a58c6ca3092ec15d1e1e /fs/nfs/filelayout | |
parent | dc1cc85133120e49c223f36aa77d398b8abac727 (diff) | |
parent | 71a6ec8ac587418ceb6b420def1ca44b334c1ff7 (diff) |
Merge tag 'nfs-for-3.17-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
Pull NFS client updates from Trond Myklebust:
"Highlights include:
- stable fix for a bug in nfs3_list_one_acl()
- speed up NFS path walks by supporting LOOKUP_RCU
- more read/write code cleanups
- pNFS fixes for layout return on close
- fixes for the RCU handling in the rpcsec_gss code
- more NFS/RDMA fixes"
* tag 'nfs-for-3.17-1' of git://git.linux-nfs.org/projects/trondmy/linux-nfs: (79 commits)
nfs: reject changes to resvport and sharecache during remount
NFS: Avoid infinite loop when RELEASE_LOCKOWNER getting expired error
SUNRPC: remove all refcounting of groupinfo from rpcauth_lookupcred
NFS: fix two problems in lookup_revalidate in RCU-walk
NFS: allow lockless access to access_cache
NFS: teach nfs_lookup_verify_inode to handle LOOKUP_RCU
NFS: teach nfs_neg_need_reval to understand LOOKUP_RCU
NFS: support RCU_WALK in nfs_permission()
sunrpc/auth: allow lockless (rcu) lookup of credential cache.
NFS: prepare for RCU-walk support but pushing tests later in code.
NFS: nfs4_lookup_revalidate: only evaluate parent if it will be used.
NFS: add checks for returned value of try_module_get()
nfs: clear_request_commit while holding i_lock
pnfs: add pnfs_put_lseg_async
pnfs: find swapped pages on pnfs commit lists too
nfs: fix comment and add warn_on for PG_INODE_REF
nfs: check wait_on_bit_lock err in page_group_lock
sunrpc: remove "ec" argument from encrypt_v2 operation
sunrpc: clean up sparse endianness warnings in gss_krb5_wrap.c
sunrpc: clean up sparse endianness warnings in gss_krb5_seal.c
...
Diffstat (limited to 'fs/nfs/filelayout')
-rw-r--r-- | fs/nfs/filelayout/filelayout.c | 298 | ||||
-rw-r--r-- | fs/nfs/filelayout/filelayoutdev.c | 2 |
2 files changed, 168 insertions, 132 deletions
diff --git a/fs/nfs/filelayout/filelayout.c b/fs/nfs/filelayout/filelayout.c index d2eba1c13b7e..1359c4a27393 100644 --- a/fs/nfs/filelayout/filelayout.c +++ b/fs/nfs/filelayout/filelayout.c | |||
@@ -84,45 +84,37 @@ filelayout_get_dserver_offset(struct pnfs_layout_segment *lseg, loff_t offset) | |||
84 | BUG(); | 84 | BUG(); |
85 | } | 85 | } |
86 | 86 | ||
87 | static void filelayout_reset_write(struct nfs_pgio_data *data) | 87 | static void filelayout_reset_write(struct nfs_pgio_header *hdr) |
88 | { | 88 | { |
89 | struct nfs_pgio_header *hdr = data->header; | 89 | struct rpc_task *task = &hdr->task; |
90 | struct rpc_task *task = &data->task; | ||
91 | 90 | ||
92 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { | 91 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { |
93 | dprintk("%s Reset task %5u for i/o through MDS " | 92 | dprintk("%s Reset task %5u for i/o through MDS " |
94 | "(req %s/%llu, %u bytes @ offset %llu)\n", __func__, | 93 | "(req %s/%llu, %u bytes @ offset %llu)\n", __func__, |
95 | data->task.tk_pid, | 94 | hdr->task.tk_pid, |
96 | hdr->inode->i_sb->s_id, | 95 | hdr->inode->i_sb->s_id, |
97 | (unsigned long long)NFS_FILEID(hdr->inode), | 96 | (unsigned long long)NFS_FILEID(hdr->inode), |
98 | data->args.count, | 97 | hdr->args.count, |
99 | (unsigned long long)data->args.offset); | 98 | (unsigned long long)hdr->args.offset); |
100 | 99 | ||
101 | task->tk_status = pnfs_write_done_resend_to_mds(hdr->inode, | 100 | task->tk_status = pnfs_write_done_resend_to_mds(hdr); |
102 | &hdr->pages, | ||
103 | hdr->completion_ops, | ||
104 | hdr->dreq); | ||
105 | } | 101 | } |
106 | } | 102 | } |
107 | 103 | ||
108 | static void filelayout_reset_read(struct nfs_pgio_data *data) | 104 | static void filelayout_reset_read(struct nfs_pgio_header *hdr) |
109 | { | 105 | { |
110 | struct nfs_pgio_header *hdr = data->header; | 106 | struct rpc_task *task = &hdr->task; |
111 | struct rpc_task *task = &data->task; | ||
112 | 107 | ||
113 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { | 108 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { |
114 | dprintk("%s Reset task %5u for i/o through MDS " | 109 | dprintk("%s Reset task %5u for i/o through MDS " |
115 | "(req %s/%llu, %u bytes @ offset %llu)\n", __func__, | 110 | "(req %s/%llu, %u bytes @ offset %llu)\n", __func__, |
116 | data->task.tk_pid, | 111 | hdr->task.tk_pid, |
117 | hdr->inode->i_sb->s_id, | 112 | hdr->inode->i_sb->s_id, |
118 | (unsigned long long)NFS_FILEID(hdr->inode), | 113 | (unsigned long long)NFS_FILEID(hdr->inode), |
119 | data->args.count, | 114 | hdr->args.count, |
120 | (unsigned long long)data->args.offset); | 115 | (unsigned long long)hdr->args.offset); |
121 | 116 | ||
122 | task->tk_status = pnfs_read_done_resend_to_mds(hdr->inode, | 117 | task->tk_status = pnfs_read_done_resend_to_mds(hdr); |
123 | &hdr->pages, | ||
124 | hdr->completion_ops, | ||
125 | hdr->dreq); | ||
126 | } | 118 | } |
127 | } | 119 | } |
128 | 120 | ||
@@ -243,18 +235,17 @@ wait_on_recovery: | |||
243 | /* NFS_PROTO call done callback routines */ | 235 | /* NFS_PROTO call done callback routines */ |
244 | 236 | ||
245 | static int filelayout_read_done_cb(struct rpc_task *task, | 237 | static int filelayout_read_done_cb(struct rpc_task *task, |
246 | struct nfs_pgio_data *data) | 238 | struct nfs_pgio_header *hdr) |
247 | { | 239 | { |
248 | struct nfs_pgio_header *hdr = data->header; | ||
249 | int err; | 240 | int err; |
250 | 241 | ||
251 | trace_nfs4_pnfs_read(data, task->tk_status); | 242 | trace_nfs4_pnfs_read(hdr, task->tk_status); |
252 | err = filelayout_async_handle_error(task, data->args.context->state, | 243 | err = filelayout_async_handle_error(task, hdr->args.context->state, |
253 | data->ds_clp, hdr->lseg); | 244 | hdr->ds_clp, hdr->lseg); |
254 | 245 | ||
255 | switch (err) { | 246 | switch (err) { |
256 | case -NFS4ERR_RESET_TO_MDS: | 247 | case -NFS4ERR_RESET_TO_MDS: |
257 | filelayout_reset_read(data); | 248 | filelayout_reset_read(hdr); |
258 | return task->tk_status; | 249 | return task->tk_status; |
259 | case -EAGAIN: | 250 | case -EAGAIN: |
260 | rpc_restart_call_prepare(task); | 251 | rpc_restart_call_prepare(task); |
@@ -270,15 +261,14 @@ static int filelayout_read_done_cb(struct rpc_task *task, | |||
270 | * rfc5661 is not clear about which credential should be used. | 261 | * rfc5661 is not clear about which credential should be used. |
271 | */ | 262 | */ |
272 | static void | 263 | static void |
273 | filelayout_set_layoutcommit(struct nfs_pgio_data *wdata) | 264 | filelayout_set_layoutcommit(struct nfs_pgio_header *hdr) |
274 | { | 265 | { |
275 | struct nfs_pgio_header *hdr = wdata->header; | ||
276 | 266 | ||
277 | if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds || | 267 | if (FILELAYOUT_LSEG(hdr->lseg)->commit_through_mds || |
278 | wdata->res.verf->committed == NFS_FILE_SYNC) | 268 | hdr->res.verf->committed == NFS_FILE_SYNC) |
279 | return; | 269 | return; |
280 | 270 | ||
281 | pnfs_set_layoutcommit(wdata); | 271 | pnfs_set_layoutcommit(hdr); |
282 | dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino, | 272 | dprintk("%s inode %lu pls_end_pos %lu\n", __func__, hdr->inode->i_ino, |
283 | (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb); | 273 | (unsigned long) NFS_I(hdr->inode)->layout->plh_lwb); |
284 | } | 274 | } |
@@ -305,83 +295,82 @@ filelayout_reset_to_mds(struct pnfs_layout_segment *lseg) | |||
305 | */ | 295 | */ |
306 | static void filelayout_read_prepare(struct rpc_task *task, void *data) | 296 | static void filelayout_read_prepare(struct rpc_task *task, void *data) |
307 | { | 297 | { |
308 | struct nfs_pgio_data *rdata = data; | 298 | struct nfs_pgio_header *hdr = data; |
309 | 299 | ||
310 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &rdata->args.context->flags))) { | 300 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) { |
311 | rpc_exit(task, -EIO); | 301 | rpc_exit(task, -EIO); |
312 | return; | 302 | return; |
313 | } | 303 | } |
314 | if (filelayout_reset_to_mds(rdata->header->lseg)) { | 304 | if (filelayout_reset_to_mds(hdr->lseg)) { |
315 | dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid); | 305 | dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid); |
316 | filelayout_reset_read(rdata); | 306 | filelayout_reset_read(hdr); |
317 | rpc_exit(task, 0); | 307 | rpc_exit(task, 0); |
318 | return; | 308 | return; |
319 | } | 309 | } |
320 | rdata->pgio_done_cb = filelayout_read_done_cb; | 310 | hdr->pgio_done_cb = filelayout_read_done_cb; |
321 | 311 | ||
322 | if (nfs41_setup_sequence(rdata->ds_clp->cl_session, | 312 | if (nfs41_setup_sequence(hdr->ds_clp->cl_session, |
323 | &rdata->args.seq_args, | 313 | &hdr->args.seq_args, |
324 | &rdata->res.seq_res, | 314 | &hdr->res.seq_res, |
325 | task)) | 315 | task)) |
326 | return; | 316 | return; |
327 | if (nfs4_set_rw_stateid(&rdata->args.stateid, rdata->args.context, | 317 | if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, |
328 | rdata->args.lock_context, FMODE_READ) == -EIO) | 318 | hdr->args.lock_context, FMODE_READ) == -EIO) |
329 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ | 319 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ |
330 | } | 320 | } |
331 | 321 | ||
332 | static void filelayout_read_call_done(struct rpc_task *task, void *data) | 322 | static void filelayout_read_call_done(struct rpc_task *task, void *data) |
333 | { | 323 | { |
334 | struct nfs_pgio_data *rdata = data; | 324 | struct nfs_pgio_header *hdr = data; |
335 | 325 | ||
336 | dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); | 326 | dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status); |
337 | 327 | ||
338 | if (test_bit(NFS_IOHDR_REDO, &rdata->header->flags) && | 328 | if (test_bit(NFS_IOHDR_REDO, &hdr->flags) && |
339 | task->tk_status == 0) { | 329 | task->tk_status == 0) { |
340 | nfs41_sequence_done(task, &rdata->res.seq_res); | 330 | nfs41_sequence_done(task, &hdr->res.seq_res); |
341 | return; | 331 | return; |
342 | } | 332 | } |
343 | 333 | ||
344 | /* Note this may cause RPC to be resent */ | 334 | /* Note this may cause RPC to be resent */ |
345 | rdata->header->mds_ops->rpc_call_done(task, data); | 335 | hdr->mds_ops->rpc_call_done(task, data); |
346 | } | 336 | } |
347 | 337 | ||
348 | static void filelayout_read_count_stats(struct rpc_task *task, void *data) | 338 | static void filelayout_read_count_stats(struct rpc_task *task, void *data) |
349 | { | 339 | { |
350 | struct nfs_pgio_data *rdata = data; | 340 | struct nfs_pgio_header *hdr = data; |
351 | 341 | ||
352 | rpc_count_iostats(task, NFS_SERVER(rdata->header->inode)->client->cl_metrics); | 342 | rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics); |
353 | } | 343 | } |
354 | 344 | ||
355 | static void filelayout_read_release(void *data) | 345 | static void filelayout_read_release(void *data) |
356 | { | 346 | { |
357 | struct nfs_pgio_data *rdata = data; | 347 | struct nfs_pgio_header *hdr = data; |
358 | struct pnfs_layout_hdr *lo = rdata->header->lseg->pls_layout; | 348 | struct pnfs_layout_hdr *lo = hdr->lseg->pls_layout; |
359 | 349 | ||
360 | filelayout_fenceme(lo->plh_inode, lo); | 350 | filelayout_fenceme(lo->plh_inode, lo); |
361 | nfs_put_client(rdata->ds_clp); | 351 | nfs_put_client(hdr->ds_clp); |
362 | rdata->header->mds_ops->rpc_release(data); | 352 | hdr->mds_ops->rpc_release(data); |
363 | } | 353 | } |
364 | 354 | ||
365 | static int filelayout_write_done_cb(struct rpc_task *task, | 355 | static int filelayout_write_done_cb(struct rpc_task *task, |
366 | struct nfs_pgio_data *data) | 356 | struct nfs_pgio_header *hdr) |
367 | { | 357 | { |
368 | struct nfs_pgio_header *hdr = data->header; | ||
369 | int err; | 358 | int err; |
370 | 359 | ||
371 | trace_nfs4_pnfs_write(data, task->tk_status); | 360 | trace_nfs4_pnfs_write(hdr, task->tk_status); |
372 | err = filelayout_async_handle_error(task, data->args.context->state, | 361 | err = filelayout_async_handle_error(task, hdr->args.context->state, |
373 | data->ds_clp, hdr->lseg); | 362 | hdr->ds_clp, hdr->lseg); |
374 | 363 | ||
375 | switch (err) { | 364 | switch (err) { |
376 | case -NFS4ERR_RESET_TO_MDS: | 365 | case -NFS4ERR_RESET_TO_MDS: |
377 | filelayout_reset_write(data); | 366 | filelayout_reset_write(hdr); |
378 | return task->tk_status; | 367 | return task->tk_status; |
379 | case -EAGAIN: | 368 | case -EAGAIN: |
380 | rpc_restart_call_prepare(task); | 369 | rpc_restart_call_prepare(task); |
381 | return -EAGAIN; | 370 | return -EAGAIN; |
382 | } | 371 | } |
383 | 372 | ||
384 | filelayout_set_layoutcommit(data); | 373 | filelayout_set_layoutcommit(hdr); |
385 | return 0; | 374 | return 0; |
386 | } | 375 | } |
387 | 376 | ||
@@ -419,57 +408,57 @@ static int filelayout_commit_done_cb(struct rpc_task *task, | |||
419 | 408 | ||
420 | static void filelayout_write_prepare(struct rpc_task *task, void *data) | 409 | static void filelayout_write_prepare(struct rpc_task *task, void *data) |
421 | { | 410 | { |
422 | struct nfs_pgio_data *wdata = data; | 411 | struct nfs_pgio_header *hdr = data; |
423 | 412 | ||
424 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &wdata->args.context->flags))) { | 413 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) { |
425 | rpc_exit(task, -EIO); | 414 | rpc_exit(task, -EIO); |
426 | return; | 415 | return; |
427 | } | 416 | } |
428 | if (filelayout_reset_to_mds(wdata->header->lseg)) { | 417 | if (filelayout_reset_to_mds(hdr->lseg)) { |
429 | dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid); | 418 | dprintk("%s task %u reset io to MDS\n", __func__, task->tk_pid); |
430 | filelayout_reset_write(wdata); | 419 | filelayout_reset_write(hdr); |
431 | rpc_exit(task, 0); | 420 | rpc_exit(task, 0); |
432 | return; | 421 | return; |
433 | } | 422 | } |
434 | if (nfs41_setup_sequence(wdata->ds_clp->cl_session, | 423 | if (nfs41_setup_sequence(hdr->ds_clp->cl_session, |
435 | &wdata->args.seq_args, | 424 | &hdr->args.seq_args, |
436 | &wdata->res.seq_res, | 425 | &hdr->res.seq_res, |
437 | task)) | 426 | task)) |
438 | return; | 427 | return; |
439 | if (nfs4_set_rw_stateid(&wdata->args.stateid, wdata->args.context, | 428 | if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, |
440 | wdata->args.lock_context, FMODE_WRITE) == -EIO) | 429 | hdr->args.lock_context, FMODE_WRITE) == -EIO) |
441 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ | 430 | rpc_exit(task, -EIO); /* lost lock, terminate I/O */ |
442 | } | 431 | } |
443 | 432 | ||
444 | static void filelayout_write_call_done(struct rpc_task *task, void *data) | 433 | static void filelayout_write_call_done(struct rpc_task *task, void *data) |
445 | { | 434 | { |
446 | struct nfs_pgio_data *wdata = data; | 435 | struct nfs_pgio_header *hdr = data; |
447 | 436 | ||
448 | if (test_bit(NFS_IOHDR_REDO, &wdata->header->flags) && | 437 | if (test_bit(NFS_IOHDR_REDO, &hdr->flags) && |
449 | task->tk_status == 0) { | 438 | task->tk_status == 0) { |
450 | nfs41_sequence_done(task, &wdata->res.seq_res); | 439 | nfs41_sequence_done(task, &hdr->res.seq_res); |
451 | return; | 440 | return; |
452 | } | 441 | } |
453 | 442 | ||
454 | /* Note this may cause RPC to be resent */ | 443 | /* Note this may cause RPC to be resent */ |
455 | wdata->header->mds_ops->rpc_call_done(task, data); | 444 | hdr->mds_ops->rpc_call_done(task, data); |
456 | } | 445 | } |
457 | 446 | ||
458 | static void filelayout_write_count_stats(struct rpc_task *task, void *data) | 447 | static void filelayout_write_count_stats(struct rpc_task *task, void *data) |
459 | { | 448 | { |
460 | struct nfs_pgio_data *wdata = data; | 449 | struct nfs_pgio_header *hdr = data; |
461 | 450 | ||
462 | rpc_count_iostats(task, NFS_SERVER(wdata->header->inode)->client->cl_metrics); | 451 | rpc_count_iostats(task, NFS_SERVER(hdr->inode)->client->cl_metrics); |
463 | } | 452 | } |
464 | 453 | ||
465 | static void filelayout_write_release(void *data) | 454 | static void filelayout_write_release(void *data) |
466 | { | 455 | { |
467 | struct nfs_pgio_data *wdata = data; | 456 | struct nfs_pgio_header *hdr = data; |
468 | struct pnfs_layout_hdr *lo = wdata->header->lseg->pls_layout; | 457 | struct pnfs_layout_hdr *lo = hdr->lseg->pls_layout; |
469 | 458 | ||
470 | filelayout_fenceme(lo->plh_inode, lo); | 459 | filelayout_fenceme(lo->plh_inode, lo); |
471 | nfs_put_client(wdata->ds_clp); | 460 | nfs_put_client(hdr->ds_clp); |
472 | wdata->header->mds_ops->rpc_release(data); | 461 | hdr->mds_ops->rpc_release(data); |
473 | } | 462 | } |
474 | 463 | ||
475 | static void filelayout_commit_prepare(struct rpc_task *task, void *data) | 464 | static void filelayout_commit_prepare(struct rpc_task *task, void *data) |
@@ -529,19 +518,18 @@ static const struct rpc_call_ops filelayout_commit_call_ops = { | |||
529 | }; | 518 | }; |
530 | 519 | ||
531 | static enum pnfs_try_status | 520 | static enum pnfs_try_status |
532 | filelayout_read_pagelist(struct nfs_pgio_data *data) | 521 | filelayout_read_pagelist(struct nfs_pgio_header *hdr) |
533 | { | 522 | { |
534 | struct nfs_pgio_header *hdr = data->header; | ||
535 | struct pnfs_layout_segment *lseg = hdr->lseg; | 523 | struct pnfs_layout_segment *lseg = hdr->lseg; |
536 | struct nfs4_pnfs_ds *ds; | 524 | struct nfs4_pnfs_ds *ds; |
537 | struct rpc_clnt *ds_clnt; | 525 | struct rpc_clnt *ds_clnt; |
538 | loff_t offset = data->args.offset; | 526 | loff_t offset = hdr->args.offset; |
539 | u32 j, idx; | 527 | u32 j, idx; |
540 | struct nfs_fh *fh; | 528 | struct nfs_fh *fh; |
541 | 529 | ||
542 | dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n", | 530 | dprintk("--> %s ino %lu pgbase %u req %Zu@%llu\n", |
543 | __func__, hdr->inode->i_ino, | 531 | __func__, hdr->inode->i_ino, |
544 | data->args.pgbase, (size_t)data->args.count, offset); | 532 | hdr->args.pgbase, (size_t)hdr->args.count, offset); |
545 | 533 | ||
546 | /* Retrieve the correct rpc_client for the byte range */ | 534 | /* Retrieve the correct rpc_client for the byte range */ |
547 | j = nfs4_fl_calc_j_index(lseg, offset); | 535 | j = nfs4_fl_calc_j_index(lseg, offset); |
@@ -559,30 +547,29 @@ filelayout_read_pagelist(struct nfs_pgio_data *data) | |||
559 | 547 | ||
560 | /* No multipath support. Use first DS */ | 548 | /* No multipath support. Use first DS */ |
561 | atomic_inc(&ds->ds_clp->cl_count); | 549 | atomic_inc(&ds->ds_clp->cl_count); |
562 | data->ds_clp = ds->ds_clp; | 550 | hdr->ds_clp = ds->ds_clp; |
563 | data->ds_idx = idx; | 551 | hdr->ds_idx = idx; |
564 | fh = nfs4_fl_select_ds_fh(lseg, j); | 552 | fh = nfs4_fl_select_ds_fh(lseg, j); |
565 | if (fh) | 553 | if (fh) |
566 | data->args.fh = fh; | 554 | hdr->args.fh = fh; |
567 | 555 | ||
568 | data->args.offset = filelayout_get_dserver_offset(lseg, offset); | 556 | hdr->args.offset = filelayout_get_dserver_offset(lseg, offset); |
569 | data->mds_offset = offset; | 557 | hdr->mds_offset = offset; |
570 | 558 | ||
571 | /* Perform an asynchronous read to ds */ | 559 | /* Perform an asynchronous read to ds */ |
572 | nfs_initiate_pgio(ds_clnt, data, | 560 | nfs_initiate_pgio(ds_clnt, hdr, |
573 | &filelayout_read_call_ops, 0, RPC_TASK_SOFTCONN); | 561 | &filelayout_read_call_ops, 0, RPC_TASK_SOFTCONN); |
574 | return PNFS_ATTEMPTED; | 562 | return PNFS_ATTEMPTED; |
575 | } | 563 | } |
576 | 564 | ||
577 | /* Perform async writes. */ | 565 | /* Perform async writes. */ |
578 | static enum pnfs_try_status | 566 | static enum pnfs_try_status |
579 | filelayout_write_pagelist(struct nfs_pgio_data *data, int sync) | 567 | filelayout_write_pagelist(struct nfs_pgio_header *hdr, int sync) |
580 | { | 568 | { |
581 | struct nfs_pgio_header *hdr = data->header; | ||
582 | struct pnfs_layout_segment *lseg = hdr->lseg; | 569 | struct pnfs_layout_segment *lseg = hdr->lseg; |
583 | struct nfs4_pnfs_ds *ds; | 570 | struct nfs4_pnfs_ds *ds; |
584 | struct rpc_clnt *ds_clnt; | 571 | struct rpc_clnt *ds_clnt; |
585 | loff_t offset = data->args.offset; | 572 | loff_t offset = hdr->args.offset; |
586 | u32 j, idx; | 573 | u32 j, idx; |
587 | struct nfs_fh *fh; | 574 | struct nfs_fh *fh; |
588 | 575 | ||
@@ -598,21 +585,20 @@ filelayout_write_pagelist(struct nfs_pgio_data *data, int sync) | |||
598 | return PNFS_NOT_ATTEMPTED; | 585 | return PNFS_NOT_ATTEMPTED; |
599 | 586 | ||
600 | dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s cl_count %d\n", | 587 | dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s cl_count %d\n", |
601 | __func__, hdr->inode->i_ino, sync, (size_t) data->args.count, | 588 | __func__, hdr->inode->i_ino, sync, (size_t) hdr->args.count, |
602 | offset, ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count)); | 589 | offset, ds->ds_remotestr, atomic_read(&ds->ds_clp->cl_count)); |
603 | 590 | ||
604 | data->pgio_done_cb = filelayout_write_done_cb; | 591 | hdr->pgio_done_cb = filelayout_write_done_cb; |
605 | atomic_inc(&ds->ds_clp->cl_count); | 592 | atomic_inc(&ds->ds_clp->cl_count); |
606 | data->ds_clp = ds->ds_clp; | 593 | hdr->ds_clp = ds->ds_clp; |
607 | data->ds_idx = idx; | 594 | hdr->ds_idx = idx; |
608 | fh = nfs4_fl_select_ds_fh(lseg, j); | 595 | fh = nfs4_fl_select_ds_fh(lseg, j); |
609 | if (fh) | 596 | if (fh) |
610 | data->args.fh = fh; | 597 | hdr->args.fh = fh; |
611 | 598 | hdr->args.offset = filelayout_get_dserver_offset(lseg, offset); | |
612 | data->args.offset = filelayout_get_dserver_offset(lseg, offset); | ||
613 | 599 | ||
614 | /* Perform an asynchronous write */ | 600 | /* Perform an asynchronous write */ |
615 | nfs_initiate_pgio(ds_clnt, data, | 601 | nfs_initiate_pgio(ds_clnt, hdr, |
616 | &filelayout_write_call_ops, sync, | 602 | &filelayout_write_call_ops, sync, |
617 | RPC_TASK_SOFTCONN); | 603 | RPC_TASK_SOFTCONN); |
618 | return PNFS_ATTEMPTED; | 604 | return PNFS_ATTEMPTED; |
@@ -1023,6 +1009,7 @@ static u32 select_bucket_index(struct nfs4_filelayout_segment *fl, u32 j) | |||
1023 | 1009 | ||
1024 | /* The generic layer is about to remove the req from the commit list. | 1010 | /* The generic layer is about to remove the req from the commit list. |
1025 | * If this will make the bucket empty, it will need to put the lseg reference. | 1011 | * If this will make the bucket empty, it will need to put the lseg reference. |
1012 | * Note this is must be called holding the inode (/cinfo) lock | ||
1026 | */ | 1013 | */ |
1027 | static void | 1014 | static void |
1028 | filelayout_clear_request_commit(struct nfs_page *req, | 1015 | filelayout_clear_request_commit(struct nfs_page *req, |
@@ -1030,7 +1017,6 @@ filelayout_clear_request_commit(struct nfs_page *req, | |||
1030 | { | 1017 | { |
1031 | struct pnfs_layout_segment *freeme = NULL; | 1018 | struct pnfs_layout_segment *freeme = NULL; |
1032 | 1019 | ||
1033 | spin_lock(cinfo->lock); | ||
1034 | if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags)) | 1020 | if (!test_and_clear_bit(PG_COMMIT_TO_DS, &req->wb_flags)) |
1035 | goto out; | 1021 | goto out; |
1036 | cinfo->ds->nwritten--; | 1022 | cinfo->ds->nwritten--; |
@@ -1045,22 +1031,25 @@ filelayout_clear_request_commit(struct nfs_page *req, | |||
1045 | } | 1031 | } |
1046 | out: | 1032 | out: |
1047 | nfs_request_remove_commit_list(req, cinfo); | 1033 | nfs_request_remove_commit_list(req, cinfo); |
1048 | spin_unlock(cinfo->lock); | 1034 | pnfs_put_lseg_async(freeme); |
1049 | pnfs_put_lseg(freeme); | ||
1050 | } | 1035 | } |
1051 | 1036 | ||
1052 | static struct list_head * | 1037 | static void |
1053 | filelayout_choose_commit_list(struct nfs_page *req, | 1038 | filelayout_mark_request_commit(struct nfs_page *req, |
1054 | struct pnfs_layout_segment *lseg, | 1039 | struct pnfs_layout_segment *lseg, |
1055 | struct nfs_commit_info *cinfo) | 1040 | struct nfs_commit_info *cinfo) |
1041 | |||
1056 | { | 1042 | { |
1057 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); | 1043 | struct nfs4_filelayout_segment *fl = FILELAYOUT_LSEG(lseg); |
1058 | u32 i, j; | 1044 | u32 i, j; |
1059 | struct list_head *list; | 1045 | struct list_head *list; |
1060 | struct pnfs_commit_bucket *buckets; | 1046 | struct pnfs_commit_bucket *buckets; |
1061 | 1047 | ||
1062 | if (fl->commit_through_mds) | 1048 | if (fl->commit_through_mds) { |
1063 | return &cinfo->mds->list; | 1049 | list = &cinfo->mds->list; |
1050 | spin_lock(cinfo->lock); | ||
1051 | goto mds_commit; | ||
1052 | } | ||
1064 | 1053 | ||
1065 | /* Note that we are calling nfs4_fl_calc_j_index on each page | 1054 | /* Note that we are calling nfs4_fl_calc_j_index on each page |
1066 | * that ends up being committed to a data server. An attractive | 1055 | * that ends up being committed to a data server. An attractive |
@@ -1084,19 +1073,22 @@ filelayout_choose_commit_list(struct nfs_page *req, | |||
1084 | } | 1073 | } |
1085 | set_bit(PG_COMMIT_TO_DS, &req->wb_flags); | 1074 | set_bit(PG_COMMIT_TO_DS, &req->wb_flags); |
1086 | cinfo->ds->nwritten++; | 1075 | cinfo->ds->nwritten++; |
1087 | spin_unlock(cinfo->lock); | ||
1088 | return list; | ||
1089 | } | ||
1090 | 1076 | ||
1091 | static void | 1077 | mds_commit: |
1092 | filelayout_mark_request_commit(struct nfs_page *req, | 1078 | /* nfs_request_add_commit_list(). We need to add req to list without |
1093 | struct pnfs_layout_segment *lseg, | 1079 | * dropping cinfo lock. |
1094 | struct nfs_commit_info *cinfo) | 1080 | */ |
1095 | { | 1081 | set_bit(PG_CLEAN, &(req)->wb_flags); |
1096 | struct list_head *list; | 1082 | nfs_list_add_request(req, list); |
1097 | 1083 | cinfo->mds->ncommit++; | |
1098 | list = filelayout_choose_commit_list(req, lseg, cinfo); | 1084 | spin_unlock(cinfo->lock); |
1099 | nfs_request_add_commit_list(req, list, cinfo); | 1085 | if (!cinfo->dreq) { |
1086 | inc_zone_page_state(req->wb_page, NR_UNSTABLE_NFS); | ||
1087 | inc_bdi_stat(page_file_mapping(req->wb_page)->backing_dev_info, | ||
1088 | BDI_RECLAIMABLE); | ||
1089 | __mark_inode_dirty(req->wb_context->dentry->d_inode, | ||
1090 | I_DIRTY_DATASYNC); | ||
1091 | } | ||
1100 | } | 1092 | } |
1101 | 1093 | ||
1102 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) | 1094 | static u32 calc_ds_index_from_commit(struct pnfs_layout_segment *lseg, u32 i) |
@@ -1244,15 +1236,63 @@ restart: | |||
1244 | spin_unlock(cinfo->lock); | 1236 | spin_unlock(cinfo->lock); |
1245 | } | 1237 | } |
1246 | 1238 | ||
1239 | /* filelayout_search_commit_reqs - Search lists in @cinfo for the head reqest | ||
1240 | * for @page | ||
1241 | * @cinfo - commit info for current inode | ||
1242 | * @page - page to search for matching head request | ||
1243 | * | ||
1244 | * Returns a the head request if one is found, otherwise returns NULL. | ||
1245 | */ | ||
1246 | static struct nfs_page * | ||
1247 | filelayout_search_commit_reqs(struct nfs_commit_info *cinfo, struct page *page) | ||
1248 | { | ||
1249 | struct nfs_page *freq, *t; | ||
1250 | struct pnfs_commit_bucket *b; | ||
1251 | int i; | ||
1252 | |||
1253 | /* Linearly search the commit lists for each bucket until a matching | ||
1254 | * request is found */ | ||
1255 | for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) { | ||
1256 | list_for_each_entry_safe(freq, t, &b->written, wb_list) { | ||
1257 | if (freq->wb_page == page) | ||
1258 | return freq->wb_head; | ||
1259 | } | ||
1260 | list_for_each_entry_safe(freq, t, &b->committing, wb_list) { | ||
1261 | if (freq->wb_page == page) | ||
1262 | return freq->wb_head; | ||
1263 | } | ||
1264 | } | ||
1265 | |||
1266 | return NULL; | ||
1267 | } | ||
1268 | |||
1269 | static void filelayout_retry_commit(struct nfs_commit_info *cinfo, int idx) | ||
1270 | { | ||
1271 | struct pnfs_ds_commit_info *fl_cinfo = cinfo->ds; | ||
1272 | struct pnfs_commit_bucket *bucket = fl_cinfo->buckets; | ||
1273 | struct pnfs_layout_segment *freeme; | ||
1274 | int i; | ||
1275 | |||
1276 | for (i = idx; i < fl_cinfo->nbuckets; i++, bucket++) { | ||
1277 | if (list_empty(&bucket->committing)) | ||
1278 | continue; | ||
1279 | nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo); | ||
1280 | spin_lock(cinfo->lock); | ||
1281 | freeme = bucket->clseg; | ||
1282 | bucket->clseg = NULL; | ||
1283 | spin_unlock(cinfo->lock); | ||
1284 | pnfs_put_lseg(freeme); | ||
1285 | } | ||
1286 | } | ||
1287 | |||
1247 | static unsigned int | 1288 | static unsigned int |
1248 | alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list) | 1289 | alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list) |
1249 | { | 1290 | { |
1250 | struct pnfs_ds_commit_info *fl_cinfo; | 1291 | struct pnfs_ds_commit_info *fl_cinfo; |
1251 | struct pnfs_commit_bucket *bucket; | 1292 | struct pnfs_commit_bucket *bucket; |
1252 | struct nfs_commit_data *data; | 1293 | struct nfs_commit_data *data; |
1253 | int i, j; | 1294 | int i; |
1254 | unsigned int nreq = 0; | 1295 | unsigned int nreq = 0; |
1255 | struct pnfs_layout_segment *freeme; | ||
1256 | 1296 | ||
1257 | fl_cinfo = cinfo->ds; | 1297 | fl_cinfo = cinfo->ds; |
1258 | bucket = fl_cinfo->buckets; | 1298 | bucket = fl_cinfo->buckets; |
@@ -1272,16 +1312,7 @@ alloc_ds_commits(struct nfs_commit_info *cinfo, struct list_head *list) | |||
1272 | } | 1312 | } |
1273 | 1313 | ||
1274 | /* Clean up on error */ | 1314 | /* Clean up on error */ |
1275 | for (j = i; j < fl_cinfo->nbuckets; j++, bucket++) { | 1315 | filelayout_retry_commit(cinfo, i); |
1276 | if (list_empty(&bucket->committing)) | ||
1277 | continue; | ||
1278 | nfs_retry_commit(&bucket->committing, bucket->clseg, cinfo); | ||
1279 | spin_lock(cinfo->lock); | ||
1280 | freeme = bucket->clseg; | ||
1281 | bucket->clseg = NULL; | ||
1282 | spin_unlock(cinfo->lock); | ||
1283 | pnfs_put_lseg(freeme); | ||
1284 | } | ||
1285 | /* Caller will clean up entries put on list */ | 1316 | /* Caller will clean up entries put on list */ |
1286 | return nreq; | 1317 | return nreq; |
1287 | } | 1318 | } |
@@ -1301,8 +1332,12 @@ filelayout_commit_pagelist(struct inode *inode, struct list_head *mds_pages, | |||
1301 | data->lseg = NULL; | 1332 | data->lseg = NULL; |
1302 | list_add(&data->pages, &list); | 1333 | list_add(&data->pages, &list); |
1303 | nreq++; | 1334 | nreq++; |
1304 | } else | 1335 | } else { |
1305 | nfs_retry_commit(mds_pages, NULL, cinfo); | 1336 | nfs_retry_commit(mds_pages, NULL, cinfo); |
1337 | filelayout_retry_commit(cinfo, 0); | ||
1338 | cinfo->completion_ops->error_cleanup(NFS_I(inode)); | ||
1339 | return -ENOMEM; | ||
1340 | } | ||
1306 | } | 1341 | } |
1307 | 1342 | ||
1308 | nreq += alloc_ds_commits(cinfo, &list); | 1343 | nreq += alloc_ds_commits(cinfo, &list); |
@@ -1380,6 +1415,7 @@ static struct pnfs_layoutdriver_type filelayout_type = { | |||
1380 | .clear_request_commit = filelayout_clear_request_commit, | 1415 | .clear_request_commit = filelayout_clear_request_commit, |
1381 | .scan_commit_lists = filelayout_scan_commit_lists, | 1416 | .scan_commit_lists = filelayout_scan_commit_lists, |
1382 | .recover_commit_reqs = filelayout_recover_commit_reqs, | 1417 | .recover_commit_reqs = filelayout_recover_commit_reqs, |
1418 | .search_commit_reqs = filelayout_search_commit_reqs, | ||
1383 | .commit_pagelist = filelayout_commit_pagelist, | 1419 | .commit_pagelist = filelayout_commit_pagelist, |
1384 | .read_pagelist = filelayout_read_pagelist, | 1420 | .read_pagelist = filelayout_read_pagelist, |
1385 | .write_pagelist = filelayout_write_pagelist, | 1421 | .write_pagelist = filelayout_write_pagelist, |
diff --git a/fs/nfs/filelayout/filelayoutdev.c b/fs/nfs/filelayout/filelayoutdev.c index e2a0361e24c6..8540516f4d71 100644 --- a/fs/nfs/filelayout/filelayoutdev.c +++ b/fs/nfs/filelayout/filelayoutdev.c | |||
@@ -695,7 +695,7 @@ filelayout_get_device_info(struct inode *inode, | |||
695 | if (pdev == NULL) | 695 | if (pdev == NULL) |
696 | return NULL; | 696 | return NULL; |
697 | 697 | ||
698 | pages = kzalloc(max_pages * sizeof(struct page *), gfp_flags); | 698 | pages = kcalloc(max_pages, sizeof(struct page *), gfp_flags); |
699 | if (pages == NULL) { | 699 | if (pages == NULL) { |
700 | kfree(pdev); | 700 | kfree(pdev); |
701 | return NULL; | 701 | return NULL; |