diff options
-rw-r--r-- | include/sys/file.h | 4 | ||||
-rw-r--r-- | include/sys/sunddi.h | 179 | ||||
-rw-r--r-- | include/sys/sunldi.h | 27 | ||||
-rw-r--r-- | include/sys/types.h | 2 | ||||
-rw-r--r-- | include/sys/vnode.h | 1 | ||||
-rw-r--r-- | modules/spl/Makefile.in | 1 | ||||
-rw-r--r-- | modules/spl/spl-module.c | 297 | ||||
-rw-r--r-- | modules/spl/spl-vnode.c | 1 | ||||
-rw-r--r-- | modules/splat/splat-vnode.c | 4 |
9 files changed, 508 insertions, 8 deletions
diff --git a/include/sys/file.h b/include/sys/file.h new file mode 100644 index 000000000..63d662237 --- /dev/null +++ b/include/sys/file.h @@ -0,0 +1,4 @@ +#ifndef _SPL_FILE_H +#define _SPL_FILE_H + +#endif /* SPL_FILE_H */ diff --git a/include/sys/sunddi.h b/include/sys/sunddi.h index 541102556..888b84451 100644 --- a/include/sys/sunddi.h +++ b/include/sys/sunddi.h @@ -1,4 +1,183 @@ #ifndef _SPL_SUNDDI_H #define _SPL_SUNDDI_H +#include <sys/cred.h> +#include <sys/uio.h> +#include <sys/sunldi.h> +#include <sys/mutex.h> +#include <linux/kdev_t.h> +#include <linux/fs.h> +#include <linux/cdev.h> +#include <linux/list.h> +#include <linux/device.h> + +typedef int ddi_devid_t; + +typedef enum { + DDI_INFO_DEVT2DEVINFO = 0, + DDI_INFO_DEVT2INSTANCE = 1 +} ddi_info_cmd_t; + +typedef enum { + DDI_ATTACH = 0, + DDI_RESUME = 1, + DDI_PM_RESUME = 2 +} ddi_attach_cmd_t; + +typedef enum { + DDI_DETACH = 0, + DDI_SUSPEND = 1, + DDI_PM_SUSPEND = 2, + DDI_HOTPLUG_DETACH = 3 +} ddi_detach_cmd_t; + +typedef enum { + DDI_RESET_FORCE = 0 +} ddi_reset_cmd_t; + +typedef enum { + PROP_LEN = 0, + PROP_LEN_AND_VAL_BUF = 1, + PROP_LEN_AND_VAL_ALLOC = 2, + PROP_EXISTS = 3 +} ddi_prop_op_t; + +typedef void *devmap_cookie_t; +typedef struct as { + uchar_t a_flags; +} as_t; + +typedef struct pollhead { + struct polldat *ph_list; +} pollhead_t; + +typedef struct dev_info { + kmutex_t di_lock; + struct dev_ops *di_ops; + struct cdev *di_cdev; + struct class *di_class; + major_t di_major; + minor_t di_minor; + dev_t di_dev; + unsigned di_minors; + struct list_head di_list; +} dev_info_t; + +typedef struct cb_ops { + int (*cb_open)(dev_t *devp, int flag, int otyp, cred_t *credp); + int (*cb_close)(dev_t dev, int flag, int otyp, cred_t *credp); + int (*cb_strategy)(void *bp); + int (*cb_print)(dev_t dev, char *str); + int (*cb_dump)(dev_t dev, caddr_t addr, daddr_t blkno, int nblk); + int (*cb_read)(dev_t dev, struct uio *uiop, cred_t *credp); + int (*cb_write)(dev_t dev, struct uio *uiop, cred_t *credp); + int (*cb_ioctl)(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *credp, int *rvalp); + int (*cb_devmap)(dev_t dev, devmap_cookie_t dhp, offset_t off, + size_t len, size_t *maplen, uint_t model); + int (*cb_mmap)(dev_t dev, off_t off, int prot); + int (*cb_segmap)(dev_t dev, off_t off, struct as *asp, + caddr_t *addrp, off_t len, unsigned int prot, + unsigned int maxprot, unsigned int flags, + cred_t *credp); + int (*cb_chpoll)(dev_t dev, short events, int anyyet, + short *reventsp, struct pollhead **phpp); + int (*cb_prop_op)(dev_t dev, dev_info_t *dip, + ddi_prop_op_t prop_op, int mod_flags, + char *name, caddr_t valuep, int *length); + struct streamtab *cb_str; + int cb_flag; + int cb_rev; + int (*cb_aread)(dev_t dev, struct aio_req *aio, cred_t *credp); + int (*cb_awrite)(dev_t dev, struct aio_req *aio, cred_t *credp); +} cb_ops_t; + +typedef struct dev_ops { + int devo_rev; + int devo_refcnt; + + int (*devo_getinfo)(dev_info_t *dip, + ddi_info_cmd_t infocmd, void *arg, void **result); + int (*devo_identify)(dev_info_t *dip); + int (*devo_probe)(dev_info_t *dip); + int (*devo_attach)(dev_info_t *dip, ddi_attach_cmd_t cmd); + int (*devo_detach)(dev_info_t *dip, ddi_detach_cmd_t cmd); + int (*devo_reset)(dev_info_t *dip, ddi_reset_cmd_t cmd); + + struct cb_ops *devo_cb_ops; + struct bus_ops *devo_bus_ops; + int (*devo_power)(dev_info_t *dip, int component, int level); +} dev_ops_t; + +typedef struct mod_ops { + int (*modm_install)(void); + int (*modm_remove)(void); + int (*modm_info)(void); +} mod_ops_t; + +typedef struct modldrv { + struct mod_ops *drv_modops; + char *drv_linkinfo; + struct dev_ops *drv_dev_ops; + struct dev_info *drv_dev_info; +} modldrv_t; + +#define MODREV_1 1 + +#define D_NEW 0x000 +#define D_MP 0x020 +#define D_64BIT 0x200 + +#define DEVO_REV 3 +#define CB_REV 1 + +#define DDI_SUCCESS 0 +#define DDI_FAILURE -1 + +#define DDI_PSEUDO "ddi_pseudo" + +#define nodev NULL +#define nochpoll NULL +#define nulldev NULL +#define mod_driverops NULL +#define ddi_prop_op NULL + +#define getminor MINOR +#define getmajor MAJOR + +#define mod_install(x) 0 +#define mod_remove(x) 0 + +extern int __ddi_create_minor_node(dev_info_t *dip, char *name, int spec_type, + minor_t minor_num, char *node_type, + int flag, struct module *mod); +extern void __ddi_remove_minor_node(dev_info_t *dip, char *name); +extern int __mod_install(struct modlinkage *modlp); +extern int __mod_remove(struct modlinkage *modlp); + +static __inline__ void ddi_report_dev(dev_info_t *d) { } +static __inline__ void ddi_prop_remove_all(dev_info_t *dip) { } + +static __inline__ major_t +ddi_driver_major(dev_info_t *di) +{ + return getminor(di->di_dev); +} + +static __inline__ int +ddi_create_minor_node(dev_info_t *di, char *name, int spec_type, + minor_t minor_num, char *node_type, int flag) +{ + return __ddi_create_minor_node(di, name, spec_type, minor_num, + node_type, flag, THIS_MODULE); + +} + +#undef mod_install +#undef mod_remove + +#define ddi_remove_minor_node __ddi_remove_minor_node +#define mod_install __mod_install +#define mod_remove __mod_remove + #endif /* SPL_SUNDDI_H */ diff --git a/include/sys/sunldi.h b/include/sys/sunldi.h index 01e80b54f..f473350be 100644 --- a/include/sys/sunldi.h +++ b/include/sys/sunldi.h @@ -1,9 +1,28 @@ #ifndef _SPL_SUNLDI_H #define _SPL_SUNLDI_H -/* XXX: ALL TOTALLY BOGUS, JUST PLACE HOLDERS */ -typedef int ddi_devid_t; -typedef int ldi_handle_t; -typedef int ldi_ident_t; +#include <sys/types.h> + +typedef struct modlinkage { + int ml_rev; + struct modlfs *ml_modlfs; + struct modldrv *ml_modldrv; + major_t ml_major; + unsigned ml_minors; + void *pad1; +} modlinkage_t; + +typedef struct ldi_ident { + char li_modname[MAXNAMELEN]; + dev_t li_dev; +} *ldi_ident_t; + +typedef struct ldi_handle { + uint_t lh_type; + struct ldi_ident *lh_ident; +} ldi_handle_t; + +extern int ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip); +extern void ldi_ident_release(ldi_ident_t li); #endif /* SPL_SUNLDI_H */ diff --git a/include/sys/types.h b/include/sys/types.h index 0d6a71ca0..dc660a761 100644 --- a/include/sys/types.h +++ b/include/sys/types.h @@ -31,7 +31,5 @@ typedef longlong_t diskaddr_t; typedef ushort_t o_mode_t; typedef uint_t major_t; typedef uint_t minor_t; -typedef uint_t ldi_ident_t; -typedef dev_t dev_info_t; #endif /* _SPL_TYPES_H */ diff --git a/include/sys/vnode.h b/include/sys/vnode.h index 1b9c3b671..4ee7e7895 100644 --- a/include/sys/vnode.h +++ b/include/sys/vnode.h @@ -19,6 +19,7 @@ extern "C" { #include <sys/types.h> #include <sys/time.h> #include <sys/uio.h> +#include <sys/sunldi.h> #define XVA_MAPSIZE 3 #define XVA_MAGIC 0x78766174 diff --git a/modules/spl/Makefile.in b/modules/spl/Makefile.in index 1005d100b..bcc25be97 100644 --- a/modules/spl/Makefile.in +++ b/modules/spl/Makefile.in @@ -17,6 +17,7 @@ spl-objs += spl-vnode.o spl-objs += spl-err.o spl-objs += spl-time.o spl-objs += spl-kobj.o +spl-objs += spl-module.o spl-objs += spl-generic.o splmodule := spl.ko diff --git a/modules/spl/spl-module.c b/modules/spl/spl-module.c new file mode 100644 index 000000000..efe516adb --- /dev/null +++ b/modules/spl/spl-module.c @@ -0,0 +1,297 @@ +#include <sys/sysmacros.h> +#include <sys/sunddi.h> +#include "config.h" + +static spinlock_t dev_info_lock = SPIN_LOCK_UNLOCKED; +static LIST_HEAD(dev_info_list); + +static struct dev_info * +get_dev_info(dev_t dev) +{ + struct dev_info *di; + + spin_lock(&dev_info_lock); + + list_for_each_entry(di, &dev_info_list, di_list) + if (di->di_dev == dev) + goto out; + + di = NULL; +out: + spin_unlock(&dev_info_lock); + return di; +} + +static int +mod_generic_ioctl(struct inode *ino, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + struct dev_info *di; + int rc, flag = 0, rvalp = 0; + cred_t *cr = NULL; + + di = get_dev_info(MKDEV(imajor(ino), iminor(ino))); + if (di == NULL) + return EINVAL; + + rc = di->di_ops->devo_cb_ops->cb_ioctl(di->di_dev, + (int)cmd,(intptr_t)arg, + flag, cr, &rvalp); + return rc; +} + +int +__ddi_create_minor_node(dev_info_t *di, char *name, int spec_type, + minor_t minor_num, char *node_type, + int flag, struct module *mod) +{ + struct cdev *cdev; + struct dev_ops *dev_ops; + struct cb_ops *cb_ops; + struct file_operations *fops; + int rc; + + BUG_ON(spec_type != S_IFCHR); + BUG_ON(minor_num < di->di_minors); + BUG_ON(strcmp(node_type, DDI_PSEUDO)); + BUG_ON(flag != 0); + + fops = kmalloc(sizeof(struct file_operations), GFP_KERNEL); + if (fops == NULL) + return DDI_FAILURE; + + cdev = cdev_alloc(); + if (cdev == NULL) { + kfree(fops); + return DDI_FAILURE; + } + + cdev->ops = fops; + + mutex_enter(&di->di_lock); + dev_ops = di->di_ops; + BUG_ON(dev_ops == NULL); + cb_ops = di->di_ops->devo_cb_ops; + BUG_ON(cb_ops == NULL); + + /* Setup the fops to cb_ops mapping */ + fops->owner = mod; + if (cb_ops->cb_ioctl) + fops->ioctl = mod_generic_ioctl; + +#if 0 + if (cb_ops->cb_open) + fops->open = mod_generic_open; + + if (cb_ops->cb_close) + fops->release = mod_generic_close; + + if (cb_ops->cb_read) + fops->read = mod_generic_read; + + if (cb_ops->cb_write) + fops->write = mod_generic_write; +#endif + /* XXX: Currently unsupported operations */ + BUG_ON(cb_ops->cb_open != NULL); + BUG_ON(cb_ops->cb_close != NULL); + BUG_ON(cb_ops->cb_read != NULL); + BUG_ON(cb_ops->cb_write != NULL); + BUG_ON(cb_ops->cb_strategy != NULL); + BUG_ON(cb_ops->cb_print != NULL); + BUG_ON(cb_ops->cb_dump != NULL); + BUG_ON(cb_ops->cb_devmap != NULL); + BUG_ON(cb_ops->cb_mmap != NULL); + BUG_ON(cb_ops->cb_segmap != NULL); + BUG_ON(cb_ops->cb_chpoll != NULL); + BUG_ON(cb_ops->cb_prop_op != NULL); + BUG_ON(cb_ops->cb_str != NULL); + BUG_ON(cb_ops->cb_aread != NULL); + BUG_ON(cb_ops->cb_awrite != NULL); + + di->di_minor = minor_num; + di->di_dev = MKDEV(di->di_major, di->di_minor); + + rc = cdev_add(cdev, di->di_dev, 1); + if (rc) { + printk("spl: Error adding cdev, %d\n", rc); + kfree(fops); + cdev_del(cdev); + mutex_exit(&di->di_lock); + return DDI_FAILURE; + } + + di->di_class = class_create(THIS_MODULE, name); + if (IS_ERR(di->di_class)) { + rc = PTR_ERR(di->di_class); + printk("spl: Error creating %s class, %d\n", name, rc); + kfree(fops); + cdev_del(di->di_cdev); + mutex_exit(&di->di_lock); + return DDI_FAILURE; + } + + class_device_create(di->di_class, NULL, di->di_dev, + NULL, "%s%d", name, di->di_minor); + + di->di_cdev = cdev; + + spin_lock(&dev_info_lock); + list_add(&di->di_list, &dev_info_list); + spin_unlock(&dev_info_lock); + + mutex_exit(&di->di_lock); + + return DDI_SUCCESS; +} +EXPORT_SYMBOL(__ddi_create_minor_node); + +static void +___ddi_remove_minor_node(dev_info_t *di, char *name) +{ + class_device_destroy(di->di_class, di->di_dev); + class_destroy(di->di_class); + cdev_del(di->di_cdev); + + spin_lock(&dev_info_lock); + list_del(&di->di_list); + spin_unlock(&dev_info_lock); +} + +void +__ddi_remove_minor_node(dev_info_t *di, char *name) +{ + mutex_enter(&di->di_lock); + ___ddi_remove_minor_node(di, name); + mutex_exit(&di->di_lock); +} +EXPORT_SYMBOL(ddi_remove_minor_node); + +#if 0 +static int +mod_generic_open(struct inode *, struct file *) +{ + open(dev_t *devp, int flag, int otyp, cred_t *credp); +} + +static int +mod_generic_close(struct inode *, struct file *) +{ + close(dev_t dev, int flag, int otyp, cred_t *credp); +} + +static ssize_t +mod_generic_read(struct file *, char __user *, size_t, loff_t *) +{ + read(dev_t dev, struct uio *uiop, cred_t *credp); +} + +static ssize_t +mod_generic_write(struct file *, const char __user *, size_t, loff_t *) +{ + write(dev_t dev, struct uio *uiop, cred_t *credp); +} +#endif + +static struct dev_info * +dev_info_alloc(major_t major, minor_t minors, struct dev_ops *ops) { + struct dev_info *di; + + di = kmalloc(sizeof(struct dev_info), GFP_KERNEL); + if (di == NULL) + return NULL; + + mutex_init(&di->di_lock, NULL, MUTEX_DEFAULT, NULL); + INIT_LIST_HEAD(&di->di_list); + di->di_ops = ops; + di->di_class = NULL; + di->di_cdev = NULL; + di->di_major = major; + di->di_minor = 0; + di->di_minors = minors; + di->di_dev = 0; + + return di; +} + +static void +dev_info_free(struct dev_info *di) +{ + mutex_enter(&di->di_lock); + __ddi_remove_minor_node(di, NULL); + mutex_exit(&di->di_lock); + mutex_destroy(&di->di_lock); + kfree(di); +} + +int +__mod_install(struct modlinkage *modlp) +{ + struct modldrv *drv = modlp->ml_modldrv; + struct dev_info *di; + int rc; + + di = dev_info_alloc(modlp->ml_major, modlp->ml_minors, + drv->drv_dev_ops); + if (di == NULL) + return ENOMEM; + + /* XXX: Really we need to be calling devo_probe if it's available + * and then calling devo_attach for each device discovered. However + * for now we just call it once and let the app sort it out. + */ + rc = drv->drv_dev_ops->devo_attach(di, DDI_ATTACH); + if (rc != DDI_SUCCESS) { + dev_info_free(di); + return rc; + } + + drv->drv_dev_info = di; + + return DDI_SUCCESS; +} +EXPORT_SYMBOL(__mod_install); + +int +__mod_remove(struct modlinkage *modlp) +{ + struct modldrv *drv = modlp->ml_modldrv; + struct dev_info *di = drv->drv_dev_info; + int rc; + + rc = drv->drv_dev_ops->devo_detach(di, DDI_DETACH); + if (rc != DDI_SUCCESS) + return rc; + + dev_info_free(di); + drv->drv_dev_info = NULL; + + return DDI_SUCCESS; +} +EXPORT_SYMBOL(__mod_remove); + +int +ldi_ident_from_mod(struct modlinkage *modlp, ldi_ident_t *lip) +{ + ldi_ident_t li; + + BUG_ON(modlp == NULL || lip == NULL); + + li = kmalloc(sizeof(struct ldi_ident), GFP_KERNEL); + if (li == NULL) + return ENOMEM; + + li->li_dev = MKDEV(modlp->ml_major, 0); + *lip = li; + + return 0; +} +EXPORT_SYMBOL(ldi_ident_from_mod); + +void +ldi_ident_release(ldi_ident_t lip) +{ + BUG_ON(lip == NULL); + kfree(lip); +} +EXPORT_SYMBOL(ldi_ident_release); diff --git a/modules/spl/spl-vnode.c b/modules/spl/spl-vnode.c index 4ed59d32e..24ee71293 100644 --- a/modules/spl/spl-vnode.c +++ b/modules/spl/spl-vnode.c @@ -548,6 +548,7 @@ vn_file_cache_constructor(void *buf, void *cdrarg, int kmflags) atomic_set(&fp->f_ref, 0); mutex_init(&fp->f_lock, NULL, MUTEX_DEFAULT, NULL); + INIT_LIST_HEAD(&fp->f_list); return (0); } /* file_cache_constructor() */ diff --git a/modules/splat/splat-vnode.c b/modules/splat/splat-vnode.c index 92bbbfc74..8578ea20a 100644 --- a/modules/splat/splat-vnode.c +++ b/modules/splat/splat-vnode.c @@ -30,8 +30,8 @@ #define SPLAT_VNODE_TEST6_DESC "Vn_sync Test" #define SPLAT_VNODE_TEST7_ID 0x0907 -#define SPLAT_VNODE_TEST7_NAME "getf" -#define SPLAT_VNODE_TEST7_DESC "getf/releasef Test" +#define SPLAT_VNODE_TEST7_NAME "vn_getf" +#define SPLAT_VNODE_TEST7_DESC "vn_getf/vn_releasef Test" #define SPLAT_VNODE_TEST_FILE "/etc/fstab" #define SPLAT_VNODE_TEST_FILE_AT "etc/fstab" |