On Sat, Jan 29, 2011 at 09:10:00PM +0100, Juergen Lock wrote:
> Hi!
> 
>  I was kinda hoping to be able to post a correct patch in public but
> getting an answer to ${Subject} seems to be more difficult than I
> thought... :)  So, does anyone here know?  copyout_map() and
You do not need Giant locked for vm_map* functions.

> copyout_unmap() are copied from ksyms_map() from sys/dev/ksyms/ksyms.c
> - should there maybe be global versions instead of two static copies
> each, and what would be good names?  And giant is taken by linux_ioctl()
Would you make a patch for this ?

> in the same source file before calling the parts I added.  So here
> comes the patch, it is to add support for dvb ioctls to the linuxolator
> as discussed on -emulation earlier in this thread:
> 
>       
> http://lists.freebsd.org/pipermail/freebsd-multimedia/2011-January/011575.html
> 
> (patch also at:
> 
>       http://people.freebsd.org/~nox/dvb/linux-dvb.patch
> 
> and a version for 8, which is what I tested with w_scan on dvb-s2
> and dvb-t, and Andrew Gallatin also tested it with SageTV:
> 
>       http://people.freebsd.org/~nox/dvb/linux-dvb-8.patch
> 
> )
> 
>  Thanx!
>       Juergen
> 
> Index: src/sys/compat/linux/linux_ioctl.c
> ===================================================================
> RCS file: /home/scvs/src/sys/compat/linux/linux_ioctl.c,v
> retrieving revision 1.167
> diff -u -p -r1.167 linux_ioctl.c
> --- src/sys/compat/linux/linux_ioctl.c        30 Dec 2010 02:18:04 -0000      
> 1.167
> +++ src/sys/compat/linux/linux_ioctl.c        18 Jan 2011 17:10:21 -0000
> @@ -59,6 +59,14 @@ __FBSDID("$FreeBSD: src/sys/compat/linux
>  #include <sys/sx.h>
>  #include <sys/tty.h>
>  #include <sys/uio.h>
> +#include <sys/types.h>
> +#include <sys/mman.h>
> +#include <sys/resourcevar.h>
> +
> +#include <vm/vm.h>
> +#include <vm/pmap.h>
> +#include <vm/vm_extern.h>
> +#include <vm/vm_map.h>
>  
>  #include <net/if.h>
>  #include <net/if_dl.h>
> @@ -83,6 +91,9 @@ __FBSDID("$FreeBSD: src/sys/compat/linux
>  #include <compat/linux/linux_videodev.h>
>  #include <compat/linux/linux_videodev_compat.h>
>  
> +#include <compat/linux/linux_dvb.h>
> +#include <compat/linux/linux_dvb_compat.h>
> +
>  CTASSERT(LINUX_IFNAMSIZ == IFNAMSIZ);
>  
>  static linux_ioctl_function_t linux_ioctl_cdrom;
> @@ -97,6 +108,7 @@ static linux_ioctl_function_t linux_ioct
>  static linux_ioctl_function_t linux_ioctl_drm;
>  static linux_ioctl_function_t linux_ioctl_sg;
>  static linux_ioctl_function_t linux_ioctl_v4l;
> +static linux_ioctl_function_t linux_ioctl_dvb;
>  static linux_ioctl_function_t linux_ioctl_special;
>  static linux_ioctl_function_t linux_ioctl_fbsd_usb;
>  
> @@ -124,6 +136,8 @@ static struct linux_ioctl_handler sg_han
>  { linux_ioctl_sg, LINUX_IOCTL_SG_MIN, LINUX_IOCTL_SG_MAX };
>  static struct linux_ioctl_handler video_handler =
>  { linux_ioctl_v4l, LINUX_IOCTL_VIDEO_MIN, LINUX_IOCTL_VIDEO_MAX };
> +static struct linux_ioctl_handler dvb_handler =
> +{ linux_ioctl_dvb, LINUX_IOCTL_DVB_MIN, LINUX_IOCTL_DVB_MAX };
>  static struct linux_ioctl_handler fbsd_usb =
>  { linux_ioctl_fbsd_usb, FBSD_LUSB_MIN, FBSD_LUSB_MAX };
>  
> @@ -139,6 +153,7 @@ DATA_SET(linux_ioctl_handler_set, privat
>  DATA_SET(linux_ioctl_handler_set, drm_handler);
>  DATA_SET(linux_ioctl_handler_set, sg_handler);
>  DATA_SET(linux_ioctl_handler_set, video_handler);
> +DATA_SET(linux_ioctl_handler_set, dvb_handler);
>  DATA_SET(linux_ioctl_handler_set, fbsd_usb);
>  
>  struct handler_element
> @@ -2989,6 +3004,251 @@ linux_ioctl_special(struct thread *td, s
>  }
>  
>  /*
> + * Map some anonymous memory in user space of size sz, rounded up to the page
> + * boundary.
> + */
> +static int
> +copyout_map(struct thread *td, vm_offset_t *addr, size_t sz)
> +{
> +     struct vmspace *vms = td->td_proc->p_vmspace;
Style recommends not to initialize in the declaration section.
[I do not repeat systematic style violations notes below].

> +     int error;
> +     vm_size_t size;
> +
> +
One empty line is enough.

> +     /*
> +      * Map somewhere after heap in process memory.
> +      */
> +     PROC_LOCK(td->td_proc);
> +     *addr = round_page((vm_offset_t)vms->vm_daddr +
> +         lim_max(td->td_proc, RLIMIT_DATA));
> +     PROC_UNLOCK(td->td_proc);
Are you sure that this is needed ? Why not leave the address selection
to the VM ?

> +
> +     /* round size up to page boundry */
> +     size = (vm_size_t) round_page(sz);
> +
> +     error = vm_mmap(&vms->vm_map, addr, size, PROT_READ | PROT_WRITE,
> +         VM_PROT_ALL, MAP_PRIVATE | MAP_ANON, OBJT_DEFAULT, NULL, 0);
> +
> +     return (error);
> +}
> +
> +/*
> + * Unmap memory in user space.
> + */
> +static int
> +copyout_unmap(struct thread *td, vm_offset_t addr, size_t sz)
> +{
> +     vm_map_t map;
> +     vm_size_t size;
> +
> +     map = &td->td_proc->p_vmspace->vm_map;
> +     size = (vm_size_t) round_page(sz);
> +
> +     if (!vm_map_remove(map, addr, addr + size))
Better do if (vm_map_remove(...) != KERN_SUCCESS)

> +             return (EINVAL);
> +
> +     return (0);
> +}
> +
> +static int
> +linux_to_bsd_dtv_properties(struct l_dtv_properties *lvps, struct 
> dtv_properties *vps)
> +{
Empty line between (empty) declaration section and executable statements.

> +     vps->num = lvps->num;
> +     vps->props = PTRIN(lvps->props);        /* possible pointer size 
> conversion */
> +     return (0);
> +}
> +
> +static int
> +linux_to_bsd_dtv_property(struct l_dtv_property *lvp, struct dtv_property 
> *vp)
> +{
> +     /*
> +      * everything until u.buffer.reserved2 is fixed size so
> +      * just memcpy it.
> +      */
> +     memcpy(vp, lvp, offsetof(struct l_dtv_property, u.buffer.reserved2));
> +     /*
> +      * the pointer may be garbage since it's part of a union,
> +      * currently no Linux code uses it so just set it to NULL.
> +      */
> +     vp->u.buffer.reserved2 = NULL;
> +     vp->result = lvp->result;
> +     return (0);
> +}
> +
> +static int
> +bsd_to_linux_dtv_property(struct dtv_property *vp, struct l_dtv_property 
> *lvp)
> +{
> +     /*
> +      * everything until u.buffer.reserved2 is fixed size so
> +      * just memcpy it.
> +      */
> +     memcpy(lvp, vp, offsetof(struct l_dtv_property, u.buffer.reserved2));
> +     /*
> +      * the pointer may be garbage since it's part of a union,
> +      * currently no Linux code uses it so just set it to NULL.
> +      */
> +     lvp->u.buffer.reserved2 = PTROUT(NULL);
> +     lvp->result = vp->result;
> +     return (0);
> +}
> +
> +static int
> +linux_ioctl_dvb(struct thread *td, struct linux_ioctl_args *args)
> +{
> +     struct file *fp;
> +     int error, i;
> +     struct l_dtv_properties l_vps;
> +     struct dtv_properties vps;
> +     struct l_dtv_property *l_vp = NULL, *l_p;
> +     struct dtv_property *vp = NULL, *p;
> +     size_t l_propsiz, propsiz;
> +     vm_offset_t uvp;
> +
> +     switch (args->cmd & 0xffff) {
> +     case LINUX_AUDIO_STOP:
> +     case LINUX_AUDIO_PLAY:
> +     case LINUX_AUDIO_PAUSE:
> +     case LINUX_AUDIO_CONTINUE:
> +     case LINUX_AUDIO_SELECT_SOURCE:
> +     case LINUX_AUDIO_SET_MUTE:
> +     case LINUX_AUDIO_SET_AV_SYNC:
> +     case LINUX_AUDIO_SET_BYPASS_MODE:
> +     case LINUX_AUDIO_CHANNEL_SELECT:
> +     case LINUX_AUDIO_CLEAR_BUFFER:
> +     case LINUX_AUDIO_SET_ID:
> +     case LINUX_AUDIO_SET_STREAMTYPE:
> +     case LINUX_AUDIO_SET_EXT_ID:
> +     case LINUX_AUDIO_BILINGUAL_CHANNEL_SELECT:
> +     case LINUX_DMX_START:
> +     case LINUX_DMX_STOP:
> +     case LINUX_DMX_SET_BUFFER_SIZE:
> +     case LINUX_NET_REMOVE_IF:
> +     case LINUX_FE_DISEQC_RESET_OVERLOAD:
> +     case LINUX_FE_DISEQC_SEND_BURST:
> +     case LINUX_FE_SET_TONE:
> +     case LINUX_FE_SET_VOLTAGE:
> +     case LINUX_FE_ENABLE_HIGH_LNB_VOLTAGE:
> +     case LINUX_FE_DISHNETWORK_SEND_LEGACY_CMD:
> +     case LINUX_FE_SET_FRONTEND_TUNE_MODE:
> +     case LINUX_CA_RESET:
> +             if ((args->cmd & IOC_DIRMASK) != LINUX_IOC_VOID)
> +                     return ENOIOCTL;
> +             args->cmd = (args->cmd & 0xffff) | IOC_VOID;
> +             break;
> +
> +     case LINUX_DMX_REMOVE_PID:
> +             /* overlaps with LINUX_NET_ADD_IF */
> +             if ((args->cmd & IOC_DIRMASK) == LINUX_IOC_INOUT)
> +                     goto net_add_if;
> +             /* FALLTHRU */
> +     case LINUX_AUDIO_SET_MIXER:
> +     case LINUX_AUDIO_SET_ATTRIBUTES:
> +     case LINUX_AUDIO_SET_KARAOKE:
> +     case LINUX_DMX_SET_FILTER:
> +     case LINUX_DMX_SET_PES_FILTER:
> +     case LINUX_DMX_SET_SOURCE:
> +     case LINUX_DMX_ADD_PID:
> +     case LINUX_FE_DISEQC_SEND_MASTER_CMD:
> +     case LINUX_FE_SET_FRONTEND:
> +     case LINUX_CA_SEND_MSG:
> +     case LINUX_CA_SET_DESCR:
> +     case LINUX_CA_SET_PID:
> +             args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_IN;
> +             break;
> +
> +     case LINUX_AUDIO_GET_STATUS:
> +     case LINUX_AUDIO_GET_CAPABILITIES:
> +     case LINUX_AUDIO_GET_PTS:
> +     case LINUX_DMX_GET_PES_PIDS:
> +     case LINUX_DMX_GET_CAPS:
> +     case LINUX_FE_GET_INFO:
> +     case LINUX_FE_DISEQC_RECV_SLAVE_REPLY:
> +     case LINUX_FE_READ_STATUS:
> +     case LINUX_FE_READ_BER:
> +     case LINUX_FE_READ_SIGNAL_STRENGTH:
> +     case LINUX_FE_READ_SNR:
> +     case LINUX_FE_READ_UNCORRECTED_BLOCKS:
> +     case LINUX_FE_GET_FRONTEND:
> +     case LINUX_FE_GET_EVENT:
> +     case LINUX_CA_GET_CAP:
> +     case LINUX_CA_GET_SLOT_INFO:
> +     case LINUX_CA_GET_DESCR_INFO:
> +     case LINUX_CA_GET_MSG:
> +             args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_OUT;
> +             break;
> +
> +     case LINUX_DMX_GET_STC:
> +     case LINUX_NET_GET_IF:
> +     net_add_if:
> +             args->cmd = (args->cmd & ~IOC_DIRMASK) | IOC_INOUT;
> +             break;
> +
> +     case LINUX_FE_SET_PROPERTY:
> +     case LINUX_FE_GET_PROPERTY:
> +             error = copyin((void *) args->arg, &l_vps, sizeof(l_vps));
> +             if (error)
> +                     return (error);
> +             linux_to_bsd_dtv_properties(&l_vps, &vps);
> +             if ((vps.num == 0) || vps.num > DTV_IOCTL_MAX_MSGS)
> +                     return EINVAL;
> +
> +             l_propsiz = vps.num * sizeof(*l_vp);
> +             propsiz = vps.num * sizeof(*vp);
> +             if (((l_vp = malloc(l_propsiz, M_LINUX, M_WAITOK)) == NULL) ||
> +                 (vp = malloc(propsiz, M_LINUX, M_WAITOK)) == NULL) {
Malloc(M_WAITOK) is guaranteed to never return NULL, you do not need the
checks.

> +                     error = ENOMEM;
> +                     goto out2;
> +             }
> +             error = copyin((void *) vps.props, l_vp, l_propsiz);
> +             if (error)
> +                     goto out2;
> +             for (i = vps.num, l_p = l_vp, p = vp; i--; ++l_p, ++p)
> +                     linux_to_bsd_dtv_property(l_p, p);
> +
> +             error = copyout_map(td, &uvp, propsiz);
> +             if (error)
> +                     goto out2;
> +             copyout(vp, (void *) uvp, propsiz);
> +
> +             if ((error = fget(td, args->fd, &fp)) != 0) {
> +                     (void) copyout_unmap(td, uvp, propsiz);
> +                     goto out2;
> +             }
> +             vps.props = (void *) uvp;
> +             if ((args->cmd & 0xffff) == LINUX_FE_SET_PROPERTY)
> +                     error = fo_ioctl(fp, FE_SET_PROPERTY, &vps, 
> td->td_ucred, td);
> +             else
> +                     error = fo_ioctl(fp, FE_GET_PROPERTY, &vps, 
> td->td_ucred, td);
> +             if (error) {
> +                     (void) copyout_unmap(td, uvp, propsiz);
> +                     goto out;
> +             }
> +             error = copyin((void *) uvp, vp, propsiz);
> +             (void) copyout_unmap(td, uvp, propsiz);
No need in space between cast and expression. Bigger issue is that I
do not understand this fragment. You do copyout_map(), and then
immediately call copyout_unmap() for the address range returned
by copyout_map(), or am I missing something ?

[snip]

Attachment: pgpbxpAy7dSR4.pgp
Description: PGP signature

Reply via email to