Re: Problems implementing write function of a character device
site_archiver@lists.apple.com Delivered-To: darwin-kernel@lists.apple.com I can't really improve on Mike's advice here. (2) The reason you are getting the 0 is that either: (b) the user is passing a 0 in their iov to a readv/writev call -- Terry On Sep 13, 2006, at 1:54 AM, sanjay yaragatti wrote: I am implementing write func for a character device. I am using the accessor methods uio_curriovlen(uio) and uio_curriovbase(uio) provided in the <sys/uio.h> file to get the length value of the current iovec associated with the given uio and the base address of the current iovec associated with the given uio respectively.However, both the calls are returning zero as the return value.Hence unable to copy the data from userspace to kernel space.Even tried using uiomove() inplace of copyin() but doesnt work. I have attached the code for reference.. Please let me know if something wrong in the code. ( dev_t device, struct uio *uio, int ioflag ) { INT ret = SUCCESS; INT is spelled "int". What is "PUCHAR"? Do you mean "unsigned char *"? If so, use it. UINT32 is spelled "uint32_t". user_size_t buff_len = 0, buff_base = 0; /* Get the minor number */ minor_num = minor(device); buff_len = uio_curriovlen(uio); buff_base = uio_curriovbase(uio); uio_curriovbase() returns user_addr_t not user_size_t. IOLog ("uio_curriovlen is %d & uio_curriovbase is %d\n ",buff_len,buff_base); tmp_buff = (PUCHAR) mem_alloc(buff_len); You should never, ever allocate memory on your hot path. For something like this, you would probably be fine with a buffer on the stack. if (NULL == tmp_buff) { IOLog("%s: Buffer is NULL\n", __FUNCTION__); return FAILURE; } if(ret = copyin(buff_base, tmp_buff,buff_len)!= 0) Why are you using copyin? Why aren't you updating the uio? Why aren't you checking whether the buffer is already in kernel space? How do you plan to deal with writev() calls that have more than one segment in the iovec? This is why you should use uiomove. { mem_free(tmp_buff,buff_len); IOlog("%s: Copy from user failed\n", __FUNCTION__); return FAILURE; } *(tmp_buff+ buff_len ) = 0; } And why don't you free the buffer in the success case? You're going to leak kernel memory here. Try something like #define WRITE_CHUNK_SIZE 128 int device_write(dev_t *dev, struct uio *uio, int ioflag) { char stk_buf[WRITE_CHUNK_SIZE]; int buf_len; /* check direction */ if (uio_rw(uio) != UIO_WRITE) return(EINVAL); /* loop bringing in chunks of data */ for (;;) { /* check UIO for more data */ buf_len = min(uio_resid(uio), WRITE_CHUNK_SIZE); if (buf_len == 0) break; /* bring in a chunk */ uiomove(stk_buf, buf_len, uio); /* emit chunk */ driver_emit_bytes(stk_buf, buf_len); } return(0); } Note that this as it stands is not very efficient; depending on your device you may want to bring in much larger chunks, or if you have a buffer pool for outbound data you might want to grab buffers in the uiomove loop and move into them rather than into a temporary stack buffer. If your device is fairly slow, however, this will work fine. You would not want to increase WRITE_CHUNK_SIZE to much more than 1KB or so, depending on how much stack you use elsewhere in your driver. With buffers that large you're looking at a higher- performance design though and mapping directly will start to be more attractive. = Mike --- Terry Lambert <tlambert@apple.com> wrote: Hi all, I am writing a kernel driver.I have as character device. I am unable to implement the device write method (dev_write( dev_t device, uio *uio, int ioflag)) since I don't know how to retrieve the buffer from struct uio. However on trying to dereference uio as uio->uio_iov->iov_base gave a compilation error. You may want to read /usr/include/sys/uio.h... /* * uio_curriovbase - return the base address of the current iovec associated * with the given uio_t. May return 0. */ user_addr_t uio_curriovbase( uio_t a_uio ); You can also look at the kernel sources; in this case, the function is implemented in: -- Terry __________________________________________________________ Yahoo! India Answers: Share what you know. Learn something new http://in.answers.yahoo.com/ _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-kernel mailing list (Darwin-kernel@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/darwin-kernel/drivers%40mu.org _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-kernel mailing list (Darwin-kernel@lists.apple.com) Help/Unsubscribe/Update your Subscription: http://lists.apple.com/mailman/options/darwin-kernel/site_archiver%40lists.a... As exposition, the reason uio structures have accessors and mutators instead of letting you access them directly is twofold: (1) It protects your driver from needing to know about 32 vs. 64 bit user space programs (a) you are failing to iterate the iov's from user space, and never get past the first one In any case, you should be using uiomove() in order to move the data, not doing it yourself. On Sep 13, 2006, at 8:45 AM, Michael Smith wrote: INT32 device_write Assuming this function is d_write in your cdevsw, it is read_write_fcn_t, which returns int, not "INT32". PUCHAR tmp_buff = NULL; UINT32 minor_num; On Sep 12, 2006, at 2:13 AM, sanjay yaragatti wrote: regestered it struct Is there a KPI to retrieve the buffer sent from user space? <http://www.opensource.apple.com/darwinsource/10.4.7.ppc/xnu-792.6.76/bsd/ker... This email sent to drivers@mu.org This email sent to site_archiver@lists.apple.com
participants (1)
-
Terry Lambert