Whamcloud - gitweb
1)add clonefs read in lustre
[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 if (!strcmp(opt, "clone")) {
250                                 lmd->lmd_clone_index = val;
251                         } 
252                 } else {
253                         val = 1;
254                         if (!strncmp(opt, "no", 2)) {
255                                 val = 0;
256                                 opt += 2;
257                         }
258                         if (!strcmp(opt, "debug")) {
259                                 debug = val;
260                         }
261                 }
262         }
263         return 0;
264 }
265
266 int
267 get_local_elan_id(char *fname, char *buf)
268 {
269         FILE *fp = fopen(fname, "r");
270         int   rc;
271
272         if (fp == NULL)
273                 return -1;
274
275         rc = fscanf(fp, "NodeId %255s", buf);
276
277         fclose(fp);
278
279         return (rc == 1) ? 0 : -1;
280 }
281
282 int
283 set_local(struct lustre_mount_data *lmd)
284 {
285         /* XXX ClusterID?
286          * XXX PtlGetId() will be safer if portals is loaded and
287          * initialised correctly at this time... */
288         char buf[256];
289         ptl_nid_t nid;
290         int rc;
291
292         if (lmd->lmd_local_nid != PTL_NID_ANY)
293                 return 0;
294
295         memset(buf, 0, sizeof(buf));
296
297         if (lmd->lmd_nal == SOCKNAL || lmd->lmd_nal == TCPNAL) {
298                 rc = gethostname(buf, sizeof(buf) - 1);
299                 if (rc) {
300                         fprintf (stderr, "%s: can't get local buf: %d\n",
301                                  progname, rc);
302                         return rc;
303                 }
304         } else if (lmd->lmd_nal == QSWNAL) {
305                 char *pfiles[] = {"/proc/qsnet/elan3/device0/position",
306                                   "/proc/qsnet/elan4/device0/position",
307                                   "/proc/elan/device0/position",
308                                   NULL};
309                 int   i = 0;
310
311                 do {
312                         rc = get_local_elan_id(pfiles[i], buf);
313                 } while (rc != 0 && pfiles[++i] != NULL);
314
315                 if (rc != 0) {
316                         fprintf(stderr, "%s: can't read Elan ID from /proc\n",
317                                 progname);
318
319                         return -1;
320                 }
321         }
322
323         if (ptl_parse_nid (&nid, buf) != 0) {
324                 fprintf (stderr, "%s: can't parse NID %s\n", progname, buf);
325                 return (-1);
326         }
327
328         lmd->lmd_local_nid = nid + lmd_cluster_id;
329         return 0;
330 }
331
332 int
333 set_peer(char *hostname, struct lustre_mount_data *lmd)
334 {
335         ptl_nid_t nid = 0;
336         int rc;
337
338         if (lmd->lmd_nal == SOCKNAL || lmd->lmd_nal == TCPNAL) {
339                 if (lmd->lmd_server_nid == PTL_NID_ANY) {
340                         if (ptl_parse_nid (&nid, hostname) != 0) {
341                                 fprintf (stderr, "%s: can't parse NID %s\n",
342                                          progname, hostname);
343                                 return (-1);
344                         }
345                         lmd->lmd_server_nid = nid;
346                 }
347
348                 if (ptl_parse_ipaddr(&lmd->lmd_server_ipaddr, hostname) != 0) {
349                         fprintf (stderr, "%s: can't parse host %s\n",
350                                  progname, hostname);
351                         return (-1);
352                 }
353         } else if (lmd->lmd_nal == QSWNAL) {
354                 char buf[64];
355                 rc = sscanf(hostname, "%*[^0-9]%63[0-9]", buf);
356                 if (rc != 1) {
357                         fprintf (stderr, "%s: can't get elan id from host %s\n",
358                                  progname, hostname);
359                         return -1;
360                 }
361                 if (ptl_parse_nid (&nid, buf) != 0) {
362                         fprintf (stderr, "%s: can't parse NID %s\n",
363                                  progname, hostname);
364                         return (-1);
365                 }
366                 lmd->lmd_server_nid = nid;
367         }
368
369
370         return 0;
371 }
372
373 int
374 build_data(char *source, char *options, struct lustre_mount_data *lmd)
375 {
376         char buf[1024];
377         char *hostname = NULL, *mds = NULL, *profile = NULL, *s;
378         int rc;
379
380         if (lmd_bad_magic(lmd))
381                 return -EINVAL;
382
383         if (strlen(source) > sizeof(buf) + 1) {
384                 fprintf(stderr, "%s: host:/mds/profile argument too long\n",
385                         progname);
386                 return -EINVAL;
387         }
388         strcpy(buf, source);
389         if ((s = strchr(buf, ':'))) {
390                 hostname = buf;
391                 *s = '\0';
392
393                 while (*++s == '/')
394                         ;
395                 mds = s;
396                 if ((s = strchr(mds, '/'))) {
397                         *s = '\0';
398                         profile = s + 1;
399                 } else {
400                         fprintf(stderr, "%s: directory to mount not in "
401                                 "host:/mds/profile format\n",
402                                 progname);
403                         return(-1);
404                 }
405         } else {
406                 fprintf(stderr, "%s: "
407                         "directory to mount not in host:/mds/profile format\n",
408                         progname);
409                 return(-1);
410         }
411
412         rc = parse_options(options, lmd);
413         if (rc)
414                 return rc;
415
416         rc = set_local(lmd);
417         if (rc)
418                 return rc;
419
420         rc = set_peer(hostname, lmd);
421         if (rc)
422                 return rc;
423         if (strlen(mds) > sizeof(lmd->lmd_mds) + 1) {
424                 fprintf(stderr, "%s: mds name too long\n", progname);
425                 return(-1);
426         }
427         strcpy(lmd->lmd_mds, mds);
428
429         if (strlen(profile) > sizeof(lmd->lmd_profile) + 1) {
430                 fprintf(stderr, "%s: profile name too long\n", progname);
431                 return(-1);
432         }
433         strcpy(lmd->lmd_profile, profile);
434
435         if (verbose)
436                 print_options(lmd);
437         return 0;
438 }
439
440 static int set_routes(struct lustre_mount_data *lmd) {
441        struct portals_cfg pcfg;
442        struct portal_ioctl_data data;
443        int i, j, route_exists, rc, err = 0;
444
445        register_ioc_dev(PORTALS_DEV_ID, PORTALS_DEV_PATH);
446
447        for (i = 0; i < route_index; i++) {
448
449                /* Check for existing routes so as not to add duplicates */
450               for (j = 0; ; j++) {
451                       PCFG_INIT(pcfg, NAL_CMD_GET_ROUTE);
452                       pcfg.pcfg_nal = ROUTER;
453                       pcfg.pcfg_count = j;
454
455                       PORTAL_IOC_INIT(data);
456                       data.ioc_pbuf1 = (char*)&pcfg;
457                       data.ioc_plen1 = sizeof(pcfg);
458                       data.ioc_nid = pcfg.pcfg_nid;
459
460                       rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
461                       if (rc != 0) {
462                               route_exists = 0;
463                               break;
464                       }
465
466                       if ((pcfg.pcfg_gw_nal == lmd->lmd_nal) &&
467                           (pcfg.pcfg_nid    == routes[i].gw) &&
468                           (pcfg.pcfg_nid2   == routes[i].lo) &&
469                           (pcfg.pcfg_nid3   == routes[i].hi)) {
470                               route_exists = 1;
471                               break;
472                       }
473               }
474
475               if (route_exists)
476                       continue;
477
478               PCFG_INIT(pcfg, NAL_CMD_ADD_ROUTE);
479               pcfg.pcfg_nid = routes[i].gw;
480               pcfg.pcfg_nal = ROUTER;
481               pcfg.pcfg_gw_nal = lmd->lmd_nal;
482               pcfg.pcfg_nid2 = MIN(routes[i].lo, routes[i].hi);
483               pcfg.pcfg_nid3 = MAX(routes[i].lo, routes[i].hi);
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                       fprintf(stderr, "%s: Unable to add route "
493                               "0x%llx : 0x%llx - 0x%llx\n[%d] %s\n",
494                                progname, routes[i].gw, routes[i].lo,
495                                routes[i].hi, errno, strerror(errno));
496                       err = -1;
497                       break;
498               }
499        }
500
501        unregister_ioc_dev(PORTALS_DEV_ID);
502        return err;
503 }
504
505 void usage(FILE *out)
506 {
507         fprintf(out, "usage: %s <source> <target> [-f] [-v] [-n] [-o mntopt]\n",
508                 progname);
509         exit(out != stdout);
510 }
511
512 int main(int argc, char *const argv[])
513 {
514         char *source, *target, *options = "";
515         int i, nargs = 3, opt, rc;
516         struct lustre_mount_data lmd;
517         static struct option long_opt[] = {
518                 {"force", 0, 0, 'f'},
519                 {"help", 0, 0, 'h'},
520                 {"nomtab", 0, 0, 'n'},
521                 {"options", 1, 0, 'o'},
522                 {"verbose", 0, 0, 'v'},
523                 {0, 0, 0, 0}
524         };
525
526         progname = strrchr(argv[0], '/');
527         progname = progname ? progname + 1 : argv[0];
528
529         while ((opt = getopt_long(argc, argv, "fno:v", long_opt, NULL)) != EOF){
530                 switch (opt) {
531                 case 'f':
532                         ++force;
533                         printf("force: %d\n", force);
534                         nargs++;
535                         break;
536                 case 'h':
537                         usage(stdout);
538                         break;
539                 case 'n':
540                         ++nomtab;
541                         printf("nomtab: %d\n", nomtab);
542                         nargs++;
543                         break;
544                 case 'o':
545                         options = optarg;
546                         nargs++;
547                         break;
548                 case 'v':
549                         ++verbose;
550                         printf("verbose: %d\n", verbose);
551                         nargs++;
552                         break;
553                 default:
554                         fprintf(stderr, "%s: unknown option '%c'\n",
555                                 progname, opt);
556                         usage(stderr);
557                         break;
558                 }
559         }
560
561         if (optind + 2 > argc) {
562                 fprintf(stderr, "%s: too few arguments\n", progname);
563                 usage(stderr);
564         }
565
566         source = argv[optind];
567         target = argv[optind + 1];
568
569         if (verbose) {
570                 for (i = 0; i < argc; i++)
571                         printf("arg[%d] = %s\n", i, argv[i]);
572                 printf("source = %s, target = %s\n", source, target);
573         }
574
575         if (check_mtab_entry(source, target, "lustre"))
576                 exit(32);
577
578         init_options(&lmd);
579         rc = build_data(source, options, &lmd);
580         if (rc) {
581                 exit(1);
582         }
583
584         rc = set_routes(&lmd);
585         if (rc) {
586                 exit(1);
587         }
588
589         if (debug) {
590                 printf("%s: debug mode, not mounting\n", progname);
591                 exit(0);
592         }
593
594         rc = mount(source, target, "lustre", 0, (void *)&lmd);
595         if (rc) {
596                 rc = errno;
597                 perror(argv[0]);
598                 if (rc == ENODEV)
599                         fprintf(stderr, "Are the lustre modules loaded?\n"
600                              "Check /etc/modules.conf and /proc/filesystems\n");
601         } else {
602                 update_mtab_entry(source, target, "lustre", options, 0, 0, 0);
603         }
604         return rc;
605 }