Whamcloud - gitweb
land b1_5 onto HEAD
[fs/lustre-release.git] / lustre / obdclass / darwin / darwin-module.c
diff --git a/lustre/obdclass/darwin/darwin-module.c b/lustre/obdclass/darwin/darwin-module.c
new file mode 100644 (file)
index 0000000..287d942
--- /dev/null
@@ -0,0 +1,181 @@
+#define DEBUG_SUBSYSTEM S_CLASS
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+
+#include <mach/mach_types.h>
+#include <string.h>
+#include <sys/file.h>
+#include <sys/conf.h>
+#include <miscfs/devfs/devfs.h>
+
+#include <libcfs/libcfs.h>
+#include <obd_support.h>
+#include <obd_class.h>
+#include <lprocfs_status.h>
+
+#ifndef OBD_MAX_IOCTL_BUFFER
+#define OBD_MAX_IOCTL_BUFFER 8192
+#endif
+
+/* buffer MUST be at least the size of obd_ioctl_hdr */
+int obd_ioctl_getdata(char **buf, int *len, void *arg)
+{
+        struct obd_ioctl_hdr *hdr;
+        struct obd_ioctl_data *data;
+        int err = 0;
+        int offset = 0;
+        ENTRY;
+
+       hdr = (struct obd_ioctl_hdr *)arg;
+        if (hdr->ioc_version != OBD_IOCTL_VERSION) {
+                CERROR("Version mismatch kernel vs application\n");
+                RETURN(-EINVAL);
+        }
+
+        if (hdr->ioc_len > OBD_MAX_IOCTL_BUFFER) {
+                CERROR("User buffer len %d exceeds %d max buffer\n",
+                       hdr->ioc_len, OBD_MAX_IOCTL_BUFFER);
+                RETURN(-EINVAL);
+        }
+
+        if (hdr->ioc_len < sizeof(struct obd_ioctl_data)) {
+                CERROR("OBD: user buffer too small for ioctl (%d)\n", hdr->ioc_len);
+                RETURN(-EINVAL);
+        }
+
+        /* XXX allocate this more intelligently, using kmalloc when
+         * appropriate */
+        OBD_VMALLOC(*buf, hdr->ioc_len);
+        if (*buf == NULL) {
+                CERROR("Cannot allocate control buffer of len %d\n",
+                       hdr->ioc_len);
+                RETURN(-EINVAL);
+        }
+        *len = hdr->ioc_len;
+        data = (struct obd_ioctl_data *)*buf;
+
+       bzero(data, hdr->ioc_len);
+       memcpy(data, (void *)arg, sizeof(struct obd_ioctl_data));
+       if (data->ioc_inlbuf1)
+               err = copy_from_user(&data->ioc_bulk[0], (void *)data->ioc_inlbuf1,
+                                    hdr->ioc_len - ((void *)&data->ioc_bulk[0] - (void *)data));
+
+        if (obd_ioctl_is_invalid(data)) {
+                CERROR("ioctl not correctly formatted\n");
+                return -EINVAL;
+        }
+
+        if (data->ioc_inllen1) {
+                data->ioc_inlbuf1 = &data->ioc_bulk[0];
+                offset += size_round(data->ioc_inllen1);
+        }
+
+        if (data->ioc_inllen2) {
+                data->ioc_inlbuf2 = &data->ioc_bulk[0] + offset;
+                offset += size_round(data->ioc_inllen2);
+        }
+
+        if (data->ioc_inllen3) {
+                data->ioc_inlbuf3 = &data->ioc_bulk[0] + offset;
+                offset += size_round(data->ioc_inllen3);
+        }
+
+        if (data->ioc_inllen4) {
+                data->ioc_inlbuf4 = &data->ioc_bulk[0] + offset;
+        }
+
+        EXIT;
+        return 0;
+}
+
+int obd_ioctl_popdata(void *arg, void *data, int len)
+{
+       /* 
+        * Xnu ioctl copyout(uaddr, arg, sizeof(struct obd_ioctl_data)),
+        * we have to copyout data exceed sizeof(struct obd_ioctl_data)
+        * by ourself.
+        */
+       if (len <= sizeof(struct obd_ioctl_data)) {
+               memcpy(arg, data, len);
+               return 0;
+       } else {
+               int err;
+               struct obd_ioctl_data *u = (struct obd_ioctl_data *)arg;
+               struct obd_ioctl_data *k = (struct obd_ioctl_data *)data;
+               err = copy_to_user((void *)u->ioc_inlbuf1, &k->ioc_bulk[0],
+                                   len -((void *)&k->ioc_bulk[0] -(void *)k));
+               memcpy(arg, data, sizeof(struct obd_ioctl_data));
+               return err;
+       }
+}
+/*
+ * cfs pseudo device
+ */
+extern struct cfs_psdev_ops          obd_psdev_ops;
+
+static int
+obd_class_open(dev_t dev, int flags, int devtype, struct proc *p)
+{
+       if (obd_psdev_ops.p_open != NULL)
+               return -obd_psdev_ops.p_open(0, NULL);
+       return EPERM;
+}
+
+/*  closing /dev/obd */
+static int
+obd_class_release(dev_t dev, int flags, int mode, struct proc *p)
+{
+       if (obd_psdev_ops.p_close != NULL)
+               return -obd_psdev_ops.p_close(0, NULL);
+       return EPERM;
+}
+
+static int
+obd_class_ioctl(dev_t dev, u_long cmd, caddr_t arg, int flag, struct proc *p)
+{
+       int err = 0;
+       ENTRY;
+
+       if (!is_suser())
+               RETURN (EPERM);
+       if (obd_psdev_ops.p_ioctl != NULL)
+               err = -obd_psdev_ops.p_ioctl(NULL, cmd, (void *)arg);
+       else
+               err = EPERM;
+
+       RETURN(err);
+}
+
+static struct cdevsw obd_psdevsw = {
+       obd_class_open,
+       obd_class_release,
+       NULL,
+       NULL,
+       obd_class_ioctl,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+       NULL,
+};
+
+cfs_psdev_t obd_psdev = {
+       -1,
+       NULL,
+       "obd",
+       &obd_psdevsw
+};
+
+int class_procfs_init(void)
+{
+       return 0;
+}
+
+int class_procfs_clean(void)
+{
+       return 0;
+}