diff options
-rw-r--r-- | fs/nfs/Kconfig | 8 | ||||
-rw-r--r-- | fs/nfs/direct.c | 82 | ||||
-rw-r--r-- | fs/nfs/file.c | 22 | ||||
-rw-r--r-- | include/linux/nfs_fs.h | 4 | ||||
-rw-r--r-- | include/linux/sunrpc/xprt.h | 3 | ||||
-rw-r--r-- | net/sunrpc/Kconfig | 5 | ||||
-rw-r--r-- | net/sunrpc/clnt.c | 9 | ||||
-rw-r--r-- | net/sunrpc/sched.c | 7 | ||||
-rw-r--r-- | net/sunrpc/xprtsock.c | 43 |
9 files changed, 149 insertions, 34 deletions
diff --git a/fs/nfs/Kconfig b/fs/nfs/Kconfig index 404c6a8ac394..6fd5f2cdcd1e 100644 --- a/fs/nfs/Kconfig +++ b/fs/nfs/Kconfig | |||
@@ -86,6 +86,14 @@ config NFS_V4 | |||
86 | 86 | ||
87 | If unsure, say Y. | 87 | If unsure, say Y. |
88 | 88 | ||
89 | config NFS_SWAP | ||
90 | bool "Provide swap over NFS support" | ||
91 | default n | ||
92 | depends on NFS_FS | ||
93 | select SUNRPC_SWAP | ||
94 | help | ||
95 | This option enables swapon to work on files located on NFS mounts. | ||
96 | |||
89 | config NFS_V4_1 | 97 | config NFS_V4_1 |
90 | bool "NFS client support for NFSv4.1 (EXPERIMENTAL)" | 98 | bool "NFS client support for NFSv4.1 (EXPERIMENTAL)" |
91 | depends on NFS_V4 && EXPERIMENTAL | 99 | depends on NFS_V4 && EXPERIMENTAL |
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index 42dce909ec70..bf9c8d0ec16a 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
@@ -115,17 +115,28 @@ static inline int put_dreq(struct nfs_direct_req *dreq) | |||
115 | * @nr_segs: size of iovec array | 115 | * @nr_segs: size of iovec array |
116 | * | 116 | * |
117 | * The presence of this routine in the address space ops vector means | 117 | * The presence of this routine in the address space ops vector means |
118 | * the NFS client supports direct I/O. However, we shunt off direct | 118 | * the NFS client supports direct I/O. However, for most direct IO, we |
119 | * read and write requests before the VFS gets them, so this method | 119 | * shunt off direct read and write requests before the VFS gets them, |
120 | * should never be called. | 120 | * so this method is only ever called for swap. |
121 | */ | 121 | */ |
122 | ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos, unsigned long nr_segs) | 122 | ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_t pos, unsigned long nr_segs) |
123 | { | 123 | { |
124 | #ifndef CONFIG_NFS_SWAP | ||
124 | dprintk("NFS: nfs_direct_IO (%s) off/no(%Ld/%lu) EINVAL\n", | 125 | dprintk("NFS: nfs_direct_IO (%s) off/no(%Ld/%lu) EINVAL\n", |
125 | iocb->ki_filp->f_path.dentry->d_name.name, | 126 | iocb->ki_filp->f_path.dentry->d_name.name, |
126 | (long long) pos, nr_segs); | 127 | (long long) pos, nr_segs); |
127 | 128 | ||
128 | return -EINVAL; | 129 | return -EINVAL; |
130 | #else | ||
131 | VM_BUG_ON(iocb->ki_left != PAGE_SIZE); | ||
132 | VM_BUG_ON(iocb->ki_nbytes != PAGE_SIZE); | ||
133 | |||
134 | if (rw == READ || rw == KERNEL_READ) | ||
135 | return nfs_file_direct_read(iocb, iov, nr_segs, pos, | ||
136 | rw == READ ? true : false); | ||
137 | return nfs_file_direct_write(iocb, iov, nr_segs, pos, | ||
138 | rw == WRITE ? true : false); | ||
139 | #endif /* CONFIG_NFS_SWAP */ | ||
129 | } | 140 | } |
130 | 141 | ||
131 | static void nfs_direct_release_pages(struct page **pages, unsigned int npages) | 142 | static void nfs_direct_release_pages(struct page **pages, unsigned int npages) |
@@ -303,7 +314,7 @@ static const struct nfs_pgio_completion_ops nfs_direct_read_completion_ops = { | |||
303 | */ | 314 | */ |
304 | static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *desc, | 315 | static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *desc, |
305 | const struct iovec *iov, | 316 | const struct iovec *iov, |
306 | loff_t pos) | 317 | loff_t pos, bool uio) |
307 | { | 318 | { |
308 | struct nfs_direct_req *dreq = desc->pg_dreq; | 319 | struct nfs_direct_req *dreq = desc->pg_dreq; |
309 | struct nfs_open_context *ctx = dreq->ctx; | 320 | struct nfs_open_context *ctx = dreq->ctx; |
@@ -331,12 +342,20 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *de | |||
331 | GFP_KERNEL); | 342 | GFP_KERNEL); |
332 | if (!pagevec) | 343 | if (!pagevec) |
333 | break; | 344 | break; |
334 | down_read(¤t->mm->mmap_sem); | 345 | if (uio) { |
335 | result = get_user_pages(current, current->mm, user_addr, | 346 | down_read(¤t->mm->mmap_sem); |
347 | result = get_user_pages(current, current->mm, user_addr, | ||
336 | npages, 1, 0, pagevec, NULL); | 348 | npages, 1, 0, pagevec, NULL); |
337 | up_read(¤t->mm->mmap_sem); | 349 | up_read(¤t->mm->mmap_sem); |
338 | if (result < 0) | 350 | if (result < 0) |
339 | break; | 351 | break; |
352 | } else { | ||
353 | WARN_ON(npages != 1); | ||
354 | result = get_kernel_page(user_addr, 1, pagevec); | ||
355 | if (WARN_ON(result != 1)) | ||
356 | break; | ||
357 | } | ||
358 | |||
340 | if ((unsigned)result < npages) { | 359 | if ((unsigned)result < npages) { |
341 | bytes = result * PAGE_SIZE; | 360 | bytes = result * PAGE_SIZE; |
342 | if (bytes <= pgbase) { | 361 | if (bytes <= pgbase) { |
@@ -386,7 +405,7 @@ static ssize_t nfs_direct_read_schedule_segment(struct nfs_pageio_descriptor *de | |||
386 | static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, | 405 | static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, |
387 | const struct iovec *iov, | 406 | const struct iovec *iov, |
388 | unsigned long nr_segs, | 407 | unsigned long nr_segs, |
389 | loff_t pos) | 408 | loff_t pos, bool uio) |
390 | { | 409 | { |
391 | struct nfs_pageio_descriptor desc; | 410 | struct nfs_pageio_descriptor desc; |
392 | ssize_t result = -EINVAL; | 411 | ssize_t result = -EINVAL; |
@@ -400,7 +419,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, | |||
400 | 419 | ||
401 | for (seg = 0; seg < nr_segs; seg++) { | 420 | for (seg = 0; seg < nr_segs; seg++) { |
402 | const struct iovec *vec = &iov[seg]; | 421 | const struct iovec *vec = &iov[seg]; |
403 | result = nfs_direct_read_schedule_segment(&desc, vec, pos); | 422 | result = nfs_direct_read_schedule_segment(&desc, vec, pos, uio); |
404 | if (result < 0) | 423 | if (result < 0) |
405 | break; | 424 | break; |
406 | requested_bytes += result; | 425 | requested_bytes += result; |
@@ -426,7 +445,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq, | |||
426 | } | 445 | } |
427 | 446 | ||
428 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, | 447 | static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, |
429 | unsigned long nr_segs, loff_t pos) | 448 | unsigned long nr_segs, loff_t pos, bool uio) |
430 | { | 449 | { |
431 | ssize_t result = -ENOMEM; | 450 | ssize_t result = -ENOMEM; |
432 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 451 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
@@ -444,7 +463,7 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
444 | if (!is_sync_kiocb(iocb)) | 463 | if (!is_sync_kiocb(iocb)) |
445 | dreq->iocb = iocb; | 464 | dreq->iocb = iocb; |
446 | 465 | ||
447 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos); | 466 | result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos, uio); |
448 | if (!result) | 467 | if (!result) |
449 | result = nfs_direct_wait(dreq); | 468 | result = nfs_direct_wait(dreq); |
450 | NFS_I(inode)->read_io += result; | 469 | NFS_I(inode)->read_io += result; |
@@ -610,7 +629,7 @@ static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode | |||
610 | */ | 629 | */ |
611 | static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *desc, | 630 | static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *desc, |
612 | const struct iovec *iov, | 631 | const struct iovec *iov, |
613 | loff_t pos) | 632 | loff_t pos, bool uio) |
614 | { | 633 | { |
615 | struct nfs_direct_req *dreq = desc->pg_dreq; | 634 | struct nfs_direct_req *dreq = desc->pg_dreq; |
616 | struct nfs_open_context *ctx = dreq->ctx; | 635 | struct nfs_open_context *ctx = dreq->ctx; |
@@ -638,12 +657,19 @@ static ssize_t nfs_direct_write_schedule_segment(struct nfs_pageio_descriptor *d | |||
638 | if (!pagevec) | 657 | if (!pagevec) |
639 | break; | 658 | break; |
640 | 659 | ||
641 | down_read(¤t->mm->mmap_sem); | 660 | if (uio) { |
642 | result = get_user_pages(current, current->mm, user_addr, | 661 | down_read(¤t->mm->mmap_sem); |
643 | npages, 0, 0, pagevec, NULL); | 662 | result = get_user_pages(current, current->mm, user_addr, |
644 | up_read(¤t->mm->mmap_sem); | 663 | npages, 0, 0, pagevec, NULL); |
645 | if (result < 0) | 664 | up_read(¤t->mm->mmap_sem); |
646 | break; | 665 | if (result < 0) |
666 | break; | ||
667 | } else { | ||
668 | WARN_ON(npages != 1); | ||
669 | result = get_kernel_page(user_addr, 0, pagevec); | ||
670 | if (WARN_ON(result != 1)) | ||
671 | break; | ||
672 | } | ||
647 | 673 | ||
648 | if ((unsigned)result < npages) { | 674 | if ((unsigned)result < npages) { |
649 | bytes = result * PAGE_SIZE; | 675 | bytes = result * PAGE_SIZE; |
@@ -774,7 +800,7 @@ static const struct nfs_pgio_completion_ops nfs_direct_write_completion_ops = { | |||
774 | static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, | 800 | static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, |
775 | const struct iovec *iov, | 801 | const struct iovec *iov, |
776 | unsigned long nr_segs, | 802 | unsigned long nr_segs, |
777 | loff_t pos) | 803 | loff_t pos, bool uio) |
778 | { | 804 | { |
779 | struct nfs_pageio_descriptor desc; | 805 | struct nfs_pageio_descriptor desc; |
780 | struct inode *inode = dreq->inode; | 806 | struct inode *inode = dreq->inode; |
@@ -790,7 +816,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, | |||
790 | 816 | ||
791 | for (seg = 0; seg < nr_segs; seg++) { | 817 | for (seg = 0; seg < nr_segs; seg++) { |
792 | const struct iovec *vec = &iov[seg]; | 818 | const struct iovec *vec = &iov[seg]; |
793 | result = nfs_direct_write_schedule_segment(&desc, vec, pos); | 819 | result = nfs_direct_write_schedule_segment(&desc, vec, pos, uio); |
794 | if (result < 0) | 820 | if (result < 0) |
795 | break; | 821 | break; |
796 | requested_bytes += result; | 822 | requested_bytes += result; |
@@ -818,7 +844,7 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq, | |||
818 | 844 | ||
819 | static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | 845 | static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, |
820 | unsigned long nr_segs, loff_t pos, | 846 | unsigned long nr_segs, loff_t pos, |
821 | size_t count) | 847 | size_t count, bool uio) |
822 | { | 848 | { |
823 | ssize_t result = -ENOMEM; | 849 | ssize_t result = -ENOMEM; |
824 | struct inode *inode = iocb->ki_filp->f_mapping->host; | 850 | struct inode *inode = iocb->ki_filp->f_mapping->host; |
@@ -836,7 +862,7 @@ static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
836 | if (!is_sync_kiocb(iocb)) | 862 | if (!is_sync_kiocb(iocb)) |
837 | dreq->iocb = iocb; | 863 | dreq->iocb = iocb; |
838 | 864 | ||
839 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos); | 865 | result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, uio); |
840 | if (!result) | 866 | if (!result) |
841 | result = nfs_direct_wait(dreq); | 867 | result = nfs_direct_wait(dreq); |
842 | out_release: | 868 | out_release: |
@@ -867,7 +893,7 @@ out: | |||
867 | * cache. | 893 | * cache. |
868 | */ | 894 | */ |
869 | ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, | 895 | ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, |
870 | unsigned long nr_segs, loff_t pos) | 896 | unsigned long nr_segs, loff_t pos, bool uio) |
871 | { | 897 | { |
872 | ssize_t retval = -EINVAL; | 898 | ssize_t retval = -EINVAL; |
873 | struct file *file = iocb->ki_filp; | 899 | struct file *file = iocb->ki_filp; |
@@ -892,7 +918,7 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov, | |||
892 | 918 | ||
893 | task_io_account_read(count); | 919 | task_io_account_read(count); |
894 | 920 | ||
895 | retval = nfs_direct_read(iocb, iov, nr_segs, pos); | 921 | retval = nfs_direct_read(iocb, iov, nr_segs, pos, uio); |
896 | if (retval > 0) | 922 | if (retval > 0) |
897 | iocb->ki_pos = pos + retval; | 923 | iocb->ki_pos = pos + retval; |
898 | 924 | ||
@@ -923,7 +949,7 @@ out: | |||
923 | * is no atomic O_APPEND write facility in the NFS protocol. | 949 | * is no atomic O_APPEND write facility in the NFS protocol. |
924 | */ | 950 | */ |
925 | ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | 951 | ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, |
926 | unsigned long nr_segs, loff_t pos) | 952 | unsigned long nr_segs, loff_t pos, bool uio) |
927 | { | 953 | { |
928 | ssize_t retval = -EINVAL; | 954 | ssize_t retval = -EINVAL; |
929 | struct file *file = iocb->ki_filp; | 955 | struct file *file = iocb->ki_filp; |
@@ -955,7 +981,7 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov, | |||
955 | 981 | ||
956 | task_io_account_write(count); | 982 | task_io_account_write(count); |
957 | 983 | ||
958 | retval = nfs_direct_write(iocb, iov, nr_segs, pos, count); | 984 | retval = nfs_direct_write(iocb, iov, nr_segs, pos, count, uio); |
959 | if (retval > 0) { | 985 | if (retval > 0) { |
960 | struct inode *inode = mapping->host; | 986 | struct inode *inode = mapping->host; |
961 | 987 | ||
diff --git a/fs/nfs/file.c b/fs/nfs/file.c index acd4e4cd2906..50fb83a88b1b 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c | |||
@@ -175,7 +175,7 @@ nfs_file_read(struct kiocb *iocb, const struct iovec *iov, | |||
175 | ssize_t result; | 175 | ssize_t result; |
176 | 176 | ||
177 | if (iocb->ki_filp->f_flags & O_DIRECT) | 177 | if (iocb->ki_filp->f_flags & O_DIRECT) |
178 | return nfs_file_direct_read(iocb, iov, nr_segs, pos); | 178 | return nfs_file_direct_read(iocb, iov, nr_segs, pos, true); |
179 | 179 | ||
180 | dprintk("NFS: read(%s/%s, %lu@%lu)\n", | 180 | dprintk("NFS: read(%s/%s, %lu@%lu)\n", |
181 | dentry->d_parent->d_name.name, dentry->d_name.name, | 181 | dentry->d_parent->d_name.name, dentry->d_name.name, |
@@ -482,6 +482,20 @@ static int nfs_launder_page(struct page *page) | |||
482 | return nfs_wb_page(inode, page); | 482 | return nfs_wb_page(inode, page); |
483 | } | 483 | } |
484 | 484 | ||
485 | #ifdef CONFIG_NFS_SWAP | ||
486 | static int nfs_swap_activate(struct swap_info_struct *sis, struct file *file, | ||
487 | sector_t *span) | ||
488 | { | ||
489 | *span = sis->pages; | ||
490 | return xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 1); | ||
491 | } | ||
492 | |||
493 | static void nfs_swap_deactivate(struct file *file) | ||
494 | { | ||
495 | xs_swapper(NFS_CLIENT(file->f_mapping->host)->cl_xprt, 0); | ||
496 | } | ||
497 | #endif | ||
498 | |||
485 | const struct address_space_operations nfs_file_aops = { | 499 | const struct address_space_operations nfs_file_aops = { |
486 | .readpage = nfs_readpage, | 500 | .readpage = nfs_readpage, |
487 | .readpages = nfs_readpages, | 501 | .readpages = nfs_readpages, |
@@ -496,6 +510,10 @@ const struct address_space_operations nfs_file_aops = { | |||
496 | .migratepage = nfs_migrate_page, | 510 | .migratepage = nfs_migrate_page, |
497 | .launder_page = nfs_launder_page, | 511 | .launder_page = nfs_launder_page, |
498 | .error_remove_page = generic_error_remove_page, | 512 | .error_remove_page = generic_error_remove_page, |
513 | #ifdef CONFIG_NFS_SWAP | ||
514 | .swap_activate = nfs_swap_activate, | ||
515 | .swap_deactivate = nfs_swap_deactivate, | ||
516 | #endif | ||
499 | }; | 517 | }; |
500 | 518 | ||
501 | /* | 519 | /* |
@@ -570,7 +588,7 @@ ssize_t nfs_file_write(struct kiocb *iocb, const struct iovec *iov, | |||
570 | size_t count = iov_length(iov, nr_segs); | 588 | size_t count = iov_length(iov, nr_segs); |
571 | 589 | ||
572 | if (iocb->ki_filp->f_flags & O_DIRECT) | 590 | if (iocb->ki_filp->f_flags & O_DIRECT) |
573 | return nfs_file_direct_write(iocb, iov, nr_segs, pos); | 591 | return nfs_file_direct_write(iocb, iov, nr_segs, pos, true); |
574 | 592 | ||
575 | dprintk("NFS: write(%s/%s, %lu@%Ld)\n", | 593 | dprintk("NFS: write(%s/%s, %lu@%Ld)\n", |
576 | dentry->d_parent->d_name.name, dentry->d_name.name, | 594 | dentry->d_parent->d_name.name, dentry->d_name.name, |
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h index 4b6043c20f77..35994f975a7f 100644 --- a/include/linux/nfs_fs.h +++ b/include/linux/nfs_fs.h | |||
@@ -473,10 +473,10 @@ extern ssize_t nfs_direct_IO(int, struct kiocb *, const struct iovec *, loff_t, | |||
473 | unsigned long); | 473 | unsigned long); |
474 | extern ssize_t nfs_file_direct_read(struct kiocb *iocb, | 474 | extern ssize_t nfs_file_direct_read(struct kiocb *iocb, |
475 | const struct iovec *iov, unsigned long nr_segs, | 475 | const struct iovec *iov, unsigned long nr_segs, |
476 | loff_t pos); | 476 | loff_t pos, bool uio); |
477 | extern ssize_t nfs_file_direct_write(struct kiocb *iocb, | 477 | extern ssize_t nfs_file_direct_write(struct kiocb *iocb, |
478 | const struct iovec *iov, unsigned long nr_segs, | 478 | const struct iovec *iov, unsigned long nr_segs, |
479 | loff_t pos); | 479 | loff_t pos, bool uio); |
480 | 480 | ||
481 | /* | 481 | /* |
482 | * linux/fs/nfs/dir.c | 482 | * linux/fs/nfs/dir.c |
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 77d278defa70..cff40aa7db62 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h | |||
@@ -174,6 +174,8 @@ struct rpc_xprt { | |||
174 | unsigned long state; /* transport state */ | 174 | unsigned long state; /* transport state */ |
175 | unsigned char shutdown : 1, /* being shut down */ | 175 | unsigned char shutdown : 1, /* being shut down */ |
176 | resvport : 1; /* use a reserved port */ | 176 | resvport : 1; /* use a reserved port */ |
177 | unsigned int swapper; /* we're swapping over this | ||
178 | transport */ | ||
177 | unsigned int bind_index; /* bind function index */ | 179 | unsigned int bind_index; /* bind function index */ |
178 | 180 | ||
179 | /* | 181 | /* |
@@ -316,6 +318,7 @@ void xprt_release_rqst_cong(struct rpc_task *task); | |||
316 | void xprt_disconnect_done(struct rpc_xprt *xprt); | 318 | void xprt_disconnect_done(struct rpc_xprt *xprt); |
317 | void xprt_force_disconnect(struct rpc_xprt *xprt); | 319 | void xprt_force_disconnect(struct rpc_xprt *xprt); |
318 | void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); | 320 | void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); |
321 | int xs_swapper(struct rpc_xprt *xprt, int enable); | ||
319 | 322 | ||
320 | /* | 323 | /* |
321 | * Reserved bit positions in xprt->state | 324 | * Reserved bit positions in xprt->state |
diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig index 9fe8857d8d59..03d03e37a7d5 100644 --- a/net/sunrpc/Kconfig +++ b/net/sunrpc/Kconfig | |||
@@ -21,6 +21,11 @@ config SUNRPC_XPRT_RDMA | |||
21 | 21 | ||
22 | If unsure, say N. | 22 | If unsure, say N. |
23 | 23 | ||
24 | config SUNRPC_SWAP | ||
25 | bool | ||
26 | depends on SUNRPC | ||
27 | select NETVM | ||
28 | |||
24 | config RPCSEC_GSS_KRB5 | 29 | config RPCSEC_GSS_KRB5 |
25 | tristate "Secure RPC: Kerberos V mechanism" | 30 | tristate "Secure RPC: Kerberos V mechanism" |
26 | depends on SUNRPC && CRYPTO | 31 | depends on SUNRPC && CRYPTO |
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index b05df36692ff..fa48c60aef23 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c | |||
@@ -717,6 +717,15 @@ void rpc_task_set_client(struct rpc_task *task, struct rpc_clnt *clnt) | |||
717 | atomic_inc(&clnt->cl_count); | 717 | atomic_inc(&clnt->cl_count); |
718 | if (clnt->cl_softrtry) | 718 | if (clnt->cl_softrtry) |
719 | task->tk_flags |= RPC_TASK_SOFT; | 719 | task->tk_flags |= RPC_TASK_SOFT; |
720 | if (sk_memalloc_socks()) { | ||
721 | struct rpc_xprt *xprt; | ||
722 | |||
723 | rcu_read_lock(); | ||
724 | xprt = rcu_dereference(clnt->cl_xprt); | ||
725 | if (xprt->swapper) | ||
726 | task->tk_flags |= RPC_TASK_SWAPPER; | ||
727 | rcu_read_unlock(); | ||
728 | } | ||
720 | /* Add to the client's list of all tasks */ | 729 | /* Add to the client's list of all tasks */ |
721 | spin_lock(&clnt->cl_lock); | 730 | spin_lock(&clnt->cl_lock); |
722 | list_add_tail(&task->tk_task, &clnt->cl_tasks); | 731 | list_add_tail(&task->tk_task, &clnt->cl_tasks); |
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c index 994cfea2bad6..83a4c43cee7f 100644 --- a/net/sunrpc/sched.c +++ b/net/sunrpc/sched.c | |||
@@ -812,7 +812,10 @@ static void rpc_async_schedule(struct work_struct *work) | |||
812 | void *rpc_malloc(struct rpc_task *task, size_t size) | 812 | void *rpc_malloc(struct rpc_task *task, size_t size) |
813 | { | 813 | { |
814 | struct rpc_buffer *buf; | 814 | struct rpc_buffer *buf; |
815 | gfp_t gfp = RPC_IS_SWAPPER(task) ? GFP_ATOMIC : GFP_NOWAIT; | 815 | gfp_t gfp = GFP_NOWAIT; |
816 | |||
817 | if (RPC_IS_SWAPPER(task)) | ||
818 | gfp |= __GFP_MEMALLOC; | ||
816 | 819 | ||
817 | size += sizeof(struct rpc_buffer); | 820 | size += sizeof(struct rpc_buffer); |
818 | if (size <= RPC_BUFFER_MAXSIZE) | 821 | if (size <= RPC_BUFFER_MAXSIZE) |
@@ -886,7 +889,7 @@ static void rpc_init_task(struct rpc_task *task, const struct rpc_task_setup *ta | |||
886 | static struct rpc_task * | 889 | static struct rpc_task * |
887 | rpc_alloc_task(void) | 890 | rpc_alloc_task(void) |
888 | { | 891 | { |
889 | return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOFS); | 892 | return (struct rpc_task *)mempool_alloc(rpc_task_mempool, GFP_NOIO); |
890 | } | 893 | } |
891 | 894 | ||
892 | /* | 895 | /* |
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 62d0dac8f780..bd59d01f035b 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c | |||
@@ -1927,6 +1927,45 @@ out: | |||
1927 | xprt_wake_pending_tasks(xprt, status); | 1927 | xprt_wake_pending_tasks(xprt, status); |
1928 | } | 1928 | } |
1929 | 1929 | ||
1930 | #ifdef CONFIG_SUNRPC_SWAP | ||
1931 | static void xs_set_memalloc(struct rpc_xprt *xprt) | ||
1932 | { | ||
1933 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, | ||
1934 | xprt); | ||
1935 | |||
1936 | if (xprt->swapper) | ||
1937 | sk_set_memalloc(transport->inet); | ||
1938 | } | ||
1939 | |||
1940 | /** | ||
1941 | * xs_swapper - Tag this transport as being used for swap. | ||
1942 | * @xprt: transport to tag | ||
1943 | * @enable: enable/disable | ||
1944 | * | ||
1945 | */ | ||
1946 | int xs_swapper(struct rpc_xprt *xprt, int enable) | ||
1947 | { | ||
1948 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, | ||
1949 | xprt); | ||
1950 | int err = 0; | ||
1951 | |||
1952 | if (enable) { | ||
1953 | xprt->swapper++; | ||
1954 | xs_set_memalloc(xprt); | ||
1955 | } else if (xprt->swapper) { | ||
1956 | xprt->swapper--; | ||
1957 | sk_clear_memalloc(transport->inet); | ||
1958 | } | ||
1959 | |||
1960 | return err; | ||
1961 | } | ||
1962 | EXPORT_SYMBOL_GPL(xs_swapper); | ||
1963 | #else | ||
1964 | static void xs_set_memalloc(struct rpc_xprt *xprt) | ||
1965 | { | ||
1966 | } | ||
1967 | #endif | ||
1968 | |||
1930 | static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) | 1969 | static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) |
1931 | { | 1970 | { |
1932 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); | 1971 | struct sock_xprt *transport = container_of(xprt, struct sock_xprt, xprt); |
@@ -1951,6 +1990,8 @@ static void xs_udp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) | |||
1951 | transport->sock = sock; | 1990 | transport->sock = sock; |
1952 | transport->inet = sk; | 1991 | transport->inet = sk; |
1953 | 1992 | ||
1993 | xs_set_memalloc(xprt); | ||
1994 | |||
1954 | write_unlock_bh(&sk->sk_callback_lock); | 1995 | write_unlock_bh(&sk->sk_callback_lock); |
1955 | } | 1996 | } |
1956 | xs_udp_do_set_buffer_size(xprt); | 1997 | xs_udp_do_set_buffer_size(xprt); |
@@ -2075,6 +2116,8 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock) | |||
2075 | if (!xprt_bound(xprt)) | 2116 | if (!xprt_bound(xprt)) |
2076 | goto out; | 2117 | goto out; |
2077 | 2118 | ||
2119 | xs_set_memalloc(xprt); | ||
2120 | |||
2078 | /* Tell the socket layer to start connecting... */ | 2121 | /* Tell the socket layer to start connecting... */ |
2079 | xprt->stat.connect_count++; | 2122 | xprt->stat.connect_count++; |
2080 | xprt->stat.connect_start = jiffies; | 2123 | xprt->stat.connect_start = jiffies; |