[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH 2/2] xen/privcmd: add PRIVCMD_MMAPBATCH_V2 ioctl



On Aug 31, 2012, at 9:08 AM, David Vrabel wrote:

> On 30/08/12 19:32, Andres Lagar-Cavilla wrote:
>> Second repost of my version, heavily based on David's. 
> 
> Doing another allocation that may be larger than a page (and its
> associated additional error paths) seems to me to be a hammer to crack
> the (admittedly bit wonky) casting nut.
> 
> That said, it's up to Konrad which version he prefers.

Yeah absolutely.

> 
> There are also some minor improvements you could make if you respin this
> patch.
> 
>> Complementary to this patch, on the xen tree I intend to add
>> PRIVCMD_MMAPBATCH_*_ERROR into the libxc header files, and remove
>> XEN_DOMCTL_PFINFO_PAGEDTAB from domctl.h
> 
> Yes, a good idea.  There's no correspondence between the ioctl's error
> reporting values and the DOMCTL_PFINFO flags.
> 
>> commit 3f40e8d79b7e032527ee207a97499ddbc81ca12b
>> Author: Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>
>> Date:   Thu Aug 30 12:23:33 2012 -0400
>> 
>>    xen/privcmd: add PRIVCMD_MMAPBATCH_V2 ioctl
>> 
>>    PRIVCMD_MMAPBATCH_V2 extends PRIVCMD_MMAPBATCH with an additional
>>    field for reporting the error code for every frame that could not be
>>    mapped.  libxc prefers PRIVCMD_MMAPBATCH_V2 over PRIVCMD_MMAPBATCH.
>> 
>>    Also expand PRIVCMD_MMAPBATCH to return appropriate error-encoding top 
>> nibble
>>    in the mfn array.
>> 
>>    Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx>
>>    Signed-off-by: Andres Lagar-Cavilla <andres@xxxxxxxxxxxxxxxx>
> [...]
>> -static long privcmd_ioctl_mmap_batch(void __user *udata)
>> +static long privcmd_ioctl_mmap_batch(void __user *udata, int version)
>> {
>>      int ret;
>> -    struct privcmd_mmapbatch m;
>> +    struct privcmd_mmapbatch_v2 m;
>>      struct mm_struct *mm = current->mm;
>>      struct vm_area_struct *vma;
>>      unsigned long nr_pages;
>>      LIST_HEAD(pagelist);
>> +    int *err_array;
> 
> int *err_array = NULL;
> 
> and you could avoid the additional jump label as kfree(NULL) is safe.

Didn't know, great.

> 
>>      struct mmap_batch_state state;
>> 
>>      if (!xen_initial_domain())
>>              return -EPERM;
>> 
>> -    if (copy_from_user(&m, udata, sizeof(m)))
>> -            return -EFAULT;
>> +    switch (version) {
>> +    case 1:
>> +            if (copy_from_user(&m, udata, sizeof(struct privcmd_mmapbatch)))
>> +                    return -EFAULT;
>> +            /* Returns per-frame error in m.arr. */
>> +            m.err = NULL;
>> +            if (!access_ok(VERIFY_WRITE, m.arr, m.num * sizeof(*m.arr)))
>> +                    return -EFAULT;
>> +            break;
>> +    case 2:
>> +            if (copy_from_user(&m, udata, sizeof(struct 
>> privcmd_mmapbatch_v2)))
>> +                    return -EFAULT;
>> +            /* Returns per-frame error code in m.err. */
>> +            if (!access_ok(VERIFY_WRITE, m.err, m.num * (sizeof(*m.err))))
>> +                    return -EFAULT;
>> +            break;
>> +    default:
>> +            return -EINVAL;
>> +    }
>> 
>>      nr_pages = m.num;
>>      if ((m.num <= 0) || (nr_pages > (LONG_MAX >> PAGE_SHIFT)))
>>              return -EINVAL;
>> 
>> -    ret = gather_array(&pagelist, m.num, sizeof(xen_pfn_t),
>> -                       m.arr);
>> +    ret = gather_array(&pagelist, m.num, sizeof(xen_pfn_t), m.arr);
>> 
>>      if (ret || list_empty(&pagelist))
>> -            goto out;
>> +            goto out_no_err_array;
>> +
>> +    err_array = kmalloc_array(m.num, sizeof(int), GFP_KERNEL);
> 
> kcalloc() (see below).
> 
>> +    if (err_array == NULL)
>> +    {
> 
> Style: if (err_array == NULL) {
> 
>> +    if (state.global_error) {
>> +            int efault;
>> +
>> +            if (state.global_error == -ENOENT)
>> +                    ret = -ENOENT;
>> +
>> +            /* Write back errors in second pass. */
>> +            state.user_mfn = (xen_pfn_t *)m.arr;
>> +            state.user_err = m.err;
>> +            state.err      = err_array;
>> +            efault = traverse_pages(m.num, sizeof(xen_pfn_t),
>> +                                     &pagelist, mmap_return_errors, &state);
>> +            if (efault)
>> +                    ret = efault;
>> +    } else if (m.err)
>> +            ret = __clear_user(m.err, m.num * sizeof(*m.err));
> 
> Since you have an array of errors already there's no need to iterate
> through all the MFNs again for V2.  A simple copy_to_user() is
> sufficient provided err_array was zeroed with kcalloc().
I can kcalloc for extra paranoia, but the code will set all error slots, and is 
guaranteed to not jump over anything. I +1 the shortcut you outline below. 
Re-spin coming.
Andres
> 
> if (m.err)
>    ret = __copy_to_user(m.err, err_array, m.num * sizeof(*m.err));
> else {
>    /* Write back errors in second pass. */
>    state.user_mfn = (xen_pfn_t *)m.arr;
>    state.user_err = m.err;
>    state.err      = err_array;
>    ret = traverse_pages(m.num, sizeof(xen_pfn_t),
>            &pagelist, mmap_return_errors, &state);
> }
> 
> if (ret == 0 && state.global_error == -ENOENT)
>    ret = -ENOENT;
> 
> David


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.