Whamcloud - gitweb
landing b_lcfg to b_devel
authorrread <rread>
Wed, 8 Oct 2003 07:07:12 +0000 (07:07 +0000)
committerrread <rread>
Wed, 8 Oct 2003 07:07:12 +0000 (07:07 +0000)
- llog network api for processing the log from the client
- config messages changed to use struct lustre_cfg and struct
  portals_cfg
- lctl record options save config messages to log on the mds
- ll_fill_super supports fetching the log and replaying to setup
  the devices needed for mount.
- small changes to lctl interface to support new config protocol.

  - newdev is now a no-op.
  - cfg_device <device name> is used to set the target device for
    detach and cleanup.

lustre/include/linux/lustre_cfg.h [new file with mode: 0644]
lustre/obdclass/llog_test.c
lustre/obdclass/obd_config.c [new file with mode: 0644]
lustre/ptlrpc/llogd.c [new file with mode: 0644]
lustre/ptlrpc/ptlrpc_module.c
lustre/utils/llmount.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..5403244
--- /dev/null
@@ -0,0 +1,237 @@
+/* -*- 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,
+        LCFG_MOUNTOPT       = 0x00cf008,
+        LCFG_DEL_MOUNTOPT   = 0x00cf009,
+};
+
+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 size_round16(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>
+
+static inline int lustre_cfg_getdata(char **buf, int len, void *arg, int kernel)
+{
+        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_ALLOC(*buf, len);
+        if (*buf == NULL) {
+                CERROR("Cannot allocate control buffer of len %d\n", len);
+                RETURN(-EINVAL);
+        }
+
+        if (kernel) {
+                memcpy(*buf, (void *)arg, len);
+        } else {
+                err = copy_from_user(*buf, (void *)arg, len);
+                if (err) 
+                        RETURN(err);
+        }
+
+        lcfg = (struct lustre_cfg *)*buf;
+
+        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_FREE(buf, len);
+        EXIT;
+        return;
+}
+
+#endif // _LUSTRE_CFG_H
index ab37397..06a4ac0 100644 (file)
@@ -72,15 +72,13 @@ static int verify_handle(char * test, struct llog_handle *llh, int num_recs)
 }
 
 /* Test named-log create/open, close */
-static int llog_test_1(struct obd_device *obd)
+static int llog_test_1(struct obd_device *obd, char * name)
 {
         struct llog_handle *llh;
-        char name[10];
         int rc;
         int rc2;
         ENTRY;
 
-        sprintf(name, "%x", llog_test_rand);
         CERROR("1a: create a log with name: %s\n", name);
 
         rc = llog_create(obd, &llh, NULL, name);
@@ -105,13 +103,11 @@ static int llog_test_1(struct obd_device *obd)
 }
 
 /* Test named-log reopen; returns opened log on success */
-static int llog_test_2(struct obd_device *obd, struct llog_handle **llh)
+static int llog_test_2(struct obd_device *obd, char * name, struct llog_handle **llh)
 {
-        char name[10];
         int rc;
         ENTRY;
 
-        sprintf(name, "%x", llog_test_rand);
         CERROR("2: re-open a log with name: %s\n", name);
         rc = llog_create(obd, llh, NULL, name);
         if (rc) {
@@ -338,6 +334,46 @@ static int llog_test_5(struct obd_device *obd)
 }
 
 
+static int llog_test6_process_rec(struct llog_rec_hdr * rec, void * private) 
+{
+        return 0;
+}
+
+/* Test client api; open log by name and process */
+static int llog_test_6(struct obd_device *obd, char * name)
+{
+        struct obd_device *mdc_obd;
+        struct obd_uuid *mds_uuid = &obd->obd_log_exp->exp_obd->obd_uuid;
+        struct lustre_handle exph = {0, };
+        struct obd_export * exp;
+        struct obd_uuid uuid = {"LLOG_TEST6_UUID"};
+        int rc;
+
+        CERROR("6a: re-open log %s using client API\n", name);
+        mdc_obd = class_find_client_obd(mds_uuid, LUSTRE_MDC_NAME, NULL);
+        if (mdc_obd == NULL) {
+                CERROR("No MDC devices connected to %s found.\n", 
+                       mds_uuid->uuid);
+                RETURN(-ENOENT);
+        }
+
+        rc = obd_connect(&exph, mdc_obd, &uuid);
+        if (rc) {
+                CERROR("Failed to connect to MDC: %s\n", mdc_obd->obd_name);
+                RETURN(rc);
+        }
+
+        exp = class_conn2export(&exph);
+        rc = mdc_llog_process(exp, name, NULL, llog_test6_process_rec);
+        if (rc) {
+                CERROR("mdc_llog_process failed: rc = %d\n", rc);
+        }
+
+        rc = obd_disconnect(exp, 0);
+        
+        RETURN(rc);
+                
+}
 
 /* -------------------------------------------------------------------------
  * Tests above, boring obd functions below
@@ -347,15 +383,17 @@ static int llog_run_tests(struct obd_device *obd)
         struct llog_handle *llh;
         struct obd_run_ctxt saved;
         int rc, err, cleanup_phase = 0;
+        char name[10];
         ENTRY;
 
+        sprintf(name, "%x", llog_test_rand);
         push_ctxt(&saved, &obd->obd_log_exp->exp_obd->obd_ctxt, NULL);
 
-        rc = llog_test_1(obd);
+        rc = llog_test_1(obd, name);
         if (rc)
                 GOTO(cleanup, rc);
 
-        rc = llog_test_2(obd, &llh);
+        rc = llog_test_2(obd, name, &llh);
         if (rc)
                 GOTO(cleanup, rc);
         cleanup_phase = 1; /* close llh */
@@ -372,6 +410,10 @@ static int llog_run_tests(struct obd_device *obd)
         if (rc)
                 GOTO(cleanup, rc);
 
+        rc = llog_test_6(obd, name);
+        if (rc)
+                GOTO(cleanup, rc);
+
         GOTO(cleanup, rc);
  cleanup:
         switch (cleanup_phase) {
@@ -398,28 +440,28 @@ static int llog_test_cleanup(struct obd_device *obd, int flags)
 
 static int llog_test_setup(struct obd_device *obd, obd_count len, void *buf)
 {
-        struct obd_ioctl_data *data = buf;
+        struct lustre_cfg *lcfg = buf;
         struct lustre_handle exph = {0, };
         struct obd_device *tgt;
         struct obd_uuid fake_uuid = { "LLOG_TEST_UUID" };
         int rc;
         ENTRY;
 
-        if (data->ioc_inllen1 < 1) {
+        if (lcfg->lcfg_inllen1 < 1) {
                 CERROR("requires a TARGET OBD name\n");
                 RETURN(-EINVAL);
         }
 
-        tgt = class_name2obd(data->ioc_inlbuf1);
+        tgt = class_name2obd(lcfg->lcfg_inlbuf1);
         if (!tgt || !tgt->obd_attached || !tgt->obd_set_up) {
                 CERROR("target device not attached or not set up (%d/%s)\n",
-                       data->ioc_dev, data->ioc_inlbuf1);
+                       lcfg->lcfg_dev, lcfg->lcfg_inlbuf1);
                 RETURN(-EINVAL);
         }
 
         rc = obd_connect(&exph, tgt, &fake_uuid);
         if (rc) {
-                CERROR("fail to connect to target device %d\n", data->ioc_dev);
+                CERROR("fail to connect to target device %d\n", lcfg->lcfg_dev);
                 RETURN(rc);
         }
         obd->obd_log_exp = class_conn2export(&exph);
diff --git a/lustre/obdclass/obd_config.c b/lustre/obdclass/obd_config.c
new file mode 100644 (file)
index 0000000..a66bdff
--- /dev/null
@@ -0,0 +1,474 @@
+/* -*- 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) {
+                CERROR("obd %s already attached\n", name);
+                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);
+}
+
+LIST_HEAD(lustre_profile_list);
+
+struct lustre_profile *class_get_profile(char * prof)
+{
+        struct lustre_profile *lprof;
+        
+        list_for_each_entry(lprof, &lustre_profile_list, lp_list) {
+                if (!strcmp(lprof->lp_profile, prof)) {
+                        RETURN(lprof);
+                }
+        }
+        RETURN(NULL);
+}
+
+int class_add_profile(int proflen, char *prof, 
+                      int osclen, char *osc, 
+                      int mdclen, char *mdc)
+{
+        struct lustre_profile *lprof;
+        int err = 0;
+
+        OBD_ALLOC(lprof, sizeof(*lprof));
+        if (lprof == NULL)
+                GOTO(out, err = -ENOMEM);
+        INIT_LIST_HEAD(&lprof->lp_list);
+
+        LASSERT(proflen == (strlen(prof) + 1));
+        OBD_ALLOC(lprof->lp_profile, proflen);
+        if (lprof->lp_profile == NULL)
+                GOTO(out, err = -ENOMEM);
+        memcpy(lprof->lp_profile, prof, proflen);
+        
+        LASSERT(osclen == (strlen(osc) + 1));
+        OBD_ALLOC(lprof->lp_osc, osclen);
+        if (lprof->lp_profile == NULL)
+                GOTO(out, err = -ENOMEM);
+        memcpy(lprof->lp_osc, osc, osclen);
+
+        LASSERT(mdclen == (strlen(mdc) + 1));
+        OBD_ALLOC(lprof->lp_mdc, mdclen);
+        if (lprof->lp_mdc == NULL)
+                GOTO(out, err = -ENOMEM);
+        memcpy(lprof->lp_mdc, mdc, mdclen);
+
+        list_add(&lprof->lp_list, &lustre_profile_list);
+
+out:
+        RETURN(err);
+}
+
+void class_del_profile(char *prof)
+{
+        struct lustre_profile *lprof;
+        
+        lprof = class_get_profile(prof);
+        if (lprof) {
+                list_del(&lprof->lp_list);
+                OBD_FREE(lprof->lp_profile, strlen(lprof->lp_profile) + 1);
+                OBD_FREE(lprof->lp_osc, strlen(lprof->lp_osc) + 1);
+                OBD_FREE(lprof->lp_mdc, strlen(lprof->lp_mdc) + 1);
+                OBD_FREE(lprof, sizeof *lprof);
+        }
+}
+
+int class_process_config(struct lustre_cfg *lcfg)
+{
+       struct obd_device *obd;
+        int err;
+
+        LASSERT(lcfg && !IS_ERR(lcfg));
+
+        CDEBUG(D_IOCTL, "processing cmd: %x\n", lcfg->lcfg_command);
+
+        /* 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);
+        }
+        case LCFG_MOUNTOPT: {
+                CDEBUG(D_IOCTL, "mountopt: profile %s osc %s mdc %s\n", 
+                       lcfg->lcfg_inlbuf1, lcfg->lcfg_inlbuf2, lcfg->lcfg_inlbuf3);
+                /* set these mount options somewhere, so ll_fill_super
+                 * can find them. */
+                err = class_add_profile(lcfg->lcfg_inllen1, lcfg->lcfg_inlbuf1, 
+                                        lcfg->lcfg_inllen2, lcfg->lcfg_inlbuf2, 
+                                        lcfg->lcfg_inllen3, lcfg->lcfg_inlbuf3);
+                GOTO(out, err);
+        }
+        case LCFG_DEL_MOUNTOPT: {
+                CDEBUG(D_IOCTL, "mountopt: profile %s\n", lcfg->lcfg_inlbuf1);
+                /* set these mount options somewhere, so ll_fill_super
+                 * can find them. */
+                class_del_profile(lcfg->lcfg_inlbuf1);
+                GOTO(out, err = 0);
+        }
+       }
+       
+
+       /* 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:
+        RETURN(err);
+}
+           
diff --git a/lustre/ptlrpc/llogd.c b/lustre/ptlrpc/llogd.c
new file mode 100644 (file)
index 0000000..e5525c9
--- /dev/null
@@ -0,0 +1,291 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2001-2003 Cluster File Systems, Inc.
+ *   Author: Andreas Dilger <adilger@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.
+ *
+ * remote api for llog
+ *
+ */
+
+#define DEBUG_SUBSYSTEM S_LOG
+
+#ifndef EXPORT_SYMTAB
+#define EXPORT_SYMTAB
+#endif
+
+#include <linux/fs.h>
+#include <linux/obd_class.h>
+#include <linux/lustre_log.h>
+#include <linux/lustre_net.h>
+#include <portals/list.h>
+
+int llogd_init(struct ptlrpc_request *req)
+{
+        struct obd_export *exp = req->rq_export;
+        struct obd_device *obd = exp->exp_obd;
+       struct llog_handle  *loghandle;
+        struct llog_desc desc;
+        struct obd_run_ctxt saved;
+        void * ptr;
+       char * name;
+        int size[] = {sizeof (desc), 
+                      LLOG_BITMAP_BYTES};
+       int rc, rc2;
+       ENTRY;
+
+        LASSERT(obd->obd_log_exp == NULL);
+
+       name = lustre_msg_string(req->rq_reqmsg, 0, 0);
+        if (name == NULL) {
+                CERROR("Can't unpack name\n");
+                GOTO(out, rc = -EFAULT);
+        }
+
+       memset(&desc, 0, sizeof(desc));
+       
+       push_ctxt(&saved, &obd->obd_ctxt, NULL);
+        obd->obd_log_exp = class_export_get(exp);
+        
+       rc = llog_create(obd, &loghandle, NULL, name);
+       if (rc)
+               GOTO(out_pop, rc);
+       desc.lgd_logid = loghandle->lgh_id;
+        desc.lgd_cur_offset = LLOG_CHUNK_SIZE; /* skip header block */
+
+       rc = llog_init_handle(loghandle, LLOG_F_IS_PLAIN, 
+                             NULL);
+       if (rc)
+               GOTO(out_close, rc);
+
+        rc = lustre_pack_msg(2, size, NULL, &req->rq_replen, &req->rq_repmsg);
+       if (rc) 
+                GOTO(out_close, rc = -ENOMEM);
+
+        ptr = lustre_msg_buf(req->rq_repmsg, 0, sizeof (desc));
+       memcpy(ptr, &desc, sizeof(desc));
+
+        ptr = lustre_msg_buf(req->rq_repmsg, 1, LLOG_BITMAP_BYTES);
+        memcpy(ptr, loghandle->lgh_hdr->llh_bitmap, LLOG_BITMAP_BYTES);
+
+out_close:
+       rc2 = llog_close(loghandle);
+        class_export_put(obd->obd_log_exp);
+        obd->obd_log_exp = NULL;
+        if (!rc) 
+                rc = rc2;
+out_pop:
+       pop_ctxt(&saved, &obd->obd_ctxt, NULL);
+out:
+       RETURN(rc);
+}
+
+int llogd_next_block(struct ptlrpc_request *req)
+{
+        struct obd_export *exp = req->rq_export;
+        struct obd_device *obd = exp->exp_obd;
+       struct llog_handle  *loghandle;
+        struct llog_desc *desc;
+        struct obd_run_ctxt saved;
+        __u8 *buf;
+        void * ptr;
+        int size[] = {sizeof (*desc),
+                      LLOG_CHUNK_SIZE};
+       int rc, rc2;
+       ENTRY;
+
+        LASSERT(obd->obd_log_exp == NULL);
+
+       desc = lustre_swab_reqbuf(req, 0, sizeof(*desc),
+                                 lustre_swab_llog_desc);
+       if (desc == NULL) {
+                CERROR ("Can't unpack llog_desc\n");
+                GOTO(out, rc =-EFAULT);
+       }
+
+        OBD_ALLOC(buf, LLOG_CHUNK_SIZE);
+        if (!buf)
+                GOTO(out, rc = -ENOMEM);
+
+       push_ctxt(&saved, &obd->obd_ctxt, NULL);
+        obd->obd_log_exp = class_export_get(exp);
+
+       rc = llog_create(obd, &loghandle, &desc->lgd_logid, NULL);
+       if (rc)
+               GOTO(out_pop, rc);
+
+       rc = llog_init_handle(loghandle, LLOG_F_IS_PLAIN, NULL);
+       if (rc)
+               GOTO(out_close, rc);
+
+       memset(buf, 0, LLOG_CHUNK_SIZE);
+       rc = llog_next_block(loghandle, &desc->lgd_saved_index, 
+                             desc->lgd_index, 
+                            &desc->lgd_cur_offset, buf, LLOG_CHUNK_SIZE);
+       if (rc)
+               GOTO(out_close, rc);
+
+
+        rc = lustre_pack_msg(2, size, NULL, &req->rq_replen, &req->rq_repmsg);
+       if (rc) 
+                GOTO(out_close, rc = -ENOMEM);
+
+        ptr = lustre_msg_buf(req->rq_repmsg, 0, sizeof (desc));
+       memcpy(ptr, desc, sizeof(*desc));
+
+        ptr = lustre_msg_buf(req->rq_repmsg, 1, LLOG_CHUNK_SIZE);
+       memcpy(ptr, buf, LLOG_CHUNK_SIZE);
+
+out_close:
+       rc2 = llog_close(loghandle);
+        class_export_put(obd->obd_log_exp);
+        obd->obd_log_exp = NULL;
+       if (!rc)
+                rc = rc2;
+
+out_pop:
+       pop_ctxt(&saved, &obd->obd_ctxt, NULL);
+        OBD_FREE(buf, LLOG_CHUNK_SIZE);
+out:
+       RETURN(rc);
+}
+
+int llogd_close(struct ptlrpc_request *req)
+{
+       int rc;
+
+        rc = 0;
+
+       RETURN(rc);
+}
+
+
+int llogd_client_init(struct obd_export *exp, char * logname, 
+                      struct llog_desc **desc, __u32 **bitmap)
+{
+        struct obd_import *imp = class_exp2cliimp(exp);
+        struct ptlrpc_request *req = NULL;
+        void * ptr;
+        int size;
+        int repsize[] = {sizeof (**desc),
+                         LLOG_BITMAP_BYTES};
+        int rc;
+        ENTRY;
+
+        LASSERT(*desc == NULL);
+        LASSERT(*bitmap == NULL);
+        
+        size = strlen(logname) + 1;
+        req = ptlrpc_prep_req(imp, LLOG_INIT, 1, &size, &logname);
+        if (!req)
+                GOTO(out, rc = -ENOMEM);
+        
+        req->rq_replen = lustre_msg_size(2, repsize);
+        rc = ptlrpc_queue_wait(req);
+        if (rc)
+                GOTO(out, rc);
+        
+        OBD_ALLOC(*desc, sizeof (**desc));
+        if (*desc == NULL)
+                GOTO(out, rc = -ENOMEM);
+
+        OBD_ALLOC(*bitmap, LLOG_BITMAP_BYTES);
+        if (*bitmap == NULL)
+                GOTO(err_free, rc = -ENOMEM);
+
+
+       ptr = lustre_swab_repbuf(req, 0, sizeof(**desc),
+                                 lustre_swab_llog_desc);
+       if (ptr == NULL) {
+                CERROR ("Can't unpack llog_desc\n");
+                GOTO(err_free, rc =-EFAULT);
+       }
+        memcpy(*desc, ptr, sizeof(**desc));
+        
+        ptr = lustre_msg_buf(req->rq_repmsg, 1, LLOG_BITMAP_BYTES);
+       if (ptr == NULL) {
+                CERROR ("Can't unpack bitmap\n");
+                GOTO(err_free, rc =-EFAULT);
+       }
+        memcpy(*bitmap, ptr, LLOG_BITMAP_BYTES);
+
+out:
+        if (req)
+                ptlrpc_req_finished(req);
+        RETURN(rc);
+
+err_free:
+        if (*bitmap)
+                OBD_FREE(*bitmap, LLOG_BITMAP_BYTES);
+        if (*desc)
+                OBD_FREE(*desc, sizeof (**desc));
+        goto out;
+}
+
+int llogd_client_next_block(struct obd_export *exp, struct llog_desc *desc, 
+                            char * buf, int buf_size)
+{
+        struct obd_import *imp = class_exp2cliimp(exp);
+        struct ptlrpc_request *req = NULL;
+        void * ptr;
+        int size = sizeof(*desc);
+        int repsize[] = {sizeof (*desc),
+                         LLOG_CHUNK_SIZE};
+        int rc;
+        ENTRY;
+
+        LASSERT (buf_size == LLOG_CHUNK_SIZE);
+        
+        req = ptlrpc_prep_req(imp, LLOG_NEXT_BLOCK, 1, &size, (char **) &desc);
+        if (!req)
+                GOTO(out, rc = -ENOMEM);
+        
+        req->rq_replen = lustre_msg_size(2, repsize);
+        rc = ptlrpc_queue_wait(req);
+        if (rc)
+                GOTO(out, rc);
+        
+       ptr = lustre_swab_repbuf(req, 0, sizeof(*desc),
+                                 lustre_swab_llog_desc);
+       if (ptr == NULL) {
+                CERROR ("Can't unpack llog_desc\n");
+                GOTO(out, rc =-EFAULT);
+       }
+        memcpy(desc, ptr, sizeof(*desc));
+        
+        ptr = lustre_msg_buf(req->rq_repmsg, 1, LLOG_CHUNK_SIZE);
+       if (ptr == NULL) {
+                CERROR ("Can't unpack bitmap\n");
+                GOTO(out, rc =-EFAULT);
+       }
+        memcpy(buf, ptr, buf_size);
+
+out:
+        if (req)
+                ptlrpc_req_finished(req);
+        RETURN(rc);
+}
+
+
+int llogd_client_close(struct obd_export *exp, struct llog_desc **desc, 
+                       __u32 **bitmap)
+{
+        OBD_FREE(*desc, sizeof (**desc));
+        OBD_FREE(*bitmap, LLOG_BITMAP_BYTES);
+        RETURN(0);
+}
index 3938a2b..8486b76 100644 (file)
@@ -248,6 +248,14 @@ EXPORT_SYMBOL(ptlrpc_pinger_sending_on_import);
 EXPORT_SYMBOL(ptlrpc_lprocfs_register_obd);
 EXPORT_SYMBOL(ptlrpc_lprocfs_unregister_obd);
 
+/* llogd.c */
+EXPORT_SYMBOL(llogd_init);
+EXPORT_SYMBOL(llogd_next_block);
+EXPORT_SYMBOL(llogd_close);
+EXPORT_SYMBOL(llogd_client_init);
+EXPORT_SYMBOL(llogd_client_next_block);
+EXPORT_SYMBOL(llogd_client_close);
+
 #ifdef __KERNEL__
 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
 MODULE_DESCRIPTION("Lustre Request Processor");
diff --git a/lustre/utils/llmount.c b/lustre/utils/llmount.c
new file mode 100644 (file)
index 0000000..1063886
--- /dev/null
@@ -0,0 +1,111 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  Copyright (C) 2002 Cluster File Systems, Inc.
+ *   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 <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/mount.h>
+#include <mntent.h>
+
+int verbose = 0;
+int nomtab = 0;
+
+
+static void
+update_mtab_entry(char *spec, char *node, char *type, char *opts,
+                 int flags, int freq, int pass) 
+{
+        FILE *fp;
+        struct mntent mnt;
+
+        mnt.mnt_fsname = spec;
+        mnt.mnt_dir = node;
+        mnt.mnt_type = type;
+        mnt.mnt_opts = opts;
+        mnt.mnt_freq = freq;
+        mnt.mnt_passno = pass;
+      
+        if (!nomtab) {
+                fp = setmntent(MOUNTED, "a+");
+                if (fp == NULL) {
+                        fprintf(stderr, "setmntent(%s): %s:", MOUNTED, 
+                                strerror (errno));
+                } else {
+                        if ((addmntent (fp, &mnt)) == 1) {
+                                fprintf(stderr, "addmntent: %s:", 
+                                        strerror (errno));
+                        }
+                        endmntent(fp);
+                }
+        }
+}
+
+int
+main(int argc, char * const argv[])
+{
+        char * source = argv[1];
+        char * target = argv[2];
+        char * options = NULL;
+        int opt;
+        int i;
+        int rc;
+        
+       for (i = 0; i < argc; i++) {
+               printf("arg[%d] = %s\n", i, argv[i]);
+       }
+       while ((opt = getopt(argc, argv, "vno:")) != EOF) {
+
+               switch (opt) {
+               case 'v':
+                        verbose = 1;
+                        break;
+               case 'n':
+                        nomtab = 1;
+                       break;
+                       
+               case 'o':
+                        options = optarg;
+                       break;
+                default:
+                        printf("default\n");
+               }
+       }
+               
+        if (optind < argc) {
+                printf("optind %d\n", optind);
+/*
+                while(optind < argc)
+*/
+        }
+        rc = mount(source, target, "lustre_lite", 0, options);
+        if (rc) {
+                perror("mount.lustre_lite:");
+        } else {
+                update_mtab_entry(source, target, "lustre_lite", options, 
+                                  0, 0, 0);
+        }
+       return rc;
+}
diff --git a/lustre/utils/lustre_cfg.c b/lustre/utils/lustre_cfg.c
new file mode 100644 (file)
index 0000000..ef64ed6
--- /dev/null
@@ -0,0 +1,477 @@
+/* -*- 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;
+}
+
+int jt_lcfg_mount_option(int argc, char **argv)
+{
+        int rc;
+        struct lustre_cfg lcfg;
+
+        LCFG_INIT(lcfg, LCFG_MOUNTOPT);
+
+        if (argc != 4)
+                return CMD_HELP;
+
+        /* profile name */
+        lcfg.lcfg_inllen1 = strlen(argv[1]) + 1;
+        lcfg.lcfg_inlbuf1 = argv[1];
+        /* osc name */
+        lcfg.lcfg_inllen2 = strlen(argv[2]) + 1;
+        lcfg.lcfg_inlbuf2 = argv[2];
+        /* mdc name */
+        lcfg.lcfg_inllen3 = strlen(argv[3]) + 1;
+        lcfg.lcfg_inlbuf3 = argv[3];
+
+        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_lcfg_del_mount_option(int argc, char **argv)
+{
+        int rc;
+        struct lustre_cfg lcfg;
+
+        LCFG_INIT(lcfg, LCFG_DEL_MOUNTOPT);
+
+        if (argc != 2)
+                return CMD_HELP;
+
+        /* profile name */
+        lcfg.lcfg_inllen1 = strlen(argv[1]) + 1;
+        lcfg.lcfg_inlbuf1 = argv[1];
+
+        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;
+}
+