--- v1
+++ v3
@@ -7,38 +7,99 @@
This is part a tree-wide conversion, as described in commit fc1d8e7cca2d
("mm: introduce put_user_page*(), placeholder versions").
-Cc: Mike Marshall <hubcap@omnibond.com>
-Cc: Martin Brandenburg <martin@omnibond.com>
-Cc: devel@lists.orangefs.org
+This also handles pages[i] = NULL cases, thanks to an approach
+that is actually written by Juergen Gross.
+
+Signed-off-by: Juergen Gross <jgross@suse.com>
+
+Cc: Boris Ostrovsky <boris.ostrovsky@oracle.com>
+Cc: xen-devel@lists.xenproject.org
Signed-off-by: John Hubbard <jhubbard@nvidia.com>
---
- fs/orangefs/orangefs-bufmap.c | 7 ++-----
- 1 file changed, 2 insertions(+), 5 deletions(-)
+ drivers/xen/privcmd.c | 32 +++++++++++---------------------
+ 1 file changed, 11 insertions(+), 21 deletions(-)
-diff --git a/fs/orangefs/orangefs-bufmap.c b/fs/orangefs/orangefs-bufmap.c
-index 2bb916d68576..f2f33a16d604 100644
---- a/fs/orangefs/orangefs-bufmap.c
-+++ b/fs/orangefs/orangefs-bufmap.c
-@@ -168,10 +168,7 @@ static DEFINE_SPINLOCK(orangefs_bufmap_lock);
- static void
- orangefs_bufmap_unmap(struct orangefs_bufmap *bufmap)
+diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
+index c6070e70dd73..c7d0763ca8c2 100644
+--- a/drivers/xen/privcmd.c
++++ b/drivers/xen/privcmd.c
+@@ -582,10 +582,11 @@ static long privcmd_ioctl_mmap_batch(
+
+ static int lock_pages(
+ struct privcmd_dm_op_buf kbufs[], unsigned int num,
+- struct page *pages[], unsigned int nr_pages)
++ struct page *pages[], unsigned int *nr_pages)
{
-- int i;
--
-- for (i = 0; i < bufmap->page_count; i++)
-- put_page(bufmap->page_array[i]);
-+ put_user_pages(bufmap->page_array, bufmap->page_count);
+- unsigned int i;
++ unsigned int i, free = *nr_pages;
+
++ *nr_pages = 0;
+ for (i = 0; i < num; i++) {
+ unsigned int requested;
+ int pinned;
+@@ -593,35 +594,22 @@ static int lock_pages(
+ requested = DIV_ROUND_UP(
+ offset_in_page(kbufs[i].uptr) + kbufs[i].size,
+ PAGE_SIZE);
+- if (requested > nr_pages)
++ if (requested > free)
+ return -ENOSPC;
+
+ pinned = get_user_pages_fast(
+ (unsigned long) kbufs[i].uptr,
+- requested, FOLL_WRITE, pages);
++ requested, FOLL_WRITE, pages + *nr_pages);
+ if (pinned < 0)
+ return pinned;
+
+- nr_pages -= pinned;
+- pages += pinned;
++ free -= pinned;
++ *nr_pages += pinned;
+ }
+
+ return 0;
}
- static void
-@@ -280,7 +277,7 @@ orangefs_bufmap_map(struct orangefs_bufmap *bufmap,
+-static void unlock_pages(struct page *pages[], unsigned int nr_pages)
+-{
+- unsigned int i;
+-
+- if (!pages)
+- return;
+-
+- for (i = 0; i < nr_pages; i++) {
+- if (pages[i])
+- put_page(pages[i]);
+- }
+-}
+-
+ static long privcmd_ioctl_dm_op(struct file *file, void __user *udata)
+ {
+ struct privcmd_data *data = file->private_data;
+@@ -681,11 +669,12 @@ static long privcmd_ioctl_dm_op(struct file *file, void __user *udata)
- for (i = 0; i < ret; i++) {
- SetPageError(bufmap->page_array[i]);
-- put_page(bufmap->page_array[i]);
-+ put_user_page(bufmap->page_array[i]);
- }
- return -ENOMEM;
+ xbufs = kcalloc(kdata.num, sizeof(*xbufs), GFP_KERNEL);
+ if (!xbufs) {
++ nr_pages = 0;
+ rc = -ENOMEM;
+ goto out;
}
+
+- rc = lock_pages(kbufs, kdata.num, pages, nr_pages);
++ rc = lock_pages(kbufs, kdata.num, pages, &nr_pages);
+ if (rc)
+ goto out;
+
+@@ -699,7 +688,8 @@ static long privcmd_ioctl_dm_op(struct file *file, void __user *udata)
+ xen_preemptible_hcall_end();
+
+ out:
+- unlock_pages(pages, nr_pages);
++ if (pages)
++ put_user_pages(pages, nr_pages);
+ kfree(xbufs);
+ kfree(pages);
+ kfree(kbufs);
--
2.22.0