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)
--- /dev/null
+.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/<server>/exports/<uuid>/nid
+.br
+/proc/fs/lustre/mds/<server>/exports/<uuid>/nid
+.br
+/proc/fs/lustre/obdfilter/<server>/exports/<uuid>/nid
+.SH AUTHOR
+Herb Wartens
.BR llobdstat (8),
.BR ll_decode_filter_fid (8),
.BR llog_reader (8),
+.BR lshowmount (8),
.BR lustre_rsync (8)
}
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
/tunefs_lustre
/lreplicate
/ltrack_stats
+/lshowmount
/lustre_rsync
/ll_decode_filter_fid
/lhsmd_posix
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
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
--- /dev/null
+/*
+ * 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 <wartens2@llnl.gov>
+ * Author: Jim Garlick <garlick@llnl.gov>
+ */
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <dirent.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <libgen.h>
+
+#include <lustre/lustre_user.h>
+#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);
+ }
+}
--- /dev/null
+/*
+ * 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 <garlick@llnl.gov>
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#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;
+}
--- /dev/null
+/*
+ * 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 <garlick@llnl.gov>
+ */
+
+#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