diff options
| -rw-r--r-- | fs/nfs/direct.c | 59 |
1 files changed, 29 insertions, 30 deletions
diff --git a/fs/nfs/direct.c b/fs/nfs/direct.c index b4bbf6d75923..58830429e42a 100644 --- a/fs/nfs/direct.c +++ b/fs/nfs/direct.c | |||
| @@ -59,7 +59,6 @@ | |||
| 59 | 59 | ||
| 60 | #define NFSDBG_FACILITY NFSDBG_VFS | 60 | #define NFSDBG_FACILITY NFSDBG_VFS |
| 61 | 61 | ||
| 62 | static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty); | ||
| 63 | static kmem_cache_t *nfs_direct_cachep; | 62 | static kmem_cache_t *nfs_direct_cachep; |
| 64 | 63 | ||
| 65 | /* | 64 | /* |
| @@ -121,6 +120,18 @@ ssize_t nfs_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, loff_ | |||
| 121 | return -EINVAL; | 120 | return -EINVAL; |
| 122 | } | 121 | } |
| 123 | 122 | ||
| 123 | static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty) | ||
| 124 | { | ||
| 125 | int i; | ||
| 126 | for (i = 0; i < npages; i++) { | ||
| 127 | struct page *page = pages[i]; | ||
| 128 | if (do_dirty && !PageCompound(page)) | ||
| 129 | set_page_dirty_lock(page); | ||
| 130 | page_cache_release(page); | ||
| 131 | } | ||
| 132 | kfree(pages); | ||
| 133 | } | ||
| 134 | |||
| 124 | static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, struct page ***pages) | 135 | static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t size, struct page ***pages) |
| 125 | { | 136 | { |
| 126 | int result = -ENOMEM; | 137 | int result = -ENOMEM; |
| @@ -138,31 +149,23 @@ static inline int nfs_get_user_pages(int rw, unsigned long user_addr, size_t siz | |||
| 138 | page_count, (rw == READ), 0, | 149 | page_count, (rw == READ), 0, |
| 139 | *pages, NULL); | 150 | *pages, NULL); |
| 140 | up_read(¤t->mm->mmap_sem); | 151 | up_read(¤t->mm->mmap_sem); |
| 141 | /* | 152 | if (result != page_count) { |
| 142 | * If we got fewer pages than expected from get_user_pages(), | 153 | /* |
| 143 | * the user buffer runs off the end of a mapping; return EFAULT. | 154 | * If we got fewer pages than expected from |
| 144 | */ | 155 | * get_user_pages(), the user buffer runs off the |
| 145 | if (result >= 0 && result < page_count) { | 156 | * end of a mapping; return EFAULT. |
| 146 | nfs_free_user_pages(*pages, result, 0); | 157 | */ |
| 158 | if (result >= 0) { | ||
| 159 | nfs_free_user_pages(*pages, result, 0); | ||
| 160 | result = -EFAULT; | ||
| 161 | } else | ||
| 162 | kfree(*pages); | ||
| 147 | *pages = NULL; | 163 | *pages = NULL; |
| 148 | result = -EFAULT; | ||
| 149 | } | 164 | } |
| 150 | } | 165 | } |
| 151 | return result; | 166 | return result; |
| 152 | } | 167 | } |
| 153 | 168 | ||
| 154 | static void nfs_free_user_pages(struct page **pages, int npages, int do_dirty) | ||
| 155 | { | ||
| 156 | int i; | ||
| 157 | for (i = 0; i < npages; i++) { | ||
| 158 | struct page *page = pages[i]; | ||
| 159 | if (do_dirty && !PageCompound(page)) | ||
| 160 | set_page_dirty_lock(page); | ||
| 161 | page_cache_release(page); | ||
| 162 | } | ||
| 163 | kfree(pages); | ||
| 164 | } | ||
| 165 | |||
| 166 | static inline struct nfs_direct_req *nfs_direct_req_alloc(void) | 169 | static inline struct nfs_direct_req *nfs_direct_req_alloc(void) |
| 167 | { | 170 | { |
| 168 | struct nfs_direct_req *dreq; | 171 | struct nfs_direct_req *dreq; |
| @@ -788,13 +791,11 @@ ssize_t nfs_file_direct_read(struct kiocb *iocb, char __user *buf, size_t count, | |||
| 788 | if (retval) | 791 | if (retval) |
| 789 | goto out; | 792 | goto out; |
| 790 | 793 | ||
| 791 | page_count = nfs_get_user_pages(READ, (unsigned long) buf, | 794 | retval = nfs_get_user_pages(READ, (unsigned long) buf, |
| 792 | count, &pages); | 795 | count, &pages); |
| 793 | if (page_count < 0) { | 796 | if (retval < 0) |
| 794 | nfs_free_user_pages(pages, 0, 0); | ||
| 795 | retval = page_count; | ||
| 796 | goto out; | 797 | goto out; |
| 797 | } | 798 | page_count = retval; |
| 798 | 799 | ||
| 799 | retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos, | 800 | retval = nfs_direct_read(iocb, (unsigned long) buf, count, pos, |
| 800 | pages, page_count); | 801 | pages, page_count); |
| @@ -862,13 +863,11 @@ ssize_t nfs_file_direct_write(struct kiocb *iocb, const char __user *buf, size_t | |||
| 862 | if (retval) | 863 | if (retval) |
| 863 | goto out; | 864 | goto out; |
| 864 | 865 | ||
| 865 | page_count = nfs_get_user_pages(WRITE, (unsigned long) buf, | 866 | retval = nfs_get_user_pages(WRITE, (unsigned long) buf, |
| 866 | count, &pages); | 867 | count, &pages); |
| 867 | if (page_count < 0) { | 868 | if (retval < 0) |
| 868 | nfs_free_user_pages(pages, 0, 0); | ||
| 869 | retval = page_count; | ||
| 870 | goto out; | 869 | goto out; |
| 871 | } | 870 | page_count = retval; |
| 872 | 871 | ||
| 873 | retval = nfs_direct_write(iocb, (unsigned long) buf, count, | 872 | retval = nfs_direct_write(iocb, (unsigned long) buf, count, |
| 874 | pos, pages, page_count); | 873 | pos, pages, page_count); |
