X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fobdclass%2Fgenops.c;h=b6403f369c8e24038067ffdec3ec047d1ce355f3;hb=51086597ce8a7041222ffeadef52d19a570a7c34;hp=bfc34994cd2f8a317694fc3949de5da67c8e8e9e;hpb=d2af72e46de8b349dc7356e2acdae375b257f6d0;p=fs%2Flustre-release.git diff --git a/lustre/obdclass/genops.c b/lustre/obdclass/genops.c index bfc3499..b6403f3 100644 --- a/lustre/obdclass/genops.c +++ b/lustre/obdclass/genops.c @@ -1,243 +1,367 @@ /* * linux/fs/ext2_obd/sim_obd.c + * Copyright (C) 2001 Cluster File Systems, Inc. * - * These are the only exported functions; they provide the simulated object- - * oriented disk. + * This code is issued under the GNU General Public License. + * See the file COPYING in this distribution + * + * These are the only exported functions, they provide some generic + * infrastructure for managing object devices * */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#define DEBUG_SUBSYSTEM S_CLASS +#include /* for request_module() */ +#include #include +#include +#include - +extern struct list_head obd_types; extern struct obd_device obd_dev[MAX_OBD_DEVICES]; +kmem_cache_t *obdo_cachep = NULL; +kmem_cache_t *export_cachep = NULL; +kmem_cache_t *import_cachep = NULL; -/* map connection to client */ -struct obd_client *gen_client(struct obd_conn *conn) +/* + * support functions: we could use inter-module communication, but this + * is more portable to other OS's + */ +static struct obd_type *class_search_type(char *nm) { - struct obd_device * obddev = conn->oc_dev; - struct list_head * lh, * next; - struct obd_client * cli; - - lh = next = &obddev->obd_gen_clients; - while ((lh = lh->next) != &obddev->obd_gen_clients) { - cli = list_entry(lh, struct obd_client, cli_chain); - - if (cli->cli_id == conn->oc_id) - return cli; - } - - return NULL; -} /* obd_client */ + 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; +} +struct obd_type *class_nm_to_type(char *nm) +{ + struct obd_type *type = class_search_type(nm); + +#ifdef CONFIG_KMOD + if ( !type ) { + if ( !request_module(nm) ) { + CDEBUG(D_INFO, "Loaded module '%s'\n", nm); + type = class_search_type(nm); + } else { + CDEBUG(D_INFO, "Can't load module '%s'\n", nm); + } + } +#endif + return type; +} +int class_register_type(struct obd_ops *ops, char *nm) +{ + struct obd_type *type; + + ENTRY; + + if (class_search_type(nm)) { + CDEBUG(D_IOCTL, "Type %s already registered\n", nm); + RETURN(-EEXIST); + } + + OBD_ALLOC(type, sizeof(*type)); + if (!type) + RETURN(-ENOMEM); + 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; + RETURN(0); +} -/* a connection defines a context in which preallocation can be managed. */ -int gen_connect (struct obd_conn *conn) +int class_unregister_type(char *nm) { - struct obd_client * cli; + struct obd_type *type = class_nm_to_type(nm); - OBD_ALLOC(cli, struct obd_client *, sizeof(struct obd_client)); - if ( !cli ) { - printk("obd_connect (minor %d): no memory!\n", - conn->oc_dev->obd_minor); - return -ENOMEM; - } + ENTRY; - INIT_LIST_HEAD(&cli->cli_prealloc_inodes); - /* this should probably spinlocked? */ - cli->cli_id = ++conn->oc_dev->obd_gen_last_id; - cli->cli_prealloc_quota = 0; - cli->cli_obd = conn->oc_dev; - list_add(&(cli->cli_chain), conn->oc_dev->obd_gen_clients.prev); + if ( !type ) { + MOD_DEC_USE_COUNT; + CERROR("unknown obd type\n"); + RETURN(-EINVAL); + } - CDEBUG(D_IOCTL, "connect: new ID %u\n", cli->cli_id); - conn->oc_id = cli->cli_id; - return 0; -} /* gen_obd_connect */ + if ( type->typ_refcnt ) { + MOD_DEC_USE_COUNT; + CERROR("type %s has refcount (%d)\n", nm, type->typ_refcnt); + RETURN(-EBUSY); + } + list_del(&type->typ_chain); + OBD_FREE(type, sizeof(*type)); + MOD_DEC_USE_COUNT; + RETURN(0); +} /* class_unregister_type */ -int gen_disconnect(struct obd_conn *conn) +int class_name2dev(char *name) { - struct obd_client * cli; - ENTRY; - - if (!(cli = gen_client(conn))) { - CDEBUG(D_IOCTL, "disconnect: attempting to free " - "nonexistent client %u\n", conn->oc_id); - return -EINVAL; - } - + int res = -1; + int i; - list_del(&(cli->cli_chain)); - OBD_FREE(cli, sizeof(struct obd_client)); + if (!name) + return -1; - CDEBUG(D_IOCTL, "disconnect: ID %u\n", conn->oc_id); - - EXIT; - return 0; -} /* gen_obd_disconnect */ + for (i=0; i < MAX_OBD_DEVICES; i++) { + struct obd_device *obd = &obd_dev[i]; + if (obd->obd_name && strcmp(name, obd->obd_name) == 0) { + res = i; + return res; + } + } + return res; +} -/* - * raid1 defines a number of connections to child devices, - * used to make calls to these devices. - * data holds nothing - */ -int gen_multi_setup(struct obd_device *obddev, int len, void *data) +int class_uuid2dev(char *name) { - int i; - - for (i = 0 ; i < obddev->obd_multi_count ; i++ ) { - int rc; - struct obd_conn *ch_conn = &obddev->obd_multi_conn[i]; - rc = OBP(ch_conn->oc_dev, connect)(ch_conn); - - if ( rc != 0 ) { - /* XXX disconnect others */ - return -EINVAL; - } - } - return 0; + int res = -1; + int i; + + for (i=0; i < MAX_OBD_DEVICES; i++) { + struct obd_device *obd = &obd_dev[i]; + if (obd->obd_name && strncmp(name, obd->obd_uuid, 37) == 0) { + res = i; + return res; + } + } + + return res; } -#if 0 -int gen_multi_attach(struct obd_device *obddev, int len, void *data) +struct obd_device *class_uuid2obd(char *name) { - int i; - int count; - struct obd_device *rdev = obddev->obd_multi_dev[0]; - - count = len/sizeof(int); - obddev->obd_multi_count = count; - for (i=0 ; iobd_type->typ_name); - } - return 0; -} -#endif + int i; + for (i=0; i < MAX_OBD_DEVICES; i++) { + struct obd_device *obd = &obd_dev[i]; + if (obd->obd_name && strncmp(name, obd->obd_uuid, 37) == 0) { + return obd; + } + } -/* - * remove all connections to this device - * close all connections to lower devices - * needed for forced unloads of OBD client drivers - */ -int gen_multi_cleanup(struct obd_device *obddev) + return NULL; +} + +void obd_cleanup_caches(void) { - int i; + int rc; + ENTRY; + if (obdo_cachep) { + rc = kmem_cache_destroy(obdo_cachep); + if (rc) + CERROR("Cannot destory obdo_cachep\n"); + obdo_cachep = NULL; + } + if (import_cachep) { + rc = kmem_cache_destroy(import_cachep); + if (rc) + CERROR("Cannot destory import_cachep\n"); + import_cachep = NULL; + } + if (export_cachep) { + rc = kmem_cache_destroy(export_cachep); + if (rc) + CERROR("Cannot destory import_cachep\n"); + export_cachep = NULL; + } + EXIT; +} - for (i = 0 ; i < obddev->obd_multi_count ; i++ ) { - struct obd_conn *ch_conn = &obddev->obd_multi_conn[i]; - int rc; - rc = OBP(ch_conn->oc_dev, disconnect)(ch_conn); +int obd_init_caches(void) +{ + ENTRY; + if (obdo_cachep == NULL) { + obdo_cachep = kmem_cache_create("obdo_cache", + sizeof(struct obdo), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (obdo_cachep == NULL) + GOTO(out, -ENOMEM); + } + + if (export_cachep == NULL) { + export_cachep = kmem_cache_create("export_cache", + sizeof(struct obd_export), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (export_cachep == NULL) + GOTO(out, -ENOMEM); + } + + if (import_cachep == NULL) { + import_cachep = kmem_cache_create("import_cache", + sizeof(struct obd_import), + 0, SLAB_HWCACHE_ALIGN, + NULL, NULL); + if (import_cachep == NULL) + GOTO(out, -ENOMEM); + } + RETURN(0); + out: + obd_cleanup_caches(); + RETURN(-ENOMEM); - if ( rc != 0 ) { - printk("OBD multi cleanup dev: disconnect failure %d\n", ch_conn->oc_dev->obd_minor); - } - } - return 0; -} /* gen_multi_cleanup_device */ +} +/* map connection to client */ +struct obd_export *class_conn2export(struct lustre_handle *conn) +{ + struct obd_export * export; + + if (!conn) + RETURN(NULL); + + if (!conn->addr || conn->addr == -1 ) { + fixme(); + RETURN(NULL); + } + + export = (struct obd_export *) (unsigned long)conn->addr; + if (!kmem_cache_validate(export_cachep, (void *)export)) + RETURN(NULL); + + if (export->export_cookie != conn->cookie) + return NULL; + return export; +} /* class_conn2export */ + +struct obd_device *class_conn2obd(struct lustre_handle *conn) +{ + struct obd_export *export; + export = class_conn2export(conn); + if (export) + return export->export_obd; + fixme(); + return NULL; +} -/* - * forced cleanup of the device: - * - remove connections from the device - * - cleanup the device afterwards - */ -int gen_cleanup(struct obd_device * obddev) +/* a connection defines an export context in which preallocation can + be managed. */ +int class_connect (struct lustre_handle *conn, struct obd_device *obd) +{ + struct obd_export * export; + + export = kmem_cache_alloc(export_cachep, GFP_KERNEL); + if ( !export ) { + CERROR("no memory! (minor %d)\n", obd->obd_minor); + return -ENOMEM; + } + + memset(export, 0, sizeof(*export)); + get_random_bytes(&export->export_cookie, sizeof(__u64)); + export->export_obd = obd; + export->export_import.addr = conn->addr; + export->export_import.cookie = conn->cookie; + + list_add(&(export->export_chain), export->export_obd->obd_exports.prev); + conn->addr = (__u64) (unsigned long)export; + conn->cookie = export->export_cookie; + return 0; +} + +int class_disconnect(struct lustre_handle *conn) { - struct list_head * lh, * tmp; - struct obd_client * cli; + struct obd_export * export; + ENTRY; - ENTRY; + if (!(export = class_conn2export(conn))) { + fixme(); + CDEBUG(D_IOCTL, "disconnect: attempting to free " + "nonexistent client %Lx\n", conn->addr); + RETURN(-EINVAL); + } + list_del(&export->export_chain); + kmem_cache_free(export_cachep, export); - lh = tmp = &obddev->obd_gen_clients; - while ((tmp = tmp->next) != lh) { - cli = list_entry(tmp, struct obd_client, cli_chain); - CDEBUG(D_IOCTL, "Disconnecting obd_connection %d, at %p\n", - cli->cli_id, cli); - } - return 0; -} /* sim_cleanup_device */ + RETURN(0); +} -void ___wait_on_page(struct page *page) -{ - struct task_struct *tsk = current; - DECLARE_WAITQUEUE(wait, tsk); - - add_wait_queue(&page->wait, &wait); - do { - run_task_queue(&tq_disk); - set_task_state(tsk, TASK_UNINTERRUPTIBLE); - if (!PageLocked(page)) - break; - schedule(); - } while (PageLocked(page)); - tsk->state = TASK_RUNNING; - remove_wait_queue(&page->wait, &wait); -} +#if 0 -void lck_page(struct page *page) +/* FIXME: Data is a space- or comma-separated list of device IDs. This will + * have to change. */ +int class_multi_setup(struct obd_device *obddev, uint32_t len, void *data) { - while (TryLockPage(page)) - ___wait_on_page(page); + int count, rc; + char *p; + ENTRY; + + for (p = data, count = 0; p < (char *)data + len; count++) { + char *end; + int tmp = simple_strtoul(p, &end, 0); + + if (p == end) { + CERROR("invalid device ID starting at: %s\n", p); + GOTO(err_disconnect, rc = -EINVAL); + } + + if (tmp < 0 || tmp >= MAX_OBD_DEVICES) { + CERROR("Trying to sub dev %d - dev no too large\n", + tmp); + GOTO(err_disconnect, rc = -EINVAL); + } + + rc = obd_connect(&obddev->obd_multi_conn[count], &obd_dev[tmp]); + if (rc) { + CERROR("cannot connect to device %d: rc = %d\n", tmp, + rc); + GOTO(err_disconnect, rc); + } + + CDEBUG(D_INFO, "target OBD %d is of type %s\n", count, + obd_dev[tmp].obd_type->typ_name); + + p = end + 1; + } + + obddev->obd_multi_count = count; + + RETURN(0); + + err_disconnect: + for (count--; count >= 0; count--) + obd_disconnect(&obddev->obd_multi_conn[count]); + return rc; } -/* XXX this should return errors correctly, so should migrate!!! */ -int gen_copy_data(struct obd_conn *conn, obdattr *tgt, obdattr *src) +/* + * remove all connections to this device + * close all connections to lower devices + * needed for forced unloads of OBD client drivers + */ +int class_multi_cleanup(struct obd_device *obddev) { - struct page *page; - unsigned long index = 0; - int rc; - ENTRY; - - CDEBUG(D_INODE, "src: ino %ld blocks %ld, size %Ld, dst: ino %ld\n", - src->i_ino, src->i_blocks, src->i_size, tgt->i_ino); - page = alloc_page(GFP_USER); - if ( !page ) { - EXIT; - return -ENOMEM; - } - - lck_page(page); - - while (index < ((src->i_size + PAGE_SIZE - 1) >> PAGE_SHIFT)) { - - page->index = index; - rc = OBP(conn->oc_dev, brw)(READ, conn, src, page, 0); - - if ( rc != PAGE_SIZE ) - break; - - rc = OBP(conn->oc_dev,brw)(WRITE, conn, tgt, page, 1); - if ( rc != PAGE_SIZE) - break; - - CDEBUG(D_INODE, "Copied page %d ...\n", index); - - index ++; - } - tgt->i_size = src->i_size; - tgt->i_blocks = src->i_blocks; - UnlockPage(page); - __free_page(page); - - EXIT; - return 0; + int i; + + for (i = 0; i < obddev->obd_multi_count; i++) { + int rc; + struct obd_device *obd = class_conn2obd(&obddev->obd_multi_conn[i]); + + if (!obd) { + CERROR("no such device [i %d]\n", i); + RETURN(-EINVAL); + } + + rc = obd_disconnect(&obddev->obd_multi_conn[i]); + if (rc) + CERROR("disconnect failure %d\n", obd->obd_minor); + } + return 0; } +#endif