diff options
author | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-08-09 15:14:28 -0400 |
---|---|---|
committer | Trond Myklebust <Trond.Myklebust@netapp.com> | 2009-08-09 15:14:28 -0400 |
commit | da77005f0d64486cd760f43d9b7cc2379262a363 (patch) | |
tree | fa64dac28c47940dd730fff68f692fd5bbd73d78 /net | |
parent | 5b7a1b9f9214cb89dd164b43ca3fab7af4058e06 (diff) |
SUNRPC: Remove the global temporary write buffer in net/sunrpc/cache.c
While we do want to protect against multiple concurrent readers and writers
on each upcall/downcall pipe, we don't want to limit concurrent reading and
writing to separate caches.
This patch therefore replaces the static buffer 'write_buf', which can only
be used by one writer at a time, with use of the page cache as the
temporary buffer for downcalls. We still fall back to using the the old
global buffer if the downcall is larger than PAGE_CACHE_SIZE, since this is
apparently needed by the SPKM security context initialisation.
It then replaces the use of the global 'queue_io_mutex' with the
inode->i_mutex in cache_read() and cache_write().
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
Diffstat (limited to 'net')
-rw-r--r-- | net/sunrpc/cache.c | 95 |
1 files changed, 70 insertions, 25 deletions
diff --git a/net/sunrpc/cache.c b/net/sunrpc/cache.c index 062d4f4307eb..c8e7d2d07260 100644 --- a/net/sunrpc/cache.c +++ b/net/sunrpc/cache.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/net.h> | 27 | #include <linux/net.h> |
28 | #include <linux/workqueue.h> | 28 | #include <linux/workqueue.h> |
29 | #include <linux/mutex.h> | 29 | #include <linux/mutex.h> |
30 | #include <linux/pagemap.h> | ||
30 | #include <asm/ioctls.h> | 31 | #include <asm/ioctls.h> |
31 | #include <linux/sunrpc/types.h> | 32 | #include <linux/sunrpc/types.h> |
32 | #include <linux/sunrpc/cache.h> | 33 | #include <linux/sunrpc/cache.h> |
@@ -702,13 +703,14 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
702 | { | 703 | { |
703 | struct cache_reader *rp = filp->private_data; | 704 | struct cache_reader *rp = filp->private_data; |
704 | struct cache_request *rq; | 705 | struct cache_request *rq; |
705 | struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; | 706 | struct inode *inode = filp->f_path.dentry->d_inode; |
707 | struct cache_detail *cd = PDE(inode)->data; | ||
706 | int err; | 708 | int err; |
707 | 709 | ||
708 | if (count == 0) | 710 | if (count == 0) |
709 | return 0; | 711 | return 0; |
710 | 712 | ||
711 | mutex_lock(&queue_io_mutex); /* protect against multiple concurrent | 713 | mutex_lock(&inode->i_mutex); /* protect against multiple concurrent |
712 | * readers on this file */ | 714 | * readers on this file */ |
713 | again: | 715 | again: |
714 | spin_lock(&queue_lock); | 716 | spin_lock(&queue_lock); |
@@ -721,7 +723,7 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
721 | } | 723 | } |
722 | if (rp->q.list.next == &cd->queue) { | 724 | if (rp->q.list.next == &cd->queue) { |
723 | spin_unlock(&queue_lock); | 725 | spin_unlock(&queue_lock); |
724 | mutex_unlock(&queue_io_mutex); | 726 | mutex_unlock(&inode->i_mutex); |
725 | BUG_ON(rp->offset); | 727 | BUG_ON(rp->offset); |
726 | return 0; | 728 | return 0; |
727 | } | 729 | } |
@@ -768,38 +770,81 @@ cache_read(struct file *filp, char __user *buf, size_t count, loff_t *ppos) | |||
768 | } | 770 | } |
769 | if (err == -EAGAIN) | 771 | if (err == -EAGAIN) |
770 | goto again; | 772 | goto again; |
771 | mutex_unlock(&queue_io_mutex); | 773 | mutex_unlock(&inode->i_mutex); |
772 | return err ? err : count; | 774 | return err ? err : count; |
773 | } | 775 | } |
774 | 776 | ||
775 | static char write_buf[8192]; /* protected by queue_io_mutex */ | 777 | static ssize_t cache_do_downcall(char *kaddr, const char __user *buf, |
778 | size_t count, struct cache_detail *cd) | ||
779 | { | ||
780 | ssize_t ret; | ||
776 | 781 | ||
777 | static ssize_t | 782 | if (copy_from_user(kaddr, buf, count)) |
778 | cache_write(struct file *filp, const char __user *buf, size_t count, | 783 | return -EFAULT; |
779 | loff_t *ppos) | 784 | kaddr[count] = '\0'; |
785 | ret = cd->cache_parse(cd, kaddr, count); | ||
786 | if (!ret) | ||
787 | ret = count; | ||
788 | return ret; | ||
789 | } | ||
790 | |||
791 | static ssize_t cache_slow_downcall(const char __user *buf, | ||
792 | size_t count, struct cache_detail *cd) | ||
780 | { | 793 | { |
781 | int err; | 794 | static char write_buf[8192]; /* protected by queue_io_mutex */ |
782 | struct cache_detail *cd = PDE(filp->f_path.dentry->d_inode)->data; | 795 | ssize_t ret = -EINVAL; |
783 | 796 | ||
784 | if (count == 0) | ||
785 | return 0; | ||
786 | if (count >= sizeof(write_buf)) | 797 | if (count >= sizeof(write_buf)) |
787 | return -EINVAL; | 798 | goto out; |
788 | |||
789 | mutex_lock(&queue_io_mutex); | 799 | mutex_lock(&queue_io_mutex); |
800 | ret = cache_do_downcall(write_buf, buf, count, cd); | ||
801 | mutex_unlock(&queue_io_mutex); | ||
802 | out: | ||
803 | return ret; | ||
804 | } | ||
790 | 805 | ||
791 | if (copy_from_user(write_buf, buf, count)) { | 806 | static ssize_t cache_downcall(struct address_space *mapping, |
792 | mutex_unlock(&queue_io_mutex); | 807 | const char __user *buf, |
793 | return -EFAULT; | 808 | size_t count, struct cache_detail *cd) |
794 | } | 809 | { |
795 | write_buf[count] = '\0'; | 810 | struct page *page; |
796 | if (cd->cache_parse) | 811 | char *kaddr; |
797 | err = cd->cache_parse(cd, write_buf, count); | 812 | ssize_t ret = -ENOMEM; |
798 | else | 813 | |
799 | err = -EINVAL; | 814 | if (count >= PAGE_CACHE_SIZE) |
815 | goto out_slow; | ||
816 | |||
817 | page = find_or_create_page(mapping, 0, GFP_KERNEL); | ||
818 | if (!page) | ||
819 | goto out_slow; | ||
820 | |||
821 | kaddr = kmap(page); | ||
822 | ret = cache_do_downcall(kaddr, buf, count, cd); | ||
823 | kunmap(page); | ||
824 | unlock_page(page); | ||
825 | page_cache_release(page); | ||
826 | return ret; | ||
827 | out_slow: | ||
828 | return cache_slow_downcall(buf, count, cd); | ||
829 | } | ||
800 | 830 | ||
801 | mutex_unlock(&queue_io_mutex); | 831 | static ssize_t |
802 | return err ? err : count; | 832 | cache_write(struct file *filp, const char __user *buf, size_t count, |
833 | loff_t *ppos) | ||
834 | { | ||
835 | struct address_space *mapping = filp->f_mapping; | ||
836 | struct inode *inode = filp->f_path.dentry->d_inode; | ||
837 | struct cache_detail *cd = PDE(inode)->data; | ||
838 | ssize_t ret = -EINVAL; | ||
839 | |||
840 | if (!cd->cache_parse) | ||
841 | goto out; | ||
842 | |||
843 | mutex_lock(&inode->i_mutex); | ||
844 | ret = cache_downcall(mapping, buf, count, cd); | ||
845 | mutex_unlock(&inode->i_mutex); | ||
846 | out: | ||
847 | return ret; | ||
803 | } | 848 | } |
804 | 849 | ||
805 | static DECLARE_WAIT_QUEUE_HEAD(queue_wait); | 850 | static DECLARE_WAIT_QUEUE_HEAD(queue_wait); |