From 1a074496b03242e0c7b0adbcd5f6f2db72fb0c47 Mon Sep 17 00:00:00 2001 From: Ben Hutchings Date: Fri, 31 Oct 2014 01:23:23 +0000 Subject: [PATCH] vfs,fuse: Change iov_iter_get_pages() to take both maxsize and maxpages parameters (Closes: #764285) svn path=/dists/sid/linux/; revision=21987 --- debian/changelog | 2 + ...read-and-max_write-in-direct_io-mode.patch | 123 ++++++++++++++++++ ...get_pages-to-passing-maximal-number-.patch | 119 +++++++++++++++++ debian/patches/series | 2 + 4 files changed, 246 insertions(+) create mode 100644 debian/patches/bugfix/all/fuse-honour-max_read-and-max_write-in-direct_io-mode.patch create mode 100644 debian/patches/bugfix/all/switch-iov_iter_get_pages-to-passing-maximal-number-.patch diff --git a/debian/changelog b/debian/changelog index 001a822da..d0f949407 100644 --- a/debian/changelog +++ b/debian/changelog @@ -119,6 +119,8 @@ linux (3.16.7-1) UNRELEASED; urgency=medium * rtsx_usb_ms: Use msleep_interruptible() in polling loop (Closes: #765717) * Bump ABI to 4 * Add '.0' to the kernel version string (Closes: #742226, #745984) + * vfs,fuse: Change iov_iter_get_pages() to take both maxsize and maxpages + parameters (Closes: #764285) [ Mauricio Faria de Oliveira ] * [ppc64el] Disable CONFIG_CMDLINE{,_BOOL} usage for setting consoles diff --git a/debian/patches/bugfix/all/fuse-honour-max_read-and-max_write-in-direct_io-mode.patch b/debian/patches/bugfix/all/fuse-honour-max_read-and-max_write-in-direct_io-mode.patch new file mode 100644 index 000000000..e039cba2a --- /dev/null +++ b/debian/patches/bugfix/all/fuse-honour-max_read-and-max_write-in-direct_io-mode.patch @@ -0,0 +1,123 @@ +From: Miklos Szeredi +Date: Wed, 24 Sep 2014 17:09:11 +0200 +Subject: fuse: honour max_read and max_write in direct_io mode +Origin: https://git.kernel.org/linus/2c80929c4c4d54e568b07ab85877d5fd38f4b02f + +The third argument of fuse_get_user_pages() "nbytesp" refers to the number of +bytes a caller asked to pack into fuse request. This value may be lesser +than capacity of fuse request or iov_iter. So fuse_get_user_pages() must +ensure that *nbytesp won't grow. + +Now, when helper iov_iter_get_pages() performs all hard work of extracting +pages from iov_iter, it can be done by passing properly calculated +"maxsize" to the helper. + +The other caller of iov_iter_get_pages() (dio_refill_pages()) doesn't need +this capability, so pass LONG_MAX as the maxsize argument here. + +Fixes: c9c37e2e6378 ("fuse: switch to iov_iter_get_pages()") +Reported-by: Werner Baumann +Tested-by: Maxim Patlasov +Signed-off-by: Miklos Szeredi +Signed-off-by: Al Viro +--- + fs/direct-io.c | 2 +- + fs/fuse/file.c | 1 + + include/linux/uio.h | 2 +- + mm/iov_iter.c | 14 +++++++++----- + 4 files changed, 12 insertions(+), 7 deletions(-) + +diff --git a/fs/direct-io.c b/fs/direct-io.c +index c311640..e181b6b 100644 +--- a/fs/direct-io.c ++++ b/fs/direct-io.c +@@ -158,7 +158,7 @@ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio) + { + ssize_t ret; + +- ret = iov_iter_get_pages(sdio->iter, dio->pages, DIO_PAGES, ++ ret = iov_iter_get_pages(sdio->iter, dio->pages, LONG_MAX, DIO_PAGES, + &sdio->from); + + if (ret < 0 && sdio->blocks_available && (dio->rw & WRITE)) { +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 912061a..caa8d95 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -1305,6 +1305,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii, + size_t start; + ssize_t ret = iov_iter_get_pages(ii, + &req->pages[req->num_pages], ++ *nbytesp - nbytes, + req->max_pages - req->num_pages, + &start); + if (ret < 0) +diff --git a/include/linux/uio.h b/include/linux/uio.h +index 48d64e6..290fbf0 100644 +--- a/include/linux/uio.h ++++ b/include/linux/uio.h +@@ -84,7 +84,7 @@ unsigned long iov_iter_alignment(const struct iov_iter *i); + void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, + unsigned long nr_segs, size_t count); + ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, +- unsigned maxpages, size_t *start); ++ size_t maxsize, unsigned maxpages, size_t *start); + ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, + size_t maxsize, size_t *start); + int iov_iter_npages(const struct iov_iter *i, int maxpages); +diff --git a/mm/iov_iter.c b/mm/iov_iter.c +index ab88dc0..9a09f20 100644 +--- a/mm/iov_iter.c ++++ b/mm/iov_iter.c +@@ -310,7 +310,7 @@ void iov_iter_init(struct iov_iter *i, int direction, + EXPORT_SYMBOL(iov_iter_init); + + static ssize_t get_pages_iovec(struct iov_iter *i, +- struct page **pages, unsigned maxpages, ++ struct page **pages, size_t maxsize, unsigned maxpages, + size_t *start) + { + size_t offset = i->iov_offset; +@@ -323,6 +323,8 @@ static ssize_t get_pages_iovec(struct iov_iter *i, + len = iov->iov_len - offset; + if (len > i->count) + len = i->count; ++ if (len > maxsize) ++ len = maxsize; + addr = (unsigned long)iov->iov_base + offset; + len += *start = addr & (PAGE_SIZE - 1); + if (len > maxpages * PAGE_SIZE) +@@ -588,13 +590,15 @@ static unsigned long alignment_bvec(const struct iov_iter *i) + } + + static ssize_t get_pages_bvec(struct iov_iter *i, +- struct page **pages, unsigned maxpages, ++ struct page **pages, size_t maxsize, unsigned maxpages, + size_t *start) + { + const struct bio_vec *bvec = i->bvec; + size_t len = bvec->bv_len - i->iov_offset; + if (len > i->count) + len = i->count; ++ if (len > maxsize) ++ len = maxsize; + /* can't be more than PAGE_SIZE */ + *start = bvec->bv_offset + i->iov_offset; + +@@ -711,13 +715,13 @@ unsigned long iov_iter_alignment(const struct iov_iter *i) + EXPORT_SYMBOL(iov_iter_alignment); + + ssize_t iov_iter_get_pages(struct iov_iter *i, +- struct page **pages, unsigned maxpages, ++ struct page **pages, size_t maxsize, unsigned maxpages, + size_t *start) + { + if (i->type & ITER_BVEC) +- return get_pages_bvec(i, pages, maxpages, start); ++ return get_pages_bvec(i, pages, maxsize, maxpages, start); + else +- return get_pages_iovec(i, pages, maxpages, start); ++ return get_pages_iovec(i, pages, maxsize, maxpages, start); + } + EXPORT_SYMBOL(iov_iter_get_pages); + diff --git a/debian/patches/bugfix/all/switch-iov_iter_get_pages-to-passing-maximal-number-.patch b/debian/patches/bugfix/all/switch-iov_iter_get_pages-to-passing-maximal-number-.patch new file mode 100644 index 000000000..033c3cc5c --- /dev/null +++ b/debian/patches/bugfix/all/switch-iov_iter_get_pages-to-passing-maximal-number-.patch @@ -0,0 +1,119 @@ +From: Al Viro +Date: Wed, 18 Jun 2014 20:34:33 -0400 +Subject: switch iov_iter_get_pages() to passing maximal number of pages +Origin: https://git.kernel.org/linus/c7f3888ad7f0932a87fb76e6e4edff2a90cc7920 + +... instead of maximal size. + +Signed-off-by: Al Viro +--- + fs/direct-io.c | 2 +- + fs/fuse/file.c | 4 ++-- + include/linux/uio.h | 2 +- + mm/iov_iter.c | 17 ++++++++--------- + 4 files changed, 12 insertions(+), 13 deletions(-) + +diff --git a/fs/direct-io.c b/fs/direct-io.c +index 17e39b0..c311640 100644 +--- a/fs/direct-io.c ++++ b/fs/direct-io.c +@@ -158,7 +158,7 @@ static inline int dio_refill_pages(struct dio *dio, struct dio_submit *sdio) + { + ssize_t ret; + +- ret = iov_iter_get_pages(sdio->iter, dio->pages, DIO_PAGES * PAGE_SIZE, ++ ret = iov_iter_get_pages(sdio->iter, dio->pages, DIO_PAGES, + &sdio->from); + + if (ret < 0 && sdio->blocks_available && (dio->rw & WRITE)) { +diff --git a/fs/fuse/file.c b/fs/fuse/file.c +index 40ac262..912061a 100644 +--- a/fs/fuse/file.c ++++ b/fs/fuse/file.c +@@ -1303,10 +1303,10 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii, + while (nbytes < *nbytesp && req->num_pages < req->max_pages) { + unsigned npages; + size_t start; +- unsigned n = req->max_pages - req->num_pages; + ssize_t ret = iov_iter_get_pages(ii, + &req->pages[req->num_pages], +- n * PAGE_SIZE, &start); ++ req->max_pages - req->num_pages, ++ &start); + if (ret < 0) + return ret; + +diff --git a/include/linux/uio.h b/include/linux/uio.h +index 09a7cff..48d64e6 100644 +--- a/include/linux/uio.h ++++ b/include/linux/uio.h +@@ -84,7 +84,7 @@ unsigned long iov_iter_alignment(const struct iov_iter *i); + void iov_iter_init(struct iov_iter *i, int direction, const struct iovec *iov, + unsigned long nr_segs, size_t count); + ssize_t iov_iter_get_pages(struct iov_iter *i, struct page **pages, +- size_t maxsize, size_t *start); ++ unsigned maxpages, size_t *start); + ssize_t iov_iter_get_pages_alloc(struct iov_iter *i, struct page ***pages, + size_t maxsize, size_t *start); + int iov_iter_npages(const struct iov_iter *i, int maxpages); +diff --git a/mm/iov_iter.c b/mm/iov_iter.c +index 7b5dbd1..ab88dc0 100644 +--- a/mm/iov_iter.c ++++ b/mm/iov_iter.c +@@ -310,7 +310,7 @@ void iov_iter_init(struct iov_iter *i, int direction, + EXPORT_SYMBOL(iov_iter_init); + + static ssize_t get_pages_iovec(struct iov_iter *i, +- struct page **pages, size_t maxsize, ++ struct page **pages, unsigned maxpages, + size_t *start) + { + size_t offset = i->iov_offset; +@@ -323,10 +323,10 @@ static ssize_t get_pages_iovec(struct iov_iter *i, + len = iov->iov_len - offset; + if (len > i->count) + len = i->count; +- if (len > maxsize) +- len = maxsize; + addr = (unsigned long)iov->iov_base + offset; + len += *start = addr & (PAGE_SIZE - 1); ++ if (len > maxpages * PAGE_SIZE) ++ len = maxpages * PAGE_SIZE; + addr &= ~(PAGE_SIZE - 1); + n = (len + PAGE_SIZE - 1) / PAGE_SIZE; + res = get_user_pages_fast(addr, n, (i->type & WRITE) != WRITE, pages); +@@ -588,15 +588,14 @@ static unsigned long alignment_bvec(const struct iov_iter *i) + } + + static ssize_t get_pages_bvec(struct iov_iter *i, +- struct page **pages, size_t maxsize, ++ struct page **pages, unsigned maxpages, + size_t *start) + { + const struct bio_vec *bvec = i->bvec; + size_t len = bvec->bv_len - i->iov_offset; + if (len > i->count) + len = i->count; +- if (len > maxsize) +- len = maxsize; ++ /* can't be more than PAGE_SIZE */ + *start = bvec->bv_offset + i->iov_offset; + + get_page(*pages = bvec->bv_page); +@@ -712,13 +711,13 @@ unsigned long iov_iter_alignment(const struct iov_iter *i) + EXPORT_SYMBOL(iov_iter_alignment); + + ssize_t iov_iter_get_pages(struct iov_iter *i, +- struct page **pages, size_t maxsize, ++ struct page **pages, unsigned maxpages, + size_t *start) + { + if (i->type & ITER_BVEC) +- return get_pages_bvec(i, pages, maxsize, start); ++ return get_pages_bvec(i, pages, maxpages, start); + else +- return get_pages_iovec(i, pages, maxsize, start); ++ return get_pages_iovec(i, pages, maxpages, start); + } + EXPORT_SYMBOL(iov_iter_get_pages); + diff --git a/debian/patches/series b/debian/patches/series index 2d8aeca4a..85502f6b6 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -393,3 +393,5 @@ features/all/mmc_block-increase-max_devices.patch bugfix/x86/drm-i915-initialise-userptr-mmu_notifier-serial-to-1.patch bugfix/all/rtsx_usb_ms-use-msleep_interruptible-in-polling-loop.patch bugfix/mips/MIPS-increase-MAX-PHYSMEM-BITS-on-Loongson-3-only.patch +bugfix/all/switch-iov_iter_get_pages-to-passing-maximal-number-.patch +bugfix/all/fuse-honour-max_read-and-max_write-in-direct_io-mode.patch