|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 3/3] Port of mmap_batch_v2 to support paging in Xen
On Fri, Dec 16, 2011 at 10:22:21PM -0500, Adin Scannell wrote:
> This wasn't ported from any patch, but was rewritten based on the XCP 2.6.32
> tree. The code structure is significantly different and this patch mirrors
> the
> existing Linux code.
>
> The primary reason for need the V2 interface is to support foreign mappings
> (i.e. qemu) of paged-out pages. The libxc code will already retry mappings
> when an ENOENT is returned. The V2 interface provides a richer error value,
> so the user-space code is capable of handling these errors specifically.
Can you give more details on how to use paged-out pages. Perhaps a
pointer to the xen's docs?
>
> Signed-off-by: Adin Scannell <adin@xxxxxxxxxxx>
>
> Index: linux/drivers/xen/xenfs/privcmd.c
> ===================================================================
> ---
> drivers/xen/xenfs/privcmd.c | 90
> ++++++++++++++++++++++++++++++++++++++++++-
So that file just moved to drivers/xen/privcmd.c
> include/xen/privcmd.h | 10 +++++
> 2 files changed, 99 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/xen/xenfs/privcmd.c b/drivers/xen/xenfs/privcmd.c
> index dbd3b16..21cbb5a 100644
> --- a/drivers/xen/xenfs/privcmd.c
> +++ b/drivers/xen/xenfs/privcmd.c
> @@ -70,7 +70,7 @@ static void free_page_list(struct list_head *pages)
> */
> static int gather_array(struct list_head *pagelist,
> unsigned nelem, size_t size,
> - void __user *data)
> + const void __user *data)
> {
> unsigned pageidx;
> void *pagedata;
> @@ -245,6 +245,15 @@ struct mmap_batch_state {
> xen_pfn_t __user *user;
> };
>
> +struct mmap_batch_v2_state {
> + domid_t domain;
> + unsigned long va;
> + struct vm_area_struct *vma;
> + int paged_out;
Should this be unsigned int?
> +
> + int __user *err;
> +};
> +
> static int mmap_batch_fn(void *data, void *state)
> {
> xen_pfn_t *mfnp = data;
> @@ -260,6 +269,20 @@ static int mmap_batch_fn(void *data, void *state)
> return 0;
> }
>
> +static int mmap_batch_v2_fn(void *data, void *state)
> +{
> + xen_pfn_t *mfnp = data;
> + struct mmap_batch_v2_state *st = state;
> +
> + int rc = xen_remap_domain_mfn_range(st->vma, st->va & PAGE_MASK, *mfnp,
> 1,
> + st->vma->vm_page_prot, st->domain);
You don't want to check that st is not NULL?
> + if ( rc == -ENOENT )
This is the wrong style. Please fix.
> + st->paged_out++;
Is it possible that this ends overflowing and hitting 0?
> + st->va += PAGE_SIZE;
> +
> + return put_user(rc, st->err++);
> +}
> +
> static int mmap_return_errors(void *data, void *state)
> {
> xen_pfn_t *mfnp = data;
> @@ -332,6 +355,67 @@ out:
> return ret;
> }
>
> +static long privcmd_ioctl_mmap_batch_v2(void __user *udata)
> +{
> + int ret;
> + struct privcmd_mmapbatch_v2 m;
> + struct mm_struct *mm = current->mm;
> + struct vm_area_struct *vma = NULL;
> + unsigned long nr_pages;
> + LIST_HEAD(pagelist);
> + struct mmap_batch_v2_state state;
> +
> + if (!xen_initial_domain())
> + return -EPERM;
> +
> + if (copy_from_user(&m, udata, sizeof(m)))
> + return -EFAULT;
> +
> + nr_pages = m.num;
> + if ((m.num <= 0) || (nr_pages > (ULONG_MAX >> PAGE_SHIFT)))
Just make it nr_pages instead of m.num.
> + return -EINVAL;
> +
> + ret = gather_array(&pagelist, m.num, sizeof(xen_pfn_t),
nr_pages.
> + m.arr);
> +
> + if (ret || list_empty(&pagelist))
> + goto out;
> +
> + down_write(&mm->mmap_sem);
> +
> + vma = find_vma(mm, m.addr);
> + ret = -EINVAL;
> + /* We allow multiple shots here, because this interface
> + * is used by libxc and mappings for specific pages will
> + * be retried when pages are paged-out (ENOENT). */
> + if (!vma ||
> + vma->vm_ops != &privcmd_vm_ops ||
> + (m.addr < vma->vm_start) ||
> + ((m.addr + (nr_pages << PAGE_SHIFT)) > vma->vm_end)) {
> + up_write(&mm->mmap_sem);
> + goto out;
> + }
> +
> + state.domain = m.dom;
Should you check the m.dom for incorrect ones? Like -1? or DOMID_IO?
> + state.vma = vma;
> + state.va = m.addr;
> + state.err = m.err;
> + state.paged_out = 0;
> +
> + up_write(&mm->mmap_sem);
> +
> + ret = traverse_pages(m.num, sizeof(xen_pfn_t),
> + &pagelist, mmap_batch_v2_fn, &state);
> +
> +out:
> + free_page_list(&pagelist);
> +
> + if ( (ret == 0) && (state.paged_out > 0) )
> + return -ENOENT;
> + else
> + return ret;
> +}
> +
> static long privcmd_ioctl(struct file *file,
> unsigned int cmd, unsigned long data)
> {
> @@ -351,6 +435,10 @@ static long privcmd_ioctl(struct file *file,
> ret = privcmd_ioctl_mmap_batch(udata);
> break;
>
> + case IOCTL_PRIVCMD_MMAPBATCH_V2:
> + ret = privcmd_ioctl_mmap_batch_v2(udata);
> + break;
> +
> default:
> ret = -EINVAL;
> break;
> diff --git a/include/xen/privcmd.h b/include/xen/privcmd.h
> index 17857fb..39b92b1 100644
> --- a/include/xen/privcmd.h
> +++ b/include/xen/privcmd.h
> @@ -62,6 +62,14 @@ struct privcmd_mmapbatch {
> xen_pfn_t __user *arr; /* array of mfns - top nibble set on err */
> };
>
> +struct privcmd_mmapbatch_v2 {
> + int num; /* number of pages to populate */
> + domid_t dom; /* target domain */
> + __u64 addr; /* virtual address */
> + const xen_pfn_t __user *arr; /* array of mfns */
> + int __user *err; /* array of error codes */
> +};
> +
> /*
> * @cmd: IOCTL_PRIVCMD_HYPERCALL
> * @arg: &privcmd_hypercall_t
> @@ -73,5 +81,7 @@ struct privcmd_mmapbatch {
> _IOC(_IOC_NONE, 'P', 2, sizeof(struct privcmd_mmap))
> #define IOCTL_PRIVCMD_MMAPBATCH \
> _IOC(_IOC_NONE, 'P', 3, sizeof(struct privcmd_mmapbatch))
> +#define IOCTL_PRIVCMD_MMAPBATCH_V2 \
> + _IOC(_IOC_NONE, 'P', 4, sizeof(struct privcmd_mmapbatch_v2))
>
> #endif /* __LINUX_PUBLIC_PRIVCMD_H__ */
> --
> 1.6.2.5
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |