[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
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |