Whamcloud - gitweb
- landing b_fid.
[fs/lustre-release.git] / lustre / utils / llmount.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  Copyright (C) 2002 Cluster File Systems, Inc.
5  *   Author: Robert Read <rread@clusterfs.com>
6  *
7  *   This file is part of Lustre, http://www.lustre.org.
8  *
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.
12  *
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.
17  *
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.
21  *
22  */
23
24
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <fcntl.h>
29 #include <errno.h>
30 #include <string.h>
31 #include <sys/mount.h>
32 #include <mntent.h>
33 #define _GNU_SOURCE
34 #include <getopt.h>
35 #include <sys/utsname.h>
36
37 #include "obdctl.h"
38 #include <portals/ptlctl.h>
39
40 int debug;
41 int verbose;
42 int nomtab;
43 int force;
44 static char *progname = NULL;
45
46 typedef struct {
47         ptl_nid_t gw;
48         ptl_nid_t lo;
49         ptl_nid_t hi;
50 } llmount_route_t;
51
52 #define MAX_ROUTES  1024
53 int route_index;
54 ptl_nid_t lmd_cluster_id = 0;
55 llmount_route_t routes[MAX_ROUTES];
56
57 static int check_mtab_entry(char *spec, char *mtpt, char *type)
58 {
59         FILE *fp;
60         struct mntent *mnt;
61
62         if (!force) {
63                 fp = setmntent(MOUNTED, "r");
64                 if (fp == NULL)
65                         return(0);
66
67                 while ((mnt = getmntent(fp)) != NULL) {
68                         if (strcmp(mnt->mnt_fsname, spec) == 0 &&
69                             strcmp(mnt->mnt_dir, mtpt) == 0 &&
70                             strcmp(mnt->mnt_type, type) == 0) {
71                                 fprintf(stderr, "%s: according to %s %s is "
72                                         "already mounted on %s\n",
73                                         progname, MOUNTED, spec, mtpt);
74                                 return(1); /* or should we return an error? */
75                         }
76                 }
77                 endmntent(fp);
78         }
79         return(0);
80 }
81
82 static void
83 update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
84                   int flags, int freq, int pass)
85 {
86         FILE *fp;
87         struct mntent mnt;
88
89         mnt.mnt_fsname = spec;
90         mnt.mnt_dir = mtpt;
91         mnt.mnt_type = type;
92         mnt.mnt_opts = opts ? opts : "";
93         mnt.mnt_freq = freq;
94         mnt.mnt_passno = pass;
95
96         if (!nomtab) {
97                 fp = setmntent(MOUNTED, "a+");
98                 if (fp == NULL) {
99                         fprintf(stderr, "%s: setmntent(%s): %s:",
100                                 progname, MOUNTED, strerror (errno));
101                 } else {
102                         if ((addmntent (fp, &mnt)) == 1) {
103                                 fprintf(stderr, "%s: addmntent: %s:",
104                                         progname, strerror (errno));
105                         }
106                         endmntent(fp);
107                 }
108         }
109 }
110
111 int
112 init_options(struct lustre_mount_data *lmd)
113 {
114         memset(lmd, 0, sizeof(*lmd));
115         lmd->lmd_magic = LMD_MAGIC;
116         lmd->lmd_server_nid = PTL_NID_ANY;
117         lmd->lmd_local_nid = PTL_NID_ANY;
118         lmd->lmd_port = 988;    /* XXX define LUSTRE_DEFAULT_PORT */
119         lmd->lmd_nal = SOCKNAL;
120         return 0;
121 }
122
123 int
124 print_options(struct lustre_mount_data *lmd)
125 {
126         int i;
127
128         printf("mds:             %s\n", lmd->lmd_mds);
129         printf("profile:         %s\n", lmd->lmd_profile);
130         printf("server_nid:      "LPX64"\n", lmd->lmd_server_nid);
131         printf("local_nid:       "LPX64"\n", lmd->lmd_local_nid);
132         printf("nal:             %d\n", lmd->lmd_nal);
133         printf("server_ipaddr:   0x%x\n", lmd->lmd_server_ipaddr);
134         printf("port:            %d\n", lmd->lmd_port);
135
136         for (i = 0; i < route_index; i++)
137                 printf("route:           "LPX64" : "LPX64" - "LPX64"\n",
138                        routes[i].gw, routes[i].lo, routes[i].hi);
139
140         return 0;
141 }
142
143 static int parse_route(char *opteq, char *opttgts)
144 {
145         char *gw_lo_ptr, *gw_hi_ptr, *tgt_lo_ptr, *tgt_hi_ptr;
146         ptl_nid_t gw_lo, gw_hi, tgt_lo, tgt_hi;
147
148         opttgts[0] = '\0';
149         gw_lo_ptr = opteq + 1;
150         if (!(gw_hi_ptr = strchr(gw_lo_ptr, '-'))) {
151                 gw_hi_ptr = gw_lo_ptr;
152         } else {
153                 gw_hi_ptr[0] = '\0';
154                 gw_hi_ptr++;
155         }
156
157         if (ptl_parse_nid(&gw_lo, gw_lo_ptr) != 0) {
158                 fprintf(stderr, "%s: can't parse NID %s\n", progname,gw_lo_ptr);
159                 return(-1);
160         }
161
162         if (ptl_parse_nid(&gw_hi, gw_hi_ptr) != 0) {
163                 fprintf(stderr, "%s: can't parse NID %s\n", progname,gw_hi_ptr);
164                 return(-1);
165         }
166
167         tgt_lo_ptr = opttgts + 1;
168         if (!(tgt_hi_ptr = strchr(tgt_lo_ptr, '-'))) {
169                 tgt_hi_ptr = tgt_lo_ptr;
170         } else {
171                 tgt_hi_ptr[0] = '\0';
172                 tgt_hi_ptr++;
173         }
174
175         if (ptl_parse_nid(&tgt_lo, tgt_lo_ptr) != 0) {
176                 fprintf(stderr, "%s: can't parse NID %s\n",progname,tgt_lo_ptr);
177                 return(-1);
178         }
179
180         if (ptl_parse_nid(&tgt_hi, tgt_hi_ptr) != 0) {
181                 fprintf(stderr, "%s: can't parse NID %s\n",progname,tgt_hi_ptr);
182                 return(-1);
183         }
184
185         while (gw_lo <= gw_hi) {
186                 if (route_index >= MAX_ROUTES) {
187                         fprintf(stderr, "%s: to many routes %d\n",
188                                 progname, MAX_ROUTES);
189                         return(-1);
190                 }
191
192                 routes[route_index].gw = gw_lo;
193                 routes[route_index].lo = tgt_lo;
194                 routes[route_index].hi = tgt_hi;
195                 route_index++;
196                 gw_lo++;
197         }
198
199         return(0);
200 }
201
202 int parse_options(char * options, struct lustre_mount_data *lmd)
203 {
204         ptl_nid_t nid = 0, cluster_id = 0;
205         int val;
206         char *opt, *opteq, *opttgts;
207
208         /* parsing ideas here taken from util-linux/mount/nfsmount.c */
209         for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
210                 if ((opteq = strchr(opt, '='))) {
211                         val = atoi(opteq + 1);
212                         *opteq = '\0';
213                         if (!strcmp(opt, "nettype")) {
214                                 lmd->lmd_nal = ptl_name2nal(opteq + 1);
215                         } else if(!strcmp(opt, "cluster_id")) {
216                                 if (ptl_parse_nid(&cluster_id, opteq+1) != 0) {
217                                         fprintf (stderr, "%s: can't parse NID "
218                                                  "%s\n", progname, opteq+1);
219                                         return (-1);
220                                 }
221                                 lmd_cluster_id = cluster_id;
222                         } else if(!strcmp(opt, "route")) {
223                                 if (!(opttgts = strchr(opteq + 1, ':'))) {
224                                         fprintf(stderr, "%s: Route must be "
225                                                 "of the form: route="
226                                                 "<gw>[-<gw>]:<low>[-<high>]\n",
227                                                 progname);
228                                         return(-1);
229                                 }
230                                 parse_route(opteq, opttgts);
231                         } else if (!strcmp(opt, "local_nid")) {
232                                 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
233                                         fprintf (stderr, "%s: "
234                                                  "can't parse NID %s\n",
235                                                  progname,
236                                                  opteq+1);
237                                         return (-1);
238                                 }
239                                 lmd->lmd_local_nid = nid;
240                         } else if (!strcmp(opt, "server_nid")) {
241                                 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
242                                         fprintf (stderr, "%s: "
243                                                  "can't parse NID %s\n",
244                                                  progname, opteq + 1);
245                                         return (-1);
246                                 }
247                                 lmd->lmd_server_nid = nid;
248                         } else if (!strcmp(opt, "port")) {
249                                 lmd->lmd_port = val;
250                         }
251                 } else {
252                         val = 1;
253                         if (!strncmp(opt, "no", 2)) {
254                                 val = 0;
255                                 opt += 2;
256                         }
257                         if (!strcmp(opt, "debug")) {
258                                 debug = val;
259                         }
260                 }
261         }
262         return 0;
263 }
264
265 int
266 get_local_elan_id(char *fname, char *buf)
267 {
268         FILE *fp = fopen(fname, "r");
269         int   rc;
270
271         if (fp == NULL)
272                 return -1;
273
274         rc = fscanf(fp, "NodeId %255s", buf);
275
276         fclose(fp);
277
278         return (rc == 1) ? 0 : -1;
279 }
280
281 int
282 set_local(struct lustre_mount_data *lmd)
283 {
284         /* XXX ClusterID?
285          * XXX PtlGetId() will be safer if portals is loaded and
286          * initialised correctly at this time... */
287         char buf[256];
288         ptl_nid_t nid;
289         int rc;
290
291         if (lmd->lmd_local_nid != PTL_NID_ANY)
292                 return 0;
293
294         memset(buf, 0, sizeof(buf));
295
296         if (lmd->lmd_nal == SOCKNAL || lmd->lmd_nal == TCPNAL ||
297             lmd->lmd_nal == OPENIBNAL) {
298                 struct utsname uts;
299
300                 rc = gethostname(buf, sizeof(buf) - 1);
301                 if (rc) {
302                         fprintf(stderr, "%s: can't get hostname: %s\n",
303                                 progname, strerror(rc));
304                         return rc;
305                 }
306                 rc = uname(&uts);
307                 /* for 2.6 kernels, reserve at least 8MB free, or we will
308                  * go OOM during heavy read load */
309                 if (rc == 0 && strncmp(uts.release, "2.6", 3) == 0) {
310                         int f, minfree = 32768;
311                         char name[40], val[40];
312                         FILE *meminfo;
313
314                         meminfo = fopen("/proc/meminfo", "r");
315                         if (meminfo != NULL) {
316                                 while (fscanf(meminfo, "%s %s %*s\n", name, val) != EOF) {
317                                         if (strcmp(name, "MemTotal:") == 0) {
318                                                 f = strtol(val, NULL, 0);
319                                                 if (f > 0 && f < 8 * minfree)
320                                                         minfree = f / 16;
321                                                 break;
322                                         }
323                                 }
324                                 fclose(meminfo);
325                         }
326                         f = open("/proc/sys/vm/min_free_kbytes", O_WRONLY);
327                         if (f >= 0) {
328                                 sprintf(val, "%d", minfree);
329                                 write(f, val, strlen(val));
330                                 close(f);
331                         }
332                  }
333         } else if (lmd->lmd_nal == QSWNAL) {
334                 char *pfiles[] = {"/proc/qsnet/elan3/device0/position",
335                                   "/proc/qsnet/elan4/device0/position",
336                                   "/proc/elan/device0/position",
337                                   NULL};
338                 int   i = 0;
339
340                 do {
341                         rc = get_local_elan_id(pfiles[i], buf);
342                 } while (rc != 0 && pfiles[++i] != NULL);
343
344                 if (rc != 0) {
345                         fprintf(stderr, "%s: can't read Elan ID from /proc\n",
346                                 progname);
347
348                         return -1;
349                 }
350         }
351
352         if (ptl_parse_nid (&nid, buf) != 0) {
353                 fprintf (stderr, "%s: can't parse NID %s\n", progname, buf);
354                 return (-1);
355         }
356
357         lmd->lmd_local_nid = nid + lmd_cluster_id;
358         return 0;
359 }
360
361 int
362 set_peer(char *hostname, struct lustre_mount_data *lmd)
363 {
364         ptl_nid_t nid = 0;
365         int rc;
366         
367         if (lmd->lmd_nal == SOCKNAL || lmd->lmd_nal == TCPNAL ||
368             lmd->lmd_nal == OPENIBNAL) {
369                 if (lmd->lmd_server_nid == PTL_NID_ANY) {
370                         if (ptl_parse_nid (&nid, hostname) != 0) {
371                                 fprintf (stderr, "%s: can't parse NID %s\n",
372                                          progname, hostname);
373                                 return (-1);
374                         }
375                         lmd->lmd_server_nid = nid;
376                 }
377
378                 if (ptl_parse_ipaddr(&lmd->lmd_server_ipaddr, hostname) != 0) {
379                         fprintf (stderr, "%s: can't parse host %s\n",
380                                  progname, hostname);
381                         return (-1);
382                 }
383         } else if (lmd->lmd_nal == QSWNAL) {
384                 char buf[64];
385                 rc = sscanf(hostname, "%*[^0-9]%63[0-9]", buf);
386                 if (rc != 1) {
387                         fprintf (stderr, "%s: can't get elan id from host %s\n",
388                                  progname, hostname);
389                         return -1;
390                 }
391                 if (ptl_parse_nid (&nid, buf) != 0) {
392                         fprintf (stderr, "%s: can't parse NID %s\n",
393                                  progname, hostname);
394                         return (-1);
395                 }
396                 lmd->lmd_server_nid = nid;
397         }
398
399
400         return 0;
401 }
402
403 int
404 build_data(char *source, char *options, struct lustre_mount_data *lmd)
405 {
406         char buf[1024];
407         char *hostname = NULL, *mds = NULL, *profile = NULL, *s;
408         int rc;
409
410         if (lmd_bad_magic(lmd))
411                 return 4;
412
413         if (strlen(source) > sizeof(buf) + 1) {
414                 fprintf(stderr, "%s: host:/mds/profile argument too long\n",
415                         progname);
416                 return 1;
417         }
418         strcpy(buf, source);
419         if ((s = strchr(buf, ':'))) {
420                 hostname = buf;
421                 *s = '\0';
422
423                 while (*++s == '/')
424                         ;
425                 mds = s;
426                 if ((s = strchr(mds, '/'))) {
427                         *s = '\0';
428                         profile = s + 1;
429                 } else {
430                         fprintf(stderr, "%s: directory to mount not in "
431                                 "host:/mds/profile format\n",
432                                 progname);
433                         return(1);
434                 }
435         } else {
436                 fprintf(stderr, "%s: "
437                         "directory to mount not in host:/mds/profile format\n",
438                         progname);
439                 return(1);
440         }
441
442         rc = parse_options(options, lmd);
443         if (rc)
444                 return rc;
445
446         rc = set_local(lmd);
447         if (rc)
448                 return rc;
449
450         rc = set_peer(hostname, lmd);
451         if (rc)
452                 return rc;
453         if (strlen(mds) > sizeof(lmd->lmd_mds) + 1) {
454                 fprintf(stderr, "%s: mds name too long\n", progname);
455                 return(1);
456         }
457         strcpy(lmd->lmd_mds, mds);
458
459         if (strlen(profile) > sizeof(lmd->lmd_profile) + 1) {
460                 fprintf(stderr, "%s: profile name too long\n", progname);
461                 return(1);
462         }
463         strcpy(lmd->lmd_profile, profile);
464
465         if (verbose)
466                 print_options(lmd);
467         return 0;
468 }
469
470 static int set_routes(struct lustre_mount_data *lmd) {
471        struct portals_cfg pcfg;
472        struct portal_ioctl_data data;
473        int i, j, route_exists, rc, err = 0;
474
475        register_ioc_dev(PORTALS_DEV_ID, PORTALS_DEV_PATH);
476
477        for (i = 0; i < route_index; i++) {
478
479                /* Check for existing routes so as not to add duplicates */
480               for (j = 0; ; j++) {
481                       PCFG_INIT(pcfg, NAL_CMD_GET_ROUTE);
482                       pcfg.pcfg_nal = ROUTER;
483                       pcfg.pcfg_count = j;
484
485                       PORTAL_IOC_INIT(data);
486                       data.ioc_pbuf1 = (char*)&pcfg;
487                       data.ioc_plen1 = sizeof(pcfg);
488                       data.ioc_nid = pcfg.pcfg_nid;
489
490                       rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
491                       if (rc != 0) {
492                               route_exists = 0;
493                               break;
494                       }
495
496                       if ((pcfg.pcfg_gw_nal == lmd->lmd_nal) &&
497                           (pcfg.pcfg_nid    == routes[i].gw) &&
498                           (pcfg.pcfg_nid2   == routes[i].lo) &&
499                           (pcfg.pcfg_nid3   == routes[i].hi)) {
500                               route_exists = 1;
501                               break;
502                       }
503               }
504
505               if (route_exists)
506                       continue;
507
508               PCFG_INIT(pcfg, NAL_CMD_ADD_ROUTE);
509               pcfg.pcfg_nid = routes[i].gw;
510               pcfg.pcfg_nal = ROUTER;
511               pcfg.pcfg_gw_nal = lmd->lmd_nal;
512               pcfg.pcfg_nid2 = MIN(routes[i].lo, routes[i].hi);
513               pcfg.pcfg_nid3 = MAX(routes[i].lo, routes[i].hi);
514
515               PORTAL_IOC_INIT(data);
516               data.ioc_pbuf1 = (char*)&pcfg;
517               data.ioc_plen1 = sizeof(pcfg);
518               data.ioc_nid = pcfg.pcfg_nid;
519
520               rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
521               if (rc != 0) {
522                       fprintf(stderr, "%s: Unable to add route "
523                               LPX64" : "LPX64" - "LPX64"\n[%d] %s\n",
524                               progname, routes[i].gw, routes[i].lo,
525                               routes[i].hi, errno, strerror(errno));
526                       err = -1;
527                       break;
528               }
529        }
530
531        unregister_ioc_dev(PORTALS_DEV_ID);
532        return err;
533 }
534
535 void usage(FILE *out)
536 {
537         fprintf(out, "usage: %s <source> <target> [-f] [-v] [-n] [-o mntopt]\n",
538                 progname);
539         exit(out != stdout);
540 }
541
542 int main(int argc, char *const argv[])
543 {
544         char *source, *target, *options = "";
545         int i, nargs = 3, opt, rc;
546         struct lustre_mount_data lmd;
547         static struct option long_opt[] = {
548                 {"force", 0, 0, 'f'},
549                 {"help", 0, 0, 'h'},
550                 {"nomtab", 0, 0, 'n'},
551                 {"options", 1, 0, 'o'},
552                 {"verbose", 0, 0, 'v'},
553                 {0, 0, 0, 0}
554         };
555
556         progname = strrchr(argv[0], '/');
557         progname = progname ? progname + 1 : argv[0];
558
559         while ((opt = getopt_long(argc, argv, "fno:v", long_opt, NULL)) != EOF){
560                 switch (opt) {
561                 case 'f':
562                         ++force;
563                         printf("force: %d\n", force);
564                         nargs++;
565                         break;
566                 case 'h':
567                         usage(stdout);
568                         break;
569                 case 'n':
570                         ++nomtab;
571                         printf("nomtab: %d\n", nomtab);
572                         nargs++;
573                         break;
574                 case 'o':
575                         options = optarg;
576                         nargs++;
577                         break;
578                 case 'v':
579                         ++verbose;
580                         printf("verbose: %d\n", verbose);
581                         nargs++;
582                         break;
583                 default:
584                         fprintf(stderr, "%s: unknown option '%c'\n",
585                                 progname, opt);
586                         usage(stderr);
587                         break;
588                 }
589         }
590
591         if (optind + 2 > argc) {
592                 fprintf(stderr, "%s: too few arguments\n", progname);
593                 usage(stderr);
594         }
595
596         source = argv[optind];
597         target = argv[optind + 1];
598
599         if (verbose) {
600                 for (i = 0; i < argc; i++)
601                         printf("arg[%d] = %s\n", i, argv[i]);
602                 printf("source = %s, target = %s\n", source, target);
603         }
604
605         if (check_mtab_entry(source, target, "lustre"))
606                 exit(32);
607
608         init_options(&lmd);
609         rc = build_data(source, options, &lmd);
610         if (rc) {
611                 exit(rc);
612         }
613
614         rc = set_routes(&lmd);
615         if (rc) {
616                 exit(rc);
617         }
618
619         if (debug) {
620                 printf("%s: debug mode, not mounting\n", progname);
621                 exit(0);
622         }
623
624         rc = mount(source, target, "lustre", 0, (void *)&lmd);
625         if (rc) {
626                 rc = errno;
627                 perror(argv[0]);
628                 if (rc == ENODEV)
629                         fprintf(stderr, "Are the lustre modules loaded?\n"
630                              "Check /etc/modules.conf and /proc/filesystems\n");
631                 return 2;
632         }
633         update_mtab_entry(source, target, "lustre", options, 0, 0, 0);
634         return 0;
635 }