X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fobdclass%2Fclass_obd.c;h=2569fb277ef1e49db93c31b6a9e961af1766e29d;hp=4f357fc3023e351ed250fab553e76ba1aef7f1fa;hb=400b0681017091fab9cef9bd00e0f536e1793dcc;hpb=fdee78b5e9e59757fa219266696098e48c782caa;ds=sidebyside diff --git a/lustre/obdclass/class_obd.c b/lustre/obdclass/class_obd.c index 4f357fc..2569fb2 100644 --- a/lustre/obdclass/class_obd.c +++ b/lustre/obdclass/class_obd.c @@ -1,32 +1,15 @@ /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * - * An implementation of a loadable kernel mode driver providing - * multiple kernel/user space bidirectional communications links. + * Copyright (C) 2001, 2002 Cluster File Systems, Inc. * - * Author: Alan Cox + * This code is issued under the GNU General Public License. + * See the file COPYING in this distribution * - * 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 - * Michael Callahan + * These are the only exported functions, they provide some generic + * infrastructure for managing object devices * - * Changes for Linux 2.1 - * Copyright (c) 1997 Carnegie-Mellon University - * - * Redone again for Intermezzo - * Copyright (c) 1998 Peter J. Braam - * - * Hacked up again for simulated OBD - * Copyright (c) 1999 Stelias Computing, Inc. - * (authors {pschwan,braam}@stelias.com) - * Copyright (C) 1999 Seagate Technology, Inc. - * Copyright (C) 2001 Cluster File Systems, Inc. - * - * + * Object Devices Class Driver */ #define EXPORT_SYMTAB @@ -35,7 +18,6 @@ #include #include #include -#include /* for request_module() */ #include #include #include @@ -49,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -58,12 +41,21 @@ #include #include +#include +#include +#include -static int obd_init_magic; -unsigned long obd_memory = 0; -unsigned long obd_fail_loc = 0; +struct semaphore obd_conf_sem; /* serialize configuration commands */ struct obd_device obd_dev[MAX_OBD_DEVICES]; struct list_head obd_types; +unsigned long obd_memory; + +/* The following are visible and mutable through /proc/sys/lustre/. */ +unsigned long obd_fail_loc; +unsigned long obd_timeout = 100; +char obd_recovery_upcall[128] = "/usr/lib/lustre/ha_assist"; + +extern struct obd_type *class_nm_to_type(char *nm); /* opening /dev/obd */ static int obd_class_open(struct inode * inode, struct file * file) @@ -71,6 +63,8 @@ static int obd_class_open(struct inode * inode, struct file * file) ENTRY; file->private_data = NULL; + CDEBUG(D_IOCTL, "MOD_INC_USE for open: count = %d\n", + atomic_read(&(THIS_MODULE)->uc.usecount)); MOD_INC_USE_COUNT; RETURN(0); } @@ -80,131 +74,205 @@ static int obd_class_release(struct inode * inode, struct file * file) { ENTRY; + // XXX drop lsm, connections here if (file->private_data) file->private_data = NULL; + CDEBUG(D_IOCTL, "MOD_DEC_USE for close: count = %d\n", + atomic_read(&(THIS_MODULE)->uc.usecount) - 1); MOD_DEC_USE_COUNT; RETURN(0); } -static int obd_class_name2dev(char *name) -{ - int res = -1; - int i; - - 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; +inline void obd_data2conn(struct lustre_handle *conn, struct obd_ioctl_data *data) +{ + conn->addr = data->ioc_addr; + conn->cookie = data->ioc_cookie; } -/* - * 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) + +inline void obd_conn2data(struct obd_ioctl_data *data, struct lustre_handle *conn) { - 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; + data->ioc_addr = conn->addr; + data->ioc_cookie = conn->cookie; } -static struct obd_type *obd_nm_to_type(char *nm) +static void forcibly_detach_exports(struct obd_device *obd) { - struct obd_type *type = obd_search_type(nm); - -#ifdef CONFIG_KMOD - if ( !type ) { - if ( !request_module(nm) ) { - CDEBUG(D_INFO, "Loaded module '%s'\n", nm); - type = obd_search_type(nm); + int rc; + struct list_head *tmp, *n; + struct lustre_handle fake_conn; + + CDEBUG(D_IOCTL, "OBD device %d (%p) has exports, " + "disconnecting them", obd->obd_minor, obd); + list_for_each_safe(tmp, n, &obd->obd_exports) { + struct obd_export *exp = list_entry(tmp, struct obd_export, + exp_obd_chain); + fake_conn.addr = (__u64)(unsigned long)exp; + fake_conn.cookie = exp->exp_cookie; + rc = obd_disconnect(&fake_conn); + if (rc) { + CDEBUG(D_IOCTL, "disconnecting export %p failed: %d\n", + exp, rc); } else { - CDEBUG(D_INFO, "Can't load module '%s'\n", nm); + CDEBUG(D_IOCTL, "export %p disconnected\n", exp); } } -#endif - return type; } /* to control /dev/obd */ -static int obd_class_ioctl (struct inode * inode, struct file * filp, +static int obd_class_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { - /* NOTE this must be larger than any of the ioctl data structs */ - char buf[1024]; + char *buf = NULL; + int len = 0; struct obd_ioctl_data *data; struct obd_device *obd = filp->private_data; - struct obd_conn conn; + + struct lustre_handle conn; int rw = OBD_BRW_READ; int err = 0; + int serialised = 0; + ENTRY; - memset(buf, 0, sizeof(buf)); + switch (cmd) + { + case OBD_IOC_BRW_WRITE: + case OBD_IOC_BRW_READ: + case OBD_IOC_GETATTR: + break; + default: + down(&obd_conf_sem); + serialised = 1; + break; + } - if (!obd && cmd != OBD_IOC_DEVICE && cmd != TCGETS - && cmd != OBD_IOC_NAME2DEV && cmd != OBD_IOC_NEWDEV) { + if (!obd && cmd != OBD_IOC_DEVICE && cmd != TCGETS && + cmd != OBD_IOC_LIST && + cmd != OBD_IOC_NAME2DEV && cmd != OBD_IOC_NEWDEV) { CERROR("OBD ioctl: No device\n"); - RETURN(-EINVAL); + GOTO(out, err=-EINVAL); } - if (obd_ioctl_getdata(buf, buf + 800, (void *)arg)) { + if (obd_ioctl_getdata(&buf, &len, (void *)arg)) { CERROR("OBD ioctl: data error\n"); - RETURN(-EINVAL); + GOTO(out, err=-EINVAL); } data = (struct obd_ioctl_data *)buf; switch (cmd) { case TCGETS: - RETURN(-EINVAL); + GOTO(out, err=-EINVAL); case OBD_IOC_DEVICE: { CDEBUG(D_IOCTL, "\n"); if (data->ioc_dev >= MAX_OBD_DEVICES || data->ioc_dev < 0) { CERROR("OBD ioctl: DEVICE insufficient devices\n"); - RETURN(-EINVAL); + GOTO(out, err=-EINVAL); } CDEBUG(D_IOCTL, "device %d\n", data->ioc_dev); filp->private_data = &obd_dev[data->ioc_dev]; - RETURN(0); + GOTO(out, err=0); + } + + case OBD_IOC_LIST: { + int i; + char *buf2 = data->ioc_bulk; + int remains = data->ioc_inllen1; + + if (!data->ioc_inlbuf1) { + CERROR("No buffer passed!\n"); + GOTO(out, err=-EINVAL); + } + + + for (i = 0 ; i < MAX_OBD_DEVICES ; i++) { + int l; + char *status; + struct obd_device *obd = &obd_dev[i]; + if (!obd->obd_type) + continue; + if (obd->obd_flags & OBD_SET_UP) + status = "UP"; + else if (obd->obd_flags & OBD_ATTACHED) + status = "AT"; + else + status = "-"; + l = snprintf(buf2, remains, "%2d %s %s %s %s %d\n", + i, status, obd->obd_type->typ_name, + obd->obd_name, obd->obd_uuid, obd->obd_type->typ_refcnt); + buf2 +=l; + remains -=l; + if (remains <= 0) { + CERROR("not enough space for device listing\n"); + break; + } + } + + err = copy_to_user((void *)arg, data, len); + GOTO(out, err); } + case OBD_IOC_NAME2DEV: { /* Resolve a device name. This does not change the * currently selected device. */ int dev; - if (!data->ioc_inlbuf1) { - CERROR("No name passed!\n"); - RETURN(-EINVAL); + if (!data->ioc_inllen1 || !data->ioc_inlbuf1 ) { + CERROR("No name passed,!\n"); + GOTO(out, err=-EINVAL); + } + if (data->ioc_inlbuf1[data->ioc_inllen1-1] !=0) { + CERROR("Name not nul terminated!\n"); + GOTO(out, err=-EINVAL); + } + + CDEBUG(D_IOCTL, "device name %s\n", data->ioc_inlbuf1); + dev = class_name2dev(data->ioc_inlbuf1); + data->ioc_dev = dev; + if (dev == -1) { + CDEBUG(D_IOCTL, "No device for name %s!\n", + data->ioc_inlbuf1); + GOTO(out, err=-EINVAL); + } + + CDEBUG(D_IOCTL, "device name %s, dev %d\n", data->ioc_inlbuf1, + dev); + err = copy_to_user((void *)arg, data, sizeof(*data)); + GOTO(out, err); + } + + case OBD_IOC_UUID2DEV: { + /* Resolve a device uuid. This does not change the + * currently selected device. + */ + int dev; + + if (!data->ioc_inllen1 || !data->ioc_inlbuf1) { + CERROR("No UUID passed!\n"); + GOTO(out, err=-EINVAL); + } + if (data->ioc_inlbuf1[data->ioc_inllen1-1] !=0) { + CERROR("Name not nul terminated!\n"); + GOTO(out, err=-EINVAL); } + CDEBUG(D_IOCTL, "device name %s\n", data->ioc_inlbuf1); - dev = obd_class_name2dev(data->ioc_inlbuf1); + dev = class_uuid2dev(data->ioc_inlbuf1); data->ioc_dev = dev; if (dev == -1) { - CERROR("No device for name %s!\n", data->ioc_inlbuf1); - RETURN(-EINVAL); + CDEBUG(D_IOCTL, "No device for name %s!\n", + data->ioc_inlbuf1); + GOTO(out, err=-EINVAL); } CDEBUG(D_IOCTL, "device name %s, dev %d\n", data->ioc_inlbuf1, dev); - err = copy_to_user((int *)arg, data, sizeof(*data)); - RETURN(err); + err = copy_to_user((void *)arg, data, sizeof(*data)); + GOTO(out, err); } case OBD_IOC_NEWDEV: { @@ -212,142 +280,173 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, int i; filp->private_data = NULL; - for (i = 0 ; i < MAX_OBD_DEVICES ; i++) { + for (i = 0 ; i < MAX_OBD_DEVICES ; i++) { struct obd_device *obd = &obd_dev[i]; - if (!obd->obd_type) { + if (!obd->obd_type) { filp->private_data = obd; dev = i; break; } } - - data->ioc_dev = dev; - if (dev == -1) - RETURN(-EINVAL); - err = copy_to_user((int *)arg, data, sizeof(*data)); - RETURN(err); + data->ioc_dev = dev; + if (dev == -1) + GOTO(out, err=-EINVAL); + + err = copy_to_user((void *)arg, data, sizeof(*data)); + GOTO(out, err); } case OBD_IOC_ATTACH: { struct obd_type *type; + int minor; /* have we attached a type to this device */ - if (obd->obd_flags & OBD_ATTACHED) { - CERROR("OBD: Device %d already typed as %s.\n", + if (obd->obd_flags & OBD_ATTACHED || obd->obd_type) { + CERROR("OBD: Device %d already typed as %s.\n", obd->obd_minor, MKSTR(obd->obd_type->typ_name)); - RETURN(-EBUSY); + GOTO(out, err=-EBUSY); } - CDEBUG(D_IOCTL, "attach %s %s\n", MKSTR(data->ioc_inlbuf1), - MKSTR(data->ioc_inlbuf2)); + if (!data->ioc_inllen1 || !data->ioc_inlbuf1) { + CERROR("No type passed!\n"); + GOTO(out, err=-EINVAL); + } + if (data->ioc_inlbuf1[data->ioc_inllen1-1] !=0) { + CERROR("Type not nul terminated!\n"); + GOTO(out, err=-EINVAL); + } + + CDEBUG(D_IOCTL, "attach type %s name: %s uuid: %s\n", + MKSTR(data->ioc_inlbuf1), + MKSTR(data->ioc_inlbuf2), MKSTR(data->ioc_inlbuf3)); /* find the type */ - type = obd_nm_to_type(data->ioc_inlbuf1); + type = class_nm_to_type(data->ioc_inlbuf1); if (!type) { CERROR("OBD: unknown type dev %d\n", obd->obd_minor); - RETURN(-EINVAL); + GOTO(out, err=-EINVAL); } + minor = obd->obd_minor; + memset(obd, 0, sizeof(*obd)); + obd->obd_minor = minor; obd->obd_type = type; - obd->obd_multi_count = 0; - INIT_LIST_HEAD(&obd->obd_gen_clients); - INIT_LIST_HEAD(&obd->obd_req_list); + INIT_LIST_HEAD(&obd->obd_exports); + INIT_LIST_HEAD(&obd->obd_imports); + spin_lock_init(&obd->obd_dev_lock); + if (data->ioc_inlbuf2) { + int len = strlen(data->ioc_inlbuf2) + 1; + OBD_ALLOC(obd->obd_name, len); + if (!obd->obd_name) { + CERROR("no memory\n"); + LBUG(); + } + memcpy(obd->obd_name, data->ioc_inlbuf2, len); + } else { + CERROR("WARNING: unnamed obd device\n"); + } + if (data->ioc_inlbuf3) { + int len = strlen(data->ioc_inlbuf3); + if (len >= sizeof(obd->obd_uuid)) { + CERROR("uuid must be < %d bytes long\n", + sizeof(obd->obd_uuid)); + if (obd->obd_name) + OBD_FREE(obd->obd_name, + strlen(obd->obd_name) + 1); + GOTO(out, err=-EINVAL); + } + memcpy(obd->obd_uuid, data->ioc_inlbuf3, len); + } /* do the attach */ - if (OBT(obd) && OBP(obd, attach)) + if (OBP(obd, attach)) err = OBP(obd,attach)(obd, sizeof(*data), data); if (err) { + if(data->ioc_inlbuf2) + OBD_FREE(obd->obd_name, strlen(obd->obd_name)+1); obd->obd_type = NULL; - } else { - obd->obd_flags |= OBD_ATTACHED; + + } else { + obd->obd_flags |= OBD_ATTACHED; + type->typ_refcnt++; CDEBUG(D_IOCTL, "OBD: dev %d attached type %s\n", obd->obd_minor, data->ioc_inlbuf1); - obd->obd_proc_entry = - proc_lustre_register_obd_device(obd); - if (data->ioc_inlbuf2) { - int len = strlen(data->ioc_inlbuf2); - OBD_ALLOC(obd->obd_name, len + 1); - if (!obd->obd_name) { - CERROR("no memory\n"); - LBUG(); - } - memcpy(obd->obd_name, data->ioc_inlbuf2, len+1); - } + CDEBUG(D_IOCTL, "MOD_INC_USE for attach: count = %d\n", + atomic_read(&(THIS_MODULE)->uc.usecount)); MOD_INC_USE_COUNT; } - RETURN(err); + GOTO(out, err); } case OBD_IOC_DETACH: { ENTRY; if (obd->obd_flags & OBD_SET_UP) { CERROR("OBD device %d still set up\n", obd->obd_minor); - RETURN(-EBUSY); + GOTO(out, err=-EBUSY); } - if (! (obd->obd_flags & OBD_ATTACHED) ) { + if (!(obd->obd_flags & OBD_ATTACHED) ) { CERROR("OBD device %d not attached\n", obd->obd_minor); - RETURN(-ENODEV); + GOTO(out, err=-ENODEV); } - if ( !list_empty(&obd->obd_gen_clients) ) { - CERROR("OBD device %d has connected clients\n", - obd->obd_minor); - RETURN(-EBUSY); - } - if ( !list_empty(&obd->obd_req_list) ) { - CERROR("OBD device %d has hanging requests\n", - obd->obd_minor); - RETURN(-EBUSY); + if (!list_empty(&obd->obd_exports)) { + if (!data->ioc_inlbuf1 || data->ioc_inlbuf1[0] != 'F') { + CERROR("OBD device %d (%p) has exports\n", + obd->obd_minor, obd); + GOTO(out, err=-EBUSY); + } + forcibly_detach_exports(obd); } - - if (obd->obd_name) { - OBD_FREE(obd->obd_name, strlen(obd->obd_name)+ 1); + if (OBP(obd, detach)) + err=OBP(obd,detach)(obd); + + if (obd->obd_name) { + OBD_FREE(obd->obd_name, strlen(obd->obd_name)+1); obd->obd_name = NULL; } - 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; + CDEBUG(D_IOCTL, "MOD_DEC_USE for detach: count = %d\n", + atomic_read(&(THIS_MODULE)->uc.usecount) - 1); MOD_DEC_USE_COUNT; - RETURN(0); + GOTO(out, err = 0); } case OBD_IOC_SETUP: { /* have we attached a type to this device? */ if (!(obd->obd_flags & OBD_ATTACHED)) { CERROR("Device %d not attached\n", obd->obd_minor); - RETURN(-ENODEV); + GOTO(out, err=-ENODEV); } /* has this been done already? */ if ( obd->obd_flags & OBD_SET_UP ) { CERROR("Device %d already setup (type %s)\n", obd->obd_minor, obd->obd_type->typ_name); - RETURN(-EBUSY); + GOTO(out, err=-EBUSY); } if ( OBT(obd) && OBP(obd, setup) ) err = obd_setup(obd, sizeof(*data), data); - if (!err) { + if (!err) { obd->obd_type->typ_refcnt++; obd->obd_flags |= OBD_SET_UP; } - RETURN(err); + GOTO(out, err); } case OBD_IOC_CLEANUP: { /* have we attached a type to this device? */ if (!(obd->obd_flags & OBD_ATTACHED)) { CERROR("Device %d not attached\n", obd->obd_minor); - RETURN(-ENODEV); + GOTO(out, err=-ENODEV); } if ( OBT(obd) && OBP(obd, cleanup) ) @@ -357,238 +456,194 @@ static int obd_class_ioctl (struct inode * inode, struct file * filp, obd->obd_flags &= ~OBD_SET_UP; obd->obd_type->typ_refcnt--; } - RETURN(err); + GOTO(out, err); } case OBD_IOC_CONNECT: { - conn.oc_id = data->ioc_conn1; - conn.oc_dev = obd; + char * cluuid = "OBD_CLASS_UUID"; + obd_data2conn(&conn, data); - err = obd_connect(&conn); + err = obd_connect(&conn, obd, cluuid, NULL, NULL); - CDEBUG(D_IOCTL, "assigned connection %d\n", conn.oc_id); - data->ioc_conn1 = conn.oc_id; + CDEBUG(D_IOCTL, "assigned export "LPX64"\n", conn.addr); + obd_conn2data(data, &conn); if (err) - RETURN(err); + GOTO(out, err); - err = copy_to_user((int *)arg, data, sizeof(*data)); - RETURN(err); + err = copy_to_user((void *)arg, data, sizeof(*data)); + // XXX save connection data into file handle + GOTO(out, err); } - case OBD_IOC_DISCONNECT: { - conn.oc_id = data->ioc_conn1; - conn.oc_dev = obd; - + case OBD_IOC_DISCONNECT: { + obd_data2conn(&conn, data); err = obd_disconnect(&conn); - RETURN(err); - } + GOTO(out, err); + } - case OBD_IOC_DEC_USE_COUNT: { + case OBD_IOC_DEC_USE_COUNT: { + CDEBUG(D_IOCTL, "MOD_DEC_USE for force dec: count = %d\n", + atomic_read(&(THIS_MODULE)->uc.usecount) - 1); MOD_DEC_USE_COUNT; - RETURN(0); + GOTO(out, err=0); } case OBD_IOC_CREATE: { - conn.oc_id = data->ioc_conn1; - conn.oc_dev = obd; - - err = obd_create(&conn, &data->ioc_obdo1); - if (err) - RETURN(err); - - err = copy_to_user((int *)arg, data, sizeof(*data)); - RETURN(err); + struct lov_stripe_md *lsm = NULL; + obd_data2conn(&conn, data); + +#warning FIXME: save lsm into file handle for other ops, release on close + err = obd_create(&conn, &data->ioc_obdo1, &lsm); + if (!err) + err = copy_to_user((void *)arg, data, sizeof(*data)); + GOTO(out, err); } case OBD_IOC_GETATTR: { - conn.oc_id = data->ioc_conn1; - conn.oc_dev = obd; - - err = obd_getattr(&conn, &data->ioc_obdo1); - if (err) - RETURN(err); - err = copy_to_user((int *)arg, data, sizeof(*data)); - RETURN(err); + obd_data2conn(&conn, data); + err = obd_getattr(&conn, &data->ioc_obdo1, NULL); + if (!err) + err = copy_to_user((void *)arg, data, sizeof(*data)); + GOTO(out, err); } case OBD_IOC_SETATTR: { - conn.oc_id = data->ioc_conn1; - conn.oc_dev = obd; + obd_data2conn(&conn, data); + err = obd_setattr(&conn, &data->ioc_obdo1, NULL); + if (!err) + err = copy_to_user((void *)arg, data, sizeof(*data)); + GOTO(out, err); + } - err = obd_setattr(&conn, &data->ioc_obdo1); - if (err) - RETURN(err); + case OBD_IOC_DESTROY: { + //void *ea; + obd_data2conn(&conn, data); - err = copy_to_user((int *)arg, data, sizeof(*data)); - RETURN(err); + err = obd_destroy(&conn, &data->ioc_obdo1, NULL); + if (!err) + err = copy_to_user((void *)arg, data, sizeof(*data)); + GOTO(out, err); } - case OBD_IOC_DESTROY: { - conn.oc_id = data->ioc_conn1; - conn.oc_dev = obd; + case OBD_IOC_OPEN: { + struct lov_stripe_md *lsm = NULL; // XXX fill in from create - err = obd_destroy(&conn, &data->ioc_obdo1); - if (err) - RETURN(err); + obd_data2conn(&conn, data); + err = obd_open(&conn, &data->ioc_obdo1, lsm); + if (!err) + err = copy_to_user((void *)arg, data, sizeof(*data)); + GOTO(out, err); + } - err = copy_to_user((int *)arg, data, sizeof(*data)); - RETURN(err); + case OBD_IOC_CLOSE: { + struct lov_stripe_md *lsm = NULL; // XXX fill in from create + + obd_data2conn(&conn, data); + err = obd_close(&conn, &data->ioc_obdo1, lsm); + GOTO(out, err); } case OBD_IOC_BRW_WRITE: rw = OBD_BRW_WRITE; case OBD_IOC_BRW_READ: { - /* FIXME: use a better ioctl data struct than obd_ioctl_data. - * We don't really support multiple-obdo I/Os here, - * for example offset and count are not per-obdo. - */ - struct obd_conn conns[2]; - struct obdo *obdos[2] = { NULL, NULL }; - obd_count oa_bufs[2] = { 0, 0 }; - struct page **bufs = NULL; - obd_size *counts = NULL; - obd_off *offsets = NULL; - obd_flag *flags = NULL; - int num = 1; - int pages; - int i, j; - - pages = oa_bufs[0] = data->ioc_plen1 / PAGE_SIZE; - if (data->ioc_obdo2.o_id) { - num = 2; - oa_bufs[1] = data->ioc_plen2 / PAGE_SIZE; - pages += oa_bufs[1]; - } - - CDEBUG(D_INODE, "BRW %s with %dx%d pages\n", - rw == OBD_BRW_READ ? "read" : "write", - num, oa_bufs[0]); - bufs = kmalloc(pages * sizeof(*bufs), GFP_KERNEL); - counts = kmalloc(pages * sizeof(*counts), GFP_KERNEL); - offsets = kmalloc(pages * sizeof(*offsets), GFP_KERNEL); - flags = kmalloc(pages * sizeof(*flags), GFP_KERNEL); - if (!bufs || !counts || !offsets || !flags) { + struct lov_stripe_md tmp_lsm; // XXX fill in from create + struct lov_stripe_md *lsm = &tmp_lsm; // XXX fill in from create + struct io_cb_data *cbd = ll_init_cb(); + obd_count pages = 0; + struct brw_page *pga, *pgp; + __u64 id = data->ioc_obdo1.o_id; + int gfp_mask = (id & 1) ? GFP_HIGHUSER : GFP_KERNEL; + int verify = (id != 0); + __u64 off; + int j; + + if (!cbd) + GOTO(out, err = -ENOMEM); + + obd_data2conn(&conn, data); + + pages = data->ioc_count / PAGE_SIZE; + off = data->ioc_offset; + + CDEBUG(D_INODE, "BRW %s with %d pages @ "LPX64"\n", + rw == OBD_BRW_READ ? "read" : "write", pages, off); + OBD_ALLOC(pga, pages * sizeof(*pga)); + if (!pga) { CERROR("no memory for %d BRW per-page data\n", pages); - err = -ENOMEM; - GOTO(brw_free, err); + GOTO(brw_free, err = -ENOMEM); } - obdos[0] = &data->ioc_obdo1; - if (num > 1) - obdos[1] = &data->ioc_obdo2; - - for (i = 0, pages = 0; i < num; i++) { - unsigned long off; - void *from; - - conns[i].oc_id = (&data->ioc_conn1)[i]; - conns[i].oc_dev = obd; - - from = (&data->ioc_pbuf1)[i]; - off = data->ioc_offset; - - for (j = 0; j < oa_bufs[i]; - j++, pages++, off += PAGE_SIZE, from += PAGE_SIZE){ - unsigned long to; - - to = __get_free_pages(GFP_KERNEL, 0); - if (!to) { - /* || - copy_from_user((void *)to,from,PAGE_SIZE)) - free_pages(to, 0); - */ - CERROR("no memory for brw pages\n"); - err = -ENOMEM; - GOTO(brw_cleanup, err); - } - bufs[pages] = virt_to_page(to); - counts[pages] = PAGE_SIZE; - offsets[pages] = off; - flags[pages] = 0; + memset(lsm, 0, sizeof(*lsm)); // XXX don't do this later + lsm->lsm_object_id = id; // ensure id == lsm->lsm_object_id + + for (j = 0, pgp = pga; j < pages; j++, off += PAGE_SIZE, pgp++){ + pgp->pg = alloc_pages(gfp_mask, 0); + if (!pgp->pg) { + CERROR("no memory for brw pages\n"); + GOTO(brw_cleanup, err = -ENOMEM); + } + pgp->count = PAGE_SIZE; + pgp->off = off; + pgp->flag = 0; + + if (verify) { + void *addr = kmap(pgp->pg); + + if (rw == OBD_BRW_WRITE) + page_debug_setup(addr, pgp->count, + pgp->off, id); + else + page_debug_setup(addr, pgp->count, + 0xdeadbeef00c0ffee, + 0xdeadbeef00c0ffee); + kunmap(pgp->pg); } } - err = obd_brw(rw, conns, num, obdos, oa_bufs, bufs, - counts, offsets, flags); - + err = obd_brw(rw, &conn, lsm, j, pga, ll_sync_io_cb, cbd); + if (err) + CERROR("test_brw: error from obd_brw: err = %d\n", err); EXIT; brw_cleanup: - while (pages-- > 0) - free_pages((unsigned long)page_address(bufs[pages]), 0); + for (j = 0, pgp = pga; j < pages; j++, pgp++) { + if (pgp->pg != NULL) { + if (verify && !err) { + void *addr = kmap(pgp->pg); + + err = page_debug_check("test_brw", + addr, + PAGE_SIZE, + pgp->off,id); + kunmap(pgp->pg); + } + __free_pages(pgp->pg, 0); + } + } brw_free: - kfree(flags); - kfree(offsets); - kfree(counts); - kfree(bufs); - return err; + OBD_FREE(pga, pages * sizeof(*pga)); + GOTO(out, err); } - default: { - conn.oc_id = data->ioc_conn1; - conn.oc_dev = obd; + default: + obd_data2conn(&conn, data); - err = obd_iocontrol(cmd, &conn, sizeof(*data), data, NULL); + err = obd_iocontrol(cmd, &conn, len, data, NULL); if (err) - RETURN(err); + GOTO(out, err); - err = copy_to_user((int *)arg, data, sizeof(*data)); - RETURN(err); + err = copy_to_user((void *)arg, data, len); + GOTO(out, err); } - } -} /* obd_class_ioctl */ - - -/* Driver interface done, utility functions follow */ -int obd_register_type(struct obd_ops *ops, char *nm) -{ - struct obd_type *type; - - ENTRY; - - if (obd_init_magic != 0x11223344) { - CERROR("bad magic for type\n"); - RETURN(-EINVAL); - } - - if ( obd_nm_to_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); -} - -int obd_unregister_type(char *nm) -{ - struct obd_type *type = obd_nm_to_type(nm); - - ENTRY; - if ( !type ) { - MOD_DEC_USE_COUNT; - CERROR("unknown obd type\n"); - RETURN(-EINVAL); - } + out: + if (buf) + OBD_FREE(buf, len); + if (serialised) + up(&obd_conf_sem); + RETURN(err); +} /* obd_class_ioctl */ - 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); -} /* obd_unregister_type */ /* declare character device */ static struct file_operations obd_psdev_fops = { @@ -605,31 +660,49 @@ static struct miscdevice obd_psdev = { &obd_psdev_fops }; -EXPORT_SYMBOL(obd_register_type); -EXPORT_SYMBOL(obd_unregister_type); +void (*class_signal_connection_failure)(struct ptlrpc_connection *); 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); EXPORT_SYMBOL(obd_memory); EXPORT_SYMBOL(obd_fail_loc); +EXPORT_SYMBOL(obd_timeout); +EXPORT_SYMBOL(obd_recovery_upcall); +EXPORT_SYMBOL(ptlrpc_put_connection_superhack); + +EXPORT_SYMBOL(class_register_type); +EXPORT_SYMBOL(class_unregister_type); +EXPORT_SYMBOL(class_name2dev); +EXPORT_SYMBOL(class_uuid2dev); +EXPORT_SYMBOL(class_uuid2obd); +EXPORT_SYMBOL(class_new_export); +EXPORT_SYMBOL(class_destroy_export); +EXPORT_SYMBOL(class_connect); +EXPORT_SYMBOL(class_conn2export); +EXPORT_SYMBOL(class_conn2obd); +EXPORT_SYMBOL(class_conn2cliimp); +EXPORT_SYMBOL(class_conn2ldlmimp); +EXPORT_SYMBOL(class_disconnect); +EXPORT_SYMBOL(class_disconnect_all); +//EXPORT_SYMBOL(class_uuid_parse); +EXPORT_SYMBOL(class_uuid_unparse); +//EXPORT_SYMBOL(class_multi_setup); +//EXPORT_SYMBOL(class_multi_cleanup); + +EXPORT_SYMBOL(class_signal_connection_failure); +EXPORT_SYMBOL(ll_sync_io_cb); +EXPORT_SYMBOL(ll_init_cb); +EXPORT_SYMBOL(class_nm_to_type); static int __init init_obdclass(void) { + struct obd_device *obd; int err; int i; - printk(KERN_INFO "OBD class driver v0.01, braam@stelias.com\n"); + printk(KERN_INFO "OBD class driver v0.9, info@clusterfs.com\n"); + sema_init(&obd_conf_sem, 1); INIT_LIST_HEAD(&obd_types); if ((err = misc_register(&obd_psdev))) { @@ -637,48 +710,48 @@ static int __init init_obdclass(void) return err; } - 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); - INIT_LIST_HEAD(&obd_dev[i].obd_req_list); - init_waitqueue_head(&obd_dev[i].obd_req_waitq); - } + /* This struct is already zerod for us (static global) */ + for (i = 0, obd = obd_dev; i < MAX_OBD_DEVICES; i++, obd++) + obd->obd_minor = i; - err = obd_init_obdo_cache(); + err = obd_init_caches(); + if (err) return err; obd_sysctl_init(); - obd_init_magic = 0x11223344; + + err=lprocfs_reg_main(); + return 0; } static void __exit cleanup_obdclass(void) { - int i; + int i, err; ENTRY; 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) ) { + 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_cleanup_caches(); obd_sysctl_clean(); + + err = lprocfs_dereg_main(); + CERROR("obd memory leaked: %ld bytes\n", obd_memory); - obd_init_magic = 0; EXIT; } -MODULE_AUTHOR("Cluster File Systems, Inc. "); +MODULE_AUTHOR("Cluster File Systems, Inc. "); MODULE_DESCRIPTION("Lustre Class Driver v1.0"); -MODULE_LICENSE("GPL"); +MODULE_LICENSE("GPL"); module_init(init_obdclass); module_exit(cleanup_obdclass);