diff options
Diffstat (limited to 'net/ceph/pagevec.c')
| -rw-r--r-- | net/ceph/pagevec.c | 83 | 
1 files changed, 32 insertions, 51 deletions
diff --git a/net/ceph/pagevec.c b/net/ceph/pagevec.c index 54caf068715..555013034f7 100644 --- a/net/ceph/pagevec.c +++ b/net/ceph/pagevec.c @@ -12,38 +12,51 @@  /*   * build a vector of user pages   */ -struct page **ceph_get_direct_page_vector(const char __user *data, -						 int num_pages, -						 loff_t off, size_t len) +struct page **ceph_get_direct_page_vector(const void __user *data, +					  int num_pages, bool write_page)  {  	struct page **pages; -	int rc; +	int got = 0; +	int rc = 0;  	pages = kmalloc(sizeof(*pages) * num_pages, GFP_NOFS);  	if (!pages)  		return ERR_PTR(-ENOMEM);  	down_read(¤t->mm->mmap_sem); -	rc = get_user_pages(current, current->mm, (unsigned long)data, -			    num_pages, 0, 0, pages, NULL); +	while (got < num_pages) { +		rc = get_user_pages(current, current->mm, +		    (unsigned long)data + ((unsigned long)got * PAGE_SIZE), +		    num_pages - got, write_page, 0, pages + got, NULL); +		if (rc < 0) +			break; +		BUG_ON(rc == 0); +		got += rc; +	}  	up_read(¤t->mm->mmap_sem);  	if (rc < 0)  		goto fail;  	return pages;  fail: -	kfree(pages); +	ceph_put_page_vector(pages, got, false);  	return ERR_PTR(rc);  }  EXPORT_SYMBOL(ceph_get_direct_page_vector); -void ceph_put_page_vector(struct page **pages, int num_pages) +void ceph_put_page_vector(struct page **pages, int num_pages, bool dirty)  {  	int i; -	for (i = 0; i < num_pages; i++) +	for (i = 0; i < num_pages; i++) { +		if (dirty) +			set_page_dirty_lock(pages[i]);  		put_page(pages[i]); -	kfree(pages); +	} +	if (is_vmalloc_addr(pages)) +		vfree(pages); +	else +		kfree(pages);  }  EXPORT_SYMBOL(ceph_put_page_vector); @@ -83,7 +96,7 @@ EXPORT_SYMBOL(ceph_alloc_page_vector);   * copy user data into a page vector   */  int ceph_copy_user_to_page_vector(struct page **pages, -					 const char __user *data, +					 const void __user *data,  					 loff_t off, size_t len)  {  	int i = 0; @@ -108,17 +121,17 @@ int ceph_copy_user_to_page_vector(struct page **pages,  }  EXPORT_SYMBOL(ceph_copy_user_to_page_vector); -int ceph_copy_to_page_vector(struct page **pages, -				    const char *data, +void ceph_copy_to_page_vector(struct page **pages, +				    const void *data,  				    loff_t off, size_t len)  {  	int i = 0;  	size_t po = off & ~PAGE_CACHE_MASK;  	size_t left = len; -	size_t l;  	while (left > 0) { -		l = min_t(size_t, PAGE_CACHE_SIZE-po, left); +		size_t l = min_t(size_t, PAGE_CACHE_SIZE-po, left); +  		memcpy(page_address(pages[i]) + po, data, l);  		data += l;  		left -= l; @@ -128,21 +141,20 @@ int ceph_copy_to_page_vector(struct page **pages,  			i++;  		}  	} -	return len;  }  EXPORT_SYMBOL(ceph_copy_to_page_vector); -int ceph_copy_from_page_vector(struct page **pages, -				    char *data, +void ceph_copy_from_page_vector(struct page **pages, +				    void *data,  				    loff_t off, size_t len)  {  	int i = 0;  	size_t po = off & ~PAGE_CACHE_MASK;  	size_t left = len; -	size_t l;  	while (left > 0) { -		l = min_t(size_t, PAGE_CACHE_SIZE-po, left); +		size_t l = min_t(size_t, PAGE_CACHE_SIZE-po, left); +  		memcpy(data, page_address(pages[i]) + po, l);  		data += l;  		left -= l; @@ -152,41 +164,10 @@ int ceph_copy_from_page_vector(struct page **pages,  			i++;  		}  	} -	return len;  }  EXPORT_SYMBOL(ceph_copy_from_page_vector);  /* - * copy user data from a page vector into a user pointer - */ -int ceph_copy_page_vector_to_user(struct page **pages, -					 char __user *data, -					 loff_t off, size_t len) -{ -	int i = 0; -	int po = off & ~PAGE_CACHE_MASK; -	int left = len; -	int l, bad; - -	while (left > 0) { -		l = min_t(int, left, PAGE_CACHE_SIZE-po); -		bad = copy_to_user(data, page_address(pages[i]) + po, l); -		if (bad == l) -			return -EFAULT; -		data += l - bad; -		left -= l - bad; -		if (po) { -			po += l - bad; -			if (po == PAGE_CACHE_SIZE) -				po = 0; -		} -		i++; -	} -	return len; -} -EXPORT_SYMBOL(ceph_copy_page_vector_to_user); - -/*   * Zero an extent within a page vector.  Offset is relative to the   * start of the first page.   */  | 
