1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2 * vim:expandtab:shiftwidth=8:tabstop=8:
4 * Copyright (C) 2002 Cluster File Systems, Inc.
5 * Author: Robert Read <rread@clusterfs.com>
7 * This file is part of Lustre, http://www.lustre.org.
9 * Lustre is free software; you can redistribute it and/or
10 * modify it under the terms of version 2 of the GNU General Public
11 * License as published by the Free Software Foundation.
13 * Lustre is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with Lustre; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #include <sys/mount.h>
36 #include <portals/ptlctl.h>
42 static char *progname = NULL;
50 #define MAX_ROUTES 1024
52 ptl_nid_t lmd_cluster_id = 0;
53 llmount_route_t routes[MAX_ROUTES];
57 fprintf(out, "usage: %s <mdsnode>:/<mdsname>/<cfgname> <mountpt> "
58 "[-fhnv] [-o mntopt]\n", progname);
59 fprintf(out, "\t<mdsnode>: hostname or nid of MDS (config) node\n"
60 "\t<mdsname>: name of MDS service (e.g. mds1)\n"
61 "\t<cfgname>: name of client config (e.g. client)\n"
62 "\t<mountpt>: filesystem mountpoint (e.g. /mnt/lustre)\n"
63 "\t-f|--fake: fake mount (updates /etc/mtab)\n"
64 "\t--force: force mount even if already in /etc/mtab\n"
65 "\t-h|--help: print this usage message\n"
66 "\t-n|--nomtab: do not update /etc/mtab after mount\n"
67 "\t-v|--verbose: print verbose config settings\n"
68 "\t-o: filesystem mount options:\n"
69 "\t\tnettype={tcp,elan,iibnal,lonal}: network type\n"
70 "\t\tcluster_id=0xNNNN: cluster this node is part of\n"
71 "\t\tlocal_nid=0xNNNN: client ID (default ipaddr or nodenum)\n"
72 "\t\tserver_nid=0xNNNN: server node ID (default mdsnode)\n"
73 "\t\tport=NNN: server port (default 988 for tcp)\n"
74 "\t\troute=<gw>[-<gw>]:<low>[-<high>]: portal route to MDS\n");
78 static int check_mtab_entry(char *spec, char *mtpt, char *type)
84 fp = setmntent(MOUNTED, "r");
88 while ((mnt = getmntent(fp)) != NULL) {
89 if (strcmp(mnt->mnt_fsname, spec) == 0 &&
90 strcmp(mnt->mnt_dir, mtpt) == 0 &&
91 strcmp(mnt->mnt_type, type) == 0) {
92 fprintf(stderr, "%s: according to %s %s is "
93 "already mounted on %s\n",
94 progname, MOUNTED, spec, mtpt);
95 return(1); /* or should we return an error? */
104 update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
105 int flags, int freq, int pass)
111 mnt.mnt_fsname = spec;
114 mnt.mnt_opts = opts ? opts : "";
116 mnt.mnt_passno = pass;
118 fp = setmntent(MOUNTED, "a+");
120 fprintf(stderr, "%s: setmntent(%s): %s:",
121 progname, MOUNTED, strerror (errno));
124 if ((addmntent(fp, &mnt)) == 1) {
125 fprintf(stderr, "%s: addmntent: %s:",
126 progname, strerror (errno));
136 init_options(struct lustre_mount_data *lmd)
138 memset(lmd, 0, sizeof(*lmd));
139 lmd->lmd_magic = LMD_MAGIC;
140 lmd->lmd_server_nid = PTL_NID_ANY;
141 lmd->lmd_local_nid = PTL_NID_ANY;
142 lmd->lmd_port = 988; /* XXX define LUSTRE_DEFAULT_PORT */
143 lmd->lmd_nal = SOCKNAL;
148 print_options(struct lustre_mount_data *lmd)
152 printf("mds: %s\n", lmd->lmd_mds);
153 printf("profile: %s\n", lmd->lmd_profile);
154 printf("server_nid: "LPX64"\n", lmd->lmd_server_nid);
155 printf("local_nid: "LPX64"\n", lmd->lmd_local_nid);
156 printf("nal: %x\n", lmd->lmd_nal);
157 printf("server_ipaddr: 0x%x\n", lmd->lmd_server_ipaddr);
158 printf("port: %d\n", lmd->lmd_port);
160 for (i = 0; i < route_index; i++)
161 printf("route: "LPX64" : "LPX64" - "LPX64"\n",
162 routes[i].gw, routes[i].lo, routes[i].hi);
167 static int parse_route(char *opteq, char *opttgts)
169 char *gw_lo_ptr, *gw_hi_ptr, *tgt_lo_ptr, *tgt_hi_ptr;
170 ptl_nid_t gw_lo, gw_hi, tgt_lo, tgt_hi;
173 gw_lo_ptr = opteq + 1;
174 if (!(gw_hi_ptr = strchr(gw_lo_ptr, '-'))) {
175 gw_hi_ptr = gw_lo_ptr;
181 if (ptl_parse_nid(&gw_lo, gw_lo_ptr) != 0) {
182 fprintf(stderr, "%s: can't parse NID %s\n", progname,gw_lo_ptr);
186 if (ptl_parse_nid(&gw_hi, gw_hi_ptr) != 0) {
187 fprintf(stderr, "%s: can't parse NID %s\n", progname,gw_hi_ptr);
191 tgt_lo_ptr = opttgts + 1;
192 if (!(tgt_hi_ptr = strchr(tgt_lo_ptr, '-'))) {
193 tgt_hi_ptr = tgt_lo_ptr;
195 tgt_hi_ptr[0] = '\0';
199 if (ptl_parse_nid(&tgt_lo, tgt_lo_ptr) != 0) {
200 fprintf(stderr, "%s: can't parse NID %s\n",progname,tgt_lo_ptr);
204 if (ptl_parse_nid(&tgt_hi, tgt_hi_ptr) != 0) {
205 fprintf(stderr, "%s: can't parse NID %s\n",progname,tgt_hi_ptr);
209 while (gw_lo <= gw_hi) {
210 if (route_index >= MAX_ROUTES) {
211 fprintf(stderr, "%s: to many routes %d\n",
212 progname, MAX_ROUTES);
216 routes[route_index].gw = gw_lo;
217 routes[route_index].lo = tgt_lo;
218 routes[route_index].hi = tgt_hi;
226 /*****************************************************************************
228 * This part was cribbed from util-linux/mount/mount.c. There was no clear
229 * license information, but many other files in the package are identified as
230 * GNU GPL, so it's a pretty safe bet that was their intent.
232 ****************************************************************************/
234 const char *opt; /* option name */
235 int skip; /* skip in mtab option string */
236 int inv; /* true if flag value should be inverted */
237 int mask; /* flag mask value */
240 static const struct opt_map opt_map[] = {
241 { "defaults", 0, 0, 0 }, /* default options */
242 { "rw", 1, 1, MS_RDONLY }, /* read-write */
243 { "exec", 0, 1, MS_NOEXEC }, /* permit execution of binaries */
244 { "noexec", 0, 0, MS_NOEXEC }, /* don't execute binaries */
245 { "suid", 0, 1, MS_NOSUID }, /* honor suid executables */
246 { "nosuid", 0, 0, MS_NOSUID }, /* don't honor suid executables */
247 { "dev", 0, 1, MS_NODEV }, /* interpret device files */
248 { "nodev", 0, 0, MS_NODEV }, /* don't interpret devices */
249 { "async", 0, 1, MS_SYNCHRONOUS}, /* asynchronous I/O */
250 { "auto", 0, 0, 0 }, /* Can be mounted using -a */
251 { "noauto", 0, 0, 0 }, /* Can only be mounted explicitly */
252 { "nousers", 0, 1, 0 }, /* Forbid ordinary user to mount */
253 { "nouser", 0, 1, 0 }, /* Forbid ordinary user to mount */
254 { "noowner", 0, 1, 0 }, /* Device owner has no special privs */
255 { "_netdev", 0, 0, 0 }, /* Device accessible only via network */
258 /****************************************************************************/
260 static int parse_one_option(const char *check, int *flagp)
262 const struct opt_map *opt;
264 for (opt = &opt_map[0]; opt->opt != NULL; opt++) {
265 if (strcmp(check, opt->opt) == 0) {
267 *flagp &= ~(opt->mask);
276 int parse_options(char *options, struct lustre_mount_data *lmd, int *flagp)
278 ptl_nid_t nid = 0, cluster_id = 0;
280 char *opt, *opteq, *opttgts;
283 /* parsing ideas here taken from util-linux/mount/nfsmount.c */
284 for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
285 if ((opteq = strchr(opt, '='))) {
286 val = atoi(opteq + 1);
288 if (!strcmp(opt, "nettype")) {
289 lmd->lmd_nal = ptl_name2nal(opteq + 1);
290 if (lmd->lmd_nal < 0) {
291 fprintf(stderr, "%s: can't parse NET "
292 "%s\n", progname, opteq + 1);
295 } else if(!strcmp(opt, "cluster_id")) {
296 if (ptl_parse_nid(&cluster_id, opteq+1) != 0) {
297 fprintf(stderr, "%s: can't parse NID "
298 "%s\n", progname, opteq+1);
301 lmd_cluster_id = cluster_id;
302 } else if(!strcmp(opt, "route")) {
303 if (!(opttgts = strchr(opteq + 1, ':'))) {
304 fprintf(stderr, "%s: Route must be "
305 "of the form: route="
306 "<gw>[-<gw>]:<low>[-<high>]\n",
310 parse_route(opteq, opttgts);
311 } else if (!strcmp(opt, "local_nid")) {
312 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
313 fprintf(stderr, "%s: "
314 "can't parse NID %s\n",
319 lmd->lmd_local_nid = nid;
320 } else if (!strcmp(opt, "server_nid")) {
321 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
322 fprintf(stderr, "%s: "
323 "can't parse NID %s\n",
324 progname, opteq + 1);
327 lmd->lmd_server_nid = nid;
328 } else if (!strcmp(opt, "port")) {
331 fprintf(stderr, "%s: unknown option '%s'\n",
336 if (parse_one_option(opt, flagp))
339 fprintf(stderr, "%s: unknown option '%s'\n",
348 get_local_elan_id(char *fname, char *buf)
350 FILE *fp = fopen(fname, "r");
356 rc = fscanf(fp, "NodeId %255s", buf);
360 return (rc == 1) ? 0 : -1;
364 set_local(struct lustre_mount_data *lmd)
367 * XXX PtlGetId() will be safer if portals is loaded and
368 * initialised correctly at this time... */
369 char buf[256], *ptr = buf;
373 if (lmd->lmd_local_nid != PTL_NID_ANY)
376 memset(buf, 0, sizeof(buf));
378 switch (lmd->lmd_nal) {
380 fprintf(stderr, "%s: Unknown network type: %d\n",
381 progname, lmd->lmd_nal);
390 rc = gethostname(buf, sizeof(buf) - 1);
392 fprintf (stderr, "%s: can't get local buf: %d\n",
398 char *pfiles[] = {"/proc/qsnet/elan3/device0/position",
399 "/proc/qsnet/elan4/device0/position",
400 "/proc/elan/device0/position",
405 rc = get_local_elan_id(pfiles[i], buf);
406 } while (rc != 0 && pfiles[++i] != NULL);
409 rc = gethostname(buf, sizeof(buf) - 1);
412 while ((*tmp >= 'a' && *tmp <= 'z') ||
413 (*tmp >= 'A' && *tmp <= 'Z'))
415 ptr = strsep(&tmp, ".");
418 "%s: can't read Elan ID from /proc\n",
427 if (ptl_parse_nid (&nid, ptr) != 0) {
428 fprintf (stderr, "%s: can't parse NID %s\n", progname, buf);
432 lmd->lmd_local_nid = nid + lmd_cluster_id;
437 set_peer(char *hostname, struct lustre_mount_data *lmd)
442 switch (lmd->lmd_nal) {
444 fprintf(stderr, "%s: Unknown network type: %d\n",
445 progname, lmd->lmd_nal);
450 if (lmd->lmd_server_nid != PTL_NID_ANY)
452 if (ptl_parse_nid (&nid, hostname) != 0) {
453 fprintf (stderr, "%s: can't parse NID %s\n",
457 lmd->lmd_server_nid = nid;
464 if (lmd->lmd_server_nid == PTL_NID_ANY) {
465 if (ptl_parse_nid (&nid, hostname) != 0) {
466 fprintf (stderr, "%s: can't parse NID %s\n",
470 lmd->lmd_server_nid = nid;
473 if (ptl_parse_ipaddr(&lmd->lmd_server_ipaddr, hostname) != 0) {
474 fprintf (stderr, "%s: can't parse host %s\n",
482 if (lmd->lmd_server_nid != PTL_NID_ANY)
485 rc = sscanf(hostname, "%*[^0-9]%63[0-9]", buf);
487 fprintf (stderr, "%s: can't get elan id from host %s\n",
491 if (ptl_parse_nid (&nid, buf) != 0) {
492 fprintf (stderr, "%s: can't parse NID %s\n",
496 lmd->lmd_server_nid = nid;
506 build_data(char *source, char *options, struct lustre_mount_data *lmd,
510 char *hostname = NULL, *mds = NULL, *profile = NULL, *s;
513 if (lmd_bad_magic(lmd))
516 if (strlen(source) >= sizeof(buf)) {
517 fprintf(stderr, "%s: host:/mds/profile argument too long\n",
522 if ((s = strchr(buf, ':'))) {
529 if ((s = strchr(mds, '/'))) {
533 fprintf(stderr, "%s: directory to mount not in "
534 "host:/mds/profile format\n",
539 fprintf(stderr, "%s: "
540 "directory to mount not in host:/mds/profile format\n",
545 rc = parse_options(options, lmd, flagp);
553 rc = set_peer(hostname, lmd);
556 if (strlen(mds) > sizeof(lmd->lmd_mds) + 1) {
557 fprintf(stderr, "%s: mds name too long\n", progname);
560 strcpy(lmd->lmd_mds, mds);
562 if (strlen(profile) > sizeof(lmd->lmd_profile) + 1) {
563 fprintf(stderr, "%s: profile name too long\n", progname);
566 strcpy(lmd->lmd_profile, profile);
573 static int set_routes(struct lustre_mount_data *lmd) {
574 struct portals_cfg pcfg;
575 struct portal_ioctl_data data;
576 int i, j, route_exists, rc, err = 0;
578 register_ioc_dev(PORTALS_DEV_ID, PORTALS_DEV_PATH);
580 for (i = 0; i < route_index; i++) {
582 /* Check for existing routes so as not to add duplicates */
584 PCFG_INIT(pcfg, NAL_CMD_GET_ROUTE);
585 pcfg.pcfg_nal = ROUTER;
588 PORTAL_IOC_INIT(data);
589 data.ioc_pbuf1 = (char*)&pcfg;
590 data.ioc_plen1 = sizeof(pcfg);
591 data.ioc_nid = pcfg.pcfg_nid;
593 rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
599 if ((pcfg.pcfg_gw_nal == lmd->lmd_nal) &&
600 (pcfg.pcfg_nid == routes[i].gw) &&
601 (pcfg.pcfg_nid2 == routes[i].lo) &&
602 (pcfg.pcfg_nid3 == routes[i].hi)) {
611 PCFG_INIT(pcfg, NAL_CMD_ADD_ROUTE);
612 pcfg.pcfg_nid = routes[i].gw;
613 pcfg.pcfg_nal = ROUTER;
614 pcfg.pcfg_gw_nal = lmd->lmd_nal;
615 pcfg.pcfg_nid2 = MIN(routes[i].lo, routes[i].hi);
616 pcfg.pcfg_nid3 = MAX(routes[i].lo, routes[i].hi);
618 PORTAL_IOC_INIT(data);
619 data.ioc_pbuf1 = (char*)&pcfg;
620 data.ioc_plen1 = sizeof(pcfg);
621 data.ioc_nid = pcfg.pcfg_nid;
623 rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
625 fprintf(stderr, "%s: Unable to add route "
626 LPX64" : "LPX64" - "LPX64"\n[%d] %s\n",
627 progname, routes[i].gw, routes[i].lo,
628 routes[i].hi, errno, strerror(errno));
634 unregister_ioc_dev(PORTALS_DEV_ID);
638 int main(int argc, char *const argv[])
640 char *source, *target, *options = "";
641 int i, nargs = 3, opt, rc, flags;
642 struct lustre_mount_data lmd;
643 static struct option long_opt[] = {
647 {"nomtab", 0, 0, 'n'},
648 {"options", 1, 0, 'o'},
649 {"verbose", 0, 0, 'v'},
653 progname = strrchr(argv[0], '/');
654 progname = progname ? progname + 1 : argv[0];
656 while ((opt = getopt_long(argc, argv, "fhno:v", long_opt,NULL)) != EOF){
660 printf("force: %d\n", force);
665 printf("fake: %d\n", fake);
673 printf("nomtab: %d\n", nomtab);
682 printf("verbose: %d\n", verbose);
686 fprintf(stderr, "%s: unknown option '%c'\n",
693 if (optind + 2 > argc) {
694 fprintf(stderr, "%s: too few arguments\n", progname);
698 source = argv[optind];
699 target = argv[optind + 1];
702 for (i = 0; i < argc; i++)
703 printf("arg[%d] = %s\n", i, argv[i]);
704 printf("source = %s, target = %s\n", source, target);
707 if (!force && check_mtab_entry(source, target, "lustre"))
711 rc = build_data(source, options, &lmd, &flags);
717 rc = set_routes(&lmd);
722 rc = access(target, F_OK);
725 fprintf(stderr, "%s: %s inaccessible: %s\n", progname, target,
731 rc = mount(source, target, "lustre", flags, (void *)&lmd);
733 fprintf(stderr, "%s: mount(%s, %s) failed: %s\n", source,
734 target, progname, strerror(errno));
736 fprintf(stderr, "Are the lustre modules loaded?\n"
737 "Check /etc/modules.conf and /proc/filesystems\n");
739 } else if (!nomtab) {
740 rc = update_mtab_entry(source, target, "lustre", options,0,0,0);