--- /dev/null
+/* -*- 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
--- /dev/null
+/* -*- 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);
+}
+
--- /dev/null
+/* -*- 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;
+}