Date: Sat, 7 Aug 2010 02:11:42 +0000 (UTC) From: Jeff Roberson <jeff@FreeBSD.org> To: src-committers@freebsd.org, svn-src-projects@freebsd.org Subject: svn commit: r210990 - projects/ofed/head/sys/ofed/include/linux Message-ID: <201008070211.o772Bg8V000186@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: jeff Date: Sat Aug 7 02:11:41 2010 New Revision: 210990 URL: http://svn.freebsd.org/changeset/base/210990 Log: - Implement device and file operations wrappers. Only read, write, poll, ioctl, open, and close are supported. Attempts to define other members in linux code will generate compiler errors. - Use selrecord via poll_wait(), however, the containing code needs selwakeup() added in appropriate places because our select can't wait on their native waitqueue structures. This still leaves very little code to change. Sponsored by: Isilon Systems, iX Systems, and Panasas. Modified: projects/ofed/head/sys/ofed/include/linux/cdev.h projects/ofed/head/sys/ofed/include/linux/fs.h projects/ofed/head/sys/ofed/include/linux/linux_compat.c projects/ofed/head/sys/ofed/include/linux/poll.h Modified: projects/ofed/head/sys/ofed/include/linux/cdev.h ============================================================================== --- projects/ofed/head/sys/ofed/include/linux/cdev.h Sat Aug 7 02:09:07 2010 (r210989) +++ projects/ofed/head/sys/ofed/include/linux/cdev.h Sat Aug 7 02:11:41 2010 (r210990) @@ -60,6 +60,7 @@ cdev_alloc(void) { struct linux_cdev *cdev; + /* XXX Need cdev_ktype */ cdev = kzalloc(sizeof(struct linux_cdev), M_WAITOK); if (cdev) kobject_init(&cdev->kobj, NULL); @@ -79,6 +80,8 @@ cdev_add(struct linux_cdev *cdev, dev_t panic("cdev_add: Unsupported count: %d", count); cdev->cdev = make_dev(&linuxcdevsw, MINOR(dev), 0, 0, 0700, kobject_name(&cdev->kobj)); + cdev->cdev->si_drv1 = cdev; + return (0); } Modified: projects/ofed/head/sys/ofed/include/linux/fs.h ============================================================================== --- projects/ofed/head/sys/ofed/include/linux/fs.h Sat Aug 7 02:09:07 2010 (r210989) +++ projects/ofed/head/sys/ofed/include/linux/fs.h Sat Aug 7 02:11:41 2010 (r210990) @@ -65,11 +65,12 @@ struct file_operations; struct linux_file { struct file *_file; - struct file_operations *f_op; + const struct file_operations *f_op; void *private_data; int f_flags; struct dentry *f_dentry; struct dentry f_dentry_store; + struct selinfo f_selinfo; }; #define file linux_file @@ -78,23 +79,25 @@ typedef int (*filldir_t)(void *, const c struct file_operations { struct module *owner; - loff_t (*llseek)(struct file *, loff_t, int); ssize_t (*read)(struct file *, char __user *, size_t, loff_t *); ssize_t (*write)(struct file *, const char __user *, size_t, loff_t *); + unsigned int (*poll) (struct file *, struct poll_table_struct *); + long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long); + int (*mmap)(struct file *, struct vm_area_struct *); + int (*open)(struct inode *, struct file *); + int (*release)(struct inode *, struct file *); +#if 0 + /* We do not support these methods. Don't permit them to compile. */ + loff_t (*llseek)(struct file *, loff_t, int); ssize_t (*aio_read)(struct kiocb *, const struct iovec *, unsigned long, loff_t); ssize_t (*aio_write)(struct kiocb *, const struct iovec *, unsigned long, loff_t); int (*readdir)(struct file *, void *, filldir_t); - unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl)(struct inode *, struct file *, unsigned int, unsigned long); - long (*unlocked_ioctl)(struct file *, unsigned int, unsigned long); long (*compat_ioctl)(struct file *, unsigned int, unsigned long); - int (*mmap)(struct file *, struct vm_area_struct *); - int (*open)(struct inode *, struct file *); int (*flush)(struct file *, fl_owner_t id); - int (*release)(struct inode *, struct file *); int (*fsync)(struct file *, struct dentry *, int datasync); int (*aio_fsync)(struct kiocb *, int datasync); int (*fasync)(int, struct file *, int); @@ -110,68 +113,28 @@ struct file_operations { ssize_t (*splice_read)(struct file *, loff_t *, struct pipe_inode_info *, size_t, unsigned int); int (*setlease)(struct file *, long, struct file_lock **); +#endif }; static inline int -linux_open(struct cdev *dev, int oflags, int devtype, struct thread *td) -{ - return 0; -} - -static inline int -linux_close(struct cdev *dev, int fflag, int devtype, struct thread *td) -{ - return 0; -} - -static inline int -linux_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, - struct thread *td) -{ - return 0; -} - -static inline int -linux_read(struct cdev *dev, struct uio *uio, int ioflag) -{ - return 0; -} - -static inline int -linux_write(struct cdev *dev, struct uio *uio, int ioflag) -{ - return 0; -} - -static inline int -linux_poll(struct cdev *dev, int events, struct thread *td) -{ - return 0; -} - -static inline int -linux_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, - int nprot, vm_memattr_t *memattr) -{ - return 0; -} - -static inline int register_chrdev_region(dev_t dev, unsigned range, const char *name) { + return 0; } static inline void unregister_chrdev_region(dev_t dev, unsigned range) { + return; } static inline dev_t iminor(struct inode *inode) { - return dev2udev(inode->v_rdev); + + return dev2unit(inode->v_rdev); } static inline struct inode * Modified: projects/ofed/head/sys/ofed/include/linux/linux_compat.c ============================================================================== --- projects/ofed/head/sys/ofed/include/linux/linux_compat.c Sat Aug 7 02:09:07 2010 (r210989) +++ projects/ofed/head/sys/ofed/include/linux/linux_compat.c Sat Aug 7 02:11:41 2010 (r210990) @@ -44,15 +44,15 @@ #include <linux/cdev.h> #include <linux/file.h> #include <linux/sysfs.h> +#include <linux/mm.h> MALLOC_DEFINE(M_KMALLOC, "linux", "Linux kmalloc compat"); -struct fileops linuxfileops; -struct cdevsw linuxcdevsw; - #include <linux/rbtree.h> -/* Undo Linux compat change. */ +/* Undo Linux compat changes. */ #undef RB_ROOT +#undef file +#undef cdev #define RB_ROOT(head) (head)->rbh_root struct kobject class_root; @@ -187,6 +187,304 @@ kobject_init_and_add(struct kobject *kob } static void +linux_file_dtor(void *cdp) +{ + struct linux_file *filp; + + filp = cdp; + filp->f_op->release(curthread->td_fpop->f_vnode, filp); + kfree(filp); +} + +static int +linux_dev_open(struct cdev *dev, int oflags, int devtype, struct thread *td) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (ENODEV); + filp = kzalloc(sizeof(*filp), GFP_KERNEL); + filp->f_dentry = &filp->f_dentry_store; + filp->f_op = ldev->ops; + filp->f_flags = file->f_flag; + if (filp->f_op->open) { + error = -filp->f_op->open(file->f_vnode, filp); + if (error) { + kfree(filp); + return (error); + } + } + error = devfs_set_cdevpriv(filp, linux_file_dtor); + if (error) { + filp->f_op->release(file->f_vnode, filp); + kfree(filp); + return (error); + } + + return 0; +} + +static int +linux_dev_close(struct cdev *dev, int fflag, int devtype, struct thread *td) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + devfs_clear_cdevpriv(); + + return (0); +} + +static int +linux_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, + struct thread *td) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + /* + * Linux does not have a generic ioctl copyin/copyout layer. All + * linux ioctls must be converted to void ioctls which pass a + * pointer to the address of the data. We want the actual user + * address so we dereference here. + */ + data = *(void **)data; + if (filp->f_op->unlocked_ioctl) + error = -filp->f_op->unlocked_ioctl(filp, cmd, (u_long)data); + else + error = ENOTTY; + + return (error); +} + +static int +linux_dev_read(struct cdev *dev, struct uio *uio, int ioflag) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + ssize_t bytes; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + if (uio->uio_iovcnt != 1) + panic("linux_dev_read: uio %p iovcnt %d", + uio, uio->uio_iovcnt); + if (filp->f_op->read) { + bytes = filp->f_op->read(filp, uio->uio_iov->iov_base, + uio->uio_iov->iov_len, &uio->uio_offset); + if (bytes >= 0) { + uio->uio_iov->iov_base += bytes; + uio->uio_iov->iov_len -= bytes; + uio->uio_resid -= bytes; + } else + error = -bytes; + } else + error = ENXIO; + + return (error); +} + +static int +linux_dev_write(struct cdev *dev, struct uio *uio, int ioflag) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + ssize_t bytes; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + if (uio->uio_iovcnt != 1) + panic("linux_dev_write: uio %p iovcnt %d", + uio, uio->uio_iovcnt); + if (filp->f_op->write) { + bytes = filp->f_op->write(filp, uio->uio_iov->iov_base, + uio->uio_iov->iov_len, &uio->uio_offset); + if (bytes >= 0) { + uio->uio_iov->iov_base += bytes; + uio->uio_iov->iov_len -= bytes; + uio->uio_resid -= bytes; + } else + error = -bytes; + } else + error = ENXIO; + + return (error); +} + +static int +linux_dev_poll(struct cdev *dev, int events, struct thread *td) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + int revents; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + if (filp->f_op->poll) + revents = filp->f_op->poll(filp, NULL) & events; + else + revents = 0; + + return (revents); +} + +static int +linux_dev_mmap(struct cdev *dev, vm_ooffset_t offset, vm_paddr_t *paddr, + int nprot, vm_memattr_t *memattr) +{ + struct linux_cdev *ldev; + struct linux_file *filp; + struct file *file; + struct vm_area_struct vma; + int error; + + file = curthread->td_fpop; + ldev = dev->si_drv1; + if (ldev == NULL) + return (0); + if ((error = devfs_get_cdevpriv((void **)&filp)) != 0) + return (error); + filp->f_flags = file->f_flag; + vma.vm_start = 0; + vma.vm_end = PAGE_SIZE; + vma.vm_pgoff = offset / PAGE_SIZE; + vma.vm_pfn = 0; + vma.vm_page_prot = *memattr; + if (filp->f_op->mmap) { + error = -filp->f_op->mmap(filp, &vma); + if (error == 0) { + *paddr = (vm_paddr_t)vma.vm_pfn << PAGE_SHIFT; + *memattr = vma.vm_page_prot; + } + } else + error = ENODEV; + + return (error); +} + +struct cdevsw linuxcdevsw = { + .d_version = D_VERSION, + .d_flags = D_TRACKCLOSE, + .d_open = linux_dev_open, + .d_close = linux_dev_close, + .d_read = linux_dev_read, + .d_write = linux_dev_write, + .d_ioctl = linux_dev_ioctl, + .d_mmap = linux_dev_mmap, + .d_poll = linux_dev_poll, +}; + +static int +linux_file_read(struct file *file, struct uio *uio, struct ucred *active_cred, + int flags, struct thread *td) +{ + struct linux_file *filp; + ssize_t bytes; + int error; + + error = 0; + filp = (struct linux_file *)file->f_data; + filp->f_flags = file->f_flag; + if (uio->uio_iovcnt != 1) + panic("linux_file_read: uio %p iovcnt %d", + uio, uio->uio_iovcnt); + if (filp->f_op->read) { + bytes = filp->f_op->read(filp, uio->uio_iov->iov_base, + uio->uio_iov->iov_len, &uio->uio_offset); + if (bytes >= 0) { + uio->uio_iov->iov_base += bytes; + uio->uio_iov->iov_len -= bytes; + uio->uio_resid -= bytes; + } else + error = -bytes; + } else + error = ENXIO; + + return (error); +} + +static int +linux_file_poll(struct file *file, int events, struct ucred *active_cred, + struct thread *td) +{ + struct linux_file *filp; + int revents; + + filp = (struct linux_file *)file->f_data; + filp->f_flags = file->f_flag; + if (filp->f_op->poll) + revents = filp->f_op->poll(filp, NULL) & events; + else + revents = 0; + + return (0); +} + +static int +linux_file_close(struct file *file, struct thread *td) +{ + struct linux_file *filp; + int error; + + filp = (struct linux_file *)file->f_data; + filp->f_flags = file->f_flag; + error = -filp->f_op->release(NULL, filp); + kfree(filp); + + return (error); +} + +struct fileops linuxfileops = { + .fo_read = linux_file_read, + .fo_poll = linux_file_poll, + .fo_close = linux_file_close +}; + +static void linux_compat_init(void) { struct sysctl_oid *rootoid; Modified: projects/ofed/head/sys/ofed/include/linux/poll.h ============================================================================== --- projects/ofed/head/sys/ofed/include/linux/poll.h Sat Aug 7 02:09:07 2010 (r210989) +++ projects/ofed/head/sys/ofed/include/linux/poll.h Sat Aug 7 02:11:41 2010 (r210990) @@ -38,6 +38,7 @@ typedef struct poll_table_struct { static inline void poll_wait(struct file *filp, wait_queue_head_t *wait_address, poll_table *p) { + selrecord(curthread, &filp->f_selinfo); } #endif /* _LINUX_POLL_H_ */
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201008070211.o772Bg8V000186>