X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fobdclass%2Fclass_obd.c;h=545f66b14afeaea2e6216b9d59cbe6a8499f6ac6;hb=58c14f99437bf9858f817e0a17b5007831987aa8;hp=bb766773d33439de1427ea9a773cc608fe0147aa;hpb=9937b22dc3b00aa886cb9e0c7c7a2b71083f03af;p=fs%2Flustre-release.git diff --git a/lustre/obdclass/class_obd.c b/lustre/obdclass/class_obd.c index bb76677..545f66b 100644 --- a/lustre/obdclass/class_obd.c +++ b/lustre/obdclass/class_obd.c @@ -1,13 +1,12 @@ /* - * An implementation of a loadable kernel mode driver providing - * multiple kernel/user space bidirectional communications links. + * An implementation of a loadable kernel mode driver providing + * multiple kernel/user space bidirectional communications links. * - * Author: Alan Cox + * Author: Alan Cox * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. * * Adapted to become the Linux 2.0 Coda pseudo device * Peter Braam @@ -23,20 +22,21 @@ * Copyright (c) 1999 Stelias Computing, Inc. * (authors {pschwan,braam}@stelias.com) * Copyright (C) 1999 Seagate Technology, Inc. + * Copyright (C) 2001 Cluster File Systems, Inc. * * */ #define EXPORT_SYMTAB - #include /* for CONFIG_PROC_FS */ #include #include #include #include +#include /* for request_module() */ #include #include -#include +#include #include #include #include @@ -48,679 +48,807 @@ #include #include #include -#include #include #include #include +#include #include #include -int obd_print_entry = 1; -int obd_debug_level = 4095; +static int obd_init_magic; +int obd_print_entry = 1; +int obd_debug_level = ~0; +long obd_memory = 0; struct obd_device obd_dev[MAX_OBD_DEVICES]; struct list_head obd_types; -/* called when opening /dev/obdNNN */ +/* opening /dev/obd */ static int obd_class_open(struct inode * inode, struct file * file) { - int dev; ENTRY; - if (!inode) - return -EINVAL; - dev = MINOR(inode->i_rdev); - if (dev >= MAX_OBD_DEVICES) - return -ENODEV; - obd_dev[dev].obd_refcnt++; - CDEBUG(D_PSDEV, "Refcount now %d\n", obd_dev[dev].obd_refcnt++); - + file->private_data = NULL; MOD_INC_USE_COUNT; EXIT; return 0; } -/* called when closing /dev/obdNNN */ +/* closing /dev/obd */ static int obd_class_release(struct inode * inode, struct file * file) { - int dev; ENTRY; - if (!inode) - return -EINVAL; - dev = MINOR(inode->i_rdev); - if (dev >= MAX_OBD_DEVICES) - return -ENODEV; - fsync_dev(inode->i_rdev); - if (obd_dev[dev].obd_refcnt <= 0) - printk(KERN_ALERT "presto_psdev_release: refcount(%d) <= 0\n", - obd_dev[dev].obd_refcnt); - obd_dev[dev].obd_refcnt--; - - CDEBUG(D_PSDEV, "Refcount now %d\n", obd_dev[dev].obd_refcnt++); + if (file->private_data) + file->private_data = NULL; MOD_DEC_USE_COUNT; - EXIT; return 0; } -/* support function */ -static struct obd_type *obd_nm_to_type(char *nm) +/* + * support functions: we could use inter-module communication, but this + * is more portable to other OS's + */ +static struct obd_type *obd_search_type(char *nm) { - struct list_head *tmp; - struct obd_type *type; - - tmp = &obd_types; - while ( (tmp = tmp->next) != &obd_types ) { - type = list_entry(tmp, struct obd_type, typ_chain); - if (strlen(type->typ_name) == strlen(nm) && - strcmp(type->typ_name, nm) == 0 ) { - return type; - } - } + struct list_head *tmp; + struct obd_type *type; + CDEBUG(D_INFO, "SEARCH %s\n", nm); + + tmp = &obd_types; + while ( (tmp = tmp->next) != &obd_types ) { + type = list_entry(tmp, struct obd_type, typ_chain); + CDEBUG(D_INFO, "TYP %s\n", type->typ_name); + if (strlen(type->typ_name) == strlen(nm) && + strcmp(type->typ_name, nm) == 0 ) { + return type; + } + } return NULL; } - -static int getdata(int len, void **data) +static struct obd_type *obd_nm_to_type(char *nm) { - void *tmp = NULL; + struct obd_type *type = obd_search_type(nm); - if (!len) - return 0; - - OBD_ALLOC(tmp, void *, len); - if ( !tmp ) - return -ENOMEM; - - memset(tmp, 0, len); - if ( copy_from_user(tmp, *data, len)) { - OBD_FREE(tmp,len); - return -EFAULT; +#ifdef CONFIG_KMOD + if ( !type ) { + if ( !request_module(nm) ) { + CDEBUG(D_PSDEV, "Loaded module '%s'\n", nm); + type = obd_search_type(nm); + } else { + CDEBUG(D_PSDEV, "Can't load module '%s'\n", nm); + } } - *data = tmp; - - return 0; +#endif + return type; } -/* to control /dev/obdNNN */ +/* to control /dev/obd */ static int obd_class_ioctl (struct inode * inode, struct file * filp, - unsigned int cmd, unsigned long arg) + unsigned int cmd, unsigned long arg) { - int err, i_ino, dev; - struct obd_device *obddev; - struct oic_rw_s rw_s; /* read, write */ - long int cli_id; /* connect, disconnect */ - - struct oic_prealloc_s prealloc; /* preallocate */ - - if (!inode) + /* NOTE this must be larger than any of the ioctl data structs */ + char buf[1024]; + struct obd_ioctl_data *data; + struct obd_device *obd = filp->private_data; + struct obd_conn conn; + int err = 0; + ENTRY; + + memset(buf, 0, sizeof(buf)); + + if (!obd && cmd != OBD_IOC_DEVICE && cmd != TCGETS) { + printk("OBD ioctl: No device\n"); + return -EINVAL; + } + if (obd_ioctl_getdata(buf, buf + 800, (void *)arg)) { + printk("OBD ioctl: data error\n"); return -EINVAL; - - dev = MINOR(inode->i_rdev); - if (dev > MAX_OBD_DEVICES) - return -ENODEV; - obddev = &obd_dev[dev]; - - switch (cmd) { - case OBD_IOC_ATTACH: { - struct obd_type *type; - struct oic_attach input; - - /* have we attached a type to this device */ - if ( obddev->obd_type || (obddev->obd_flags & OBD_ATTACHED) ){ - CDEBUG(D_IOCTL, "OBD Device %d already attached to type %s.\n", dev, obddev->obd_type->typ_name); - return -EINVAL; - } - - /* get data structures */ - err = copy_from_user(&input, (void *) arg, sizeof(input)); - if (err) - return err; - - if ( (err = getdata(input.att_typelen + 1, &input.att_type)) ) - return err; - - /* find the type */ - err = -EINVAL; - type = obd_nm_to_type(input.att_type); - OBD_FREE(input.att_type, input.att_typelen + 1); - if ( !type ) { - printk("Unknown obd type dev %d\n", dev); - return err; - } - obddev->obd_type = type; - - /* get the attach data */ - if ( (err = getdata(input.att_datalen, &input.att_data)) ) { - return err; - } - - CDEBUG(D_IOCTL, "Attach %d, type %s\n", - dev, obddev->obd_type->typ_name); - if (!obddev->obd_type->typ_ops || - !obddev->obd_type->typ_ops->o_attach ) { - obddev->obd_flags |= OBD_ATTACHED; - type->typ_refcnt++; - MOD_INC_USE_COUNT; - return 0; - } - - /* do the attach */ - err = obddev->obd_type->typ_ops->o_attach - (obddev, input.att_datalen, &input.att_data); - OBD_FREE(input.att_data, input.att_datalen); - - if ( err ) { - obddev->obd_flags &= ~OBD_ATTACHED; - obddev->obd_type = NULL; - } else { - obddev->obd_flags |= OBD_ATTACHED; - type->typ_refcnt++; - MOD_INC_USE_COUNT; - } - return err; - } - case OBD_IOC_FORMAT: { - struct ioc_format { - int format_datalen; - void *format_data; - } input; - - /* have we attached a type to this device */ - if ( !obddev->obd_type ) { - CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev); - return -EINVAL; - } - - /* get main structure */ - err = copy_from_user(&input, (void *) arg, sizeof(input)); - if (err) - return err; - - err = getdata(input.format_datalen, &input.format_data); - if (err) - return err; - - if (!obddev->obd_type->typ_ops || - !obddev->obd_type->typ_ops->o_format ) - return -EOPNOTSUPP; - - /* do the format */ - CDEBUG(D_IOCTL, "Format %d, type %s\n", dev, - obddev->obd_type->typ_name); - err = obddev->obd_type->typ_ops->o_format - (obddev, input.format_datalen, input.format_data); - - OBD_FREE(input.format_data, input.format_datalen); - return err; - } - case OBD_IOC_PARTITION: { - struct ioc_part { - int part_datalen; - void *part_data; - } input; - - /* have we attached a type to this device */ - if ( !obddev->obd_type ) { - CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev); - return -EINVAL; - } - - /* get main structure */ - err = copy_from_user(&input, (void *) arg, sizeof(input)); - if (err) - return err; - - err = getdata(input.part_datalen, &input.part_data); - if (err) - return err; - - if (!obddev->obd_type->typ_ops || - !obddev->obd_type->typ_ops->o_partition ) - return -EOPNOTSUPP; - - /* do the partition */ - CDEBUG(D_IOCTL, "Partition %d, type %s\n", dev, - obddev->obd_type->typ_name); - err = obddev->obd_type->typ_ops->o_partition - (obddev, input.part_datalen, input.part_data); - - OBD_FREE(input.part_data, input.part_datalen); - return err; } - case OBD_IOC_SETUP_OBDDEV: { - struct ioc_setup { - int setup_datalen; - void *setup_data; - } input; - - /* have we attached a type to this device */ - if (!(obddev->obd_flags & OBD_ATTACHED)) { - CDEBUG(D_IOCTL, "OBD Device %d has no type.\n", dev); - return -EINVAL; - } + data = (struct obd_ioctl_data *)buf; - /* has this been done already? */ - if ( obddev->obd_flags & OBD_SET_UP ) { - CDEBUG(D_IOCTL, "Device %d already setup (type %s)\n", - dev, obddev->obd_type->typ_name); + switch (cmd) { + case TCGETS: + return -EINVAL; + case OBD_IOC_DEVICE: { + CDEBUG(D_IOCTL, "\n"); + if (data->ioc_dev >= MAX_OBD_DEVICES || + data->ioc_dev < 0) { + printk("OBD ioctl: DEVICE insufficient devices\n"); return -EINVAL; } + CDEBUG(D_IOCTL, "device %d\n", data->ioc_dev); - /* get main structure */ - err = copy_from_user(&input, (void *) arg, sizeof(input)); - if (err) - return err; - - err = getdata(input.setup_datalen, &input.setup_data); - if (err) - return err; - - /* do the setup */ - CDEBUG(D_IOCTL, "Setup %d, type %s\n", dev, - obddev->obd_type->typ_name); - if ( !obddev->obd_type->typ_ops || - !obddev->obd_type->typ_ops->o_setup ) - return -EOPNOTSUPP; - - err = obddev->obd_type->typ_ops->o_setup - (obddev, input.setup_datalen, input.setup_data); - - if ( err ) - obddev->obd_flags &= ~OBD_SET_UP; - else - obddev->obd_flags |= OBD_SET_UP; - return err; - } - case OBD_IOC_CLEANUP_OBDDEV: { - int rc; - - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - if ( !obddev->obd_type->typ_refcnt ) - printk("OBD_CLEANUP: refcount wrap!\n"); - - if ( !obddev->obd_type->typ_ops->o_cleanup ) - goto cleanup_out; - - /* cleanup has no argument */ - rc = obddev->obd_type->typ_ops->o_cleanup(obddev); - if ( rc ) - return rc; - - cleanup_out: - obddev->obd_flags = 0; - obddev->obd_type->typ_refcnt--; - obddev->obd_type = NULL; - MOD_DEC_USE_COUNT; + filp->private_data = &obd_dev[data->ioc_dev]; + EXIT; return 0; } - case OBD_IOC_CONNECT: - { - struct obd_conn_info conninfo; - if ( (!(obddev->obd_flags & OBD_SET_UP)) || - (!(obddev->obd_flags & OBD_ATTACHED))) { - CDEBUG(D_IOCTL, "Device not attached or set up\n"); - return -EINVAL; + case OBD_IOC_ATTACH: { + struct obd_type *type; + + ENTRY; + /* have we attached a type to this device */ + if ( obd->obd_type || (obd->obd_flags & OBD_ATTACHED) ){ + printk("OBD: Device %d already typed as %s.\n", + obd->obd_minor, MKSTR(obd->obd_type->typ_name)); + return -EBUSY; + } + + printk("-----> attach %s %s\n", MKSTR(data->ioc_inlbuf1), + MKSTR(data->ioc_inlbuf2)); + + /* find the type */ + type = obd_nm_to_type(data->ioc_inlbuf1); + if ( !type ) { + printk("OBD: unknown type dev %d\n", obd->obd_minor); + return -EINVAL; + } + + obd->obd_type = type; + obd->obd_multi_count = 0; + INIT_LIST_HEAD(&obd->obd_gen_clients); + + /* do the attach */ + if ( OBT(obd) && OBP(obd, attach) ) { + err = OBP(obd, attach)(obd, data); } - if (obddev->obd_type->typ_ops->o_connect(obddev, &conninfo)) - return -EINVAL; - - return copy_to_user((int *)arg, &conninfo, - sizeof(struct obd_conn_info)); - } - case OBD_IOC_DISCONNECT: - /* frees data structures */ - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - get_user(cli_id, (int *) arg); - - obddev->obd_type->typ_ops->o_disconnect(cli_id); - return 0; - - case OBD_IOC_SYNC: - /* sync doesn't need a connection ID, because it knows - * what device it was called on, and can thus get the - * superblock that it needs. */ - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - if (!obddev->u.sim.sim_sb || !obddev->u.sim.sim_sb->s_dev) { - CDEBUG(D_IOCTL, "fatal: device not initialized.\n"); - err = -EINVAL; - } else { - if ((err = fsync_dev(obddev->u.sim.sim_sb->s_dev))) - CDEBUG(D_IOCTL, "sync: fsync_dev failure\n"); - else - CDEBUG(D_IOCTL, "sync: success\n"); + if ( err ) { + obd->obd_flags &= ~OBD_ATTACHED; + obd->obd_type = NULL; + EXIT; + } else { + obd->obd_flags |= OBD_ATTACHED; + type->typ_refcnt++; + printk("OBD: dev %d attached type %s\n", + obd->obd_minor, data->ioc_inlbuf1); + obd->obd_proc_entry = + proc_lustre_register_obd_device(obd); + MOD_INC_USE_COUNT; + EXIT; + } + + return err; + } + + case OBD_IOC_DETACH: { + ENTRY; + if (obd->obd_flags & OBD_SET_UP) { + printk("OBD device %d still set up\n", obd->obd_minor); + return -EBUSY; + } + if (! (obd->obd_flags & OBD_ATTACHED) ) { + printk("OBD device %d not attached\n", obd->obd_minor); + return -ENODEV; + } + if ( !list_empty(&obd->obd_gen_clients) ) { + printk("OBD device %d has connected clients\n", obd->obd_minor); + return -EBUSY; + } + + if (obd->obd_proc_entry) + proc_lustre_release_obd_device(obd); + + obd->obd_flags &= ~OBD_ATTACHED; + obd->obd_type->typ_refcnt--; + obd->obd_type = NULL; + MOD_DEC_USE_COUNT; + EXIT; + return 0; + } + + case OBD_IOC_SETUP: { + ENTRY; + /* have we attached a type to this device? */ + if (!(obd->obd_flags & OBD_ATTACHED)) { + printk("Device %d not attached\n", obd->obd_minor); + return -ENODEV; + } + + /* has this been done already? */ + if ( obd->obd_flags & OBD_SET_UP ) { + printk("Device %d already setup (type %s)\n", + obd->obd_minor, obd->obd_type->typ_name); + return -EBUSY; + } + + if ( OBT(obd) && OBP(obd, setup) ) + err = OBP(obd, setup)(obd, data); + + if (!err) { + obd->obd_type->typ_refcnt++; + obd->obd_flags |= OBD_SET_UP; + EXIT; } - return put_user(err, (int *) arg); - case OBD_IOC_CREATE: - /* similarly, create doesn't need a connection ID for - * the same reasons. */ - - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - - if (!obddev->u.sim.sim_sb) { - CDEBUG(D_IOCTL, "fatal: device not initialized.\n"); - return put_user(-EINVAL, (int *) arg); - } - - i_ino = obddev->obd_type->typ_ops->o_create(obddev, 0, &err); - if (err) { - CDEBUG(D_IOCTL, "create: obd_inode_new failure\n"); - /* 0 is the only error value */ - return put_user(0, (int *) arg); - } - - return put_user(i_ino, (int *) arg); - case OBD_IOC_DESTROY: - { - struct destroy_s { - unsigned int conn_id; - unsigned int ino; - } destroy; - - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - - copy_from_user(&destroy, (int *)arg, sizeof(struct destroy_s)); - if ( !obddev->obd_type || - !obddev->obd_type->typ_ops->o_destroy) - return -EINVAL; - - return obddev->obd_type->typ_ops->o_destroy(destroy.conn_id, destroy.ino); - } - case OBD_IOC_SETATTR: - { - int err; - struct tmp { - unsigned int conn_id; - unsigned long ino; - struct iattr iattr; - } foo; - struct inode holder; - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - - err= copy_from_user(&foo, (int *)arg, sizeof(struct tmp)); - if (err) - return err; - - if ( !obddev->obd_type || - !obddev->obd_type->typ_ops->o_setattr) - return -EINVAL; - - inode_setattr(&holder, &foo.iattr); - return obddev->obd_type->typ_ops->o_setattr(foo.conn_id, foo.ino, &holder); - } - - case OBD_IOC_GETATTR: - { - int err; - struct tmp { - unsigned int conn_id; - unsigned long ino; - } foo; - struct iattr iattr; - struct inode holder; - copy_from_user(&foo, (int *)arg, sizeof(struct tmp)); - - if ( !obddev->obd_type || - !obddev->obd_type->typ_ops->o_getattr) - return -EINVAL; - - if (obddev->obd_type->typ_ops->o_getattr(foo.conn_id, - foo.ino, &holder)) - return -EINVAL; - - inode_to_iattr(&holder, &iattr); - err = copy_to_user((int *)arg, &iattr, sizeof(iattr)); - return err; - } - - case OBD_IOC_READ2: - { - int err; - - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - err = copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s)); - if ( err ) - return err; - - if ( !obddev->obd_type->typ_ops || - !obddev->obd_type->typ_ops->o_read ) - return -EINVAL; - - rw_s.count = obddev->obd_type->typ_ops->o_read2(rw_s.conn_id, - rw_s.inode, - rw_s.buf, - rw_s.count, - rw_s.offset, - &err); - if ( err ) - return err; - - err = copy_to_user((int*)arg, &rw_s.count, - sizeof(unsigned long)); - return err; - } - - - case OBD_IOC_READ: - { - int err; - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - - err = copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s)); - if ( err ) - return err; - - if ( !obddev->obd_type->typ_ops || - !obddev->obd_type->typ_ops->o_read ) - return -EINVAL; - - rw_s.count = obddev->obd_type->typ_ops->o_read(rw_s.conn_id, - rw_s.inode, - rw_s.buf, - rw_s.count, - rw_s.offset, - &err); - if ( err ) - return err; - - err = copy_to_user((int*)arg, &rw_s.count, - sizeof(unsigned long)); - return err; - } - - case OBD_IOC_WRITE: - { - int err; - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - - copy_from_user(&rw_s, (int *)arg, sizeof(struct oic_rw_s)); - CDEBUG(D_IOCTL, "\n"); - if ( !obddev->obd_type->typ_ops->o_write ) - return -EINVAL; - rw_s.count = - obddev->obd_type->typ_ops->o_write(rw_s.conn_id, - rw_s.inode, - rw_s.buf, - rw_s.count, - rw_s.offset, - &err); - - printk("Result rw_s.count %ld\n", rw_s.count); - return (int)rw_s.count; - copy_to_user((int *)arg, &rw_s.count, - sizeof(unsigned long)); - return err; + return err; + } + case OBD_IOC_CLEANUP: { + ENTRY; + /* has this minor been registered? */ + if (!obd->obd_type) { + printk("OBD cleanup dev %d has no type.\n", + obd->obd_minor); + EXIT; + return -ENODEV; + } + + if ( (!(obd->obd_flags & OBD_SET_UP)) || + (!(obd->obd_flags & OBD_ATTACHED))) { + printk("OBD cleanup device %d not attached/set up\n", + obd->obd_minor); + EXIT; + return -ENODEV; + } + + if ( !OBT(obd) || !OBP(obd, cleanup) ) + goto cleanup_out; + + /* cleanup has no argument */ + err = OBP(obd, cleanup)(obd); + if ( err ) { + EXIT; + return err; + } + + cleanup_out: + obd->obd_flags &= ~OBD_SET_UP; + obd->obd_type->typ_refcnt--; + EXIT; + return 0; + } + + case OBD_IOC_CONNECT: + { + if ( (!(obd->obd_flags & OBD_SET_UP)) || + (!(obd->obd_flags & OBD_ATTACHED))) { + CDEBUG(D_IOCTL, "Device not attached or set up\n"); + return -ENODEV; + } + + if ( !OBT(obd) || !OBP(obd, connect) ) + return -EOPNOTSUPP; + + conn.oc_id = data->ioc_conn1; + conn.oc_dev = obd; + + err = OBP(obd, connect)(&conn); + CDEBUG(D_IOCTL, "assigned connection %d\n", conn.oc_id); + data->ioc_conn1 = conn.oc_id; + if ( err ) + return err; + + return copy_to_user((int *)arg, data, sizeof(*data)); + } + case OBD_IOC_DISCONNECT: { + + if (!obd->obd_type) + return -ENODEV; + + if ( !OBT(obd) || !OBP(obd, disconnect)) + return -EOPNOTSUPP; + + conn.oc_id = data->ioc_conn1; + conn.oc_dev = obd; + OBP(obd, disconnect)(&conn); + return 0; + } + + case OBD_IOC_DEC_USE_COUNT: { + MOD_DEC_USE_COUNT; + return 0; } - case OBD_IOC_PREALLOCATE: - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - - copy_from_user(&prealloc, (int *)arg, - sizeof(struct oic_prealloc_s)); - - if (!obddev->u.sim.sim_sb || !obddev->u.sim.sim_sb->s_dev) { - CDEBUG(D_IOCTL, "fatal: device not initialized.\n"); - return -EINVAL; - } - if (!obddev->obd_type || - !obddev->obd_type->typ_ops->o_preallocate) - return -EINVAL; - - prealloc.alloc = - obddev->obd_type->typ_ops->o_preallocate(prealloc.cli_id, prealloc.alloc, - prealloc.inodes, &err); - if ( err ) - return err; - return copy_to_user((int *)arg, &prealloc, - sizeof(struct oic_prealloc_s)); - case OBD_IOC_STATFS: - { - struct statfs *tmp; - unsigned int conn_id; - struct statfs buf; - int rc; - - /* has this minor been registered? */ - if (!obddev->obd_type) - return -ENODEV; - - tmp = (void *)arg + sizeof(unsigned int); - get_user(conn_id, (int *) arg); - if ( !obddev->obd_type || - !obddev->obd_type->typ_ops->o_statfs) - return -EINVAL; - - rc = obddev->obd_type->typ_ops->o_statfs(conn_id, &buf); - if ( rc ) - return rc; - rc = copy_to_user(tmp, &buf, sizeof(buf)); - return rc; - - } + case OBD_IOC_CREATE: { + /* has this minor been registered? */ + if ( !(obd->obd_flags & OBD_ATTACHED) || + !(obd->obd_flags & OBD_SET_UP)) { + CDEBUG(D_IOCTL, "Device not attached or set up\n"); + return -ENODEV; + } + conn.oc_id = data->ioc_conn1; + conn.oc_dev = obd; + + if ( !OBT(obd) || !OBP(obd, create) ) + return -EOPNOTSUPP; + + err = OBP(obd, create)(&conn, &data->ioc_obdo1); + if (err) { + EXIT; + return err; + } + + err = copy_to_user((int *)arg, data, sizeof(*data)); + EXIT; + return err; + } +#if 0 + case OBD_IOC_SYNC: { + struct oic_range_s *range = tmp_buf; + + if (!obd->obd_type) + return -ENODEV; + + err = copy_from_user(range, (const void *)arg, sizeof(*range)); + + if ( err ) { + EXIT; + return err; + } + + if ( !OBT(obd) || !OBP(obd, sync) ) { + err = -EOPNOTSUPP; + EXIT; + return err; + } + + /* XXX sync needs to be tested/verified */ + err = OBP(obd, sync)(&conn, &range->obdo, range->count, + range->offset); + + if ( err ) { + EXIT; + return err; + } + + return put_user(err, (int *) arg); + } + + case OBD_IOC_DESTROY: { + struct oic_attr_s *attr = tmp_buf; + + /* has this minor been registered? */ + if (!obd->obd_type) + return -ENODEV; + + err = copy_from_user(attr, (int *)arg, sizeof(*attr)); + if ( err ) { + EXIT; + return err; + } + + if ( !OBT(obd) || !OBP(obd, destroy) ) + return -EOPNOTSUPP; + + conn.oc_id = attr->conn_id; + err = OBP(obd, destroy)(&conn, &attr->obdo); + EXIT; + return err; + } + + case OBD_IOC_SETATTR: { + struct oic_attr_s *attr = tmp_buf; + + /* has this minor been registered? */ + if (!obd->obd_type) + return -ENODEV; + + err = copy_from_user(attr, (int *)arg, sizeof(*attr)); + if (err) + return err; + + if ( !OBT(obd) || !OBP(obd, setattr) ) + return -EOPNOTSUPP; + + conn.oc_id = attr->conn_id; + err = OBP(obd, setattr)(&conn, &attr->obdo); + EXIT; + return err; + } + + case OBD_IOC_GETATTR: { + struct oic_attr_s *attr = tmp_buf; + + err = copy_from_user(attr, (int *)arg, sizeof(*attr)); + if (err) + return err; + + conn.oc_id = attr->conn_id; + ODEBUG(&attr->obdo); + err = OBP(obd, getattr)(&conn, &attr->obdo); + if ( err ) { + EXIT; + return err; + } + + err = copy_to_user((int *)arg, attr, sizeof(*attr)); + EXIT; + return err; + } + + case OBD_IOC_READ: { + int err; + struct oic_rw_s *rw_s = tmp_buf; /* read, write ioctl str */ + + err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s)); + if ( err ) { + EXIT; + return err; + } + + conn.oc_id = rw_s->conn_id; + + if ( !OBT(obd) || !OBP(obd, read) ) { + err = -EOPNOTSUPP; + EXIT; + return err; + } + + + err = OBP(obd, read)(&conn, &rw_s->obdo, rw_s->buf, + &rw_s->count, rw_s->offset); + + ODEBUG(&rw_s->obdo); + CDEBUG(D_INFO, "READ: conn %d, count %Ld, offset %Ld, '%s'\n", + rw_s->conn_id, rw_s->count, rw_s->offset, rw_s->buf); + if ( err ) { + EXIT; + return err; + } + + err = copy_to_user((int*)arg, &rw_s->count, sizeof(rw_s->count)); + EXIT; + return err; + } + + case OBD_IOC_WRITE: { + struct oic_rw_s *rw_s = tmp_buf; /* read, write ioctl str */ + + err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s)); + if ( err ) { + EXIT; + return err; + } + + conn.oc_id = rw_s->conn_id; + + if ( !OBT(obd) || !OBP(obd, write) ) { + err = -EOPNOTSUPP; + return err; + } + + CDEBUG(D_INFO, "WRITE: conn %d, count %Ld, offset %Ld, '%s'\n", + rw_s->conn_id, rw_s->count, rw_s->offset, rw_s->buf); + + err = OBP(obd, write)(&conn, &rw_s->obdo, rw_s->buf, + &rw_s->count, rw_s->offset); + ODEBUG(&rw_s->obdo); + if ( err ) { + EXIT; + return err; + } + + err = copy_to_user((int *)arg, &rw_s->count, + sizeof(rw_s->count)); + EXIT; + return err; + } + case OBD_IOC_PREALLOCATE: { + struct oic_prealloc_s *prealloc = tmp_buf; + + /* has this minor been registered? */ + if (!obd->obd_type) + return -ENODEV; + + err = copy_from_user(prealloc, (int *)arg, sizeof(*prealloc)); + if (err) + return -EFAULT; + + if ( !(obd->obd_flags & OBD_ATTACHED) || + !(obd->obd_flags & OBD_SET_UP)) { + CDEBUG(D_IOCTL, "Device not attached or set up\n"); + return -ENODEV; + } + + if ( !OBT(obd) || !OBP(obd, preallocate) ) + return -EOPNOTSUPP; + + conn.oc_id = prealloc->conn_id; + err = OBP(obd, preallocate)(&conn, &prealloc->alloc, + prealloc->ids); + if ( err ) { + EXIT; + return err; + } + + err =copy_to_user((int *)arg, prealloc, sizeof(*prealloc)); + EXIT; + return err; + } + case OBD_IOC_STATFS: { + struct statfs *tmp; + unsigned int conn_id; + struct statfs buf; + + /* has this minor been registered? */ + if (!obd->obd_type) + return -ENODEV; + + tmp = (void *)arg + sizeof(unsigned int); + get_user(conn_id, (int *) arg); + + if ( !OBT(obd) || !OBP(obd, statfs) ) + return -EOPNOTSUPP; + + conn.oc_id = conn_id; + err = OBP(obd, statfs)(&conn, &buf); + if ( err ) { + EXIT; + return err; + } + err = copy_to_user(tmp, &buf, sizeof(buf)); + EXIT; + return err; + + } + case OBD_IOC_COPY: { + struct ioc_mv_s *mvdata = tmp_buf; + + if ( (!(obd->obd_flags & OBD_SET_UP)) || + (!(obd->obd_flags & OBD_ATTACHED))) { + CDEBUG(D_IOCTL, "Device not attached or set up\n"); + return -ENODEV; + } + + /* get main structure */ + err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata)); + if (err) { + EXIT; + return err; + } + + if ( !OBT(obd) || !OBP(obd, copy) ) + return -EOPNOTSUPP; + + /* do the partition */ + CDEBUG(D_INFO, "Copy %d, type %s dst %Ld src %Ld\n", dev, + obd->obd_type->typ_name, mvdata->dst.o_id, + mvdata->src.o_id); + + conn.oc_id = mvdata->src_conn_id; + + err = OBP(obd, copy)(&conn, &mvdata->dst, + &conn, &mvdata->src, + mvdata->src.o_size, 0); + return err; + } + + case OBD_IOC_MIGR: { + struct ioc_mv_s *mvdata = tmp_buf; + + if ( (!(obd->obd_flags & OBD_SET_UP)) || + (!(obd->obd_flags & OBD_ATTACHED))) { + CDEBUG(D_IOCTL, "Device not attached or set up\n"); + return -ENODEV; + } + + err = copy_from_user(mvdata, (void *) arg, sizeof(*mvdata)); + if (err) { + EXIT; + return err; + } + + CDEBUG(D_INFO, "Migrate copying %d bytes\n", sizeof(*mvdata)); + + if ( !OBT(obd) || !OBP(obd, migrate) ) + return -EOPNOTSUPP; + + /* do the partition */ + CDEBUG(D_INFO, "Migrate %d, type %s conn %d src %Ld dst %Ld\n", + dev, obd->obd_type->typ_name, mvdata->src_conn_id, + mvdata->src.o_id, mvdata->dst.o_id); + + conn.oc_id = mvdata->src_conn_id; + err = OBP(obd, migrate)(&conn, &mvdata->dst, &mvdata->src, + mvdata->src.o_size, 0); + + return err; + } + case OBD_IOC_PUNCH: { + struct oic_rw_s *rw_s = tmp_buf; /* read, write ioctl str */ + + err = copy_from_user(rw_s, (int *)arg, sizeof(*rw_s)); + if ( err ) { + EXIT; + return err; + } + + conn.oc_id = rw_s->conn_id; + + if ( !OBT(obd) || !OBP(obd, punch) ) { + err = -EOPNOTSUPP; + return err; + } + + CDEBUG(D_INFO, "PUNCH: conn %d, count %Ld, offset %Ld\n", + rw_s->conn_id, rw_s->count, rw_s->offset); + err = OBP(obd, punch)(&conn, &rw_s->obdo, rw_s->count, + rw_s->offset); + ODEBUG(&rw_s->obdo); + if ( err ) { + EXIT; + return err; + } + EXIT; + return err; + } + + default: { + struct obd_type *type; + struct oic_generic input; + char *nm; + void *karg; + + /* get data structures */ + err = copy_from_user(&input, (void *)arg, sizeof(input)); + if ( err ) { + EXIT; + return err; + } + + err = getdata(input.att_typelen + 1, &input.att_type); + if ( err ) { + EXIT; + return err; + } + + /* find the type */ + nm = input.att_type; + type = obd_nm_to_type(nm); +#ifdef CONFIG_KMOD + if ( !type ) { + if ( !request_module(nm) ) { + CDEBUG(D_PSDEV, "Loaded module '%s'\n", nm); + type = obd_nm_to_type(nm); + } else { + CDEBUG(D_PSDEV, "Can't load module '%s'\n", nm); + } + } +#endif + OBD_FREE(input.att_type, input.att_typelen + 1); + if ( !type ) { + printk(__FUNCTION__ ": unknown obd type dev %d\n", dev); + EXIT; + return -EINVAL; + } + + if ( !type->typ_ops || !type->typ_ops->o_iocontrol ) { + EXIT; + return -EOPNOTSUPP; + } + conn.oc_id = input.att_connid; + + CDEBUG(D_INFO, "Calling ioctl %x for type %s, len %d\n", + cmd, type->typ_name, input.att_datalen); + + /* get the generic data */ + karg = input.att_data; + err = getdata(input.att_datalen, &karg); + if ( err ) { + EXIT; + return err; + } + + err = type->typ_ops->o_iocontrol(cmd, &conn, input.att_datalen, + karg, input.att_data); + OBD_FREE(karg, input.att_datalen); + + EXIT; + return err; + } +#endif default: - printk("invalid ioctl: cmd = %x, arg = %lx\n", cmd, arg); - return -ENOTTY; - } -} + return -EINVAL; + + } +} /* obd_class_ioctl */ /* Driver interface done, utility functions follow */ int obd_register_type(struct obd_ops *ops, char *nm) { - struct obd_type *type; - - if ( obd_nm_to_type(nm) ) { - CDEBUG(D_IOCTL, "Type %s already registered\n", nm); - return -1; - } - - OBD_ALLOC(type, struct obd_type * , sizeof(*type)); - if ( !type ) - return -ENOMEM; - memset(type, 0, sizeof(*type)); - INIT_LIST_HEAD(&type->typ_chain); - - list_add(&type->typ_chain, obd_types.next); - type->typ_ops = ops; - type->typ_name = nm; - return 0; + struct obd_type *type; + + + if (obd_init_magic != 0x11223344) { + printk(__FUNCTION__ ": bad magic for type\n"); + EXIT; + return -EINVAL; + } + + if ( obd_nm_to_type(nm) ) { + CDEBUG(D_IOCTL, "Type %s already registered\n", nm); + EXIT; + return -EEXIST; + } + + OBD_ALLOC(type, struct obd_type * , sizeof(*type)); + if ( !type ) { + EXIT; + return -ENOMEM; + } + memset(type, 0, sizeof(*type)); + INIT_LIST_HEAD(&type->typ_chain); + MOD_INC_USE_COUNT; + list_add(&type->typ_chain, obd_types.next); + type->typ_ops = ops; + type->typ_name = nm; + EXIT; + return 0; } - + int obd_unregister_type(char *nm) { - struct obd_type *type = obd_nm_to_type(nm); - - if ( !type ) - return -1; - - if ( type->typ_refcnt ) - return -1; - - list_del(&type->typ_chain); - OBD_FREE(type, sizeof(*type)); - return 0; -} + struct obd_type *type = obd_nm_to_type(nm); + + if ( !type ) { + MOD_DEC_USE_COUNT; + printk(KERN_INFO __FUNCTION__ ": unknown obd type\n"); + EXIT; + return -EINVAL; + } + + if ( type->typ_refcnt ) { + MOD_DEC_USE_COUNT; + printk(KERN_ALERT __FUNCTION__ ":type %s has refcount " + "(%d)\n", nm, type->typ_refcnt); + EXIT; + return -EBUSY; + } + + list_del(&type->typ_chain); + OBD_FREE(type, sizeof(*type)); + MOD_DEC_USE_COUNT; + return 0; +} /* obd_unregister_type */ /* declare character device */ static struct file_operations obd_psdev_fops = { - NULL, /* llseek */ - NULL, /* read */ - NULL, /* write */ - NULL, /* presto_psdev_readdir */ - NULL, /* poll */ - obd_class_ioctl, /* ioctl */ - NULL, /* presto_psdev_mmap */ - obd_class_open, /* open */ - NULL, - obd_class_release, /* release */ - NULL, /* fsync */ - NULL, /* fasync */ - NULL, /* check_media_change */ - NULL, /* revalidate */ - NULL /* lock */ + ioctl: obd_class_ioctl, /* ioctl */ + open: obd_class_open, /* open */ + release: obd_class_release, /* release */ }; /* modules setup */ +#define OBD_MINOR 241 +static struct miscdevice obd_psdev = { + OBD_MINOR, + "obd_psdev", + &obd_psdev_fops +}; int init_obd(void) { - int i; - - printk(KERN_INFO "OBD class driver v0.002, braam@stelias.com\n"); - - INIT_LIST_HEAD(&obd_types); - - if (register_chrdev(OBD_PSDEV_MAJOR,"obd_psdev", - &obd_psdev_fops)) { - printk(KERN_ERR "obd_psdev: unable to get major %d\n", - OBD_PSDEV_MAJOR); - return -EIO; - } - - for (i = 0; i < MAX_OBD_DEVICES; i++) { - memset(&(obd_dev[i]), 0, sizeof(obd_dev[i])); - INIT_LIST_HEAD(&obd_dev[i].u.sim.sim_clients); - } - - obd_sysctl_init(); - - return 0; + int err; + int i; + + printk(KERN_INFO "OBD class driver v0.01, braam@stelias.com\n"); + + INIT_LIST_HEAD(&obd_types); + + if ( (err = misc_register(&obd_psdev)) ) { + printk(KERN_ERR __FUNCTION__ ": cannot register %d err %d\n", + OBD_MINOR, err); + return -EIO; + } + + for (i = 0; i < MAX_OBD_DEVICES; i++) { + memset(&(obd_dev[i]), 0, sizeof(obd_dev[i])); + obd_dev[i].obd_minor = i; + INIT_LIST_HEAD(&obd_dev[i].obd_gen_clients); + } + + err = obd_init_obdo_cache(); + if (err) + return err; + obd_sysctl_init(); + obd_init_magic = 0x11223344; + return 0; } EXPORT_SYMBOL(obd_register_type); @@ -730,25 +858,44 @@ EXPORT_SYMBOL(obd_print_entry); EXPORT_SYMBOL(obd_debug_level); EXPORT_SYMBOL(obd_dev); +EXPORT_SYMBOL(gen_connect); +EXPORT_SYMBOL(gen_client); +EXPORT_SYMBOL(gen_cleanup); +EXPORT_SYMBOL(gen_disconnect); +EXPORT_SYMBOL(gen_copy_data); +EXPORT_SYMBOL(obdo_cachep); + +/* EXPORT_SYMBOL(gen_multi_attach); */ +EXPORT_SYMBOL(gen_multi_setup); +EXPORT_SYMBOL(gen_multi_cleanup); + + #ifdef MODULE int init_module(void) { - return init_obd(); + return init_obd(); } void cleanup_module(void) { - int i; + int i; ENTRY; - unregister_chrdev(OBD_PSDEV_MAJOR, "obd_psdev"); - for (i = 0; i < MAX_OBD_DEVICES; i++) { - struct obd_device *obddev = &obd_dev[i]; - if ( obddev->obd_type && - obddev->obd_type->typ_ops->o_cleanup_device ) - return obddev->obd_type->typ_ops->o_cleanup_device(i); - } - - obd_sysctl_clean(); + misc_deregister(&obd_psdev); + for (i = 0; i < MAX_OBD_DEVICES; i++) { + struct obd_device *obd = &obd_dev[i]; + if ( obd->obd_type && + (obd->obd_flags & OBD_SET_UP) && + OBT(obd) && OBP(obd, detach) ) { + /* XXX should this call generic detach otherwise? */ + OBP(obd, detach)(obd); + } + } + + obd_cleanup_obdo_cache(); + obd_sysctl_clean(); + CDEBUG(D_MALLOC, "CLASS mem used %ld\n", obd_memory); + obd_init_magic = 0; + EXIT; } #endif