]> git.proxmox.com Git - mirror_spl-debian.git/commitdiff
OK, a first reasonable attempt at a solaris module/chdev shim layer.
authorbehlendo <behlendo@7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c>
Thu, 20 Mar 2008 23:30:15 +0000 (23:30 +0000)
committerbehlendo <behlendo@7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c>
Thu, 20 Mar 2008 23:30:15 +0000 (23:30 +0000)
This should handle the absolute minimum I need for ZFS.  It will
register the chdev with the right callbacks.  Then the generic
registered linux callback will find the right registered solaris
callback for the function and munge the args just right before
passing it on.  Should work, but untested (just compiled), so I
expect bugs.

git-svn-id: https://outreach.scidac.gov/svn/spl/trunk@52 7e1ea52c-4ff2-0310-8f11-9dd32ca42a1c

include/sys/file.h [new file with mode: 0644]
include/sys/sunddi.h
include/sys/sunldi.h
include/sys/types.h
include/sys/vnode.h
modules/spl/Makefile.in
modules/spl/spl-module.c [new file with mode: 0644]
modules/spl/spl-vnode.c
modules/splat/splat-vnode.c

diff --git a/include/sys/file.h b/include/sys/file.h
new file mode 100644 (file)
index 0000000..63d6622
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef _SPL_FILE_H
+#define _SPL_FILE_H
+
+#endif /* SPL_FILE_H */
index 541102556eec4488137071469607badbe635d498..888b844518b30106ea17f4a0e552c2a0256cd91f 100644 (file)
@@ -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 */
index 01e80b54f468a20dba711b10a78cc471ebf1669c..f473350beb5cc1cdf4cfb1e12b4494f55728d9e8 100644 (file)
@@ -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 */
index 0d6a71ca0bba57aa324dc8686d24d756956ded26..dc660a761de1b16e08dfb49912952d5a7d69f80f 100644 (file)
@@ -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 */
index 1b9c3b671f2fdfc59d057b92e896f84092f9b4ae..4ee7e789548f007d832b041916663640a7729905 100644 (file)
@@ -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
index 1005d100b8f8341ed28922fbc72f8950c921bbed..bcc25be9731cf148d2bd9405cec7e6c270c7facd 100644 (file)
@@ -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 (file)
index 0000000..efe516a
--- /dev/null
@@ -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);
index 4ed59d32e697e75e9cefbc4d05f49549a303728b..24ee71293bc7d2b43e09419c7f1ce903e0263380 100644 (file)
@@ -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() */
index 92bbbfc74ab703053d761153de19768624c74910..8578ea20a24a90baca25eacec46d3340727146f3 100644 (file)
@@ -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"