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