Date: Mon, 25 Jul 2005 18:14:05 -0600 From: Scott Long <scottl@samsco.org> To: Felix-KM@yandex.ru Cc: freebsd-hackers@freebsd.org Subject: Re: how to use the function copyout() Message-ID: <42E5804D.4030206@samsco.org> In-Reply-To: <42E578E7.7050307@samsco.org> References: <42E4DC88.000006.21996@camay.yandex.ru> <42E578E7.7050307@samsco.org>
next in thread | previous in thread | raw e-mail | index | archive | help
Scott Long wrote: > Felix-KM wrote: > >> I can't understand how to use the function copyout(). >> It is necessary to write the data from a device driver to the >> array defined in user program. >> I do it this way: >> >> #define IOCTL_GET_B _IOWR("F", 127, 0x4) >> > > What you've declared here is an ioctl that will copy in 4 bytes of > user data on entry, and copy out 4 bytes back out on exit. The argument > that you supply to the ioctl(2) must be a pointer to a 4 byte word that > you want to copy. This probably isn't what you want. Based on your > code snippets, you want: > > #define IOCTL_GET_B _IOW("F", 127, unsigned short) > > static int my_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int > flag, struct thread *td) > { > unsigned short data; > [...] > > case IOCTL_GET_B: > *(unsigned short *)arg = data; > break; > [...] > > > Similar code will work for all integral types, as well as simple > structures. The generic ioctl layer will handle all of the copying > magic for you. Copying compound structures (ones that have pointers > to other data that you also want to copy) require explicit copyin > or copyout operations on the pointers that are embedded into the > struct. Likewise, copying arbitrary data that isn't a structure or > integral type (like an array) also requires an explicit copy operation. > You could do something like the following: > > struct mysubdata { > int foo; > int bar; > }; > > struct mystruct { > struct mysubdata *msd; > }; > > #define IOCTL_SET_COMPOUNT_STRUCT _IOR("F", 123, struct mystruct) > #define IOCTL_SET_BIGDATA _IO("F", 124") > > static int my_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int > flag, struct thread *td) > { > struct mystruct *ms; > struct mysubdata msd; > char *bigdata *bd; > > [...] > > case IOCTL_SET_COMPOUNT_STRUCT: > ms = *(struct mystruct *)arg; > copyin(ms->msd, &msd, sizeof(struct mysubdata)); > break; > case IOCTL_SET_BIGDATA: > bd = malloc(65536, M_DEVBUF, M_WAITOK); > copyin(arg, bd, 65536); > break; > [...] > > > Note that the BIGDATA ioctl doesn't copy in anything on its own. For > ioctls like this, it's often convenient to pass a structure anyway that > contains the size of the data to be copied in and a pointer to the data, > like so: > > struct mybigdata { > int datasize; > char *bigdata; > } > > #define IOCTL_SET_BIGDATA _IOR("B", 123, struct mybigdata) > > case IOCTL_GET_BIGDATA: > mbd = *(struct mybigdata *)arg; > bd = malloc(mbd->datasize, M_DEVBUF, M_WAITOK); > copyin(mbd->bigdata, bd, mbd->datasize); > break; > > Does this make sense? Fell free to contact me with questions on this or > anything else. > > Scott > Oops, I made a small but important mistake in these examples. When you use _IOR or _IOW, the data argument passed to your routine will be a pointer (in kernel address space) to the data that you specified, not a pointer to a pointer. So in the above example, you'd do: mbd = (struct mybigdata *)arg; not: mbd = *(struct mybigdata *)arg; For integral types, you'd still do: data = *(unsigned short *)arg; For ioctls that are specified with merely _IO, the data argument is a pointer in user address space. Technically you could just use bcopy on this, but the physical pages backing that address might have been swapped out in between the time the syscall was started and the time that your handler got called. The whole point of copyin/copyout is to safely and transparently handle this situation. Sorry for the confusion. Scott
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?42E5804D.4030206>