[PATCH] xen/privcmd: sprinkle around cond_resched() calls in mmap ioctl handling

Jan Beulich
2016-07-07T07:35:09Z

Many of these operations can take arbitrarily long, which can become a
problem irrespective of them being exposed to privileged users only.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
---
drivers/xen/privcmd.c | 18 ++++++++++++++----
1 file changed, 14 insertions(+), 4 deletions(-)

--- 4.7-rc6-xen.orig/drivers/xen/privcmd.c
+++ 4.7-rc6-xen/drivers/xen/privcmd.c
@@ -69,9 +69,13 @@ static long privcmd_ioctl_hypercall(void
static void free_page_list(struct list_head *pages)
{
struct page *p, *n;
+ unsigned idx = 0;

- list_for_each_entry_safe(p, n, pages, lru)
+ list_for_each_entry_safe(p, n, pages, lru) {
+ if (!(++idx & 7))
+ cond_resched();
__free_page(p);
+ }

INIT_LIST_HEAD(pages);
}
@@ -103,6 +107,8 @@ static int gather_array(struct list_head
if (page == NULL)
goto fail;

+ if (pagedata)
+ cond_resched();
pagedata = page_address(page);

list_add_tail(&page->lru, pagelist);
@@ -144,6 +150,9 @@ static int traverse_pages(unsigned nelem
while (nelem--) {
if (pageidx > PAGE_SIZE-size) {
struct page *page;
+
+ if (pagedata)
+ cond_resched();
pos = pos->next;
page = list_entry(pos, struct page, lru);
pagedata = page_address(page);
@@ -169,16 +178,17 @@ static int traverse_pages_block(unsigned
void *state)
{
void *pagedata;
- unsigned pageidx;
+ unsigned pageidx = 0;
int ret = 0;

BUG_ON(size > PAGE_SIZE);

- pageidx = PAGE_SIZE;
-
while (nelem) {
int nr = (PAGE_SIZE/size);
struct page *page;
+
+ if (pageidx++)
+ cond_resched();
if (nr > nelem)
nr = nelem;
pos = pos->next;