svn commit: r210990 - projects/ofed/head/sys/ofed/include/linux

Jeff Roberson jeff at FreeBSD.org
Sat Aug 7 02:11:42 UTC 2010


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_ */


More information about the svn-src-projects mailing list