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>
35 #include <sys/utsname.h>
40 #include <portals/ptlctl.h>
41 #include <linux/lustre_idl.h>
47 static char *progname = NULL;
55 #define MAX_ROUTES 1024
57 ptl_nid_t lmd_cluster_id = 0;
58 llmount_route_t routes[MAX_ROUTES];
60 static int check_mtab_entry(char *spec, char *mtpt, char *type)
66 fp = setmntent(MOUNTED, "r");
70 while ((mnt = getmntent(fp)) != NULL) {
71 if (strcmp(mnt->mnt_fsname, spec) == 0 &&
72 strcmp(mnt->mnt_dir, mtpt) == 0 &&
73 strcmp(mnt->mnt_type, type) == 0) {
74 fprintf(stderr, "%s: according to %s %s is "
75 "already mounted on %s\n",
76 progname, MOUNTED, spec, mtpt);
77 return(1); /* or should we return an error? */
86 update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
87 int flags, int freq, int pass)
92 mnt.mnt_fsname = spec;
95 mnt.mnt_opts = opts ? opts : "";
97 mnt.mnt_passno = pass;
100 fp = setmntent(MOUNTED, "a+");
102 fprintf(stderr, "%s: setmntent(%s): %s:",
103 progname, MOUNTED, strerror (errno));
105 if ((addmntent (fp, &mnt)) == 1) {
106 fprintf(stderr, "%s: addmntent: %s:",
107 progname, strerror (errno));
115 init_options(struct lustre_mount_data *lmd)
117 memset(lmd, 0, sizeof(*lmd));
118 lmd->lmd_magic = LMD_MAGIC;
119 lmd->lmd_server_nid = PTL_NID_ANY;
120 lmd->lmd_local_nid = PTL_NID_ANY;
121 lmd->lmd_port = 988; /* XXX define LUSTRE_DEFAULT_PORT */
122 lmd->lmd_nal = SOCKNAL;
124 lmd->lmd_remote_flag = 0;
125 lmd->lmd_nllu = NOBODY_UID;
126 lmd->lmd_nllg = NOBODY_GID;
128 strncpy(lmd->lmd_mds_security, "null", sizeof(lmd->lmd_mds_security));
129 strncpy(lmd->lmd_oss_security, "null", sizeof(lmd->lmd_oss_security));
134 print_options(struct lustre_mount_data *lmd)
138 printf("mds: %s\n", lmd->lmd_mds);
139 printf("profile: %s\n", lmd->lmd_profile);
140 printf("mds_sec_flavor: %s\n", lmd->lmd_mds_security);
141 printf("oss_sec_flavor: %s\n", lmd->lmd_oss_security);
142 printf("server_nid: "LPX64"\n", lmd->lmd_server_nid);
144 if (lmd->lmd_nal != CRAY_KB_SSNAL) {
146 printf("local_nid: "LPX64"\n", lmd->lmd_local_nid);
150 printf("nal: %x\n", lmd->lmd_nal);
152 if (lmd->lmd_nal != CRAY_KB_SSNAL) {
154 printf("server_ipaddr: 0x%x\n", lmd->lmd_server_ipaddr);
155 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;
227 * here all what we do is gurantee the result is exactly
228 * what user intend to get, no ambiguous. maybe there have
229 * simpler library call could do the same job for us?
231 static int parse_u32(char *str, uint32_t *res)
236 id = strtol(str, &endptr, 0);
237 if (endptr && *endptr != 0)
240 if (id == LONG_MAX || id == LONG_MIN)
243 if ((uint32_t)id != id)
246 *res = (uint32_t) id;
250 static int parse_nllu(struct lustre_mount_data *lmd, char *str_nllu)
254 if (parse_u32(str_nllu, &lmd->lmd_nllu) == 0)
257 pass = getpwnam(str_nllu);
261 lmd->lmd_nllu = pass->pw_uid;
265 static int parse_nllg(struct lustre_mount_data *lmd, char *str_nllg)
269 if (parse_u32(str_nllg, &lmd->lmd_nllg) == 0)
272 grp = getgrnam(str_nllg);
276 lmd->lmd_nllg = grp->gr_gid;
280 int parse_options(char * options, struct lustre_mount_data *lmd)
282 ptl_nid_t nid = 0, cluster_id = 0;
284 char *opt, *opteq, *opttgts;
286 /* parsing ideas here taken from util-linux/mount/nfsmount.c */
287 for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
288 if ((opteq = strchr(opt, '='))) {
289 val = atoi(opteq + 1);
291 if (!strcmp(opt, "nettype")) {
292 lmd->lmd_nal = ptl_name2nal(opteq + 1);
293 if (lmd->lmd_nal < 0) {
294 fprintf(stderr, "%s: can't parse NET "
295 "%s\n", progname, opteq + 1);
298 } else if(!strcmp(opt, "cluster_id")) {
299 if (ptl_parse_nid(&cluster_id, opteq+1) != 0) {
300 fprintf (stderr, "%s: can't parse NID "
301 "%s\n", progname, opteq+1);
304 lmd_cluster_id = cluster_id;
305 } else if(!strcmp(opt, "route")) {
306 if (!(opttgts = strchr(opteq + 1, ':'))) {
307 fprintf(stderr, "%s: Route must be "
308 "of the form: route="
309 "<gw>[-<gw>]:<low>[-<high>]\n",
313 parse_route(opteq, opttgts);
314 } else if (!strcmp(opt, "local_nid")) {
315 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
316 fprintf (stderr, "%s: "
317 "can't parse NID %s\n",
322 lmd->lmd_local_nid = nid;
323 } else if (!strcmp(opt, "server_nid")) {
324 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
325 fprintf (stderr, "%s: "
326 "can't parse NID %s\n",
327 progname, opteq + 1);
330 lmd->lmd_server_nid = nid;
331 } else if (!strcmp(opt, "port")) {
333 } else if (!strcmp(opt, "mds_sec")) {
334 strncpy(lmd->lmd_mds_security, opteq + 1,
335 sizeof(lmd->lmd_mds_security));
336 } else if (!strcmp(opt, "oss_sec")) {
337 strncpy(lmd->lmd_oss_security, opteq + 1,
338 sizeof(lmd->lmd_oss_security));
339 } else if (!strcmp(opt, "nllu")) {
340 if (parse_nllu(lmd, opteq + 1)) {
341 fprintf(stderr, "%s: "
342 "can't parse user: %s\n",
343 progname, opteq + 1);
346 } else if (!strcmp(opt, "nllg")) {
347 if (parse_nllg(lmd, opteq + 1)) {
348 fprintf(stderr, "%s: "
349 "can't parse group: %s\n",
350 progname, opteq + 1);
355 if (!strcmp(opt, "remote")) {
356 lmd->lmd_remote_flag = OBD_CONNECT_REMOTE;
357 } else if (!strcmp(opt, "local")) {
358 lmd->lmd_remote_flag = OBD_CONNECT_LOCAL;
359 } else if (!strcmp(opt, "async")) {
361 } else if (!strcmp(opt, "pag")) {
365 if (!strncmp(opt, "no", 2)) {
369 if (!strcmp(opt, "debug")) {
379 get_local_elan_id(char *fname, char *buf)
381 FILE *fp = fopen(fname, "r");
387 rc = fscanf(fp, "NodeId %255s", buf);
391 return (rc == 1) ? 0 : -1;
395 set_local(struct lustre_mount_data *lmd)
398 * XXX PtlGetId() will be safer if portals is loaded and
399 * initialised correctly at this time... */
404 if (lmd->lmd_local_nid != PTL_NID_ANY)
407 memset(buf, 0, sizeof(buf));
409 switch (lmd->lmd_nal) {
411 fprintf(stderr, "%s: Unknown network type: %d\n",
412 progname, lmd->lmd_nal);
431 rc = gethostname(buf, sizeof(buf) - 1);
433 fprintf(stderr, "%s: can't get hostname: %s\n",
434 progname, strerror(rc));
439 /* for 2.6 kernels, reserve at least 8MB free, or we will
440 * go OOM during heavy read load */
441 if (rc == 0 && strncmp(uts.release, "2.6", 3) == 0) {
442 int f, minfree = 32768;
443 char name[40], val[40];
446 meminfo = fopen("/proc/meminfo", "r");
447 if (meminfo != NULL) {
448 while (fscanf(meminfo, "%s %s %*s\n", name, val) != EOF) {
449 if (strcmp(name, "MemTotal:") == 0) {
450 f = strtol(val, NULL, 0);
451 if (f > 0 && f < 8 * minfree)
458 f = open("/proc/sys/vm/min_free_kbytes", O_WRONLY);
460 sprintf(val, "%d", minfree);
461 write(f, val, strlen(val));
470 char *pfiles[] = {"/proc/qsnet/elan3/device0/position",
471 "/proc/qsnet/elan4/device0/position",
472 "/proc/elan/device0/position",
477 rc = get_local_elan_id(pfiles[i], buf);
478 } while (rc != 0 && pfiles[++i] != NULL);
481 fprintf(stderr, "%s: can't read Elan ID from /proc\n",
491 if (ptl_parse_nid (&nid, buf) != 0) {
492 fprintf (stderr, "%s: can't parse NID %s\n", progname, buf);
496 lmd->lmd_local_nid = nid + lmd_cluster_id;
501 set_peer(char *hostname, struct lustre_mount_data *lmd)
506 switch (lmd->lmd_nal) {
508 fprintf(stderr, "%s: Unknown network type: %d\n",
509 progname, lmd->lmd_nal);
514 lmd->lmd_server_nid = strtoll(hostname,0,0);
520 if (lmd->lmd_server_nid != PTL_NID_ANY)
522 if (ptl_parse_nid (&nid, hostname) != 0) {
523 fprintf (stderr, "%s: can't parse NID %s\n",
527 lmd->lmd_server_nid = nid;
536 if (lmd->lmd_server_nid == PTL_NID_ANY) {
537 if (ptl_parse_nid (&nid, hostname) != 0) {
538 fprintf (stderr, "%s: can't parse NID %s\n",
542 lmd->lmd_server_nid = nid;
545 if (ptl_parse_ipaddr(&lmd->lmd_server_ipaddr, hostname) != 0) {
546 fprintf (stderr, "%s: can't parse host %s\n",
556 if (lmd->lmd_server_nid != PTL_NID_ANY)
559 rc = sscanf(hostname, "%*[^0-9]%63[0-9]", buf);
561 fprintf (stderr, "%s: can't get elan id from host %s\n",
565 if (ptl_parse_nid (&nid, buf) != 0) {
566 fprintf (stderr, "%s: can't parse NID %s\n",
570 lmd->lmd_server_nid = nid;
580 build_data(char *source, char *options, struct lustre_mount_data *lmd)
583 char *hostname = NULL, *mds = NULL, *profile = NULL, *s;
586 if (lmd_bad_magic(lmd))
589 if (strlen(source) > sizeof(buf) + 1) {
590 fprintf(stderr, "%s: host:/mds/profile argument too long\n",
595 if ((s = strchr(buf, ':'))) {
602 if ((s = strchr(mds, '/'))) {
606 fprintf(stderr, "%s: directory to mount not in "
607 "host:/mds/profile format\n",
612 fprintf(stderr, "%s: "
613 "directory to mount not in host:/mds/profile format\n",
618 rc = parse_options(options, lmd);
626 rc = set_peer(hostname, lmd);
629 if (strlen(mds) > sizeof(lmd->lmd_mds) + 1) {
630 fprintf(stderr, "%s: mds name too long\n", progname);
633 strcpy(lmd->lmd_mds, mds);
635 if (strlen(profile) > sizeof(lmd->lmd_profile) + 1) {
636 fprintf(stderr, "%s: profile name too long\n", progname);
639 strcpy(lmd->lmd_profile, profile);
646 static int set_routes(struct lustre_mount_data *lmd) {
647 struct portals_cfg pcfg;
648 struct portal_ioctl_data data;
649 int i, j, route_exists, rc, err = 0;
651 register_ioc_dev(PORTALS_DEV_ID, PORTALS_DEV_PATH);
653 for (i = 0; i < route_index; i++) {
655 /* Check for existing routes so as not to add duplicates */
657 PCFG_INIT(pcfg, NAL_CMD_GET_ROUTE);
658 pcfg.pcfg_nal = ROUTER;
661 PORTAL_IOC_INIT(data);
662 data.ioc_pbuf1 = (char*)&pcfg;
663 data.ioc_plen1 = sizeof(pcfg);
664 data.ioc_nid = pcfg.pcfg_nid;
666 rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
672 if ((pcfg.pcfg_gw_nal == lmd->lmd_nal) &&
673 (pcfg.pcfg_nid == routes[i].gw) &&
674 (pcfg.pcfg_nid2 == routes[i].lo) &&
675 (pcfg.pcfg_nid3 == routes[i].hi)) {
684 PCFG_INIT(pcfg, NAL_CMD_ADD_ROUTE);
685 pcfg.pcfg_nid = routes[i].gw;
686 pcfg.pcfg_nal = ROUTER;
687 pcfg.pcfg_gw_nal = lmd->lmd_nal;
688 pcfg.pcfg_nid2 = MIN(routes[i].lo, routes[i].hi);
689 pcfg.pcfg_nid3 = MAX(routes[i].lo, routes[i].hi);
691 PORTAL_IOC_INIT(data);
692 data.ioc_pbuf1 = (char*)&pcfg;
693 data.ioc_plen1 = sizeof(pcfg);
694 data.ioc_nid = pcfg.pcfg_nid;
696 rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
698 fprintf(stderr, "%s: Unable to add route "
699 LPX64" : "LPX64" - "LPX64"\n[%d] %s\n",
700 progname, routes[i].gw, routes[i].lo,
701 routes[i].hi, errno, strerror(errno));
707 unregister_ioc_dev(PORTALS_DEV_ID);
711 void usage(FILE *out)
713 fprintf(out, "usage: %s <source> <target> [-f] [-v] [-n] [-o mntopt]\n",
718 int main(int argc, char *const argv[])
720 char *source, *target, *options = "";
721 int i, nargs = 3, opt, rc;
722 struct lustre_mount_data lmd;
723 static struct option long_opt[] = {
724 {"force", 0, 0, 'f'},
726 {"nomtab", 0, 0, 'n'},
727 {"options", 1, 0, 'o'},
728 {"verbose", 0, 0, 'v'},
732 progname = strrchr(argv[0], '/');
733 progname = progname ? progname + 1 : argv[0];
735 while ((opt = getopt_long(argc, argv, "fno:v", long_opt, NULL)) != EOF){
739 printf("force: %d\n", force);
747 printf("nomtab: %d\n", nomtab);
756 printf("verbose: %d\n", verbose);
760 fprintf(stderr, "%s: unknown option '%c'\n",
767 if (optind + 2 > argc) {
768 fprintf(stderr, "%s: too few arguments\n", progname);
772 source = argv[optind];
773 target = argv[optind + 1];
776 for (i = 0; i < argc; i++)
777 printf("arg[%d] = %s\n", i, argv[i]);
778 printf("source = %s, target = %s\n", source, target);
781 if (check_mtab_entry(source, target, "lustre"))
785 rc = build_data(source, options, &lmd);
790 rc = set_routes(&lmd);
796 printf("%s: debug mode, not mounting\n", progname);
800 rc = access(target, F_OK);
803 fprintf(stderr, "%s: %s inaccessible: %s\n", progname, target,
808 rc = mount(source, target, "lustre", 0, (void *)&lmd);
812 fprintf(stderr, "%s: mount(%s, %s) failed: %s\n", source,
813 target, progname, strerror(errno));
815 fprintf(stderr, "Are the lustre modules loaded?\n"
816 "Check /etc/modules.conf and /proc/filesystems\n");
819 update_mtab_entry(source, target, "lustre", options, 0, 0, 0);