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 | |
| 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
...
54 files changed, 1967 insertions, 1288 deletions
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c index 9b431f44fad9..cbb1797149d5 100644 --- a/fs/nfs/blocklayout/blocklayout.c +++ b/fs/nfs/blocklayout/blocklayout.c | |||
| @@ -210,8 +210,7 @@ static void bl_end_io_read(struct bio *bio, int err) | |||
| 210 | SetPageUptodate(bvec->bv_page); | 210 | SetPageUptodate(bvec->bv_page); |
| 211 | 211 | ||
| 212 | if (err) { | 212 | if (err) { |
| 213 | struct nfs_pgio_data *rdata = par->data; | 213 | struct nfs_pgio_header *header = par->data; |
| 214 | struct nfs_pgio_header *header = rdata->header; | ||
| 215 | 214 | ||
| 216 | if (!header->pnfs_error) | 215 | if (!header->pnfs_error) |
| 217 | header->pnfs_error = -EIO; | 216 | header->pnfs_error = -EIO; |
| @@ -224,43 +223,44 @@ static void bl_end_io_read(struct bio *bio, int err) | |||
| 224 | static void bl_read_cleanup(struct work_struct *work) | 223 | static void bl_read_cleanup(struct work_struct *work) |
| 225 | { | 224 | { |
| 226 | struct rpc_task *task; | 225 | struct rpc_task *task; |
| 227 | struct nfs_pgio_data *rdata; | 226 | struct nfs_pgio_header *hdr; |
| 228 | dprintk("%s enter\n", __func__); | 227 | dprintk("%s enter\n", __func__); |
| 229 | task = container_of(work, struct rpc_task, u.tk_work); | 228 | task = container_of(work, struct rpc_task, u.tk_work); |
| 230 | rdata = container_of(task, struct nfs_pgio_data, task); | 229 | hdr = container_of(task, struct nfs_pgio_header, task); |
| 231 | pnfs_ld_read_done(rdata); | 230 | pnfs_ld_read_done(hdr); |
| 232 | } | 231 | } |
| 233 | 232 | ||
| 234 | static void | 233 | static void |
| 235 | bl_end_par_io_read(void *data, int unused) | 234 | bl_end_par_io_read(void *data, int unused) |
| 236 | { | 235 | { |
| 237 | struct nfs_pgio_data *rdata = data; | 236 | struct nfs_pgio_header *hdr = data; |
| 238 | 237 | ||
| 239 | rdata->task.tk_status = rdata->header->pnfs_error; | 238 | hdr->task.tk_status = hdr->pnfs_error; |
| 240 | INIT_WORK(&rdata->task.u.tk_work, bl_read_cleanup); | 239 | INIT_WORK(&hdr->task.u.tk_work, bl_read_cleanup); |
| 241 | schedule_work(&rdata->task.u.tk_work); | 240 | schedule_work(&hdr->task.u.tk_work); |
| 242 | } | 241 | } |
| 243 | 242 | ||
| 244 | static enum pnfs_try_status | 243 | static enum pnfs_try_status |
| 245 | bl_read_pagelist(struct nfs_pgio_data *rdata) | 244 | bl_read_pagelist(struct nfs_pgio_header *hdr) |
| 246 | { | 245 | { |
| 247 | struct nfs_pgio_header *header = rdata->header; | 246 | struct nfs_pgio_header *header = hdr; |
| 248 | int i, hole; | 247 | int i, hole; |
| 249 | struct bio *bio = NULL; | 248 | struct bio *bio = NULL; |
| 250 | struct pnfs_block_extent *be = NULL, *cow_read = NULL; | 249 | struct pnfs_block_extent *be = NULL, *cow_read = NULL; |
| 251 | sector_t isect, extent_length = 0; | 250 | sector_t isect, extent_length = 0; |
| 252 | struct parallel_io *par; | 251 | struct parallel_io *par; |
| 253 | loff_t f_offset = rdata->args.offset; | 252 | loff_t f_offset = hdr->args.offset; |
| 254 | size_t bytes_left = rdata->args.count; | 253 | size_t bytes_left = hdr->args.count; |
| 255 | unsigned int pg_offset, pg_len; | 254 | unsigned int pg_offset, pg_len; |
| 256 | struct page **pages = rdata->args.pages; | 255 | struct page **pages = hdr->args.pages; |
| 257 | int pg_index = rdata->args.pgbase >> PAGE_CACHE_SHIFT; | 256 | int pg_index = hdr->args.pgbase >> PAGE_CACHE_SHIFT; |
| 258 | const bool is_dio = (header->dreq != NULL); | 257 | const bool is_dio = (header->dreq != NULL); |
| 259 | 258 | ||
| 260 | dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__, | 259 | dprintk("%s enter nr_pages %u offset %lld count %u\n", __func__, |
| 261 | rdata->pages.npages, f_offset, (unsigned int)rdata->args.count); | 260 | hdr->page_array.npages, f_offset, |
| 261 | (unsigned int)hdr->args.count); | ||
| 262 | 262 | ||
| 263 | par = alloc_parallel(rdata); | 263 | par = alloc_parallel(hdr); |
| 264 | if (!par) | 264 | if (!par) |
| 265 | goto use_mds; | 265 | goto use_mds; |
| 266 | par->pnfs_callback = bl_end_par_io_read; | 266 | par->pnfs_callback = bl_end_par_io_read; |
| @@ -268,7 +268,7 @@ bl_read_pagelist(struct nfs_pgio_data *rdata) | |||
| 268 | 268 | ||
| 269 | isect = (sector_t) (f_offset >> SECTOR_SHIFT); | 269 | isect = (sector_t) (f_offset >> SECTOR_SHIFT); |
| 270 | /* Code assumes extents are page-aligned */ | 270 | /* Code assumes extents are page-aligned */ |
| 271 | for (i = pg_index; i < rdata->pages.npages; i++) { | 271 | for (i = pg_index; i < hdr->page_array.npages; i++) { |
| 272 | if (!extent_length) { | 272 | if (!extent_length) { |
| 273 | /* We've used up the previous extent */ | 273 | /* We've used up the previous extent */ |
| 274 | bl_put_extent(be); | 274 | bl_put_extent(be); |
| @@ -317,7 +317,8 @@ bl_read_pagelist(struct nfs_pgio_data *rdata) | |||
| 317 | struct pnfs_block_extent *be_read; | 317 | struct pnfs_block_extent *be_read; |
| 318 | 318 | ||
| 319 | be_read = (hole && cow_read) ? cow_read : be; | 319 | be_read = (hole && cow_read) ? cow_read : be; |
| 320 | bio = do_add_page_to_bio(bio, rdata->pages.npages - i, | 320 | bio = do_add_page_to_bio(bio, |
| 321 | hdr->page_array.npages - i, | ||
| 321 | READ, | 322 | READ, |
| 322 | isect, pages[i], be_read, | 323 | isect, pages[i], be_read, |
| 323 | bl_end_io_read, par, | 324 | bl_end_io_read, par, |
| @@ -332,10 +333,10 @@ bl_read_pagelist(struct nfs_pgio_data *rdata) | |||
| 332 | extent_length -= PAGE_CACHE_SECTORS; | 333 | extent_length -= PAGE_CACHE_SECTORS; |
| 333 | } | 334 | } |
| 334 | if ((isect << SECTOR_SHIFT) >= header->inode->i_size) { | 335 | if ((isect << SECTOR_SHIFT) >= header->inode->i_size) { |
| 335 | rdata->res.eof = 1; | 336 | hdr->res.eof = 1; |
| 336 | rdata->res.count = header->inode->i_size - rdata->args.offset; | 337 | hdr->res.count = header->inode->i_size - hdr->args.offset; |
| 337 | } else { | 338 | } else { |
| 338 | rdata->res.count = (isect << SECTOR_SHIFT) - rdata->args.offset; | 339 | hdr->res.count = (isect << SECTOR_SHIFT) - hdr->args.offset; |
| 339 | } | 340 | } |
| 340 | out: | 341 | out: |
| 341 | bl_put_extent(be); | 342 | bl_put_extent(be); |
| @@ -390,8 +391,7 @@ static void bl_end_io_write_zero(struct bio *bio, int err) | |||
| 390 | } | 391 | } |
| 391 | 392 | ||
| 392 | if (unlikely(err)) { | 393 | if (unlikely(err)) { |
| 393 | struct nfs_pgio_data *data = par->data; | 394 | struct nfs_pgio_header *header = par->data; |
| 394 | struct nfs_pgio_header *header = data->header; | ||
| 395 | 395 | ||
| 396 | if (!header->pnfs_error) | 396 | if (!header->pnfs_error) |
| 397 | header->pnfs_error = -EIO; | 397 | header->pnfs_error = -EIO; |
| @@ -405,8 +405,7 @@ static void bl_end_io_write(struct bio *bio, int err) | |||
| 405 | { | 405 | { |
| 406 | struct parallel_io *par = bio->bi_private; | 406 | struct parallel_io *par = bio->bi_private; |
| 407 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); | 407 | const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags); |
| 408 | struct nfs_pgio_data *data = par->data; | 408 | struct nfs_pgio_header *header = par->data; |
| 409 | struct nfs_pgio_header *header = data->header; | ||
| 410 | 409 | ||
| 411 | if (!uptodate) { | 410 | if (!uptodate) { |
| 412 | if (!header->pnfs_error) | 411 | if (!header->pnfs_error) |
| @@ -423,32 +422,32 @@ static void bl_end_io_write(struct bio *bio, int err) | |||
| 423 | static void bl_write_cleanup(struct work_struct *work) | 422 | static void bl_write_cleanup(struct work_struct *work) |
| 424 | { | 423 | { |
| 425 | struct rpc_task *task; | 424 | struct rpc_task *task; |
| 426 | struct nfs_pgio_data *wdata; | 425 | struct nfs_pgio_header *hdr; |
| 427 | dprintk("%s enter\n", __func__); | 426 | dprintk("%s enter\n", __func__); |
| 428 | task = container_of(work, struct rpc_task, u.tk_work); | 427 | task = container_of(work, struct rpc_task, u.tk_work); |
| 429 | wdata = container_of(task, struct nfs_pgio_data, task); | 428 | hdr = container_of(task, struct nfs_pgio_header, task); |
| 430 | if (likely(!wdata->header->pnfs_error)) { | 429 | if (likely(!hdr->pnfs_error)) { |
| 431 | /* Marks for LAYOUTCOMMIT */ | 430 | /* Marks for LAYOUTCOMMIT */ |
| 432 | mark_extents_written(BLK_LSEG2EXT(wdata->header->lseg), | 431 | mark_extents_written(BLK_LSEG2EXT(hdr->lseg), |
| 433 | wdata->args.offset, wdata->args.count); | 432 | hdr->args.offset, hdr->args.count); |
| 434 | } | 433 | } |
| 435 | pnfs_ld_write_done(wdata); | 434 | pnfs_ld_write_done(hdr); |
| 436 | } | 435 | } |
| 437 | 436 | ||
| 438 | /* Called when last of bios associated with a bl_write_pagelist call finishes */ | 437 | /* Called when last of bios associated with a bl_write_pagelist call finishes */ |
| 439 | static void bl_end_par_io_write(void *data, int num_se) | 438 | static void bl_end_par_io_write(void *data, int num_se) |
| 440 | { | 439 | { |
| 441 | struct nfs_pgio_data *wdata = data; | 440 | struct nfs_pgio_header *hdr = data; |
| 442 | 441 | ||
| 443 | if (unlikely(wdata->header->pnfs_error)) { | 442 | if (unlikely(hdr->pnfs_error)) { |
| 444 | bl_free_short_extents(&BLK_LSEG2EXT(wdata->header->lseg)->bl_inval, | 443 | bl_free_short_extents(&BLK_LSEG2EXT(hdr->lseg)->bl_inval, |
| 445 | num_se); | 444 | num_se); |
| 446 | } | 445 | } |
| 447 | 446 | ||
| 448 | wdata->task.tk_status = wdata->header->pnfs_error; | 447 | hdr->task.tk_status = hdr->pnfs_error; |
| 449 | wdata->verf.committed = NFS_FILE_SYNC; | 448 | hdr->verf.committed = NFS_FILE_SYNC; |
| 450 | INIT_WORK(&wdata->task.u.tk_work, bl_write_cleanup); | 449 | INIT_WORK(&hdr->task.u.tk_work, bl_write_cleanup); |
| 451 | schedule_work(&wdata->task.u.tk_work); | 450 | schedule_work(&hdr->task.u.tk_work); |
| 452 | } | 451 | } |
| 453 | 452 | ||
| 454 | /* FIXME STUB - mark intersection of layout and page as bad, so is not | 453 | /* FIXME STUB - mark intersection of layout and page as bad, so is not |
| @@ -673,18 +672,17 @@ check_page: | |||
| 673 | } | 672 | } |
| 674 | 673 | ||
| 675 | static enum pnfs_try_status | 674 | static enum pnfs_try_status |
| 676 | bl_write_pagelist(struct nfs_pgio_data *wdata, int sync) | 675 | bl_write_pagelist(struct nfs_pgio_header *header, int sync) |
| 677 | { | 676 | { |
| 678 | struct nfs_pgio_header *header = wdata->header; | ||
| 679 | int i, ret, npg_zero, pg_index, last = 0; | 677 | int i, ret, npg_zero, pg_index, last = 0; |
| 680 | struct bio *bio = NULL; | 678 | struct bio *bio = NULL; |
| 681 | struct pnfs_block_extent *be = NULL, *cow_read = NULL; | 679 | struct pnfs_block_extent *be = NULL, *cow_read = NULL; |
| 682 | sector_t isect, last_isect = 0, extent_length = 0; | 680 | sector_t isect, last_isect = 0, extent_length = 0; |
| 683 | struct parallel_io *par = NULL; | 681 | struct parallel_io *par = NULL; |
| 684 | loff_t offset = wdata->args.offset; | 682 | loff_t offset = header->args.offset; |
| 685 | size_t count = wdata->args.count; | 683 | size_t count = header->args.count; |
| 686 | unsigned int pg_offset, pg_len, saved_len; | 684 | unsigned int pg_offset, pg_len, saved_len; |
| 687 | struct page **pages = wdata->args.pages; | 685 | struct page **pages = header->args.pages; |
| 688 | struct page *page; | 686 | struct page *page; |
| 689 | pgoff_t index; | 687 | pgoff_t index; |
| 690 | u64 temp; | 688 | u64 temp; |
| @@ -699,11 +697,11 @@ bl_write_pagelist(struct nfs_pgio_data *wdata, int sync) | |||
| 699 | dprintk("pnfsblock nonblock aligned DIO writes. Resend MDS\n"); | 697 | dprintk("pnfsblock nonblock aligned DIO writes. Resend MDS\n"); |
| 700 | goto out_mds; | 698 | goto out_mds; |
| 701 | } | 699 | } |
| 702 | /* At this point, wdata->pages is a (sequential) list of nfs_pages. | 700 | /* At this point, header->page_aray is a (sequential) list of nfs_pages. |
| 703 | * We want to write each, and if there is an error set pnfs_error | 701 | * We want to write each, and if there is an error set pnfs_error |
| 704 | * to have it redone using nfs. | 702 | * to have it redone using nfs. |
| 705 | */ | 703 | */ |
| 706 | par = alloc_parallel(wdata); | 704 | par = alloc_parallel(header); |
| 707 | if (!par) | 705 | if (!par) |
| 708 | goto out_mds; | 706 | goto out_mds; |
| 709 | par->pnfs_callback = bl_end_par_io_write; | 707 | par->pnfs_callback = bl_end_par_io_write; |
| @@ -790,8 +788,8 @@ next_page: | |||
| 790 | bio = bl_submit_bio(WRITE, bio); | 788 | bio = bl_submit_bio(WRITE, bio); |
| 791 | 789 | ||
| 792 | /* Middle pages */ | 790 | /* Middle pages */ |
| 793 | pg_index = wdata->args.pgbase >> PAGE_CACHE_SHIFT; | 791 | pg_index = header->args.pgbase >> PAGE_CACHE_SHIFT; |
| 794 | for (i = pg_index; i < wdata->pages.npages; i++) { | 792 | for (i = pg_index; i < header->page_array.npages; i++) { |
| 795 | if (!extent_length) { | 793 | if (!extent_length) { |
| 796 | /* We've used up the previous extent */ | 794 | /* We've used up the previous extent */ |
| 797 | bl_put_extent(be); | 795 | bl_put_extent(be); |
| @@ -862,7 +860,8 @@ next_page: | |||
| 862 | } | 860 | } |
| 863 | 861 | ||
| 864 | 862 | ||
| 865 | bio = do_add_page_to_bio(bio, wdata->pages.npages - i, WRITE, | 863 | bio = do_add_page_to_bio(bio, header->page_array.npages - i, |
| 864 | WRITE, | ||
| 866 | isect, pages[i], be, | 865 | isect, pages[i], be, |
| 867 | bl_end_io_write, par, | 866 | bl_end_io_write, par, |
| 868 | pg_offset, pg_len); | 867 | pg_offset, pg_len); |
| @@ -890,7 +889,7 @@ next_page: | |||
| 890 | } | 889 | } |
| 891 | 890 | ||
| 892 | write_done: | 891 | write_done: |
| 893 | wdata->res.count = wdata->args.count; | 892 | header->res.count = header->args.count; |
| 894 | out: | 893 | out: |
| 895 | bl_put_extent(be); | 894 | bl_put_extent(be); |
| 896 | bl_put_extent(cow_read); | 895 | bl_put_extent(cow_read); |
| @@ -1063,7 +1062,7 @@ nfs4_blk_get_deviceinfo(struct nfs_server *server, const struct nfs_fh *fh, | |||
| 1063 | return ERR_PTR(-ENOMEM); | 1062 | return ERR_PTR(-ENOMEM); |
| 1064 | } | 1063 | } |
| 1065 | 1064 | ||
| 1066 | pages = kzalloc(max_pages * sizeof(struct page *), GFP_NOFS); | 1065 | pages = kcalloc(max_pages, sizeof(struct page *), GFP_NOFS); |
| 1067 | if (pages == NULL) { | 1066 | if (pages == NULL) { |
| 1068 | kfree(dev); | 1067 | kfree(dev); |
| 1069 | return ERR_PTR(-ENOMEM); | 1068 | return ERR_PTR(-ENOMEM); |
diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 073b4cf67ed9..54de482143cc 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c | |||
| @@ -428,6 +428,18 @@ check_gss_callback_principal(struct nfs_client *clp, struct svc_rqst *rqstp) | |||
| 428 | if (p == NULL) | 428 | if (p == NULL) |
| 429 | return 0; | 429 | return 0; |
| 430 | 430 | ||
| 431 | /* | ||
| 432 | * Did we get the acceptor from userland during the SETCLIENID | ||
| 433 | * negotiation? | ||
| 434 | */ | ||
| 435 | if (clp->cl_acceptor) | ||
| 436 | return !strcmp(p, clp->cl_acceptor); | ||
| 437 | |||
| 438 | /* | ||
| 439 | * Otherwise try to verify it using the cl_hostname. Note that this | ||
| 440 | * doesn't work if a non-canonical hostname was used in the devname. | ||
| 441 | */ | ||
| 442 | |||
| 431 | /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ | 443 | /* Expect a GSS_C_NT_HOSTBASED_NAME like "nfs@serverhostname" */ |
| 432 | 444 | ||
| 433 | if (memcmp(p, "nfs@", 4) != 0) | 445 | if (memcmp(p, "nfs@", 4) != 0) |
diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 180d1ec9c32e..1c5ff6d58385 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c | |||
| @@ -110,8 +110,8 @@ struct nfs_subversion *get_nfs_version(unsigned int version) | |||
| 110 | mutex_unlock(&nfs_version_mutex); | 110 | mutex_unlock(&nfs_version_mutex); |
| 111 | } | 111 | } |
| 112 | 112 | ||
| 113 | if (!IS_ERR(nfs)) | 113 | if (!IS_ERR(nfs) && !try_module_get(nfs->owner)) |
| 114 | try_module_get(nfs->owner); | 114 | return ERR_PTR(-EAGAIN); |
| 115 | return nfs; | 115 | return nfs; |
| 116 | } | 116 | } |
| 117 | 117 | ||
| @@ -158,7 +158,8 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) | |||
| 158 | goto error_0; | 158 | goto error_0; |
| 159 | 159 | ||
| 160 | clp->cl_nfs_mod = cl_init->nfs_mod; | 160 | clp->cl_nfs_mod = cl_init->nfs_mod; |
| 161 | try_module_get(clp->cl_nfs_mod->owner); | 161 | if (!try_module_get(clp->cl_nfs_mod->owner)) |
| 162 | goto error_dealloc; | ||
| 162 | 163 | ||
| 163 | clp->rpc_ops = clp->cl_nfs_mod->rpc_ops; | 164 | clp->rpc_ops = clp->cl_nfs_mod->rpc_ops; |
| 164 | 165 | ||
| @@ -190,6 +191,7 @@ struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_init) | |||
| 190 | 191 | ||
| 191 | error_cleanup: | 192 | error_cleanup: |
| 192 | put_nfs_version(clp->cl_nfs_mod); | 193 | put_nfs_version(clp->cl_nfs_mod); |
| 194 | error_dealloc: | ||
| 193 | kfree(clp); | 195 | kfree(clp); |
| 194 | error_0: | 196 | error_0: |
| 195 | return ERR_PTR(err); | 197 | return ERR_PTR(err); |
| @@ -252,6 +254,7 @@ void nfs_free_client(struct nfs_client *clp) | |||
| 252 | put_net(clp->cl_net); | 254 | put_net(clp->cl_net); |
| 253 | put_nfs_version(clp->cl_nfs_mod); | 255 | put_nfs_version(clp->cl_nfs_mod); |
| 254 | kfree(clp->cl_hostname); | 256 | kfree(clp->cl_hostname); |
| 257 | kfree(clp->cl_acceptor); | ||
| 255 | kfree(clp); | 258 | kfree(clp); |
| 256 | 259 | ||
| 257 | dprintk("<-- nfs_free_client()\n"); | 260 | dprintk("<-- nfs_free_client()\n"); |
| @@ -482,8 +485,13 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
| 482 | struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id); | 485 | struct nfs_net *nn = net_generic(cl_init->net, nfs_net_id); |
| 483 | const struct nfs_rpc_ops *rpc_ops = cl_init->nfs_mod->rpc_ops; | 486 | const struct nfs_rpc_ops *rpc_ops = cl_init->nfs_mod->rpc_ops; |
| 484 | 487 | ||
| 488 | if (cl_init->hostname == NULL) { | ||
| 489 | WARN_ON(1); | ||
| 490 | return NULL; | ||
| 491 | } | ||
| 492 | |||
| 485 | dprintk("--> nfs_get_client(%s,v%u)\n", | 493 | dprintk("--> nfs_get_client(%s,v%u)\n", |
| 486 | cl_init->hostname ?: "", rpc_ops->version); | 494 | cl_init->hostname, rpc_ops->version); |
| 487 | 495 | ||
| 488 | /* see if the client already exists */ | 496 | /* see if the client already exists */ |
| 489 | do { | 497 | do { |
| @@ -510,7 +518,7 @@ nfs_get_client(const struct nfs_client_initdata *cl_init, | |||
| 510 | } while (!IS_ERR(new)); | 518 | } while (!IS_ERR(new)); |
| 511 | 519 | ||
| 512 | dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n", | 520 | dprintk("<-- nfs_get_client() Failed to find %s (%ld)\n", |
| 513 | cl_init->hostname ?: "", PTR_ERR(new)); | 521 | cl_init->hostname, PTR_ERR(new)); |
| 514 | return new; | 522 | return new; |
| 515 | } | 523 | } |
| 516 | EXPORT_SYMBOL_GPL(nfs_get_client); | 524 | EXPORT_SYMBOL_GPL(nfs_get_client); |
diff --git a/fs/nfs/delegation.c b/fs/nfs/delegation.c index 5d8ccecf5f5c..5853f53db732 100644 --- a/fs/nfs/delegation.c +++ b/fs/nfs/delegation.c | |||
| @@ -41,14 +41,8 @@ void nfs_mark_delegation_referenced(struct nfs_delegation *delegation) | |||
| 41 | set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags); | 41 | set_bit(NFS_DELEGATION_REFERENCED, &delegation->flags); |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | /** | 44 | static int |
| 45 | * nfs_have_delegation - check if inode has a delegation | 45 | nfs4_do_check_delegation(struct inode *inode, fmode_t flags, bool mark) |
| 46 | * @inode: inode to check | ||
| 47 | * @flags: delegation types to check for | ||
| 48 | * | ||
| 49 | * Returns one if inode has the indicated delegation, otherwise zero. | ||
| 50 | */ | ||
| 51 | int nfs4_have_delegation(struct inode *inode, fmode_t flags) | ||
| 52 | { | 46 | { |
| 53 | struct nfs_delegation *delegation; | 47 | struct nfs_delegation *delegation; |
| 54 | int ret = 0; | 48 | int ret = 0; |
| @@ -58,12 +52,34 @@ int nfs4_have_delegation(struct inode *inode, fmode_t flags) | |||
| 58 | delegation = rcu_dereference(NFS_I(inode)->delegation); | 52 | delegation = rcu_dereference(NFS_I(inode)->delegation); |
| 59 | if (delegation != NULL && (delegation->type & flags) == flags && | 53 | if (delegation != NULL && (delegation->type & flags) == flags && |
| 60 | !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { | 54 | !test_bit(NFS_DELEGATION_RETURNING, &delegation->flags)) { |
| 61 | nfs_mark_delegation_referenced(delegation); | 55 | if (mark) |
| 56 | nfs_mark_delegation_referenced(delegation); | ||
| 62 | ret = 1; | 57 | ret = 1; |
| 63 | } | 58 | } |
| 64 | rcu_read_unlock(); | 59 | rcu_read_unlock(); |
| 65 | return ret; | 60 | return ret; |
| 66 | } | 61 | } |
| 62 | /** | ||
| 63 | * nfs_have_delegation - check if inode has a delegation, mark it | ||
| 64 | * NFS_DELEGATION_REFERENCED if there is one. | ||
| 65 | * @inode: inode to check | ||
| 66 | * @flags: delegation types to check for | ||
| 67 | * | ||
| 68 | * Returns one if inode has the indicated delegation, otherwise zero. | ||
| 69 | */ | ||
| 70 | int nfs4_have_delegation(struct inode *inode, fmode_t flags) | ||
| 71 | { | ||
| 72 | return nfs4_do_check_delegation(inode, flags, true); | ||
| 73 | } | ||
| 74 | |||
| 75 | /* | ||
| 76 | * nfs4_check_delegation - check if inode has a delegation, do not mark | ||
| 77 | * NFS_DELEGATION_REFERENCED if it has one. | ||
| 78 | */ | ||
| 79 | int nfs4_check_delegation(struct inode *inode, fmode_t flags) | ||
| 80 | { | ||
| 81 | return nfs4_do_check_delegation(inode, flags, false); | ||
| 82 | } | ||
| 67 | 83 | ||
| 68 | static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) | 84 | static int nfs_delegation_claim_locks(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) |
| 69 | { | 85 | { |
diff --git a/fs/nfs/delegation.h b/fs/nfs/delegation.h index 9a79c7a99d6d..5c1cce39297f 100644 --- a/fs/nfs/delegation.h +++ b/fs/nfs/delegation.h | |||
| @@ -59,6 +59,7 @@ bool nfs4_copy_delegation_stateid(nfs4_stateid *dst, struct inode *inode, fmode_ | |||
| 59 | 59 | ||
| 60 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); | 60 | void nfs_mark_delegation_referenced(struct nfs_delegation *delegation); |
| 61 | int nfs4_have_delegation(struct inode *inode, fmode_t flags); | 61 | int nfs4_have_delegation(struct inode *inode, fmode_t flags); |
| 62 | int nfs4_check_delegation(struct inode *inode, fmode_t flags); | ||
| 62 | 63 | ||
| 63 | #endif | 64 | #endif |
| 64 | 65 | ||
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 4a3d4ef76127..36d921f0c602 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -988,9 +988,13 @@ EXPORT_SYMBOL_GPL(nfs_force_lookup_revalidate); | |||
| 988 | * A check for whether or not the parent directory has changed. | 988 | * A check for whether or not the parent directory has changed. |
| 989 | * In the case it has, we assume that the dentries are untrustworthy | 989 | * In the case it has, we assume that the dentries are untrustworthy |
| 990 | * and may need to be looked up again. | 990 | * and may need to be looked up again. |
| 991 | * If rcu_walk prevents us from performing a full check, return 0. | ||
| 991 | */ | 992 | */ |
| 992 | static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) | 993 | static int nfs_check_verifier(struct inode *dir, struct dentry *dentry, |
| 994 | int rcu_walk) | ||
| 993 | { | 995 | { |
| 996 | int ret; | ||
| 997 | |||
| 994 | if (IS_ROOT(dentry)) | 998 | if (IS_ROOT(dentry)) |
| 995 | return 1; | 999 | return 1; |
| 996 | if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) | 1000 | if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONE) |
| @@ -998,7 +1002,11 @@ static int nfs_check_verifier(struct inode *dir, struct dentry *dentry) | |||
| 998 | if (!nfs_verify_change_attribute(dir, dentry->d_time)) | 1002 | if (!nfs_verify_change_attribute(dir, dentry->d_time)) |
| 999 | return 0; | 1003 | return 0; |
| 1000 | /* Revalidate nfsi->cache_change_attribute before we declare a match */ | 1004 | /* Revalidate nfsi->cache_change_attribute before we declare a match */ |
| 1001 | if (nfs_revalidate_inode(NFS_SERVER(dir), dir) < 0) | 1005 | if (rcu_walk) |
| 1006 | ret = nfs_revalidate_inode_rcu(NFS_SERVER(dir), dir); | ||
| 1007 | else | ||
| 1008 | ret = nfs_revalidate_inode(NFS_SERVER(dir), dir); | ||
| 1009 | if (ret < 0) | ||
| 1002 | return 0; | 1010 | return 0; |
| 1003 | if (!nfs_verify_change_attribute(dir, dentry->d_time)) | 1011 | if (!nfs_verify_change_attribute(dir, dentry->d_time)) |
| 1004 | return 0; | 1012 | return 0; |
| @@ -1042,6 +1050,8 @@ int nfs_lookup_verify_inode(struct inode *inode, unsigned int flags) | |||
| 1042 | out: | 1050 | out: |
| 1043 | return (inode->i_nlink == 0) ? -ENOENT : 0; | 1051 | return (inode->i_nlink == 0) ? -ENOENT : 0; |
| 1044 | out_force: | 1052 | out_force: |
| 1053 | if (flags & LOOKUP_RCU) | ||
| 1054 | return -ECHILD; | ||
| 1045 | ret = __nfs_revalidate_inode(server, inode); | 1055 | ret = __nfs_revalidate_inode(server, inode); |
| 1046 | if (ret != 0) | 1056 | if (ret != 0) |
| 1047 | return ret; | 1057 | return ret; |
| @@ -1054,6 +1064,9 @@ out_force: | |||
| 1054 | * | 1064 | * |
| 1055 | * If parent mtime has changed, we revalidate, else we wait for a | 1065 | * If parent mtime has changed, we revalidate, else we wait for a |
| 1056 | * period corresponding to the parent's attribute cache timeout value. | 1066 | * period corresponding to the parent's attribute cache timeout value. |
| 1067 | * | ||
| 1068 | * If LOOKUP_RCU prevents us from performing a full check, return 1 | ||
| 1069 | * suggesting a reval is needed. | ||
| 1057 | */ | 1070 | */ |
| 1058 | static inline | 1071 | static inline |
| 1059 | int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, | 1072 | int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, |
| @@ -1064,7 +1077,7 @@ int nfs_neg_need_reval(struct inode *dir, struct dentry *dentry, | |||
| 1064 | return 0; | 1077 | return 0; |
| 1065 | if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) | 1078 | if (NFS_SERVER(dir)->flags & NFS_MOUNT_LOOKUP_CACHE_NONEG) |
| 1066 | return 1; | 1079 | return 1; |
| 1067 | return !nfs_check_verifier(dir, dentry); | 1080 | return !nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU); |
| 1068 | } | 1081 | } |
| 1069 | 1082 | ||
| 1070 | /* | 1083 | /* |
| @@ -1088,21 +1101,30 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) | |||
| 1088 | struct nfs4_label *label = NULL; | 1101 | struct nfs4_label *label = NULL; |
| 1089 | int error; | 1102 | int error; |
| 1090 | 1103 | ||
| 1091 | if (flags & LOOKUP_RCU) | 1104 | if (flags & LOOKUP_RCU) { |
| 1092 | return -ECHILD; | 1105 | parent = ACCESS_ONCE(dentry->d_parent); |
| 1093 | 1106 | dir = ACCESS_ONCE(parent->d_inode); | |
| 1094 | parent = dget_parent(dentry); | 1107 | if (!dir) |
| 1095 | dir = parent->d_inode; | 1108 | return -ECHILD; |
| 1109 | } else { | ||
| 1110 | parent = dget_parent(dentry); | ||
| 1111 | dir = parent->d_inode; | ||
| 1112 | } | ||
| 1096 | nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); | 1113 | nfs_inc_stats(dir, NFSIOS_DENTRYREVALIDATE); |
| 1097 | inode = dentry->d_inode; | 1114 | inode = dentry->d_inode; |
| 1098 | 1115 | ||
| 1099 | if (!inode) { | 1116 | if (!inode) { |
| 1100 | if (nfs_neg_need_reval(dir, dentry, flags)) | 1117 | if (nfs_neg_need_reval(dir, dentry, flags)) { |
| 1118 | if (flags & LOOKUP_RCU) | ||
| 1119 | return -ECHILD; | ||
| 1101 | goto out_bad; | 1120 | goto out_bad; |
| 1121 | } | ||
| 1102 | goto out_valid_noent; | 1122 | goto out_valid_noent; |
| 1103 | } | 1123 | } |
| 1104 | 1124 | ||
| 1105 | if (is_bad_inode(inode)) { | 1125 | if (is_bad_inode(inode)) { |
| 1126 | if (flags & LOOKUP_RCU) | ||
| 1127 | return -ECHILD; | ||
| 1106 | dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n", | 1128 | dfprintk(LOOKUPCACHE, "%s: %pd2 has dud inode\n", |
| 1107 | __func__, dentry); | 1129 | __func__, dentry); |
| 1108 | goto out_bad; | 1130 | goto out_bad; |
| @@ -1112,12 +1134,20 @@ static int nfs_lookup_revalidate(struct dentry *dentry, unsigned int flags) | |||
| 1112 | goto out_set_verifier; | 1134 | goto out_set_verifier; |
| 1113 | 1135 | ||
| 1114 | /* Force a full look up iff the parent directory has changed */ | 1136 | /* Force a full look up iff the parent directory has changed */ |
| 1115 | if (!nfs_is_exclusive_create(dir, flags) && nfs_check_verifier(dir, dentry)) { | 1137 | if (!nfs_is_exclusive_create(dir, flags) && |
| 1116 | if (nfs_lookup_verify_inode(inode, flags)) | 1138 | nfs_check_verifier(dir, dentry, flags & LOOKUP_RCU)) { |
| 1139 | |||
| 1140 | if (nfs_lookup_verify_inode(inode, flags)) { | ||
| 1141 | if (flags & LOOKUP_RCU) | ||
| 1142 | return -ECHILD; | ||
| 1117 | goto out_zap_parent; | 1143 | goto out_zap_parent; |
| 1144 | } | ||
| 1118 | goto out_valid; | 1145 | goto out_valid; |
| 1119 | } | 1146 | } |
| 1120 | 1147 | ||
| 1148 | if (flags & LOOKUP_RCU) | ||
| 1149 | return -ECHILD; | ||
| 1150 | |||
| 1121 | if (NFS_STALE(inode)) | 1151 | if (NFS_STALE(inode)) |
| 1122 | goto out_bad; | 1152 | goto out_bad; |
| 1123 | 1153 | ||
| @@ -1153,13 +1183,18 @@ out_set_verifier: | |||
| 1153 | /* Success: notify readdir to use READDIRPLUS */ | 1183 | /* Success: notify readdir to use READDIRPLUS */ |
| 1154 | nfs_advise_use_readdirplus(dir); | 1184 | nfs_advise_use_readdirplus(dir); |
| 1155 | out_valid_noent: | 1185 | out_valid_noent: |
| 1156 | dput(parent); | 1186 | if (flags & LOOKUP_RCU) { |
| 1187 | if (parent != ACCESS_ONCE(dentry->d_parent)) | ||
| 1188 | return -ECHILD; | ||
| 1189 | } else | ||
| 1190 | dput(parent); | ||
| 1157 | dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n", | 1191 | dfprintk(LOOKUPCACHE, "NFS: %s(%pd2) is valid\n", |
| 1158 | __func__, dentry); | 1192 | __func__, dentry); |
| 1159 | return 1; | 1193 | return 1; |
| 1160 | out_zap_parent: | 1194 | out_zap_parent: |
| 1161 | nfs_zap_caches(dir); | 1195 | nfs_zap_caches(dir); |
| 1162 | out_bad: | 1196 | out_bad: |
| 1197 | WARN_ON(flags & LOOKUP_RCU); | ||
| 1163 | nfs_free_fattr(fattr); | 1198 | nfs_free_fattr(fattr); |
| 1164 | nfs_free_fhandle(fhandle); | 1199 | nfs_free_fhandle(fhandle); |
| 1165 | nfs4_label_free(label); | 1200 | nfs4_label_free(label); |
| @@ -1185,6 +1220,7 @@ out_zap_parent: | |||
| 1185 | __func__, dentry); | 1220 | __func__, dentry); |
| 1186 | return 0; | 1221 | return 0; |
| 1187 | out_error: | 1222 | out_error: |
| 1223 | WARN_ON(flags & LOOKUP_RCU); | ||
| 1188 | nfs_free_fattr(fattr); | 1224 | nfs_free_fattr(fattr); |
| 1189 | nfs_free_fhandle(fhandle); | 1225 | nfs_free_fhandle(fhandle); |
| 1190 | nfs4_label_free(label); | 1226 | nfs4_label_free(label); |
| @@ -1529,14 +1565,9 @@ EXPORT_SYMBOL_GPL(nfs_atomic_open); | |||
| 1529 | 1565 | ||
| 1530 | static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) | 1566 | static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) |
| 1531 | { | 1567 | { |
| 1532 | struct dentry *parent = NULL; | ||
| 1533 | struct inode *inode; | 1568 | struct inode *inode; |
| 1534 | struct inode *dir; | ||
| 1535 | int ret = 0; | 1569 | int ret = 0; |
| 1536 | 1570 | ||
| 1537 | if (flags & LOOKUP_RCU) | ||
| 1538 | return -ECHILD; | ||
| 1539 | |||
| 1540 | if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY)) | 1571 | if (!(flags & LOOKUP_OPEN) || (flags & LOOKUP_DIRECTORY)) |
| 1541 | goto no_open; | 1572 | goto no_open; |
| 1542 | if (d_mountpoint(dentry)) | 1573 | if (d_mountpoint(dentry)) |
| @@ -1545,34 +1576,47 @@ static int nfs4_lookup_revalidate(struct dentry *dentry, unsigned int flags) | |||
| 1545 | goto no_open; | 1576 | goto no_open; |
| 1546 | 1577 | ||
| 1547 | inode = dentry->d_inode; | 1578 | inode = dentry->d_inode; |
| 1548 | parent = dget_parent(dentry); | ||
| 1549 | dir = parent->d_inode; | ||
| 1550 | 1579 | ||
| 1551 | /* We can't create new files in nfs_open_revalidate(), so we | 1580 | /* We can't create new files in nfs_open_revalidate(), so we |
| 1552 | * optimize away revalidation of negative dentries. | 1581 | * optimize away revalidation of negative dentries. |
| 1553 | */ | 1582 | */ |
| 1554 | if (inode == NULL) { | 1583 | if (inode == NULL) { |
| 1584 | struct dentry *parent; | ||
| 1585 | struct inode *dir; | ||
| 1586 | |||
| 1587 | if (flags & LOOKUP_RCU) { | ||
| 1588 | parent = ACCESS_ONCE(dentry->d_parent); | ||
| 1589 | dir = ACCESS_ONCE(parent->d_inode); | ||
| 1590 | if (!dir) | ||
| 1591 | return -ECHILD; | ||
| 1592 | } else { | ||
| 1593 | parent = dget_parent(dentry); | ||
| 1594 | dir = parent->d_inode; | ||
| 1595 | } | ||
| 1555 | if (!nfs_neg_need_reval(dir, dentry, flags)) | 1596 | if (!nfs_neg_need_reval(dir, dentry, flags)) |
| 1556 | ret = 1; | 1597 | ret = 1; |
| 1598 | else if (flags & LOOKUP_RCU) | ||
| 1599 | ret = -ECHILD; | ||
| 1600 | if (!(flags & LOOKUP_RCU)) | ||
| 1601 | dput(parent); | ||
| 1602 | else if (parent != ACCESS_ONCE(dentry->d_parent)) | ||
| 1603 | return -ECHILD; | ||
| 1557 | goto out; | 1604 | goto out; |
| 1558 | } | 1605 | } |
| 1559 | 1606 | ||
| 1560 | /* NFS only supports OPEN on regular files */ | 1607 | /* NFS only supports OPEN on regular files */ |
| 1561 | if (!S_ISREG(inode->i_mode)) | 1608 | if (!S_ISREG(inode->i_mode)) |
| 1562 | goto no_open_dput; | 1609 | goto no_open; |
| 1563 | /* We cannot do exclusive creation on a positive dentry */ | 1610 | /* We cannot do exclusive creation on a positive dentry */ |
| 1564 | if (flags & LOOKUP_EXCL) | 1611 | if (flags & LOOKUP_EXCL) |
| 1565 | goto no_open_dput; | 1612 | goto no_open; |
| 1566 | 1613 | ||
| 1567 | /* Let f_op->open() actually open (and revalidate) the file */ | 1614 | /* Let f_op->open() actually open (and revalidate) the file */ |
| 1568 | ret = 1; | 1615 | ret = 1; |
| 1569 | 1616 | ||
| 1570 | out: | 1617 | out: |
| 1571 | dput(parent); | ||
| 1572 | return ret; | 1618 | return ret; |
| 1573 | 1619 | ||
| 1574 | no_open_dput: | ||
| 1575 | dput(parent); | ||
| 1576 | no_open: | 1620 | no_open: |
| 1577 | return nfs_lookup_revalidate(dentry, flags); | 1621 | return nfs_lookup_revalidate(dentry, flags); |
| 1578 | } | 1622 | } |
| @@ -2028,10 +2072,14 @@ static DEFINE_SPINLOCK(nfs_access_lru_lock); | |||
| 2028 | static LIST_HEAD(nfs_access_lru_list); | 2072 | static LIST_HEAD(nfs_access_lru_list); |
| 2029 | static atomic_long_t nfs_access_nr_entries; | 2073 | static atomic_long_t nfs_access_nr_entries; |
| 2030 | 2074 | ||
| 2075 | static unsigned long nfs_access_max_cachesize = ULONG_MAX; | ||
| 2076 | module_param(nfs_access_max_cachesize, ulong, 0644); | ||
| 2077 | MODULE_PARM_DESC(nfs_access_max_cachesize, "NFS access maximum total cache length"); | ||
| 2078 | |||
| 2031 | static void nfs_access_free_entry(struct nfs_access_entry *entry) | 2079 | static void nfs_access_free_entry(struct nfs_access_entry *entry) |
| 2032 | { | 2080 | { |
| 2033 | put_rpccred(entry->cred); | 2081 | put_rpccred(entry->cred); |
| 2034 | kfree(entry); | 2082 | kfree_rcu(entry, rcu_head); |
| 2035 | smp_mb__before_atomic(); | 2083 | smp_mb__before_atomic(); |
| 2036 | atomic_long_dec(&nfs_access_nr_entries); | 2084 | atomic_long_dec(&nfs_access_nr_entries); |
| 2037 | smp_mb__after_atomic(); | 2085 | smp_mb__after_atomic(); |
| @@ -2048,19 +2096,14 @@ static void nfs_access_free_list(struct list_head *head) | |||
| 2048 | } | 2096 | } |
| 2049 | } | 2097 | } |
| 2050 | 2098 | ||
| 2051 | unsigned long | 2099 | static unsigned long |
| 2052 | nfs_access_cache_scan(struct shrinker *shrink, struct shrink_control *sc) | 2100 | nfs_do_access_cache_scan(unsigned int nr_to_scan) |
| 2053 | { | 2101 | { |
| 2054 | LIST_HEAD(head); | 2102 | LIST_HEAD(head); |
| 2055 | struct nfs_inode *nfsi, *next; | 2103 | struct nfs_inode *nfsi, *next; |
| 2056 | struct nfs_access_entry *cache; | 2104 | struct nfs_access_entry *cache; |
| 2057 | int nr_to_scan = sc->nr_to_scan; | ||
| 2058 | gfp_t gfp_mask = sc->gfp_mask; | ||
| 2059 | long freed = 0; | 2105 | long freed = 0; |
| 2060 | 2106 | ||
| 2061 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) | ||
| 2062 | return SHRINK_STOP; | ||
| 2063 | |||
| 2064 | spin_lock(&nfs_access_lru_lock); | 2107 | spin_lock(&nfs_access_lru_lock); |
| 2065 | list_for_each_entry_safe(nfsi, next, &nfs_access_lru_list, access_cache_inode_lru) { | 2108 | list_for_each_entry_safe(nfsi, next, &nfs_access_lru_list, access_cache_inode_lru) { |
| 2066 | struct inode *inode; | 2109 | struct inode *inode; |
| @@ -2094,11 +2137,39 @@ remove_lru_entry: | |||
| 2094 | } | 2137 | } |
| 2095 | 2138 | ||
| 2096 | unsigned long | 2139 | unsigned long |
| 2140 | nfs_access_cache_scan(struct shrinker *shrink, struct shrink_control *sc) | ||
| 2141 | { | ||
| 2142 | int nr_to_scan = sc->nr_to_scan; | ||
| 2143 | gfp_t gfp_mask = sc->gfp_mask; | ||
| 2144 | |||
| 2145 | if ((gfp_mask & GFP_KERNEL) != GFP_KERNEL) | ||
| 2146 | return SHRINK_STOP; | ||
| 2147 | return nfs_do_access_cache_scan(nr_to_scan); | ||
| 2148 | } | ||
| 2149 | |||
| 2150 | |||
| 2151 | unsigned long | ||
| 2097 | nfs_access_cache_count(struct shrinker *shrink, struct shrink_control *sc) | 2152 | nfs_access_cache_count(struct shrinker *shrink, struct shrink_control *sc) |
| 2098 | { | 2153 | { |
| 2099 | return vfs_pressure_ratio(atomic_long_read(&nfs_access_nr_entries)); | 2154 | return vfs_pressure_ratio(atomic_long_read(&nfs_access_nr_entries)); |
| 2100 | } | 2155 | } |
| 2101 | 2156 | ||
| 2157 | static void | ||
| 2158 | nfs_access_cache_enforce_limit(void) | ||
| 2159 | { | ||
| 2160 | long nr_entries = atomic_long_read(&nfs_access_nr_entries); | ||
| 2161 | unsigned long diff; | ||
| 2162 | unsigned int nr_to_scan; | ||
| 2163 | |||
| 2164 | if (nr_entries < 0 || nr_entries <= nfs_access_max_cachesize) | ||
| 2165 | return; | ||
| 2166 | nr_to_scan = 100; | ||
| 2167 | diff = nr_entries - nfs_access_max_cachesize; | ||
| 2168 | if (diff < nr_to_scan) | ||
| 2169 | nr_to_scan = diff; | ||
| 2170 | nfs_do_access_cache_scan(nr_to_scan); | ||
| 2171 | } | ||
| 2172 | |||
| 2102 | static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head) | 2173 | static void __nfs_access_zap_cache(struct nfs_inode *nfsi, struct list_head *head) |
| 2103 | { | 2174 | { |
| 2104 | struct rb_root *root_node = &nfsi->access_cache; | 2175 | struct rb_root *root_node = &nfsi->access_cache; |
| @@ -2186,6 +2257,38 @@ out_zap: | |||
| 2186 | return -ENOENT; | 2257 | return -ENOENT; |
| 2187 | } | 2258 | } |
| 2188 | 2259 | ||
| 2260 | static int nfs_access_get_cached_rcu(struct inode *inode, struct rpc_cred *cred, struct nfs_access_entry *res) | ||
| 2261 | { | ||
| 2262 | /* Only check the most recently returned cache entry, | ||
| 2263 | * but do it without locking. | ||
| 2264 | */ | ||
| 2265 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 2266 | struct nfs_access_entry *cache; | ||
| 2267 | int err = -ECHILD; | ||
| 2268 | struct list_head *lh; | ||
| 2269 | |||
| 2270 | rcu_read_lock(); | ||
| 2271 | if (nfsi->cache_validity & NFS_INO_INVALID_ACCESS) | ||
| 2272 | goto out; | ||
| 2273 | lh = rcu_dereference(nfsi->access_cache_entry_lru.prev); | ||
| 2274 | cache = list_entry(lh, struct nfs_access_entry, lru); | ||
| 2275 | if (lh == &nfsi->access_cache_entry_lru || | ||
| 2276 | cred != cache->cred) | ||
| 2277 | cache = NULL; | ||
| 2278 | if (cache == NULL) | ||
| 2279 | goto out; | ||
| 2280 | if (!nfs_have_delegated_attributes(inode) && | ||
| 2281 | !time_in_range_open(jiffies, cache->jiffies, cache->jiffies + nfsi->attrtimeo)) | ||
| 2282 | goto out; | ||
| 2283 | res->jiffies = cache->jiffies; | ||
| 2284 | res->cred = cache->cred; | ||
| 2285 | res->mask = cache->mask; | ||
| 2286 | err = 0; | ||
| 2287 | out: | ||
| 2288 | rcu_read_unlock(); | ||
| 2289 | return err; | ||
| 2290 | } | ||
| 2291 | |||
| 2189 | static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *set) | 2292 | static void nfs_access_add_rbtree(struct inode *inode, struct nfs_access_entry *set) |
| 2190 | { | 2293 | { |
| 2191 | struct nfs_inode *nfsi = NFS_I(inode); | 2294 | struct nfs_inode *nfsi = NFS_I(inode); |
| @@ -2229,6 +2332,11 @@ void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) | |||
| 2229 | cache->cred = get_rpccred(set->cred); | 2332 | cache->cred = get_rpccred(set->cred); |
| 2230 | cache->mask = set->mask; | 2333 | cache->mask = set->mask; |
| 2231 | 2334 | ||
| 2335 | /* The above field assignments must be visible | ||
| 2336 | * before this item appears on the lru. We cannot easily | ||
| 2337 | * use rcu_assign_pointer, so just force the memory barrier. | ||
| 2338 | */ | ||
| 2339 | smp_wmb(); | ||
| 2232 | nfs_access_add_rbtree(inode, cache); | 2340 | nfs_access_add_rbtree(inode, cache); |
| 2233 | 2341 | ||
| 2234 | /* Update accounting */ | 2342 | /* Update accounting */ |
| @@ -2244,6 +2352,7 @@ void nfs_access_add_cache(struct inode *inode, struct nfs_access_entry *set) | |||
| 2244 | &nfs_access_lru_list); | 2352 | &nfs_access_lru_list); |
| 2245 | spin_unlock(&nfs_access_lru_lock); | 2353 | spin_unlock(&nfs_access_lru_lock); |
| 2246 | } | 2354 | } |
| 2355 | nfs_access_cache_enforce_limit(); | ||
| 2247 | } | 2356 | } |
| 2248 | EXPORT_SYMBOL_GPL(nfs_access_add_cache); | 2357 | EXPORT_SYMBOL_GPL(nfs_access_add_cache); |
| 2249 | 2358 | ||
| @@ -2267,10 +2376,16 @@ static int nfs_do_access(struct inode *inode, struct rpc_cred *cred, int mask) | |||
| 2267 | 2376 | ||
| 2268 | trace_nfs_access_enter(inode); | 2377 | trace_nfs_access_enter(inode); |
| 2269 | 2378 | ||
| 2270 | status = nfs_access_get_cached(inode, cred, &cache); | 2379 | status = nfs_access_get_cached_rcu(inode, cred, &cache); |
| 2380 | if (status != 0) | ||
| 2381 | status = nfs_access_get_cached(inode, cred, &cache); | ||
| 2271 | if (status == 0) | 2382 | if (status == 0) |
| 2272 | goto out_cached; | 2383 | goto out_cached; |
| 2273 | 2384 | ||
| 2385 | status = -ECHILD; | ||
| 2386 | if (mask & MAY_NOT_BLOCK) | ||
| 2387 | goto out; | ||
| 2388 | |||
| 2274 | /* Be clever: ask server to check for all possible rights */ | 2389 | /* Be clever: ask server to check for all possible rights */ |
| 2275 | cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ; | 2390 | cache.mask = MAY_EXEC | MAY_WRITE | MAY_READ; |
| 2276 | cache.cred = cred; | 2391 | cache.cred = cred; |
| @@ -2321,9 +2436,6 @@ int nfs_permission(struct inode *inode, int mask) | |||
| 2321 | struct rpc_cred *cred; | 2436 | struct rpc_cred *cred; |
| 2322 | int res = 0; | 2437 | int res = 0; |
| 2323 | 2438 | ||
| 2324 | if (mask & MAY_NOT_BLOCK) | ||
| 2325 | return -ECHILD; | ||
| 2326 | |||
| 2327 | nfs_inc_stats(inode, NFSIOS_VFSACCESS); | 2439 | nfs_inc_stats(inode, NFSIOS_VFSACCESS); |
| 2328 | 2440 | ||
| 2329 | if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) | 2441 | if ((mask & (MAY_READ | MAY_WRITE | MAY_EXEC)) == 0) |
| @@ -2350,12 +2462,23 @@ force_lookup: | |||
| 2350 | if (!NFS_PROTO(inode)->access) | 2462 | if (!NFS_PROTO(inode)->access) |
| 2351 | goto out_notsup; | 2463 | goto out_notsup; |
| 2352 | 2464 | ||
| 2353 | cred = rpc_lookup_cred(); | 2465 | /* Always try fast lookups first */ |
| 2354 | if (!IS_ERR(cred)) { | 2466 | rcu_read_lock(); |
| 2355 | res = nfs_do_access(inode, cred, mask); | 2467 | cred = rpc_lookup_cred_nonblock(); |
| 2356 | put_rpccred(cred); | 2468 | if (!IS_ERR(cred)) |
| 2357 | } else | 2469 | res = nfs_do_access(inode, cred, mask|MAY_NOT_BLOCK); |
| 2470 | else | ||
| 2358 | res = PTR_ERR(cred); | 2471 | res = PTR_ERR(cred); |
| 2472 | rcu_read_unlock(); | ||
| 2473 | if (res == -ECHILD && !(mask & MAY_NOT_BLOCK)) { | ||
| 2474 | /* Fast lookup failed, try the slow way */ | ||
| 2475 | cred = rpc_lookup_cred(); | ||
| 2476 | if (!IS_ERR(cred)) { | ||
| 2477 | res = nfs_do_access(inode, cred, mask); | ||
| 2478 | put_rpccred(cred); | ||
| 2479 | } else | ||
| 2480 | res = PTR_ERR(cred); | ||
| 2481 | } | ||
| 2359 | out: | 2482 | out: |
| 2360 | if (!res && (mask & MAY_EXEC) && !execute_ok(inode)) | 2483 | if (!res && (mask & MAY_EXEC) && !execute_ok(inode)) |
| 2361 | res = -EACCES; | 2484 | res = -EACCES; |
| @@ -2364,6 +2487,9 @@ out: | |||
| 2364 | inode->i_sb->s_id, inode->i_ino, mask, res); | 2487 | inode->i_sb->s_id, inode->i_ino, mask, res); |
| 2365 | return res; | 2488 | return res; |
| 2366 | out_notsup: | 2489 | out_notsup: |
| 2490 | if (mask & MAY_NOT_BLOCK) | ||
| 2491 | return -ECHILD; | ||
| 2492 | |||
| 2367 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); | 2493 | res = nfs_revalidate_inode(NFS_SERVER(inode), inode); |
| 2368 | if (res == 0) | 2494 | if (res == 0) |
| 2369 | res = generic_permission(inode, mask); | 2495 | res = generic_permission(inode, mask); |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index f11b9eed0de1..65ef6e00deee 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -148,8 +148,8 @@ static void nfs_direct_set_hdr_verf(struct nfs_direct_req *dreq, | |||
| 148 | { | 148 | { |
| 149 | struct nfs_writeverf *verfp; | 149 | struct nfs_writeverf *verfp; |
| 150 | 150 | ||
| 151 | verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp, | 151 | verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, |
| 152 | hdr->data->ds_idx); | 152 | hdr->ds_idx); |
| 153 | WARN_ON_ONCE(verfp->committed >= 0); | 153 | WARN_ON_ONCE(verfp->committed >= 0); |
| 154 | memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); | 154 | memcpy(verfp, &hdr->verf, sizeof(struct nfs_writeverf)); |
| 155 | WARN_ON_ONCE(verfp->committed < 0); | 155 | WARN_ON_ONCE(verfp->committed < 0); |
| @@ -169,8 +169,8 @@ static int nfs_direct_set_or_cmp_hdr_verf(struct nfs_direct_req *dreq, | |||
| 169 | { | 169 | { |
| 170 | struct nfs_writeverf *verfp; | 170 | struct nfs_writeverf *verfp; |
| 171 | 171 | ||
| 172 | verfp = nfs_direct_select_verf(dreq, hdr->data->ds_clp, | 172 | verfp = nfs_direct_select_verf(dreq, hdr->ds_clp, |
| 173 | hdr->data->ds_idx); | 173 | hdr->ds_idx); |
| 174 | if (verfp->committed < 0) { | 174 | if (verfp->committed < 0) { |
| 175 | nfs_direct_set_hdr_verf(dreq, hdr); | 175 | nfs_direct_set_hdr_verf(dreq, hdr); |
| 176 | return 0; | 176 | return 0; |
| @@ -715,7 +715,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) | |||
| 715 | { | 715 | { |
| 716 | struct nfs_direct_req *dreq = hdr->dreq; | 716 | struct nfs_direct_req *dreq = hdr->dreq; |
| 717 | struct nfs_commit_info cinfo; | 717 | struct nfs_commit_info cinfo; |
| 718 | int bit = -1; | 718 | bool request_commit = false; |
| 719 | struct nfs_page *req = nfs_list_entry(hdr->pages.next); | 719 | struct nfs_page *req = nfs_list_entry(hdr->pages.next); |
| 720 | 720 | ||
| 721 | if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) | 721 | if (test_bit(NFS_IOHDR_REDO, &hdr->flags)) |
| @@ -729,27 +729,20 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) | |||
| 729 | dreq->flags = 0; | 729 | dreq->flags = 0; |
| 730 | dreq->error = hdr->error; | 730 | dreq->error = hdr->error; |
| 731 | } | 731 | } |
| 732 | if (dreq->error != 0) | 732 | if (dreq->error == 0) { |
| 733 | bit = NFS_IOHDR_ERROR; | ||
| 734 | else { | ||
| 735 | dreq->count += hdr->good_bytes; | 733 | dreq->count += hdr->good_bytes; |
| 736 | if (test_bit(NFS_IOHDR_NEED_RESCHED, &hdr->flags)) { | 734 | if (nfs_write_need_commit(hdr)) { |
| 737 | dreq->flags = NFS_ODIRECT_RESCHED_WRITES; | ||
| 738 | bit = NFS_IOHDR_NEED_RESCHED; | ||
| 739 | } else if (test_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) { | ||
| 740 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) | 735 | if (dreq->flags == NFS_ODIRECT_RESCHED_WRITES) |
| 741 | bit = NFS_IOHDR_NEED_RESCHED; | 736 | request_commit = true; |
| 742 | else if (dreq->flags == 0) { | 737 | else if (dreq->flags == 0) { |
| 743 | nfs_direct_set_hdr_verf(dreq, hdr); | 738 | nfs_direct_set_hdr_verf(dreq, hdr); |
| 744 | bit = NFS_IOHDR_NEED_COMMIT; | 739 | request_commit = true; |
| 745 | dreq->flags = NFS_ODIRECT_DO_COMMIT; | 740 | dreq->flags = NFS_ODIRECT_DO_COMMIT; |
| 746 | } else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) { | 741 | } else if (dreq->flags == NFS_ODIRECT_DO_COMMIT) { |
| 747 | if (nfs_direct_set_or_cmp_hdr_verf(dreq, hdr)) { | 742 | request_commit = true; |
| 743 | if (nfs_direct_set_or_cmp_hdr_verf(dreq, hdr)) | ||
| 748 | dreq->flags = | 744 | dreq->flags = |
| 749 | NFS_ODIRECT_RESCHED_WRITES; | 745 | NFS_ODIRECT_RESCHED_WRITES; |
| 750 | bit = NFS_IOHDR_NEED_RESCHED; | ||
| 751 | } else | ||
| 752 | bit = NFS_IOHDR_NEED_COMMIT; | ||
| 753 | } | 746 | } |
| 754 | } | 747 | } |
| 755 | } | 748 | } |
| @@ -759,9 +752,7 @@ static void nfs_direct_write_completion(struct nfs_pgio_header *hdr) | |||
| 759 | 752 | ||
| 760 | req = nfs_list_entry(hdr->pages.next); | 753 | req = nfs_list_entry(hdr->pages.next); |
| 761 | nfs_list_remove_request(req); | 754 | nfs_list_remove_request(req); |
| 762 | switch (bit) { | 755 | if (request_commit) { |
| 763 | case NFS_IOHDR_NEED_RESCHED: | ||
| 764 | case NFS_IOHDR_NEED_COMMIT: | ||
| 765 | kref_get(&req->wb_kref); | 756 | kref_get(&req->wb_kref); |
| 766 | nfs_mark_request_commit(req, hdr->lseg, &cinfo); | 757 | nfs_mark_request_commit(req, hdr->lseg, &cinfo); |
| 767 | } | 758 | } |
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; |
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index 68921b01b792..577a36f0a510 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c | |||
| @@ -1002,6 +1002,15 @@ int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode) | |||
| 1002 | } | 1002 | } |
| 1003 | EXPORT_SYMBOL_GPL(nfs_revalidate_inode); | 1003 | EXPORT_SYMBOL_GPL(nfs_revalidate_inode); |
| 1004 | 1004 | ||
| 1005 | int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode) | ||
| 1006 | { | ||
| 1007 | if (!(NFS_I(inode)->cache_validity & | ||
| 1008 | (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_LABEL)) | ||
| 1009 | && !nfs_attribute_cache_expired(inode)) | ||
| 1010 | return NFS_STALE(inode) ? -ESTALE : 0; | ||
| 1011 | return -ECHILD; | ||
| 1012 | } | ||
| 1013 | |||
| 1005 | static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) | 1014 | static int nfs_invalidate_mapping(struct inode *inode, struct address_space *mapping) |
| 1006 | { | 1015 | { |
| 1007 | struct nfs_inode *nfsi = NFS_I(inode); | 1016 | struct nfs_inode *nfsi = NFS_I(inode); |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index e2a45ae5014e..9056622d2230 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -247,11 +247,11 @@ void nfs_set_pgio_error(struct nfs_pgio_header *hdr, int error, loff_t pos); | |||
| 247 | int nfs_iocounter_wait(struct nfs_io_counter *c); | 247 | int nfs_iocounter_wait(struct nfs_io_counter *c); |
| 248 | 248 | ||
| 249 | extern const struct nfs_pageio_ops nfs_pgio_rw_ops; | 249 | extern const struct nfs_pageio_ops nfs_pgio_rw_ops; |
| 250 | struct nfs_rw_header *nfs_rw_header_alloc(const struct nfs_rw_ops *); | 250 | struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *); |
| 251 | void nfs_rw_header_free(struct nfs_pgio_header *); | 251 | void nfs_pgio_header_free(struct nfs_pgio_header *); |
| 252 | void nfs_pgio_data_release(struct nfs_pgio_data *); | 252 | void nfs_pgio_data_destroy(struct nfs_pgio_header *); |
| 253 | int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *); | 253 | int nfs_generic_pgio(struct nfs_pageio_descriptor *, struct nfs_pgio_header *); |
| 254 | int nfs_initiate_pgio(struct rpc_clnt *, struct nfs_pgio_data *, | 254 | int nfs_initiate_pgio(struct rpc_clnt *, struct nfs_pgio_header *, |
| 255 | const struct rpc_call_ops *, int, int); | 255 | const struct rpc_call_ops *, int, int); |
| 256 | void nfs_free_request(struct nfs_page *req); | 256 | void nfs_free_request(struct nfs_page *req); |
| 257 | 257 | ||
| @@ -451,6 +451,7 @@ int nfs_scan_commit(struct inode *inode, struct list_head *dst, | |||
| 451 | void nfs_mark_request_commit(struct nfs_page *req, | 451 | void nfs_mark_request_commit(struct nfs_page *req, |
| 452 | struct pnfs_layout_segment *lseg, | 452 | struct pnfs_layout_segment *lseg, |
| 453 | struct nfs_commit_info *cinfo); | 453 | struct nfs_commit_info *cinfo); |
| 454 | int nfs_write_need_commit(struct nfs_pgio_header *); | ||
| 454 | int nfs_generic_commit_list(struct inode *inode, struct list_head *head, | 455 | int nfs_generic_commit_list(struct inode *inode, struct list_head *head, |
| 455 | int how, struct nfs_commit_info *cinfo); | 456 | int how, struct nfs_commit_info *cinfo); |
| 456 | void nfs_retry_commit(struct list_head *page_list, | 457 | void nfs_retry_commit(struct list_head *page_list, |
| @@ -491,7 +492,7 @@ static inline void nfs_inode_dio_wait(struct inode *inode) | |||
| 491 | extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq); | 492 | extern ssize_t nfs_dreq_bytes_left(struct nfs_direct_req *dreq); |
| 492 | 493 | ||
| 493 | /* nfs4proc.c */ | 494 | /* nfs4proc.c */ |
| 494 | extern void __nfs4_read_done_cb(struct nfs_pgio_data *); | 495 | extern void __nfs4_read_done_cb(struct nfs_pgio_header *); |
| 495 | extern struct nfs_client *nfs4_init_client(struct nfs_client *clp, | 496 | extern struct nfs_client *nfs4_init_client(struct nfs_client *clp, |
| 496 | const struct rpc_timeout *timeparms, | 497 | const struct rpc_timeout *timeparms, |
| 497 | const char *ip_addr); | 498 | const char *ip_addr); |
diff --git a/fs/nfs/nfs3acl.c b/fs/nfs/nfs3acl.c index 8f854dde4150..d0fec260132a 100644 --- a/fs/nfs/nfs3acl.c +++ b/fs/nfs/nfs3acl.c | |||
| @@ -256,7 +256,7 @@ nfs3_list_one_acl(struct inode *inode, int type, const char *name, void *data, | |||
| 256 | char *p = data + *result; | 256 | char *p = data + *result; |
| 257 | 257 | ||
| 258 | acl = get_acl(inode, type); | 258 | acl = get_acl(inode, type); |
| 259 | if (!acl) | 259 | if (IS_ERR_OR_NULL(acl)) |
| 260 | return 0; | 260 | return 0; |
| 261 | 261 | ||
| 262 | posix_acl_release(acl); | 262 | posix_acl_release(acl); |
diff --git a/fs/nfs/nfs3proc.c b/fs/nfs/nfs3proc.c index f0afa291fd58..809670eba52a 100644 --- a/fs/nfs/nfs3proc.c +++ b/fs/nfs/nfs3proc.c | |||
| @@ -795,41 +795,44 @@ nfs3_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
| 795 | return status; | 795 | return status; |
| 796 | } | 796 | } |
| 797 | 797 | ||
| 798 | static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_data *data) | 798 | static int nfs3_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) |
| 799 | { | 799 | { |
| 800 | struct inode *inode = data->header->inode; | 800 | struct inode *inode = hdr->inode; |
| 801 | 801 | ||
| 802 | if (nfs3_async_handle_jukebox(task, inode)) | 802 | if (nfs3_async_handle_jukebox(task, inode)) |
| 803 | return -EAGAIN; | 803 | return -EAGAIN; |
| 804 | 804 | ||
| 805 | nfs_invalidate_atime(inode); | 805 | nfs_invalidate_atime(inode); |
| 806 | nfs_refresh_inode(inode, &data->fattr); | 806 | nfs_refresh_inode(inode, &hdr->fattr); |
| 807 | return 0; | 807 | return 0; |
| 808 | } | 808 | } |
| 809 | 809 | ||
| 810 | static void nfs3_proc_read_setup(struct nfs_pgio_data *data, struct rpc_message *msg) | 810 | static void nfs3_proc_read_setup(struct nfs_pgio_header *hdr, |
| 811 | struct rpc_message *msg) | ||
| 811 | { | 812 | { |
| 812 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ]; | 813 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_READ]; |
| 813 | } | 814 | } |
| 814 | 815 | ||
| 815 | static int nfs3_proc_pgio_rpc_prepare(struct rpc_task *task, struct nfs_pgio_data *data) | 816 | static int nfs3_proc_pgio_rpc_prepare(struct rpc_task *task, |
| 817 | struct nfs_pgio_header *hdr) | ||
| 816 | { | 818 | { |
| 817 | rpc_call_start(task); | 819 | rpc_call_start(task); |
| 818 | return 0; | 820 | return 0; |
| 819 | } | 821 | } |
| 820 | 822 | ||
| 821 | static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_data *data) | 823 | static int nfs3_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) |
| 822 | { | 824 | { |
| 823 | struct inode *inode = data->header->inode; | 825 | struct inode *inode = hdr->inode; |
| 824 | 826 | ||
| 825 | if (nfs3_async_handle_jukebox(task, inode)) | 827 | if (nfs3_async_handle_jukebox(task, inode)) |
| 826 | return -EAGAIN; | 828 | return -EAGAIN; |
| 827 | if (task->tk_status >= 0) | 829 | if (task->tk_status >= 0) |
| 828 | nfs_post_op_update_inode_force_wcc(inode, data->res.fattr); | 830 | nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr); |
| 829 | return 0; | 831 | return 0; |
| 830 | } | 832 | } |
| 831 | 833 | ||
| 832 | static void nfs3_proc_write_setup(struct nfs_pgio_data *data, struct rpc_message *msg) | 834 | static void nfs3_proc_write_setup(struct nfs_pgio_header *hdr, |
| 835 | struct rpc_message *msg) | ||
| 833 | { | 836 | { |
| 834 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE]; | 837 | msg->rpc_proc = &nfs3_procedures[NFS3PROC_WRITE]; |
| 835 | } | 838 | } |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index ba2affa51941..92193eddb41d 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -54,7 +54,7 @@ struct nfs4_minor_version_ops { | |||
| 54 | const nfs4_stateid *); | 54 | const nfs4_stateid *); |
| 55 | int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, | 55 | int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, |
| 56 | struct nfs_fsinfo *); | 56 | struct nfs_fsinfo *); |
| 57 | int (*free_lock_state)(struct nfs_server *, | 57 | void (*free_lock_state)(struct nfs_server *, |
| 58 | struct nfs4_lock_state *); | 58 | struct nfs4_lock_state *); |
| 59 | const struct rpc_call_ops *call_sync_ops; | 59 | const struct rpc_call_ops *call_sync_ops; |
| 60 | const struct nfs4_state_recovery_ops *reboot_recovery_ops; | 60 | const struct nfs4_state_recovery_ops *reboot_recovery_ops; |
| @@ -129,27 +129,17 @@ enum { | |||
| 129 | * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) | 129 | * LOCK: one nfs4_state (LOCK) to hold the lock stateid nfs4_state(OPEN) |
| 130 | */ | 130 | */ |
| 131 | 131 | ||
| 132 | struct nfs4_lock_owner { | ||
| 133 | unsigned int lo_type; | ||
| 134 | #define NFS4_ANY_LOCK_TYPE (0U) | ||
| 135 | #define NFS4_FLOCK_LOCK_TYPE (1U << 0) | ||
| 136 | #define NFS4_POSIX_LOCK_TYPE (1U << 1) | ||
| 137 | union { | ||
| 138 | fl_owner_t posix_owner; | ||
| 139 | pid_t flock_owner; | ||
| 140 | } lo_u; | ||
| 141 | }; | ||
| 142 | |||
| 143 | struct nfs4_lock_state { | 132 | struct nfs4_lock_state { |
| 144 | struct list_head ls_locks; /* Other lock stateids */ | 133 | struct list_head ls_locks; /* Other lock stateids */ |
| 145 | struct nfs4_state * ls_state; /* Pointer to open state */ | 134 | struct nfs4_state * ls_state; /* Pointer to open state */ |
| 146 | #define NFS_LOCK_INITIALIZED 0 | 135 | #define NFS_LOCK_INITIALIZED 0 |
| 147 | #define NFS_LOCK_LOST 1 | 136 | #define NFS_LOCK_LOST 1 |
| 148 | unsigned long ls_flags; | 137 | unsigned long ls_flags; |
| 149 | struct nfs_seqid_counter ls_seqid; | 138 | struct nfs_seqid_counter ls_seqid; |
| 150 | nfs4_stateid ls_stateid; | 139 | nfs4_stateid ls_stateid; |
| 151 | atomic_t ls_count; | 140 | atomic_t ls_count; |
| 152 | struct nfs4_lock_owner ls_owner; | 141 | fl_owner_t ls_owner; |
| 142 | struct work_struct ls_release; | ||
| 153 | }; | 143 | }; |
| 154 | 144 | ||
| 155 | /* bits for nfs4_state->flags */ | 145 | /* bits for nfs4_state->flags */ |
| @@ -337,11 +327,11 @@ nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_mode, | |||
| 337 | */ | 327 | */ |
| 338 | static inline void | 328 | static inline void |
| 339 | nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp, | 329 | nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp, |
| 340 | struct rpc_message *msg, struct nfs_pgio_data *wdata) | 330 | struct rpc_message *msg, struct nfs_pgio_header *hdr) |
| 341 | { | 331 | { |
| 342 | if (_nfs4_state_protect(clp, NFS_SP4_MACH_CRED_WRITE, clntp, msg) && | 332 | if (_nfs4_state_protect(clp, NFS_SP4_MACH_CRED_WRITE, clntp, msg) && |
| 343 | !test_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags)) | 333 | !test_bit(NFS_SP4_MACH_CRED_COMMIT, &clp->cl_sp4_flags)) |
| 344 | wdata->args.stable = NFS_FILE_SYNC; | 334 | hdr->args.stable = NFS_FILE_SYNC; |
| 345 | } | 335 | } |
| 346 | #else /* CONFIG_NFS_v4_1 */ | 336 | #else /* CONFIG_NFS_v4_1 */ |
| 347 | static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server) | 337 | static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *server) |
| @@ -369,7 +359,7 @@ nfs4_state_protect(struct nfs_client *clp, unsigned long sp4_flags, | |||
| 369 | 359 | ||
| 370 | static inline void | 360 | static inline void |
| 371 | nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp, | 361 | nfs4_state_protect_write(struct nfs_client *clp, struct rpc_clnt **clntp, |
| 372 | struct rpc_message *msg, struct nfs_pgio_data *wdata) | 362 | struct rpc_message *msg, struct nfs_pgio_header *hdr) |
| 373 | { | 363 | { |
| 374 | } | 364 | } |
| 375 | #endif /* CONFIG_NFS_V4_1 */ | 365 | #endif /* CONFIG_NFS_V4_1 */ |
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index aa9ef4876046..53e435a95260 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c | |||
| @@ -855,6 +855,11 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, | |||
| 855 | }; | 855 | }; |
| 856 | struct rpc_timeout ds_timeout; | 856 | struct rpc_timeout ds_timeout; |
| 857 | struct nfs_client *clp; | 857 | struct nfs_client *clp; |
| 858 | char buf[INET6_ADDRSTRLEN + 1]; | ||
| 859 | |||
| 860 | if (rpc_ntop(ds_addr, buf, sizeof(buf)) <= 0) | ||
| 861 | return ERR_PTR(-EINVAL); | ||
| 862 | cl_init.hostname = buf; | ||
| 858 | 863 | ||
| 859 | /* | 864 | /* |
| 860 | * Set an authflavor equual to the MDS value. Use the MDS nfs_client | 865 | * Set an authflavor equual to the MDS value. Use the MDS nfs_client |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index 4bf3d97cc5a0..75ae8d22f067 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
| @@ -1952,6 +1952,14 @@ static int _nfs4_recover_proc_open(struct nfs4_opendata *data) | |||
| 1952 | return status; | 1952 | return status; |
| 1953 | } | 1953 | } |
| 1954 | 1954 | ||
| 1955 | /* | ||
| 1956 | * Additional permission checks in order to distinguish between an | ||
| 1957 | * open for read, and an open for execute. This works around the | ||
| 1958 | * fact that NFSv4 OPEN treats read and execute permissions as being | ||
| 1959 | * the same. | ||
| 1960 | * Note that in the non-execute case, we want to turn off permission | ||
| 1961 | * checking if we just created a new file (POSIX open() semantics). | ||
| 1962 | */ | ||
| 1955 | static int nfs4_opendata_access(struct rpc_cred *cred, | 1963 | static int nfs4_opendata_access(struct rpc_cred *cred, |
| 1956 | struct nfs4_opendata *opendata, | 1964 | struct nfs4_opendata *opendata, |
| 1957 | struct nfs4_state *state, fmode_t fmode, | 1965 | struct nfs4_state *state, fmode_t fmode, |
| @@ -1966,14 +1974,14 @@ static int nfs4_opendata_access(struct rpc_cred *cred, | |||
| 1966 | return 0; | 1974 | return 0; |
| 1967 | 1975 | ||
| 1968 | mask = 0; | 1976 | mask = 0; |
| 1969 | /* don't check MAY_WRITE - a newly created file may not have | 1977 | /* |
| 1970 | * write mode bits, but POSIX allows the creating process to write. | 1978 | * Use openflags to check for exec, because fmode won't |
| 1971 | * use openflags to check for exec, because fmode won't | 1979 | * always have FMODE_EXEC set when file open for exec. |
| 1972 | * always have FMODE_EXEC set when file open for exec. */ | 1980 | */ |
| 1973 | if (openflags & __FMODE_EXEC) { | 1981 | if (openflags & __FMODE_EXEC) { |
| 1974 | /* ONLY check for exec rights */ | 1982 | /* ONLY check for exec rights */ |
| 1975 | mask = MAY_EXEC; | 1983 | mask = MAY_EXEC; |
| 1976 | } else if (fmode & FMODE_READ) | 1984 | } else if ((fmode & FMODE_READ) && !opendata->file_created) |
| 1977 | mask = MAY_READ; | 1985 | mask = MAY_READ; |
| 1978 | 1986 | ||
| 1979 | cache.cred = cred; | 1987 | cache.cred = cred; |
| @@ -2216,8 +2224,15 @@ static int _nfs4_open_and_get_state(struct nfs4_opendata *opendata, | |||
| 2216 | seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); | 2224 | seq = raw_seqcount_begin(&sp->so_reclaim_seqcount); |
| 2217 | 2225 | ||
| 2218 | ret = _nfs4_proc_open(opendata); | 2226 | ret = _nfs4_proc_open(opendata); |
| 2219 | if (ret != 0) | 2227 | if (ret != 0) { |
| 2228 | if (ret == -ENOENT) { | ||
| 2229 | d_drop(opendata->dentry); | ||
| 2230 | d_add(opendata->dentry, NULL); | ||
| 2231 | nfs_set_verifier(opendata->dentry, | ||
| 2232 | nfs_save_change_attribute(opendata->dir->d_inode)); | ||
| 2233 | } | ||
| 2220 | goto out; | 2234 | goto out; |
| 2235 | } | ||
| 2221 | 2236 | ||
| 2222 | state = nfs4_opendata_to_nfs4_state(opendata); | 2237 | state = nfs4_opendata_to_nfs4_state(opendata); |
| 2223 | ret = PTR_ERR(state); | 2238 | ret = PTR_ERR(state); |
| @@ -2647,6 +2662,48 @@ static const struct rpc_call_ops nfs4_close_ops = { | |||
| 2647 | .rpc_release = nfs4_free_closedata, | 2662 | .rpc_release = nfs4_free_closedata, |
| 2648 | }; | 2663 | }; |
| 2649 | 2664 | ||
| 2665 | static bool nfs4_state_has_opener(struct nfs4_state *state) | ||
| 2666 | { | ||
| 2667 | /* first check existing openers */ | ||
| 2668 | if (test_bit(NFS_O_RDONLY_STATE, &state->flags) != 0 && | ||
| 2669 | state->n_rdonly != 0) | ||
| 2670 | return true; | ||
| 2671 | |||
| 2672 | if (test_bit(NFS_O_WRONLY_STATE, &state->flags) != 0 && | ||
| 2673 | state->n_wronly != 0) | ||
| 2674 | return true; | ||
| 2675 | |||
| 2676 | if (test_bit(NFS_O_RDWR_STATE, &state->flags) != 0 && | ||
| 2677 | state->n_rdwr != 0) | ||
| 2678 | return true; | ||
| 2679 | |||
| 2680 | return false; | ||
| 2681 | } | ||
| 2682 | |||
| 2683 | static bool nfs4_roc(struct inode *inode) | ||
| 2684 | { | ||
| 2685 | struct nfs_inode *nfsi = NFS_I(inode); | ||
| 2686 | struct nfs_open_context *ctx; | ||
| 2687 | struct nfs4_state *state; | ||
| 2688 | |||
| 2689 | spin_lock(&inode->i_lock); | ||
| 2690 | list_for_each_entry(ctx, &nfsi->open_files, list) { | ||
| 2691 | state = ctx->state; | ||
| 2692 | if (state == NULL) | ||
| 2693 | continue; | ||
| 2694 | if (nfs4_state_has_opener(state)) { | ||
| 2695 | spin_unlock(&inode->i_lock); | ||
| 2696 | return false; | ||
| 2697 | } | ||
| 2698 | } | ||
| 2699 | spin_unlock(&inode->i_lock); | ||
| 2700 | |||
| 2701 | if (nfs4_check_delegation(inode, FMODE_READ)) | ||
| 2702 | return false; | ||
| 2703 | |||
| 2704 | return pnfs_roc(inode); | ||
| 2705 | } | ||
| 2706 | |||
| 2650 | /* | 2707 | /* |
| 2651 | * It is possible for data to be read/written from a mem-mapped file | 2708 | * It is possible for data to be read/written from a mem-mapped file |
| 2652 | * after the sys_close call (which hits the vfs layer as a flush). | 2709 | * after the sys_close call (which hits the vfs layer as a flush). |
| @@ -2697,7 +2754,7 @@ int nfs4_do_close(struct nfs4_state *state, gfp_t gfp_mask, int wait) | |||
| 2697 | calldata->res.fattr = &calldata->fattr; | 2754 | calldata->res.fattr = &calldata->fattr; |
| 2698 | calldata->res.seqid = calldata->arg.seqid; | 2755 | calldata->res.seqid = calldata->arg.seqid; |
| 2699 | calldata->res.server = server; | 2756 | calldata->res.server = server; |
| 2700 | calldata->roc = pnfs_roc(state->inode); | 2757 | calldata->roc = nfs4_roc(state->inode); |
| 2701 | nfs_sb_active(calldata->inode->i_sb); | 2758 | nfs_sb_active(calldata->inode->i_sb); |
| 2702 | 2759 | ||
| 2703 | msg.rpc_argp = &calldata->arg; | 2760 | msg.rpc_argp = &calldata->arg; |
| @@ -4033,24 +4090,25 @@ static bool nfs4_error_stateid_expired(int err) | |||
| 4033 | return false; | 4090 | return false; |
| 4034 | } | 4091 | } |
| 4035 | 4092 | ||
| 4036 | void __nfs4_read_done_cb(struct nfs_pgio_data *data) | 4093 | void __nfs4_read_done_cb(struct nfs_pgio_header *hdr) |
| 4037 | { | 4094 | { |
| 4038 | nfs_invalidate_atime(data->header->inode); | 4095 | nfs_invalidate_atime(hdr->inode); |
| 4039 | } | 4096 | } |
| 4040 | 4097 | ||
| 4041 | static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_data *data) | 4098 | static int nfs4_read_done_cb(struct rpc_task *task, struct nfs_pgio_header *hdr) |
| 4042 | { | 4099 | { |
| 4043 | struct nfs_server *server = NFS_SERVER(data->header->inode); | 4100 | struct nfs_server *server = NFS_SERVER(hdr->inode); |
| 4044 | 4101 | ||
| 4045 | trace_nfs4_read(data, task->tk_status); | 4102 | trace_nfs4_read(hdr, task->tk_status); |
| 4046 | if (nfs4_async_handle_error(task, server, data->args.context->state) == -EAGAIN) { | 4103 | if (nfs4_async_handle_error(task, server, |
| 4104 | hdr->args.context->state) == -EAGAIN) { | ||
| 4047 | rpc_restart_call_prepare(task); | 4105 | rpc_restart_call_prepare(task); |
| 4048 | return -EAGAIN; | 4106 | return -EAGAIN; |
| 4049 | } | 4107 | } |
| 4050 | 4108 | ||
| 4051 | __nfs4_read_done_cb(data); | 4109 | __nfs4_read_done_cb(hdr); |
| 4052 | if (task->tk_status > 0) | 4110 | if (task->tk_status > 0) |
| 4053 | renew_lease(server, data->timestamp); | 4111 | renew_lease(server, hdr->timestamp); |
| 4054 | return 0; | 4112 | return 0; |
| 4055 | } | 4113 | } |
| 4056 | 4114 | ||
| @@ -4068,54 +4126,59 @@ static bool nfs4_read_stateid_changed(struct rpc_task *task, | |||
| 4068 | return true; | 4126 | return true; |
| 4069 | } | 4127 | } |
| 4070 | 4128 | ||
| 4071 | static int nfs4_read_done(struct rpc_task *task, struct nfs_pgio_data *data) | 4129 | static int nfs4_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) |
| 4072 | { | 4130 | { |
| 4073 | 4131 | ||
| 4074 | dprintk("--> %s\n", __func__); | 4132 | dprintk("--> %s\n", __func__); |
| 4075 | 4133 | ||
| 4076 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | 4134 | if (!nfs4_sequence_done(task, &hdr->res.seq_res)) |
| 4077 | return -EAGAIN; | 4135 | return -EAGAIN; |
| 4078 | if (nfs4_read_stateid_changed(task, &data->args)) | 4136 | if (nfs4_read_stateid_changed(task, &hdr->args)) |
| 4079 | return -EAGAIN; | 4137 | return -EAGAIN; |
| 4080 | return data->pgio_done_cb ? data->pgio_done_cb(task, data) : | 4138 | return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) : |
| 4081 | nfs4_read_done_cb(task, data); | 4139 | nfs4_read_done_cb(task, hdr); |
| 4082 | } | 4140 | } |
| 4083 | 4141 | ||
| 4084 | static void nfs4_proc_read_setup(struct nfs_pgio_data *data, struct rpc_message *msg) | 4142 | static void nfs4_proc_read_setup(struct nfs_pgio_header *hdr, |
| 4143 | struct rpc_message *msg) | ||
| 4085 | { | 4144 | { |
| 4086 | data->timestamp = jiffies; | 4145 | hdr->timestamp = jiffies; |
| 4087 | data->pgio_done_cb = nfs4_read_done_cb; | 4146 | hdr->pgio_done_cb = nfs4_read_done_cb; |
| 4088 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; | 4147 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_READ]; |
| 4089 | nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); | 4148 | nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 0); |
| 4090 | } | 4149 | } |
| 4091 | 4150 | ||
| 4092 | static int nfs4_proc_pgio_rpc_prepare(struct rpc_task *task, struct nfs_pgio_data *data) | 4151 | static int nfs4_proc_pgio_rpc_prepare(struct rpc_task *task, |
| 4152 | struct nfs_pgio_header *hdr) | ||
| 4093 | { | 4153 | { |
| 4094 | if (nfs4_setup_sequence(NFS_SERVER(data->header->inode), | 4154 | if (nfs4_setup_sequence(NFS_SERVER(hdr->inode), |
| 4095 | &data->args.seq_args, | 4155 | &hdr->args.seq_args, |
| 4096 | &data->res.seq_res, | 4156 | &hdr->res.seq_res, |
| 4097 | task)) | 4157 | task)) |
| 4098 | return 0; | 4158 | return 0; |
| 4099 | if (nfs4_set_rw_stateid(&data->args.stateid, data->args.context, | 4159 | if (nfs4_set_rw_stateid(&hdr->args.stateid, hdr->args.context, |
| 4100 | data->args.lock_context, data->header->rw_ops->rw_mode) == -EIO) | 4160 | hdr->args.lock_context, |
| 4161 | hdr->rw_ops->rw_mode) == -EIO) | ||
| 4101 | return -EIO; | 4162 | return -EIO; |
| 4102 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &data->args.context->flags))) | 4163 | if (unlikely(test_bit(NFS_CONTEXT_BAD, &hdr->args.context->flags))) |
| 4103 | return -EIO; | 4164 | return -EIO; |
| 4104 | return 0; | 4165 | return 0; |
| 4105 | } | 4166 | } |
| 4106 | 4167 | ||
| 4107 | static int nfs4_write_done_cb(struct rpc_task *task, struct nfs_pgio_data *data) | 4168 | static int nfs4_write_done_cb(struct rpc_task *task, |
| 4169 | struct nfs_pgio_header *hdr) | ||
| 4108 | { | 4170 | { |
| 4109 | struct inode *inode = data->header->inode; | 4171 | struct inode *inode = hdr->inode; |
| 4110 | 4172 | ||
| 4111 | trace_nfs4_write(data, task->tk_status); | 4173 | trace_nfs4_write(hdr, task->tk_status); |
| 4112 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), data->args.context->state) == -EAGAIN) { | 4174 | if (nfs4_async_handle_error(task, NFS_SERVER(inode), |
| 4175 | hdr->args.context->state) == -EAGAIN) { | ||
| 4113 | rpc_restart_call_prepare(task); | 4176 | rpc_restart_call_prepare(task); |
| 4114 | return -EAGAIN; | 4177 | return -EAGAIN; |
| 4115 | } | 4178 | } |
| 4116 | if (task->tk_status >= 0) { | 4179 | if (task->tk_status >= 0) { |
| 4117 | renew_lease(NFS_SERVER(inode), data->timestamp); | 4180 | renew_lease(NFS_SERVER(inode), hdr->timestamp); |
| 4118 | nfs_post_op_update_inode_force_wcc(inode, &data->fattr); | 4181 | nfs_post_op_update_inode_force_wcc(inode, &hdr->fattr); |
| 4119 | } | 4182 | } |
| 4120 | return 0; | 4183 | return 0; |
| 4121 | } | 4184 | } |
| @@ -4134,23 +4197,21 @@ static bool nfs4_write_stateid_changed(struct rpc_task *task, | |||
| 4134 | return true; | 4197 | return true; |
| 4135 | } | 4198 | } |
| 4136 | 4199 | ||
| 4137 | static int nfs4_write_done(struct rpc_task *task, struct nfs_pgio_data *data) | 4200 | static int nfs4_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) |
| 4138 | { | 4201 | { |
| 4139 | if (!nfs4_sequence_done(task, &data->res.seq_res)) | 4202 | if (!nfs4_sequence_done(task, &hdr->res.seq_res)) |
| 4140 | return -EAGAIN; | 4203 | return -EAGAIN; |
| 4141 | if (nfs4_write_stateid_changed(task, &data->args)) | 4204 | if (nfs4_write_stateid_changed(task, &hdr->args)) |
| 4142 | return -EAGAIN; | 4205 | return -EAGAIN; |
| 4143 | return data->pgio_done_cb ? data->pgio_done_cb(task, data) : | 4206 | return hdr->pgio_done_cb ? hdr->pgio_done_cb(task, hdr) : |
| 4144 | nfs4_write_done_cb(task, data); | 4207 | nfs4_write_done_cb(task, hdr); |
| 4145 | } | 4208 | } |
| 4146 | 4209 | ||
| 4147 | static | 4210 | static |
| 4148 | bool nfs4_write_need_cache_consistency_data(const struct nfs_pgio_data *data) | 4211 | bool nfs4_write_need_cache_consistency_data(struct nfs_pgio_header *hdr) |
| 4149 | { | 4212 | { |
| 4150 | const struct nfs_pgio_header *hdr = data->header; | ||
| 4151 | |||
| 4152 | /* Don't request attributes for pNFS or O_DIRECT writes */ | 4213 | /* Don't request attributes for pNFS or O_DIRECT writes */ |
| 4153 | if (data->ds_clp != NULL || hdr->dreq != NULL) | 4214 | if (hdr->ds_clp != NULL || hdr->dreq != NULL) |
| 4154 | return false; | 4215 | return false; |
| 4155 | /* Otherwise, request attributes if and only if we don't hold | 4216 | /* Otherwise, request attributes if and only if we don't hold |
| 4156 | * a delegation | 4217 | * a delegation |
| @@ -4158,23 +4219,24 @@ bool nfs4_write_need_cache_consistency_data(const struct nfs_pgio_data *data) | |||
| 4158 | return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0; | 4219 | return nfs4_have_delegation(hdr->inode, FMODE_READ) == 0; |
| 4159 | } | 4220 | } |
| 4160 | 4221 | ||
| 4161 | static void nfs4_proc_write_setup(struct nfs_pgio_data *data, struct rpc_message *msg) | 4222 | static void nfs4_proc_write_setup(struct nfs_pgio_header *hdr, |
| 4223 | struct rpc_message *msg) | ||
| 4162 | { | 4224 | { |
| 4163 | struct nfs_server *server = NFS_SERVER(data->header->inode); | 4225 | struct nfs_server *server = NFS_SERVER(hdr->inode); |
| 4164 | 4226 | ||
| 4165 | if (!nfs4_write_need_cache_consistency_data(data)) { | 4227 | if (!nfs4_write_need_cache_consistency_data(hdr)) { |
| 4166 | data->args.bitmask = NULL; | 4228 | hdr->args.bitmask = NULL; |
| 4167 | data->res.fattr = NULL; | 4229 | hdr->res.fattr = NULL; |
| 4168 | } else | 4230 | } else |
| 4169 | data->args.bitmask = server->cache_consistency_bitmask; | 4231 | hdr->args.bitmask = server->cache_consistency_bitmask; |
| 4170 | 4232 | ||
| 4171 | if (!data->pgio_done_cb) | 4233 | if (!hdr->pgio_done_cb) |
| 4172 | data->pgio_done_cb = nfs4_write_done_cb; | 4234 | hdr->pgio_done_cb = nfs4_write_done_cb; |
| 4173 | data->res.server = server; | 4235 | hdr->res.server = server; |
| 4174 | data->timestamp = jiffies; | 4236 | hdr->timestamp = jiffies; |
| 4175 | 4237 | ||
| 4176 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; | 4238 | msg->rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_WRITE]; |
| 4177 | nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 1); | 4239 | nfs4_init_sequence(&hdr->args.seq_args, &hdr->res.seq_res, 1); |
| 4178 | } | 4240 | } |
| 4179 | 4241 | ||
| 4180 | static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data) | 4242 | static void nfs4_proc_commit_rpc_prepare(struct rpc_task *task, struct nfs_commit_data *data) |
| @@ -4881,6 +4943,18 @@ nfs4_init_callback_netid(const struct nfs_client *clp, char *buf, size_t len) | |||
| 4881 | return scnprintf(buf, len, "tcp"); | 4943 | return scnprintf(buf, len, "tcp"); |
| 4882 | } | 4944 | } |
| 4883 | 4945 | ||
| 4946 | static void nfs4_setclientid_done(struct rpc_task *task, void *calldata) | ||
| 4947 | { | ||
| 4948 | struct nfs4_setclientid *sc = calldata; | ||
| 4949 | |||
| 4950 | if (task->tk_status == 0) | ||
| 4951 | sc->sc_cred = get_rpccred(task->tk_rqstp->rq_cred); | ||
| 4952 | } | ||
| 4953 | |||
| 4954 | static const struct rpc_call_ops nfs4_setclientid_ops = { | ||
| 4955 | .rpc_call_done = nfs4_setclientid_done, | ||
| 4956 | }; | ||
| 4957 | |||
| 4884 | /** | 4958 | /** |
| 4885 | * nfs4_proc_setclientid - Negotiate client ID | 4959 | * nfs4_proc_setclientid - Negotiate client ID |
| 4886 | * @clp: state data structure | 4960 | * @clp: state data structure |
| @@ -4907,6 +4981,14 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
| 4907 | .rpc_resp = res, | 4981 | .rpc_resp = res, |
| 4908 | .rpc_cred = cred, | 4982 | .rpc_cred = cred, |
| 4909 | }; | 4983 | }; |
| 4984 | struct rpc_task *task; | ||
| 4985 | struct rpc_task_setup task_setup_data = { | ||
| 4986 | .rpc_client = clp->cl_rpcclient, | ||
| 4987 | .rpc_message = &msg, | ||
| 4988 | .callback_ops = &nfs4_setclientid_ops, | ||
| 4989 | .callback_data = &setclientid, | ||
| 4990 | .flags = RPC_TASK_TIMEOUT, | ||
| 4991 | }; | ||
| 4910 | int status; | 4992 | int status; |
| 4911 | 4993 | ||
| 4912 | /* nfs_client_id4 */ | 4994 | /* nfs_client_id4 */ |
| @@ -4933,7 +5015,18 @@ int nfs4_proc_setclientid(struct nfs_client *clp, u32 program, | |||
| 4933 | dprintk("NFS call setclientid auth=%s, '%.*s'\n", | 5015 | dprintk("NFS call setclientid auth=%s, '%.*s'\n", |
| 4934 | clp->cl_rpcclient->cl_auth->au_ops->au_name, | 5016 | clp->cl_rpcclient->cl_auth->au_ops->au_name, |
| 4935 | setclientid.sc_name_len, setclientid.sc_name); | 5017 | setclientid.sc_name_len, setclientid.sc_name); |
| 4936 | status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); | 5018 | task = rpc_run_task(&task_setup_data); |
| 5019 | if (IS_ERR(task)) { | ||
| 5020 | status = PTR_ERR(task); | ||
| 5021 | goto out; | ||
| 5022 | } | ||
| 5023 | status = task->tk_status; | ||
| 5024 | if (setclientid.sc_cred) { | ||
| 5025 | clp->cl_acceptor = rpcauth_stringify_acceptor(setclientid.sc_cred); | ||
| 5026 | put_rpccred(setclientid.sc_cred); | ||
| 5027 | } | ||
| 5028 | rpc_put_task(task); | ||
| 5029 | out: | ||
| 4937 | trace_nfs4_setclientid(clp, status); | 5030 | trace_nfs4_setclientid(clp, status); |
| 4938 | dprintk("NFS reply setclientid: %d\n", status); | 5031 | dprintk("NFS reply setclientid: %d\n", status); |
| 4939 | return status; | 5032 | return status; |
| @@ -4975,6 +5068,9 @@ struct nfs4_delegreturndata { | |||
| 4975 | unsigned long timestamp; | 5068 | unsigned long timestamp; |
| 4976 | struct nfs_fattr fattr; | 5069 | struct nfs_fattr fattr; |
| 4977 | int rpc_status; | 5070 | int rpc_status; |
| 5071 | struct inode *inode; | ||
| 5072 | bool roc; | ||
| 5073 | u32 roc_barrier; | ||
| 4978 | }; | 5074 | }; |
| 4979 | 5075 | ||
| 4980 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | 5076 | static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) |
| @@ -4988,7 +5084,6 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
| 4988 | switch (task->tk_status) { | 5084 | switch (task->tk_status) { |
| 4989 | case 0: | 5085 | case 0: |
| 4990 | renew_lease(data->res.server, data->timestamp); | 5086 | renew_lease(data->res.server, data->timestamp); |
| 4991 | break; | ||
| 4992 | case -NFS4ERR_ADMIN_REVOKED: | 5087 | case -NFS4ERR_ADMIN_REVOKED: |
| 4993 | case -NFS4ERR_DELEG_REVOKED: | 5088 | case -NFS4ERR_DELEG_REVOKED: |
| 4994 | case -NFS4ERR_BAD_STATEID: | 5089 | case -NFS4ERR_BAD_STATEID: |
| @@ -4996,6 +5091,8 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
| 4996 | case -NFS4ERR_STALE_STATEID: | 5091 | case -NFS4ERR_STALE_STATEID: |
| 4997 | case -NFS4ERR_EXPIRED: | 5092 | case -NFS4ERR_EXPIRED: |
| 4998 | task->tk_status = 0; | 5093 | task->tk_status = 0; |
| 5094 | if (data->roc) | ||
| 5095 | pnfs_roc_set_barrier(data->inode, data->roc_barrier); | ||
| 4999 | break; | 5096 | break; |
| 5000 | default: | 5097 | default: |
| 5001 | if (nfs4_async_handle_error(task, data->res.server, NULL) == | 5098 | if (nfs4_async_handle_error(task, data->res.server, NULL) == |
| @@ -5009,6 +5106,10 @@ static void nfs4_delegreturn_done(struct rpc_task *task, void *calldata) | |||
| 5009 | 5106 | ||
| 5010 | static void nfs4_delegreturn_release(void *calldata) | 5107 | static void nfs4_delegreturn_release(void *calldata) |
| 5011 | { | 5108 | { |
| 5109 | struct nfs4_delegreturndata *data = calldata; | ||
| 5110 | |||
| 5111 | if (data->roc) | ||
| 5112 | pnfs_roc_release(data->inode); | ||
| 5012 | kfree(calldata); | 5113 | kfree(calldata); |
| 5013 | } | 5114 | } |
| 5014 | 5115 | ||
| @@ -5018,6 +5119,10 @@ static void nfs4_delegreturn_prepare(struct rpc_task *task, void *data) | |||
| 5018 | 5119 | ||
| 5019 | d_data = (struct nfs4_delegreturndata *)data; | 5120 | d_data = (struct nfs4_delegreturndata *)data; |
| 5020 | 5121 | ||
| 5122 | if (d_data->roc && | ||
| 5123 | pnfs_roc_drain(d_data->inode, &d_data->roc_barrier, task)) | ||
| 5124 | return; | ||
| 5125 | |||
| 5021 | nfs4_setup_sequence(d_data->res.server, | 5126 | nfs4_setup_sequence(d_data->res.server, |
| 5022 | &d_data->args.seq_args, | 5127 | &d_data->args.seq_args, |
| 5023 | &d_data->res.seq_res, | 5128 | &d_data->res.seq_res, |
| @@ -5061,6 +5166,9 @@ static int _nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, co | |||
| 5061 | nfs_fattr_init(data->res.fattr); | 5166 | nfs_fattr_init(data->res.fattr); |
| 5062 | data->timestamp = jiffies; | 5167 | data->timestamp = jiffies; |
| 5063 | data->rpc_status = 0; | 5168 | data->rpc_status = 0; |
| 5169 | data->inode = inode; | ||
| 5170 | data->roc = list_empty(&NFS_I(inode)->open_files) ? | ||
| 5171 | pnfs_roc(inode) : false; | ||
| 5064 | 5172 | ||
| 5065 | task_setup_data.callback_data = data; | 5173 | task_setup_data.callback_data = data; |
| 5066 | msg.rpc_argp = &data->args; | 5174 | msg.rpc_argp = &data->args; |
| @@ -5834,8 +5942,10 @@ struct nfs_release_lockowner_data { | |||
| 5834 | static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata) | 5942 | static void nfs4_release_lockowner_prepare(struct rpc_task *task, void *calldata) |
| 5835 | { | 5943 | { |
| 5836 | struct nfs_release_lockowner_data *data = calldata; | 5944 | struct nfs_release_lockowner_data *data = calldata; |
| 5837 | nfs40_setup_sequence(data->server, | 5945 | struct nfs_server *server = data->server; |
| 5838 | &data->args.seq_args, &data->res.seq_res, task); | 5946 | nfs40_setup_sequence(server, &data->args.seq_args, |
| 5947 | &data->res.seq_res, task); | ||
| 5948 | data->args.lock_owner.clientid = server->nfs_client->cl_clientid; | ||
| 5839 | data->timestamp = jiffies; | 5949 | data->timestamp = jiffies; |
| 5840 | } | 5950 | } |
| 5841 | 5951 | ||
| @@ -5852,6 +5962,8 @@ static void nfs4_release_lockowner_done(struct rpc_task *task, void *calldata) | |||
| 5852 | break; | 5962 | break; |
| 5853 | case -NFS4ERR_STALE_CLIENTID: | 5963 | case -NFS4ERR_STALE_CLIENTID: |
| 5854 | case -NFS4ERR_EXPIRED: | 5964 | case -NFS4ERR_EXPIRED: |
| 5965 | nfs4_schedule_lease_recovery(server->nfs_client); | ||
| 5966 | break; | ||
| 5855 | case -NFS4ERR_LEASE_MOVED: | 5967 | case -NFS4ERR_LEASE_MOVED: |
| 5856 | case -NFS4ERR_DELAY: | 5968 | case -NFS4ERR_DELAY: |
| 5857 | if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) | 5969 | if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) |
| @@ -5872,7 +5984,8 @@ static const struct rpc_call_ops nfs4_release_lockowner_ops = { | |||
| 5872 | .rpc_release = nfs4_release_lockowner_release, | 5984 | .rpc_release = nfs4_release_lockowner_release, |
| 5873 | }; | 5985 | }; |
| 5874 | 5986 | ||
| 5875 | static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp) | 5987 | static void |
| 5988 | nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_state *lsp) | ||
| 5876 | { | 5989 | { |
| 5877 | struct nfs_release_lockowner_data *data; | 5990 | struct nfs_release_lockowner_data *data; |
| 5878 | struct rpc_message msg = { | 5991 | struct rpc_message msg = { |
| @@ -5880,11 +5993,11 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st | |||
| 5880 | }; | 5993 | }; |
| 5881 | 5994 | ||
| 5882 | if (server->nfs_client->cl_mvops->minor_version != 0) | 5995 | if (server->nfs_client->cl_mvops->minor_version != 0) |
| 5883 | return -EINVAL; | 5996 | return; |
| 5884 | 5997 | ||
| 5885 | data = kmalloc(sizeof(*data), GFP_NOFS); | 5998 | data = kmalloc(sizeof(*data), GFP_NOFS); |
| 5886 | if (!data) | 5999 | if (!data) |
| 5887 | return -ENOMEM; | 6000 | return; |
| 5888 | data->lsp = lsp; | 6001 | data->lsp = lsp; |
| 5889 | data->server = server; | 6002 | data->server = server; |
| 5890 | data->args.lock_owner.clientid = server->nfs_client->cl_clientid; | 6003 | data->args.lock_owner.clientid = server->nfs_client->cl_clientid; |
| @@ -5895,7 +6008,6 @@ static int nfs4_release_lockowner(struct nfs_server *server, struct nfs4_lock_st | |||
| 5895 | msg.rpc_resp = &data->res; | 6008 | msg.rpc_resp = &data->res; |
| 5896 | nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); | 6009 | nfs4_init_sequence(&data->args.seq_args, &data->res.seq_res, 0); |
| 5897 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data); | 6010 | rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data); |
| 5898 | return 0; | ||
| 5899 | } | 6011 | } |
| 5900 | 6012 | ||
| 5901 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" | 6013 | #define XATTR_NAME_NFSV4_ACL "system.nfs4_acl" |
| @@ -8182,7 +8294,8 @@ static int nfs41_free_stateid(struct nfs_server *server, | |||
| 8182 | return ret; | 8294 | return ret; |
| 8183 | } | 8295 | } |
| 8184 | 8296 | ||
| 8185 | static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) | 8297 | static void |
| 8298 | nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp) | ||
| 8186 | { | 8299 | { |
| 8187 | struct rpc_task *task; | 8300 | struct rpc_task *task; |
| 8188 | struct rpc_cred *cred = lsp->ls_state->owner->so_cred; | 8301 | struct rpc_cred *cred = lsp->ls_state->owner->so_cred; |
| @@ -8190,9 +8303,8 @@ static int nfs41_free_lock_state(struct nfs_server *server, struct nfs4_lock_sta | |||
| 8190 | task = _nfs41_free_stateid(server, &lsp->ls_stateid, cred, false); | 8303 | task = _nfs41_free_stateid(server, &lsp->ls_stateid, cred, false); |
| 8191 | nfs4_free_lock_state(server, lsp); | 8304 | nfs4_free_lock_state(server, lsp); |
| 8192 | if (IS_ERR(task)) | 8305 | if (IS_ERR(task)) |
| 8193 | return PTR_ERR(task); | 8306 | return; |
| 8194 | rpc_put_task(task); | 8307 | rpc_put_task(task); |
| 8195 | return 0; | ||
| 8196 | } | 8308 | } |
| 8197 | 8309 | ||
| 8198 | static bool nfs41_match_stateid(const nfs4_stateid *s1, | 8310 | static bool nfs41_match_stateid(const nfs4_stateid *s1, |
diff --git a/fs/nfs/nfs4state.c b/fs/nfs/nfs4state.c index 42f121182167..a043f618cd5a 100644 --- a/fs/nfs/nfs4state.c +++ b/fs/nfs/nfs4state.c | |||
| @@ -787,33 +787,36 @@ void nfs4_close_sync(struct nfs4_state *state, fmode_t fmode) | |||
| 787 | * that is compatible with current->files | 787 | * that is compatible with current->files |
| 788 | */ | 788 | */ |
| 789 | static struct nfs4_lock_state * | 789 | static struct nfs4_lock_state * |
| 790 | __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type) | 790 | __nfs4_find_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) |
| 791 | { | 791 | { |
| 792 | struct nfs4_lock_state *pos; | 792 | struct nfs4_lock_state *pos; |
| 793 | list_for_each_entry(pos, &state->lock_states, ls_locks) { | 793 | list_for_each_entry(pos, &state->lock_states, ls_locks) { |
| 794 | if (type != NFS4_ANY_LOCK_TYPE && pos->ls_owner.lo_type != type) | 794 | if (pos->ls_owner != fl_owner) |
| 795 | continue; | 795 | continue; |
| 796 | switch (pos->ls_owner.lo_type) { | ||
| 797 | case NFS4_POSIX_LOCK_TYPE: | ||
| 798 | if (pos->ls_owner.lo_u.posix_owner != fl_owner) | ||
| 799 | continue; | ||
| 800 | break; | ||
| 801 | case NFS4_FLOCK_LOCK_TYPE: | ||
| 802 | if (pos->ls_owner.lo_u.flock_owner != fl_pid) | ||
| 803 | continue; | ||
| 804 | } | ||
| 805 | atomic_inc(&pos->ls_count); | 796 | atomic_inc(&pos->ls_count); |
| 806 | return pos; | 797 | return pos; |
| 807 | } | 798 | } |
| 808 | return NULL; | 799 | return NULL; |
| 809 | } | 800 | } |
| 810 | 801 | ||
| 802 | static void | ||
| 803 | free_lock_state_work(struct work_struct *work) | ||
| 804 | { | ||
| 805 | struct nfs4_lock_state *lsp = container_of(work, | ||
| 806 | struct nfs4_lock_state, ls_release); | ||
| 807 | struct nfs4_state *state = lsp->ls_state; | ||
| 808 | struct nfs_server *server = state->owner->so_server; | ||
| 809 | struct nfs_client *clp = server->nfs_client; | ||
| 810 | |||
| 811 | clp->cl_mvops->free_lock_state(server, lsp); | ||
| 812 | } | ||
| 813 | |||
| 811 | /* | 814 | /* |
| 812 | * Return a compatible lock_state. If no initialized lock_state structure | 815 | * Return a compatible lock_state. If no initialized lock_state structure |
| 813 | * exists, return an uninitialized one. | 816 | * exists, return an uninitialized one. |
| 814 | * | 817 | * |
| 815 | */ | 818 | */ |
| 816 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner, pid_t fl_pid, unsigned int type) | 819 | static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, fl_owner_t fl_owner) |
| 817 | { | 820 | { |
| 818 | struct nfs4_lock_state *lsp; | 821 | struct nfs4_lock_state *lsp; |
| 819 | struct nfs_server *server = state->owner->so_server; | 822 | struct nfs_server *server = state->owner->so_server; |
| @@ -824,21 +827,12 @@ static struct nfs4_lock_state *nfs4_alloc_lock_state(struct nfs4_state *state, f | |||
| 824 | nfs4_init_seqid_counter(&lsp->ls_seqid); | 827 | nfs4_init_seqid_counter(&lsp->ls_seqid); |
| 825 | atomic_set(&lsp->ls_count, 1); | 828 | atomic_set(&lsp->ls_count, 1); |
| 826 | lsp->ls_state = state; | 829 | lsp->ls_state = state; |
| 827 | lsp->ls_owner.lo_type = type; | 830 | lsp->ls_owner = fl_owner; |
| 828 | switch (lsp->ls_owner.lo_type) { | ||
| 829 | case NFS4_FLOCK_LOCK_TYPE: | ||
| 830 | lsp->ls_owner.lo_u.flock_owner = fl_pid; | ||
| 831 | break; | ||
| 832 | case NFS4_POSIX_LOCK_TYPE: | ||
| 833 | lsp->ls_owner.lo_u.posix_owner = fl_owner; | ||
| 834 | break; | ||
| 835 | default: | ||
| 836 | goto out_free; | ||
| 837 | } | ||
| 838 | lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS); | 831 | lsp->ls_seqid.owner_id = ida_simple_get(&server->lockowner_id, 0, 0, GFP_NOFS); |
| 839 | if (lsp->ls_seqid.owner_id < 0) | 832 | if (lsp->ls_seqid.owner_id < 0) |
| 840 | goto out_free; | 833 | goto out_free; |
| 841 | INIT_LIST_HEAD(&lsp->ls_locks); | 834 | INIT_LIST_HEAD(&lsp->ls_locks); |
| 835 | INIT_WORK(&lsp->ls_release, free_lock_state_work); | ||
| 842 | return lsp; | 836 | return lsp; |
| 843 | out_free: | 837 | out_free: |
| 844 | kfree(lsp); | 838 | kfree(lsp); |
| @@ -857,13 +851,13 @@ void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_state *lsp | |||
| 857 | * exists, return an uninitialized one. | 851 | * exists, return an uninitialized one. |
| 858 | * | 852 | * |
| 859 | */ | 853 | */ |
| 860 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner, pid_t pid, unsigned int type) | 854 | static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_owner_t owner) |
| 861 | { | 855 | { |
| 862 | struct nfs4_lock_state *lsp, *new = NULL; | 856 | struct nfs4_lock_state *lsp, *new = NULL; |
| 863 | 857 | ||
| 864 | for(;;) { | 858 | for(;;) { |
| 865 | spin_lock(&state->state_lock); | 859 | spin_lock(&state->state_lock); |
| 866 | lsp = __nfs4_find_lock_state(state, owner, pid, type); | 860 | lsp = __nfs4_find_lock_state(state, owner); |
| 867 | if (lsp != NULL) | 861 | if (lsp != NULL) |
| 868 | break; | 862 | break; |
| 869 | if (new != NULL) { | 863 | if (new != NULL) { |
| @@ -874,7 +868,7 @@ static struct nfs4_lock_state *nfs4_get_lock_state(struct nfs4_state *state, fl_ | |||
| 874 | break; | 868 | break; |
| 875 | } | 869 | } |
| 876 | spin_unlock(&state->state_lock); | 870 | spin_unlock(&state->state_lock); |
| 877 | new = nfs4_alloc_lock_state(state, owner, pid, type); | 871 | new = nfs4_alloc_lock_state(state, owner); |
| 878 | if (new == NULL) | 872 | if (new == NULL) |
| 879 | return NULL; | 873 | return NULL; |
| 880 | } | 874 | } |
| @@ -902,13 +896,12 @@ void nfs4_put_lock_state(struct nfs4_lock_state *lsp) | |||
| 902 | if (list_empty(&state->lock_states)) | 896 | if (list_empty(&state->lock_states)) |
| 903 | clear_bit(LK_STATE_IN_USE, &state->flags); | 897 | clear_bit(LK_STATE_IN_USE, &state->flags); |
| 904 | spin_unlock(&state->state_lock); | 898 | spin_unlock(&state->state_lock); |
| 905 | server = state->owner->so_server; | 899 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) |
| 906 | if (test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags)) { | 900 | queue_work(nfsiod_workqueue, &lsp->ls_release); |
| 907 | struct nfs_client *clp = server->nfs_client; | 901 | else { |
| 908 | 902 | server = state->owner->so_server; | |
| 909 | clp->cl_mvops->free_lock_state(server, lsp); | ||
| 910 | } else | ||
| 911 | nfs4_free_lock_state(server, lsp); | 903 | nfs4_free_lock_state(server, lsp); |
| 904 | } | ||
| 912 | } | 905 | } |
| 913 | 906 | ||
| 914 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) | 907 | static void nfs4_fl_copy_lock(struct file_lock *dst, struct file_lock *src) |
| @@ -935,13 +928,7 @@ int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl) | |||
| 935 | 928 | ||
| 936 | if (fl->fl_ops != NULL) | 929 | if (fl->fl_ops != NULL) |
| 937 | return 0; | 930 | return 0; |
| 938 | if (fl->fl_flags & FL_POSIX) | 931 | lsp = nfs4_get_lock_state(state, fl->fl_owner); |
| 939 | lsp = nfs4_get_lock_state(state, fl->fl_owner, 0, NFS4_POSIX_LOCK_TYPE); | ||
| 940 | else if (fl->fl_flags & FL_FLOCK) | ||
| 941 | lsp = nfs4_get_lock_state(state, NULL, fl->fl_pid, | ||
| 942 | NFS4_FLOCK_LOCK_TYPE); | ||
| 943 | else | ||
| 944 | return -EINVAL; | ||
| 945 | if (lsp == NULL) | 932 | if (lsp == NULL) |
| 946 | return -ENOMEM; | 933 | return -ENOMEM; |
| 947 | fl->fl_u.nfs4_fl.owner = lsp; | 934 | fl->fl_u.nfs4_fl.owner = lsp; |
| @@ -955,7 +942,6 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst, | |||
| 955 | { | 942 | { |
| 956 | struct nfs4_lock_state *lsp; | 943 | struct nfs4_lock_state *lsp; |
| 957 | fl_owner_t fl_owner; | 944 | fl_owner_t fl_owner; |
| 958 | pid_t fl_pid; | ||
| 959 | int ret = -ENOENT; | 945 | int ret = -ENOENT; |
| 960 | 946 | ||
| 961 | 947 | ||
| @@ -966,9 +952,8 @@ static int nfs4_copy_lock_stateid(nfs4_stateid *dst, | |||
| 966 | goto out; | 952 | goto out; |
| 967 | 953 | ||
| 968 | fl_owner = lockowner->l_owner; | 954 | fl_owner = lockowner->l_owner; |
| 969 | fl_pid = lockowner->l_pid; | ||
| 970 | spin_lock(&state->state_lock); | 955 | spin_lock(&state->state_lock); |
| 971 | lsp = __nfs4_find_lock_state(state, fl_owner, fl_pid, NFS4_ANY_LOCK_TYPE); | 956 | lsp = __nfs4_find_lock_state(state, fl_owner); |
| 972 | if (lsp && test_bit(NFS_LOCK_LOST, &lsp->ls_flags)) | 957 | if (lsp && test_bit(NFS_LOCK_LOST, &lsp->ls_flags)) |
| 973 | ret = -EIO; | 958 | ret = -EIO; |
| 974 | else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) { | 959 | else if (lsp != NULL && test_bit(NFS_LOCK_INITIALIZED, &lsp->ls_flags) != 0) { |
diff --git a/fs/nfs/nfs4trace.h b/fs/nfs/nfs4trace.h index 0a744f3a86f6..1c32adbe728d 100644 --- a/fs/nfs/nfs4trace.h +++ b/fs/nfs/nfs4trace.h | |||
| @@ -932,11 +932,11 @@ DEFINE_NFS4_IDMAP_EVENT(nfs4_map_gid_to_group); | |||
| 932 | 932 | ||
| 933 | DECLARE_EVENT_CLASS(nfs4_read_event, | 933 | DECLARE_EVENT_CLASS(nfs4_read_event, |
| 934 | TP_PROTO( | 934 | TP_PROTO( |
| 935 | const struct nfs_pgio_data *data, | 935 | const struct nfs_pgio_header *hdr, |
| 936 | int error | 936 | int error |
| 937 | ), | 937 | ), |
| 938 | 938 | ||
| 939 | TP_ARGS(data, error), | 939 | TP_ARGS(hdr, error), |
| 940 | 940 | ||
| 941 | TP_STRUCT__entry( | 941 | TP_STRUCT__entry( |
| 942 | __field(dev_t, dev) | 942 | __field(dev_t, dev) |
| @@ -948,12 +948,12 @@ DECLARE_EVENT_CLASS(nfs4_read_event, | |||
| 948 | ), | 948 | ), |
| 949 | 949 | ||
| 950 | TP_fast_assign( | 950 | TP_fast_assign( |
| 951 | const struct inode *inode = data->header->inode; | 951 | const struct inode *inode = hdr->inode; |
| 952 | __entry->dev = inode->i_sb->s_dev; | 952 | __entry->dev = inode->i_sb->s_dev; |
| 953 | __entry->fileid = NFS_FILEID(inode); | 953 | __entry->fileid = NFS_FILEID(inode); |
| 954 | __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode)); | 954 | __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode)); |
| 955 | __entry->offset = data->args.offset; | 955 | __entry->offset = hdr->args.offset; |
| 956 | __entry->count = data->args.count; | 956 | __entry->count = hdr->args.count; |
| 957 | __entry->error = error; | 957 | __entry->error = error; |
| 958 | ), | 958 | ), |
| 959 | 959 | ||
| @@ -972,10 +972,10 @@ DECLARE_EVENT_CLASS(nfs4_read_event, | |||
| 972 | #define DEFINE_NFS4_READ_EVENT(name) \ | 972 | #define DEFINE_NFS4_READ_EVENT(name) \ |
| 973 | DEFINE_EVENT(nfs4_read_event, name, \ | 973 | DEFINE_EVENT(nfs4_read_event, name, \ |
| 974 | TP_PROTO( \ | 974 | TP_PROTO( \ |
| 975 | const struct nfs_pgio_data *data, \ | 975 | const struct nfs_pgio_header *hdr, \ |
| 976 | int error \ | 976 | int error \ |
| 977 | ), \ | 977 | ), \ |
| 978 | TP_ARGS(data, error)) | 978 | TP_ARGS(hdr, error)) |
| 979 | DEFINE_NFS4_READ_EVENT(nfs4_read); | 979 | DEFINE_NFS4_READ_EVENT(nfs4_read); |
| 980 | #ifdef CONFIG_NFS_V4_1 | 980 | #ifdef CONFIG_NFS_V4_1 |
| 981 | DEFINE_NFS4_READ_EVENT(nfs4_pnfs_read); | 981 | DEFINE_NFS4_READ_EVENT(nfs4_pnfs_read); |
| @@ -983,11 +983,11 @@ DEFINE_NFS4_READ_EVENT(nfs4_pnfs_read); | |||
| 983 | 983 | ||
| 984 | DECLARE_EVENT_CLASS(nfs4_write_event, | 984 | DECLARE_EVENT_CLASS(nfs4_write_event, |
| 985 | TP_PROTO( | 985 | TP_PROTO( |
| 986 | const struct nfs_pgio_data *data, | 986 | const struct nfs_pgio_header *hdr, |
| 987 | int error | 987 | int error |
| 988 | ), | 988 | ), |
| 989 | 989 | ||
| 990 | TP_ARGS(data, error), | 990 | TP_ARGS(hdr, error), |
| 991 | 991 | ||
| 992 | TP_STRUCT__entry( | 992 | TP_STRUCT__entry( |
| 993 | __field(dev_t, dev) | 993 | __field(dev_t, dev) |
| @@ -999,12 +999,12 @@ DECLARE_EVENT_CLASS(nfs4_write_event, | |||
| 999 | ), | 999 | ), |
| 1000 | 1000 | ||
| 1001 | TP_fast_assign( | 1001 | TP_fast_assign( |
| 1002 | const struct inode *inode = data->header->inode; | 1002 | const struct inode *inode = hdr->inode; |
| 1003 | __entry->dev = inode->i_sb->s_dev; | 1003 | __entry->dev = inode->i_sb->s_dev; |
| 1004 | __entry->fileid = NFS_FILEID(inode); | 1004 | __entry->fileid = NFS_FILEID(inode); |
| 1005 | __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode)); | 1005 | __entry->fhandle = nfs_fhandle_hash(NFS_FH(inode)); |
| 1006 | __entry->offset = data->args.offset; | 1006 | __entry->offset = hdr->args.offset; |
| 1007 | __entry->count = data->args.count; | 1007 | __entry->count = hdr->args.count; |
| 1008 | __entry->error = error; | 1008 | __entry->error = error; |
| 1009 | ), | 1009 | ), |
| 1010 | 1010 | ||
| @@ -1024,10 +1024,10 @@ DECLARE_EVENT_CLASS(nfs4_write_event, | |||
| 1024 | #define DEFINE_NFS4_WRITE_EVENT(name) \ | 1024 | #define DEFINE_NFS4_WRITE_EVENT(name) \ |
| 1025 | DEFINE_EVENT(nfs4_write_event, name, \ | 1025 | DEFINE_EVENT(nfs4_write_event, name, \ |
| 1026 | TP_PROTO( \ | 1026 | TP_PROTO( \ |
| 1027 | const struct nfs_pgio_data *data, \ | 1027 | const struct nfs_pgio_header *hdr, \ |
| 1028 | int error \ | 1028 | int error \ |
| 1029 | ), \ | 1029 | ), \ |
| 1030 | TP_ARGS(data, error)) | 1030 | TP_ARGS(hdr, error)) |
| 1031 | DEFINE_NFS4_WRITE_EVENT(nfs4_write); | 1031 | DEFINE_NFS4_WRITE_EVENT(nfs4_write); |
| 1032 | #ifdef CONFIG_NFS_V4_1 | 1032 | #ifdef CONFIG_NFS_V4_1 |
| 1033 | DEFINE_NFS4_WRITE_EVENT(nfs4_pnfs_write); | 1033 | DEFINE_NFS4_WRITE_EVENT(nfs4_pnfs_write); |
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c index 939ae606cfa4..e13b59d8d9aa 100644 --- a/fs/nfs/nfs4xdr.c +++ b/fs/nfs/nfs4xdr.c | |||
| @@ -7092,7 +7092,7 @@ static int nfs4_xdr_dec_reclaim_complete(struct rpc_rqst *rqstp, | |||
| 7092 | if (!status) | 7092 | if (!status) |
| 7093 | status = decode_sequence(xdr, &res->seq_res, rqstp); | 7093 | status = decode_sequence(xdr, &res->seq_res, rqstp); |
| 7094 | if (!status) | 7094 | if (!status) |
| 7095 | status = decode_reclaim_complete(xdr, (void *)NULL); | 7095 | status = decode_reclaim_complete(xdr, NULL); |
| 7096 | return status; | 7096 | return status; |
| 7097 | } | 7097 | } |
| 7098 | 7098 | ||
diff --git a/fs/nfs/objlayout/objio_osd.c b/fs/nfs/objlayout/objio_osd.c index 611320753db2..ae05278b3761 100644 --- a/fs/nfs/objlayout/objio_osd.c +++ b/fs/nfs/objlayout/objio_osd.c | |||
| @@ -439,22 +439,21 @@ static void _read_done(struct ore_io_state *ios, void *private) | |||
| 439 | objlayout_read_done(&objios->oir, status, objios->sync); | 439 | objlayout_read_done(&objios->oir, status, objios->sync); |
| 440 | } | 440 | } |
| 441 | 441 | ||
| 442 | int objio_read_pagelist(struct nfs_pgio_data *rdata) | 442 | int objio_read_pagelist(struct nfs_pgio_header *hdr) |
| 443 | { | 443 | { |
| 444 | struct nfs_pgio_header *hdr = rdata->header; | ||
| 445 | struct objio_state *objios; | 444 | struct objio_state *objios; |
| 446 | int ret; | 445 | int ret; |
| 447 | 446 | ||
| 448 | ret = objio_alloc_io_state(NFS_I(hdr->inode)->layout, true, | 447 | ret = objio_alloc_io_state(NFS_I(hdr->inode)->layout, true, |
| 449 | hdr->lseg, rdata->args.pages, rdata->args.pgbase, | 448 | hdr->lseg, hdr->args.pages, hdr->args.pgbase, |
| 450 | rdata->args.offset, rdata->args.count, rdata, | 449 | hdr->args.offset, hdr->args.count, hdr, |
| 451 | GFP_KERNEL, &objios); | 450 | GFP_KERNEL, &objios); |
| 452 | if (unlikely(ret)) | 451 | if (unlikely(ret)) |
| 453 | return ret; | 452 | return ret; |
| 454 | 453 | ||
| 455 | objios->ios->done = _read_done; | 454 | objios->ios->done = _read_done; |
| 456 | dprintk("%s: offset=0x%llx length=0x%x\n", __func__, | 455 | dprintk("%s: offset=0x%llx length=0x%x\n", __func__, |
| 457 | rdata->args.offset, rdata->args.count); | 456 | hdr->args.offset, hdr->args.count); |
| 458 | ret = ore_read(objios->ios); | 457 | ret = ore_read(objios->ios); |
| 459 | if (unlikely(ret)) | 458 | if (unlikely(ret)) |
| 460 | objio_free_result(&objios->oir); | 459 | objio_free_result(&objios->oir); |
| @@ -487,11 +486,11 @@ static void _write_done(struct ore_io_state *ios, void *private) | |||
| 487 | static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) | 486 | static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate) |
| 488 | { | 487 | { |
| 489 | struct objio_state *objios = priv; | 488 | struct objio_state *objios = priv; |
| 490 | struct nfs_pgio_data *wdata = objios->oir.rpcdata; | 489 | struct nfs_pgio_header *hdr = objios->oir.rpcdata; |
| 491 | struct address_space *mapping = wdata->header->inode->i_mapping; | 490 | struct address_space *mapping = hdr->inode->i_mapping; |
| 492 | pgoff_t index = offset / PAGE_SIZE; | 491 | pgoff_t index = offset / PAGE_SIZE; |
| 493 | struct page *page; | 492 | struct page *page; |
| 494 | loff_t i_size = i_size_read(wdata->header->inode); | 493 | loff_t i_size = i_size_read(hdr->inode); |
| 495 | 494 | ||
| 496 | if (offset >= i_size) { | 495 | if (offset >= i_size) { |
| 497 | *uptodate = true; | 496 | *uptodate = true; |
| @@ -531,15 +530,14 @@ static const struct _ore_r4w_op _r4w_op = { | |||
| 531 | .put_page = &__r4w_put_page, | 530 | .put_page = &__r4w_put_page, |
| 532 | }; | 531 | }; |
| 533 | 532 | ||
| 534 | int objio_write_pagelist(struct nfs_pgio_data *wdata, int how) | 533 | int objio_write_pagelist(struct nfs_pgio_header *hdr, int how) |
| 535 | { | 534 | { |
| 536 | struct nfs_pgio_header *hdr = wdata->header; | ||
| 537 | struct objio_state *objios; | 535 | struct objio_state *objios; |
| 538 | int ret; | 536 | int ret; |
| 539 | 537 | ||
| 540 | ret = objio_alloc_io_state(NFS_I(hdr->inode)->layout, false, | 538 | ret = objio_alloc_io_state(NFS_I(hdr->inode)->layout, false, |
| 541 | hdr->lseg, wdata->args.pages, wdata->args.pgbase, | 539 | hdr->lseg, hdr->args.pages, hdr->args.pgbase, |
| 542 | wdata->args.offset, wdata->args.count, wdata, GFP_NOFS, | 540 | hdr->args.offset, hdr->args.count, hdr, GFP_NOFS, |
| 543 | &objios); | 541 | &objios); |
| 544 | if (unlikely(ret)) | 542 | if (unlikely(ret)) |
| 545 | return ret; | 543 | return ret; |
| @@ -551,7 +549,7 @@ int objio_write_pagelist(struct nfs_pgio_data *wdata, int how) | |||
| 551 | objios->ios->done = _write_done; | 549 | objios->ios->done = _write_done; |
| 552 | 550 | ||
| 553 | dprintk("%s: offset=0x%llx length=0x%x\n", __func__, | 551 | dprintk("%s: offset=0x%llx length=0x%x\n", __func__, |
| 554 | wdata->args.offset, wdata->args.count); | 552 | hdr->args.offset, hdr->args.count); |
| 555 | ret = ore_write(objios->ios); | 553 | ret = ore_write(objios->ios); |
| 556 | if (unlikely(ret)) { | 554 | if (unlikely(ret)) { |
| 557 | objio_free_result(&objios->oir); | 555 | objio_free_result(&objios->oir); |
diff --git a/fs/nfs/objlayout/objlayout.c b/fs/nfs/objlayout/objlayout.c index 765d3f54e986..697a16d11fac 100644 --- a/fs/nfs/objlayout/objlayout.c +++ b/fs/nfs/objlayout/objlayout.c | |||
| @@ -229,36 +229,36 @@ objlayout_io_set_result(struct objlayout_io_res *oir, unsigned index, | |||
| 229 | static void _rpc_read_complete(struct work_struct *work) | 229 | static void _rpc_read_complete(struct work_struct *work) |
| 230 | { | 230 | { |
| 231 | struct rpc_task *task; | 231 | struct rpc_task *task; |
| 232 | struct nfs_pgio_data *rdata; | 232 | struct nfs_pgio_header *hdr; |
| 233 | 233 | ||
| 234 | dprintk("%s enter\n", __func__); | 234 | dprintk("%s enter\n", __func__); |
| 235 | task = container_of(work, struct rpc_task, u.tk_work); | 235 | task = container_of(work, struct rpc_task, u.tk_work); |
| 236 | rdata = container_of(task, struct nfs_pgio_data, task); | 236 | hdr = container_of(task, struct nfs_pgio_header, task); |
| 237 | 237 | ||
| 238 | pnfs_ld_read_done(rdata); | 238 | pnfs_ld_read_done(hdr); |
| 239 | } | 239 | } |
| 240 | 240 | ||
| 241 | void | 241 | void |
| 242 | objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) | 242 | objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) |
| 243 | { | 243 | { |
| 244 | struct nfs_pgio_data *rdata = oir->rpcdata; | 244 | struct nfs_pgio_header *hdr = oir->rpcdata; |
| 245 | 245 | ||
| 246 | oir->status = rdata->task.tk_status = status; | 246 | oir->status = hdr->task.tk_status = status; |
| 247 | if (status >= 0) | 247 | if (status >= 0) |
| 248 | rdata->res.count = status; | 248 | hdr->res.count = status; |
| 249 | else | 249 | else |
| 250 | rdata->header->pnfs_error = status; | 250 | hdr->pnfs_error = status; |
| 251 | objlayout_iodone(oir); | 251 | objlayout_iodone(oir); |
| 252 | /* must not use oir after this point */ | 252 | /* must not use oir after this point */ |
| 253 | 253 | ||
| 254 | dprintk("%s: Return status=%zd eof=%d sync=%d\n", __func__, | 254 | dprintk("%s: Return status=%zd eof=%d sync=%d\n", __func__, |
| 255 | status, rdata->res.eof, sync); | 255 | status, hdr->res.eof, sync); |
| 256 | 256 | ||
| 257 | if (sync) | 257 | if (sync) |
| 258 | pnfs_ld_read_done(rdata); | 258 | pnfs_ld_read_done(hdr); |
| 259 | else { | 259 | else { |
| 260 | INIT_WORK(&rdata->task.u.tk_work, _rpc_read_complete); | 260 | INIT_WORK(&hdr->task.u.tk_work, _rpc_read_complete); |
| 261 | schedule_work(&rdata->task.u.tk_work); | 261 | schedule_work(&hdr->task.u.tk_work); |
| 262 | } | 262 | } |
| 263 | } | 263 | } |
| 264 | 264 | ||
| @@ -266,12 +266,11 @@ objlayout_read_done(struct objlayout_io_res *oir, ssize_t status, bool sync) | |||
| 266 | * Perform sync or async reads. | 266 | * Perform sync or async reads. |
| 267 | */ | 267 | */ |
| 268 | enum pnfs_try_status | 268 | enum pnfs_try_status |
| 269 | objlayout_read_pagelist(struct nfs_pgio_data *rdata) | 269 | objlayout_read_pagelist(struct nfs_pgio_header *hdr) |
| 270 | { | 270 | { |
| 271 | struct nfs_pgio_header *hdr = rdata->header; | ||
| 272 | struct inode *inode = hdr->inode; | 271 | struct inode *inode = hdr->inode; |
| 273 | loff_t offset = rdata->args.offset; | 272 | loff_t offset = hdr->args.offset; |
| 274 | size_t count = rdata->args.count; | 273 | size_t count = hdr->args.count; |
| 275 | int err; | 274 | int err; |
| 276 | loff_t eof; | 275 | loff_t eof; |
| 277 | 276 | ||
| @@ -279,23 +278,23 @@ objlayout_read_pagelist(struct nfs_pgio_data *rdata) | |||
| 279 | if (unlikely(offset + count > eof)) { | 278 | if (unlikely(offset + count > eof)) { |
| 280 | if (offset >= eof) { | 279 | if (offset >= eof) { |
| 281 | err = 0; | 280 | err = 0; |
| 282 | rdata->res.count = 0; | 281 | hdr->res.count = 0; |
| 283 | rdata->res.eof = 1; | 282 | hdr->res.eof = 1; |
| 284 | /*FIXME: do we need to call pnfs_ld_read_done() */ | 283 | /*FIXME: do we need to call pnfs_ld_read_done() */ |
| 285 | goto out; | 284 | goto out; |
| 286 | } | 285 | } |
| 287 | count = eof - offset; | 286 | count = eof - offset; |
| 288 | } | 287 | } |
| 289 | 288 | ||
| 290 | rdata->res.eof = (offset + count) >= eof; | 289 | hdr->res.eof = (offset + count) >= eof; |
| 291 | _fix_verify_io_params(hdr->lseg, &rdata->args.pages, | 290 | _fix_verify_io_params(hdr->lseg, &hdr->args.pages, |
| 292 | &rdata->args.pgbase, | 291 | &hdr->args.pgbase, |
| 293 | rdata->args.offset, rdata->args.count); | 292 | hdr->args.offset, hdr->args.count); |
| 294 | 293 | ||
| 295 | dprintk("%s: inode(%lx) offset 0x%llx count 0x%Zx eof=%d\n", | 294 | dprintk("%s: inode(%lx) offset 0x%llx count 0x%Zx eof=%d\n", |
| 296 | __func__, inode->i_ino, offset, count, rdata->res.eof); | 295 | __func__, inode->i_ino, offset, count, hdr->res.eof); |
| 297 | 296 | ||
| 298 | err = objio_read_pagelist(rdata); | 297 | err = objio_read_pagelist(hdr); |
| 299 | out: | 298 | out: |
| 300 | if (unlikely(err)) { | 299 | if (unlikely(err)) { |
| 301 | hdr->pnfs_error = err; | 300 | hdr->pnfs_error = err; |
| @@ -312,38 +311,38 @@ objlayout_read_pagelist(struct nfs_pgio_data *rdata) | |||
| 312 | static void _rpc_write_complete(struct work_struct *work) | 311 | static void _rpc_write_complete(struct work_struct *work) |
| 313 | { | 312 | { |
| 314 | struct rpc_task *task; | 313 | struct rpc_task *task; |
| 315 | struct nfs_pgio_data *wdata; | 314 | struct nfs_pgio_header *hdr; |
| 316 | 315 | ||
| 317 | dprintk("%s enter\n", __func__); | 316 | dprintk("%s enter\n", __func__); |
| 318 | task = container_of(work, struct rpc_task, u.tk_work); | 317 | task = container_of(work, struct rpc_task, u.tk_work); |
| 319 | wdata = container_of(task, struct nfs_pgio_data, task); | 318 | hdr = container_of(task, struct nfs_pgio_header, task); |
| 320 | 319 | ||
| 321 | pnfs_ld_write_done(wdata); | 320 | pnfs_ld_write_done(hdr); |
| 322 | } | 321 | } |
| 323 | 322 | ||
| 324 | void | 323 | void |
| 325 | objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync) | 324 | objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync) |
| 326 | { | 325 | { |
| 327 | struct nfs_pgio_data *wdata = oir->rpcdata; | 326 | struct nfs_pgio_header *hdr = oir->rpcdata; |
| 328 | 327 | ||
| 329 | oir->status = wdata->task.tk_status = status; | 328 | oir->status = hdr->task.tk_status = status; |
| 330 | if (status >= 0) { | 329 | if (status >= 0) { |
| 331 | wdata->res.count = status; | 330 | hdr->res.count = status; |
| 332 | wdata->verf.committed = oir->committed; | 331 | hdr->verf.committed = oir->committed; |
| 333 | } else { | 332 | } else { |
| 334 | wdata->header->pnfs_error = status; | 333 | hdr->pnfs_error = status; |
| 335 | } | 334 | } |
| 336 | objlayout_iodone(oir); | 335 | objlayout_iodone(oir); |
| 337 | /* must not use oir after this point */ | 336 | /* must not use oir after this point */ |
| 338 | 337 | ||
| 339 | dprintk("%s: Return status %zd committed %d sync=%d\n", __func__, | 338 | dprintk("%s: Return status %zd committed %d sync=%d\n", __func__, |
| 340 | status, wdata->verf.committed, sync); | 339 | status, hdr->verf.committed, sync); |
| 341 | 340 | ||
| 342 | if (sync) | 341 | if (sync) |
| 343 | pnfs_ld_write_done(wdata); | 342 | pnfs_ld_write_done(hdr); |
| 344 | else { | 343 | else { |
| 345 | INIT_WORK(&wdata->task.u.tk_work, _rpc_write_complete); | 344 | INIT_WORK(&hdr->task.u.tk_work, _rpc_write_complete); |
| 346 | schedule_work(&wdata->task.u.tk_work); | 345 | schedule_work(&hdr->task.u.tk_work); |
| 347 | } | 346 | } |
| 348 | } | 347 | } |
| 349 | 348 | ||
| @@ -351,17 +350,15 @@ objlayout_write_done(struct objlayout_io_res *oir, ssize_t status, bool sync) | |||
| 351 | * Perform sync or async writes. | 350 | * Perform sync or async writes. |
| 352 | */ | 351 | */ |
| 353 | enum pnfs_try_status | 352 | enum pnfs_try_status |
| 354 | objlayout_write_pagelist(struct nfs_pgio_data *wdata, | 353 | objlayout_write_pagelist(struct nfs_pgio_header *hdr, int how) |
| 355 | int how) | ||
| 356 | { | 354 | { |
| 357 | struct nfs_pgio_header *hdr = wdata->header; | ||
| 358 | int err; | 355 | int err; |
| 359 | 356 | ||
| 360 | _fix_verify_io_params(hdr->lseg, &wdata->args.pages, | 357 | _fix_verify_io_params(hdr->lseg, &hdr->args.pages, |
| 361 | &wdata->args.pgbase, | 358 | &hdr->args.pgbase, |
| 362 | wdata->args.offset, wdata->args.count); | 359 | hdr->args.offset, hdr->args.count); |
| 363 | 360 | ||
| 364 | err = objio_write_pagelist(wdata, how); | 361 | err = objio_write_pagelist(hdr, how); |
| 365 | if (unlikely(err)) { | 362 | if (unlikely(err)) { |
| 366 | hdr->pnfs_error = err; | 363 | hdr->pnfs_error = err; |
| 367 | dprintk("%s: Returned Error %d\n", __func__, err); | 364 | dprintk("%s: Returned Error %d\n", __func__, err); |
diff --git a/fs/nfs/objlayout/objlayout.h b/fs/nfs/objlayout/objlayout.h index 01e041029a6c..fd13f1d2f136 100644 --- a/fs/nfs/objlayout/objlayout.h +++ b/fs/nfs/objlayout/objlayout.h | |||
| @@ -119,8 +119,8 @@ extern void objio_free_lseg(struct pnfs_layout_segment *lseg); | |||
| 119 | */ | 119 | */ |
| 120 | extern void objio_free_result(struct objlayout_io_res *oir); | 120 | extern void objio_free_result(struct objlayout_io_res *oir); |
| 121 | 121 | ||
| 122 | extern int objio_read_pagelist(struct nfs_pgio_data *rdata); | 122 | extern int objio_read_pagelist(struct nfs_pgio_header *rdata); |
| 123 | extern int objio_write_pagelist(struct nfs_pgio_data *wdata, int how); | 123 | extern int objio_write_pagelist(struct nfs_pgio_header *wdata, int how); |
| 124 | 124 | ||
| 125 | /* | 125 | /* |
| 126 | * callback API | 126 | * callback API |
| @@ -168,10 +168,10 @@ extern struct pnfs_layout_segment *objlayout_alloc_lseg( | |||
| 168 | extern void objlayout_free_lseg(struct pnfs_layout_segment *); | 168 | extern void objlayout_free_lseg(struct pnfs_layout_segment *); |
| 169 | 169 | ||
| 170 | extern enum pnfs_try_status objlayout_read_pagelist( | 170 | extern enum pnfs_try_status objlayout_read_pagelist( |
| 171 | struct nfs_pgio_data *); | 171 | struct nfs_pgio_header *); |
| 172 | 172 | ||
| 173 | extern enum pnfs_try_status objlayout_write_pagelist( | 173 | extern enum pnfs_try_status objlayout_write_pagelist( |
| 174 | struct nfs_pgio_data *, | 174 | struct nfs_pgio_header *, |
| 175 | int how); | 175 | int how); |
| 176 | 176 | ||
| 177 | extern void objlayout_encode_layoutcommit( | 177 | extern void objlayout_encode_layoutcommit( |
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c index 0be5050638f7..ba491926df5f 100644 --- a/fs/nfs/pagelist.c +++ b/fs/nfs/pagelist.c | |||
| @@ -141,16 +141,24 @@ nfs_iocounter_wait(struct nfs_io_counter *c) | |||
| 141 | * @req - request in group that is to be locked | 141 | * @req - request in group that is to be locked |
| 142 | * | 142 | * |
| 143 | * this lock must be held if modifying the page group list | 143 | * this lock must be held if modifying the page group list |
| 144 | * | ||
| 145 | * returns result from wait_on_bit_lock: 0 on success, < 0 on error | ||
| 144 | */ | 146 | */ |
| 145 | void | 147 | int |
| 146 | nfs_page_group_lock(struct nfs_page *req) | 148 | nfs_page_group_lock(struct nfs_page *req, bool wait) |
| 147 | { | 149 | { |
| 148 | struct nfs_page *head = req->wb_head; | 150 | struct nfs_page *head = req->wb_head; |
| 151 | int ret; | ||
| 149 | 152 | ||
| 150 | WARN_ON_ONCE(head != head->wb_head); | 153 | WARN_ON_ONCE(head != head->wb_head); |
| 151 | 154 | ||
| 152 | wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, | 155 | do { |
| 156 | ret = wait_on_bit_lock(&head->wb_flags, PG_HEADLOCK, | ||
| 153 | TASK_UNINTERRUPTIBLE); | 157 | TASK_UNINTERRUPTIBLE); |
| 158 | } while (wait && ret != 0); | ||
| 159 | |||
| 160 | WARN_ON_ONCE(ret > 0); | ||
| 161 | return ret; | ||
| 154 | } | 162 | } |
| 155 | 163 | ||
| 156 | /* | 164 | /* |
| @@ -211,7 +219,7 @@ bool nfs_page_group_sync_on_bit(struct nfs_page *req, unsigned int bit) | |||
| 211 | { | 219 | { |
| 212 | bool ret; | 220 | bool ret; |
| 213 | 221 | ||
| 214 | nfs_page_group_lock(req); | 222 | nfs_page_group_lock(req, true); |
| 215 | ret = nfs_page_group_sync_on_bit_locked(req, bit); | 223 | ret = nfs_page_group_sync_on_bit_locked(req, bit); |
| 216 | nfs_page_group_unlock(req); | 224 | nfs_page_group_unlock(req); |
| 217 | 225 | ||
| @@ -454,123 +462,72 @@ size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, | |||
| 454 | } | 462 | } |
| 455 | EXPORT_SYMBOL_GPL(nfs_generic_pg_test); | 463 | EXPORT_SYMBOL_GPL(nfs_generic_pg_test); |
| 456 | 464 | ||
| 457 | static inline struct nfs_rw_header *NFS_RW_HEADER(struct nfs_pgio_header *hdr) | 465 | struct nfs_pgio_header *nfs_pgio_header_alloc(const struct nfs_rw_ops *ops) |
| 458 | { | ||
| 459 | return container_of(hdr, struct nfs_rw_header, header); | ||
| 460 | } | ||
| 461 | |||
| 462 | /** | ||
| 463 | * nfs_rw_header_alloc - Allocate a header for a read or write | ||
| 464 | * @ops: Read or write function vector | ||
| 465 | */ | ||
| 466 | struct nfs_rw_header *nfs_rw_header_alloc(const struct nfs_rw_ops *ops) | ||
| 467 | { | 466 | { |
| 468 | struct nfs_rw_header *header = ops->rw_alloc_header(); | 467 | struct nfs_pgio_header *hdr = ops->rw_alloc_header(); |
| 469 | |||
| 470 | if (header) { | ||
| 471 | struct nfs_pgio_header *hdr = &header->header; | ||
| 472 | 468 | ||
| 469 | if (hdr) { | ||
| 473 | INIT_LIST_HEAD(&hdr->pages); | 470 | INIT_LIST_HEAD(&hdr->pages); |
| 474 | spin_lock_init(&hdr->lock); | 471 | spin_lock_init(&hdr->lock); |
| 475 | atomic_set(&hdr->refcnt, 0); | ||
| 476 | hdr->rw_ops = ops; | 472 | hdr->rw_ops = ops; |
| 477 | } | 473 | } |
| 478 | return header; | 474 | return hdr; |
| 479 | } | 475 | } |
| 480 | EXPORT_SYMBOL_GPL(nfs_rw_header_alloc); | 476 | EXPORT_SYMBOL_GPL(nfs_pgio_header_alloc); |
| 481 | 477 | ||
| 482 | /* | 478 | /* |
| 483 | * nfs_rw_header_free - Free a read or write header | 479 | * nfs_pgio_header_free - Free a read or write header |
| 484 | * @hdr: The header to free | 480 | * @hdr: The header to free |
| 485 | */ | 481 | */ |
| 486 | void nfs_rw_header_free(struct nfs_pgio_header *hdr) | 482 | void nfs_pgio_header_free(struct nfs_pgio_header *hdr) |
| 487 | { | 483 | { |
| 488 | hdr->rw_ops->rw_free_header(NFS_RW_HEADER(hdr)); | 484 | hdr->rw_ops->rw_free_header(hdr); |
| 489 | } | 485 | } |
| 490 | EXPORT_SYMBOL_GPL(nfs_rw_header_free); | 486 | EXPORT_SYMBOL_GPL(nfs_pgio_header_free); |
| 491 | 487 | ||
| 492 | /** | 488 | /** |
| 493 | * nfs_pgio_data_alloc - Allocate pageio data | 489 | * nfs_pgio_data_destroy - make @hdr suitable for reuse |
| 494 | * @hdr: The header making a request | 490 | * |
| 495 | * @pagecount: Number of pages to create | 491 | * Frees memory and releases refs from nfs_generic_pgio, so that it may |
| 496 | */ | 492 | * be called again. |
| 497 | static struct nfs_pgio_data *nfs_pgio_data_alloc(struct nfs_pgio_header *hdr, | 493 | * |
| 498 | unsigned int pagecount) | 494 | * @hdr: A header that has had nfs_generic_pgio called |
| 499 | { | ||
| 500 | struct nfs_pgio_data *data, *prealloc; | ||
| 501 | |||
| 502 | prealloc = &NFS_RW_HEADER(hdr)->rpc_data; | ||
| 503 | if (prealloc->header == NULL) | ||
| 504 | data = prealloc; | ||
| 505 | else | ||
| 506 | data = kzalloc(sizeof(*data), GFP_KERNEL); | ||
| 507 | if (!data) | ||
| 508 | goto out; | ||
| 509 | |||
| 510 | if (nfs_pgarray_set(&data->pages, pagecount)) { | ||
| 511 | data->header = hdr; | ||
| 512 | atomic_inc(&hdr->refcnt); | ||
| 513 | } else { | ||
| 514 | if (data != prealloc) | ||
| 515 | kfree(data); | ||
| 516 | data = NULL; | ||
| 517 | } | ||
| 518 | out: | ||
| 519 | return data; | ||
| 520 | } | ||
| 521 | |||
| 522 | /** | ||
| 523 | * nfs_pgio_data_release - Properly free pageio data | ||
| 524 | * @data: The data to release | ||
| 525 | */ | 495 | */ |
| 526 | void nfs_pgio_data_release(struct nfs_pgio_data *data) | 496 | void nfs_pgio_data_destroy(struct nfs_pgio_header *hdr) |
| 527 | { | 497 | { |
| 528 | struct nfs_pgio_header *hdr = data->header; | 498 | put_nfs_open_context(hdr->args.context); |
| 529 | struct nfs_rw_header *pageio_header = NFS_RW_HEADER(hdr); | 499 | if (hdr->page_array.pagevec != hdr->page_array.page_array) |
| 530 | 500 | kfree(hdr->page_array.pagevec); | |
| 531 | put_nfs_open_context(data->args.context); | ||
| 532 | if (data->pages.pagevec != data->pages.page_array) | ||
| 533 | kfree(data->pages.pagevec); | ||
| 534 | if (data == &pageio_header->rpc_data) { | ||
| 535 | data->header = NULL; | ||
| 536 | data = NULL; | ||
| 537 | } | ||
| 538 | if (atomic_dec_and_test(&hdr->refcnt)) | ||
| 539 | hdr->completion_ops->completion(hdr); | ||
| 540 | /* Note: we only free the rpc_task after callbacks are done. | ||
| 541 | * See the comment in rpc_free_task() for why | ||
| 542 | */ | ||
| 543 | kfree(data); | ||
| 544 | } | 501 | } |
| 545 | EXPORT_SYMBOL_GPL(nfs_pgio_data_release); | 502 | EXPORT_SYMBOL_GPL(nfs_pgio_data_destroy); |
| 546 | 503 | ||
| 547 | /** | 504 | /** |
| 548 | * nfs_pgio_rpcsetup - Set up arguments for a pageio call | 505 | * nfs_pgio_rpcsetup - Set up arguments for a pageio call |
| 549 | * @data: The pageio data | 506 | * @hdr: The pageio hdr |
| 550 | * @count: Number of bytes to read | 507 | * @count: Number of bytes to read |
| 551 | * @offset: Initial offset | 508 | * @offset: Initial offset |
| 552 | * @how: How to commit data (writes only) | 509 | * @how: How to commit data (writes only) |
| 553 | * @cinfo: Commit information for the call (writes only) | 510 | * @cinfo: Commit information for the call (writes only) |
| 554 | */ | 511 | */ |
| 555 | static void nfs_pgio_rpcsetup(struct nfs_pgio_data *data, | 512 | static void nfs_pgio_rpcsetup(struct nfs_pgio_header *hdr, |
| 556 | unsigned int count, unsigned int offset, | 513 | unsigned int count, unsigned int offset, |
| 557 | int how, struct nfs_commit_info *cinfo) | 514 | int how, struct nfs_commit_info *cinfo) |
| 558 | { | 515 | { |
| 559 | struct nfs_page *req = data->header->req; | 516 | struct nfs_page *req = hdr->req; |
| 560 | 517 | ||
| 561 | /* Set up the RPC argument and reply structs | 518 | /* Set up the RPC argument and reply structs |
| 562 | * NB: take care not to mess about with data->commit et al. */ | 519 | * NB: take care not to mess about with hdr->commit et al. */ |
| 563 | 520 | ||
| 564 | data->args.fh = NFS_FH(data->header->inode); | 521 | hdr->args.fh = NFS_FH(hdr->inode); |
| 565 | data->args.offset = req_offset(req) + offset; | 522 | hdr->args.offset = req_offset(req) + offset; |
| 566 | /* pnfs_set_layoutcommit needs this */ | 523 | /* pnfs_set_layoutcommit needs this */ |
| 567 | data->mds_offset = data->args.offset; | 524 | hdr->mds_offset = hdr->args.offset; |
| 568 | data->args.pgbase = req->wb_pgbase + offset; | 525 | hdr->args.pgbase = req->wb_pgbase + offset; |
| 569 | data->args.pages = data->pages.pagevec; | 526 | hdr->args.pages = hdr->page_array.pagevec; |
| 570 | data->args.count = count; | 527 | hdr->args.count = count; |
| 571 | data->args.context = get_nfs_open_context(req->wb_context); | 528 | hdr->args.context = get_nfs_open_context(req->wb_context); |
| 572 | data->args.lock_context = req->wb_lock_context; | 529 | hdr->args.lock_context = req->wb_lock_context; |
| 573 | data->args.stable = NFS_UNSTABLE; | 530 | hdr->args.stable = NFS_UNSTABLE; |
| 574 | switch (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { | 531 | switch (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { |
| 575 | case 0: | 532 | case 0: |
| 576 | break; | 533 | break; |
| @@ -578,59 +535,59 @@ static void nfs_pgio_rpcsetup(struct nfs_pgio_data *data, | |||
| 578 | if (nfs_reqs_to_commit(cinfo)) | 535 | if (nfs_reqs_to_commit(cinfo)) |
| 579 | break; | 536 | break; |
| 580 | default: | 537 | default: |
| 581 | data->args.stable = NFS_FILE_SYNC; | 538 | hdr->args.stable = NFS_FILE_SYNC; |
| 582 | } | 539 | } |
| 583 | 540 | ||
| 584 | data->res.fattr = &data->fattr; | 541 | hdr->res.fattr = &hdr->fattr; |
| 585 | data->res.count = count; | 542 | hdr->res.count = count; |
| 586 | data->res.eof = 0; | 543 | hdr->res.eof = 0; |
| 587 | data->res.verf = &data->verf; | 544 | hdr->res.verf = &hdr->verf; |
| 588 | nfs_fattr_init(&data->fattr); | 545 | nfs_fattr_init(&hdr->fattr); |
| 589 | } | 546 | } |
| 590 | 547 | ||
| 591 | /** | 548 | /** |
| 592 | * nfs_pgio_prepare - Prepare pageio data to go over the wire | 549 | * nfs_pgio_prepare - Prepare pageio hdr to go over the wire |
| 593 | * @task: The current task | 550 | * @task: The current task |
| 594 | * @calldata: pageio data to prepare | 551 | * @calldata: pageio header to prepare |
| 595 | */ | 552 | */ |
| 596 | static void nfs_pgio_prepare(struct rpc_task *task, void *calldata) | 553 | static void nfs_pgio_prepare(struct rpc_task *task, void *calldata) |
| 597 | { | 554 | { |
| 598 | struct nfs_pgio_data *data = calldata; | 555 | struct nfs_pgio_header *hdr = calldata; |
| 599 | int err; | 556 | int err; |
| 600 | err = NFS_PROTO(data->header->inode)->pgio_rpc_prepare(task, data); | 557 | err = NFS_PROTO(hdr->inode)->pgio_rpc_prepare(task, hdr); |
| 601 | if (err) | 558 | if (err) |
| 602 | rpc_exit(task, err); | 559 | rpc_exit(task, err); |
| 603 | } | 560 | } |
| 604 | 561 | ||
| 605 | int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_data *data, | 562 | int nfs_initiate_pgio(struct rpc_clnt *clnt, struct nfs_pgio_header *hdr, |
| 606 | const struct rpc_call_ops *call_ops, int how, int flags) | 563 | const struct rpc_call_ops *call_ops, int how, int flags) |
| 607 | { | 564 | { |
| 608 | struct rpc_task *task; | 565 | struct rpc_task *task; |
| 609 | struct rpc_message msg = { | 566 | struct rpc_message msg = { |
| 610 | .rpc_argp = &data->args, | 567 | .rpc_argp = &hdr->args, |
| 611 | .rpc_resp = &data->res, | 568 | .rpc_resp = &hdr->res, |
| 612 | .rpc_cred = data->header->cred, | 569 | .rpc_cred = hdr->cred, |
| 613 | }; | 570 | }; |
| 614 | struct rpc_task_setup task_setup_data = { | 571 | struct rpc_task_setup task_setup_data = { |
| 615 | .rpc_client = clnt, | 572 | .rpc_client = clnt, |
| 616 | .task = &data->task, | 573 | .task = &hdr->task, |
| 617 | .rpc_message = &msg, | 574 | .rpc_message = &msg, |
| 618 | .callback_ops = call_ops, | 575 | .callback_ops = call_ops, |
| 619 | .callback_data = data, | 576 | .callback_data = hdr, |
| 620 | .workqueue = nfsiod_workqueue, | 577 | .workqueue = nfsiod_workqueue, |
| 621 | .flags = RPC_TASK_ASYNC | flags, | 578 | .flags = RPC_TASK_ASYNC | flags, |
| 622 | }; | 579 | }; |
| 623 | int ret = 0; | 580 | int ret = 0; |
| 624 | 581 | ||
| 625 | data->header->rw_ops->rw_initiate(data, &msg, &task_setup_data, how); | 582 | hdr->rw_ops->rw_initiate(hdr, &msg, &task_setup_data, how); |
| 626 | 583 | ||
| 627 | dprintk("NFS: %5u initiated pgio call " | 584 | dprintk("NFS: %5u initiated pgio call " |
| 628 | "(req %s/%llu, %u bytes @ offset %llu)\n", | 585 | "(req %s/%llu, %u bytes @ offset %llu)\n", |
| 629 | data->task.tk_pid, | 586 | hdr->task.tk_pid, |
| 630 | data->header->inode->i_sb->s_id, | 587 | hdr->inode->i_sb->s_id, |
| 631 | (unsigned long long)NFS_FILEID(data->header->inode), | 588 | (unsigned long long)NFS_FILEID(hdr->inode), |
| 632 | data->args.count, | 589 | hdr->args.count, |
| 633 | (unsigned long long)data->args.offset); | 590 | (unsigned long long)hdr->args.offset); |
| 634 | 591 | ||
| 635 | task = rpc_run_task(&task_setup_data); | 592 | task = rpc_run_task(&task_setup_data); |
| 636 | if (IS_ERR(task)) { | 593 | if (IS_ERR(task)) { |
| @@ -657,22 +614,23 @@ static int nfs_pgio_error(struct nfs_pageio_descriptor *desc, | |||
| 657 | struct nfs_pgio_header *hdr) | 614 | struct nfs_pgio_header *hdr) |
| 658 | { | 615 | { |
| 659 | set_bit(NFS_IOHDR_REDO, &hdr->flags); | 616 | set_bit(NFS_IOHDR_REDO, &hdr->flags); |
| 660 | nfs_pgio_data_release(hdr->data); | 617 | nfs_pgio_data_destroy(hdr); |
| 661 | hdr->data = NULL; | 618 | hdr->completion_ops->completion(hdr); |
| 662 | desc->pg_completion_ops->error_cleanup(&desc->pg_list); | 619 | desc->pg_completion_ops->error_cleanup(&desc->pg_list); |
| 663 | return -ENOMEM; | 620 | return -ENOMEM; |
| 664 | } | 621 | } |
| 665 | 622 | ||
| 666 | /** | 623 | /** |
| 667 | * nfs_pgio_release - Release pageio data | 624 | * nfs_pgio_release - Release pageio data |
| 668 | * @calldata: The pageio data to release | 625 | * @calldata: The pageio header to release |
| 669 | */ | 626 | */ |
| 670 | static void nfs_pgio_release(void *calldata) | 627 | static void nfs_pgio_release(void *calldata) |
| 671 | { | 628 | { |
| 672 | struct nfs_pgio_data *data = calldata; | 629 | struct nfs_pgio_header *hdr = calldata; |
| 673 | if (data->header->rw_ops->rw_release) | 630 | if (hdr->rw_ops->rw_release) |
| 674 | data->header->rw_ops->rw_release(data); | 631 | hdr->rw_ops->rw_release(hdr); |
| 675 | nfs_pgio_data_release(data); | 632 | nfs_pgio_data_destroy(hdr); |
| 633 | hdr->completion_ops->completion(hdr); | ||
| 676 | } | 634 | } |
| 677 | 635 | ||
| 678 | /** | 636 | /** |
| @@ -713,22 +671,22 @@ EXPORT_SYMBOL_GPL(nfs_pageio_init); | |||
| 713 | /** | 671 | /** |
| 714 | * nfs_pgio_result - Basic pageio error handling | 672 | * nfs_pgio_result - Basic pageio error handling |
| 715 | * @task: The task that ran | 673 | * @task: The task that ran |
| 716 | * @calldata: Pageio data to check | 674 | * @calldata: Pageio header to check |
| 717 | */ | 675 | */ |
| 718 | static void nfs_pgio_result(struct rpc_task *task, void *calldata) | 676 | static void nfs_pgio_result(struct rpc_task *task, void *calldata) |
| 719 | { | 677 | { |
| 720 | struct nfs_pgio_data *data = calldata; | 678 | struct nfs_pgio_header *hdr = calldata; |
| 721 | struct inode *inode = data->header->inode; | 679 | struct inode *inode = hdr->inode; |
| 722 | 680 | ||
| 723 | dprintk("NFS: %s: %5u, (status %d)\n", __func__, | 681 | dprintk("NFS: %s: %5u, (status %d)\n", __func__, |
| 724 | task->tk_pid, task->tk_status); | 682 | task->tk_pid, task->tk_status); |
| 725 | 683 | ||
| 726 | if (data->header->rw_ops->rw_done(task, data, inode) != 0) | 684 | if (hdr->rw_ops->rw_done(task, hdr, inode) != 0) |
| 727 | return; | 685 | return; |
| 728 | if (task->tk_status < 0) | 686 | if (task->tk_status < 0) |
| 729 | nfs_set_pgio_error(data->header, task->tk_status, data->args.offset); | 687 | nfs_set_pgio_error(hdr, task->tk_status, hdr->args.offset); |
| 730 | else | 688 | else |
| 731 | data->header->rw_ops->rw_result(task, data); | 689 | hdr->rw_ops->rw_result(task, hdr); |
| 732 | } | 690 | } |
| 733 | 691 | ||
| 734 | /* | 692 | /* |
| @@ -744,17 +702,16 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, | |||
| 744 | { | 702 | { |
| 745 | struct nfs_page *req; | 703 | struct nfs_page *req; |
| 746 | struct page **pages; | 704 | struct page **pages; |
| 747 | struct nfs_pgio_data *data; | ||
| 748 | struct list_head *head = &desc->pg_list; | 705 | struct list_head *head = &desc->pg_list; |
| 749 | struct nfs_commit_info cinfo; | 706 | struct nfs_commit_info cinfo; |
| 707 | unsigned int pagecount; | ||
| 750 | 708 | ||
| 751 | data = nfs_pgio_data_alloc(hdr, nfs_page_array_len(desc->pg_base, | 709 | pagecount = nfs_page_array_len(desc->pg_base, desc->pg_count); |
| 752 | desc->pg_count)); | 710 | if (!nfs_pgarray_set(&hdr->page_array, pagecount)) |
| 753 | if (!data) | ||
| 754 | return nfs_pgio_error(desc, hdr); | 711 | return nfs_pgio_error(desc, hdr); |
| 755 | 712 | ||
| 756 | nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); | 713 | nfs_init_cinfo(&cinfo, desc->pg_inode, desc->pg_dreq); |
| 757 | pages = data->pages.pagevec; | 714 | pages = hdr->page_array.pagevec; |
| 758 | while (!list_empty(head)) { | 715 | while (!list_empty(head)) { |
| 759 | req = nfs_list_entry(head->next); | 716 | req = nfs_list_entry(head->next); |
| 760 | nfs_list_remove_request(req); | 717 | nfs_list_remove_request(req); |
| @@ -767,8 +724,7 @@ int nfs_generic_pgio(struct nfs_pageio_descriptor *desc, | |||
| 767 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; | 724 | desc->pg_ioflags &= ~FLUSH_COND_STABLE; |
| 768 | 725 | ||
| 769 | /* Set up the argument struct */ | 726 | /* Set up the argument struct */ |
| 770 | nfs_pgio_rpcsetup(data, desc->pg_count, 0, desc->pg_ioflags, &cinfo); | 727 | nfs_pgio_rpcsetup(hdr, desc->pg_count, 0, desc->pg_ioflags, &cinfo); |
| 771 | hdr->data = data; | ||
| 772 | desc->pg_rpc_callops = &nfs_pgio_common_ops; | 728 | desc->pg_rpc_callops = &nfs_pgio_common_ops; |
| 773 | return 0; | 729 | return 0; |
| 774 | } | 730 | } |
| @@ -776,25 +732,20 @@ EXPORT_SYMBOL_GPL(nfs_generic_pgio); | |||
| 776 | 732 | ||
| 777 | static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc) | 733 | static int nfs_generic_pg_pgios(struct nfs_pageio_descriptor *desc) |
| 778 | { | 734 | { |
| 779 | struct nfs_rw_header *rw_hdr; | ||
| 780 | struct nfs_pgio_header *hdr; | 735 | struct nfs_pgio_header *hdr; |
| 781 | int ret; | 736 | int ret; |
| 782 | 737 | ||
| 783 | rw_hdr = nfs_rw_header_alloc(desc->pg_rw_ops); | 738 | hdr = nfs_pgio_header_alloc(desc->pg_rw_ops); |
| 784 | if (!rw_hdr) { | 739 | if (!hdr) { |
| 785 | desc->pg_completion_ops->error_cleanup(&desc->pg_list); | 740 | desc->pg_completion_ops->error_cleanup(&desc->pg_list); |
| 786 | return -ENOMEM; | 741 | return -ENOMEM; |
| 787 | } | 742 | } |
| 788 | hdr = &rw_hdr->header; | 743 | nfs_pgheader_init(desc, hdr, nfs_pgio_header_free); |
| 789 | nfs_pgheader_init(desc, hdr, nfs_rw_header_free); | ||
| 790 | atomic_inc(&hdr->refcnt); | ||
| 791 | ret = nfs_generic_pgio(desc, hdr); | 744 | ret = nfs_generic_pgio(desc, hdr); |
| 792 | if (ret == 0) | 745 | if (ret == 0) |
| 793 | ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode), | 746 | ret = nfs_initiate_pgio(NFS_CLIENT(hdr->inode), |
| 794 | hdr->data, desc->pg_rpc_callops, | 747 | hdr, desc->pg_rpc_callops, |
| 795 | desc->pg_ioflags, 0); | 748 | desc->pg_ioflags, 0); |
| 796 | if (atomic_dec_and_test(&hdr->refcnt)) | ||
| 797 | hdr->completion_ops->completion(hdr); | ||
| 798 | return ret; | 749 | return ret; |
| 799 | } | 750 | } |
| 800 | 751 | ||
| @@ -907,8 +858,13 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
| 907 | struct nfs_page *subreq; | 858 | struct nfs_page *subreq; |
| 908 | unsigned int bytes_left = 0; | 859 | unsigned int bytes_left = 0; |
| 909 | unsigned int offset, pgbase; | 860 | unsigned int offset, pgbase; |
| 861 | int ret; | ||
| 910 | 862 | ||
| 911 | nfs_page_group_lock(req); | 863 | ret = nfs_page_group_lock(req, false); |
| 864 | if (ret < 0) { | ||
| 865 | desc->pg_error = ret; | ||
| 866 | return 0; | ||
| 867 | } | ||
| 912 | 868 | ||
| 913 | subreq = req; | 869 | subreq = req; |
| 914 | bytes_left = subreq->wb_bytes; | 870 | bytes_left = subreq->wb_bytes; |
| @@ -930,7 +886,11 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
| 930 | if (desc->pg_recoalesce) | 886 | if (desc->pg_recoalesce) |
| 931 | return 0; | 887 | return 0; |
| 932 | /* retry add_request for this subreq */ | 888 | /* retry add_request for this subreq */ |
| 933 | nfs_page_group_lock(req); | 889 | ret = nfs_page_group_lock(req, false); |
| 890 | if (ret < 0) { | ||
| 891 | desc->pg_error = ret; | ||
| 892 | return 0; | ||
| 893 | } | ||
| 934 | continue; | 894 | continue; |
| 935 | } | 895 | } |
| 936 | 896 | ||
| @@ -1005,7 +965,38 @@ int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, | |||
| 1005 | } while (ret); | 965 | } while (ret); |
| 1006 | return ret; | 966 | return ret; |
| 1007 | } | 967 | } |
| 1008 | EXPORT_SYMBOL_GPL(nfs_pageio_add_request); | 968 | |
| 969 | /* | ||
| 970 | * nfs_pageio_resend - Transfer requests to new descriptor and resend | ||
| 971 | * @hdr - the pgio header to move request from | ||
| 972 | * @desc - the pageio descriptor to add requests to | ||
| 973 | * | ||
| 974 | * Try to move each request (nfs_page) from @hdr to @desc then attempt | ||
| 975 | * to send them. | ||
| 976 | * | ||
| 977 | * Returns 0 on success and < 0 on error. | ||
| 978 | */ | ||
| 979 | int nfs_pageio_resend(struct nfs_pageio_descriptor *desc, | ||
| 980 | struct nfs_pgio_header *hdr) | ||
| 981 | { | ||
| 982 | LIST_HEAD(failed); | ||
| 983 | |||
| 984 | desc->pg_dreq = hdr->dreq; | ||
| 985 | while (!list_empty(&hdr->pages)) { | ||
| 986 | struct nfs_page *req = nfs_list_entry(hdr->pages.next); | ||
| 987 | |||
| 988 | nfs_list_remove_request(req); | ||
| 989 | if (!nfs_pageio_add_request(desc, req)) | ||
| 990 | nfs_list_add_request(req, &failed); | ||
| 991 | } | ||
| 992 | nfs_pageio_complete(desc); | ||
| 993 | if (!list_empty(&failed)) { | ||
| 994 | list_move(&failed, &hdr->pages); | ||
| 995 | return -EIO; | ||
| 996 | } | ||
| 997 | return 0; | ||
| 998 | } | ||
| 999 | EXPORT_SYMBOL_GPL(nfs_pageio_resend); | ||
| 1009 | 1000 | ||
| 1010 | /** | 1001 | /** |
| 1011 | * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor | 1002 | * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor |
| @@ -1021,7 +1012,6 @@ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) | |||
| 1021 | break; | 1012 | break; |
| 1022 | } | 1013 | } |
| 1023 | } | 1014 | } |
| 1024 | EXPORT_SYMBOL_GPL(nfs_pageio_complete); | ||
| 1025 | 1015 | ||
| 1026 | /** | 1016 | /** |
| 1027 | * nfs_pageio_cond_complete - Conditional I/O completion | 1017 | * nfs_pageio_cond_complete - Conditional I/O completion |
diff --git a/fs/nfs/pnfs.c b/fs/nfs/pnfs.c index a8914b335617..a3851debf8a2 100644 --- a/fs/nfs/pnfs.c +++ b/fs/nfs/pnfs.c | |||
| @@ -361,6 +361,23 @@ pnfs_put_lseg(struct pnfs_layout_segment *lseg) | |||
| 361 | } | 361 | } |
| 362 | EXPORT_SYMBOL_GPL(pnfs_put_lseg); | 362 | EXPORT_SYMBOL_GPL(pnfs_put_lseg); |
| 363 | 363 | ||
| 364 | static void pnfs_put_lseg_async_work(struct work_struct *work) | ||
| 365 | { | ||
| 366 | struct pnfs_layout_segment *lseg; | ||
| 367 | |||
| 368 | lseg = container_of(work, struct pnfs_layout_segment, pls_work); | ||
| 369 | |||
| 370 | pnfs_put_lseg(lseg); | ||
| 371 | } | ||
| 372 | |||
| 373 | void | ||
| 374 | pnfs_put_lseg_async(struct pnfs_layout_segment *lseg) | ||
| 375 | { | ||
| 376 | INIT_WORK(&lseg->pls_work, pnfs_put_lseg_async_work); | ||
| 377 | schedule_work(&lseg->pls_work); | ||
| 378 | } | ||
| 379 | EXPORT_SYMBOL_GPL(pnfs_put_lseg_async); | ||
| 380 | |||
| 364 | static u64 | 381 | static u64 |
| 365 | end_offset(u64 start, u64 len) | 382 | end_offset(u64 start, u64 len) |
| 366 | { | 383 | { |
| @@ -1470,41 +1487,19 @@ pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, | |||
| 1470 | } | 1487 | } |
| 1471 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); | 1488 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_test); |
| 1472 | 1489 | ||
| 1473 | int pnfs_write_done_resend_to_mds(struct inode *inode, | 1490 | int pnfs_write_done_resend_to_mds(struct nfs_pgio_header *hdr) |
| 1474 | struct list_head *head, | ||
| 1475 | const struct nfs_pgio_completion_ops *compl_ops, | ||
| 1476 | struct nfs_direct_req *dreq) | ||
| 1477 | { | 1491 | { |
| 1478 | struct nfs_pageio_descriptor pgio; | 1492 | struct nfs_pageio_descriptor pgio; |
| 1479 | LIST_HEAD(failed); | ||
| 1480 | 1493 | ||
| 1481 | /* Resend all requests through the MDS */ | 1494 | /* Resend all requests through the MDS */ |
| 1482 | nfs_pageio_init_write(&pgio, inode, FLUSH_STABLE, true, compl_ops); | 1495 | nfs_pageio_init_write(&pgio, hdr->inode, FLUSH_STABLE, true, |
| 1483 | pgio.pg_dreq = dreq; | 1496 | hdr->completion_ops); |
| 1484 | while (!list_empty(head)) { | 1497 | return nfs_pageio_resend(&pgio, hdr); |
| 1485 | struct nfs_page *req = nfs_list_entry(head->next); | ||
| 1486 | |||
| 1487 | nfs_list_remove_request(req); | ||
| 1488 | if (!nfs_pageio_add_request(&pgio, req)) | ||
| 1489 | nfs_list_add_request(req, &failed); | ||
| 1490 | } | ||
| 1491 | nfs_pageio_complete(&pgio); | ||
| 1492 | |||
| 1493 | if (!list_empty(&failed)) { | ||
| 1494 | /* For some reason our attempt to resend pages. Mark the | ||
| 1495 | * overall send request as having failed, and let | ||
| 1496 | * nfs_writeback_release_full deal with the error. | ||
| 1497 | */ | ||
| 1498 | list_move(&failed, head); | ||
| 1499 | return -EIO; | ||
| 1500 | } | ||
| 1501 | return 0; | ||
| 1502 | } | 1498 | } |
| 1503 | EXPORT_SYMBOL_GPL(pnfs_write_done_resend_to_mds); | 1499 | EXPORT_SYMBOL_GPL(pnfs_write_done_resend_to_mds); |
| 1504 | 1500 | ||
| 1505 | static void pnfs_ld_handle_write_error(struct nfs_pgio_data *data) | 1501 | static void pnfs_ld_handle_write_error(struct nfs_pgio_header *hdr) |
| 1506 | { | 1502 | { |
| 1507 | struct nfs_pgio_header *hdr = data->header; | ||
| 1508 | 1503 | ||
| 1509 | dprintk("pnfs write error = %d\n", hdr->pnfs_error); | 1504 | dprintk("pnfs write error = %d\n", hdr->pnfs_error); |
| 1510 | if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & | 1505 | if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & |
| @@ -1512,50 +1507,42 @@ static void pnfs_ld_handle_write_error(struct nfs_pgio_data *data) | |||
| 1512 | pnfs_return_layout(hdr->inode); | 1507 | pnfs_return_layout(hdr->inode); |
| 1513 | } | 1508 | } |
| 1514 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) | 1509 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) |
| 1515 | data->task.tk_status = pnfs_write_done_resend_to_mds(hdr->inode, | 1510 | hdr->task.tk_status = pnfs_write_done_resend_to_mds(hdr); |
| 1516 | &hdr->pages, | ||
| 1517 | hdr->completion_ops, | ||
| 1518 | hdr->dreq); | ||
| 1519 | } | 1511 | } |
| 1520 | 1512 | ||
| 1521 | /* | 1513 | /* |
| 1522 | * Called by non rpc-based layout drivers | 1514 | * Called by non rpc-based layout drivers |
| 1523 | */ | 1515 | */ |
| 1524 | void pnfs_ld_write_done(struct nfs_pgio_data *data) | 1516 | void pnfs_ld_write_done(struct nfs_pgio_header *hdr) |
| 1525 | { | 1517 | { |
| 1526 | struct nfs_pgio_header *hdr = data->header; | 1518 | trace_nfs4_pnfs_write(hdr, hdr->pnfs_error); |
| 1527 | |||
| 1528 | trace_nfs4_pnfs_write(data, hdr->pnfs_error); | ||
| 1529 | if (!hdr->pnfs_error) { | 1519 | if (!hdr->pnfs_error) { |
| 1530 | pnfs_set_layoutcommit(data); | 1520 | pnfs_set_layoutcommit(hdr); |
| 1531 | hdr->mds_ops->rpc_call_done(&data->task, data); | 1521 | hdr->mds_ops->rpc_call_done(&hdr->task, hdr); |
| 1532 | } else | 1522 | } else |
| 1533 | pnfs_ld_handle_write_error(data); | 1523 | pnfs_ld_handle_write_error(hdr); |
| 1534 | hdr->mds_ops->rpc_release(data); | 1524 | hdr->mds_ops->rpc_release(hdr); |
| 1535 | } | 1525 | } |
| 1536 | EXPORT_SYMBOL_GPL(pnfs_ld_write_done); | 1526 | EXPORT_SYMBOL_GPL(pnfs_ld_write_done); |
| 1537 | 1527 | ||
| 1538 | static void | 1528 | static void |
| 1539 | pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, | 1529 | pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, |
| 1540 | struct nfs_pgio_data *data) | 1530 | struct nfs_pgio_header *hdr) |
| 1541 | { | 1531 | { |
| 1542 | struct nfs_pgio_header *hdr = data->header; | ||
| 1543 | |||
| 1544 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { | 1532 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { |
| 1545 | list_splice_tail_init(&hdr->pages, &desc->pg_list); | 1533 | list_splice_tail_init(&hdr->pages, &desc->pg_list); |
| 1546 | nfs_pageio_reset_write_mds(desc); | 1534 | nfs_pageio_reset_write_mds(desc); |
| 1547 | desc->pg_recoalesce = 1; | 1535 | desc->pg_recoalesce = 1; |
| 1548 | } | 1536 | } |
| 1549 | nfs_pgio_data_release(data); | 1537 | nfs_pgio_data_destroy(hdr); |
| 1550 | } | 1538 | } |
| 1551 | 1539 | ||
| 1552 | static enum pnfs_try_status | 1540 | static enum pnfs_try_status |
| 1553 | pnfs_try_to_write_data(struct nfs_pgio_data *wdata, | 1541 | pnfs_try_to_write_data(struct nfs_pgio_header *hdr, |
| 1554 | const struct rpc_call_ops *call_ops, | 1542 | const struct rpc_call_ops *call_ops, |
| 1555 | struct pnfs_layout_segment *lseg, | 1543 | struct pnfs_layout_segment *lseg, |
| 1556 | int how) | 1544 | int how) |
| 1557 | { | 1545 | { |
| 1558 | struct nfs_pgio_header *hdr = wdata->header; | ||
| 1559 | struct inode *inode = hdr->inode; | 1546 | struct inode *inode = hdr->inode; |
| 1560 | enum pnfs_try_status trypnfs; | 1547 | enum pnfs_try_status trypnfs; |
| 1561 | struct nfs_server *nfss = NFS_SERVER(inode); | 1548 | struct nfs_server *nfss = NFS_SERVER(inode); |
| @@ -1563,8 +1550,8 @@ pnfs_try_to_write_data(struct nfs_pgio_data *wdata, | |||
| 1563 | hdr->mds_ops = call_ops; | 1550 | hdr->mds_ops = call_ops; |
| 1564 | 1551 | ||
| 1565 | dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__, | 1552 | dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__, |
| 1566 | inode->i_ino, wdata->args.count, wdata->args.offset, how); | 1553 | inode->i_ino, hdr->args.count, hdr->args.offset, how); |
| 1567 | trypnfs = nfss->pnfs_curr_ld->write_pagelist(wdata, how); | 1554 | trypnfs = nfss->pnfs_curr_ld->write_pagelist(hdr, how); |
| 1568 | if (trypnfs != PNFS_NOT_ATTEMPTED) | 1555 | if (trypnfs != PNFS_NOT_ATTEMPTED) |
| 1569 | nfs_inc_stats(inode, NFSIOS_PNFS_WRITE); | 1556 | nfs_inc_stats(inode, NFSIOS_PNFS_WRITE); |
| 1570 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | 1557 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); |
| @@ -1575,139 +1562,105 @@ static void | |||
| 1575 | pnfs_do_write(struct nfs_pageio_descriptor *desc, | 1562 | pnfs_do_write(struct nfs_pageio_descriptor *desc, |
| 1576 | struct nfs_pgio_header *hdr, int how) | 1563 | struct nfs_pgio_header *hdr, int how) |
| 1577 | { | 1564 | { |
| 1578 | struct nfs_pgio_data *data = hdr->data; | ||
| 1579 | const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; | 1565 | const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; |
| 1580 | struct pnfs_layout_segment *lseg = desc->pg_lseg; | 1566 | struct pnfs_layout_segment *lseg = desc->pg_lseg; |
| 1581 | enum pnfs_try_status trypnfs; | 1567 | enum pnfs_try_status trypnfs; |
| 1582 | 1568 | ||
| 1583 | desc->pg_lseg = NULL; | 1569 | desc->pg_lseg = NULL; |
| 1584 | trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how); | 1570 | trypnfs = pnfs_try_to_write_data(hdr, call_ops, lseg, how); |
| 1585 | if (trypnfs == PNFS_NOT_ATTEMPTED) | 1571 | if (trypnfs == PNFS_NOT_ATTEMPTED) |
| 1586 | pnfs_write_through_mds(desc, data); | 1572 | pnfs_write_through_mds(desc, hdr); |
| 1587 | pnfs_put_lseg(lseg); | 1573 | pnfs_put_lseg(lseg); |
| 1588 | } | 1574 | } |
| 1589 | 1575 | ||
| 1590 | static void pnfs_writehdr_free(struct nfs_pgio_header *hdr) | 1576 | static void pnfs_writehdr_free(struct nfs_pgio_header *hdr) |
| 1591 | { | 1577 | { |
| 1592 | pnfs_put_lseg(hdr->lseg); | 1578 | pnfs_put_lseg(hdr->lseg); |
| 1593 | nfs_rw_header_free(hdr); | 1579 | nfs_pgio_header_free(hdr); |
| 1594 | } | 1580 | } |
| 1595 | EXPORT_SYMBOL_GPL(pnfs_writehdr_free); | 1581 | EXPORT_SYMBOL_GPL(pnfs_writehdr_free); |
| 1596 | 1582 | ||
| 1597 | int | 1583 | int |
| 1598 | pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) | 1584 | pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) |
| 1599 | { | 1585 | { |
| 1600 | struct nfs_rw_header *whdr; | ||
| 1601 | struct nfs_pgio_header *hdr; | 1586 | struct nfs_pgio_header *hdr; |
| 1602 | int ret; | 1587 | int ret; |
| 1603 | 1588 | ||
| 1604 | whdr = nfs_rw_header_alloc(desc->pg_rw_ops); | 1589 | hdr = nfs_pgio_header_alloc(desc->pg_rw_ops); |
| 1605 | if (!whdr) { | 1590 | if (!hdr) { |
| 1606 | desc->pg_completion_ops->error_cleanup(&desc->pg_list); | 1591 | desc->pg_completion_ops->error_cleanup(&desc->pg_list); |
| 1607 | pnfs_put_lseg(desc->pg_lseg); | 1592 | pnfs_put_lseg(desc->pg_lseg); |
| 1608 | desc->pg_lseg = NULL; | 1593 | desc->pg_lseg = NULL; |
| 1609 | return -ENOMEM; | 1594 | return -ENOMEM; |
| 1610 | } | 1595 | } |
| 1611 | hdr = &whdr->header; | ||
| 1612 | nfs_pgheader_init(desc, hdr, pnfs_writehdr_free); | 1596 | nfs_pgheader_init(desc, hdr, pnfs_writehdr_free); |
| 1613 | hdr->lseg = pnfs_get_lseg(desc->pg_lseg); | 1597 | hdr->lseg = pnfs_get_lseg(desc->pg_lseg); |
| 1614 | atomic_inc(&hdr->refcnt); | ||
| 1615 | ret = nfs_generic_pgio(desc, hdr); | 1598 | ret = nfs_generic_pgio(desc, hdr); |
| 1616 | if (ret != 0) { | 1599 | if (ret != 0) { |
| 1617 | pnfs_put_lseg(desc->pg_lseg); | 1600 | pnfs_put_lseg(desc->pg_lseg); |
| 1618 | desc->pg_lseg = NULL; | 1601 | desc->pg_lseg = NULL; |
| 1619 | } else | 1602 | } else |
| 1620 | pnfs_do_write(desc, hdr, desc->pg_ioflags); | 1603 | pnfs_do_write(desc, hdr, desc->pg_ioflags); |
| 1621 | if (atomic_dec_and_test(&hdr->refcnt)) | ||
| 1622 | hdr->completion_ops->completion(hdr); | ||
| 1623 | return ret; | 1604 | return ret; |
| 1624 | } | 1605 | } |
| 1625 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); | 1606 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); |
| 1626 | 1607 | ||
| 1627 | int pnfs_read_done_resend_to_mds(struct inode *inode, | 1608 | int pnfs_read_done_resend_to_mds(struct nfs_pgio_header *hdr) |
| 1628 | struct list_head *head, | ||
| 1629 | const struct nfs_pgio_completion_ops *compl_ops, | ||
| 1630 | struct nfs_direct_req *dreq) | ||
| 1631 | { | 1609 | { |
| 1632 | struct nfs_pageio_descriptor pgio; | 1610 | struct nfs_pageio_descriptor pgio; |
| 1633 | LIST_HEAD(failed); | ||
| 1634 | 1611 | ||
| 1635 | /* Resend all requests through the MDS */ | 1612 | /* Resend all requests through the MDS */ |
| 1636 | nfs_pageio_init_read(&pgio, inode, true, compl_ops); | 1613 | nfs_pageio_init_read(&pgio, hdr->inode, true, hdr->completion_ops); |
| 1637 | pgio.pg_dreq = dreq; | 1614 | return nfs_pageio_resend(&pgio, hdr); |
| 1638 | while (!list_empty(head)) { | ||
| 1639 | struct nfs_page *req = nfs_list_entry(head->next); | ||
| 1640 | |||
| 1641 | nfs_list_remove_request(req); | ||
| 1642 | if (!nfs_pageio_add_request(&pgio, req)) | ||
| 1643 | nfs_list_add_request(req, &failed); | ||
| 1644 | } | ||
| 1645 | nfs_pageio_complete(&pgio); | ||
| 1646 | |||
| 1647 | if (!list_empty(&failed)) { | ||
| 1648 | list_move(&failed, head); | ||
| 1649 | return -EIO; | ||
| 1650 | } | ||
| 1651 | return 0; | ||
| 1652 | } | 1615 | } |
| 1653 | EXPORT_SYMBOL_GPL(pnfs_read_done_resend_to_mds); | 1616 | EXPORT_SYMBOL_GPL(pnfs_read_done_resend_to_mds); |
| 1654 | 1617 | ||
| 1655 | static void pnfs_ld_handle_read_error(struct nfs_pgio_data *data) | 1618 | static void pnfs_ld_handle_read_error(struct nfs_pgio_header *hdr) |
| 1656 | { | 1619 | { |
| 1657 | struct nfs_pgio_header *hdr = data->header; | ||
| 1658 | |||
| 1659 | dprintk("pnfs read error = %d\n", hdr->pnfs_error); | 1620 | dprintk("pnfs read error = %d\n", hdr->pnfs_error); |
| 1660 | if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & | 1621 | if (NFS_SERVER(hdr->inode)->pnfs_curr_ld->flags & |
| 1661 | PNFS_LAYOUTRET_ON_ERROR) { | 1622 | PNFS_LAYOUTRET_ON_ERROR) { |
| 1662 | pnfs_return_layout(hdr->inode); | 1623 | pnfs_return_layout(hdr->inode); |
| 1663 | } | 1624 | } |
| 1664 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) | 1625 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) |
| 1665 | data->task.tk_status = pnfs_read_done_resend_to_mds(hdr->inode, | 1626 | hdr->task.tk_status = pnfs_read_done_resend_to_mds(hdr); |
| 1666 | &hdr->pages, | ||
| 1667 | hdr->completion_ops, | ||
| 1668 | hdr->dreq); | ||
| 1669 | } | 1627 | } |
| 1670 | 1628 | ||
| 1671 | /* | 1629 | /* |
| 1672 | * Called by non rpc-based layout drivers | 1630 | * Called by non rpc-based layout drivers |
| 1673 | */ | 1631 | */ |
| 1674 | void pnfs_ld_read_done(struct nfs_pgio_data *data) | 1632 | void pnfs_ld_read_done(struct nfs_pgio_header *hdr) |
| 1675 | { | 1633 | { |
| 1676 | struct nfs_pgio_header *hdr = data->header; | 1634 | trace_nfs4_pnfs_read(hdr, hdr->pnfs_error); |
| 1677 | |||
| 1678 | trace_nfs4_pnfs_read(data, hdr->pnfs_error); | ||
| 1679 | if (likely(!hdr->pnfs_error)) { | 1635 | if (likely(!hdr->pnfs_error)) { |
| 1680 | __nfs4_read_done_cb(data); | 1636 | __nfs4_read_done_cb(hdr); |
| 1681 | hdr->mds_ops->rpc_call_done(&data->task, data); | 1637 | hdr->mds_ops->rpc_call_done(&hdr->task, hdr); |
| 1682 | } else | 1638 | } else |
| 1683 | pnfs_ld_handle_read_error(data); | 1639 | pnfs_ld_handle_read_error(hdr); |
| 1684 | hdr->mds_ops->rpc_release(data); | 1640 | hdr->mds_ops->rpc_release(hdr); |
| 1685 | } | 1641 | } |
| 1686 | EXPORT_SYMBOL_GPL(pnfs_ld_read_done); | 1642 | EXPORT_SYMBOL_GPL(pnfs_ld_read_done); |
| 1687 | 1643 | ||
| 1688 | static void | 1644 | static void |
| 1689 | pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, | 1645 | pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, |
| 1690 | struct nfs_pgio_data *data) | 1646 | struct nfs_pgio_header *hdr) |
| 1691 | { | 1647 | { |
| 1692 | struct nfs_pgio_header *hdr = data->header; | ||
| 1693 | |||
| 1694 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { | 1648 | if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) { |
| 1695 | list_splice_tail_init(&hdr->pages, &desc->pg_list); | 1649 | list_splice_tail_init(&hdr->pages, &desc->pg_list); |
| 1696 | nfs_pageio_reset_read_mds(desc); | 1650 | nfs_pageio_reset_read_mds(desc); |
| 1697 | desc->pg_recoalesce = 1; | 1651 | desc->pg_recoalesce = 1; |
| 1698 | } | 1652 | } |
| 1699 | nfs_pgio_data_release(data); | 1653 | nfs_pgio_data_destroy(hdr); |
| 1700 | } | 1654 | } |
| 1701 | 1655 | ||
| 1702 | /* | 1656 | /* |
| 1703 | * Call the appropriate parallel I/O subsystem read function. | 1657 | * Call the appropriate parallel I/O subsystem read function. |
| 1704 | */ | 1658 | */ |
| 1705 | static enum pnfs_try_status | 1659 | static enum pnfs_try_status |
| 1706 | pnfs_try_to_read_data(struct nfs_pgio_data *rdata, | 1660 | pnfs_try_to_read_data(struct nfs_pgio_header *hdr, |
| 1707 | const struct rpc_call_ops *call_ops, | 1661 | const struct rpc_call_ops *call_ops, |
| 1708 | struct pnfs_layout_segment *lseg) | 1662 | struct pnfs_layout_segment *lseg) |
| 1709 | { | 1663 | { |
| 1710 | struct nfs_pgio_header *hdr = rdata->header; | ||
| 1711 | struct inode *inode = hdr->inode; | 1664 | struct inode *inode = hdr->inode; |
| 1712 | struct nfs_server *nfss = NFS_SERVER(inode); | 1665 | struct nfs_server *nfss = NFS_SERVER(inode); |
| 1713 | enum pnfs_try_status trypnfs; | 1666 | enum pnfs_try_status trypnfs; |
| @@ -1715,9 +1668,9 @@ pnfs_try_to_read_data(struct nfs_pgio_data *rdata, | |||
| 1715 | hdr->mds_ops = call_ops; | 1668 | hdr->mds_ops = call_ops; |
| 1716 | 1669 | ||
| 1717 | dprintk("%s: Reading ino:%lu %u@%llu\n", | 1670 | dprintk("%s: Reading ino:%lu %u@%llu\n", |
| 1718 | __func__, inode->i_ino, rdata->args.count, rdata->args.offset); | 1671 | __func__, inode->i_ino, hdr->args.count, hdr->args.offset); |
| 1719 | 1672 | ||
| 1720 | trypnfs = nfss->pnfs_curr_ld->read_pagelist(rdata); | 1673 | trypnfs = nfss->pnfs_curr_ld->read_pagelist(hdr); |
| 1721 | if (trypnfs != PNFS_NOT_ATTEMPTED) | 1674 | if (trypnfs != PNFS_NOT_ATTEMPTED) |
| 1722 | nfs_inc_stats(inode, NFSIOS_PNFS_READ); | 1675 | nfs_inc_stats(inode, NFSIOS_PNFS_READ); |
| 1723 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); | 1676 | dprintk("%s End (trypnfs:%d)\n", __func__, trypnfs); |
| @@ -1727,52 +1680,46 @@ pnfs_try_to_read_data(struct nfs_pgio_data *rdata, | |||
| 1727 | static void | 1680 | static void |
| 1728 | pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr) | 1681 | pnfs_do_read(struct nfs_pageio_descriptor *desc, struct nfs_pgio_header *hdr) |
| 1729 | { | 1682 | { |
| 1730 | struct nfs_pgio_data *data = hdr->data; | ||
| 1731 | const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; | 1683 | const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; |
| 1732 | struct pnfs_layout_segment *lseg = desc->pg_lseg; | 1684 | struct pnfs_layout_segment *lseg = desc->pg_lseg; |
| 1733 | enum pnfs_try_status trypnfs; | 1685 | enum pnfs_try_status trypnfs; |
| 1734 | 1686 | ||
| 1735 | desc->pg_lseg = NULL; | 1687 | desc->pg_lseg = NULL; |
| 1736 | trypnfs = pnfs_try_to_read_data(data, call_ops, lseg); | 1688 | trypnfs = pnfs_try_to_read_data(hdr, call_ops, lseg); |
| 1737 | if (trypnfs == PNFS_NOT_ATTEMPTED) | 1689 | if (trypnfs == PNFS_NOT_ATTEMPTED) |
| 1738 | pnfs_read_through_mds(desc, data); | 1690 | pnfs_read_through_mds(desc, hdr); |
| 1739 | pnfs_put_lseg(lseg); | 1691 | pnfs_put_lseg(lseg); |
| 1740 | } | 1692 | } |
| 1741 | 1693 | ||
| 1742 | static void pnfs_readhdr_free(struct nfs_pgio_header *hdr) | 1694 | static void pnfs_readhdr_free(struct nfs_pgio_header *hdr) |
| 1743 | { | 1695 | { |
| 1744 | pnfs_put_lseg(hdr->lseg); | 1696 | pnfs_put_lseg(hdr->lseg); |
| 1745 | nfs_rw_header_free(hdr); | 1697 | nfs_pgio_header_free(hdr); |
| 1746 | } | 1698 | } |
| 1747 | EXPORT_SYMBOL_GPL(pnfs_readhdr_free); | 1699 | EXPORT_SYMBOL_GPL(pnfs_readhdr_free); |
| 1748 | 1700 | ||
| 1749 | int | 1701 | int |
| 1750 | pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) | 1702 | pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) |
| 1751 | { | 1703 | { |
| 1752 | struct nfs_rw_header *rhdr; | ||
| 1753 | struct nfs_pgio_header *hdr; | 1704 | struct nfs_pgio_header *hdr; |
| 1754 | int ret; | 1705 | int ret; |
| 1755 | 1706 | ||
| 1756 | rhdr = nfs_rw_header_alloc(desc->pg_rw_ops); | 1707 | hdr = nfs_pgio_header_alloc(desc->pg_rw_ops); |
| 1757 | if (!rhdr) { | 1708 | if (!hdr) { |
| 1758 | desc->pg_completion_ops->error_cleanup(&desc->pg_list); | 1709 | desc->pg_completion_ops->error_cleanup(&desc->pg_list); |
| 1759 | ret = -ENOMEM; | 1710 | ret = -ENOMEM; |
| 1760 | pnfs_put_lseg(desc->pg_lseg); | 1711 | pnfs_put_lseg(desc->pg_lseg); |
| 1761 | desc->pg_lseg = NULL; | 1712 | desc->pg_lseg = NULL; |
| 1762 | return ret; | 1713 | return ret; |
| 1763 | } | 1714 | } |
| 1764 | hdr = &rhdr->header; | ||
| 1765 | nfs_pgheader_init(desc, hdr, pnfs_readhdr_free); | 1715 | nfs_pgheader_init(desc, hdr, pnfs_readhdr_free); |
| 1766 | hdr->lseg = pnfs_get_lseg(desc->pg_lseg); | 1716 | hdr->lseg = pnfs_get_lseg(desc->pg_lseg); |
| 1767 | atomic_inc(&hdr->refcnt); | ||
| 1768 | ret = nfs_generic_pgio(desc, hdr); | 1717 | ret = nfs_generic_pgio(desc, hdr); |
| 1769 | if (ret != 0) { | 1718 | if (ret != 0) { |
| 1770 | pnfs_put_lseg(desc->pg_lseg); | 1719 | pnfs_put_lseg(desc->pg_lseg); |
| 1771 | desc->pg_lseg = NULL; | 1720 | desc->pg_lseg = NULL; |
| 1772 | } else | 1721 | } else |
| 1773 | pnfs_do_read(desc, hdr); | 1722 | pnfs_do_read(desc, hdr); |
| 1774 | if (atomic_dec_and_test(&hdr->refcnt)) | ||
| 1775 | hdr->completion_ops->completion(hdr); | ||
| 1776 | return ret; | 1723 | return ret; |
| 1777 | } | 1724 | } |
| 1778 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages); | 1725 | EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages); |
| @@ -1820,12 +1767,11 @@ void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg) | |||
| 1820 | EXPORT_SYMBOL_GPL(pnfs_set_lo_fail); | 1767 | EXPORT_SYMBOL_GPL(pnfs_set_lo_fail); |
| 1821 | 1768 | ||
| 1822 | void | 1769 | void |
| 1823 | pnfs_set_layoutcommit(struct nfs_pgio_data *wdata) | 1770 | pnfs_set_layoutcommit(struct nfs_pgio_header *hdr) |
| 1824 | { | 1771 | { |
| 1825 | struct nfs_pgio_header *hdr = wdata->header; | ||
| 1826 | struct inode *inode = hdr->inode; | 1772 | struct inode *inode = hdr->inode; |
| 1827 | struct nfs_inode *nfsi = NFS_I(inode); | 1773 | struct nfs_inode *nfsi = NFS_I(inode); |
| 1828 | loff_t end_pos = wdata->mds_offset + wdata->res.count; | 1774 | loff_t end_pos = hdr->mds_offset + hdr->res.count; |
| 1829 | bool mark_as_dirty = false; | 1775 | bool mark_as_dirty = false; |
| 1830 | 1776 | ||
| 1831 | spin_lock(&inode->i_lock); | 1777 | spin_lock(&inode->i_lock); |
diff --git a/fs/nfs/pnfs.h b/fs/nfs/pnfs.h index 4fb309a2b4c4..aca3dff5dae6 100644 --- a/fs/nfs/pnfs.h +++ b/fs/nfs/pnfs.h | |||
| @@ -32,6 +32,7 @@ | |||
| 32 | 32 | ||
| 33 | #include <linux/nfs_fs.h> | 33 | #include <linux/nfs_fs.h> |
| 34 | #include <linux/nfs_page.h> | 34 | #include <linux/nfs_page.h> |
| 35 | #include <linux/workqueue.h> | ||
| 35 | 36 | ||
| 36 | enum { | 37 | enum { |
| 37 | NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */ | 38 | NFS_LSEG_VALID = 0, /* cleared when lseg is recalled/returned */ |
| @@ -46,6 +47,7 @@ struct pnfs_layout_segment { | |||
| 46 | atomic_t pls_refcount; | 47 | atomic_t pls_refcount; |
| 47 | unsigned long pls_flags; | 48 | unsigned long pls_flags; |
| 48 | struct pnfs_layout_hdr *pls_layout; | 49 | struct pnfs_layout_hdr *pls_layout; |
| 50 | struct work_struct pls_work; | ||
| 49 | }; | 51 | }; |
| 50 | 52 | ||
| 51 | enum pnfs_try_status { | 53 | enum pnfs_try_status { |
| @@ -104,6 +106,8 @@ struct pnfs_layoutdriver_type { | |||
| 104 | int max); | 106 | int max); |
| 105 | void (*recover_commit_reqs) (struct list_head *list, | 107 | void (*recover_commit_reqs) (struct list_head *list, |
| 106 | struct nfs_commit_info *cinfo); | 108 | struct nfs_commit_info *cinfo); |
| 109 | struct nfs_page * (*search_commit_reqs)(struct nfs_commit_info *cinfo, | ||
| 110 | struct page *page); | ||
| 107 | int (*commit_pagelist)(struct inode *inode, | 111 | int (*commit_pagelist)(struct inode *inode, |
| 108 | struct list_head *mds_pages, | 112 | struct list_head *mds_pages, |
| 109 | int how, | 113 | int how, |
| @@ -113,8 +117,8 @@ struct pnfs_layoutdriver_type { | |||
| 113 | * Return PNFS_ATTEMPTED to indicate the layout code has attempted | 117 | * Return PNFS_ATTEMPTED to indicate the layout code has attempted |
| 114 | * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS | 118 | * I/O, else return PNFS_NOT_ATTEMPTED to fall back to normal NFS |
| 115 | */ | 119 | */ |
| 116 | enum pnfs_try_status (*read_pagelist) (struct nfs_pgio_data *nfs_data); | 120 | enum pnfs_try_status (*read_pagelist)(struct nfs_pgio_header *); |
| 117 | enum pnfs_try_status (*write_pagelist) (struct nfs_pgio_data *nfs_data, int how); | 121 | enum pnfs_try_status (*write_pagelist)(struct nfs_pgio_header *, int); |
| 118 | 122 | ||
| 119 | void (*free_deviceid_node) (struct nfs4_deviceid_node *); | 123 | void (*free_deviceid_node) (struct nfs4_deviceid_node *); |
| 120 | 124 | ||
| @@ -179,6 +183,7 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); | |||
| 179 | /* pnfs.c */ | 183 | /* pnfs.c */ |
| 180 | void pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo); | 184 | void pnfs_get_layout_hdr(struct pnfs_layout_hdr *lo); |
| 181 | void pnfs_put_lseg(struct pnfs_layout_segment *lseg); | 185 | void pnfs_put_lseg(struct pnfs_layout_segment *lseg); |
| 186 | void pnfs_put_lseg_async(struct pnfs_layout_segment *lseg); | ||
| 182 | 187 | ||
| 183 | void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32); | 188 | void set_pnfs_layoutdriver(struct nfs_server *, const struct nfs_fh *, u32); |
| 184 | void unset_pnfs_layoutdriver(struct nfs_server *); | 189 | void unset_pnfs_layoutdriver(struct nfs_server *); |
| @@ -213,13 +218,13 @@ bool pnfs_roc(struct inode *ino); | |||
| 213 | void pnfs_roc_release(struct inode *ino); | 218 | void pnfs_roc_release(struct inode *ino); |
| 214 | void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); | 219 | void pnfs_roc_set_barrier(struct inode *ino, u32 barrier); |
| 215 | bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task); | 220 | bool pnfs_roc_drain(struct inode *ino, u32 *barrier, struct rpc_task *task); |
| 216 | void pnfs_set_layoutcommit(struct nfs_pgio_data *wdata); | 221 | void pnfs_set_layoutcommit(struct nfs_pgio_header *); |
| 217 | void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data); | 222 | void pnfs_cleanup_layoutcommit(struct nfs4_layoutcommit_data *data); |
| 218 | int pnfs_layoutcommit_inode(struct inode *inode, bool sync); | 223 | int pnfs_layoutcommit_inode(struct inode *inode, bool sync); |
| 219 | int _pnfs_return_layout(struct inode *); | 224 | int _pnfs_return_layout(struct inode *); |
| 220 | int pnfs_commit_and_return_layout(struct inode *); | 225 | int pnfs_commit_and_return_layout(struct inode *); |
| 221 | void pnfs_ld_write_done(struct nfs_pgio_data *); | 226 | void pnfs_ld_write_done(struct nfs_pgio_header *); |
| 222 | void pnfs_ld_read_done(struct nfs_pgio_data *); | 227 | void pnfs_ld_read_done(struct nfs_pgio_header *); |
| 223 | struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, | 228 | struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, |
| 224 | struct nfs_open_context *ctx, | 229 | struct nfs_open_context *ctx, |
| 225 | loff_t pos, | 230 | loff_t pos, |
| @@ -228,12 +233,8 @@ struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, | |||
| 228 | gfp_t gfp_flags); | 233 | gfp_t gfp_flags); |
| 229 | 234 | ||
| 230 | void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp); | 235 | void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp); |
| 231 | int pnfs_read_done_resend_to_mds(struct inode *inode, struct list_head *head, | 236 | int pnfs_read_done_resend_to_mds(struct nfs_pgio_header *); |
| 232 | const struct nfs_pgio_completion_ops *compl_ops, | 237 | int pnfs_write_done_resend_to_mds(struct nfs_pgio_header *); |
| 233 | struct nfs_direct_req *dreq); | ||
| 234 | int pnfs_write_done_resend_to_mds(struct inode *inode, struct list_head *head, | ||
| 235 | const struct nfs_pgio_completion_ops *compl_ops, | ||
| 236 | struct nfs_direct_req *dreq); | ||
| 237 | struct nfs4_threshold *pnfs_mdsthreshold_alloc(void); | 238 | struct nfs4_threshold *pnfs_mdsthreshold_alloc(void); |
| 238 | 239 | ||
| 239 | /* nfs4_deviceid_flags */ | 240 | /* nfs4_deviceid_flags */ |
| @@ -345,6 +346,17 @@ pnfs_recover_commit_reqs(struct inode *inode, struct list_head *list, | |||
| 345 | NFS_SERVER(inode)->pnfs_curr_ld->recover_commit_reqs(list, cinfo); | 346 | NFS_SERVER(inode)->pnfs_curr_ld->recover_commit_reqs(list, cinfo); |
| 346 | } | 347 | } |
| 347 | 348 | ||
| 349 | static inline struct nfs_page * | ||
| 350 | pnfs_search_commit_reqs(struct inode *inode, struct nfs_commit_info *cinfo, | ||
| 351 | struct page *page) | ||
| 352 | { | ||
| 353 | struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; | ||
| 354 | |||
| 355 | if (ld == NULL || ld->search_commit_reqs == NULL) | ||
| 356 | return NULL; | ||
| 357 | return ld->search_commit_reqs(cinfo, page); | ||
| 358 | } | ||
| 359 | |||
| 348 | /* Should the pNFS client commit and return the layout upon a setattr */ | 360 | /* Should the pNFS client commit and return the layout upon a setattr */ |
| 349 | static inline bool | 361 | static inline bool |
| 350 | pnfs_ld_layoutret_on_setattr(struct inode *inode) | 362 | pnfs_ld_layoutret_on_setattr(struct inode *inode) |
| @@ -410,6 +422,10 @@ static inline void pnfs_put_lseg(struct pnfs_layout_segment *lseg) | |||
| 410 | { | 422 | { |
| 411 | } | 423 | } |
| 412 | 424 | ||
| 425 | static inline void pnfs_put_lseg_async(struct pnfs_layout_segment *lseg) | ||
| 426 | { | ||
| 427 | } | ||
| 428 | |||
| 413 | static inline int pnfs_return_layout(struct inode *ino) | 429 | static inline int pnfs_return_layout(struct inode *ino) |
| 414 | { | 430 | { |
| 415 | return 0; | 431 | return 0; |
| @@ -496,6 +512,13 @@ pnfs_recover_commit_reqs(struct inode *inode, struct list_head *list, | |||
| 496 | { | 512 | { |
| 497 | } | 513 | } |
| 498 | 514 | ||
| 515 | static inline struct nfs_page * | ||
| 516 | pnfs_search_commit_reqs(struct inode *inode, struct nfs_commit_info *cinfo, | ||
| 517 | struct page *page) | ||
| 518 | { | ||
| 519 | return NULL; | ||
| 520 | } | ||
| 521 | |||
| 499 | static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync) | 522 | static inline int pnfs_layoutcommit_inode(struct inode *inode, bool sync) |
| 500 | { | 523 | { |
| 501 | return 0; | 524 | return 0; |
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c index c171ce1a8a30..b09cc23d6f43 100644 --- a/fs/nfs/proc.c +++ b/fs/nfs/proc.c | |||
| @@ -578,46 +578,49 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, | |||
| 578 | return 0; | 578 | return 0; |
| 579 | } | 579 | } |
| 580 | 580 | ||
| 581 | static int nfs_read_done(struct rpc_task *task, struct nfs_pgio_data *data) | 581 | static int nfs_read_done(struct rpc_task *task, struct nfs_pgio_header *hdr) |
| 582 | { | 582 | { |
| 583 | struct inode *inode = data->header->inode; | 583 | struct inode *inode = hdr->inode; |
| 584 | 584 | ||
| 585 | nfs_invalidate_atime(inode); | 585 | nfs_invalidate_atime(inode); |
| 586 | if (task->tk_status >= 0) { | 586 | if (task->tk_status >= 0) { |
| 587 | nfs_refresh_inode(inode, data->res.fattr); | 587 | nfs_refresh_inode(inode, hdr->res.fattr); |
| 588 | /* Emulate the eof flag, which isn't normally needed in NFSv2 | 588 | /* Emulate the eof flag, which isn't normally needed in NFSv2 |
| 589 | * as it is guaranteed to always return the file attributes | 589 | * as it is guaranteed to always return the file attributes |
| 590 | */ | 590 | */ |
| 591 | if (data->args.offset + data->res.count >= data->res.fattr->size) | 591 | if (hdr->args.offset + hdr->res.count >= hdr->res.fattr->size) |
| 592 | data->res.eof = 1; | 592 | hdr->res.eof = 1; |
| 593 | } | 593 | } |
| 594 | return 0; | 594 | return 0; |
| 595 | } | 595 | } |
| 596 | 596 | ||
| 597 | static void nfs_proc_read_setup(struct nfs_pgio_data *data, struct rpc_message *msg) | 597 | static void nfs_proc_read_setup(struct nfs_pgio_header *hdr, |
| 598 | struct rpc_message *msg) | ||
| 598 | { | 599 | { |
| 599 | msg->rpc_proc = &nfs_procedures[NFSPROC_READ]; | 600 | msg->rpc_proc = &nfs_procedures[NFSPROC_READ]; |
| 600 | } | 601 | } |
| 601 | 602 | ||
| 602 | static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task, struct nfs_pgio_data *data) | 603 | static int nfs_proc_pgio_rpc_prepare(struct rpc_task *task, |
| 604 | struct nfs_pgio_header *hdr) | ||
| 603 | { | 605 | { |
| 604 | rpc_call_start(task); | 606 | rpc_call_start(task); |
| 605 | return 0; | 607 | return 0; |
| 606 | } | 608 | } |
| 607 | 609 | ||
| 608 | static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_data *data) | 610 | static int nfs_write_done(struct rpc_task *task, struct nfs_pgio_header *hdr) |
| 609 | { | 611 | { |
| 610 | struct inode *inode = data->header->inode; | 612 | struct inode *inode = hdr->inode; |
| 611 | 613 | ||
| 612 | if (task->tk_status >= 0) | 614 | if (task->tk_status >= 0) |
| 613 | nfs_post_op_update_inode_force_wcc(inode, data->res.fattr); | 615 | nfs_post_op_update_inode_force_wcc(inode, hdr->res.fattr); |
| 614 | return 0; | 616 | return 0; |
| 615 | } | 617 | } |
| 616 | 618 | ||
| 617 | static void nfs_proc_write_setup(struct nfs_pgio_data *data, struct rpc_message *msg) | 619 | static void nfs_proc_write_setup(struct nfs_pgio_header *hdr, |
| 620 | struct rpc_message *msg) | ||
| 618 | { | 621 | { |
| 619 | /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ | 622 | /* Note: NFSv2 ignores @stable and always uses NFS_FILE_SYNC */ |
| 620 | data->args.stable = NFS_FILE_SYNC; | 623 | hdr->args.stable = NFS_FILE_SYNC; |
| 621 | msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE]; | 624 | msg->rpc_proc = &nfs_procedures[NFSPROC_WRITE]; |
| 622 | } | 625 | } |
| 623 | 626 | ||
diff --git a/fs/nfs/read.c b/fs/nfs/read.c index e818a475ca64..beff2769c5c5 100644 --- a/fs/nfs/read.c +++ b/fs/nfs/read.c | |||
| @@ -33,12 +33,12 @@ static const struct nfs_rw_ops nfs_rw_read_ops; | |||
| 33 | 33 | ||
| 34 | static struct kmem_cache *nfs_rdata_cachep; | 34 | static struct kmem_cache *nfs_rdata_cachep; |
| 35 | 35 | ||
| 36 | static struct nfs_rw_header *nfs_readhdr_alloc(void) | 36 | static struct nfs_pgio_header *nfs_readhdr_alloc(void) |
| 37 | { | 37 | { |
| 38 | return kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL); | 38 | return kmem_cache_zalloc(nfs_rdata_cachep, GFP_KERNEL); |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | static void nfs_readhdr_free(struct nfs_rw_header *rhdr) | 41 | static void nfs_readhdr_free(struct nfs_pgio_header *rhdr) |
| 42 | { | 42 | { |
| 43 | kmem_cache_free(nfs_rdata_cachep, rhdr); | 43 | kmem_cache_free(nfs_rdata_cachep, rhdr); |
| 44 | } | 44 | } |
| @@ -115,12 +115,6 @@ static void nfs_readpage_release(struct nfs_page *req) | |||
| 115 | 115 | ||
| 116 | unlock_page(req->wb_page); | 116 | unlock_page(req->wb_page); |
| 117 | } | 117 | } |
| 118 | |||
| 119 | dprintk("NFS: read done (%s/%Lu %d@%Ld)\n", | ||
| 120 | req->wb_context->dentry->d_inode->i_sb->s_id, | ||
| 121 | (unsigned long long)NFS_FILEID(req->wb_context->dentry->d_inode), | ||
| 122 | req->wb_bytes, | ||
| 123 | (long long)req_offset(req)); | ||
| 124 | nfs_release_request(req); | 118 | nfs_release_request(req); |
| 125 | } | 119 | } |
| 126 | 120 | ||
| @@ -172,14 +166,15 @@ out: | |||
| 172 | hdr->release(hdr); | 166 | hdr->release(hdr); |
| 173 | } | 167 | } |
| 174 | 168 | ||
| 175 | static void nfs_initiate_read(struct nfs_pgio_data *data, struct rpc_message *msg, | 169 | static void nfs_initiate_read(struct nfs_pgio_header *hdr, |
| 170 | struct rpc_message *msg, | ||
| 176 | struct rpc_task_setup *task_setup_data, int how) | 171 | struct rpc_task_setup *task_setup_data, int how) |
| 177 | { | 172 | { |
| 178 | struct inode *inode = data->header->inode; | 173 | struct inode *inode = hdr->inode; |
| 179 | int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; | 174 | int swap_flags = IS_SWAPFILE(inode) ? NFS_RPC_SWAPFLAGS : 0; |
| 180 | 175 | ||
| 181 | task_setup_data->flags |= swap_flags; | 176 | task_setup_data->flags |= swap_flags; |
| 182 | NFS_PROTO(inode)->read_setup(data, msg); | 177 | NFS_PROTO(inode)->read_setup(hdr, msg); |
| 183 | } | 178 | } |
| 184 | 179 | ||
| 185 | static void | 180 | static void |
| @@ -203,14 +198,15 @@ static const struct nfs_pgio_completion_ops nfs_async_read_completion_ops = { | |||
| 203 | * This is the callback from RPC telling us whether a reply was | 198 | * This is the callback from RPC telling us whether a reply was |
| 204 | * received or some error occurred (timeout or socket shutdown). | 199 | * received or some error occurred (timeout or socket shutdown). |
| 205 | */ | 200 | */ |
| 206 | static int nfs_readpage_done(struct rpc_task *task, struct nfs_pgio_data *data, | 201 | static int nfs_readpage_done(struct rpc_task *task, |
| 202 | struct nfs_pgio_header *hdr, | ||
| 207 | struct inode *inode) | 203 | struct inode *inode) |
| 208 | { | 204 | { |
| 209 | int status = NFS_PROTO(inode)->read_done(task, data); | 205 | int status = NFS_PROTO(inode)->read_done(task, hdr); |
| 210 | if (status != 0) | 206 | if (status != 0) |
| 211 | return status; | 207 | return status; |
| 212 | 208 | ||
| 213 | nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, data->res.count); | 209 | nfs_add_stats(inode, NFSIOS_SERVERREADBYTES, hdr->res.count); |
| 214 | 210 | ||
| 215 | if (task->tk_status == -ESTALE) { | 211 | if (task->tk_status == -ESTALE) { |
| 216 | set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); | 212 | set_bit(NFS_INO_STALE, &NFS_I(inode)->flags); |
| @@ -219,34 +215,34 @@ static int nfs_readpage_done(struct rpc_task *task, struct nfs_pgio_data *data, | |||
| 219 | return 0; | 215 | return 0; |
| 220 | } | 216 | } |
| 221 | 217 | ||
| 222 | static void nfs_readpage_retry(struct rpc_task *task, struct nfs_pgio_data *data) | 218 | static void nfs_readpage_retry(struct rpc_task *task, |
| 219 | struct nfs_pgio_header *hdr) | ||
| 223 | { | 220 | { |
| 224 | struct nfs_pgio_args *argp = &data->args; | 221 | struct nfs_pgio_args *argp = &hdr->args; |
| 225 | struct nfs_pgio_res *resp = &data->res; | 222 | struct nfs_pgio_res *resp = &hdr->res; |
| 226 | 223 | ||
| 227 | /* This is a short read! */ | 224 | /* This is a short read! */ |
| 228 | nfs_inc_stats(data->header->inode, NFSIOS_SHORTREAD); | 225 | nfs_inc_stats(hdr->inode, NFSIOS_SHORTREAD); |
| 229 | /* Has the server at least made some progress? */ | 226 | /* Has the server at least made some progress? */ |
| 230 | if (resp->count == 0) { | 227 | if (resp->count == 0) { |
| 231 | nfs_set_pgio_error(data->header, -EIO, argp->offset); | 228 | nfs_set_pgio_error(hdr, -EIO, argp->offset); |
| 232 | return; | 229 | return; |
| 233 | } | 230 | } |
| 234 | /* Yes, so retry the read at the end of the data */ | 231 | /* Yes, so retry the read at the end of the hdr */ |
| 235 | data->mds_offset += resp->count; | 232 | hdr->mds_offset += resp->count; |
| 236 | argp->offset += resp->count; | 233 | argp->offset += resp->count; |
| 237 | argp->pgbase += resp->count; | 234 | argp->pgbase += resp->count; |
| 238 | argp->count -= resp->count; | 235 | argp->count -= resp->count; |
| 239 | rpc_restart_call_prepare(task); | 236 | rpc_restart_call_prepare(task); |
| 240 | } | 237 | } |
| 241 | 238 | ||
| 242 | static void nfs_readpage_result(struct rpc_task *task, struct nfs_pgio_data *data) | 239 | static void nfs_readpage_result(struct rpc_task *task, |
| 240 | struct nfs_pgio_header *hdr) | ||
| 243 | { | 241 | { |
| 244 | struct nfs_pgio_header *hdr = data->header; | 242 | if (hdr->res.eof) { |
| 245 | |||
| 246 | if (data->res.eof) { | ||
| 247 | loff_t bound; | 243 | loff_t bound; |
| 248 | 244 | ||
| 249 | bound = data->args.offset + data->res.count; | 245 | bound = hdr->args.offset + hdr->res.count; |
| 250 | spin_lock(&hdr->lock); | 246 | spin_lock(&hdr->lock); |
| 251 | if (bound < hdr->io_start + hdr->good_bytes) { | 247 | if (bound < hdr->io_start + hdr->good_bytes) { |
| 252 | set_bit(NFS_IOHDR_EOF, &hdr->flags); | 248 | set_bit(NFS_IOHDR_EOF, &hdr->flags); |
| @@ -254,8 +250,8 @@ static void nfs_readpage_result(struct rpc_task *task, struct nfs_pgio_data *dat | |||
| 254 | hdr->good_bytes = bound - hdr->io_start; | 250 | hdr->good_bytes = bound - hdr->io_start; |
| 255 | } | 251 | } |
| 256 | spin_unlock(&hdr->lock); | 252 | spin_unlock(&hdr->lock); |
| 257 | } else if (data->res.count != data->args.count) | 253 | } else if (hdr->res.count != hdr->args.count) |
| 258 | nfs_readpage_retry(task, data); | 254 | nfs_readpage_retry(task, hdr); |
| 259 | } | 255 | } |
| 260 | 256 | ||
| 261 | /* | 257 | /* |
| @@ -404,7 +400,7 @@ out: | |||
| 404 | int __init nfs_init_readpagecache(void) | 400 | int __init nfs_init_readpagecache(void) |
| 405 | { | 401 | { |
| 406 | nfs_rdata_cachep = kmem_cache_create("nfs_read_data", | 402 | nfs_rdata_cachep = kmem_cache_create("nfs_read_data", |
| 407 | sizeof(struct nfs_rw_header), | 403 | sizeof(struct nfs_pgio_header), |
| 408 | 0, SLAB_HWCACHE_ALIGN, | 404 | 0, SLAB_HWCACHE_ALIGN, |
| 409 | NULL); | 405 | NULL); |
| 410 | if (nfs_rdata_cachep == NULL) | 406 | if (nfs_rdata_cachep == NULL) |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 084af1060d79..e4499d5b51e8 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -1027,8 +1027,7 @@ static bool nfs_auth_info_add(struct nfs_auth_info *auth_info, | |||
| 1027 | rpc_authflavor_t flavor) | 1027 | rpc_authflavor_t flavor) |
| 1028 | { | 1028 | { |
| 1029 | unsigned int i; | 1029 | unsigned int i; |
| 1030 | unsigned int max_flavor_len = (sizeof(auth_info->flavors) / | 1030 | unsigned int max_flavor_len = ARRAY_SIZE(auth_info->flavors); |
| 1031 | sizeof(auth_info->flavors[0])); | ||
| 1032 | 1031 | ||
| 1033 | /* make sure this flavor isn't already in the list */ | 1032 | /* make sure this flavor isn't already in the list */ |
| 1034 | for (i = 0; i < auth_info->flavor_len; i++) { | 1033 | for (i = 0; i < auth_info->flavor_len; i++) { |
| @@ -2180,7 +2179,7 @@ out_no_address: | |||
| 2180 | return -EINVAL; | 2179 | return -EINVAL; |
| 2181 | } | 2180 | } |
| 2182 | 2181 | ||
| 2183 | #define NFS_MOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \ | 2182 | #define NFS_REMOUNT_CMP_FLAGMASK ~(NFS_MOUNT_INTR \ |
| 2184 | | NFS_MOUNT_SECURE \ | 2183 | | NFS_MOUNT_SECURE \ |
| 2185 | | NFS_MOUNT_TCP \ | 2184 | | NFS_MOUNT_TCP \ |
| 2186 | | NFS_MOUNT_VER3 \ | 2185 | | NFS_MOUNT_VER3 \ |
| @@ -2188,15 +2187,16 @@ out_no_address: | |||
| 2188 | | NFS_MOUNT_NONLM \ | 2187 | | NFS_MOUNT_NONLM \ |
| 2189 | | NFS_MOUNT_BROKEN_SUID \ | 2188 | | NFS_MOUNT_BROKEN_SUID \ |
| 2190 | | NFS_MOUNT_STRICTLOCK \ | 2189 | | NFS_MOUNT_STRICTLOCK \ |
| 2191 | | NFS_MOUNT_UNSHARED \ | ||
| 2192 | | NFS_MOUNT_NORESVPORT \ | ||
| 2193 | | NFS_MOUNT_LEGACY_INTERFACE) | 2190 | | NFS_MOUNT_LEGACY_INTERFACE) |
| 2194 | 2191 | ||
| 2192 | #define NFS_MOUNT_CMP_FLAGMASK (NFS_REMOUNT_CMP_FLAGMASK & \ | ||
| 2193 | ~(NFS_MOUNT_UNSHARED | NFS_MOUNT_NORESVPORT)) | ||
| 2194 | |||
| 2195 | static int | 2195 | static int |
| 2196 | nfs_compare_remount_data(struct nfs_server *nfss, | 2196 | nfs_compare_remount_data(struct nfs_server *nfss, |
| 2197 | struct nfs_parsed_mount_data *data) | 2197 | struct nfs_parsed_mount_data *data) |
| 2198 | { | 2198 | { |
| 2199 | if ((data->flags ^ nfss->flags) & NFS_MOUNT_CMP_FLAGMASK || | 2199 | if ((data->flags ^ nfss->flags) & NFS_REMOUNT_CMP_FLAGMASK || |
| 2200 | data->rsize != nfss->rsize || | 2200 | data->rsize != nfss->rsize || |
| 2201 | data->wsize != nfss->wsize || | 2201 | data->wsize != nfss->wsize || |
| 2202 | data->version != nfss->nfs_client->rpc_ops->version || | 2202 | data->version != nfss->nfs_client->rpc_ops->version || |
diff --git a/fs/nfs/write.c b/fs/nfs/write.c index 962c9ee758be..e3b5cf28bdc5 100644 --- a/fs/nfs/write.c +++ b/fs/nfs/write.c | |||
| @@ -47,6 +47,8 @@ static const struct nfs_pgio_completion_ops nfs_async_write_completion_ops; | |||
| 47 | static const struct nfs_commit_completion_ops nfs_commit_completion_ops; | 47 | static const struct nfs_commit_completion_ops nfs_commit_completion_ops; |
| 48 | static const struct nfs_rw_ops nfs_rw_write_ops; | 48 | static const struct nfs_rw_ops nfs_rw_write_ops; |
| 49 | static void nfs_clear_request_commit(struct nfs_page *req); | 49 | static void nfs_clear_request_commit(struct nfs_page *req); |
| 50 | static void nfs_init_cinfo_from_inode(struct nfs_commit_info *cinfo, | ||
| 51 | struct inode *inode); | ||
| 50 | 52 | ||
| 51 | static struct kmem_cache *nfs_wdata_cachep; | 53 | static struct kmem_cache *nfs_wdata_cachep; |
| 52 | static mempool_t *nfs_wdata_mempool; | 54 | static mempool_t *nfs_wdata_mempool; |
| @@ -71,18 +73,18 @@ void nfs_commit_free(struct nfs_commit_data *p) | |||
| 71 | } | 73 | } |
| 72 | EXPORT_SYMBOL_GPL(nfs_commit_free); | 74 | EXPORT_SYMBOL_GPL(nfs_commit_free); |
| 73 | 75 | ||
| 74 | static struct nfs_rw_header *nfs_writehdr_alloc(void) | 76 | static struct nfs_pgio_header *nfs_writehdr_alloc(void) |
| 75 | { | 77 | { |
| 76 | struct nfs_rw_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOIO); | 78 | struct nfs_pgio_header *p = mempool_alloc(nfs_wdata_mempool, GFP_NOIO); |
| 77 | 79 | ||
| 78 | if (p) | 80 | if (p) |
| 79 | memset(p, 0, sizeof(*p)); | 81 | memset(p, 0, sizeof(*p)); |
| 80 | return p; | 82 | return p; |
| 81 | } | 83 | } |
| 82 | 84 | ||
| 83 | static void nfs_writehdr_free(struct nfs_rw_header *whdr) | 85 | static void nfs_writehdr_free(struct nfs_pgio_header *hdr) |
| 84 | { | 86 | { |
| 85 | mempool_free(whdr, nfs_wdata_mempool); | 87 | mempool_free(hdr, nfs_wdata_mempool); |
| 86 | } | 88 | } |
| 87 | 89 | ||
| 88 | static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) | 90 | static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) |
| @@ -93,6 +95,38 @@ static void nfs_context_set_write_error(struct nfs_open_context *ctx, int error) | |||
| 93 | } | 95 | } |
| 94 | 96 | ||
| 95 | /* | 97 | /* |
| 98 | * nfs_page_search_commits_for_head_request_locked | ||
| 99 | * | ||
| 100 | * Search through commit lists on @inode for the head request for @page. | ||
| 101 | * Must be called while holding the inode (which is cinfo) lock. | ||
| 102 | * | ||
| 103 | * Returns the head request if found, or NULL if not found. | ||
| 104 | */ | ||
| 105 | static struct nfs_page * | ||
| 106 | nfs_page_search_commits_for_head_request_locked(struct nfs_inode *nfsi, | ||
| 107 | struct page *page) | ||
| 108 | { | ||
| 109 | struct nfs_page *freq, *t; | ||
| 110 | struct nfs_commit_info cinfo; | ||
| 111 | struct inode *inode = &nfsi->vfs_inode; | ||
| 112 | |||
| 113 | nfs_init_cinfo_from_inode(&cinfo, inode); | ||
| 114 | |||
| 115 | /* search through pnfs commit lists */ | ||
| 116 | freq = pnfs_search_commit_reqs(inode, &cinfo, page); | ||
| 117 | if (freq) | ||
| 118 | return freq->wb_head; | ||
| 119 | |||
| 120 | /* Linearly search the commit list for the correct request */ | ||
| 121 | list_for_each_entry_safe(freq, t, &cinfo.mds->list, wb_list) { | ||
| 122 | if (freq->wb_page == page) | ||
| 123 | return freq->wb_head; | ||
| 124 | } | ||
| 125 | |||
| 126 | return NULL; | ||
| 127 | } | ||
| 128 | |||
| 129 | /* | ||
| 96 | * nfs_page_find_head_request_locked - find head request associated with @page | 130 | * nfs_page_find_head_request_locked - find head request associated with @page |
| 97 | * | 131 | * |
| 98 | * must be called while holding the inode lock. | 132 | * must be called while holding the inode lock. |
| @@ -106,21 +140,12 @@ nfs_page_find_head_request_locked(struct nfs_inode *nfsi, struct page *page) | |||
| 106 | 140 | ||
| 107 | if (PagePrivate(page)) | 141 | if (PagePrivate(page)) |
| 108 | req = (struct nfs_page *)page_private(page); | 142 | req = (struct nfs_page *)page_private(page); |
| 109 | else if (unlikely(PageSwapCache(page))) { | 143 | else if (unlikely(PageSwapCache(page))) |
| 110 | struct nfs_page *freq, *t; | 144 | req = nfs_page_search_commits_for_head_request_locked(nfsi, |
| 111 | 145 | page); | |
| 112 | /* Linearly search the commit list for the correct req */ | ||
| 113 | list_for_each_entry_safe(freq, t, &nfsi->commit_info.list, wb_list) { | ||
| 114 | if (freq->wb_page == page) { | ||
| 115 | req = freq->wb_head; | ||
| 116 | break; | ||
| 117 | } | ||
| 118 | } | ||
| 119 | } | ||
| 120 | 146 | ||
| 121 | if (req) { | 147 | if (req) { |
| 122 | WARN_ON_ONCE(req->wb_head != req); | 148 | WARN_ON_ONCE(req->wb_head != req); |
| 123 | |||
| 124 | kref_get(&req->wb_kref); | 149 | kref_get(&req->wb_kref); |
| 125 | } | 150 | } |
| 126 | 151 | ||
| @@ -216,7 +241,7 @@ static bool nfs_page_group_covers_page(struct nfs_page *req) | |||
| 216 | unsigned int pos = 0; | 241 | unsigned int pos = 0; |
| 217 | unsigned int len = nfs_page_length(req->wb_page); | 242 | unsigned int len = nfs_page_length(req->wb_page); |
| 218 | 243 | ||
| 219 | nfs_page_group_lock(req); | 244 | nfs_page_group_lock(req, true); |
| 220 | 245 | ||
| 221 | do { | 246 | do { |
| 222 | tmp = nfs_page_group_search_locked(req->wb_head, pos); | 247 | tmp = nfs_page_group_search_locked(req->wb_head, pos); |
| @@ -379,8 +404,6 @@ nfs_destroy_unlinked_subrequests(struct nfs_page *destroy_list, | |||
| 379 | subreq->wb_head = subreq; | 404 | subreq->wb_head = subreq; |
| 380 | subreq->wb_this_page = subreq; | 405 | subreq->wb_this_page = subreq; |
| 381 | 406 | ||
| 382 | nfs_clear_request_commit(subreq); | ||
| 383 | |||
| 384 | /* subreq is now totally disconnected from page group or any | 407 | /* subreq is now totally disconnected from page group or any |
| 385 | * write / commit lists. last chance to wake any waiters */ | 408 | * write / commit lists. last chance to wake any waiters */ |
| 386 | nfs_unlock_request(subreq); | 409 | nfs_unlock_request(subreq); |
| @@ -456,7 +479,9 @@ try_again: | |||
| 456 | } | 479 | } |
| 457 | 480 | ||
| 458 | /* lock each request in the page group */ | 481 | /* lock each request in the page group */ |
| 459 | nfs_page_group_lock(head); | 482 | ret = nfs_page_group_lock(head, false); |
| 483 | if (ret < 0) | ||
| 484 | return ERR_PTR(ret); | ||
| 460 | subreq = head; | 485 | subreq = head; |
| 461 | do { | 486 | do { |
| 462 | /* | 487 | /* |
| @@ -488,7 +513,7 @@ try_again: | |||
| 488 | * Commit list removal accounting is done after locks are dropped */ | 513 | * Commit list removal accounting is done after locks are dropped */ |
| 489 | subreq = head; | 514 | subreq = head; |
| 490 | do { | 515 | do { |
| 491 | nfs_list_remove_request(subreq); | 516 | nfs_clear_request_commit(subreq); |
| 492 | subreq = subreq->wb_this_page; | 517 | subreq = subreq->wb_this_page; |
| 493 | } while (subreq != head); | 518 | } while (subreq != head); |
| 494 | 519 | ||
| @@ -518,15 +543,11 @@ try_again: | |||
| 518 | 543 | ||
| 519 | nfs_page_group_unlock(head); | 544 | nfs_page_group_unlock(head); |
| 520 | 545 | ||
| 521 | /* drop lock to clear_request_commit the head req and clean up | 546 | /* drop lock to clean uprequests on destroy list */ |
| 522 | * requests on destroy list */ | ||
| 523 | spin_unlock(&inode->i_lock); | 547 | spin_unlock(&inode->i_lock); |
| 524 | 548 | ||
| 525 | nfs_destroy_unlinked_subrequests(destroy_list, head); | 549 | nfs_destroy_unlinked_subrequests(destroy_list, head); |
| 526 | 550 | ||
| 527 | /* clean up commit list state */ | ||
| 528 | nfs_clear_request_commit(head); | ||
| 529 | |||
| 530 | /* still holds ref on head from nfs_page_find_head_request_locked | 551 | /* still holds ref on head from nfs_page_find_head_request_locked |
| 531 | * and still has lock on head from lock loop */ | 552 | * and still has lock on head from lock loop */ |
| 532 | return head; | 553 | return head; |
| @@ -705,6 +726,8 @@ static void nfs_inode_remove_request(struct nfs_page *req) | |||
| 705 | 726 | ||
| 706 | if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) | 727 | if (test_and_clear_bit(PG_INODE_REF, &req->wb_flags)) |
| 707 | nfs_release_request(req); | 728 | nfs_release_request(req); |
| 729 | else | ||
| 730 | WARN_ON_ONCE(1); | ||
| 708 | } | 731 | } |
| 709 | 732 | ||
| 710 | static void | 733 | static void |
| @@ -808,6 +831,7 @@ nfs_clear_page_commit(struct page *page) | |||
| 808 | dec_bdi_stat(page_file_mapping(page)->backing_dev_info, BDI_RECLAIMABLE); | 831 | dec_bdi_stat(page_file_mapping(page)->backing_dev_info, BDI_RECLAIMABLE); |
| 809 | } | 832 | } |
| 810 | 833 | ||
| 834 | /* Called holding inode (/cinfo) lock */ | ||
| 811 | static void | 835 | static void |
| 812 | nfs_clear_request_commit(struct nfs_page *req) | 836 | nfs_clear_request_commit(struct nfs_page *req) |
| 813 | { | 837 | { |
| @@ -817,20 +841,17 @@ nfs_clear_request_commit(struct nfs_page *req) | |||
| 817 | 841 | ||
| 818 | nfs_init_cinfo_from_inode(&cinfo, inode); | 842 | nfs_init_cinfo_from_inode(&cinfo, inode); |
| 819 | if (!pnfs_clear_request_commit(req, &cinfo)) { | 843 | if (!pnfs_clear_request_commit(req, &cinfo)) { |
| 820 | spin_lock(cinfo.lock); | ||
| 821 | nfs_request_remove_commit_list(req, &cinfo); | 844 | nfs_request_remove_commit_list(req, &cinfo); |
| 822 | spin_unlock(cinfo.lock); | ||
| 823 | } | 845 | } |
| 824 | nfs_clear_page_commit(req->wb_page); | 846 | nfs_clear_page_commit(req->wb_page); |
| 825 | } | 847 | } |
| 826 | } | 848 | } |
| 827 | 849 | ||
| 828 | static inline | 850 | int nfs_write_need_commit(struct nfs_pgio_header *hdr) |
| 829 | int nfs_write_need_commit(struct nfs_pgio_data *data) | ||
| 830 | { | 851 | { |
| 831 | if (data->verf.committed == NFS_DATA_SYNC) | 852 | if (hdr->verf.committed == NFS_DATA_SYNC) |
| 832 | return data->header->lseg == NULL; | 853 | return hdr->lseg == NULL; |
| 833 | return data->verf.committed != NFS_FILE_SYNC; | 854 | return hdr->verf.committed != NFS_FILE_SYNC; |
| 834 | } | 855 | } |
| 835 | 856 | ||
| 836 | #else | 857 | #else |
| @@ -856,8 +877,7 @@ nfs_clear_request_commit(struct nfs_page *req) | |||
| 856 | { | 877 | { |
| 857 | } | 878 | } |
| 858 | 879 | ||
| 859 | static inline | 880 | int nfs_write_need_commit(struct nfs_pgio_header *hdr) |
| 860 | int nfs_write_need_commit(struct nfs_pgio_data *data) | ||
| 861 | { | 881 | { |
| 862 | return 0; | 882 | return 0; |
| 863 | } | 883 | } |
| @@ -883,11 +903,7 @@ static void nfs_write_completion(struct nfs_pgio_header *hdr) | |||
| 883 | nfs_context_set_write_error(req->wb_context, hdr->error); | 903 | nfs_context_set_write_error(req->wb_context, hdr->error); |
| 884 | goto remove_req; | 904 | goto remove_req; |
| 885 | } | 905 | } |
| 886 | if (test_bit(NFS_IOHDR_NEED_RESCHED, &hdr->flags)) { | 906 | if (nfs_write_need_commit(hdr)) { |
| 887 | nfs_mark_request_dirty(req); | ||
| 888 | goto next; | ||
| 889 | } | ||
| 890 | if (test_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) { | ||
| 891 | memcpy(&req->wb_verf, &hdr->verf.verifier, sizeof(req->wb_verf)); | 907 | memcpy(&req->wb_verf, &hdr->verf.verifier, sizeof(req->wb_verf)); |
| 892 | nfs_mark_request_commit(req, hdr->lseg, &cinfo); | 908 | nfs_mark_request_commit(req, hdr->lseg, &cinfo); |
| 893 | goto next; | 909 | goto next; |
| @@ -1038,9 +1054,9 @@ static struct nfs_page *nfs_try_to_update_request(struct inode *inode, | |||
| 1038 | else | 1054 | else |
| 1039 | req->wb_bytes = rqend - req->wb_offset; | 1055 | req->wb_bytes = rqend - req->wb_offset; |
| 1040 | out_unlock: | 1056 | out_unlock: |
| 1041 | spin_unlock(&inode->i_lock); | ||
| 1042 | if (req) | 1057 | if (req) |
| 1043 | nfs_clear_request_commit(req); | 1058 | nfs_clear_request_commit(req); |
| 1059 | spin_unlock(&inode->i_lock); | ||
| 1044 | return req; | 1060 | return req; |
| 1045 | out_flushme: | 1061 | out_flushme: |
| 1046 | spin_unlock(&inode->i_lock); | 1062 | spin_unlock(&inode->i_lock); |
| @@ -1241,17 +1257,18 @@ static int flush_task_priority(int how) | |||
| 1241 | return RPC_PRIORITY_NORMAL; | 1257 | return RPC_PRIORITY_NORMAL; |
| 1242 | } | 1258 | } |
| 1243 | 1259 | ||
| 1244 | static void nfs_initiate_write(struct nfs_pgio_data *data, struct rpc_message *msg, | 1260 | static void nfs_initiate_write(struct nfs_pgio_header *hdr, |
| 1261 | struct rpc_message *msg, | ||
| 1245 | struct rpc_task_setup *task_setup_data, int how) | 1262 | struct rpc_task_setup *task_setup_data, int how) |
| 1246 | { | 1263 | { |
| 1247 | struct inode *inode = data->header->inode; | 1264 | struct inode *inode = hdr->inode; |
| 1248 | int priority = flush_task_priority(how); | 1265 | int priority = flush_task_priority(how); |
| 1249 | 1266 | ||
| 1250 | task_setup_data->priority = priority; | 1267 | task_setup_data->priority = priority; |
| 1251 | NFS_PROTO(inode)->write_setup(data, msg); | 1268 | NFS_PROTO(inode)->write_setup(hdr, msg); |
| 1252 | 1269 | ||
| 1253 | nfs4_state_protect_write(NFS_SERVER(inode)->nfs_client, | 1270 | nfs4_state_protect_write(NFS_SERVER(inode)->nfs_client, |
| 1254 | &task_setup_data->rpc_client, msg, data); | 1271 | &task_setup_data->rpc_client, msg, hdr); |
| 1255 | } | 1272 | } |
| 1256 | 1273 | ||
| 1257 | /* If a nfs_flush_* function fails, it should remove reqs from @head and | 1274 | /* If a nfs_flush_* function fails, it should remove reqs from @head and |
| @@ -1313,21 +1330,9 @@ void nfs_commit_prepare(struct rpc_task *task, void *calldata) | |||
| 1313 | NFS_PROTO(data->inode)->commit_rpc_prepare(task, data); | 1330 | NFS_PROTO(data->inode)->commit_rpc_prepare(task, data); |
| 1314 | } | 1331 | } |
| 1315 | 1332 | ||
| 1316 | static void nfs_writeback_release_common(struct nfs_pgio_data *data) | 1333 | static void nfs_writeback_release_common(struct nfs_pgio_header *hdr) |
| 1317 | { | 1334 | { |
| 1318 | struct nfs_pgio_header *hdr = data->header; | 1335 | /* do nothing! */ |
| 1319 | int status = data->task.tk_status; | ||
| 1320 | |||
| 1321 | if ((status >= 0) && nfs_write_need_commit(data)) { | ||
| 1322 | spin_lock(&hdr->lock); | ||
| 1323 | if (test_bit(NFS_IOHDR_NEED_RESCHED, &hdr->flags)) | ||
| 1324 | ; /* Do nothing */ | ||
| 1325 | else if (!test_and_set_bit(NFS_IOHDR_NEED_COMMIT, &hdr->flags)) | ||
| 1326 | memcpy(&hdr->verf, &data->verf, sizeof(hdr->verf)); | ||
| 1327 | else if (memcmp(&hdr->verf, &data->verf, sizeof(hdr->verf))) | ||
| 1328 | set_bit(NFS_IOHDR_NEED_RESCHED, &hdr->flags); | ||
| 1329 | spin_unlock(&hdr->lock); | ||
| 1330 | } | ||
| 1331 | } | 1336 | } |
| 1332 | 1337 | ||
| 1333 | /* | 1338 | /* |
| @@ -1358,7 +1363,8 @@ static int nfs_should_remove_suid(const struct inode *inode) | |||
| 1358 | /* | 1363 | /* |
| 1359 | * This function is called when the WRITE call is complete. | 1364 | * This function is called when the WRITE call is complete. |
| 1360 | */ | 1365 | */ |
| 1361 | static int nfs_writeback_done(struct rpc_task *task, struct nfs_pgio_data *data, | 1366 | static int nfs_writeback_done(struct rpc_task *task, |
| 1367 | struct nfs_pgio_header *hdr, | ||
| 1362 | struct inode *inode) | 1368 | struct inode *inode) |
| 1363 | { | 1369 | { |
| 1364 | int status; | 1370 | int status; |
| @@ -1370,13 +1376,14 @@ static int nfs_writeback_done(struct rpc_task *task, struct nfs_pgio_data *data, | |||
| 1370 | * another writer had changed the file, but some applications | 1376 | * another writer had changed the file, but some applications |
| 1371 | * depend on tighter cache coherency when writing. | 1377 | * depend on tighter cache coherency when writing. |
| 1372 | */ | 1378 | */ |
| 1373 | status = NFS_PROTO(inode)->write_done(task, data); | 1379 | status = NFS_PROTO(inode)->write_done(task, hdr); |
| 1374 | if (status != 0) | 1380 | if (status != 0) |
| 1375 | return status; | 1381 | return status; |
| 1376 | nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, data->res.count); | 1382 | nfs_add_stats(inode, NFSIOS_SERVERWRITTENBYTES, hdr->res.count); |
| 1377 | 1383 | ||
| 1378 | #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) | 1384 | #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4) |
| 1379 | if (data->res.verf->committed < data->args.stable && task->tk_status >= 0) { | 1385 | if (hdr->res.verf->committed < hdr->args.stable && |
| 1386 | task->tk_status >= 0) { | ||
| 1380 | /* We tried a write call, but the server did not | 1387 | /* We tried a write call, but the server did not |
| 1381 | * commit data to stable storage even though we | 1388 | * commit data to stable storage even though we |
| 1382 | * requested it. | 1389 | * requested it. |
| @@ -1392,7 +1399,7 @@ static int nfs_writeback_done(struct rpc_task *task, struct nfs_pgio_data *data, | |||
| 1392 | dprintk("NFS: faulty NFS server %s:" | 1399 | dprintk("NFS: faulty NFS server %s:" |
| 1393 | " (committed = %d) != (stable = %d)\n", | 1400 | " (committed = %d) != (stable = %d)\n", |
| 1394 | NFS_SERVER(inode)->nfs_client->cl_hostname, | 1401 | NFS_SERVER(inode)->nfs_client->cl_hostname, |
| 1395 | data->res.verf->committed, data->args.stable); | 1402 | hdr->res.verf->committed, hdr->args.stable); |
| 1396 | complain = jiffies + 300 * HZ; | 1403 | complain = jiffies + 300 * HZ; |
| 1397 | } | 1404 | } |
| 1398 | } | 1405 | } |
| @@ -1407,16 +1414,17 @@ static int nfs_writeback_done(struct rpc_task *task, struct nfs_pgio_data *data, | |||
| 1407 | /* | 1414 | /* |
| 1408 | * This function is called when the WRITE call is complete. | 1415 | * This function is called when the WRITE call is complete. |
| 1409 | */ | 1416 | */ |
| 1410 | static void nfs_writeback_result(struct rpc_task *task, struct nfs_pgio_data *data) | 1417 | static void nfs_writeback_result(struct rpc_task *task, |
| 1418 | struct nfs_pgio_header *hdr) | ||
| 1411 | { | 1419 | { |
| 1412 | struct nfs_pgio_args *argp = &data->args; | 1420 | struct nfs_pgio_args *argp = &hdr->args; |
| 1413 | struct nfs_pgio_res *resp = &data->res; | 1421 | struct nfs_pgio_res *resp = &hdr->res; |
| 1414 | 1422 | ||
| 1415 | if (resp->count < argp->count) { | 1423 | if (resp->count < argp->count) { |
| 1416 | static unsigned long complain; | 1424 | static unsigned long complain; |
| 1417 | 1425 | ||
| 1418 | /* This a short write! */ | 1426 | /* This a short write! */ |
| 1419 | nfs_inc_stats(data->header->inode, NFSIOS_SHORTWRITE); | 1427 | nfs_inc_stats(hdr->inode, NFSIOS_SHORTWRITE); |
| 1420 | 1428 | ||
| 1421 | /* Has the server at least made some progress? */ | 1429 | /* Has the server at least made some progress? */ |
| 1422 | if (resp->count == 0) { | 1430 | if (resp->count == 0) { |
| @@ -1426,14 +1434,14 @@ static void nfs_writeback_result(struct rpc_task *task, struct nfs_pgio_data *da | |||
| 1426 | argp->count); | 1434 | argp->count); |
| 1427 | complain = jiffies + 300 * HZ; | 1435 | complain = jiffies + 300 * HZ; |
| 1428 | } | 1436 | } |
| 1429 | nfs_set_pgio_error(data->header, -EIO, argp->offset); | 1437 | nfs_set_pgio_error(hdr, -EIO, argp->offset); |
| 1430 | task->tk_status = -EIO; | 1438 | task->tk_status = -EIO; |
| 1431 | return; | 1439 | return; |
| 1432 | } | 1440 | } |
| 1433 | /* Was this an NFSv2 write or an NFSv3 stable write? */ | 1441 | /* Was this an NFSv2 write or an NFSv3 stable write? */ |
| 1434 | if (resp->verf->committed != NFS_UNSTABLE) { | 1442 | if (resp->verf->committed != NFS_UNSTABLE) { |
| 1435 | /* Resend from where the server left off */ | 1443 | /* Resend from where the server left off */ |
| 1436 | data->mds_offset += resp->count; | 1444 | hdr->mds_offset += resp->count; |
| 1437 | argp->offset += resp->count; | 1445 | argp->offset += resp->count; |
| 1438 | argp->pgbase += resp->count; | 1446 | argp->pgbase += resp->count; |
| 1439 | argp->count -= resp->count; | 1447 | argp->count -= resp->count; |
| @@ -1884,7 +1892,7 @@ int nfs_migrate_page(struct address_space *mapping, struct page *newpage, | |||
| 1884 | int __init nfs_init_writepagecache(void) | 1892 | int __init nfs_init_writepagecache(void) |
| 1885 | { | 1893 | { |
| 1886 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", | 1894 | nfs_wdata_cachep = kmem_cache_create("nfs_write_data", |
| 1887 | sizeof(struct nfs_rw_header), | 1895 | sizeof(struct nfs_pgio_header), |
| 1888 | 0, SLAB_HWCACHE_ALIGN, | 1896 | 0, SLAB_HWCACHE_ALIGN, |
| 1889 | NULL); | 1897 | NULL); |
| 1890 | if (nfs_wdata_cachep == NULL) | 1898 | if (nfs_wdata_cachep == NULL) |
diff --git a/fs/nfs_common/nfsacl.c b/fs/nfs_common/nfsacl.c index ed628f71274c..538f142935ea 100644 --- a/fs/nfs_common/nfsacl.c +++ b/fs/nfs_common/nfsacl.c | |||
| @@ -30,9 +30,6 @@ | |||
| 30 | 30 | ||
| 31 | MODULE_LICENSE("GPL"); | 31 | MODULE_LICENSE("GPL"); |
| 32 | 32 | ||
| 33 | EXPORT_SYMBOL_GPL(nfsacl_encode); | ||
| 34 | EXPORT_SYMBOL_GPL(nfsacl_decode); | ||
| 35 | |||
| 36 | struct nfsacl_encode_desc { | 33 | struct nfsacl_encode_desc { |
| 37 | struct xdr_array2_desc desc; | 34 | struct xdr_array2_desc desc; |
| 38 | unsigned int count; | 35 | unsigned int count; |
| @@ -136,6 +133,7 @@ int nfsacl_encode(struct xdr_buf *buf, unsigned int base, struct inode *inode, | |||
| 136 | nfsacl_desc.desc.array_len; | 133 | nfsacl_desc.desc.array_len; |
| 137 | return err; | 134 | return err; |
| 138 | } | 135 | } |
| 136 | EXPORT_SYMBOL_GPL(nfsacl_encode); | ||
| 139 | 137 | ||
| 140 | struct nfsacl_decode_desc { | 138 | struct nfsacl_decode_desc { |
| 141 | struct xdr_array2_desc desc; | 139 | struct xdr_array2_desc desc; |
| @@ -295,3 +293,4 @@ int nfsacl_decode(struct xdr_buf *buf, unsigned int base, unsigned int *aclcnt, | |||
| 295 | return 8 + nfsacl_desc.desc.elem_size * | 293 | return 8 + nfsacl_desc.desc.elem_size * |
| 296 | nfsacl_desc.desc.array_len; | 294 | nfsacl_desc.desc.array_len; |
| 297 | } | 295 | } |
| 296 | EXPORT_SYMBOL_GPL(nfsacl_decode); | ||
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index e30f6059ecd6..5180a7ededec 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
| @@ -52,6 +52,7 @@ struct nfs_access_entry { | |||
| 52 | unsigned long jiffies; | 52 | unsigned long jiffies; |
| 53 | struct rpc_cred * cred; | 53 | struct rpc_cred * cred; |
| 54 | int mask; | 54 | int mask; |
| 55 | struct rcu_head rcu_head; | ||
| 55 | }; | 56 | }; |
| 56 | 57 | ||
| 57 | struct nfs_lockowner { | 58 | struct nfs_lockowner { |
| @@ -352,6 +353,7 @@ extern int nfs_release(struct inode *, struct file *); | |||
| 352 | extern int nfs_attribute_timeout(struct inode *inode); | 353 | extern int nfs_attribute_timeout(struct inode *inode); |
| 353 | extern int nfs_attribute_cache_expired(struct inode *inode); | 354 | extern int nfs_attribute_cache_expired(struct inode *inode); |
| 354 | extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode); | 355 | extern int nfs_revalidate_inode(struct nfs_server *server, struct inode *inode); |
| 356 | extern int nfs_revalidate_inode_rcu(struct nfs_server *server, struct inode *inode); | ||
| 355 | extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); | 357 | extern int __nfs_revalidate_inode(struct nfs_server *, struct inode *); |
| 356 | extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); | 358 | extern int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping); |
| 357 | extern int nfs_setattr(struct dentry *, struct iattr *); | 359 | extern int nfs_setattr(struct dentry *, struct iattr *); |
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index 1150ea41b626..922be2e050f5 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h | |||
| @@ -45,6 +45,7 @@ struct nfs_client { | |||
| 45 | struct sockaddr_storage cl_addr; /* server identifier */ | 45 | struct sockaddr_storage cl_addr; /* server identifier */ |
| 46 | size_t cl_addrlen; | 46 | size_t cl_addrlen; |
| 47 | char * cl_hostname; /* hostname of server */ | 47 | char * cl_hostname; /* hostname of server */ |
| 48 | char * cl_acceptor; /* GSSAPI acceptor name */ | ||
| 48 | struct list_head cl_share_link; /* link in global client list */ | 49 | struct list_head cl_share_link; /* link in global client list */ |
| 49 | struct list_head cl_superblocks; /* List of nfs_server structs */ | 50 | struct list_head cl_superblocks; /* List of nfs_server structs */ |
| 50 | 51 | ||
diff --git a/include/linux/nfs_page.h b/include/linux/nfs_page.h index 7d9096d95d4a..6ad2bbcad405 100644 --- a/include/linux/nfs_page.h +++ b/include/linux/nfs_page.h | |||
| @@ -26,7 +26,7 @@ enum { | |||
| 26 | PG_MAPPED, /* page private set for buffered io */ | 26 | PG_MAPPED, /* page private set for buffered io */ |
| 27 | PG_CLEAN, /* write succeeded */ | 27 | PG_CLEAN, /* write succeeded */ |
| 28 | PG_COMMIT_TO_DS, /* used by pnfs layouts */ | 28 | PG_COMMIT_TO_DS, /* used by pnfs layouts */ |
| 29 | PG_INODE_REF, /* extra ref held by inode (head req only) */ | 29 | PG_INODE_REF, /* extra ref held by inode when in writeback */ |
| 30 | PG_HEADLOCK, /* page group lock of wb_head */ | 30 | PG_HEADLOCK, /* page group lock of wb_head */ |
| 31 | PG_TEARDOWN, /* page group sync for destroy */ | 31 | PG_TEARDOWN, /* page group sync for destroy */ |
| 32 | PG_UNLOCKPAGE, /* page group sync bit in read path */ | 32 | PG_UNLOCKPAGE, /* page group sync bit in read path */ |
| @@ -62,12 +62,13 @@ struct nfs_pageio_ops { | |||
| 62 | 62 | ||
| 63 | struct nfs_rw_ops { | 63 | struct nfs_rw_ops { |
| 64 | const fmode_t rw_mode; | 64 | const fmode_t rw_mode; |
| 65 | struct nfs_rw_header *(*rw_alloc_header)(void); | 65 | struct nfs_pgio_header *(*rw_alloc_header)(void); |
| 66 | void (*rw_free_header)(struct nfs_rw_header *); | 66 | void (*rw_free_header)(struct nfs_pgio_header *); |
| 67 | void (*rw_release)(struct nfs_pgio_data *); | 67 | void (*rw_release)(struct nfs_pgio_header *); |
| 68 | int (*rw_done)(struct rpc_task *, struct nfs_pgio_data *, struct inode *); | 68 | int (*rw_done)(struct rpc_task *, struct nfs_pgio_header *, |
| 69 | void (*rw_result)(struct rpc_task *, struct nfs_pgio_data *); | 69 | struct inode *); |
| 70 | void (*rw_initiate)(struct nfs_pgio_data *, struct rpc_message *, | 70 | void (*rw_result)(struct rpc_task *, struct nfs_pgio_header *); |
| 71 | void (*rw_initiate)(struct nfs_pgio_header *, struct rpc_message *, | ||
| 71 | struct rpc_task_setup *, int); | 72 | struct rpc_task_setup *, int); |
| 72 | }; | 73 | }; |
| 73 | 74 | ||
| @@ -111,6 +112,8 @@ extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc, | |||
| 111 | int how); | 112 | int how); |
| 112 | extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *, | 113 | extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *, |
| 113 | struct nfs_page *); | 114 | struct nfs_page *); |
| 115 | extern int nfs_pageio_resend(struct nfs_pageio_descriptor *, | ||
| 116 | struct nfs_pgio_header *); | ||
| 114 | extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc); | 117 | extern void nfs_pageio_complete(struct nfs_pageio_descriptor *desc); |
| 115 | extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t); | 118 | extern void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *, pgoff_t); |
| 116 | extern size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, | 119 | extern size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, |
| @@ -119,7 +122,7 @@ extern size_t nfs_generic_pg_test(struct nfs_pageio_descriptor *desc, | |||
| 119 | extern int nfs_wait_on_request(struct nfs_page *); | 122 | extern int nfs_wait_on_request(struct nfs_page *); |
| 120 | extern void nfs_unlock_request(struct nfs_page *req); | 123 | extern void nfs_unlock_request(struct nfs_page *req); |
| 121 | extern void nfs_unlock_and_release_request(struct nfs_page *); | 124 | extern void nfs_unlock_and_release_request(struct nfs_page *); |
| 122 | extern void nfs_page_group_lock(struct nfs_page *); | 125 | extern int nfs_page_group_lock(struct nfs_page *, bool); |
| 123 | extern void nfs_page_group_unlock(struct nfs_page *); | 126 | extern void nfs_page_group_unlock(struct nfs_page *); |
| 124 | extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int); | 127 | extern bool nfs_page_group_sync_on_bit(struct nfs_page *, unsigned int); |
| 125 | 128 | ||
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h index 9a1396e70310..0040629894df 100644 --- a/include/linux/nfs_xdr.h +++ b/include/linux/nfs_xdr.h | |||
| @@ -993,6 +993,7 @@ struct nfs4_setclientid { | |||
| 993 | unsigned int sc_uaddr_len; | 993 | unsigned int sc_uaddr_len; |
| 994 | char sc_uaddr[RPCBIND_MAXUADDRLEN + 1]; | 994 | char sc_uaddr[RPCBIND_MAXUADDRLEN + 1]; |
| 995 | u32 sc_cb_ident; | 995 | u32 sc_cb_ident; |
| 996 | struct rpc_cred *sc_cred; | ||
| 996 | }; | 997 | }; |
| 997 | 998 | ||
| 998 | struct nfs4_setclientid_res { | 999 | struct nfs4_setclientid_res { |
| @@ -1253,18 +1254,12 @@ enum { | |||
| 1253 | NFS_IOHDR_ERROR = 0, | 1254 | NFS_IOHDR_ERROR = 0, |
| 1254 | NFS_IOHDR_EOF, | 1255 | NFS_IOHDR_EOF, |
| 1255 | NFS_IOHDR_REDO, | 1256 | NFS_IOHDR_REDO, |
| 1256 | NFS_IOHDR_NEED_COMMIT, | ||
| 1257 | NFS_IOHDR_NEED_RESCHED, | ||
| 1258 | }; | 1257 | }; |
| 1259 | 1258 | ||
| 1260 | struct nfs_pgio_data; | ||
| 1261 | |||
| 1262 | struct nfs_pgio_header { | 1259 | struct nfs_pgio_header { |
| 1263 | struct inode *inode; | 1260 | struct inode *inode; |
| 1264 | struct rpc_cred *cred; | 1261 | struct rpc_cred *cred; |
| 1265 | struct list_head pages; | 1262 | struct list_head pages; |
| 1266 | struct nfs_pgio_data *data; | ||
| 1267 | atomic_t refcnt; | ||
| 1268 | struct nfs_page *req; | 1263 | struct nfs_page *req; |
| 1269 | struct nfs_writeverf verf; /* Used for writes */ | 1264 | struct nfs_writeverf verf; /* Used for writes */ |
| 1270 | struct pnfs_layout_segment *lseg; | 1265 | struct pnfs_layout_segment *lseg; |
| @@ -1281,28 +1276,22 @@ struct nfs_pgio_header { | |||
| 1281 | int error; /* merge with pnfs_error */ | 1276 | int error; /* merge with pnfs_error */ |
| 1282 | unsigned long good_bytes; /* boundary of good data */ | 1277 | unsigned long good_bytes; /* boundary of good data */ |
| 1283 | unsigned long flags; | 1278 | unsigned long flags; |
| 1284 | }; | ||
| 1285 | 1279 | ||
| 1286 | struct nfs_pgio_data { | 1280 | /* |
| 1287 | struct nfs_pgio_header *header; | 1281 | * rpc data |
| 1282 | */ | ||
| 1288 | struct rpc_task task; | 1283 | struct rpc_task task; |
| 1289 | struct nfs_fattr fattr; | 1284 | struct nfs_fattr fattr; |
| 1290 | struct nfs_writeverf verf; /* Used for writes */ | ||
| 1291 | struct nfs_pgio_args args; /* argument struct */ | 1285 | struct nfs_pgio_args args; /* argument struct */ |
| 1292 | struct nfs_pgio_res res; /* result struct */ | 1286 | struct nfs_pgio_res res; /* result struct */ |
| 1293 | unsigned long timestamp; /* For lease renewal */ | 1287 | unsigned long timestamp; /* For lease renewal */ |
| 1294 | int (*pgio_done_cb) (struct rpc_task *task, struct nfs_pgio_data *data); | 1288 | int (*pgio_done_cb)(struct rpc_task *, struct nfs_pgio_header *); |
| 1295 | __u64 mds_offset; /* Filelayout dense stripe */ | 1289 | __u64 mds_offset; /* Filelayout dense stripe */ |
| 1296 | struct nfs_page_array pages; | 1290 | struct nfs_page_array page_array; |
| 1297 | struct nfs_client *ds_clp; /* pNFS data server */ | 1291 | struct nfs_client *ds_clp; /* pNFS data server */ |
| 1298 | int ds_idx; /* ds index if ds_clp is set */ | 1292 | int ds_idx; /* ds index if ds_clp is set */ |
| 1299 | }; | 1293 | }; |
| 1300 | 1294 | ||
| 1301 | struct nfs_rw_header { | ||
| 1302 | struct nfs_pgio_header header; | ||
| 1303 | struct nfs_pgio_data rpc_data; | ||
| 1304 | }; | ||
| 1305 | |||
| 1306 | struct nfs_mds_commit_info { | 1295 | struct nfs_mds_commit_info { |
| 1307 | atomic_t rpcs_out; | 1296 | atomic_t rpcs_out; |
| 1308 | unsigned long ncommit; | 1297 | unsigned long ncommit; |
| @@ -1432,11 +1421,12 @@ struct nfs_rpc_ops { | |||
| 1432 | struct nfs_pathconf *); | 1421 | struct nfs_pathconf *); |
| 1433 | int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); | 1422 | int (*set_capabilities)(struct nfs_server *, struct nfs_fh *); |
| 1434 | int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int); | 1423 | int (*decode_dirent)(struct xdr_stream *, struct nfs_entry *, int); |
| 1435 | int (*pgio_rpc_prepare)(struct rpc_task *, struct nfs_pgio_data *); | 1424 | int (*pgio_rpc_prepare)(struct rpc_task *, |
| 1436 | void (*read_setup) (struct nfs_pgio_data *, struct rpc_message *); | 1425 | struct nfs_pgio_header *); |
| 1437 | int (*read_done) (struct rpc_task *, struct nfs_pgio_data *); | 1426 | void (*read_setup)(struct nfs_pgio_header *, struct rpc_message *); |
| 1438 | void (*write_setup) (struct nfs_pgio_data *, struct rpc_message *); | 1427 | int (*read_done)(struct rpc_task *, struct nfs_pgio_header *); |
| 1439 | int (*write_done) (struct rpc_task *, struct nfs_pgio_data *); | 1428 | void (*write_setup)(struct nfs_pgio_header *, struct rpc_message *); |
| 1429 | int (*write_done)(struct rpc_task *, struct nfs_pgio_header *); | ||
| 1440 | void (*commit_setup) (struct nfs_commit_data *, struct rpc_message *); | 1430 | void (*commit_setup) (struct nfs_commit_data *, struct rpc_message *); |
| 1441 | void (*commit_rpc_prepare)(struct rpc_task *, struct nfs_commit_data *); | 1431 | void (*commit_rpc_prepare)(struct rpc_task *, struct nfs_commit_data *); |
| 1442 | int (*commit_done) (struct rpc_task *, struct nfs_commit_data *); | 1432 | int (*commit_done) (struct rpc_task *, struct nfs_commit_data *); |
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h index 790be1472792..8e030075fe79 100644 --- a/include/linux/sunrpc/auth.h +++ b/include/linux/sunrpc/auth.h | |||
| @@ -103,6 +103,7 @@ struct rpc_auth_create_args { | |||
| 103 | 103 | ||
| 104 | /* Flags for rpcauth_lookupcred() */ | 104 | /* Flags for rpcauth_lookupcred() */ |
| 105 | #define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ | 105 | #define RPCAUTH_LOOKUP_NEW 0x01 /* Accept an uninitialised cred */ |
| 106 | #define RPCAUTH_LOOKUP_RCU 0x02 /* lock-less lookup */ | ||
| 106 | 107 | ||
| 107 | /* | 108 | /* |
| 108 | * Client authentication ops | 109 | * Client authentication ops |
| @@ -140,6 +141,7 @@ struct rpc_credops { | |||
| 140 | void *, __be32 *, void *); | 141 | void *, __be32 *, void *); |
| 141 | int (*crkey_timeout)(struct rpc_cred *); | 142 | int (*crkey_timeout)(struct rpc_cred *); |
| 142 | bool (*crkey_to_expire)(struct rpc_cred *); | 143 | bool (*crkey_to_expire)(struct rpc_cred *); |
| 144 | char * (*crstringify_acceptor)(struct rpc_cred *); | ||
| 143 | }; | 145 | }; |
| 144 | 146 | ||
| 145 | extern const struct rpc_authops authunix_ops; | 147 | extern const struct rpc_authops authunix_ops; |
| @@ -153,6 +155,7 @@ void rpc_destroy_generic_auth(void); | |||
| 153 | void rpc_destroy_authunix(void); | 155 | void rpc_destroy_authunix(void); |
| 154 | 156 | ||
| 155 | struct rpc_cred * rpc_lookup_cred(void); | 157 | struct rpc_cred * rpc_lookup_cred(void); |
| 158 | struct rpc_cred * rpc_lookup_cred_nonblock(void); | ||
| 156 | struct rpc_cred * rpc_lookup_machine_cred(const char *service_name); | 159 | struct rpc_cred * rpc_lookup_machine_cred(const char *service_name); |
| 157 | int rpcauth_register(const struct rpc_authops *); | 160 | int rpcauth_register(const struct rpc_authops *); |
| 158 | int rpcauth_unregister(const struct rpc_authops *); | 161 | int rpcauth_unregister(const struct rpc_authops *); |
| @@ -182,6 +185,7 @@ void rpcauth_clear_credcache(struct rpc_cred_cache *); | |||
| 182 | int rpcauth_key_timeout_notify(struct rpc_auth *, | 185 | int rpcauth_key_timeout_notify(struct rpc_auth *, |
| 183 | struct rpc_cred *); | 186 | struct rpc_cred *); |
| 184 | bool rpcauth_cred_key_to_expire(struct rpc_cred *); | 187 | bool rpcauth_cred_key_to_expire(struct rpc_cred *); |
| 188 | char * rpcauth_stringify_acceptor(struct rpc_cred *); | ||
| 185 | 189 | ||
| 186 | static inline | 190 | static inline |
| 187 | struct rpc_cred * get_rpccred(struct rpc_cred *cred) | 191 | struct rpc_cred * get_rpccred(struct rpc_cred *cred) |
diff --git a/include/linux/sunrpc/auth_gss.h b/include/linux/sunrpc/auth_gss.h index f1cfd4c85cd0..36eebc451b41 100644 --- a/include/linux/sunrpc/auth_gss.h +++ b/include/linux/sunrpc/auth_gss.h | |||
| @@ -69,8 +69,9 @@ struct gss_cl_ctx { | |||
| 69 | enum rpc_gss_proc gc_proc; | 69 | enum rpc_gss_proc gc_proc; |
| 70 | u32 gc_seq; | 70 | u32 gc_seq; |
| 71 | spinlock_t gc_seq_lock; | 71 | spinlock_t gc_seq_lock; |
| 72 | struct gss_ctx __rcu *gc_gss_ctx; | 72 | struct gss_ctx *gc_gss_ctx; |
| 73 | struct xdr_netobj gc_wire_ctx; | 73 | struct xdr_netobj gc_wire_ctx; |
| 74 | struct xdr_netobj gc_acceptor; | ||
| 74 | u32 gc_win; | 75 | u32 gc_win; |
| 75 | unsigned long gc_expiry; | 76 | unsigned long gc_expiry; |
| 76 | struct rcu_head gc_rcu; | 77 | struct rcu_head gc_rcu; |
diff --git a/include/linux/sunrpc/gss_krb5.h b/include/linux/sunrpc/gss_krb5.h index 5af2931cf58d..df02a4188487 100644 --- a/include/linux/sunrpc/gss_krb5.h +++ b/include/linux/sunrpc/gss_krb5.h | |||
| @@ -81,7 +81,7 @@ struct gss_krb5_enctype { | |||
| 81 | struct xdr_netobj *in, | 81 | struct xdr_netobj *in, |
| 82 | struct xdr_netobj *out); /* complete key generation */ | 82 | struct xdr_netobj *out); /* complete key generation */ |
| 83 | u32 (*encrypt_v2) (struct krb5_ctx *kctx, u32 offset, | 83 | u32 (*encrypt_v2) (struct krb5_ctx *kctx, u32 offset, |
| 84 | struct xdr_buf *buf, int ec, | 84 | struct xdr_buf *buf, |
| 85 | struct page **pages); /* v2 encryption function */ | 85 | struct page **pages); /* v2 encryption function */ |
| 86 | u32 (*decrypt_v2) (struct krb5_ctx *kctx, u32 offset, | 86 | u32 (*decrypt_v2) (struct krb5_ctx *kctx, u32 offset, |
| 87 | struct xdr_buf *buf, u32 *headskip, | 87 | struct xdr_buf *buf, u32 *headskip, |
| @@ -310,7 +310,7 @@ gss_krb5_aes_make_key(const struct gss_krb5_enctype *gk5e, | |||
| 310 | 310 | ||
| 311 | u32 | 311 | u32 |
| 312 | gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, | 312 | gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, |
| 313 | struct xdr_buf *buf, int ec, | 313 | struct xdr_buf *buf, |
| 314 | struct page **pages); | 314 | struct page **pages); |
| 315 | 315 | ||
| 316 | u32 | 316 | u32 |
diff --git a/include/linux/sunrpc/xprtrdma.h b/include/linux/sunrpc/xprtrdma.h index c2f04e1ae159..64a0a0a97b23 100644 --- a/include/linux/sunrpc/xprtrdma.h +++ b/include/linux/sunrpc/xprtrdma.h | |||
| @@ -62,8 +62,6 @@ | |||
| 62 | #define RPCRDMA_INLINE_PAD_THRESH (512)/* payload threshold to pad (bytes) */ | 62 | #define RPCRDMA_INLINE_PAD_THRESH (512)/* payload threshold to pad (bytes) */ |
| 63 | 63 | ||
| 64 | /* memory registration strategies */ | 64 | /* memory registration strategies */ |
| 65 | #define RPCRDMA_PERSISTENT_REGISTRATION (1) | ||
| 66 | |||
| 67 | enum rpcrdma_memreg { | 65 | enum rpcrdma_memreg { |
| 68 | RPCRDMA_BOUNCEBUFFERS = 0, | 66 | RPCRDMA_BOUNCEBUFFERS = 0, |
| 69 | RPCRDMA_REGISTER, | 67 | RPCRDMA_REGISTER, |
diff --git a/net/sunrpc/addr.c b/net/sunrpc/addr.c index a622ad64acd8..2e0a6f92e563 100644 --- a/net/sunrpc/addr.c +++ b/net/sunrpc/addr.c | |||
| @@ -176,7 +176,7 @@ static int rpc_parse_scope_id(struct net *net, const char *buf, | |||
| 176 | len = (buf + buflen) - delim - 1; | 176 | len = (buf + buflen) - delim - 1; |
| 177 | p = kstrndup(delim + 1, len, GFP_KERNEL); | 177 | p = kstrndup(delim + 1, len, GFP_KERNEL); |
| 178 | if (p) { | 178 | if (p) { |
| 179 | unsigned long scope_id = 0; | 179 | u32 scope_id = 0; |
| 180 | struct net_device *dev; | 180 | struct net_device *dev; |
| 181 | 181 | ||
| 182 | dev = dev_get_by_name(net, p); | 182 | dev = dev_get_by_name(net, p); |
| @@ -184,7 +184,7 @@ static int rpc_parse_scope_id(struct net *net, const char *buf, | |||
| 184 | scope_id = dev->ifindex; | 184 | scope_id = dev->ifindex; |
| 185 | dev_put(dev); | 185 | dev_put(dev); |
| 186 | } else { | 186 | } else { |
| 187 | if (strict_strtoul(p, 10, &scope_id) == 0) { | 187 | if (kstrtou32(p, 10, &scope_id) == 0) { |
| 188 | kfree(p); | 188 | kfree(p); |
| 189 | return 0; | 189 | return 0; |
| 190 | } | 190 | } |
| @@ -304,7 +304,7 @@ char *rpc_sockaddr2uaddr(const struct sockaddr *sap, gfp_t gfp_flags) | |||
| 304 | * @sap: buffer into which to plant socket address | 304 | * @sap: buffer into which to plant socket address |
| 305 | * @salen: size of buffer | 305 | * @salen: size of buffer |
| 306 | * | 306 | * |
| 307 | * @uaddr does not have to be '\0'-terminated, but strict_strtoul() and | 307 | * @uaddr does not have to be '\0'-terminated, but kstrtou8() and |
| 308 | * rpc_pton() require proper string termination to be successful. | 308 | * rpc_pton() require proper string termination to be successful. |
| 309 | * | 309 | * |
| 310 | * Returns the size of the socket address if successful; otherwise | 310 | * Returns the size of the socket address if successful; otherwise |
| @@ -315,7 +315,7 @@ size_t rpc_uaddr2sockaddr(struct net *net, const char *uaddr, | |||
| 315 | const size_t salen) | 315 | const size_t salen) |
| 316 | { | 316 | { |
| 317 | char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')]; | 317 | char *c, buf[RPCBIND_MAXUADDRLEN + sizeof('\0')]; |
| 318 | unsigned long portlo, porthi; | 318 | u8 portlo, porthi; |
| 319 | unsigned short port; | 319 | unsigned short port; |
| 320 | 320 | ||
| 321 | if (uaddr_len > RPCBIND_MAXUADDRLEN) | 321 | if (uaddr_len > RPCBIND_MAXUADDRLEN) |
| @@ -327,18 +327,14 @@ size_t rpc_uaddr2sockaddr(struct net *net, const char *uaddr, | |||
| 327 | c = strrchr(buf, '.'); | 327 | c = strrchr(buf, '.'); |
| 328 | if (unlikely(c == NULL)) | 328 | if (unlikely(c == NULL)) |
| 329 | return 0; | 329 | return 0; |
| 330 | if (unlikely(strict_strtoul(c + 1, 10, &portlo) != 0)) | 330 | if (unlikely(kstrtou8(c + 1, 10, &portlo) != 0)) |
| 331 | return 0; | ||
| 332 | if (unlikely(portlo > 255)) | ||
| 333 | return 0; | 331 | return 0; |
| 334 | 332 | ||
| 335 | *c = '\0'; | 333 | *c = '\0'; |
| 336 | c = strrchr(buf, '.'); | 334 | c = strrchr(buf, '.'); |
| 337 | if (unlikely(c == NULL)) | 335 | if (unlikely(c == NULL)) |
| 338 | return 0; | 336 | return 0; |
| 339 | if (unlikely(strict_strtoul(c + 1, 10, &porthi) != 0)) | 337 | if (unlikely(kstrtou8(c + 1, 10, &porthi) != 0)) |
| 340 | return 0; | ||
| 341 | if (unlikely(porthi > 255)) | ||
| 342 | return 0; | 338 | return 0; |
| 343 | 339 | ||
| 344 | port = (unsigned short)((porthi << 8) | portlo); | 340 | port = (unsigned short)((porthi << 8) | portlo); |
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c index f77366717420..383eb919ac0b 100644 --- a/net/sunrpc/auth.c +++ b/net/sunrpc/auth.c | |||
| @@ -48,7 +48,7 @@ static int param_set_hashtbl_sz(const char *val, const struct kernel_param *kp) | |||
| 48 | 48 | ||
| 49 | if (!val) | 49 | if (!val) |
| 50 | goto out_inval; | 50 | goto out_inval; |
| 51 | ret = strict_strtoul(val, 0, &num); | 51 | ret = kstrtoul(val, 0, &num); |
| 52 | if (ret == -EINVAL) | 52 | if (ret == -EINVAL) |
| 53 | goto out_inval; | 53 | goto out_inval; |
| 54 | nbits = fls(num); | 54 | nbits = fls(num); |
| @@ -80,6 +80,10 @@ static struct kernel_param_ops param_ops_hashtbl_sz = { | |||
| 80 | module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644); | 80 | module_param_named(auth_hashtable_size, auth_hashbits, hashtbl_sz, 0644); |
| 81 | MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); | 81 | MODULE_PARM_DESC(auth_hashtable_size, "RPC credential cache hashtable size"); |
| 82 | 82 | ||
| 83 | static unsigned long auth_max_cred_cachesize = ULONG_MAX; | ||
| 84 | module_param(auth_max_cred_cachesize, ulong, 0644); | ||
| 85 | MODULE_PARM_DESC(auth_max_cred_cachesize, "RPC credential maximum total cache size"); | ||
| 86 | |||
| 83 | static u32 | 87 | static u32 |
| 84 | pseudoflavor_to_flavor(u32 flavor) { | 88 | pseudoflavor_to_flavor(u32 flavor) { |
| 85 | if (flavor > RPC_AUTH_MAXFLAVOR) | 89 | if (flavor > RPC_AUTH_MAXFLAVOR) |
| @@ -363,6 +367,15 @@ rpcauth_cred_key_to_expire(struct rpc_cred *cred) | |||
| 363 | } | 367 | } |
| 364 | EXPORT_SYMBOL_GPL(rpcauth_cred_key_to_expire); | 368 | EXPORT_SYMBOL_GPL(rpcauth_cred_key_to_expire); |
| 365 | 369 | ||
| 370 | char * | ||
| 371 | rpcauth_stringify_acceptor(struct rpc_cred *cred) | ||
| 372 | { | ||
| 373 | if (!cred->cr_ops->crstringify_acceptor) | ||
| 374 | return NULL; | ||
| 375 | return cred->cr_ops->crstringify_acceptor(cred); | ||
| 376 | } | ||
| 377 | EXPORT_SYMBOL_GPL(rpcauth_stringify_acceptor); | ||
| 378 | |||
| 366 | /* | 379 | /* |
| 367 | * Destroy a list of credentials | 380 | * Destroy a list of credentials |
| 368 | */ | 381 | */ |
| @@ -472,6 +485,20 @@ rpcauth_prune_expired(struct list_head *free, int nr_to_scan) | |||
| 472 | return freed; | 485 | return freed; |
| 473 | } | 486 | } |
| 474 | 487 | ||
| 488 | static unsigned long | ||
| 489 | rpcauth_cache_do_shrink(int nr_to_scan) | ||
| 490 | { | ||
| 491 | LIST_HEAD(free); | ||
| 492 | unsigned long freed; | ||
| 493 | |||
| 494 | spin_lock(&rpc_credcache_lock); | ||
| 495 | freed = rpcauth_prune_expired(&free, nr_to_scan); | ||
| 496 | spin_unlock(&rpc_credcache_lock); | ||
| 497 | rpcauth_destroy_credlist(&free); | ||
| 498 | |||
| 499 | return freed; | ||
| 500 | } | ||
| 501 | |||
| 475 | /* | 502 | /* |
| 476 | * Run memory cache shrinker. | 503 | * Run memory cache shrinker. |
| 477 | */ | 504 | */ |
| @@ -479,9 +506,6 @@ static unsigned long | |||
| 479 | rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) | 506 | rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) |
| 480 | 507 | ||
| 481 | { | 508 | { |
| 482 | LIST_HEAD(free); | ||
| 483 | unsigned long freed; | ||
| 484 | |||
| 485 | if ((sc->gfp_mask & GFP_KERNEL) != GFP_KERNEL) | 509 | if ((sc->gfp_mask & GFP_KERNEL) != GFP_KERNEL) |
| 486 | return SHRINK_STOP; | 510 | return SHRINK_STOP; |
| 487 | 511 | ||
| @@ -489,12 +513,7 @@ rpcauth_cache_shrink_scan(struct shrinker *shrink, struct shrink_control *sc) | |||
| 489 | if (list_empty(&cred_unused)) | 513 | if (list_empty(&cred_unused)) |
| 490 | return SHRINK_STOP; | 514 | return SHRINK_STOP; |
| 491 | 515 | ||
| 492 | spin_lock(&rpc_credcache_lock); | 516 | return rpcauth_cache_do_shrink(sc->nr_to_scan); |
| 493 | freed = rpcauth_prune_expired(&free, sc->nr_to_scan); | ||
| 494 | spin_unlock(&rpc_credcache_lock); | ||
| 495 | rpcauth_destroy_credlist(&free); | ||
| 496 | |||
| 497 | return freed; | ||
| 498 | } | 517 | } |
| 499 | 518 | ||
| 500 | static unsigned long | 519 | static unsigned long |
| @@ -504,6 +523,21 @@ rpcauth_cache_shrink_count(struct shrinker *shrink, struct shrink_control *sc) | |||
| 504 | return (number_cred_unused / 100) * sysctl_vfs_cache_pressure; | 523 | return (number_cred_unused / 100) * sysctl_vfs_cache_pressure; |
| 505 | } | 524 | } |
| 506 | 525 | ||
| 526 | static void | ||
| 527 | rpcauth_cache_enforce_limit(void) | ||
| 528 | { | ||
| 529 | unsigned long diff; | ||
| 530 | unsigned int nr_to_scan; | ||
| 531 | |||
| 532 | if (number_cred_unused <= auth_max_cred_cachesize) | ||
| 533 | return; | ||
| 534 | diff = number_cred_unused - auth_max_cred_cachesize; | ||
| 535 | nr_to_scan = 100; | ||
| 536 | if (diff < nr_to_scan) | ||
| 537 | nr_to_scan = diff; | ||
| 538 | rpcauth_cache_do_shrink(nr_to_scan); | ||
| 539 | } | ||
| 540 | |||
| 507 | /* | 541 | /* |
| 508 | * Look up a process' credentials in the authentication cache | 542 | * Look up a process' credentials in the authentication cache |
| 509 | */ | 543 | */ |
| @@ -523,6 +557,12 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
| 523 | hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) { | 557 | hlist_for_each_entry_rcu(entry, &cache->hashtable[nr], cr_hash) { |
| 524 | if (!entry->cr_ops->crmatch(acred, entry, flags)) | 558 | if (!entry->cr_ops->crmatch(acred, entry, flags)) |
| 525 | continue; | 559 | continue; |
| 560 | if (flags & RPCAUTH_LOOKUP_RCU) { | ||
| 561 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) && | ||
| 562 | !test_bit(RPCAUTH_CRED_NEW, &entry->cr_flags)) | ||
| 563 | cred = entry; | ||
| 564 | break; | ||
| 565 | } | ||
| 526 | spin_lock(&cache->lock); | 566 | spin_lock(&cache->lock); |
| 527 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { | 567 | if (test_bit(RPCAUTH_CRED_HASHED, &entry->cr_flags) == 0) { |
| 528 | spin_unlock(&cache->lock); | 568 | spin_unlock(&cache->lock); |
| @@ -537,6 +577,9 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
| 537 | if (cred != NULL) | 577 | if (cred != NULL) |
| 538 | goto found; | 578 | goto found; |
| 539 | 579 | ||
| 580 | if (flags & RPCAUTH_LOOKUP_RCU) | ||
| 581 | return ERR_PTR(-ECHILD); | ||
| 582 | |||
| 540 | new = auth->au_ops->crcreate(auth, acred, flags); | 583 | new = auth->au_ops->crcreate(auth, acred, flags); |
| 541 | if (IS_ERR(new)) { | 584 | if (IS_ERR(new)) { |
| 542 | cred = new; | 585 | cred = new; |
| @@ -557,6 +600,7 @@ rpcauth_lookup_credcache(struct rpc_auth *auth, struct auth_cred * acred, | |||
| 557 | } else | 600 | } else |
| 558 | list_add_tail(&new->cr_lru, &free); | 601 | list_add_tail(&new->cr_lru, &free); |
| 559 | spin_unlock(&cache->lock); | 602 | spin_unlock(&cache->lock); |
| 603 | rpcauth_cache_enforce_limit(); | ||
| 560 | found: | 604 | found: |
| 561 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && | 605 | if (test_bit(RPCAUTH_CRED_NEW, &cred->cr_flags) && |
| 562 | cred->cr_ops->cr_init != NULL && | 606 | cred->cr_ops->cr_init != NULL && |
| @@ -586,10 +630,8 @@ rpcauth_lookupcred(struct rpc_auth *auth, int flags) | |||
| 586 | memset(&acred, 0, sizeof(acred)); | 630 | memset(&acred, 0, sizeof(acred)); |
| 587 | acred.uid = cred->fsuid; | 631 | acred.uid = cred->fsuid; |
| 588 | acred.gid = cred->fsgid; | 632 | acred.gid = cred->fsgid; |
| 589 | acred.group_info = get_group_info(((struct cred *)cred)->group_info); | 633 | acred.group_info = cred->group_info; |
| 590 | |||
| 591 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); | 634 | ret = auth->au_ops->lookup_cred(auth, &acred, flags); |
| 592 | put_group_info(acred.group_info); | ||
| 593 | return ret; | 635 | return ret; |
| 594 | } | 636 | } |
| 595 | EXPORT_SYMBOL_GPL(rpcauth_lookupcred); | 637 | EXPORT_SYMBOL_GPL(rpcauth_lookupcred); |
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c index ed04869b2d4f..6f6b829c9e8e 100644 --- a/net/sunrpc/auth_generic.c +++ b/net/sunrpc/auth_generic.c | |||
| @@ -38,6 +38,12 @@ struct rpc_cred *rpc_lookup_cred(void) | |||
| 38 | } | 38 | } |
| 39 | EXPORT_SYMBOL_GPL(rpc_lookup_cred); | 39 | EXPORT_SYMBOL_GPL(rpc_lookup_cred); |
| 40 | 40 | ||
| 41 | struct rpc_cred *rpc_lookup_cred_nonblock(void) | ||
| 42 | { | ||
| 43 | return rpcauth_lookupcred(&generic_auth, RPCAUTH_LOOKUP_RCU); | ||
| 44 | } | ||
| 45 | EXPORT_SYMBOL_GPL(rpc_lookup_cred_nonblock); | ||
| 46 | |||
| 41 | /* | 47 | /* |
| 42 | * Public call interface for looking up machine creds. | 48 | * Public call interface for looking up machine creds. |
| 43 | */ | 49 | */ |
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c index b6e440baccc3..afb292cd797d 100644 --- a/net/sunrpc/auth_gss/auth_gss.c +++ b/net/sunrpc/auth_gss/auth_gss.c | |||
| @@ -183,8 +183,9 @@ gss_cred_get_ctx(struct rpc_cred *cred) | |||
| 183 | struct gss_cl_ctx *ctx = NULL; | 183 | struct gss_cl_ctx *ctx = NULL; |
| 184 | 184 | ||
| 185 | rcu_read_lock(); | 185 | rcu_read_lock(); |
| 186 | if (gss_cred->gc_ctx) | 186 | ctx = rcu_dereference(gss_cred->gc_ctx); |
| 187 | ctx = gss_get_ctx(gss_cred->gc_ctx); | 187 | if (ctx) |
| 188 | gss_get_ctx(ctx); | ||
| 188 | rcu_read_unlock(); | 189 | rcu_read_unlock(); |
| 189 | return ctx; | 190 | return ctx; |
| 190 | } | 191 | } |
| @@ -262,9 +263,22 @@ gss_fill_context(const void *p, const void *end, struct gss_cl_ctx *ctx, struct | |||
| 262 | p = ERR_PTR(ret); | 263 | p = ERR_PTR(ret); |
| 263 | goto err; | 264 | goto err; |
| 264 | } | 265 | } |
| 265 | dprintk("RPC: %s Success. gc_expiry %lu now %lu timeout %u\n", | 266 | |
| 266 | __func__, ctx->gc_expiry, now, timeout); | 267 | /* is there any trailing data? */ |
| 267 | return q; | 268 | if (q == end) { |
| 269 | p = q; | ||
| 270 | goto done; | ||
| 271 | } | ||
| 272 | |||
| 273 | /* pull in acceptor name (if there is one) */ | ||
| 274 | p = simple_get_netobj(q, end, &ctx->gc_acceptor); | ||
| 275 | if (IS_ERR(p)) | ||
| 276 | goto err; | ||
| 277 | done: | ||
| 278 | dprintk("RPC: %s Success. gc_expiry %lu now %lu timeout %u acceptor %.*s\n", | ||
| 279 | __func__, ctx->gc_expiry, now, timeout, ctx->gc_acceptor.len, | ||
| 280 | ctx->gc_acceptor.data); | ||
| 281 | return p; | ||
| 268 | err: | 282 | err: |
| 269 | dprintk("RPC: %s returns error %ld\n", __func__, -PTR_ERR(p)); | 283 | dprintk("RPC: %s returns error %ld\n", __func__, -PTR_ERR(p)); |
| 270 | return p; | 284 | return p; |
| @@ -1194,13 +1208,13 @@ gss_destroying_context(struct rpc_cred *cred) | |||
| 1194 | { | 1208 | { |
| 1195 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 1209 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
| 1196 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | 1210 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); |
| 1211 | struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1); | ||
| 1197 | struct rpc_task *task; | 1212 | struct rpc_task *task; |
| 1198 | 1213 | ||
| 1199 | if (gss_cred->gc_ctx == NULL || | 1214 | if (test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) |
| 1200 | test_bit(RPCAUTH_CRED_UPTODATE, &cred->cr_flags) == 0) | ||
| 1201 | return 0; | 1215 | return 0; |
| 1202 | 1216 | ||
| 1203 | gss_cred->gc_ctx->gc_proc = RPC_GSS_PROC_DESTROY; | 1217 | ctx->gc_proc = RPC_GSS_PROC_DESTROY; |
| 1204 | cred->cr_ops = &gss_nullops; | 1218 | cred->cr_ops = &gss_nullops; |
| 1205 | 1219 | ||
| 1206 | /* Take a reference to ensure the cred will be destroyed either | 1220 | /* Take a reference to ensure the cred will be destroyed either |
| @@ -1225,6 +1239,7 @@ gss_do_free_ctx(struct gss_cl_ctx *ctx) | |||
| 1225 | 1239 | ||
| 1226 | gss_delete_sec_context(&ctx->gc_gss_ctx); | 1240 | gss_delete_sec_context(&ctx->gc_gss_ctx); |
| 1227 | kfree(ctx->gc_wire_ctx.data); | 1241 | kfree(ctx->gc_wire_ctx.data); |
| 1242 | kfree(ctx->gc_acceptor.data); | ||
| 1228 | kfree(ctx); | 1243 | kfree(ctx); |
| 1229 | } | 1244 | } |
| 1230 | 1245 | ||
| @@ -1260,7 +1275,7 @@ gss_destroy_nullcred(struct rpc_cred *cred) | |||
| 1260 | { | 1275 | { |
| 1261 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | 1276 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); |
| 1262 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); | 1277 | struct gss_auth *gss_auth = container_of(cred->cr_auth, struct gss_auth, rpc_auth); |
| 1263 | struct gss_cl_ctx *ctx = gss_cred->gc_ctx; | 1278 | struct gss_cl_ctx *ctx = rcu_dereference_protected(gss_cred->gc_ctx, 1); |
| 1264 | 1279 | ||
| 1265 | RCU_INIT_POINTER(gss_cred->gc_ctx, NULL); | 1280 | RCU_INIT_POINTER(gss_cred->gc_ctx, NULL); |
| 1266 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); | 1281 | call_rcu(&cred->cr_rcu, gss_free_cred_callback); |
| @@ -1332,6 +1347,36 @@ gss_cred_init(struct rpc_auth *auth, struct rpc_cred *cred) | |||
| 1332 | return err; | 1347 | return err; |
| 1333 | } | 1348 | } |
| 1334 | 1349 | ||
| 1350 | static char * | ||
| 1351 | gss_stringify_acceptor(struct rpc_cred *cred) | ||
| 1352 | { | ||
| 1353 | char *string = NULL; | ||
| 1354 | struct gss_cred *gss_cred = container_of(cred, struct gss_cred, gc_base); | ||
| 1355 | struct gss_cl_ctx *ctx; | ||
| 1356 | struct xdr_netobj *acceptor; | ||
| 1357 | |||
| 1358 | rcu_read_lock(); | ||
| 1359 | ctx = rcu_dereference(gss_cred->gc_ctx); | ||
| 1360 | if (!ctx) | ||
| 1361 | goto out; | ||
| 1362 | |||
| 1363 | acceptor = &ctx->gc_acceptor; | ||
| 1364 | |||
| 1365 | /* no point if there's no string */ | ||
| 1366 | if (!acceptor->len) | ||
| 1367 | goto out; | ||
| 1368 | |||
| 1369 | string = kmalloc(acceptor->len + 1, GFP_KERNEL); | ||
| 1370 | if (!string) | ||
| 1371 | goto out; | ||
| 1372 | |||
| 1373 | memcpy(string, acceptor->data, acceptor->len); | ||
| 1374 | string[acceptor->len] = '\0'; | ||
| 1375 | out: | ||
| 1376 | rcu_read_unlock(); | ||
| 1377 | return string; | ||
| 1378 | } | ||
| 1379 | |||
| 1335 | /* | 1380 | /* |
| 1336 | * Returns -EACCES if GSS context is NULL or will expire within the | 1381 | * Returns -EACCES if GSS context is NULL or will expire within the |
| 1337 | * timeout (miliseconds) | 1382 | * timeout (miliseconds) |
| @@ -1340,15 +1385,16 @@ static int | |||
| 1340 | gss_key_timeout(struct rpc_cred *rc) | 1385 | gss_key_timeout(struct rpc_cred *rc) |
| 1341 | { | 1386 | { |
| 1342 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); | 1387 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); |
| 1388 | struct gss_cl_ctx *ctx; | ||
| 1343 | unsigned long now = jiffies; | 1389 | unsigned long now = jiffies; |
| 1344 | unsigned long expire; | 1390 | unsigned long expire; |
| 1345 | 1391 | ||
| 1346 | if (gss_cred->gc_ctx == NULL) | 1392 | rcu_read_lock(); |
| 1347 | return -EACCES; | 1393 | ctx = rcu_dereference(gss_cred->gc_ctx); |
| 1348 | 1394 | if (ctx) | |
| 1349 | expire = gss_cred->gc_ctx->gc_expiry - (gss_key_expire_timeo * HZ); | 1395 | expire = ctx->gc_expiry - (gss_key_expire_timeo * HZ); |
| 1350 | 1396 | rcu_read_unlock(); | |
| 1351 | if (time_after(now, expire)) | 1397 | if (!ctx || time_after(now, expire)) |
| 1352 | return -EACCES; | 1398 | return -EACCES; |
| 1353 | return 0; | 1399 | return 0; |
| 1354 | } | 1400 | } |
| @@ -1357,13 +1403,19 @@ static int | |||
| 1357 | gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) | 1403 | gss_match(struct auth_cred *acred, struct rpc_cred *rc, int flags) |
| 1358 | { | 1404 | { |
| 1359 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); | 1405 | struct gss_cred *gss_cred = container_of(rc, struct gss_cred, gc_base); |
| 1406 | struct gss_cl_ctx *ctx; | ||
| 1360 | int ret; | 1407 | int ret; |
| 1361 | 1408 | ||
| 1362 | if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) | 1409 | if (test_bit(RPCAUTH_CRED_NEW, &rc->cr_flags)) |
| 1363 | goto out; | 1410 | goto out; |
| 1364 | /* Don't match with creds that have expired. */ | 1411 | /* Don't match with creds that have expired. */ |
| 1365 | if (time_after(jiffies, gss_cred->gc_ctx->gc_expiry)) | 1412 | rcu_read_lock(); |
| 1413 | ctx = rcu_dereference(gss_cred->gc_ctx); | ||
| 1414 | if (!ctx || time_after(jiffies, ctx->gc_expiry)) { | ||
| 1415 | rcu_read_unlock(); | ||
| 1366 | return 0; | 1416 | return 0; |
| 1417 | } | ||
| 1418 | rcu_read_unlock(); | ||
| 1367 | if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags)) | 1419 | if (!test_bit(RPCAUTH_CRED_UPTODATE, &rc->cr_flags)) |
| 1368 | return 0; | 1420 | return 0; |
| 1369 | out: | 1421 | out: |
| @@ -1909,29 +1961,31 @@ static const struct rpc_authops authgss_ops = { | |||
| 1909 | }; | 1961 | }; |
| 1910 | 1962 | ||
| 1911 | static const struct rpc_credops gss_credops = { | 1963 | static const struct rpc_credops gss_credops = { |
| 1912 | .cr_name = "AUTH_GSS", | 1964 | .cr_name = "AUTH_GSS", |
| 1913 | .crdestroy = gss_destroy_cred, | 1965 | .crdestroy = gss_destroy_cred, |
| 1914 | .cr_init = gss_cred_init, | 1966 | .cr_init = gss_cred_init, |
| 1915 | .crbind = rpcauth_generic_bind_cred, | 1967 | .crbind = rpcauth_generic_bind_cred, |
| 1916 | .crmatch = gss_match, | 1968 | .crmatch = gss_match, |
| 1917 | .crmarshal = gss_marshal, | 1969 | .crmarshal = gss_marshal, |
| 1918 | .crrefresh = gss_refresh, | 1970 | .crrefresh = gss_refresh, |
| 1919 | .crvalidate = gss_validate, | 1971 | .crvalidate = gss_validate, |
| 1920 | .crwrap_req = gss_wrap_req, | 1972 | .crwrap_req = gss_wrap_req, |
| 1921 | .crunwrap_resp = gss_unwrap_resp, | 1973 | .crunwrap_resp = gss_unwrap_resp, |
| 1922 | .crkey_timeout = gss_key_timeout, | 1974 | .crkey_timeout = gss_key_timeout, |
| 1975 | .crstringify_acceptor = gss_stringify_acceptor, | ||
| 1923 | }; | 1976 | }; |
| 1924 | 1977 | ||
| 1925 | static const struct rpc_credops gss_nullops = { | 1978 | static const struct rpc_credops gss_nullops = { |
| 1926 | .cr_name = "AUTH_GSS", | 1979 | .cr_name = "AUTH_GSS", |
| 1927 | .crdestroy = gss_destroy_nullcred, | 1980 | .crdestroy = gss_destroy_nullcred, |
| 1928 | .crbind = rpcauth_generic_bind_cred, | 1981 | .crbind = rpcauth_generic_bind_cred, |
| 1929 | .crmatch = gss_match, | 1982 | .crmatch = gss_match, |
| 1930 | .crmarshal = gss_marshal, | 1983 | .crmarshal = gss_marshal, |
| 1931 | .crrefresh = gss_refresh_null, | 1984 | .crrefresh = gss_refresh_null, |
| 1932 | .crvalidate = gss_validate, | 1985 | .crvalidate = gss_validate, |
| 1933 | .crwrap_req = gss_wrap_req, | 1986 | .crwrap_req = gss_wrap_req, |
| 1934 | .crunwrap_resp = gss_unwrap_resp, | 1987 | .crunwrap_resp = gss_unwrap_resp, |
| 1988 | .crstringify_acceptor = gss_stringify_acceptor, | ||
| 1935 | }; | 1989 | }; |
| 1936 | 1990 | ||
| 1937 | static const struct rpc_pipe_ops gss_upcall_ops_v0 = { | 1991 | static const struct rpc_pipe_ops gss_upcall_ops_v0 = { |
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c index 0f43e894bc0a..f5ed9f6ece06 100644 --- a/net/sunrpc/auth_gss/gss_krb5_crypto.c +++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c | |||
| @@ -641,7 +641,7 @@ out: | |||
| 641 | 641 | ||
| 642 | u32 | 642 | u32 |
| 643 | gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, | 643 | gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, |
| 644 | struct xdr_buf *buf, int ec, struct page **pages) | 644 | struct xdr_buf *buf, struct page **pages) |
| 645 | { | 645 | { |
| 646 | u32 err; | 646 | u32 err; |
| 647 | struct xdr_netobj hmac; | 647 | struct xdr_netobj hmac; |
| @@ -684,13 +684,8 @@ gss_krb5_aes_encrypt(struct krb5_ctx *kctx, u32 offset, | |||
| 684 | ecptr = buf->tail[0].iov_base; | 684 | ecptr = buf->tail[0].iov_base; |
| 685 | } | 685 | } |
| 686 | 686 | ||
| 687 | memset(ecptr, 'X', ec); | ||
| 688 | buf->tail[0].iov_len += ec; | ||
| 689 | buf->len += ec; | ||
| 690 | |||
| 691 | /* copy plaintext gss token header after filler (if any) */ | 687 | /* copy plaintext gss token header after filler (if any) */ |
| 692 | memcpy(ecptr + ec, buf->head[0].iov_base + offset, | 688 | memcpy(ecptr, buf->head[0].iov_base + offset, GSS_KRB5_TOK_HDR_LEN); |
| 693 | GSS_KRB5_TOK_HDR_LEN); | ||
| 694 | buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN; | 689 | buf->tail[0].iov_len += GSS_KRB5_TOK_HDR_LEN; |
| 695 | buf->len += GSS_KRB5_TOK_HDR_LEN; | 690 | buf->len += GSS_KRB5_TOK_HDR_LEN; |
| 696 | 691 | ||
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c index 62ae3273186c..42768e5c3994 100644 --- a/net/sunrpc/auth_gss/gss_krb5_seal.c +++ b/net/sunrpc/auth_gss/gss_krb5_seal.c | |||
| @@ -70,31 +70,37 @@ | |||
| 70 | 70 | ||
| 71 | DEFINE_SPINLOCK(krb5_seq_lock); | 71 | DEFINE_SPINLOCK(krb5_seq_lock); |
| 72 | 72 | ||
| 73 | static char * | 73 | static void * |
| 74 | setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token) | 74 | setup_token(struct krb5_ctx *ctx, struct xdr_netobj *token) |
| 75 | { | 75 | { |
| 76 | __be16 *ptr, *krb5_hdr; | 76 | u16 *ptr; |
| 77 | void *krb5_hdr; | ||
| 77 | int body_size = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; | 78 | int body_size = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; |
| 78 | 79 | ||
| 79 | token->len = g_token_size(&ctx->mech_used, body_size); | 80 | token->len = g_token_size(&ctx->mech_used, body_size); |
| 80 | 81 | ||
| 81 | ptr = (__be16 *)token->data; | 82 | ptr = (u16 *)token->data; |
| 82 | g_make_token_header(&ctx->mech_used, body_size, (unsigned char **)&ptr); | 83 | g_make_token_header(&ctx->mech_used, body_size, (unsigned char **)&ptr); |
| 83 | 84 | ||
| 84 | /* ptr now at start of header described in rfc 1964, section 1.2.1: */ | 85 | /* ptr now at start of header described in rfc 1964, section 1.2.1: */ |
| 85 | krb5_hdr = ptr; | 86 | krb5_hdr = ptr; |
| 86 | *ptr++ = KG_TOK_MIC_MSG; | 87 | *ptr++ = KG_TOK_MIC_MSG; |
| 87 | *ptr++ = cpu_to_le16(ctx->gk5e->signalg); | 88 | /* |
| 89 | * signalg is stored as if it were converted from LE to host endian, even | ||
| 90 | * though it's an opaque pair of bytes according to the RFC. | ||
| 91 | */ | ||
| 92 | *ptr++ = (__force u16)cpu_to_le16(ctx->gk5e->signalg); | ||
| 88 | *ptr++ = SEAL_ALG_NONE; | 93 | *ptr++ = SEAL_ALG_NONE; |
| 89 | *ptr++ = 0xffff; | 94 | *ptr = 0xffff; |
| 90 | 95 | ||
| 91 | return (char *)krb5_hdr; | 96 | return krb5_hdr; |
| 92 | } | 97 | } |
| 93 | 98 | ||
| 94 | static void * | 99 | static void * |
| 95 | setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token) | 100 | setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token) |
| 96 | { | 101 | { |
| 97 | __be16 *ptr, *krb5_hdr; | 102 | u16 *ptr; |
| 103 | void *krb5_hdr; | ||
| 98 | u8 *p, flags = 0x00; | 104 | u8 *p, flags = 0x00; |
| 99 | 105 | ||
| 100 | if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0) | 106 | if ((ctx->flags & KRB5_CTX_FLAG_INITIATOR) == 0) |
| @@ -104,15 +110,15 @@ setup_token_v2(struct krb5_ctx *ctx, struct xdr_netobj *token) | |||
| 104 | 110 | ||
| 105 | /* Per rfc 4121, sec 4.2.6.1, there is no header, | 111 | /* Per rfc 4121, sec 4.2.6.1, there is no header, |
| 106 | * just start the token */ | 112 | * just start the token */ |
| 107 | krb5_hdr = ptr = (__be16 *)token->data; | 113 | krb5_hdr = ptr = (u16 *)token->data; |
| 108 | 114 | ||
| 109 | *ptr++ = KG2_TOK_MIC; | 115 | *ptr++ = KG2_TOK_MIC; |
| 110 | p = (u8 *)ptr; | 116 | p = (u8 *)ptr; |
| 111 | *p++ = flags; | 117 | *p++ = flags; |
| 112 | *p++ = 0xff; | 118 | *p++ = 0xff; |
| 113 | ptr = (__be16 *)p; | 119 | ptr = (u16 *)p; |
| 114 | *ptr++ = 0xffff; | ||
| 115 | *ptr++ = 0xffff; | 120 | *ptr++ = 0xffff; |
| 121 | *ptr = 0xffff; | ||
| 116 | 122 | ||
| 117 | token->len = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; | 123 | token->len = GSS_KRB5_TOK_HDR_LEN + ctx->gk5e->cksumlength; |
| 118 | return krb5_hdr; | 124 | return krb5_hdr; |
| @@ -181,7 +187,7 @@ gss_get_mic_v2(struct krb5_ctx *ctx, struct xdr_buf *text, | |||
| 181 | spin_lock(&krb5_seq_lock); | 187 | spin_lock(&krb5_seq_lock); |
| 182 | seq_send = ctx->seq_send64++; | 188 | seq_send = ctx->seq_send64++; |
| 183 | spin_unlock(&krb5_seq_lock); | 189 | spin_unlock(&krb5_seq_lock); |
| 184 | *((u64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send); | 190 | *((__be64 *)(krb5_hdr + 8)) = cpu_to_be64(seq_send); |
| 185 | 191 | ||
| 186 | if (ctx->initiate) { | 192 | if (ctx->initiate) { |
| 187 | cksumkey = ctx->initiator_sign; | 193 | cksumkey = ctx->initiator_sign; |
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c index 42560e55d978..4b614c604fe0 100644 --- a/net/sunrpc/auth_gss/gss_krb5_wrap.c +++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c | |||
| @@ -201,9 +201,15 @@ gss_wrap_kerberos_v1(struct krb5_ctx *kctx, int offset, | |||
| 201 | 201 | ||
| 202 | msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength; | 202 | msg_start = ptr + GSS_KRB5_TOK_HDR_LEN + kctx->gk5e->cksumlength; |
| 203 | 203 | ||
| 204 | *(__be16 *)(ptr + 2) = cpu_to_le16(kctx->gk5e->signalg); | 204 | /* |
| 205 | memset(ptr + 4, 0xff, 4); | 205 | * signalg and sealalg are stored as if they were converted from LE |
| 206 | *(__be16 *)(ptr + 4) = cpu_to_le16(kctx->gk5e->sealalg); | 206 | * to host endian, even though they're opaque pairs of bytes according |
| 207 | * to the RFC. | ||
| 208 | */ | ||
| 209 | *(__le16 *)(ptr + 2) = cpu_to_le16(kctx->gk5e->signalg); | ||
| 210 | *(__le16 *)(ptr + 4) = cpu_to_le16(kctx->gk5e->sealalg); | ||
| 211 | ptr[6] = 0xff; | ||
| 212 | ptr[7] = 0xff; | ||
| 207 | 213 | ||
| 208 | gss_krb5_make_confounder(msg_start, conflen); | 214 | gss_krb5_make_confounder(msg_start, conflen); |
| 209 | 215 | ||
| @@ -438,7 +444,7 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset, | |||
| 438 | u8 *ptr, *plainhdr; | 444 | u8 *ptr, *plainhdr; |
| 439 | s32 now; | 445 | s32 now; |
| 440 | u8 flags = 0x00; | 446 | u8 flags = 0x00; |
| 441 | __be16 *be16ptr, ec = 0; | 447 | __be16 *be16ptr; |
| 442 | __be64 *be64ptr; | 448 | __be64 *be64ptr; |
| 443 | u32 err; | 449 | u32 err; |
| 444 | 450 | ||
| @@ -468,16 +474,16 @@ gss_wrap_kerberos_v2(struct krb5_ctx *kctx, u32 offset, | |||
| 468 | be16ptr = (__be16 *)ptr; | 474 | be16ptr = (__be16 *)ptr; |
| 469 | 475 | ||
| 470 | blocksize = crypto_blkcipher_blocksize(kctx->acceptor_enc); | 476 | blocksize = crypto_blkcipher_blocksize(kctx->acceptor_enc); |
| 471 | *be16ptr++ = cpu_to_be16(ec); | 477 | *be16ptr++ = 0; |
| 472 | /* "inner" token header always uses 0 for RRC */ | 478 | /* "inner" token header always uses 0 for RRC */ |
| 473 | *be16ptr++ = cpu_to_be16(0); | 479 | *be16ptr++ = 0; |
| 474 | 480 | ||
| 475 | be64ptr = (__be64 *)be16ptr; | 481 | be64ptr = (__be64 *)be16ptr; |
| 476 | spin_lock(&krb5_seq_lock); | 482 | spin_lock(&krb5_seq_lock); |
| 477 | *be64ptr = cpu_to_be64(kctx->seq_send64++); | 483 | *be64ptr = cpu_to_be64(kctx->seq_send64++); |
| 478 | spin_unlock(&krb5_seq_lock); | 484 | spin_unlock(&krb5_seq_lock); |
| 479 | 485 | ||
| 480 | err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, ec, pages); | 486 | err = (*kctx->gk5e->encrypt_v2)(kctx, offset, buf, pages); |
| 481 | if (err) | 487 | if (err) |
| 482 | return err; | 488 | return err; |
| 483 | 489 | ||
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c index f0ebe07978a2..712c123e04e9 100644 --- a/net/sunrpc/auth_null.c +++ b/net/sunrpc/auth_null.c | |||
| @@ -35,6 +35,8 @@ nul_destroy(struct rpc_auth *auth) | |||
| 35 | static struct rpc_cred * | 35 | static struct rpc_cred * |
| 36 | nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) | 36 | nul_lookup_cred(struct rpc_auth *auth, struct auth_cred *acred, int flags) |
| 37 | { | 37 | { |
| 38 | if (flags & RPCAUTH_LOOKUP_RCU) | ||
| 39 | return &null_cred; | ||
| 38 | return get_rpccred(&null_cred); | 40 | return get_rpccred(&null_cred); |
| 39 | } | 41 | } |
| 40 | 42 | ||
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 2e6ab10734f6..488ddeed9363 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
| @@ -1746,6 +1746,7 @@ call_bind_status(struct rpc_task *task) | |||
| 1746 | case -EHOSTDOWN: | 1746 | case -EHOSTDOWN: |
| 1747 | case -EHOSTUNREACH: | 1747 | case -EHOSTUNREACH: |
| 1748 | case -ENETUNREACH: | 1748 | case -ENETUNREACH: |
| 1749 | case -ENOBUFS: | ||
| 1749 | case -EPIPE: | 1750 | case -EPIPE: |
| 1750 | dprintk("RPC: %5u remote rpcbind unreachable: %d\n", | 1751 | dprintk("RPC: %5u remote rpcbind unreachable: %d\n", |
| 1751 | task->tk_pid, task->tk_status); | 1752 | task->tk_pid, task->tk_status); |
| @@ -1812,6 +1813,8 @@ call_connect_status(struct rpc_task *task) | |||
| 1812 | case -ECONNABORTED: | 1813 | case -ECONNABORTED: |
| 1813 | case -ENETUNREACH: | 1814 | case -ENETUNREACH: |
| 1814 | case -EHOSTUNREACH: | 1815 | case -EHOSTUNREACH: |
| 1816 | case -ENOBUFS: | ||
| 1817 | case -EPIPE: | ||
| 1815 | if (RPC_IS_SOFTCONN(task)) | 1818 | if (RPC_IS_SOFTCONN(task)) |
| 1816 | break; | 1819 | break; |
| 1817 | /* retry with existing socket, after a delay */ | 1820 | /* retry with existing socket, after a delay */ |
| @@ -1918,6 +1921,7 @@ call_transmit_status(struct rpc_task *task) | |||
| 1918 | case -ECONNRESET: | 1921 | case -ECONNRESET: |
| 1919 | case -ECONNABORTED: | 1922 | case -ECONNABORTED: |
| 1920 | case -ENOTCONN: | 1923 | case -ENOTCONN: |
| 1924 | case -ENOBUFS: | ||
| 1921 | case -EPIPE: | 1925 | case -EPIPE: |
| 1922 | rpc_task_force_reencode(task); | 1926 | rpc_task_force_reencode(task); |
| 1923 | } | 1927 | } |
| @@ -2034,6 +2038,7 @@ call_status(struct rpc_task *task) | |||
| 2034 | case -ECONNRESET: | 2038 | case -ECONNRESET: |
| 2035 | case -ECONNABORTED: | 2039 | case -ECONNABORTED: |
| 2036 | rpc_force_rebind(clnt); | 2040 | rpc_force_rebind(clnt); |
| 2041 | case -ENOBUFS: | ||
| 2037 | rpc_delay(task, 3*HZ); | 2042 | rpc_delay(task, 3*HZ); |
| 2038 | case -EPIPE: | 2043 | case -EPIPE: |
| 2039 | case -ENOTCONN: | 2044 | case -ENOTCONN: |
diff --git a/net/sunrpc/rpc_pipe.c b/net/sunrpc/rpc_pipe.c index b18554898562..2d12b76b5a64 100644 --- a/net/sunrpc/rpc_pipe.c +++ b/net/sunrpc/rpc_pipe.c | |||
| @@ -195,7 +195,7 @@ static struct inode * | |||
| 195 | rpc_alloc_inode(struct super_block *sb) | 195 | rpc_alloc_inode(struct super_block *sb) |
| 196 | { | 196 | { |
| 197 | struct rpc_inode *rpci; | 197 | struct rpc_inode *rpci; |
| 198 | rpci = (struct rpc_inode *)kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); | 198 | rpci = kmem_cache_alloc(rpc_inode_cachep, GFP_KERNEL); |
| 199 | if (!rpci) | 199 | if (!rpci) |
| 200 | return NULL; | 200 | return NULL; |
| 201 | return &rpci->vfs_inode; | 201 | return &rpci->vfs_inode; |
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c index 51c63165073c..56e4e150e80e 100644 --- a/net/sunrpc/xprt.c +++ b/net/sunrpc/xprt.c | |||
| @@ -744,6 +744,7 @@ static void xprt_connect_status(struct rpc_task *task) | |||
| 744 | case -ECONNABORTED: | 744 | case -ECONNABORTED: |
| 745 | case -ENETUNREACH: | 745 | case -ENETUNREACH: |
| 746 | case -EHOSTUNREACH: | 746 | case -EHOSTUNREACH: |
| 747 | case -EPIPE: | ||
| 747 | case -EAGAIN: | 748 | case -EAGAIN: |
| 748 | dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid); | 749 | dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid); |
| 749 | break; | 750 | break; |
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c index 693966d3f33b..6166c985fe24 100644 --- a/net/sunrpc/xprtrdma/rpc_rdma.c +++ b/net/sunrpc/xprtrdma/rpc_rdma.c | |||
| @@ -53,14 +53,6 @@ | |||
| 53 | # define RPCDBG_FACILITY RPCDBG_TRANS | 53 | # define RPCDBG_FACILITY RPCDBG_TRANS |
| 54 | #endif | 54 | #endif |
| 55 | 55 | ||
| 56 | enum rpcrdma_chunktype { | ||
| 57 | rpcrdma_noch = 0, | ||
| 58 | rpcrdma_readch, | ||
| 59 | rpcrdma_areadch, | ||
| 60 | rpcrdma_writech, | ||
| 61 | rpcrdma_replych | ||
| 62 | }; | ||
| 63 | |||
| 64 | #ifdef RPC_DEBUG | 56 | #ifdef RPC_DEBUG |
| 65 | static const char transfertypes[][12] = { | 57 | static const char transfertypes[][12] = { |
| 66 | "pure inline", /* no chunks */ | 58 | "pure inline", /* no chunks */ |
| @@ -279,13 +271,37 @@ rpcrdma_create_chunks(struct rpc_rqst *rqst, struct xdr_buf *target, | |||
| 279 | return (unsigned char *)iptr - (unsigned char *)headerp; | 271 | return (unsigned char *)iptr - (unsigned char *)headerp; |
| 280 | 272 | ||
| 281 | out: | 273 | out: |
| 282 | for (pos = 0; nchunks--;) | 274 | if (r_xprt->rx_ia.ri_memreg_strategy != RPCRDMA_FRMR) { |
| 283 | pos += rpcrdma_deregister_external( | 275 | for (pos = 0; nchunks--;) |
| 284 | &req->rl_segments[pos], r_xprt); | 276 | pos += rpcrdma_deregister_external( |
| 277 | &req->rl_segments[pos], r_xprt); | ||
| 278 | } | ||
| 285 | return n; | 279 | return n; |
| 286 | } | 280 | } |
| 287 | 281 | ||
| 288 | /* | 282 | /* |
| 283 | * Marshal chunks. This routine returns the header length | ||
| 284 | * consumed by marshaling. | ||
| 285 | * | ||
| 286 | * Returns positive RPC/RDMA header size, or negative errno. | ||
| 287 | */ | ||
| 288 | |||
| 289 | ssize_t | ||
| 290 | rpcrdma_marshal_chunks(struct rpc_rqst *rqst, ssize_t result) | ||
| 291 | { | ||
| 292 | struct rpcrdma_req *req = rpcr_to_rdmar(rqst); | ||
| 293 | struct rpcrdma_msg *headerp = (struct rpcrdma_msg *)req->rl_base; | ||
| 294 | |||
| 295 | if (req->rl_rtype != rpcrdma_noch) | ||
| 296 | result = rpcrdma_create_chunks(rqst, &rqst->rq_snd_buf, | ||
| 297 | headerp, req->rl_rtype); | ||
| 298 | else if (req->rl_wtype != rpcrdma_noch) | ||
| 299 | result = rpcrdma_create_chunks(rqst, &rqst->rq_rcv_buf, | ||
| 300 | headerp, req->rl_wtype); | ||
| 301 | return result; | ||
| 302 | } | ||
| 303 | |||
| 304 | /* | ||
| 289 | * Copy write data inline. | 305 | * Copy write data inline. |
| 290 | * This function is used for "small" requests. Data which is passed | 306 | * This function is used for "small" requests. Data which is passed |
| 291 | * to RPC via iovecs (or page list) is copied directly into the | 307 | * to RPC via iovecs (or page list) is copied directly into the |
| @@ -377,7 +393,6 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 377 | char *base; | 393 | char *base; |
| 378 | size_t rpclen, padlen; | 394 | size_t rpclen, padlen; |
| 379 | ssize_t hdrlen; | 395 | ssize_t hdrlen; |
| 380 | enum rpcrdma_chunktype rtype, wtype; | ||
| 381 | struct rpcrdma_msg *headerp; | 396 | struct rpcrdma_msg *headerp; |
| 382 | 397 | ||
| 383 | /* | 398 | /* |
| @@ -415,13 +430,13 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 415 | * into pages; otherwise use reply chunks. | 430 | * into pages; otherwise use reply chunks. |
| 416 | */ | 431 | */ |
| 417 | if (rqst->rq_rcv_buf.buflen <= RPCRDMA_INLINE_READ_THRESHOLD(rqst)) | 432 | if (rqst->rq_rcv_buf.buflen <= RPCRDMA_INLINE_READ_THRESHOLD(rqst)) |
| 418 | wtype = rpcrdma_noch; | 433 | req->rl_wtype = rpcrdma_noch; |
| 419 | else if (rqst->rq_rcv_buf.page_len == 0) | 434 | else if (rqst->rq_rcv_buf.page_len == 0) |
| 420 | wtype = rpcrdma_replych; | 435 | req->rl_wtype = rpcrdma_replych; |
| 421 | else if (rqst->rq_rcv_buf.flags & XDRBUF_READ) | 436 | else if (rqst->rq_rcv_buf.flags & XDRBUF_READ) |
| 422 | wtype = rpcrdma_writech; | 437 | req->rl_wtype = rpcrdma_writech; |
| 423 | else | 438 | else |
| 424 | wtype = rpcrdma_replych; | 439 | req->rl_wtype = rpcrdma_replych; |
| 425 | 440 | ||
| 426 | /* | 441 | /* |
| 427 | * Chunks needed for arguments? | 442 | * Chunks needed for arguments? |
| @@ -438,16 +453,16 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 438 | * TBD check NFSv4 setacl | 453 | * TBD check NFSv4 setacl |
| 439 | */ | 454 | */ |
| 440 | if (rqst->rq_snd_buf.len <= RPCRDMA_INLINE_WRITE_THRESHOLD(rqst)) | 455 | if (rqst->rq_snd_buf.len <= RPCRDMA_INLINE_WRITE_THRESHOLD(rqst)) |
| 441 | rtype = rpcrdma_noch; | 456 | req->rl_rtype = rpcrdma_noch; |
| 442 | else if (rqst->rq_snd_buf.page_len == 0) | 457 | else if (rqst->rq_snd_buf.page_len == 0) |
| 443 | rtype = rpcrdma_areadch; | 458 | req->rl_rtype = rpcrdma_areadch; |
| 444 | else | 459 | else |
| 445 | rtype = rpcrdma_readch; | 460 | req->rl_rtype = rpcrdma_readch; |
| 446 | 461 | ||
| 447 | /* The following simplification is not true forever */ | 462 | /* The following simplification is not true forever */ |
| 448 | if (rtype != rpcrdma_noch && wtype == rpcrdma_replych) | 463 | if (req->rl_rtype != rpcrdma_noch && req->rl_wtype == rpcrdma_replych) |
| 449 | wtype = rpcrdma_noch; | 464 | req->rl_wtype = rpcrdma_noch; |
| 450 | if (rtype != rpcrdma_noch && wtype != rpcrdma_noch) { | 465 | if (req->rl_rtype != rpcrdma_noch && req->rl_wtype != rpcrdma_noch) { |
| 451 | dprintk("RPC: %s: cannot marshal multiple chunk lists\n", | 466 | dprintk("RPC: %s: cannot marshal multiple chunk lists\n", |
| 452 | __func__); | 467 | __func__); |
| 453 | return -EIO; | 468 | return -EIO; |
| @@ -461,7 +476,7 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 461 | * When padding is in use and applies to the transfer, insert | 476 | * When padding is in use and applies to the transfer, insert |
| 462 | * it and change the message type. | 477 | * it and change the message type. |
| 463 | */ | 478 | */ |
| 464 | if (rtype == rpcrdma_noch) { | 479 | if (req->rl_rtype == rpcrdma_noch) { |
| 465 | 480 | ||
| 466 | padlen = rpcrdma_inline_pullup(rqst, | 481 | padlen = rpcrdma_inline_pullup(rqst, |
| 467 | RPCRDMA_INLINE_PAD_VALUE(rqst)); | 482 | RPCRDMA_INLINE_PAD_VALUE(rqst)); |
| @@ -476,7 +491,7 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 476 | headerp->rm_body.rm_padded.rm_pempty[1] = xdr_zero; | 491 | headerp->rm_body.rm_padded.rm_pempty[1] = xdr_zero; |
| 477 | headerp->rm_body.rm_padded.rm_pempty[2] = xdr_zero; | 492 | headerp->rm_body.rm_padded.rm_pempty[2] = xdr_zero; |
| 478 | hdrlen += 2 * sizeof(u32); /* extra words in padhdr */ | 493 | hdrlen += 2 * sizeof(u32); /* extra words in padhdr */ |
| 479 | if (wtype != rpcrdma_noch) { | 494 | if (req->rl_wtype != rpcrdma_noch) { |
| 480 | dprintk("RPC: %s: invalid chunk list\n", | 495 | dprintk("RPC: %s: invalid chunk list\n", |
| 481 | __func__); | 496 | __func__); |
| 482 | return -EIO; | 497 | return -EIO; |
| @@ -497,30 +512,18 @@ rpcrdma_marshal_req(struct rpc_rqst *rqst) | |||
| 497 | * on receive. Therefore, we request a reply chunk | 512 | * on receive. Therefore, we request a reply chunk |
| 498 | * for non-writes wherever feasible and efficient. | 513 | * for non-writes wherever feasible and efficient. |
| 499 | */ | 514 | */ |
| 500 | if (wtype == rpcrdma_noch) | 515 | if (req->rl_wtype == rpcrdma_noch) |
| 501 | wtype = rpcrdma_replych; | 516 | req->rl_wtype = rpcrdma_replych; |
| 502 | } | 517 | } |
| 503 | } | 518 | } |
| 504 | 519 | ||
| 505 | /* | 520 | hdrlen = rpcrdma_marshal_chunks(rqst, hdrlen); |
| 506 | * Marshal chunks. This routine will return the header length | ||
| 507 | * consumed by marshaling. | ||
| 508 | */ | ||
| 509 | if (rtype != rpcrdma_noch) { | ||
| 510 | hdrlen = rpcrdma_create_chunks(rqst, | ||
| 511 | &rqst->rq_snd_buf, headerp, rtype); | ||
| 512 | wtype = rtype; /* simplify dprintk */ | ||
| 513 | |||
| 514 | } else if (wtype != rpcrdma_noch) { | ||
| 515 | hdrlen = rpcrdma_create_chunks(rqst, | ||
| 516 | &rqst->rq_rcv_buf, headerp, wtype); | ||
| 517 | } | ||
| 518 | if (hdrlen < 0) | 521 | if (hdrlen < 0) |
| 519 | return hdrlen; | 522 | return hdrlen; |
| 520 | 523 | ||
| 521 | dprintk("RPC: %s: %s: hdrlen %zd rpclen %zd padlen %zd" | 524 | dprintk("RPC: %s: %s: hdrlen %zd rpclen %zd padlen %zd" |
| 522 | " headerp 0x%p base 0x%p lkey 0x%x\n", | 525 | " headerp 0x%p base 0x%p lkey 0x%x\n", |
| 523 | __func__, transfertypes[wtype], hdrlen, rpclen, padlen, | 526 | __func__, transfertypes[req->rl_wtype], hdrlen, rpclen, padlen, |
| 524 | headerp, base, req->rl_iov.lkey); | 527 | headerp, base, req->rl_iov.lkey); |
| 525 | 528 | ||
| 526 | /* | 529 | /* |
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c index 66f91f0d071a..2faac4940563 100644 --- a/net/sunrpc/xprtrdma/transport.c +++ b/net/sunrpc/xprtrdma/transport.c | |||
| @@ -296,7 +296,6 @@ xprt_setup_rdma(struct xprt_create *args) | |||
| 296 | 296 | ||
| 297 | xprt->resvport = 0; /* privileged port not needed */ | 297 | xprt->resvport = 0; /* privileged port not needed */ |
| 298 | xprt->tsh_size = 0; /* RPC-RDMA handles framing */ | 298 | xprt->tsh_size = 0; /* RPC-RDMA handles framing */ |
| 299 | xprt->max_payload = RPCRDMA_MAX_DATA_SEGS * PAGE_SIZE; | ||
| 300 | xprt->ops = &xprt_rdma_procs; | 299 | xprt->ops = &xprt_rdma_procs; |
| 301 | 300 | ||
| 302 | /* | 301 | /* |
| @@ -382,6 +381,9 @@ xprt_setup_rdma(struct xprt_create *args) | |||
| 382 | new_ep->rep_xprt = xprt; | 381 | new_ep->rep_xprt = xprt; |
| 383 | 382 | ||
| 384 | xprt_rdma_format_addresses(xprt); | 383 | xprt_rdma_format_addresses(xprt); |
| 384 | xprt->max_payload = rpcrdma_max_payload(new_xprt); | ||
| 385 | dprintk("RPC: %s: transport data payload maximum: %zu bytes\n", | ||
| 386 | __func__, xprt->max_payload); | ||
| 385 | 387 | ||
| 386 | if (!try_module_get(THIS_MODULE)) | 388 | if (!try_module_get(THIS_MODULE)) |
| 387 | goto out4; | 389 | goto out4; |
| @@ -412,7 +414,7 @@ xprt_rdma_close(struct rpc_xprt *xprt) | |||
| 412 | if (r_xprt->rx_ep.rep_connected > 0) | 414 | if (r_xprt->rx_ep.rep_connected > 0) |
| 413 | xprt->reestablish_timeout = 0; | 415 | xprt->reestablish_timeout = 0; |
| 414 | xprt_disconnect_done(xprt); | 416 | xprt_disconnect_done(xprt); |
| 415 | (void) rpcrdma_ep_disconnect(&r_xprt->rx_ep, &r_xprt->rx_ia); | 417 | rpcrdma_ep_disconnect(&r_xprt->rx_ep, &r_xprt->rx_ia); |
| 416 | } | 418 | } |
| 417 | 419 | ||
| 418 | static void | 420 | static void |
| @@ -595,13 +597,14 @@ xprt_rdma_send_request(struct rpc_task *task) | |||
| 595 | struct rpc_xprt *xprt = rqst->rq_xprt; | 597 | struct rpc_xprt *xprt = rqst->rq_xprt; |
| 596 | struct rpcrdma_req *req = rpcr_to_rdmar(rqst); | 598 | struct rpcrdma_req *req = rpcr_to_rdmar(rqst); |
| 597 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); | 599 | struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); |
| 598 | int rc; | 600 | int rc = 0; |
| 599 | 601 | ||
| 600 | if (req->rl_niovs == 0) { | 602 | if (req->rl_niovs == 0) |
| 601 | rc = rpcrdma_marshal_req(rqst); | 603 | rc = rpcrdma_marshal_req(rqst); |
| 602 | if (rc < 0) | 604 | else if (r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_FRMR) |
| 603 | goto failed_marshal; | 605 | rc = rpcrdma_marshal_chunks(rqst, 0); |
| 604 | } | 606 | if (rc < 0) |
| 607 | goto failed_marshal; | ||
| 605 | 608 | ||
| 606 | if (req->rl_reply == NULL) /* e.g. reconnection */ | 609 | if (req->rl_reply == NULL) /* e.g. reconnection */ |
| 607 | rpcrdma_recv_buffer_get(req); | 610 | rpcrdma_recv_buffer_get(req); |
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 13dbd1c389ff..61c41298b4ea 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
| @@ -61,6 +61,8 @@ | |||
| 61 | # define RPCDBG_FACILITY RPCDBG_TRANS | 61 | # define RPCDBG_FACILITY RPCDBG_TRANS |
| 62 | #endif | 62 | #endif |
| 63 | 63 | ||
| 64 | static void rpcrdma_reset_frmrs(struct rpcrdma_ia *); | ||
| 65 | |||
| 64 | /* | 66 | /* |
| 65 | * internal functions | 67 | * internal functions |
| 66 | */ | 68 | */ |
| @@ -103,17 +105,6 @@ rpcrdma_run_tasklet(unsigned long data) | |||
| 103 | 105 | ||
| 104 | static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL); | 106 | static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL); |
| 105 | 107 | ||
| 106 | static inline void | ||
| 107 | rpcrdma_schedule_tasklet(struct rpcrdma_rep *rep) | ||
| 108 | { | ||
| 109 | unsigned long flags; | ||
| 110 | |||
| 111 | spin_lock_irqsave(&rpcrdma_tk_lock_g, flags); | ||
| 112 | list_add_tail(&rep->rr_list, &rpcrdma_tasklets_g); | ||
| 113 | spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags); | ||
| 114 | tasklet_schedule(&rpcrdma_tasklet_g); | ||
| 115 | } | ||
| 116 | |||
| 117 | static void | 108 | static void |
| 118 | rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context) | 109 | rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context) |
| 119 | { | 110 | { |
| @@ -153,12 +144,7 @@ rpcrdma_sendcq_process_wc(struct ib_wc *wc) | |||
| 153 | if (wc->wr_id == 0ULL) | 144 | if (wc->wr_id == 0ULL) |
| 154 | return; | 145 | return; |
| 155 | if (wc->status != IB_WC_SUCCESS) | 146 | if (wc->status != IB_WC_SUCCESS) |
| 156 | return; | 147 | frmr->r.frmr.fr_state = FRMR_IS_STALE; |
| 157 | |||
| 158 | if (wc->opcode == IB_WC_FAST_REG_MR) | ||
| 159 | frmr->r.frmr.state = FRMR_IS_VALID; | ||
| 160 | else if (wc->opcode == IB_WC_LOCAL_INV) | ||
| 161 | frmr->r.frmr.state = FRMR_IS_INVALID; | ||
| 162 | } | 148 | } |
| 163 | 149 | ||
| 164 | static int | 150 | static int |
| @@ -217,7 +203,7 @@ rpcrdma_sendcq_upcall(struct ib_cq *cq, void *cq_context) | |||
| 217 | } | 203 | } |
| 218 | 204 | ||
| 219 | static void | 205 | static void |
| 220 | rpcrdma_recvcq_process_wc(struct ib_wc *wc) | 206 | rpcrdma_recvcq_process_wc(struct ib_wc *wc, struct list_head *sched_list) |
| 221 | { | 207 | { |
| 222 | struct rpcrdma_rep *rep = | 208 | struct rpcrdma_rep *rep = |
| 223 | (struct rpcrdma_rep *)(unsigned long)wc->wr_id; | 209 | (struct rpcrdma_rep *)(unsigned long)wc->wr_id; |
| @@ -248,28 +234,38 @@ rpcrdma_recvcq_process_wc(struct ib_wc *wc) | |||
| 248 | } | 234 | } |
| 249 | 235 | ||
| 250 | out_schedule: | 236 | out_schedule: |
| 251 | rpcrdma_schedule_tasklet(rep); | 237 | list_add_tail(&rep->rr_list, sched_list); |
| 252 | } | 238 | } |
| 253 | 239 | ||
| 254 | static int | 240 | static int |
| 255 | rpcrdma_recvcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep) | 241 | rpcrdma_recvcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep) |
| 256 | { | 242 | { |
| 243 | struct list_head sched_list; | ||
| 257 | struct ib_wc *wcs; | 244 | struct ib_wc *wcs; |
| 258 | int budget, count, rc; | 245 | int budget, count, rc; |
| 246 | unsigned long flags; | ||
| 259 | 247 | ||
| 248 | INIT_LIST_HEAD(&sched_list); | ||
| 260 | budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE; | 249 | budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE; |
| 261 | do { | 250 | do { |
| 262 | wcs = ep->rep_recv_wcs; | 251 | wcs = ep->rep_recv_wcs; |
| 263 | 252 | ||
| 264 | rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs); | 253 | rc = ib_poll_cq(cq, RPCRDMA_POLLSIZE, wcs); |
| 265 | if (rc <= 0) | 254 | if (rc <= 0) |
| 266 | return rc; | 255 | goto out_schedule; |
| 267 | 256 | ||
| 268 | count = rc; | 257 | count = rc; |
| 269 | while (count-- > 0) | 258 | while (count-- > 0) |
| 270 | rpcrdma_recvcq_process_wc(wcs++); | 259 | rpcrdma_recvcq_process_wc(wcs++, &sched_list); |
| 271 | } while (rc == RPCRDMA_POLLSIZE && --budget); | 260 | } while (rc == RPCRDMA_POLLSIZE && --budget); |
| 272 | return 0; | 261 | rc = 0; |
| 262 | |||
| 263 | out_schedule: | ||
| 264 | spin_lock_irqsave(&rpcrdma_tk_lock_g, flags); | ||
| 265 | list_splice_tail(&sched_list, &rpcrdma_tasklets_g); | ||
| 266 | spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags); | ||
| 267 | tasklet_schedule(&rpcrdma_tasklet_g); | ||
| 268 | return rc; | ||
| 273 | } | 269 | } |
| 274 | 270 | ||
| 275 | /* | 271 | /* |
| @@ -310,6 +306,13 @@ rpcrdma_recvcq_upcall(struct ib_cq *cq, void *cq_context) | |||
| 310 | rpcrdma_recvcq_poll(cq, ep); | 306 | rpcrdma_recvcq_poll(cq, ep); |
| 311 | } | 307 | } |
| 312 | 308 | ||
| 309 | static void | ||
| 310 | rpcrdma_flush_cqs(struct rpcrdma_ep *ep) | ||
| 311 | { | ||
| 312 | rpcrdma_recvcq_upcall(ep->rep_attr.recv_cq, ep); | ||
| 313 | rpcrdma_sendcq_upcall(ep->rep_attr.send_cq, ep); | ||
| 314 | } | ||
| 315 | |||
| 313 | #ifdef RPC_DEBUG | 316 | #ifdef RPC_DEBUG |
| 314 | static const char * const conn[] = { | 317 | static const char * const conn[] = { |
| 315 | "address resolved", | 318 | "address resolved", |
| @@ -323,8 +326,16 @@ static const char * const conn[] = { | |||
| 323 | "rejected", | 326 | "rejected", |
| 324 | "established", | 327 | "established", |
| 325 | "disconnected", | 328 | "disconnected", |
| 326 | "device removal" | 329 | "device removal", |
| 330 | "multicast join", | ||
| 331 | "multicast error", | ||
| 332 | "address change", | ||
| 333 | "timewait exit", | ||
| 327 | }; | 334 | }; |
| 335 | |||
| 336 | #define CONNECTION_MSG(status) \ | ||
| 337 | ((status) < ARRAY_SIZE(conn) ? \ | ||
| 338 | conn[(status)] : "unrecognized connection error") | ||
| 328 | #endif | 339 | #endif |
| 329 | 340 | ||
| 330 | static int | 341 | static int |
| @@ -382,23 +393,18 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event) | |||
| 382 | case RDMA_CM_EVENT_DEVICE_REMOVAL: | 393 | case RDMA_CM_EVENT_DEVICE_REMOVAL: |
| 383 | connstate = -ENODEV; | 394 | connstate = -ENODEV; |
| 384 | connected: | 395 | connected: |
| 385 | dprintk("RPC: %s: %s: %pI4:%u (ep 0x%p event 0x%x)\n", | ||
| 386 | __func__, | ||
| 387 | (event->event <= 11) ? conn[event->event] : | ||
| 388 | "unknown connection error", | ||
| 389 | &addr->sin_addr.s_addr, | ||
| 390 | ntohs(addr->sin_port), | ||
| 391 | ep, event->event); | ||
| 392 | atomic_set(&rpcx_to_rdmax(ep->rep_xprt)->rx_buf.rb_credits, 1); | 396 | atomic_set(&rpcx_to_rdmax(ep->rep_xprt)->rx_buf.rb_credits, 1); |
| 393 | dprintk("RPC: %s: %sconnected\n", | 397 | dprintk("RPC: %s: %sconnected\n", |
| 394 | __func__, connstate > 0 ? "" : "dis"); | 398 | __func__, connstate > 0 ? "" : "dis"); |
| 395 | ep->rep_connected = connstate; | 399 | ep->rep_connected = connstate; |
| 396 | ep->rep_func(ep); | 400 | ep->rep_func(ep); |
| 397 | wake_up_all(&ep->rep_connect_wait); | 401 | wake_up_all(&ep->rep_connect_wait); |
| 398 | break; | 402 | /*FALLTHROUGH*/ |
| 399 | default: | 403 | default: |
| 400 | dprintk("RPC: %s: unexpected CM event %d\n", | 404 | dprintk("RPC: %s: %pI4:%u (ep 0x%p): %s\n", |
| 401 | __func__, event->event); | 405 | __func__, &addr->sin_addr.s_addr, |
| 406 | ntohs(addr->sin_port), ep, | ||
| 407 | CONNECTION_MSG(event->event)); | ||
| 402 | break; | 408 | break; |
| 403 | } | 409 | } |
| 404 | 410 | ||
| @@ -558,12 +564,7 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg) | |||
| 558 | if (!ia->ri_id->device->alloc_fmr) { | 564 | if (!ia->ri_id->device->alloc_fmr) { |
| 559 | dprintk("RPC: %s: MTHCAFMR registration " | 565 | dprintk("RPC: %s: MTHCAFMR registration " |
| 560 | "not supported by HCA\n", __func__); | 566 | "not supported by HCA\n", __func__); |
| 561 | #if RPCRDMA_PERSISTENT_REGISTRATION | ||
| 562 | memreg = RPCRDMA_ALLPHYSICAL; | 567 | memreg = RPCRDMA_ALLPHYSICAL; |
| 563 | #else | ||
| 564 | rc = -ENOMEM; | ||
| 565 | goto out2; | ||
| 566 | #endif | ||
| 567 | } | 568 | } |
| 568 | } | 569 | } |
| 569 | 570 | ||
| @@ -578,20 +579,16 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg) | |||
| 578 | switch (memreg) { | 579 | switch (memreg) { |
| 579 | case RPCRDMA_FRMR: | 580 | case RPCRDMA_FRMR: |
| 580 | break; | 581 | break; |
| 581 | #if RPCRDMA_PERSISTENT_REGISTRATION | ||
| 582 | case RPCRDMA_ALLPHYSICAL: | 582 | case RPCRDMA_ALLPHYSICAL: |
| 583 | mem_priv = IB_ACCESS_LOCAL_WRITE | | 583 | mem_priv = IB_ACCESS_LOCAL_WRITE | |
| 584 | IB_ACCESS_REMOTE_WRITE | | 584 | IB_ACCESS_REMOTE_WRITE | |
| 585 | IB_ACCESS_REMOTE_READ; | 585 | IB_ACCESS_REMOTE_READ; |
| 586 | goto register_setup; | 586 | goto register_setup; |
| 587 | #endif | ||
| 588 | case RPCRDMA_MTHCAFMR: | 587 | case RPCRDMA_MTHCAFMR: |
| 589 | if (ia->ri_have_dma_lkey) | 588 | if (ia->ri_have_dma_lkey) |
| 590 | break; | 589 | break; |
| 591 | mem_priv = IB_ACCESS_LOCAL_WRITE; | 590 | mem_priv = IB_ACCESS_LOCAL_WRITE; |
| 592 | #if RPCRDMA_PERSISTENT_REGISTRATION | ||
| 593 | register_setup: | 591 | register_setup: |
| 594 | #endif | ||
| 595 | ia->ri_bind_mem = ib_get_dma_mr(ia->ri_pd, mem_priv); | 592 | ia->ri_bind_mem = ib_get_dma_mr(ia->ri_pd, mem_priv); |
| 596 | if (IS_ERR(ia->ri_bind_mem)) { | 593 | if (IS_ERR(ia->ri_bind_mem)) { |
| 597 | printk(KERN_ALERT "%s: ib_get_dma_mr for " | 594 | printk(KERN_ALERT "%s: ib_get_dma_mr for " |
| @@ -613,6 +610,7 @@ rpcrdma_ia_open(struct rpcrdma_xprt *xprt, struct sockaddr *addr, int memreg) | |||
| 613 | /* Else will do memory reg/dereg for each chunk */ | 610 | /* Else will do memory reg/dereg for each chunk */ |
| 614 | ia->ri_memreg_strategy = memreg; | 611 | ia->ri_memreg_strategy = memreg; |
| 615 | 612 | ||
| 613 | rwlock_init(&ia->ri_qplock); | ||
| 616 | return 0; | 614 | return 0; |
| 617 | out2: | 615 | out2: |
| 618 | rdma_destroy_id(ia->ri_id); | 616 | rdma_destroy_id(ia->ri_id); |
| @@ -826,10 +824,7 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | |||
| 826 | cancel_delayed_work_sync(&ep->rep_connect_worker); | 824 | cancel_delayed_work_sync(&ep->rep_connect_worker); |
| 827 | 825 | ||
| 828 | if (ia->ri_id->qp) { | 826 | if (ia->ri_id->qp) { |
| 829 | rc = rpcrdma_ep_disconnect(ep, ia); | 827 | rpcrdma_ep_disconnect(ep, ia); |
| 830 | if (rc) | ||
| 831 | dprintk("RPC: %s: rpcrdma_ep_disconnect" | ||
| 832 | " returned %i\n", __func__, rc); | ||
| 833 | rdma_destroy_qp(ia->ri_id); | 828 | rdma_destroy_qp(ia->ri_id); |
| 834 | ia->ri_id->qp = NULL; | 829 | ia->ri_id->qp = NULL; |
| 835 | } | 830 | } |
| @@ -859,7 +854,7 @@ rpcrdma_ep_destroy(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | |||
| 859 | int | 854 | int |
| 860 | rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | 855 | rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) |
| 861 | { | 856 | { |
| 862 | struct rdma_cm_id *id; | 857 | struct rdma_cm_id *id, *old; |
| 863 | int rc = 0; | 858 | int rc = 0; |
| 864 | int retry_count = 0; | 859 | int retry_count = 0; |
| 865 | 860 | ||
| @@ -867,13 +862,12 @@ rpcrdma_ep_connect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | |||
| 867 | struct rpcrdma_xprt *xprt; | 862 | struct rpcrdma_xprt *xprt; |
| 868 | retry: | 863 | retry: |
| 869 | dprintk("RPC: %s: reconnecting...\n", __func__); | 864 | dprintk("RPC: %s: reconnecting...\n", __func__); |
| 870 | rc = rpcrdma_ep_disconnect(ep, ia); | ||
| 871 | if (rc && rc != -ENOTCONN) | ||
| 872 | dprintk("RPC: %s: rpcrdma_ep_disconnect" | ||
| 873 | " status %i\n", __func__, rc); | ||
| 874 | 865 | ||
| 875 | rpcrdma_clean_cq(ep->rep_attr.recv_cq); | 866 | rpcrdma_ep_disconnect(ep, ia); |
| 876 | rpcrdma_clean_cq(ep->rep_attr.send_cq); | 867 | rpcrdma_flush_cqs(ep); |
| 868 | |||
| 869 | if (ia->ri_memreg_strategy == RPCRDMA_FRMR) | ||
| 870 | rpcrdma_reset_frmrs(ia); | ||
| 877 | 871 | ||
| 878 | xprt = container_of(ia, struct rpcrdma_xprt, rx_ia); | 872 | xprt = container_of(ia, struct rpcrdma_xprt, rx_ia); |
| 879 | id = rpcrdma_create_id(xprt, ia, | 873 | id = rpcrdma_create_id(xprt, ia, |
| @@ -905,9 +899,14 @@ retry: | |||
| 905 | rc = -ENETUNREACH; | 899 | rc = -ENETUNREACH; |
| 906 | goto out; | 900 | goto out; |
| 907 | } | 901 | } |
| 908 | rdma_destroy_qp(ia->ri_id); | 902 | |
| 909 | rdma_destroy_id(ia->ri_id); | 903 | write_lock(&ia->ri_qplock); |
| 904 | old = ia->ri_id; | ||
| 910 | ia->ri_id = id; | 905 | ia->ri_id = id; |
| 906 | write_unlock(&ia->ri_qplock); | ||
| 907 | |||
| 908 | rdma_destroy_qp(old); | ||
| 909 | rdma_destroy_id(old); | ||
| 911 | } else { | 910 | } else { |
| 912 | dprintk("RPC: %s: connecting...\n", __func__); | 911 | dprintk("RPC: %s: connecting...\n", __func__); |
| 913 | rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr); | 912 | rc = rdma_create_qp(ia->ri_id, ia->ri_pd, &ep->rep_attr); |
| @@ -974,13 +973,12 @@ out: | |||
| 974 | * This call is not reentrant, and must not be made in parallel | 973 | * This call is not reentrant, and must not be made in parallel |
| 975 | * on the same endpoint. | 974 | * on the same endpoint. |
| 976 | */ | 975 | */ |
| 977 | int | 976 | void |
| 978 | rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | 977 | rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) |
| 979 | { | 978 | { |
| 980 | int rc; | 979 | int rc; |
| 981 | 980 | ||
| 982 | rpcrdma_clean_cq(ep->rep_attr.recv_cq); | 981 | rpcrdma_flush_cqs(ep); |
| 983 | rpcrdma_clean_cq(ep->rep_attr.send_cq); | ||
| 984 | rc = rdma_disconnect(ia->ri_id); | 982 | rc = rdma_disconnect(ia->ri_id); |
| 985 | if (!rc) { | 983 | if (!rc) { |
| 986 | /* returns without wait if not connected */ | 984 | /* returns without wait if not connected */ |
| @@ -992,12 +990,93 @@ rpcrdma_ep_disconnect(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia) | |||
| 992 | dprintk("RPC: %s: rdma_disconnect %i\n", __func__, rc); | 990 | dprintk("RPC: %s: rdma_disconnect %i\n", __func__, rc); |
| 993 | ep->rep_connected = rc; | 991 | ep->rep_connected = rc; |
| 994 | } | 992 | } |
| 993 | } | ||
| 994 | |||
| 995 | static int | ||
| 996 | rpcrdma_init_fmrs(struct rpcrdma_ia *ia, struct rpcrdma_buffer *buf) | ||
| 997 | { | ||
| 998 | int mr_access_flags = IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ; | ||
| 999 | struct ib_fmr_attr fmr_attr = { | ||
| 1000 | .max_pages = RPCRDMA_MAX_DATA_SEGS, | ||
| 1001 | .max_maps = 1, | ||
| 1002 | .page_shift = PAGE_SHIFT | ||
| 1003 | }; | ||
| 1004 | struct rpcrdma_mw *r; | ||
| 1005 | int i, rc; | ||
| 1006 | |||
| 1007 | i = (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS; | ||
| 1008 | dprintk("RPC: %s: initalizing %d FMRs\n", __func__, i); | ||
| 1009 | |||
| 1010 | while (i--) { | ||
| 1011 | r = kzalloc(sizeof(*r), GFP_KERNEL); | ||
| 1012 | if (r == NULL) | ||
| 1013 | return -ENOMEM; | ||
| 1014 | |||
| 1015 | r->r.fmr = ib_alloc_fmr(ia->ri_pd, mr_access_flags, &fmr_attr); | ||
| 1016 | if (IS_ERR(r->r.fmr)) { | ||
| 1017 | rc = PTR_ERR(r->r.fmr); | ||
| 1018 | dprintk("RPC: %s: ib_alloc_fmr failed %i\n", | ||
| 1019 | __func__, rc); | ||
| 1020 | goto out_free; | ||
| 1021 | } | ||
| 1022 | |||
| 1023 | list_add(&r->mw_list, &buf->rb_mws); | ||
| 1024 | list_add(&r->mw_all, &buf->rb_all); | ||
| 1025 | } | ||
| 1026 | return 0; | ||
| 1027 | |||
| 1028 | out_free: | ||
| 1029 | kfree(r); | ||
| 1030 | return rc; | ||
| 1031 | } | ||
| 1032 | |||
| 1033 | static int | ||
| 1034 | rpcrdma_init_frmrs(struct rpcrdma_ia *ia, struct rpcrdma_buffer *buf) | ||
| 1035 | { | ||
| 1036 | struct rpcrdma_frmr *f; | ||
| 1037 | struct rpcrdma_mw *r; | ||
| 1038 | int i, rc; | ||
| 1039 | |||
| 1040 | i = (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS; | ||
| 1041 | dprintk("RPC: %s: initalizing %d FRMRs\n", __func__, i); | ||
| 1042 | |||
| 1043 | while (i--) { | ||
| 1044 | r = kzalloc(sizeof(*r), GFP_KERNEL); | ||
| 1045 | if (r == NULL) | ||
| 1046 | return -ENOMEM; | ||
| 1047 | f = &r->r.frmr; | ||
| 1048 | |||
| 1049 | f->fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd, | ||
| 1050 | ia->ri_max_frmr_depth); | ||
| 1051 | if (IS_ERR(f->fr_mr)) { | ||
| 1052 | rc = PTR_ERR(f->fr_mr); | ||
| 1053 | dprintk("RPC: %s: ib_alloc_fast_reg_mr " | ||
| 1054 | "failed %i\n", __func__, rc); | ||
| 1055 | goto out_free; | ||
| 1056 | } | ||
| 1057 | |||
| 1058 | f->fr_pgl = ib_alloc_fast_reg_page_list(ia->ri_id->device, | ||
| 1059 | ia->ri_max_frmr_depth); | ||
| 1060 | if (IS_ERR(f->fr_pgl)) { | ||
| 1061 | rc = PTR_ERR(f->fr_pgl); | ||
| 1062 | dprintk("RPC: %s: ib_alloc_fast_reg_page_list " | ||
| 1063 | "failed %i\n", __func__, rc); | ||
| 1064 | |||
| 1065 | ib_dereg_mr(f->fr_mr); | ||
| 1066 | goto out_free; | ||
| 1067 | } | ||
| 1068 | |||
| 1069 | list_add(&r->mw_list, &buf->rb_mws); | ||
| 1070 | list_add(&r->mw_all, &buf->rb_all); | ||
| 1071 | } | ||
| 1072 | |||
| 1073 | return 0; | ||
| 1074 | |||
| 1075 | out_free: | ||
| 1076 | kfree(r); | ||
| 995 | return rc; | 1077 | return rc; |
| 996 | } | 1078 | } |
| 997 | 1079 | ||
| 998 | /* | ||
| 999 | * Initialize buffer memory | ||
| 1000 | */ | ||
| 1001 | int | 1080 | int |
| 1002 | rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep, | 1081 | rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep, |
| 1003 | struct rpcrdma_ia *ia, struct rpcrdma_create_data_internal *cdata) | 1082 | struct rpcrdma_ia *ia, struct rpcrdma_create_data_internal *cdata) |
| @@ -1005,7 +1084,6 @@ rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep, | |||
| 1005 | char *p; | 1084 | char *p; |
| 1006 | size_t len, rlen, wlen; | 1085 | size_t len, rlen, wlen; |
| 1007 | int i, rc; | 1086 | int i, rc; |
| 1008 | struct rpcrdma_mw *r; | ||
| 1009 | 1087 | ||
| 1010 | buf->rb_max_requests = cdata->max_requests; | 1088 | buf->rb_max_requests = cdata->max_requests; |
| 1011 | spin_lock_init(&buf->rb_lock); | 1089 | spin_lock_init(&buf->rb_lock); |
| @@ -1016,28 +1094,12 @@ rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep, | |||
| 1016 | * 2. arrays of struct rpcrdma_req to fill in pointers | 1094 | * 2. arrays of struct rpcrdma_req to fill in pointers |
| 1017 | * 3. array of struct rpcrdma_rep for replies | 1095 | * 3. array of struct rpcrdma_rep for replies |
| 1018 | * 4. padding, if any | 1096 | * 4. padding, if any |
| 1019 | * 5. mw's, fmr's or frmr's, if any | ||
| 1020 | * Send/recv buffers in req/rep need to be registered | 1097 | * Send/recv buffers in req/rep need to be registered |
| 1021 | */ | 1098 | */ |
| 1022 | |||
| 1023 | len = buf->rb_max_requests * | 1099 | len = buf->rb_max_requests * |
| 1024 | (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *)); | 1100 | (sizeof(struct rpcrdma_req *) + sizeof(struct rpcrdma_rep *)); |
| 1025 | len += cdata->padding; | 1101 | len += cdata->padding; |
| 1026 | switch (ia->ri_memreg_strategy) { | ||
| 1027 | case RPCRDMA_FRMR: | ||
| 1028 | len += buf->rb_max_requests * RPCRDMA_MAX_SEGS * | ||
| 1029 | sizeof(struct rpcrdma_mw); | ||
| 1030 | break; | ||
| 1031 | case RPCRDMA_MTHCAFMR: | ||
| 1032 | /* TBD we are perhaps overallocating here */ | ||
| 1033 | len += (buf->rb_max_requests + 1) * RPCRDMA_MAX_SEGS * | ||
| 1034 | sizeof(struct rpcrdma_mw); | ||
| 1035 | break; | ||
| 1036 | default: | ||
| 1037 | break; | ||
| 1038 | } | ||
| 1039 | 1102 | ||
| 1040 | /* allocate 1, 4 and 5 in one shot */ | ||
| 1041 | p = kzalloc(len, GFP_KERNEL); | 1103 | p = kzalloc(len, GFP_KERNEL); |
| 1042 | if (p == NULL) { | 1104 | if (p == NULL) { |
| 1043 | dprintk("RPC: %s: req_t/rep_t/pad kzalloc(%zd) failed\n", | 1105 | dprintk("RPC: %s: req_t/rep_t/pad kzalloc(%zd) failed\n", |
| @@ -1064,51 +1126,17 @@ rpcrdma_buffer_create(struct rpcrdma_buffer *buf, struct rpcrdma_ep *ep, | |||
| 1064 | p += cdata->padding; | 1126 | p += cdata->padding; |
| 1065 | 1127 | ||
| 1066 | INIT_LIST_HEAD(&buf->rb_mws); | 1128 | INIT_LIST_HEAD(&buf->rb_mws); |
| 1067 | r = (struct rpcrdma_mw *)p; | 1129 | INIT_LIST_HEAD(&buf->rb_all); |
| 1068 | switch (ia->ri_memreg_strategy) { | 1130 | switch (ia->ri_memreg_strategy) { |
| 1069 | case RPCRDMA_FRMR: | 1131 | case RPCRDMA_FRMR: |
| 1070 | for (i = buf->rb_max_requests * RPCRDMA_MAX_SEGS; i; i--) { | 1132 | rc = rpcrdma_init_frmrs(ia, buf); |
| 1071 | r->r.frmr.fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd, | 1133 | if (rc) |
| 1072 | ia->ri_max_frmr_depth); | 1134 | goto out; |
| 1073 | if (IS_ERR(r->r.frmr.fr_mr)) { | ||
| 1074 | rc = PTR_ERR(r->r.frmr.fr_mr); | ||
| 1075 | dprintk("RPC: %s: ib_alloc_fast_reg_mr" | ||
| 1076 | " failed %i\n", __func__, rc); | ||
| 1077 | goto out; | ||
| 1078 | } | ||
| 1079 | r->r.frmr.fr_pgl = ib_alloc_fast_reg_page_list( | ||
| 1080 | ia->ri_id->device, | ||
| 1081 | ia->ri_max_frmr_depth); | ||
| 1082 | if (IS_ERR(r->r.frmr.fr_pgl)) { | ||
| 1083 | rc = PTR_ERR(r->r.frmr.fr_pgl); | ||
| 1084 | dprintk("RPC: %s: " | ||
| 1085 | "ib_alloc_fast_reg_page_list " | ||
| 1086 | "failed %i\n", __func__, rc); | ||
| 1087 | |||
| 1088 | ib_dereg_mr(r->r.frmr.fr_mr); | ||
| 1089 | goto out; | ||
| 1090 | } | ||
| 1091 | list_add(&r->mw_list, &buf->rb_mws); | ||
| 1092 | ++r; | ||
| 1093 | } | ||
| 1094 | break; | 1135 | break; |
| 1095 | case RPCRDMA_MTHCAFMR: | 1136 | case RPCRDMA_MTHCAFMR: |
| 1096 | /* TBD we are perhaps overallocating here */ | 1137 | rc = rpcrdma_init_fmrs(ia, buf); |
| 1097 | for (i = (buf->rb_max_requests+1) * RPCRDMA_MAX_SEGS; i; i--) { | 1138 | if (rc) |
| 1098 | static struct ib_fmr_attr fa = | 1139 | goto out; |
| 1099 | { RPCRDMA_MAX_DATA_SEGS, 1, PAGE_SHIFT }; | ||
| 1100 | r->r.fmr = ib_alloc_fmr(ia->ri_pd, | ||
| 1101 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_REMOTE_READ, | ||
| 1102 | &fa); | ||
| 1103 | if (IS_ERR(r->r.fmr)) { | ||
| 1104 | rc = PTR_ERR(r->r.fmr); | ||
| 1105 | dprintk("RPC: %s: ib_alloc_fmr" | ||
| 1106 | " failed %i\n", __func__, rc); | ||
| 1107 | goto out; | ||
| 1108 | } | ||
| 1109 | list_add(&r->mw_list, &buf->rb_mws); | ||
| 1110 | ++r; | ||
| 1111 | } | ||
| 1112 | break; | 1140 | break; |
| 1113 | default: | 1141 | default: |
| 1114 | break; | 1142 | break; |
| @@ -1176,24 +1204,57 @@ out: | |||
| 1176 | return rc; | 1204 | return rc; |
| 1177 | } | 1205 | } |
| 1178 | 1206 | ||
| 1179 | /* | 1207 | static void |
| 1180 | * Unregister and destroy buffer memory. Need to deal with | 1208 | rpcrdma_destroy_fmrs(struct rpcrdma_buffer *buf) |
| 1181 | * partial initialization, so it's callable from failed create. | 1209 | { |
| 1182 | * Must be called before destroying endpoint, as registrations | 1210 | struct rpcrdma_mw *r; |
| 1183 | * reference it. | 1211 | int rc; |
| 1184 | */ | 1212 | |
| 1213 | while (!list_empty(&buf->rb_all)) { | ||
| 1214 | r = list_entry(buf->rb_all.next, struct rpcrdma_mw, mw_all); | ||
| 1215 | list_del(&r->mw_all); | ||
| 1216 | list_del(&r->mw_list); | ||
| 1217 | |||
| 1218 | rc = ib_dealloc_fmr(r->r.fmr); | ||
| 1219 | if (rc) | ||
| 1220 | dprintk("RPC: %s: ib_dealloc_fmr failed %i\n", | ||
| 1221 | __func__, rc); | ||
| 1222 | |||
| 1223 | kfree(r); | ||
| 1224 | } | ||
| 1225 | } | ||
| 1226 | |||
| 1227 | static void | ||
| 1228 | rpcrdma_destroy_frmrs(struct rpcrdma_buffer *buf) | ||
| 1229 | { | ||
| 1230 | struct rpcrdma_mw *r; | ||
| 1231 | int rc; | ||
| 1232 | |||
| 1233 | while (!list_empty(&buf->rb_all)) { | ||
| 1234 | r = list_entry(buf->rb_all.next, struct rpcrdma_mw, mw_all); | ||
| 1235 | list_del(&r->mw_all); | ||
| 1236 | list_del(&r->mw_list); | ||
| 1237 | |||
| 1238 | rc = ib_dereg_mr(r->r.frmr.fr_mr); | ||
| 1239 | if (rc) | ||
| 1240 | dprintk("RPC: %s: ib_dereg_mr failed %i\n", | ||
| 1241 | __func__, rc); | ||
| 1242 | ib_free_fast_reg_page_list(r->r.frmr.fr_pgl); | ||
| 1243 | |||
| 1244 | kfree(r); | ||
| 1245 | } | ||
| 1246 | } | ||
| 1247 | |||
| 1185 | void | 1248 | void |
| 1186 | rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) | 1249 | rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) |
| 1187 | { | 1250 | { |
| 1188 | int rc, i; | ||
| 1189 | struct rpcrdma_ia *ia = rdmab_to_ia(buf); | 1251 | struct rpcrdma_ia *ia = rdmab_to_ia(buf); |
| 1190 | struct rpcrdma_mw *r; | 1252 | int i; |
| 1191 | 1253 | ||
| 1192 | /* clean up in reverse order from create | 1254 | /* clean up in reverse order from create |
| 1193 | * 1. recv mr memory (mr free, then kfree) | 1255 | * 1. recv mr memory (mr free, then kfree) |
| 1194 | * 2. send mr memory (mr free, then kfree) | 1256 | * 2. send mr memory (mr free, then kfree) |
| 1195 | * 3. padding (if any) [moved to rpcrdma_ep_destroy] | 1257 | * 3. MWs |
| 1196 | * 4. arrays | ||
| 1197 | */ | 1258 | */ |
| 1198 | dprintk("RPC: %s: entering\n", __func__); | 1259 | dprintk("RPC: %s: entering\n", __func__); |
| 1199 | 1260 | ||
| @@ -1212,34 +1273,217 @@ rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) | |||
| 1212 | } | 1273 | } |
| 1213 | } | 1274 | } |
| 1214 | 1275 | ||
| 1276 | switch (ia->ri_memreg_strategy) { | ||
| 1277 | case RPCRDMA_FRMR: | ||
| 1278 | rpcrdma_destroy_frmrs(buf); | ||
| 1279 | break; | ||
| 1280 | case RPCRDMA_MTHCAFMR: | ||
| 1281 | rpcrdma_destroy_fmrs(buf); | ||
| 1282 | break; | ||
| 1283 | default: | ||
| 1284 | break; | ||
| 1285 | } | ||
| 1286 | |||
| 1287 | kfree(buf->rb_pool); | ||
| 1288 | } | ||
| 1289 | |||
| 1290 | /* After a disconnect, a flushed FAST_REG_MR can leave an FRMR in | ||
| 1291 | * an unusable state. Find FRMRs in this state and dereg / reg | ||
| 1292 | * each. FRMRs that are VALID and attached to an rpcrdma_req are | ||
| 1293 | * also torn down. | ||
| 1294 | * | ||
| 1295 | * This gives all in-use FRMRs a fresh rkey and leaves them INVALID. | ||
| 1296 | * | ||
| 1297 | * This is invoked only in the transport connect worker in order | ||
| 1298 | * to serialize with rpcrdma_register_frmr_external(). | ||
| 1299 | */ | ||
| 1300 | static void | ||
| 1301 | rpcrdma_reset_frmrs(struct rpcrdma_ia *ia) | ||
| 1302 | { | ||
| 1303 | struct rpcrdma_xprt *r_xprt = | ||
| 1304 | container_of(ia, struct rpcrdma_xprt, rx_ia); | ||
| 1305 | struct rpcrdma_buffer *buf = &r_xprt->rx_buf; | ||
| 1306 | struct list_head *pos; | ||
| 1307 | struct rpcrdma_mw *r; | ||
| 1308 | int rc; | ||
| 1309 | |||
| 1310 | list_for_each(pos, &buf->rb_all) { | ||
| 1311 | r = list_entry(pos, struct rpcrdma_mw, mw_all); | ||
| 1312 | |||
| 1313 | if (r->r.frmr.fr_state == FRMR_IS_INVALID) | ||
| 1314 | continue; | ||
| 1315 | |||
| 1316 | rc = ib_dereg_mr(r->r.frmr.fr_mr); | ||
| 1317 | if (rc) | ||
| 1318 | dprintk("RPC: %s: ib_dereg_mr failed %i\n", | ||
| 1319 | __func__, rc); | ||
| 1320 | ib_free_fast_reg_page_list(r->r.frmr.fr_pgl); | ||
| 1321 | |||
| 1322 | r->r.frmr.fr_mr = ib_alloc_fast_reg_mr(ia->ri_pd, | ||
| 1323 | ia->ri_max_frmr_depth); | ||
| 1324 | if (IS_ERR(r->r.frmr.fr_mr)) { | ||
| 1325 | rc = PTR_ERR(r->r.frmr.fr_mr); | ||
| 1326 | dprintk("RPC: %s: ib_alloc_fast_reg_mr" | ||
| 1327 | " failed %i\n", __func__, rc); | ||
| 1328 | continue; | ||
| 1329 | } | ||
| 1330 | r->r.frmr.fr_pgl = ib_alloc_fast_reg_page_list( | ||
| 1331 | ia->ri_id->device, | ||
| 1332 | ia->ri_max_frmr_depth); | ||
| 1333 | if (IS_ERR(r->r.frmr.fr_pgl)) { | ||
| 1334 | rc = PTR_ERR(r->r.frmr.fr_pgl); | ||
| 1335 | dprintk("RPC: %s: " | ||
| 1336 | "ib_alloc_fast_reg_page_list " | ||
| 1337 | "failed %i\n", __func__, rc); | ||
| 1338 | |||
| 1339 | ib_dereg_mr(r->r.frmr.fr_mr); | ||
| 1340 | continue; | ||
| 1341 | } | ||
| 1342 | r->r.frmr.fr_state = FRMR_IS_INVALID; | ||
| 1343 | } | ||
| 1344 | } | ||
| 1345 | |||
| 1346 | /* "*mw" can be NULL when rpcrdma_buffer_get_mrs() fails, leaving | ||
| 1347 | * some req segments uninitialized. | ||
| 1348 | */ | ||
| 1349 | static void | ||
| 1350 | rpcrdma_buffer_put_mr(struct rpcrdma_mw **mw, struct rpcrdma_buffer *buf) | ||
| 1351 | { | ||
| 1352 | if (*mw) { | ||
| 1353 | list_add_tail(&(*mw)->mw_list, &buf->rb_mws); | ||
| 1354 | *mw = NULL; | ||
| 1355 | } | ||
| 1356 | } | ||
| 1357 | |||
| 1358 | /* Cycle mw's back in reverse order, and "spin" them. | ||
| 1359 | * This delays and scrambles reuse as much as possible. | ||
| 1360 | */ | ||
| 1361 | static void | ||
| 1362 | rpcrdma_buffer_put_mrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf) | ||
| 1363 | { | ||
| 1364 | struct rpcrdma_mr_seg *seg = req->rl_segments; | ||
| 1365 | struct rpcrdma_mr_seg *seg1 = seg; | ||
| 1366 | int i; | ||
| 1367 | |||
| 1368 | for (i = 1, seg++; i < RPCRDMA_MAX_SEGS; seg++, i++) | ||
| 1369 | rpcrdma_buffer_put_mr(&seg->mr_chunk.rl_mw, buf); | ||
| 1370 | rpcrdma_buffer_put_mr(&seg1->mr_chunk.rl_mw, buf); | ||
| 1371 | } | ||
| 1372 | |||
| 1373 | static void | ||
| 1374 | rpcrdma_buffer_put_sendbuf(struct rpcrdma_req *req, struct rpcrdma_buffer *buf) | ||
| 1375 | { | ||
| 1376 | buf->rb_send_bufs[--buf->rb_send_index] = req; | ||
| 1377 | req->rl_niovs = 0; | ||
| 1378 | if (req->rl_reply) { | ||
| 1379 | buf->rb_recv_bufs[--buf->rb_recv_index] = req->rl_reply; | ||
| 1380 | req->rl_reply->rr_func = NULL; | ||
| 1381 | req->rl_reply = NULL; | ||
| 1382 | } | ||
| 1383 | } | ||
| 1384 | |||
| 1385 | /* rpcrdma_unmap_one() was already done by rpcrdma_deregister_frmr_external(). | ||
| 1386 | * Redo only the ib_post_send(). | ||
| 1387 | */ | ||
| 1388 | static void | ||
| 1389 | rpcrdma_retry_local_inv(struct rpcrdma_mw *r, struct rpcrdma_ia *ia) | ||
| 1390 | { | ||
| 1391 | struct rpcrdma_xprt *r_xprt = | ||
| 1392 | container_of(ia, struct rpcrdma_xprt, rx_ia); | ||
| 1393 | struct ib_send_wr invalidate_wr, *bad_wr; | ||
| 1394 | int rc; | ||
| 1395 | |||
| 1396 | dprintk("RPC: %s: FRMR %p is stale\n", __func__, r); | ||
| 1397 | |||
| 1398 | /* When this FRMR is re-inserted into rb_mws, it is no longer stale */ | ||
| 1399 | r->r.frmr.fr_state = FRMR_IS_INVALID; | ||
| 1400 | |||
| 1401 | memset(&invalidate_wr, 0, sizeof(invalidate_wr)); | ||
| 1402 | invalidate_wr.wr_id = (unsigned long)(void *)r; | ||
| 1403 | invalidate_wr.opcode = IB_WR_LOCAL_INV; | ||
| 1404 | invalidate_wr.ex.invalidate_rkey = r->r.frmr.fr_mr->rkey; | ||
| 1405 | DECR_CQCOUNT(&r_xprt->rx_ep); | ||
| 1406 | |||
| 1407 | dprintk("RPC: %s: frmr %p invalidating rkey %08x\n", | ||
| 1408 | __func__, r, r->r.frmr.fr_mr->rkey); | ||
| 1409 | |||
| 1410 | read_lock(&ia->ri_qplock); | ||
| 1411 | rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr); | ||
| 1412 | read_unlock(&ia->ri_qplock); | ||
| 1413 | if (rc) { | ||
| 1414 | /* Force rpcrdma_buffer_get() to retry */ | ||
| 1415 | r->r.frmr.fr_state = FRMR_IS_STALE; | ||
| 1416 | dprintk("RPC: %s: ib_post_send failed, %i\n", | ||
| 1417 | __func__, rc); | ||
| 1418 | } | ||
| 1419 | } | ||
| 1420 | |||
| 1421 | static void | ||
| 1422 | rpcrdma_retry_flushed_linv(struct list_head *stale, | ||
| 1423 | struct rpcrdma_buffer *buf) | ||
| 1424 | { | ||
| 1425 | struct rpcrdma_ia *ia = rdmab_to_ia(buf); | ||
| 1426 | struct list_head *pos; | ||
| 1427 | struct rpcrdma_mw *r; | ||
| 1428 | unsigned long flags; | ||
| 1429 | |||
| 1430 | list_for_each(pos, stale) { | ||
| 1431 | r = list_entry(pos, struct rpcrdma_mw, mw_list); | ||
| 1432 | rpcrdma_retry_local_inv(r, ia); | ||
| 1433 | } | ||
| 1434 | |||
| 1435 | spin_lock_irqsave(&buf->rb_lock, flags); | ||
| 1436 | list_splice_tail(stale, &buf->rb_mws); | ||
| 1437 | spin_unlock_irqrestore(&buf->rb_lock, flags); | ||
| 1438 | } | ||
| 1439 | |||
| 1440 | static struct rpcrdma_req * | ||
| 1441 | rpcrdma_buffer_get_frmrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf, | ||
| 1442 | struct list_head *stale) | ||
| 1443 | { | ||
| 1444 | struct rpcrdma_mw *r; | ||
| 1445 | int i; | ||
| 1446 | |||
| 1447 | i = RPCRDMA_MAX_SEGS - 1; | ||
| 1215 | while (!list_empty(&buf->rb_mws)) { | 1448 | while (!list_empty(&buf->rb_mws)) { |
| 1216 | r = list_entry(buf->rb_mws.next, | 1449 | r = list_entry(buf->rb_mws.next, |
| 1217 | struct rpcrdma_mw, mw_list); | 1450 | struct rpcrdma_mw, mw_list); |
| 1218 | list_del(&r->mw_list); | 1451 | list_del(&r->mw_list); |
| 1219 | switch (ia->ri_memreg_strategy) { | 1452 | if (r->r.frmr.fr_state == FRMR_IS_STALE) { |
| 1220 | case RPCRDMA_FRMR: | 1453 | list_add(&r->mw_list, stale); |
| 1221 | rc = ib_dereg_mr(r->r.frmr.fr_mr); | 1454 | continue; |
| 1222 | if (rc) | ||
| 1223 | dprintk("RPC: %s:" | ||
| 1224 | " ib_dereg_mr" | ||
| 1225 | " failed %i\n", | ||
| 1226 | __func__, rc); | ||
| 1227 | ib_free_fast_reg_page_list(r->r.frmr.fr_pgl); | ||
| 1228 | break; | ||
| 1229 | case RPCRDMA_MTHCAFMR: | ||
| 1230 | rc = ib_dealloc_fmr(r->r.fmr); | ||
| 1231 | if (rc) | ||
| 1232 | dprintk("RPC: %s:" | ||
| 1233 | " ib_dealloc_fmr" | ||
| 1234 | " failed %i\n", | ||
| 1235 | __func__, rc); | ||
| 1236 | break; | ||
| 1237 | default: | ||
| 1238 | break; | ||
| 1239 | } | 1455 | } |
| 1456 | req->rl_segments[i].mr_chunk.rl_mw = r; | ||
| 1457 | if (unlikely(i-- == 0)) | ||
| 1458 | return req; /* Success */ | ||
| 1240 | } | 1459 | } |
| 1241 | 1460 | ||
| 1242 | kfree(buf->rb_pool); | 1461 | /* Not enough entries on rb_mws for this req */ |
| 1462 | rpcrdma_buffer_put_sendbuf(req, buf); | ||
| 1463 | rpcrdma_buffer_put_mrs(req, buf); | ||
| 1464 | return NULL; | ||
| 1465 | } | ||
| 1466 | |||
| 1467 | static struct rpcrdma_req * | ||
| 1468 | rpcrdma_buffer_get_fmrs(struct rpcrdma_req *req, struct rpcrdma_buffer *buf) | ||
| 1469 | { | ||
| 1470 | struct rpcrdma_mw *r; | ||
| 1471 | int i; | ||
| 1472 | |||
| 1473 | i = RPCRDMA_MAX_SEGS - 1; | ||
| 1474 | while (!list_empty(&buf->rb_mws)) { | ||
| 1475 | r = list_entry(buf->rb_mws.next, | ||
| 1476 | struct rpcrdma_mw, mw_list); | ||
| 1477 | list_del(&r->mw_list); | ||
| 1478 | req->rl_segments[i].mr_chunk.rl_mw = r; | ||
| 1479 | if (unlikely(i-- == 0)) | ||
| 1480 | return req; /* Success */ | ||
| 1481 | } | ||
| 1482 | |||
| 1483 | /* Not enough entries on rb_mws for this req */ | ||
| 1484 | rpcrdma_buffer_put_sendbuf(req, buf); | ||
| 1485 | rpcrdma_buffer_put_mrs(req, buf); | ||
| 1486 | return NULL; | ||
| 1243 | } | 1487 | } |
| 1244 | 1488 | ||
| 1245 | /* | 1489 | /* |
| @@ -1254,10 +1498,10 @@ rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf) | |||
| 1254 | struct rpcrdma_req * | 1498 | struct rpcrdma_req * |
| 1255 | rpcrdma_buffer_get(struct rpcrdma_buffer *buffers) | 1499 | rpcrdma_buffer_get(struct rpcrdma_buffer *buffers) |
| 1256 | { | 1500 | { |
| 1501 | struct rpcrdma_ia *ia = rdmab_to_ia(buffers); | ||
| 1502 | struct list_head stale; | ||
| 1257 | struct rpcrdma_req *req; | 1503 | struct rpcrdma_req *req; |
| 1258 | unsigned long flags; | 1504 | unsigned long flags; |
| 1259 | int i; | ||
| 1260 | struct rpcrdma_mw *r; | ||
| 1261 | 1505 | ||
| 1262 | spin_lock_irqsave(&buffers->rb_lock, flags); | 1506 | spin_lock_irqsave(&buffers->rb_lock, flags); |
| 1263 | if (buffers->rb_send_index == buffers->rb_max_requests) { | 1507 | if (buffers->rb_send_index == buffers->rb_max_requests) { |
| @@ -1277,16 +1521,21 @@ rpcrdma_buffer_get(struct rpcrdma_buffer *buffers) | |||
| 1277 | buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL; | 1521 | buffers->rb_recv_bufs[buffers->rb_recv_index++] = NULL; |
| 1278 | } | 1522 | } |
| 1279 | buffers->rb_send_bufs[buffers->rb_send_index++] = NULL; | 1523 | buffers->rb_send_bufs[buffers->rb_send_index++] = NULL; |
| 1280 | if (!list_empty(&buffers->rb_mws)) { | 1524 | |
| 1281 | i = RPCRDMA_MAX_SEGS - 1; | 1525 | INIT_LIST_HEAD(&stale); |
| 1282 | do { | 1526 | switch (ia->ri_memreg_strategy) { |
| 1283 | r = list_entry(buffers->rb_mws.next, | 1527 | case RPCRDMA_FRMR: |
| 1284 | struct rpcrdma_mw, mw_list); | 1528 | req = rpcrdma_buffer_get_frmrs(req, buffers, &stale); |
| 1285 | list_del(&r->mw_list); | 1529 | break; |
| 1286 | req->rl_segments[i].mr_chunk.rl_mw = r; | 1530 | case RPCRDMA_MTHCAFMR: |
| 1287 | } while (--i >= 0); | 1531 | req = rpcrdma_buffer_get_fmrs(req, buffers); |
| 1532 | break; | ||
| 1533 | default: | ||
| 1534 | break; | ||
| 1288 | } | 1535 | } |
| 1289 | spin_unlock_irqrestore(&buffers->rb_lock, flags); | 1536 | spin_unlock_irqrestore(&buffers->rb_lock, flags); |
| 1537 | if (!list_empty(&stale)) | ||
| 1538 | rpcrdma_retry_flushed_linv(&stale, buffers); | ||
| 1290 | return req; | 1539 | return req; |
| 1291 | } | 1540 | } |
| 1292 | 1541 | ||
| @@ -1299,34 +1548,14 @@ rpcrdma_buffer_put(struct rpcrdma_req *req) | |||
| 1299 | { | 1548 | { |
| 1300 | struct rpcrdma_buffer *buffers = req->rl_buffer; | 1549 | struct rpcrdma_buffer *buffers = req->rl_buffer; |
| 1301 | struct rpcrdma_ia *ia = rdmab_to_ia(buffers); | 1550 | struct rpcrdma_ia *ia = rdmab_to_ia(buffers); |
| 1302 | int i; | ||
| 1303 | unsigned long flags; | 1551 | unsigned long flags; |
| 1304 | 1552 | ||
| 1305 | spin_lock_irqsave(&buffers->rb_lock, flags); | 1553 | spin_lock_irqsave(&buffers->rb_lock, flags); |
| 1306 | buffers->rb_send_bufs[--buffers->rb_send_index] = req; | 1554 | rpcrdma_buffer_put_sendbuf(req, buffers); |
| 1307 | req->rl_niovs = 0; | ||
| 1308 | if (req->rl_reply) { | ||
| 1309 | buffers->rb_recv_bufs[--buffers->rb_recv_index] = req->rl_reply; | ||
| 1310 | req->rl_reply->rr_func = NULL; | ||
| 1311 | req->rl_reply = NULL; | ||
| 1312 | } | ||
| 1313 | switch (ia->ri_memreg_strategy) { | 1555 | switch (ia->ri_memreg_strategy) { |
| 1314 | case RPCRDMA_FRMR: | 1556 | case RPCRDMA_FRMR: |
| 1315 | case RPCRDMA_MTHCAFMR: | 1557 | case RPCRDMA_MTHCAFMR: |
| 1316 | /* | 1558 | rpcrdma_buffer_put_mrs(req, buffers); |
| 1317 | * Cycle mw's back in reverse order, and "spin" them. | ||
| 1318 | * This delays and scrambles reuse as much as possible. | ||
| 1319 | */ | ||
| 1320 | i = 1; | ||
| 1321 | do { | ||
| 1322 | struct rpcrdma_mw **mw; | ||
| 1323 | mw = &req->rl_segments[i].mr_chunk.rl_mw; | ||
| 1324 | list_add_tail(&(*mw)->mw_list, &buffers->rb_mws); | ||
| 1325 | *mw = NULL; | ||
| 1326 | } while (++i < RPCRDMA_MAX_SEGS); | ||
| 1327 | list_add_tail(&req->rl_segments[0].mr_chunk.rl_mw->mw_list, | ||
| 1328 | &buffers->rb_mws); | ||
| 1329 | req->rl_segments[0].mr_chunk.rl_mw = NULL; | ||
| 1330 | break; | 1559 | break; |
| 1331 | default: | 1560 | default: |
| 1332 | break; | 1561 | break; |
| @@ -1388,6 +1617,9 @@ rpcrdma_register_internal(struct rpcrdma_ia *ia, void *va, int len, | |||
| 1388 | */ | 1617 | */ |
| 1389 | iov->addr = ib_dma_map_single(ia->ri_id->device, | 1618 | iov->addr = ib_dma_map_single(ia->ri_id->device, |
| 1390 | va, len, DMA_BIDIRECTIONAL); | 1619 | va, len, DMA_BIDIRECTIONAL); |
| 1620 | if (ib_dma_mapping_error(ia->ri_id->device, iov->addr)) | ||
| 1621 | return -ENOMEM; | ||
| 1622 | |||
| 1391 | iov->length = len; | 1623 | iov->length = len; |
| 1392 | 1624 | ||
| 1393 | if (ia->ri_have_dma_lkey) { | 1625 | if (ia->ri_have_dma_lkey) { |
| @@ -1483,8 +1715,10 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1483 | struct rpcrdma_xprt *r_xprt) | 1715 | struct rpcrdma_xprt *r_xprt) |
| 1484 | { | 1716 | { |
| 1485 | struct rpcrdma_mr_seg *seg1 = seg; | 1717 | struct rpcrdma_mr_seg *seg1 = seg; |
| 1486 | struct ib_send_wr invalidate_wr, frmr_wr, *bad_wr, *post_wr; | 1718 | struct rpcrdma_mw *mw = seg1->mr_chunk.rl_mw; |
| 1487 | 1719 | struct rpcrdma_frmr *frmr = &mw->r.frmr; | |
| 1720 | struct ib_mr *mr = frmr->fr_mr; | ||
| 1721 | struct ib_send_wr fastreg_wr, *bad_wr; | ||
| 1488 | u8 key; | 1722 | u8 key; |
| 1489 | int len, pageoff; | 1723 | int len, pageoff; |
| 1490 | int i, rc; | 1724 | int i, rc; |
| @@ -1502,8 +1736,7 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1502 | rpcrdma_map_one(ia, seg, writing); | 1736 | rpcrdma_map_one(ia, seg, writing); |
| 1503 | pa = seg->mr_dma; | 1737 | pa = seg->mr_dma; |
| 1504 | for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) { | 1738 | for (seg_len = seg->mr_len; seg_len > 0; seg_len -= PAGE_SIZE) { |
| 1505 | seg1->mr_chunk.rl_mw->r.frmr.fr_pgl-> | 1739 | frmr->fr_pgl->page_list[page_no++] = pa; |
| 1506 | page_list[page_no++] = pa; | ||
| 1507 | pa += PAGE_SIZE; | 1740 | pa += PAGE_SIZE; |
| 1508 | } | 1741 | } |
| 1509 | len += seg->mr_len; | 1742 | len += seg->mr_len; |
| @@ -1515,65 +1748,51 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1515 | break; | 1748 | break; |
| 1516 | } | 1749 | } |
| 1517 | dprintk("RPC: %s: Using frmr %p to map %d segments\n", | 1750 | dprintk("RPC: %s: Using frmr %p to map %d segments\n", |
| 1518 | __func__, seg1->mr_chunk.rl_mw, i); | 1751 | __func__, mw, i); |
| 1519 | 1752 | ||
| 1520 | if (unlikely(seg1->mr_chunk.rl_mw->r.frmr.state == FRMR_IS_VALID)) { | 1753 | frmr->fr_state = FRMR_IS_VALID; |
| 1521 | dprintk("RPC: %s: frmr %x left valid, posting invalidate.\n", | 1754 | |
| 1522 | __func__, | 1755 | memset(&fastreg_wr, 0, sizeof(fastreg_wr)); |
| 1523 | seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey); | 1756 | fastreg_wr.wr_id = (unsigned long)(void *)mw; |
| 1524 | /* Invalidate before using. */ | 1757 | fastreg_wr.opcode = IB_WR_FAST_REG_MR; |
| 1525 | memset(&invalidate_wr, 0, sizeof invalidate_wr); | 1758 | fastreg_wr.wr.fast_reg.iova_start = seg1->mr_dma; |
| 1526 | invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | 1759 | fastreg_wr.wr.fast_reg.page_list = frmr->fr_pgl; |
| 1527 | invalidate_wr.next = &frmr_wr; | 1760 | fastreg_wr.wr.fast_reg.page_list_len = page_no; |
| 1528 | invalidate_wr.opcode = IB_WR_LOCAL_INV; | 1761 | fastreg_wr.wr.fast_reg.page_shift = PAGE_SHIFT; |
| 1529 | invalidate_wr.send_flags = IB_SEND_SIGNALED; | 1762 | fastreg_wr.wr.fast_reg.length = page_no << PAGE_SHIFT; |
| 1530 | invalidate_wr.ex.invalidate_rkey = | 1763 | if (fastreg_wr.wr.fast_reg.length < len) { |
| 1531 | seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1764 | rc = -EIO; |
| 1532 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1765 | goto out_err; |
| 1533 | post_wr = &invalidate_wr; | ||
| 1534 | } else | ||
| 1535 | post_wr = &frmr_wr; | ||
| 1536 | |||
| 1537 | /* Prepare FRMR WR */ | ||
| 1538 | memset(&frmr_wr, 0, sizeof frmr_wr); | ||
| 1539 | frmr_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | ||
| 1540 | frmr_wr.opcode = IB_WR_FAST_REG_MR; | ||
| 1541 | frmr_wr.send_flags = IB_SEND_SIGNALED; | ||
| 1542 | frmr_wr.wr.fast_reg.iova_start = seg1->mr_dma; | ||
| 1543 | frmr_wr.wr.fast_reg.page_list = seg1->mr_chunk.rl_mw->r.frmr.fr_pgl; | ||
| 1544 | frmr_wr.wr.fast_reg.page_list_len = page_no; | ||
| 1545 | frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; | ||
| 1546 | frmr_wr.wr.fast_reg.length = page_no << PAGE_SHIFT; | ||
| 1547 | if (frmr_wr.wr.fast_reg.length < len) { | ||
| 1548 | while (seg1->mr_nsegs--) | ||
| 1549 | rpcrdma_unmap_one(ia, seg++); | ||
| 1550 | return -EIO; | ||
| 1551 | } | 1766 | } |
| 1552 | 1767 | ||
| 1553 | /* Bump the key */ | 1768 | /* Bump the key */ |
| 1554 | key = (u8)(seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey & 0x000000FF); | 1769 | key = (u8)(mr->rkey & 0x000000FF); |
| 1555 | ib_update_fast_reg_key(seg1->mr_chunk.rl_mw->r.frmr.fr_mr, ++key); | 1770 | ib_update_fast_reg_key(mr, ++key); |
| 1556 | 1771 | ||
| 1557 | frmr_wr.wr.fast_reg.access_flags = (writing ? | 1772 | fastreg_wr.wr.fast_reg.access_flags = (writing ? |
| 1558 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : | 1773 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : |
| 1559 | IB_ACCESS_REMOTE_READ); | 1774 | IB_ACCESS_REMOTE_READ); |
| 1560 | frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1775 | fastreg_wr.wr.fast_reg.rkey = mr->rkey; |
| 1561 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1776 | DECR_CQCOUNT(&r_xprt->rx_ep); |
| 1562 | 1777 | ||
| 1563 | rc = ib_post_send(ia->ri_id->qp, post_wr, &bad_wr); | 1778 | rc = ib_post_send(ia->ri_id->qp, &fastreg_wr, &bad_wr); |
| 1564 | |||
| 1565 | if (rc) { | 1779 | if (rc) { |
| 1566 | dprintk("RPC: %s: failed ib_post_send for register," | 1780 | dprintk("RPC: %s: failed ib_post_send for register," |
| 1567 | " status %i\n", __func__, rc); | 1781 | " status %i\n", __func__, rc); |
| 1568 | while (i--) | 1782 | ib_update_fast_reg_key(mr, --key); |
| 1569 | rpcrdma_unmap_one(ia, --seg); | 1783 | goto out_err; |
| 1570 | } else { | 1784 | } else { |
| 1571 | seg1->mr_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1785 | seg1->mr_rkey = mr->rkey; |
| 1572 | seg1->mr_base = seg1->mr_dma + pageoff; | 1786 | seg1->mr_base = seg1->mr_dma + pageoff; |
| 1573 | seg1->mr_nsegs = i; | 1787 | seg1->mr_nsegs = i; |
| 1574 | seg1->mr_len = len; | 1788 | seg1->mr_len = len; |
| 1575 | } | 1789 | } |
| 1576 | *nsegs = i; | 1790 | *nsegs = i; |
| 1791 | return 0; | ||
| 1792 | out_err: | ||
| 1793 | frmr->fr_state = FRMR_IS_INVALID; | ||
| 1794 | while (i--) | ||
| 1795 | rpcrdma_unmap_one(ia, --seg); | ||
| 1577 | return rc; | 1796 | return rc; |
| 1578 | } | 1797 | } |
| 1579 | 1798 | ||
| @@ -1585,20 +1804,25 @@ rpcrdma_deregister_frmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1585 | struct ib_send_wr invalidate_wr, *bad_wr; | 1804 | struct ib_send_wr invalidate_wr, *bad_wr; |
| 1586 | int rc; | 1805 | int rc; |
| 1587 | 1806 | ||
| 1588 | while (seg1->mr_nsegs--) | 1807 | seg1->mr_chunk.rl_mw->r.frmr.fr_state = FRMR_IS_INVALID; |
| 1589 | rpcrdma_unmap_one(ia, seg++); | ||
| 1590 | 1808 | ||
| 1591 | memset(&invalidate_wr, 0, sizeof invalidate_wr); | 1809 | memset(&invalidate_wr, 0, sizeof invalidate_wr); |
| 1592 | invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; | 1810 | invalidate_wr.wr_id = (unsigned long)(void *)seg1->mr_chunk.rl_mw; |
| 1593 | invalidate_wr.opcode = IB_WR_LOCAL_INV; | 1811 | invalidate_wr.opcode = IB_WR_LOCAL_INV; |
| 1594 | invalidate_wr.send_flags = IB_SEND_SIGNALED; | ||
| 1595 | invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1812 | invalidate_wr.ex.invalidate_rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; |
| 1596 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1813 | DECR_CQCOUNT(&r_xprt->rx_ep); |
| 1597 | 1814 | ||
| 1815 | read_lock(&ia->ri_qplock); | ||
| 1816 | while (seg1->mr_nsegs--) | ||
| 1817 | rpcrdma_unmap_one(ia, seg++); | ||
| 1598 | rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr); | 1818 | rc = ib_post_send(ia->ri_id->qp, &invalidate_wr, &bad_wr); |
| 1599 | if (rc) | 1819 | read_unlock(&ia->ri_qplock); |
| 1820 | if (rc) { | ||
| 1821 | /* Force rpcrdma_buffer_get() to retry */ | ||
| 1822 | seg1->mr_chunk.rl_mw->r.frmr.fr_state = FRMR_IS_STALE; | ||
| 1600 | dprintk("RPC: %s: failed ib_post_send for invalidate," | 1823 | dprintk("RPC: %s: failed ib_post_send for invalidate," |
| 1601 | " status %i\n", __func__, rc); | 1824 | " status %i\n", __func__, rc); |
| 1825 | } | ||
| 1602 | return rc; | 1826 | return rc; |
| 1603 | } | 1827 | } |
| 1604 | 1828 | ||
| @@ -1656,8 +1880,10 @@ rpcrdma_deregister_fmr_external(struct rpcrdma_mr_seg *seg, | |||
| 1656 | 1880 | ||
| 1657 | list_add(&seg1->mr_chunk.rl_mw->r.fmr->list, &l); | 1881 | list_add(&seg1->mr_chunk.rl_mw->r.fmr->list, &l); |
| 1658 | rc = ib_unmap_fmr(&l); | 1882 | rc = ib_unmap_fmr(&l); |
| 1883 | read_lock(&ia->ri_qplock); | ||
| 1659 | while (seg1->mr_nsegs--) | 1884 | while (seg1->mr_nsegs--) |
| 1660 | rpcrdma_unmap_one(ia, seg++); | 1885 | rpcrdma_unmap_one(ia, seg++); |
| 1886 | read_unlock(&ia->ri_qplock); | ||
| 1661 | if (rc) | 1887 | if (rc) |
| 1662 | dprintk("RPC: %s: failed ib_unmap_fmr," | 1888 | dprintk("RPC: %s: failed ib_unmap_fmr," |
| 1663 | " status %i\n", __func__, rc); | 1889 | " status %i\n", __func__, rc); |
| @@ -1673,7 +1899,6 @@ rpcrdma_register_external(struct rpcrdma_mr_seg *seg, | |||
| 1673 | 1899 | ||
| 1674 | switch (ia->ri_memreg_strategy) { | 1900 | switch (ia->ri_memreg_strategy) { |
| 1675 | 1901 | ||
| 1676 | #if RPCRDMA_PERSISTENT_REGISTRATION | ||
| 1677 | case RPCRDMA_ALLPHYSICAL: | 1902 | case RPCRDMA_ALLPHYSICAL: |
| 1678 | rpcrdma_map_one(ia, seg, writing); | 1903 | rpcrdma_map_one(ia, seg, writing); |
| 1679 | seg->mr_rkey = ia->ri_bind_mem->rkey; | 1904 | seg->mr_rkey = ia->ri_bind_mem->rkey; |
| @@ -1681,7 +1906,6 @@ rpcrdma_register_external(struct rpcrdma_mr_seg *seg, | |||
| 1681 | seg->mr_nsegs = 1; | 1906 | seg->mr_nsegs = 1; |
| 1682 | nsegs = 1; | 1907 | nsegs = 1; |
| 1683 | break; | 1908 | break; |
| 1684 | #endif | ||
| 1685 | 1909 | ||
| 1686 | /* Registration using frmr registration */ | 1910 | /* Registration using frmr registration */ |
| 1687 | case RPCRDMA_FRMR: | 1911 | case RPCRDMA_FRMR: |
| @@ -1711,11 +1935,11 @@ rpcrdma_deregister_external(struct rpcrdma_mr_seg *seg, | |||
| 1711 | 1935 | ||
| 1712 | switch (ia->ri_memreg_strategy) { | 1936 | switch (ia->ri_memreg_strategy) { |
| 1713 | 1937 | ||
| 1714 | #if RPCRDMA_PERSISTENT_REGISTRATION | ||
| 1715 | case RPCRDMA_ALLPHYSICAL: | 1938 | case RPCRDMA_ALLPHYSICAL: |
| 1939 | read_lock(&ia->ri_qplock); | ||
| 1716 | rpcrdma_unmap_one(ia, seg); | 1940 | rpcrdma_unmap_one(ia, seg); |
| 1941 | read_unlock(&ia->ri_qplock); | ||
| 1717 | break; | 1942 | break; |
| 1718 | #endif | ||
| 1719 | 1943 | ||
| 1720 | case RPCRDMA_FRMR: | 1944 | case RPCRDMA_FRMR: |
| 1721 | rc = rpcrdma_deregister_frmr_external(seg, ia, r_xprt); | 1945 | rc = rpcrdma_deregister_frmr_external(seg, ia, r_xprt); |
| @@ -1809,3 +2033,44 @@ rpcrdma_ep_post_recv(struct rpcrdma_ia *ia, | |||
| 1809 | rc); | 2033 | rc); |
| 1810 | return rc; | 2034 | return rc; |
| 1811 | } | 2035 | } |
| 2036 | |||
| 2037 | /* Physical mapping means one Read/Write list entry per-page. | ||
| 2038 | * All list entries must fit within an inline buffer | ||
| 2039 | * | ||
| 2040 | * NB: The server must return a Write list for NFS READ, | ||
| 2041 | * which has the same constraint. Factor in the inline | ||
| 2042 | * rsize as well. | ||
| 2043 | */ | ||
| 2044 | static size_t | ||
| 2045 | rpcrdma_physical_max_payload(struct rpcrdma_xprt *r_xprt) | ||
| 2046 | { | ||
| 2047 | struct rpcrdma_create_data_internal *cdata = &r_xprt->rx_data; | ||
| 2048 | unsigned int inline_size, pages; | ||
| 2049 | |||
| 2050 | inline_size = min_t(unsigned int, | ||
| 2051 | cdata->inline_wsize, cdata->inline_rsize); | ||
| 2052 | inline_size -= RPCRDMA_HDRLEN_MIN; | ||
| 2053 | pages = inline_size / sizeof(struct rpcrdma_segment); | ||
| 2054 | return pages << PAGE_SHIFT; | ||
| 2055 | } | ||
| 2056 | |||
| 2057 | static size_t | ||
| 2058 | rpcrdma_mr_max_payload(struct rpcrdma_xprt *r_xprt) | ||
| 2059 | { | ||
| 2060 | return RPCRDMA_MAX_DATA_SEGS << PAGE_SHIFT; | ||
| 2061 | } | ||
| 2062 | |||
| 2063 | size_t | ||
| 2064 | rpcrdma_max_payload(struct rpcrdma_xprt *r_xprt) | ||
| 2065 | { | ||
| 2066 | size_t result; | ||
| 2067 | |||
| 2068 | switch (r_xprt->rx_ia.ri_memreg_strategy) { | ||
| 2069 | case RPCRDMA_ALLPHYSICAL: | ||
| 2070 | result = rpcrdma_physical_max_payload(r_xprt); | ||
| 2071 | break; | ||
| 2072 | default: | ||
| 2073 | result = rpcrdma_mr_max_payload(r_xprt); | ||
| 2074 | } | ||
| 2075 | return result; | ||
| 2076 | } | ||
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h index 89e7cd479705..c419498b8f46 100644 --- a/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/net/sunrpc/xprtrdma/xprt_rdma.h | |||
| @@ -59,6 +59,7 @@ | |||
| 59 | * Interface Adapter -- one per transport instance | 59 | * Interface Adapter -- one per transport instance |
| 60 | */ | 60 | */ |
| 61 | struct rpcrdma_ia { | 61 | struct rpcrdma_ia { |
| 62 | rwlock_t ri_qplock; | ||
| 62 | struct rdma_cm_id *ri_id; | 63 | struct rdma_cm_id *ri_id; |
| 63 | struct ib_pd *ri_pd; | 64 | struct ib_pd *ri_pd; |
| 64 | struct ib_mr *ri_bind_mem; | 65 | struct ib_mr *ri_bind_mem; |
| @@ -98,6 +99,14 @@ struct rpcrdma_ep { | |||
| 98 | #define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit) | 99 | #define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit) |
| 99 | #define DECR_CQCOUNT(ep) atomic_sub_return(1, &(ep)->rep_cqcount) | 100 | #define DECR_CQCOUNT(ep) atomic_sub_return(1, &(ep)->rep_cqcount) |
| 100 | 101 | ||
| 102 | enum rpcrdma_chunktype { | ||
| 103 | rpcrdma_noch = 0, | ||
| 104 | rpcrdma_readch, | ||
| 105 | rpcrdma_areadch, | ||
| 106 | rpcrdma_writech, | ||
| 107 | rpcrdma_replych | ||
| 108 | }; | ||
| 109 | |||
| 101 | /* | 110 | /* |
| 102 | * struct rpcrdma_rep -- this structure encapsulates state required to recv | 111 | * struct rpcrdma_rep -- this structure encapsulates state required to recv |
| 103 | * and complete a reply, asychronously. It needs several pieces of | 112 | * and complete a reply, asychronously. It needs several pieces of |
| @@ -137,6 +146,40 @@ struct rpcrdma_rep { | |||
| 137 | }; | 146 | }; |
| 138 | 147 | ||
| 139 | /* | 148 | /* |
| 149 | * struct rpcrdma_mw - external memory region metadata | ||
| 150 | * | ||
| 151 | * An external memory region is any buffer or page that is registered | ||
| 152 | * on the fly (ie, not pre-registered). | ||
| 153 | * | ||
| 154 | * Each rpcrdma_buffer has a list of free MWs anchored in rb_mws. During | ||
| 155 | * call_allocate, rpcrdma_buffer_get() assigns one to each segment in | ||
| 156 | * an rpcrdma_req. Then rpcrdma_register_external() grabs these to keep | ||
| 157 | * track of registration metadata while each RPC is pending. | ||
| 158 | * rpcrdma_deregister_external() uses this metadata to unmap and | ||
| 159 | * release these resources when an RPC is complete. | ||
| 160 | */ | ||
| 161 | enum rpcrdma_frmr_state { | ||
| 162 | FRMR_IS_INVALID, /* ready to be used */ | ||
| 163 | FRMR_IS_VALID, /* in use */ | ||
| 164 | FRMR_IS_STALE, /* failed completion */ | ||
| 165 | }; | ||
| 166 | |||
| 167 | struct rpcrdma_frmr { | ||
| 168 | struct ib_fast_reg_page_list *fr_pgl; | ||
| 169 | struct ib_mr *fr_mr; | ||
| 170 | enum rpcrdma_frmr_state fr_state; | ||
| 171 | }; | ||
| 172 | |||
| 173 | struct rpcrdma_mw { | ||
| 174 | union { | ||
| 175 | struct ib_fmr *fmr; | ||
| 176 | struct rpcrdma_frmr frmr; | ||
| 177 | } r; | ||
| 178 | struct list_head mw_list; | ||
| 179 | struct list_head mw_all; | ||
| 180 | }; | ||
| 181 | |||
| 182 | /* | ||
| 140 | * struct rpcrdma_req -- structure central to the request/reply sequence. | 183 | * struct rpcrdma_req -- structure central to the request/reply sequence. |
| 141 | * | 184 | * |
| 142 | * N of these are associated with a transport instance, and stored in | 185 | * N of these are associated with a transport instance, and stored in |
| @@ -163,17 +206,7 @@ struct rpcrdma_rep { | |||
| 163 | struct rpcrdma_mr_seg { /* chunk descriptors */ | 206 | struct rpcrdma_mr_seg { /* chunk descriptors */ |
| 164 | union { /* chunk memory handles */ | 207 | union { /* chunk memory handles */ |
| 165 | struct ib_mr *rl_mr; /* if registered directly */ | 208 | struct ib_mr *rl_mr; /* if registered directly */ |
| 166 | struct rpcrdma_mw { /* if registered from region */ | 209 | struct rpcrdma_mw *rl_mw; /* if registered from region */ |
| 167 | union { | ||
| 168 | struct ib_fmr *fmr; | ||
| 169 | struct { | ||
| 170 | struct ib_fast_reg_page_list *fr_pgl; | ||
| 171 | struct ib_mr *fr_mr; | ||
| 172 | enum { FRMR_IS_INVALID, FRMR_IS_VALID } state; | ||
| 173 | } frmr; | ||
| 174 | } r; | ||
| 175 | struct list_head mw_list; | ||
| 176 | } *rl_mw; | ||
| 177 | } mr_chunk; | 210 | } mr_chunk; |
| 178 | u64 mr_base; /* registration result */ | 211 | u64 mr_base; /* registration result */ |
| 179 | u32 mr_rkey; /* registration result */ | 212 | u32 mr_rkey; /* registration result */ |
| @@ -191,6 +224,7 @@ struct rpcrdma_req { | |||
| 191 | unsigned int rl_niovs; /* 0, 2 or 4 */ | 224 | unsigned int rl_niovs; /* 0, 2 or 4 */ |
| 192 | unsigned int rl_nchunks; /* non-zero if chunks */ | 225 | unsigned int rl_nchunks; /* non-zero if chunks */ |
| 193 | unsigned int rl_connect_cookie; /* retry detection */ | 226 | unsigned int rl_connect_cookie; /* retry detection */ |
| 227 | enum rpcrdma_chunktype rl_rtype, rl_wtype; | ||
| 194 | struct rpcrdma_buffer *rl_buffer; /* home base for this structure */ | 228 | struct rpcrdma_buffer *rl_buffer; /* home base for this structure */ |
| 195 | struct rpcrdma_rep *rl_reply;/* holder for reply buffer */ | 229 | struct rpcrdma_rep *rl_reply;/* holder for reply buffer */ |
| 196 | struct rpcrdma_mr_seg rl_segments[RPCRDMA_MAX_SEGS];/* chunk segments */ | 230 | struct rpcrdma_mr_seg rl_segments[RPCRDMA_MAX_SEGS];/* chunk segments */ |
| @@ -214,6 +248,7 @@ struct rpcrdma_buffer { | |||
| 214 | atomic_t rb_credits; /* most recent server credits */ | 248 | atomic_t rb_credits; /* most recent server credits */ |
| 215 | int rb_max_requests;/* client max requests */ | 249 | int rb_max_requests;/* client max requests */ |
| 216 | struct list_head rb_mws; /* optional memory windows/fmrs/frmrs */ | 250 | struct list_head rb_mws; /* optional memory windows/fmrs/frmrs */ |
| 251 | struct list_head rb_all; | ||
| 217 | int rb_send_index; | 252 | int rb_send_index; |
| 218 | struct rpcrdma_req **rb_send_bufs; | 253 | struct rpcrdma_req **rb_send_bufs; |
| 219 | int rb_recv_index; | 254 | int rb_recv_index; |
| @@ -306,7 +341,7 @@ int rpcrdma_ep_create(struct rpcrdma_ep *, struct rpcrdma_ia *, | |||
| 306 | struct rpcrdma_create_data_internal *); | 341 | struct rpcrdma_create_data_internal *); |
| 307 | void rpcrdma_ep_destroy(struct rpcrdma_ep *, struct rpcrdma_ia *); | 342 | void rpcrdma_ep_destroy(struct rpcrdma_ep *, struct rpcrdma_ia *); |
| 308 | int rpcrdma_ep_connect(struct rpcrdma_ep *, struct rpcrdma_ia *); | 343 | int rpcrdma_ep_connect(struct rpcrdma_ep *, struct rpcrdma_ia *); |
| 309 | int rpcrdma_ep_disconnect(struct rpcrdma_ep *, struct rpcrdma_ia *); | 344 | void rpcrdma_ep_disconnect(struct rpcrdma_ep *, struct rpcrdma_ia *); |
| 310 | 345 | ||
| 311 | int rpcrdma_ep_post(struct rpcrdma_ia *, struct rpcrdma_ep *, | 346 | int rpcrdma_ep_post(struct rpcrdma_ia *, struct rpcrdma_ep *, |
| 312 | struct rpcrdma_req *); | 347 | struct rpcrdma_req *); |
| @@ -346,7 +381,9 @@ void rpcrdma_reply_handler(struct rpcrdma_rep *); | |||
| 346 | /* | 381 | /* |
| 347 | * RPC/RDMA protocol calls - xprtrdma/rpc_rdma.c | 382 | * RPC/RDMA protocol calls - xprtrdma/rpc_rdma.c |
| 348 | */ | 383 | */ |
| 384 | ssize_t rpcrdma_marshal_chunks(struct rpc_rqst *, ssize_t); | ||
| 349 | int rpcrdma_marshal_req(struct rpc_rqst *); | 385 | int rpcrdma_marshal_req(struct rpc_rqst *); |
| 386 | size_t rpcrdma_max_payload(struct rpcrdma_xprt *); | ||
| 350 | 387 | ||
| 351 | /* Temporary NFS request map cache. Created in svc_rdma.c */ | 388 | /* Temporary NFS request map cache. Created in svc_rdma.c */ |
| 352 | extern struct kmem_cache *svc_rdma_map_cachep; | 389 | extern struct kmem_cache *svc_rdma_map_cachep; |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index be8bbd5d65ec..43cd89eacfab 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
| @@ -594,6 +594,7 @@ static int xs_local_send_request(struct rpc_task *task) | |||
| 594 | } | 594 | } |
| 595 | 595 | ||
| 596 | switch (status) { | 596 | switch (status) { |
| 597 | case -ENOBUFS: | ||
| 597 | case -EAGAIN: | 598 | case -EAGAIN: |
| 598 | status = xs_nospace(task); | 599 | status = xs_nospace(task); |
| 599 | break; | 600 | break; |
| @@ -661,6 +662,7 @@ static int xs_udp_send_request(struct rpc_task *task) | |||
| 661 | dprintk("RPC: sendmsg returned unrecognized error %d\n", | 662 | dprintk("RPC: sendmsg returned unrecognized error %d\n", |
| 662 | -status); | 663 | -status); |
| 663 | case -ENETUNREACH: | 664 | case -ENETUNREACH: |
| 665 | case -ENOBUFS: | ||
| 664 | case -EPIPE: | 666 | case -EPIPE: |
| 665 | case -ECONNREFUSED: | 667 | case -ECONNREFUSED: |
| 666 | /* When the server has died, an ICMP port unreachable message | 668 | /* When the server has died, an ICMP port unreachable message |
| @@ -758,6 +760,7 @@ static int xs_tcp_send_request(struct rpc_task *task) | |||
| 758 | status = -ENOTCONN; | 760 | status = -ENOTCONN; |
| 759 | /* Should we call xs_close() here? */ | 761 | /* Should we call xs_close() here? */ |
| 760 | break; | 762 | break; |
| 763 | case -ENOBUFS: | ||
| 761 | case -EAGAIN: | 764 | case -EAGAIN: |
| 762 | status = xs_nospace(task); | 765 | status = xs_nospace(task); |
| 763 | break; | 766 | break; |
| @@ -1946,6 +1949,7 @@ static int xs_local_setup_socket(struct sock_xprt *transport) | |||
| 1946 | dprintk("RPC: xprt %p connected to %s\n", | 1949 | dprintk("RPC: xprt %p connected to %s\n", |
| 1947 | xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); | 1950 | xprt, xprt->address_strings[RPC_DISPLAY_ADDR]); |
| 1948 | xprt_set_connected(xprt); | 1951 | xprt_set_connected(xprt); |
| 1952 | case -ENOBUFS: | ||
| 1949 | break; | 1953 | break; |
| 1950 | case -ENOENT: | 1954 | case -ENOENT: |
| 1951 | dprintk("RPC: xprt %p: socket %s does not exist\n", | 1955 | dprintk("RPC: xprt %p: socket %s does not exist\n", |
| @@ -2281,6 +2285,7 @@ static void xs_tcp_setup_socket(struct work_struct *work) | |||
| 2281 | case -ECONNREFUSED: | 2285 | case -ECONNREFUSED: |
| 2282 | case -ECONNRESET: | 2286 | case -ECONNRESET: |
| 2283 | case -ENETUNREACH: | 2287 | case -ENETUNREACH: |
| 2288 | case -ENOBUFS: | ||
| 2284 | /* retry with existing socket, after a delay */ | 2289 | /* retry with existing socket, after a delay */ |
| 2285 | goto out; | 2290 | goto out; |
| 2286 | } | 2291 | } |
| @@ -3054,12 +3059,12 @@ static int param_set_uint_minmax(const char *val, | |||
| 3054 | const struct kernel_param *kp, | 3059 | const struct kernel_param *kp, |
| 3055 | unsigned int min, unsigned int max) | 3060 | unsigned int min, unsigned int max) |
| 3056 | { | 3061 | { |
| 3057 | unsigned long num; | 3062 | unsigned int num; |
| 3058 | int ret; | 3063 | int ret; |
| 3059 | 3064 | ||
| 3060 | if (!val) | 3065 | if (!val) |
| 3061 | return -EINVAL; | 3066 | return -EINVAL; |
| 3062 | ret = strict_strtoul(val, 0, &num); | 3067 | ret = kstrtouint(val, 0, &num); |
| 3063 | if (ret == -EINVAL || num < min || num > max) | 3068 | if (ret == -EINVAL || num < min || num > max) |
| 3064 | return -EINVAL; | 3069 | return -EINVAL; |
| 3065 | *((unsigned int *)kp->arg) = num; | 3070 | *((unsigned int *)kp->arg) = num; |
