From 6c47e7f99f5fa8884751ac549a45dd3c0b81e7f1 Mon Sep 17 00:00:00 2001 From: Andreas Dilger Date: Thu, 15 Sep 2016 01:49:55 +0800 Subject: [PATCH] LU-8599 utils: restore lshowmount utility The lshowmount utility was removed in commit b5a7260ae8f as being obsolete, but it was not as unused as previously thought. Restore lshowmount.c, lshowmount.8, nidlist.c, and nidlist.h from history, with minor updates to the Makefiles and .gitignore to avoid conflicts in context. Signed-off-by: Andreas Dilger Signed-off-by: Yang Sheng Change-Id: Ibf6f72684d4dcaa95e0366b4fde74386893ebbe5 Reviewed-on: http://review.whamcloud.com/17593 Tested-by: Jenkins Tested-by: Maloo Reviewed-by: James Simmons Reviewed-by: Thomas Stibor Reviewed-by: Oleg Drokin --- lustre/doc/Makefile.am | 2 +- lustre/doc/lshowmount.8 | 43 ++++++ lustre/doc/lustre.7 | 1 + lustre/tests/conf-sanity.sh | 27 ++++ lustre/utils/.gitignore | 1 + lustre/utils/Makefile.am | 5 +- lustre/utils/lshowmount.c | 223 ++++++++++++++++++++++++++++ lustre/utils/nidlist.c | 353 ++++++++++++++++++++++++++++++++++++++++++++ lustre/utils/nidlist.h | 51 +++++++ 9 files changed, 704 insertions(+), 2 deletions(-) create mode 100644 lustre/doc/lshowmount.8 create mode 100644 lustre/utils/lshowmount.c create mode 100644 lustre/utils/nidlist.c create mode 100644 lustre/utils/nidlist.h diff --git a/lustre/doc/Makefile.am b/lustre/doc/Makefile.am index bd5de6c..21eb4a9 100644 --- a/lustre/doc/Makefile.am +++ b/lustre/doc/Makefile.am @@ -60,7 +60,7 @@ MANFILES = lustre.7 lfs.1 mount.lustre.8 lctl.8 lnetctl.8 \ llapi_hsm_action_get_fd.3 lustreapi.7 llapi_hsm_action_begin.3 \ llapi_hsm_copytool_register.3 lfs-ladvise.1 llapi_ladvise.3 -SERVER_MANFILES = mkfs.lustre.8 tunefs.lustre.8 +SERVER_MANFILES = mkfs.lustre.8 tunefs.lustre.8 lshowmount.8 if SERVER MANFILES += $(SERVER_MANFILES) diff --git a/lustre/doc/lshowmount.8 b/lustre/doc/lshowmount.8 new file mode 100644 index 0000000..a2ad08e --- /dev/null +++ b/lustre/doc/lshowmount.8 @@ -0,0 +1,43 @@ +.TH LSHOWMOUNT 8 Lustre LLNL LSHOWMOUNT +.SH NAME +lshowmount \- show lustre exports +.SH SYNOPSIS +.B "lshowmount [-ehlv]" +.br +.SH DESCRIPTION +.B lshowmount +Utility to show the hosts that have lustre currently mounted to a server. +Ths utility looks for any exports from the mgs, mds, and obdfilter. +.SH OPTIONS +.B lshowmount +accepts the following options: +.TP +.I "-e | --enumerate" +causes +.B lshowmount +to list each client mounted on a separate line instead of trying +to compress the list of clients into a hostrange string. +.TP +.I "-h | --help" +causes +.B lshowmount +to print out a usage message. +.TP +.I "-l | --lookup" +causes +.B lshowmount +to try to lookup the hostname for nids that look like IP addresses. +.TP +.I "-v | --verbose" +causes +.B lshowmount +to output export information for each service instead of only displaying +the aggregate information for all Lustre services on the server. +.SH FILES +/proc/fs/lustre/mgs//exports//nid +.br +/proc/fs/lustre/mds//exports//nid +.br +/proc/fs/lustre/obdfilter//exports//nid +.SH AUTHOR +Herb Wartens diff --git a/lustre/doc/lustre.7 b/lustre/doc/lustre.7 index a8f013a..df31389 100644 --- a/lustre/doc/lustre.7 +++ b/lustre/doc/lustre.7 @@ -81,4 +81,5 @@ https://downloads.hpdd.intel.com/ .BR llobdstat (8), .BR ll_decode_filter_fid (8), .BR llog_reader (8), +.BR lshowmount (8), .BR lustre_rsync (8) diff --git a/lustre/tests/conf-sanity.sh b/lustre/tests/conf-sanity.sh index 69643ef..a795457 100755 --- a/lustre/tests/conf-sanity.sh +++ b/lustre/tests/conf-sanity.sh @@ -6924,6 +6924,33 @@ test_99() } run_test 99 "Adding meta_bg option" +test_100() { + reformat + start_mds || error "MDS start failed" + start_ost || error "unable to start OST" + mount_client $MOUNT || error "client start failed" + check_mount || error "check_mount failed" + + # Desired output + # MGS: + # 0@lo + # lustre-MDT0000: + # 0@lo + # lustre-OST0000: + # 0@lo + do_facet mgs 'lshowmount -v' | awk 'BEGIN {NR == 0; rc=1} /MGS:/ {rc=0} + END {exit rc}' || error "lshowmount have no output MGS" + + do_facet mds1 'lshowmount -v' | awk 'BEGIN {NR == 2; rc=1} /-MDT0000:/ + {rc=0} END {exit rc}' || error "lshowmount have no output MDT0" + + do_facet ost1 'lshowmount -v' | awk 'BEGIN {NR == 4; rc=1} /-OST0000:/ + {rc=0} END {exit rc}' || error "lshowmount have no output OST0" + + cleanup || error "cleanup failed with $?" +} +run_test 100 "check lshowmount lists MGS, MDT, OST and 0@lo" + if ! combined_mgs_mds ; then stop mgs fi diff --git a/lustre/utils/.gitignore b/lustre/utils/.gitignore index 197a83d..41c8add 100644 --- a/lustre/utils/.gitignore +++ b/lustre/utils/.gitignore @@ -20,6 +20,7 @@ /tunefs_lustre /lreplicate /ltrack_stats +/lshowmount /lustre_rsync /ll_decode_filter_fid /lhsmd_posix diff --git a/lustre/utils/Makefile.am b/lustre/utils/Makefile.am index 87b4861..bf03079 100644 --- a/lustre/utils/Makefile.am +++ b/lustre/utils/Makefile.am @@ -39,7 +39,7 @@ sbin_PROGRAMS += wiretest endif # TESTS if SERVER -sbin_PROGRAMS += mkfs.lustre tunefs.lustre llverdev lr_reader \ +sbin_PROGRAMS += mkfs.lustre tunefs.lustre llverdev lr_reader lshowmount \ ll_decode_filter_fid llog_reader endif if LIBPTHREAD @@ -66,6 +66,9 @@ lustre_rsync_SOURCES = lustre_rsync.c obd.c lustre_cfg.c lustre_rsync.h lustre_rsync_LDADD := liblustreapi.a $(LIBPTLCTL) $(LIBREADLINE) $(PTHREAD_LIBS) lustre_rsync_DEPENDENCIES := $(LIBPTLCTL) liblustreapi.a +lshowmount_SOURCES = lshowmount.c nidlist.c nidlist.h +lshowmount_LDADD := liblustreapi.a + if EXT2FS_DEVEL EXT2FSLIB = -lext2fs E2PLIB = -le2p diff --git a/lustre/utils/lshowmount.c b/lustre/utils/lshowmount.c new file mode 100644 index 0000000..89bc3d5 --- /dev/null +++ b/lustre/utils/lshowmount.c @@ -0,0 +1,223 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program 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 version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * + * lustre/utils/lshowmount.h + * + * Author: Herb Wartens + * Author: Jim Garlick + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "nidlist.h" +#include "lustreapi_internal.h" + +#define PROC_UUID_TMPL "%s/%s/uuid" + +static void print_nids(NIDList nidlist, int lookup, int enumerate, int indent); +static int lshowmount(int lookup, int enumerate, int verbose); +static void read_exports(char *exports, NIDList nidlist); + +char *prog; + +#define OPTIONS "ehlv" +static struct option long_options[] = { + {"enumerate", no_argument, 0, 'e'}, + {"help", no_argument, 0, 'h'}, + {"lookup", no_argument, 0, 'l'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0}, +}; + +static void usage(void) +{ + fprintf(stderr, "usage: %s [-e] [-h] [-l] [-v]\n", prog); + exit(1); +} + +int main(int argc, char **argv) +{ + int opt, optidx = 0; + int lopt = 0; + int vopt = 0; + int eopt = 0; + + prog = basename(argv[0]); + + while ((opt = getopt_long(argc, argv, OPTIONS, long_options, + &optidx)) != -1) { + switch (opt) { + case 'e': /* --enumerate */ + eopt = 1; + break; + case 'l': /* --lookup */ + lopt = 1; + break; + case 'v': /* --verbose */ + vopt = 1; + break; + case 'h': /* --help */ + default: + usage(); + } + } + + if (lshowmount(lopt, eopt, vopt) == 0) { + fprintf(stderr, "%s: lustre server modules not loaded\n", prog); + exit(1); + } + exit(0); +} + + +static void print_expname(const char *path) +{ + char *hp, buf[PATH_MAX + 1]; + + strncpy(buf, path, PATH_MAX); + buf[PATH_MAX] = '\0'; + hp = strstr(buf, "exports"); + if (hp && hp > buf) { + *(--hp) = '\0'; + for (; *hp == '/' && hp > buf; hp--) + ; + for (; *hp != '/' && hp > buf; hp--) + ; + printf("%s:\n", hp + 1); + } +} + +static void print_nids(NIDList nidlist, int lookup, int enumerate, int indent) +{ + char *s, *sep = "\n", *pfx = ""; + + if (lookup) + nl_lookup_ip(nidlist); + nl_sort(nidlist); + nl_uniq(nidlist); + if (nl_count(nidlist) > 0) { + if (indent) { + sep = "\n "; + pfx = " "; + } + if (enumerate) + s = nl_string(nidlist, sep); + else + s = nl_xstring(nidlist, sep); + printf("%s%s\n", pfx, s); + free(s); + } +} + +static int lshowmount(int lookup, int enumerate, int verbose) +{ + NIDList nidlist = NULL; + glob_t exp_list; + int i; + + i = get_lustre_param_path("{mgs,mdt,obdfilter}", "*", + FILTER_BY_EXACT, "exports", &exp_list); + if (i < 0) + return i; + if (!verbose) + nidlist = nl_create(); + for (i = 0; i < exp_list.gl_pathc; i++) { + if (verbose) { + nidlist = nl_create(); + read_exports(exp_list.gl_pathv[i], nidlist); + print_expname(exp_list.gl_pathv[i]); + print_nids(nidlist, lookup, enumerate, 1); + nl_destroy(nidlist); + } else + read_exports(exp_list.gl_pathv[i], nidlist); + } + if (!verbose) { + print_nids(nidlist, lookup, enumerate, 0); + nl_destroy(nidlist); + } + cfs_free_param_data(&exp_list); + return i; +} + +static int empty_proc_file(char *path) +{ + int empty = 0; + char buf[36]; + int fd; + + fd = open(path, O_RDONLY); + if (fd < 0 || read(fd, buf, sizeof(buf)) <= 0) + empty = 1; + if (fd >= 0) + close(fd); + return empty; +} + +static void read_exports(char *exports, NIDList nidlist) +{ + DIR *dirp; + struct dirent *dp; + char path[PATH_MAX + 1]; + + dirp = opendir(exports); + if (dirp) { + while ((dp = readdir(dirp))) { + if (dp->d_type != DT_DIR) + continue; + if (!strcmp(dp->d_name, ".")) + continue; + if (!strcmp(dp->d_name, "..")) + continue; + if (strchr(dp->d_name, '@') == NULL) + continue; + snprintf(path, sizeof(path), PROC_UUID_TMPL, exports, + dp->d_name); + if (empty_proc_file(path)) + continue; + + nl_add(nidlist, dp->d_name); + } + closedir(dirp); + } +} diff --git a/lustre/utils/nidlist.c b/lustre/utils/nidlist.c new file mode 100644 index 0000000..e9ff697 --- /dev/null +++ b/lustre/utils/nidlist.c @@ -0,0 +1,353 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program 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 version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * + * lustre/utils/nidlist.c + * + * Author: Jim Garlick + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "nidlist.h" + +struct nl_struct { + char **nids; + int len; + int count; +}; +#define NL_CHUNK 64 + +static void nl_oom(void) +{ + fprintf(stderr, "%s: out of memory\n", prog); + exit(1); +} + +NIDList nl_create(void) +{ + struct nl_struct *nl; + + nl = malloc(sizeof(struct nl_struct)); + if (!nl) + nl_oom(); + nl->len = NL_CHUNK; + nl->nids = malloc(nl->len * sizeof(char *)); + if (!nl->nids) + nl_oom(); + nl->count = 0; + + return nl; +} + +void nl_destroy(NIDList nl) +{ + int i; + + for (i = 0; i < nl->count; i++) + free(nl->nids[i]); + free(nl->nids); + free(nl); +} + +static void nl_grow(NIDList nl, int n) +{ + nl->len += n; + nl->nids = realloc(nl->nids, nl->len * sizeof(char *)); + if (!nl->nids) + nl_oom(); +} + +void nl_add(NIDList nl, char *nid) +{ + char *cp; + + cp = strdup(nid); + if (!cp) + nl_oom(); + if (nl->count == nl->len) + nl_grow(nl, NL_CHUNK); + nl->nids[nl->count++] = cp; +} + +int nl_count(NIDList nl) +{ + return nl->count; +} + +static char *nl_nid_addr(char *nid) +{ + char *addr, *p; + + addr = strdup(nid); + if (!addr) + nl_oom(); + p = strchr(addr, '@'); + if (p) + *p = '\0'; + + return addr; +} + +static int nl_nid_parse_addr(char *addr) +{ + int o; + + for (o = strlen(addr); o > 0; o--) + if (!isdigit(addr[o - 1])) + break; + + return o; +} + +static int nl_cmp_addr(char *nid1, char *nid2, int *cflagp) +{ + char *p1 = nl_nid_addr(nid1); + char *p2 = nl_nid_addr(nid2); + int res, o1, o2, cflag = 0; + + o1 = nl_nid_parse_addr(p1); + o2 = nl_nid_parse_addr(p2); + + res = strncmp(p1, p2, o1); + if (o1 == o2 && res == 0) { + res = strtoul(&p1[o1], NULL, 10) - strtoul(&p2[o2], NULL, 10); + if (cflagp && strlen(&p1[o1]) > 0 && strlen(&p2[o2]) > 0) + cflag = 1; + } else + res = strcmp(p1, p2); + free(p1); + free(p2); + if (cflagp) + *cflagp = cflag; + return res; +} + +static int nl_cmp_lnet(char *nid1, char *nid2) +{ + char *s1 = strchr(nid1, '@'); + char *s2 = strchr(nid2, '@'); + + return strcmp(s1 ? s1 + 1 : "", s2 ? s2 + 1 : ""); +} + +static int nl_cmp(const void *p1, const void *p2) +{ + int res; + + res = nl_cmp_lnet(*(char **)p1, *(char **)p2); + if (res == 0) + res = nl_cmp_addr(*(char **)p1, *(char **)p2, NULL); + return res; +} + +void nl_sort(NIDList nl) +{ + qsort(nl->nids, nl->count, sizeof(char *), nl_cmp); +} + +void nl_uniq(NIDList nl) +{ + int i, j; + + for (i = 1; i < nl->count; i++) { + if (!strcmp(nl->nids[i], nl->nids[i - 1])) { + free(nl->nids[i]); + for (j = i; j < nl->count - 1; j++) + nl->nids[j] = nl->nids[j + 1]; + nl->count--; + i--; + } + } +} + +static char *nl_nid_lookup_ipaddr(char *nid) +{ + struct addrinfo *ai, *aip; + char name[NI_MAXHOST] = ""; + char *p, *addr, *lnet = NULL, *res = NULL; + int len, x; + + addr = nl_nid_addr(nid); + if (sscanf(addr, "%d.%d.%d.%d", &x, &x, &x, &x) == 4) { + p = strchr(nid, '@'); + if (p) + lnet = p + 1; + if (getaddrinfo(addr, NULL, NULL, &ai) == 0) { + for (aip = ai; aip != NULL; aip = aip->ai_next) { + if (getnameinfo(aip->ai_addr, aip->ai_addrlen, + name, sizeof(name), NULL, 0, + NI_NAMEREQD | NI_NOFQDN) == 0) { + p = strchr(name, '.'); + if (p) + *p = '\0'; + len = strlen(name) + 2; + if (lnet != NULL) + len += strlen(lnet); + res = malloc(len); + if (!res) + nl_oom(); + if (lnet != NULL) + snprintf(res, len, "%s@%s", + name, lnet); + else + snprintf(res, len, "%s", name); + break; + } + } + freeaddrinfo(ai); + } + } + free(addr); + + return res; +} + +void nl_lookup_ip(NIDList nl) +{ + int i; + char *new; + + for (i = 0; i < nl->count; i++) { + new = nl_nid_lookup_ipaddr(nl->nids[i]); + if (new) { + free(nl->nids[i]); + nl->nids[i] = new; + } + } +} + +char *nl_string(NIDList nl, char *sep) +{ + int seplen = strlen(sep); + int i, len = 1; + char *s; + + for (i = 0; i < nl->count; i++) + len += strlen(nl->nids[i]) + seplen; + s = malloc(len); + if (!s) + nl_oom(); + s[0] = '\0'; + for (i = 0; i < nl->count; i++) { + if (i > 0) + strncat(s, sep, len); + strncat(s, nl->nids[i], len); + } + return s; +} + +static void nl_strxcat(char *s, char **nids, int len, const int max_len) +{ + int i, o, lastn = 0; + char *base, *p, *lnet = NULL, *savedn = NULL; + + p = strchr(nids[0], '@'); + if (p) + lnet = p + 1; + base = nl_nid_addr(nids[0]); + o = nl_nid_parse_addr(base); + base[o] = '\0'; + for (i = 0; i < len; i++) { + char *addr = nl_nid_addr(nids[i]); + int n = strtoul(&addr[o], NULL, 10); + + if (i == 0) + snprintf(s + strlen(s), max_len, "%s[%s", base, + &addr[o]); + else if (i < len) { + if (n == lastn + 1) { + if (savedn) + free(savedn); + savedn = strdup(&addr[o]); + if (!savedn) + nl_oom(); + } else { + if (savedn) { + snprintf(s + strlen(s), + max_len - strlen(s), + "-%s", savedn); + free(savedn); + savedn = NULL; + } + snprintf(s + strlen(s), max_len - strlen(s), + ",%s", &addr[o]); + } + } + if (i == len - 1) { + if (savedn) { + snprintf(s + strlen(s), max_len - strlen(s), + "-%s", savedn); + free(savedn); + } + strncat(s, "]", 1); + if (lnet) + snprintf(s + strlen(s), max_len - strlen(s), + "@%s", lnet); + } + free(addr); + lastn = n; + } + free(base); +} + +char *nl_xstring(NIDList nl, char *sep) +{ + int seplen = strlen(sep); + int cflag, i, j, len = 1; + char *s; + + for (i = 0; i < nl->count; i++) + len += strlen(nl->nids[i]) + seplen; + s = malloc(len); + if (!s) + nl_oom(); + s[0] = '\0'; + for (i = 0; i < nl->count; i++) { + if (i > 0) + strncat(s, sep, len); + for (j = i + 1; j < nl->count; j++) { + if (nl_cmp_lnet(nl->nids[i], nl->nids[j]) != 0) + break; + (void)nl_cmp_addr(nl->nids[i], nl->nids[j], &cflag); + if (!cflag) + break; + } + if (j - i > 1) + nl_strxcat(s, &nl->nids[i], j - i, len); + else + strncat(s, nl->nids[i], len); + i += j - i - 1; + } + return s; +} diff --git a/lustre/utils/nidlist.h b/lustre/utils/nidlist.h new file mode 100644 index 0000000..4663a28 --- /dev/null +++ b/lustre/utils/nidlist.h @@ -0,0 +1,51 @@ +/* + * GPL HEADER START + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 only, + * as published by the Free Software Foundation. + * + * This program 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 version 2 for more details (a copy is included + * in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU General Public License + * version 2 along with this program; If not, see + * http://www.gnu.org/licenses/gpl-2.0.html + * + * GPL HEADER END + */ +/* + * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. + * Use is subject to license terms. + */ +/* + * This file is part of Lustre, http://www.lustre.org/ + * + * lustre/utils/nidlist.h + * + * Author: Jim Garlick + */ + +#ifndef NIDLIST_H +#define NIDLIST_H + +extern char *prog; + +typedef struct nl_struct *NIDList; + +NIDList nl_create(void); +void nl_destroy(NIDList nl); +void nl_add(NIDList nl, char *nid); +int nl_count(NIDList nl); +void nl_lookup_ip(NIDList nl); +void nl_sort(NIDList nl); +void nl_uniq(NIDList nl); +char *nl_string(NIDList nl, char *sep); +char *nl_xstring(NIDList nl, char *sep); + +#endif -- 1.8.3.1