Whamcloud - gitweb
Config interface now uses the new struct lustre_cfg for all config
authorrread <rread>
Mon, 29 Sep 2003 23:26:50 +0000 (23:26 +0000)
committerrread <rread>
Mon, 29 Sep 2003 23:26:50 +0000 (23:26 +0000)
commands.  Config commands are sent by lctl using the
OBD_IOC_PROCESS_CFG ioctl, and they can be recorded with
OBD_IOC_RECORD (untested). The configuration process is now stateless,
and each command refers to the device it operates on by name, if
needed.  The lctl interface has changed slightly:

* newdev is not needed. (It continues to exist for compatibility, but
  is a NOOP.)  The attach command now selects the new device.

* cfg_device <name> is used to select the device that is being
  configured. This takes the place of the "device; probe" for config
  commands only.

The current config ops are:
        LCFG_ATTACH
        LCFG_DETACH
        LCFG_SETUP
        LCFG_CLEANUP
        LCFG_LOV_SET_CONFIG
        LCFG_ADD_UUID
        LCFG_DEL_UUID

The other ioctls are unchanged. The portals config commands have not
been incorporated yet.

lustre/include/linux/lustre_cfg.h [new file with mode: 0644]
lustre/obdclass/config.c [new file with mode: 0644]
lustre/utils/lustre_cfg.c [new file with mode: 0644]

diff --git a/lustre/include/linux/lustre_cfg.h b/lustre/include/linux/lustre_cfg.h
new file mode 100644 (file)
index 0000000..e6becb6
--- /dev/null
@@ -0,0 +1,234 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001 Cluster File Systems, Inc. <braam@clusterfs.com>
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   Lustre is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   Lustre is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with Lustre; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef _LUSTRE_CFG_H
+#define _LUSTRE_CFG_H
+
+#define LUSTRE_CFG_VERSION 0x00010001
+
+enum lcfg_command_type {
+        LCFG_ATTACH         = 0x00cf001,
+        LCFG_DETACH         = 0x00cf002,
+        LCFG_SETUP          = 0x00cf003,
+        LCFG_CLEANUP        = 0x00cf004,
+        LCFG_LOV_SET_CONFIG = 0x00cf005,
+        LCFG_ADD_UUID       = 0x00cf006,
+        LCFG_DEL_UUID       = 0x00cf007,
+};
+
+struct lustre_cfg {
+        uint32_t lcfg_version;
+        uint32_t lcfg_command;
+
+        uint32_t lcfg_dev;
+        uint32_t lcfg_flags;
+        uint64_t lcfg_nid;
+        uint32_t lcfg_nal;
+
+        /* inline buffers for various arguments */
+        uint32_t lcfg_dev_namelen;
+        char    *lcfg_dev_name;
+        uint32_t lcfg_inllen1;
+        char    *lcfg_inlbuf1;
+        uint32_t lcfg_inllen2;
+        char    *lcfg_inlbuf2;
+        uint32_t lcfg_inllen3;
+        char    *lcfg_inlbuf3;
+        uint32_t lcfg_inllen4;
+        char    *lcfg_inlbuf4;
+
+        char    lcfg_bulk[0];
+
+};
+
+#ifndef __KERNEL__
+static inline int lustre_cfg_packlen(struct lustre_cfg *lcfg)
+{
+        int len = size_round(sizeof(struct lustre_cfg));
+        len += size_round(lcfg->lcfg_dev_namelen);
+        len += size_round(lcfg->lcfg_inllen1);
+        len += size_round(lcfg->lcfg_inllen2);
+        len += size_round(lcfg->lcfg_inllen3);
+        len += size_round(lcfg->lcfg_inllen4);
+        return len;
+
+}
+
+static inline int lustre_cfg_pack(struct lustre_cfg *data, char **pbuf,
+                                 int max, int *plen)
+{
+        char *ptr;
+        struct lustre_cfg *overlay;
+       int len;
+
+        len = lustre_cfg_packlen(data);
+
+        data->lcfg_version = LUSTRE_CFG_VERSION;
+
+        if (*pbuf && len > max)
+                return 1;
+        if (*pbuf == NULL) {
+                *pbuf = malloc(len);
+        }
+        if (!*pbuf)
+                return 1;
+        overlay = (struct lustre_cfg *)*pbuf;
+        memcpy(*pbuf, data, sizeof(*data));
+
+        ptr = overlay->lcfg_bulk;
+        if (data->lcfg_dev_name)
+                LOGL(data->lcfg_dev_name, data->lcfg_dev_namelen, ptr);
+        if (data->lcfg_inlbuf1)
+                LOGL(data->lcfg_inlbuf1, data->lcfg_inllen1, ptr);
+        if (data->lcfg_inlbuf2)
+                LOGL(data->lcfg_inlbuf2, data->lcfg_inllen2, ptr);
+        if (data->lcfg_inlbuf3)
+                LOGL(data->lcfg_inlbuf3, data->lcfg_inllen3, ptr);
+        if (data->lcfg_inlbuf4)
+                LOGL(data->lcfg_inlbuf4, data->lcfg_inllen4, ptr);
+//        if (lustre_cfg_is_invalid(overlay))
+//                return 1;
+
+       *plen = len;
+
+        return 0;
+}
+
+static inline int lustre_cfg_unpack(struct lustre_cfg *data, char *pbuf,
+                                   int max)
+{
+        char *ptr;
+        struct lustre_cfg *overlay;
+
+        if (!pbuf)
+                return 1;
+        overlay = (struct lustre_cfg *)pbuf;
+
+        /* Preserve the caller's buffer pointers */
+        overlay->lcfg_dev_name = data->lcfg_dev_name;
+        overlay->lcfg_inlbuf1 = data->lcfg_inlbuf1;
+        overlay->lcfg_inlbuf2 = data->lcfg_inlbuf2;
+        overlay->lcfg_inlbuf3 = data->lcfg_inlbuf3;
+        overlay->lcfg_inlbuf4 = data->lcfg_inlbuf4;
+
+        memcpy(data, pbuf, sizeof(*data));
+
+        ptr = overlay->lcfg_bulk;
+        if (data->lcfg_dev_name)
+                LOGU(data->lcfg_dev_name, data->lcfg_dev_namelen, ptr);
+        if (data->lcfg_inlbuf1)
+                LOGU(data->lcfg_inlbuf1, data->lcfg_inllen1, ptr);
+        if (data->lcfg_inlbuf2)
+                LOGU(data->lcfg_inlbuf2, data->lcfg_inllen2, ptr);
+        if (data->lcfg_inlbuf3)
+                LOGU(data->lcfg_inlbuf3, data->lcfg_inllen3, ptr);
+        if (data->lcfg_inlbuf4)
+                LOGU(data->lcfg_inlbuf4, data->lcfg_inllen4, ptr);
+
+        return 0;
+}
+#endif
+
+#include <linux/obd_support.h>
+
+/* buffer MUST be at least the size of obd_ioctl_hdr */
+static inline int lustre_cfg_getdata(char **buf, int len, void *arg)
+{
+        struct lustre_cfg *lcfg;
+        int err;
+       int offset = 0;
+        ENTRY;
+        if (len > OBD_MAX_IOCTL_BUFFER) {
+                CERROR("User buffer len %d exceeds %d max buffer\n",
+                       len, OBD_MAX_IOCTL_BUFFER);
+                return -EINVAL;
+        }
+
+        if (len < sizeof(struct lustre_cfg)) {
+                CERROR("OBD: user buffer too small for lustre_cfg\n");
+                return -EINVAL;
+        }
+
+        /* XXX allocate this more intelligently, using kmalloc when
+         * appropriate */
+        OBD_VMALLOC(*buf, len);
+        if (*buf == NULL) {
+                CERROR("Cannot allocate control buffer of len %d\n", len);
+                RETURN(-EINVAL);
+        }
+        lcfg = (struct lustre_cfg *)*buf;
+
+        err = copy_from_user(*buf, (void *)arg, len);
+        if ( err ) {
+                EXIT;
+                return err;
+        }
+
+
+        if (lcfg->lcfg_version != LUSTRE_CFG_VERSION) {
+                CERROR("Version mismatch kernel vs application\n");
+                return -EINVAL;
+        }
+
+//        if (lustre_cfg_is_invalid(data)) {
+//                CERROR("ioctl not correctly formatted\n");
+//                return -EINVAL;
+//        }
+
+        if (lcfg->lcfg_dev_name) {
+                lcfg->lcfg_dev_name = &lcfg->lcfg_bulk[0];
+               offset += size_round(lcfg->lcfg_dev_namelen);
+        }
+
+        if (lcfg->lcfg_inllen1) {
+                lcfg->lcfg_inlbuf1 = &lcfg->lcfg_bulk[0] + offset;
+               offset += size_round(lcfg->lcfg_inllen1);
+        }
+
+        if (lcfg->lcfg_inllen2) {
+                lcfg->lcfg_inlbuf2 = &lcfg->lcfg_bulk[0] + offset;
+               offset += size_round(lcfg->lcfg_inllen2);
+        }
+
+        if (lcfg->lcfg_inllen3) {
+                lcfg->lcfg_inlbuf3 = &lcfg->lcfg_bulk[0] + offset;
+               offset += size_round(lcfg->lcfg_inllen3);
+        }
+
+        if (lcfg->lcfg_inllen4) {
+                lcfg->lcfg_inlbuf4 = &lcfg->lcfg_bulk[0] + offset;
+        }
+
+        EXIT;
+        return 0;
+}
+
+static inline void lustre_cfg_freedata(char *buf, int len)
+{
+        ENTRY;
+
+        OBD_VFREE(buf, len);
+        EXIT;
+        return;
+}
+
+#endif // _LUSTRE_CFG_H
diff --git a/lustre/obdclass/config.c b/lustre/obdclass/config.c
new file mode 100644 (file)
index 0000000..8080dab
--- /dev/null
@@ -0,0 +1,393 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (c) 2001-2003 Cluster File Systems, Inc.
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   Lustre is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   Lustre is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with Lustre; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Config API
+ *
+ */
+
+#define DEBUG_SUBSYSTEM S_CLASS
+#ifdef __KERNEL__
+#include <linux/kmod.h>   /* for request_module() */
+#include <linux/module.h>
+#include <linux/obd_class.h>
+#include <linux/random.h>
+#include <linux/slab.h>
+#include <linux/pagemap.h>
+#else 
+#include <liblustre.h>
+#include <linux/obd_class.h>
+#include <linux/obd.h>
+#endif
+#include <linux/lprocfs_status.h>
+#include <portals/list.h>
+
+
+/* Create a new device and set the type, name and uuid.  If
+ * successful, the new device can be accessed by either name or uuid.
+ */
+int class_attach(struct lustre_cfg *lcfg)
+{
+        int minor;
+        struct obd_type *type;
+        int err = 0;
+        int len;
+       char *typename;
+       char *name;
+       char *uuid;
+       struct obd_device *obd;
+       int dev;
+                 
+       if (!lcfg->lcfg_inllen1 || !lcfg->lcfg_inlbuf1) {
+               CERROR("No type passed!\n");
+               RETURN(-EINVAL);
+       }
+       if (lcfg->lcfg_inlbuf1[lcfg->lcfg_inllen1 - 1] != 0) {
+               CERROR("Type not nul terminated!\n");
+               RETURN(-EINVAL);
+       }
+       typename = lcfg->lcfg_inlbuf1;
+
+       if (!lcfg->lcfg_dev_namelen || !lcfg->lcfg_dev_name) {
+               CERROR("No name passed!\n");
+               RETURN(-EINVAL);
+       }
+       if (lcfg->lcfg_dev_name[lcfg->lcfg_dev_namelen - 1] != 0) {
+               CERROR("Name not nul terminated!\n");
+               RETURN(-EINVAL);
+       }
+       name = lcfg->lcfg_dev_name;
+
+       if (!lcfg->lcfg_inllen2 || !lcfg->lcfg_inlbuf2) {
+               CERROR("No UUID passed!\n");
+               RETURN(-EINVAL);
+       }
+       if (lcfg->lcfg_inlbuf2[lcfg->lcfg_inllen2 - 1] != 0) {
+               CERROR("UUID not nul terminated!\n");
+               RETURN(-EINVAL);
+       }
+       uuid = lcfg->lcfg_inlbuf2;
+
+       CDEBUG(D_IOCTL, "attach type %s name: %s uuid: %s\n",
+              MKSTR(lcfg->lcfg_inlbuf1),
+              MKSTR(lcfg->lcfg_inlbuf2), MKSTR(lcfg->lcfg_inlbuf3));
+
+        /* find the type */
+        type = class_get_type(typename);
+        if (!type) {
+                CERROR("OBD: unknown type: %s\n", typename);
+                RETURN(-EINVAL);
+        }
+        
+        obd = class_name2obd(name);
+        if (obd != NULL)
+                RETURN(-EEXIST);
+
+       obd = class_newdev(&dev);
+       if (dev == -1)
+               RETURN(-EINVAL);
+
+       /* have we attached a type to this device */
+       if (obd->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);
+       }
+
+        minor = obd->obd_minor;
+        memset(obd, 0, sizeof(*obd));
+        obd->obd_minor = minor;
+        obd->obd_type = type;
+        INIT_LIST_HEAD(&obd->obd_exports);
+        obd->obd_num_exports = 0;
+        spin_lock_init(&obd->obd_dev_lock);
+        init_waitqueue_head(&obd->obd_refcount_waitq);
+        
+        /* XXX belong ins setup not attach  */
+        /* recovery data */
+        spin_lock_init(&obd->obd_processing_task_lock);
+        init_waitqueue_head(&obd->obd_next_transno_waitq);
+        INIT_LIST_HEAD(&obd->obd_recovery_queue);
+        INIT_LIST_HEAD(&obd->obd_delayed_reply_queue);
+        
+        init_waitqueue_head(&obd->obd_commit_waitq);
+        
+        len = strlen(name) + 1;
+        OBD_ALLOC(obd->obd_name, len);
+        if (!obd->obd_name) {
+                class_put_type(obd->obd_type);
+                obd->obd_type = NULL;
+                RETURN(-ENOMEM);
+        }
+        memcpy(obd->obd_name, name, len);
+        
+        len = strlen(uuid);
+        if (len >= sizeof(obd->obd_uuid)) {
+                CERROR("uuid must be < "LPSZ" bytes long\n",
+                       sizeof(obd->obd_uuid));
+                if (obd->obd_name)
+                        OBD_FREE(obd->obd_name,
+                                 strlen(obd->obd_name) + 1);
+                class_put_type(obd->obd_type);
+                obd->obd_type = NULL;
+                RETURN(-EINVAL);
+        }
+        memcpy(obd->obd_uuid.uuid, uuid, len);
+        
+        /* do the attach */
+        if (OBP(obd, attach))
+                err = OBP(obd,attach)(obd, sizeof *lcfg, lcfg);
+
+        if (err) {
+                if(name)
+                        OBD_FREE(obd->obd_name,
+                                 strlen(obd->obd_name) + 1);
+                class_put_type(obd->obd_type);
+                obd->obd_type = NULL;
+        } else {
+                obd->obd_attached = 1;
+                
+                type->typ_refcnt++;
+                CDEBUG(D_IOCTL, "OBD: dev %d attached type %s\n",
+                       obd->obd_minor, typename);
+        }
+        RETURN(err);
+}
+
+int class_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
+{
+        int err = 0;
+        ENTRY;
+
+        /* have we attached a type to this device? */
+        if (!obd->obd_attached) {
+                CERROR("Device %d not attached\n", obd->obd_minor);
+                RETURN(-ENODEV);
+        }
+
+        /* has this been done already? */
+        if (obd->obd_set_up) {
+                CERROR("Device %d already setup (type %s)\n",
+                       obd->obd_minor, obd->obd_type->typ_name);
+                RETURN(-EBUSY);
+        }
+
+        atomic_set(&obd->obd_refcount, 0);
+        
+        if (OBT(obd) && OBP(obd, setup))
+                err = obd_setup(obd, sizeof(*lcfg), lcfg);
+
+        if (!err) {
+                obd->obd_type->typ_refcnt++;
+                obd->obd_set_up = 1;
+                atomic_inc(&obd->obd_refcount);
+        } 
+        RETURN(err);
+}
+
+int class_detach(struct obd_device *obd, struct lustre_cfg *lcfg)
+{
+        int err = 0;
+
+        ENTRY;
+        if (obd->obd_set_up) {
+                CERROR("OBD device %d still set up\n", obd->obd_minor);
+                RETURN(-EBUSY);
+        }
+        if (!obd->obd_attached) {
+                CERROR("OBD device %d not attached\n", obd->obd_minor);
+                RETURN(-ENODEV);
+        }
+        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;
+        }
+
+        obd->obd_attached = 0;
+        obd->obd_type->typ_refcnt--;
+        class_put_type(obd->obd_type);
+        obd->obd_type = NULL;
+        memset(obd, 0, sizeof(*obd));
+        RETURN(err);
+}
+
+static void dump_exports(struct obd_device *obd)
+{
+        struct obd_export *exp, *n;
+
+        list_for_each_entry_safe(exp, n, &obd->obd_exports, exp_obd_chain) {
+                CERROR("%s: %p %s %d %d %p\n",
+                       obd->obd_name, exp, exp->exp_client_uuid.uuid,
+                       atomic_read(&exp->exp_refcount),
+                       exp->exp_failed, exp->exp_outstanding_reply );
+        }
+}
+
+int class_cleanup(struct obd_device *obd, struct lustre_cfg *lcfg)
+{
+        int flags = 0;
+       int err = 0;
+        char *flag;
+        
+        ENTRY;
+        if (!obd->obd_set_up) {
+                CERROR("Device %d not setup\n", obd->obd_minor);
+                RETURN(-ENODEV);
+        }
+
+        if (lcfg->lcfg_inlbuf1) {
+                for (flag = lcfg->lcfg_inlbuf1; *flag != 0; flag++)
+                        switch (*flag) {
+                        case 'F':
+                                flags |= OBD_OPT_FORCE;
+                                break;
+                        case 'A':
+                                flags |= OBD_OPT_FAILOVER;
+                                break;
+                        default:
+                                CERROR("unrecognised flag '%c'\n",
+                                       *flag);
+                        }
+        }
+
+        if (atomic_read(&obd->obd_refcount) == 1 ||
+            flags & OBD_OPT_FORCE) {
+                /* this will stop new connections, and need to
+                   do it before class_disconnect_exports() */
+                obd->obd_stopping = 1;
+        }
+
+        if (atomic_read(&obd->obd_refcount) > 1) {
+                struct l_wait_info lwi = LWI_TIMEOUT_INTR(1 * HZ, NULL,
+                                                          NULL, NULL);
+                int rc;
+
+                if (!(flags & OBD_OPT_FORCE)) {
+                        CERROR("OBD device %d (%p) has refcount %d\n",
+                               obd->obd_minor, obd,
+                               atomic_read(&obd->obd_refcount));
+                        dump_exports(obd);
+                        RETURN(-EBUSY);
+                }
+                class_disconnect_exports(obd, flags);
+                CDEBUG(D_IOCTL,
+                       "%s: waiting for obd refs to go away: %d\n",
+                       obd->obd_name, atomic_read(&obd->obd_refcount));
+
+                rc = l_wait_event(obd->obd_refcount_waitq,
+                                  atomic_read(&obd->obd_refcount) < 2, &lwi);
+                if (rc == 0) {
+                        LASSERT(atomic_read(&obd->obd_refcount) == 1);
+                } else {
+                        CERROR("wait cancelled cleaning anyway. "
+                               "refcount: %d\n",
+                               atomic_read(&obd->obd_refcount));
+                        dump_exports(obd);
+                }
+                CDEBUG(D_IOCTL, "%s: awake, now finishing cleanup\n",
+                       obd->obd_name);
+        }
+
+        if (OBT(obd) && OBP(obd, cleanup))
+                err = obd_cleanup(obd, flags);
+
+        if (!err) {
+                obd->obd_set_up = obd->obd_stopping = 0;
+                obd->obd_type->typ_refcnt--;
+                atomic_dec(&obd->obd_refcount);
+                /* XXX this should be an LASSERT */
+                if (atomic_read(&obd->obd_refcount) > 0) 
+                        CERROR("%s still has refcount %d after "
+                               "cleanup.\n", obd->obd_name,
+                               atomic_read(&obd->obd_refcount));
+        }
+
+        RETURN(err);
+}
+
+int class_process_config(int len, char *data)
+{
+        char *buf;
+       struct obd_device *obd;
+        struct lustre_cfg *lcfg;
+        int err;
+
+        lustre_cfg_getdata(&buf, len, data);
+        lcfg = (struct lustre_cfg* ) buf;
+
+        /* Commands that don't need a device */
+       switch(lcfg->lcfg_command) {
+        case LCFG_ATTACH: {
+                err = class_attach(lcfg);
+                GOTO(out, err);
+        }
+        case LCFG_ADD_UUID: {
+                CDEBUG(D_IOCTL, "adding mapping from uuid %s to nid "LPX64
+                       ", nal %d\n", lcfg->lcfg_inlbuf1, lcfg->lcfg_nid,
+                       lcfg->lcfg_nal);
+
+                err = class_add_uuid(lcfg->lcfg_inlbuf1, lcfg->lcfg_nid,
+                                     lcfg->lcfg_nal);
+                GOTO(out, err);
+        }
+        case LCFG_DEL_UUID: {
+                CDEBUG(D_IOCTL, "removing mappings for uuid %s\n",
+                       lcfg->lcfg_inlbuf1 == NULL ? "<all uuids>" :
+                       lcfg->lcfg_inlbuf1);
+
+                err = class_del_uuid(lcfg->lcfg_inlbuf1);
+                GOTO(out, err);
+        }
+       }
+       
+
+       /* Commands that require a device */
+        obd = class_name2obd(lcfg->lcfg_dev_name);
+        if (obd == NULL) {
+                CERROR("no device\n");
+                GOTO(out, err = -EINVAL);
+       }
+           
+        switch(lcfg->lcfg_command) {
+        case LCFG_SETUP: {
+                err = class_setup(obd, lcfg);
+                GOTO(out, err);
+        }
+        case LCFG_DETACH: {
+                err = class_detach(obd, lcfg);
+                GOTO(out, err = 0);
+        }
+        case LCFG_CLEANUP: {
+                err = class_cleanup(obd, lcfg);
+                GOTO(out, err = 0);
+        }
+        default: { 
+                err = obd_config(obd, lcfg);
+                if (err)
+                        GOTO(out, err);
+        }
+       }
+out:
+        lustre_cfg_freedata(buf, len);
+        RETURN(err);
+}
+           
diff --git a/lustre/utils/lustre_cfg.c b/lustre/utils/lustre_cfg.c
new file mode 100644 (file)
index 0000000..510cd42
--- /dev/null
@@ -0,0 +1,424 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2002 Cluster File Systems, Inc.
+ *   Author: Peter J. Braam <braam@clusterfs.com>
+ *   Author: Phil Schwan <phil@clusterfs.com>
+ *   Author: Andreas Dilger <adilger@clusterfs.com>
+ *   Author: Robert Read <rread@clusterfs.com>
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   Lustre is free software; you can redistribute it and/or
+ *   modify it under the terms of version 2 of the GNU General Public
+ *   License as published by the Free Software Foundation.
+ *
+ *   Lustre is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with Lustre; if not, write to the Free Software
+ *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdarg.h>
+
+#ifndef __KERNEL__
+#include <liblustre.h>
+#endif
+#include <linux/lustre_lib.h>
+#include <linux/lustre_cfg.h>
+#include <linux/lustre_idl.h>
+#include <linux/lustre_dlm.h>
+#include <linux/obd.h>          /* for struct lov_stripe_md */
+#include <linux/lustre_build_version.h>
+
+#include <unistd.h>
+#include <sys/un.h>
+#include <time.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <string.h>
+
+
+#include "obdctl.h"
+#include <portals/ptlctl.h>
+#include "parser.h"
+#include <stdio.h>
+
+
+#define LCFG_INIT(lcfg, cmd)                                           \
+do {                                                                   \
+        memset(&lcfg, 0, sizeof(lcfg));                                        \
+        lcfg.lcfg_version = LUSTRE_CFG_VERSION;                                \
+        lcfg.lcfg_command = (cmd);                                     \
+        if (lcfg_devname) {                                            \
+                lcfg.lcfg_dev_namelen = strlen(lcfg_devname) + 1;      \
+                lcfg.lcfg_dev_name = lcfg_devname;                     \
+        }                                                              \
+                                                                       \
+} while (0)
+
+static char * lcfg_devname;
+
+void lcfg_set_devname(char *name)
+{
+       if (lcfg_devname)
+               free(lcfg_devname);
+       lcfg_devname = strdup(name);
+}
+
+
+int jt_lcfg_device(int argc, char **argv)
+{
+       char *name;
+
+        if (argc == 1) {
+               printf("current device is %s\n", lcfg_devname? : "not set");
+               return 0;
+       } else if (argc != 2) {
+                return CMD_HELP;
+       }
+
+       name = argv[1];
+
+       /* quietly strip the unnecessary '$' */
+       if (*name == '$')
+               name++;
+
+       lcfg_set_devname(name);
+
+        return 0;
+}
+
+/* NOOP */
+int jt_lcfg_newdev(int argc, char **argv)
+{
+        return 0;
+}
+
+int jt_lcfg_attach(int argc, char **argv)
+{
+        struct lustre_cfg lcfg;
+        int rc;
+
+        LCFG_INIT(lcfg, LCFG_ATTACH);
+
+        if (argc != 2 && argc != 3 && argc != 4)
+                return CMD_HELP;
+
+        lcfg.lcfg_inllen1 = strlen(argv[1]) + 1;
+        lcfg.lcfg_inlbuf1 = argv[1];
+        if (argc >= 3) {
+                lcfg.lcfg_dev_namelen = strlen(argv[2]) + 1;
+                lcfg.lcfg_dev_name = argv[2];
+        } else {
+                fprintf(stderr, "error: %s: LCFG_ATTACH requires a name\n",
+                        jt_cmdname(argv[0])); 
+               return -EINVAL;
+       }
+
+        if (argc == 4) {
+                lcfg.lcfg_inllen2 = strlen(argv[3]) + 1;
+                lcfg.lcfg_inlbuf2 = argv[3];
+        }
+
+        rc = lcfg_ioctl(argv[0], OBD_DEV_ID, &lcfg);
+        if (rc < 0) {
+                fprintf(stderr, "error: %s: LCFG_ATTACH %s\n",
+                        jt_cmdname(argv[0]), strerror(rc = errno));
+        } else if (argc == 3) {
+                char name[1024];
+
+               lcfg_set_devname(argv[2]);
+                if (strlen(argv[2]) > 128) {
+                        printf("Name too long to set environment\n");
+                        return -EINVAL;
+                }
+                snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
+                rc = setenv(name, argv[1], 1);
+                if (rc) {
+                        printf("error setting env variable %s\n", name);
+                }
+        } else {
+               lcfg_set_devname(argv[2]);
+       }
+
+        return rc;
+}
+
+int jt_lcfg_setup(int argc, char **argv)
+{
+        struct lustre_cfg lcfg;
+        int rc;
+
+        LCFG_INIT(lcfg, LCFG_SETUP);
+
+        if (argc > 5)
+                return CMD_HELP;
+
+        if (argc > 1) {
+                lcfg.lcfg_inllen1 = strlen(argv[1]) + 1;
+                lcfg.lcfg_inlbuf1 = argv[1];
+        }
+        if (argc > 2) {
+                lcfg.lcfg_inllen2 = strlen(argv[2]) + 1;
+                lcfg.lcfg_inlbuf2 = argv[2];
+        }
+        if (argc > 3) {
+                lcfg.lcfg_inllen3 = strlen(argv[3]) + 1;
+                lcfg.lcfg_inlbuf3 = argv[3];
+        }
+        if (argc > 4) {
+                lcfg.lcfg_inllen4 = strlen(argv[4]) + 1;
+                lcfg.lcfg_inlbuf4 = argv[4];
+        }
+
+        rc = lcfg_ioctl(argv[0], OBD_DEV_ID, &lcfg);
+        if (rc < 0)
+                fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
+                        strerror(rc = errno));
+
+        return rc;
+}
+
+int jt_obd_detach(int argc, char **argv)
+{
+        struct lustre_cfg lcfg;
+        int rc;
+
+        LCFG_INIT(lcfg, LCFG_DETACH);
+
+        if (argc != 1)
+                return CMD_HELP;
+
+        rc = lcfg_ioctl(argv[0], OBD_DEV_ID, &lcfg);
+        if (rc < 0)
+                fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
+                        strerror(rc = errno));
+
+        return rc;
+}
+
+int jt_obd_cleanup(int argc, char **argv)
+{
+        struct lustre_cfg lcfg;
+        char force = 'F';
+        char failover = 'A';
+        char flags[3];
+        int flag_cnt = 0, n;
+        int rc;
+
+        LCFG_INIT(lcfg, LCFG_CLEANUP);
+
+        if (argc < 1 || argc > 3)
+                return CMD_HELP;
+
+        for (n = 1; n < argc; n++) 
+                if (strcmp(argv[n], "force") == 0) {
+                        flags[flag_cnt++] = force;
+                } else if (strcmp(argv[n], "failover") == 0) {
+                        flags[flag_cnt++] = failover;
+                } else {
+                        fprintf(stderr, "unknown option: %s", argv[n]);
+                        return CMD_HELP;
+                }
+
+       lcfg.lcfg_inllen1 = flag_cnt;
+        if (flag_cnt)
+                lcfg.lcfg_inlbuf1 = flags;
+
+        rc = lcfg_ioctl(argv[0], OBD_DEV_ID, &lcfg);
+        if (rc < 0)
+                fprintf(stderr, "error: %s: %s\n", jt_cmdname(argv[0]),
+                        strerror(rc = errno));
+
+        return rc;
+}
+
+static 
+int do_add_uuid(char * func, char *uuid, ptl_nid_t nid, int nal) 
+{
+        char tmp[64];
+        int rc;
+        struct lustre_cfg lcfg;
+
+        LCFG_INIT(lcfg, LCFG_ADD_UUID);
+        lcfg.lcfg_nid = nid;
+        lcfg.lcfg_inllen1 = strlen(uuid) + 1;
+        lcfg.lcfg_inlbuf1 = uuid;
+        lcfg.lcfg_nal = nal;
+
+        rc = lcfg_ioctl(func, OBD_DEV_ID, &lcfg);
+        if (rc) {
+                fprintf(stderr, "IOC_PORTAL_ADD_UUID failed: %s\n",
+                        strerror(errno));
+                return -1;
+        }
+
+        printf ("Added uuid %s: %s\n", uuid, ptl_nid2str (tmp, nid));
+        return 0;
+}
+
+int jt_lcfg_add_uuid(int argc, char **argv)
+{
+        ptl_nid_t nid = 0;
+        int nal;
+        
+        if (argc != 4) {                
+                return CMD_HELP;
+        }
+
+        if (ptl_parse_nid (&nid, argv[2]) != 0) {
+                fprintf (stderr, "Can't parse NID %s\n", argv[2]);
+                        return (-1);
+        }
+
+        nal = ptl_name2nal(argv[3]);
+
+        if (nal == 0) {
+                fprintf (stderr, "Can't parse NAL %s\n", argv[3]);
+                return -1;
+        }
+
+        return do_add_uuid(argv[0], argv[1], nid, nal);
+}
+
+int jt_lcfg_del_uuid(int argc, char **argv)
+{
+        int rc;
+        struct lustre_cfg lcfg;
+
+        if (argc != 2) {
+                fprintf(stderr, "usage: %s <uuid>\n", argv[0]);
+                return 0;
+        }
+
+        LCFG_INIT(lcfg, LCFG_DEL_UUID);
+
+        if (strcmp (argv[1], "_all_"))
+        {
+                lcfg.lcfg_inllen1 = strlen(argv[1]) + 1;
+                lcfg.lcfg_inlbuf1 = argv[1];
+        }
+        
+        rc = lcfg_ioctl(argv[0], OBD_DEV_ID, &lcfg);
+        if (rc) {
+                fprintf(stderr, "IOC_PORTAL_DEL_UUID failed: %s\n",
+                        strerror(errno));
+                return -1;
+        }
+        return 0;
+}
+
+int jt_lcfg_lov_setconfig(int argc, char **argv)
+{
+        struct lustre_cfg lcfg;
+        struct lov_desc desc;
+        struct obd_uuid *uuidarray, *ptr;
+        int rc, i;
+        char *end;
+
+        LCFG_INIT(lcfg, LCFG_LOV_SET_CONFIG);
+
+        if (argc <= 6)
+                return CMD_HELP;
+
+        if (strlen(argv[1]) > sizeof(desc.ld_uuid) - 1) {
+                fprintf(stderr,
+                        "error: %s: LOV uuid '%s' longer than "LPSZ" chars\n",
+                        jt_cmdname(argv[0]), argv[1], sizeof(desc.ld_uuid) - 1);
+                return -EINVAL;
+        }
+
+        memset(&desc, 0, sizeof(desc));
+        obd_str2uuid(&desc.ld_uuid, argv[1]);
+        desc.ld_tgt_count = argc - 6;
+        desc.ld_default_stripe_count = strtoul(argv[2], &end, 0);
+        if (*end) {
+                fprintf(stderr, "error: %s: bad default stripe count '%s'\n",
+                        jt_cmdname(argv[0]), argv[2]);
+                return CMD_HELP;
+        }
+        if (desc.ld_default_stripe_count > desc.ld_tgt_count) {
+                fprintf(stderr,
+                        "error: %s: default stripe count %u > OST count %u\n",
+                        jt_cmdname(argv[0]), desc.ld_default_stripe_count,
+                        desc.ld_tgt_count);
+                return -EINVAL;
+        }
+
+        desc.ld_default_stripe_size = strtoull(argv[3], &end, 0);
+        if (*end) {
+                fprintf(stderr, "error: %s: bad default stripe size '%s'\n",
+                        jt_cmdname(argv[0]), argv[3]);
+                return CMD_HELP;
+        }
+        if (desc.ld_default_stripe_size < 4096) {
+                fprintf(stderr,
+                        "error: %s: default stripe size "LPU64" too small\n",
+                        jt_cmdname(argv[0]), desc.ld_default_stripe_size);
+                return -EINVAL;
+        } else if ((long)desc.ld_default_stripe_size <
+                   desc.ld_default_stripe_size) {
+                fprintf(stderr,
+                        "error: %s: default stripe size "LPU64" too large\n",
+                        jt_cmdname(argv[0]), desc.ld_default_stripe_size);
+                return -EINVAL;
+        }
+        desc.ld_default_stripe_offset = strtoull(argv[4], &end, 0);
+        if (*end) {
+                fprintf(stderr, "error: %s: bad default stripe offset '%s'\n",
+                        jt_cmdname(argv[0]), argv[4]);
+                return CMD_HELP;
+        }
+        desc.ld_pattern = strtoul(argv[5], &end, 0);
+        if (*end) {
+                fprintf(stderr, "error: %s: bad stripe pattern '%s'\n",
+                        jt_cmdname(argv[0]), argv[5]);
+                return CMD_HELP;
+        }
+
+        /* NOTE: it is possible to overwrite the default striping parameters,
+         *       but EXTREME care must be taken when saving the OST UUID list.
+         *       It must be EXACTLY the same, or have only additions at the
+         *       end of the list, or only overwrite individual OST entries
+         *       that are restored from backups of the previous OST.
+         */
+        uuidarray = calloc(desc.ld_tgt_count, sizeof(*uuidarray));
+        if (!uuidarray) {
+                fprintf(stderr, "error: %s: no memory for %d UUIDs\n",
+                        jt_cmdname(argv[0]), desc.ld_tgt_count);
+                rc = -ENOMEM;
+                goto out;
+        }
+        for (i = 6, ptr = uuidarray; i < argc; i++, ptr++) {
+                if (strlen(argv[i]) >= sizeof(*ptr)) {
+                        fprintf(stderr, "error: %s: arg %d (%s) too long\n",
+                                jt_cmdname(argv[0]), i, argv[i]);
+                        rc = -EINVAL;
+                        goto out;
+                }
+                strcpy((char *)ptr, argv[i]);
+        }
+
+        lcfg.lcfg_inllen1 = sizeof(desc);
+        lcfg.lcfg_inlbuf1 = (char *)&desc;
+        lcfg.lcfg_inllen2 = desc.ld_tgt_count * sizeof(*uuidarray);
+        lcfg.lcfg_inlbuf2 = (char *)uuidarray;
+
+        rc = lcfg_ioctl(argv[0], OBD_DEV_ID, &lcfg);
+        if (rc)
+                fprintf(stderr, "error: %s: ioctl error: %s\n",
+                        jt_cmdname(argv[0]), strerror(rc = errno));
+out:
+        free(uuidarray);
+        return rc;
+}