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