From: rread Date: Mon, 29 Sep 2003 23:26:50 +0000 (+0000) Subject: Config interface now uses the new struct lustre_cfg for all config X-Git-Tag: v1_7_0_51~2^7~486 X-Git-Url: https://git.whamcloud.com/?a=commitdiff_plain;h=1133e35588273fcd3b29d6f6fce2ce24c73a866f;p=fs%2Flustre-release.git Config interface now uses the new struct lustre_cfg for all config 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 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. --- diff --git a/lustre/include/linux/lustre_cfg.h b/lustre/include/linux/lustre_cfg.h new file mode 100644 index 0000000..e6becb6 --- /dev/null +++ b/lustre/include/linux/lustre_cfg.h @@ -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. + * + * 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 + +/* 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 index 0000000..8080dab --- /dev/null +++ b/lustre/obdclass/config.c @@ -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 /* for request_module() */ +#include +#include +#include +#include +#include +#else +#include +#include +#include +#endif +#include +#include + + +/* 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 ? "" : + 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 index 0000000..510cd42 --- /dev/null +++ b/lustre/utils/lustre_cfg.c @@ -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 + * Author: Phil Schwan + * Author: Andreas Dilger + * Author: Robert Read + * + * 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 +#include +#include +#include + +#ifndef __KERNEL__ +#include +#endif +#include +#include +#include +#include +#include /* for struct lov_stripe_md */ +#include + +#include +#include +#include +#include +#include +#include + + +#include "obdctl.h" +#include +#include "parser.h" +#include + + +#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 \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; +}