Whamcloud - gitweb
fix for bug #4481
[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 verbose;
39 int nomtab;
40 int fake;
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 void usage(FILE *out)
56 {
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");
75         exit(out != stdout);
76 }
77
78 static int check_mtab_entry(char *spec, char *mtpt, char *type)
79 {
80         FILE *fp;
81         struct mntent *mnt;
82
83         if (!force) {
84                 fp = setmntent(MOUNTED, "r");
85                 if (fp == NULL)
86                         return(0);
87
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? */
96                         }
97                 }
98                 endmntent(fp);
99         }
100         return(0);
101 }
102
103 static int
104 update_mtab_entry(char *spec, char *mtpt, char *type, char *opts,
105                   int flags, int freq, int pass)
106 {
107         FILE *fp;
108         struct mntent mnt;
109         int rc = 0;
110
111         mnt.mnt_fsname = spec;
112         mnt.mnt_dir = mtpt;
113         mnt.mnt_type = type;
114         mnt.mnt_opts = opts ? opts : "";
115         mnt.mnt_freq = freq;
116         mnt.mnt_passno = pass;
117
118         fp = setmntent(MOUNTED, "a+");
119         if (fp == NULL) {
120                 fprintf(stderr, "%s: setmntent(%s): %s:",
121                         progname, MOUNTED, strerror (errno));
122                 rc = 16;
123         } else {
124                 if ((addmntent(fp, &mnt)) == 1) {
125                         fprintf(stderr, "%s: addmntent: %s:",
126                                 progname, strerror (errno));
127                         rc = 16;
128                 }
129                 endmntent(fp);
130         }
131
132         return rc;
133 }
134
135 int
136 init_options(struct lustre_mount_data *lmd)
137 {
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;
144         return 0;
145 }
146
147 int
148 print_options(struct lustre_mount_data *lmd)
149 {
150         int i;
151
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);
159
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);
163
164         return 0;
165 }
166
167 static int parse_route(char *opteq, char *opttgts)
168 {
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;
171
172         opttgts[0] = '\0';
173         gw_lo_ptr = opteq + 1;
174         if (!(gw_hi_ptr = strchr(gw_lo_ptr, '-'))) {
175                 gw_hi_ptr = gw_lo_ptr;
176         } else {
177                 gw_hi_ptr[0] = '\0';
178                 gw_hi_ptr++;
179         }
180
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);
183                 return(1);
184         }
185
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);
188                 return(1);
189         }
190
191         tgt_lo_ptr = opttgts + 1;
192         if (!(tgt_hi_ptr = strchr(tgt_lo_ptr, '-'))) {
193                 tgt_hi_ptr = tgt_lo_ptr;
194         } else {
195                 tgt_hi_ptr[0] = '\0';
196                 tgt_hi_ptr++;
197         }
198
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);
201                 return(1);
202         }
203
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);
206                 return(1);
207         }
208
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);
213                         return(-1);
214                 }
215
216                 routes[route_index].gw = gw_lo;
217                 routes[route_index].lo = tgt_lo;
218                 routes[route_index].hi = tgt_hi;
219                 route_index++;
220                 gw_lo++;
221         }
222
223         return(0);
224 }
225
226 static int ignored_option(const char *check)
227 {
228         char *ignore[] = { "noatime", "async", "rw", "suid", "dev",
229                            "exec", "nouser", "auto", "noauto", "_netdev", 
230                            NULL };
231         char **which = ignore;
232
233         while (*which != NULL) {
234                 if (strcmp(check, *which) == 0)
235                         return 1;
236                 which++;
237         }
238         return 0;
239 }
240
241 int parse_options(char *options, struct lustre_mount_data *lmd)
242 {
243         ptl_nid_t nid = 0, cluster_id = 0;
244         int val;
245         char *opt, *opteq, *opttgts;
246
247         /* parsing ideas here taken from util-linux/mount/nfsmount.c */
248         for (opt = strtok(options, ","); opt; opt = strtok(NULL, ",")) {
249                 if ((opteq = strchr(opt, '='))) {
250                         val = atoi(opteq + 1);
251                         *opteq = '\0';
252                         if (!strcmp(opt, "nettype")) {
253                                 lmd->lmd_nal = ptl_name2nal(opteq + 1);
254                         } else if(!strcmp(opt, "cluster_id")) {
255                                 if (ptl_parse_nid(&cluster_id, opteq+1) != 0) {
256                                         fprintf(stderr, "%s: can't parse NID "
257                                                 "%s\n", progname, opteq+1);
258                                         return (1);
259                                 }
260                                 lmd_cluster_id = cluster_id;
261                         } else if(!strcmp(opt, "route")) {
262                                 if (!(opttgts = strchr(opteq + 1, ':'))) {
263                                         fprintf(stderr, "%s: Route must be "
264                                                 "of the form: route="
265                                                 "<gw>[-<gw>]:<low>[-<high>]\n",
266                                                 progname);
267                                         return(1);
268                                 }
269                                 parse_route(opteq, opttgts);
270                         } else if (!strcmp(opt, "local_nid")) {
271                                 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
272                                         fprintf(stderr, "%s: "
273                                                 "can't parse NID %s\n",
274                                                 progname,
275                                                 opteq+1);
276                                         return (1);
277                                 }
278                                 lmd->lmd_local_nid = nid;
279                         } else if (!strcmp(opt, "server_nid")) {
280                                 if (ptl_parse_nid(&nid, opteq + 1) != 0) {
281                                         fprintf(stderr, "%s: "
282                                                 "can't parse NID %s\n",
283                                                 progname, opteq + 1);
284                                         return (1);
285                                 }
286                                 lmd->lmd_server_nid = nid;
287                         } else if (!strcmp(opt, "port")) {
288                                 lmd->lmd_port = val;
289                         } else {
290                                 fprintf(stderr, "%s: unknown option '%s'\n",
291                                         progname, opt);
292                                 usage(stderr);
293                         }
294                 } else {
295                         if (ignored_option(opt))
296                                 continue;
297
298                         val = 1;
299                         if (!strncmp(opt, "no", 2)) {
300                                 val = 0;
301                                 opt += 2;
302                         }
303                         if (!strcmp(opt, "debug")) { /* deprecated */
304                                 fake = val;
305                         } else {
306                                 fprintf(stderr, "%s: unknown option '%s'\n",
307                                         progname, opt);
308                                 usage(stderr);
309                         }
310                 }
311         }
312         return 0;
313 }
314
315 int
316 get_local_elan_id(char *fname, char *buf)
317 {
318         FILE *fp = fopen(fname, "r");
319         int   rc;
320
321         if (fp == NULL)
322                 return 1;
323
324         rc = fscanf(fp, "NodeId %255s", buf);
325
326         fclose(fp);
327
328         return (rc == 1) ? 0 : -1;
329 }
330
331 int
332 set_local(struct lustre_mount_data *lmd)
333 {
334         /* XXX ClusterID?
335          * XXX PtlGetId() will be safer if portals is loaded and
336          * initialised correctly at this time... */
337         char buf[256], *ptr = buf;
338         ptl_nid_t nid;
339         int rc;
340
341         if (lmd->lmd_local_nid != PTL_NID_ANY)
342                 return 0;
343
344         memset(buf, 0, sizeof(buf));
345
346         switch (lmd->lmd_nal) {
347         default:
348                 fprintf(stderr, "%s: Unknown network type: %d\n",
349                         progname, lmd->lmd_nal);
350                 return 1;
351                 
352         case SOCKNAL:
353         case TCPNAL:
354         case OPENIBNAL:
355         case IIBNAL:
356         case VIBNAL:
357         case RANAL:
358                 rc = gethostname(buf, sizeof(buf) - 1);
359                 if (rc) {
360                         fprintf (stderr, "%s: can't get local buf: %d\n",
361                                  progname, rc);
362                         return rc;
363                 }
364                 break;
365         case QSWNAL: {
366                 char *pfiles[] = {"/proc/qsnet/elan3/device0/position",
367                                   "/proc/qsnet/elan4/device0/position",
368                                   "/proc/elan/device0/position",
369                                   NULL};
370                 int   i = 0;
371
372                 do {
373                         rc = get_local_elan_id(pfiles[i], buf);
374                 } while (rc != 0 && pfiles[++i] != NULL);
375
376                 if (rc != 0) {
377                         rc = gethostname(buf, sizeof(buf) - 1);
378                         if (rc == 0) {
379                                 char *tmp = ptr;
380                                 while ((*tmp >= 'a' && *tmp <= 'z') ||
381                                        (*tmp >= 'A' && *tmp <= 'Z'))
382                                         tmp++;
383                                 ptr = strsep(&tmp, ".");
384                         } else {
385                                 fprintf(stderr,
386                                         "%s: can't read Elan ID from /proc\n",
387                                         progname);
388                                 return 1;
389                         }
390                 }
391                 break;
392         }
393         }
394
395         if (ptl_parse_nid (&nid, ptr) != 0) {
396                 fprintf (stderr, "%s: can't parse NID %s\n", progname, buf);
397                 return (1);
398         }
399
400         lmd->lmd_local_nid = nid + lmd_cluster_id;
401         return 0;
402 }
403
404 int
405 set_peer(char *hostname, struct lustre_mount_data *lmd)
406 {
407         ptl_nid_t nid = 0;
408         int rc;
409
410         switch (lmd->lmd_nal) {
411         default:
412                 fprintf(stderr, "%s: Unknown network type: %d\n",
413                         progname, lmd->lmd_nal);
414                 return 1;
415                 
416         case IIBNAL:
417         case VIBNAL:
418                 if (lmd->lmd_server_nid != PTL_NID_ANY)
419                         break;
420                 if (ptl_parse_nid (&nid, hostname) != 0) {
421                         fprintf (stderr, "%s: can't parse NID %s\n",
422                                  progname, hostname);
423                         return (1);
424                 }
425                 lmd->lmd_server_nid = nid;
426                 break;
427
428         case SOCKNAL:
429         case TCPNAL:
430         case OPENIBNAL:
431         case RANAL:
432                 if (lmd->lmd_server_nid == PTL_NID_ANY) {
433                         if (ptl_parse_nid (&nid, hostname) != 0) {
434                                 fprintf (stderr, "%s: can't parse NID %s\n",
435                                          progname, hostname);
436                                 return (1);
437                         }
438                         lmd->lmd_server_nid = nid;
439                 }
440
441                 if (ptl_parse_ipaddr(&lmd->lmd_server_ipaddr, hostname) != 0) {
442                         fprintf (stderr, "%s: can't parse host %s\n",
443                                  progname, hostname);
444                         return (1);
445                 }
446                 break;
447         case QSWNAL: {
448                 char buf[64];
449
450                 if (lmd->lmd_server_nid != PTL_NID_ANY)
451                         break;
452
453                 rc = sscanf(hostname, "%*[^0-9]%63[0-9]", buf);
454                 if (rc != 1) {
455                         fprintf (stderr, "%s: can't get elan id from host %s\n",
456                                  progname, hostname);
457                         return 1;
458                 }
459                 if (ptl_parse_nid (&nid, buf) != 0) {
460                         fprintf (stderr, "%s: can't parse NID %s\n",
461                                  progname, hostname);
462                         return (1);
463                 }
464                 lmd->lmd_server_nid = nid;
465
466                 break;
467         }
468         }
469
470         return 0;
471 }
472
473 int
474 build_data(char *source, char *options, struct lustre_mount_data *lmd)
475 {
476         char buf[1024];
477         char *hostname = NULL, *mds = NULL, *profile = NULL, *s;
478         int rc;
479
480         if (lmd_bad_magic(lmd))
481                 return -EINVAL;
482
483         if (strlen(source) > sizeof(buf) + 1) {
484                 fprintf(stderr, "%s: host:/mds/profile argument too long\n",
485                         progname);
486                 return -EINVAL;
487         }
488         strcpy(buf, source);
489         if ((s = strchr(buf, ':'))) {
490                 hostname = buf;
491                 *s = '\0';
492
493                 while (*++s == '/')
494                         ;
495                 mds = s;
496                 if ((s = strchr(mds, '/'))) {
497                         *s = '\0';
498                         profile = s + 1;
499                 } else {
500                         fprintf(stderr, "%s: directory to mount not in "
501                                 "host:/mds/profile format\n",
502                                 progname);
503                         return(1);
504                 }
505         } else {
506                 fprintf(stderr, "%s: "
507                         "directory to mount not in host:/mds/profile format\n",
508                         progname);
509                 return(1);
510         }
511
512         rc = parse_options(options, lmd);
513         if (rc)
514                 return rc;
515
516         rc = set_local(lmd);
517         if (rc)
518                 return rc;
519
520         rc = set_peer(hostname, lmd);
521         if (rc)
522                 return rc;
523         if (strlen(mds) > sizeof(lmd->lmd_mds) + 1) {
524                 fprintf(stderr, "%s: mds name too long\n", progname);
525                 return(1);
526         }
527         strcpy(lmd->lmd_mds, mds);
528
529         if (strlen(profile) > sizeof(lmd->lmd_profile) + 1) {
530                 fprintf(stderr, "%s: profile name too long\n", progname);
531                 return(1);
532         }
533         strcpy(lmd->lmd_profile, profile);
534
535         if (verbose)
536                 print_options(lmd);
537         return 0;
538 }
539
540 static int set_routes(struct lustre_mount_data *lmd) {
541        struct portals_cfg pcfg;
542        struct portal_ioctl_data data;
543        int i, j, route_exists, rc, err = 0;
544
545        register_ioc_dev(PORTALS_DEV_ID, PORTALS_DEV_PATH);
546
547        for (i = 0; i < route_index; i++) {
548
549                /* Check for existing routes so as not to add duplicates */
550               for (j = 0; ; j++) {
551                       PCFG_INIT(pcfg, NAL_CMD_GET_ROUTE);
552                       pcfg.pcfg_nal = ROUTER;
553                       pcfg.pcfg_count = j;
554
555                       PORTAL_IOC_INIT(data);
556                       data.ioc_pbuf1 = (char*)&pcfg;
557                       data.ioc_plen1 = sizeof(pcfg);
558                       data.ioc_nid = pcfg.pcfg_nid;
559
560                       rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
561                       if (rc != 0) {
562                               route_exists = 0;
563                               break;
564                       }
565
566                       if ((pcfg.pcfg_gw_nal == lmd->lmd_nal) &&
567                           (pcfg.pcfg_nid    == routes[i].gw) &&
568                           (pcfg.pcfg_nid2   == routes[i].lo) &&
569                           (pcfg.pcfg_nid3   == routes[i].hi)) {
570                               route_exists = 1;
571                               break;
572                       }
573               }
574
575               if (route_exists)
576                       continue;
577
578               PCFG_INIT(pcfg, NAL_CMD_ADD_ROUTE);
579               pcfg.pcfg_nid = routes[i].gw;
580               pcfg.pcfg_nal = ROUTER;
581               pcfg.pcfg_gw_nal = lmd->lmd_nal;
582               pcfg.pcfg_nid2 = MIN(routes[i].lo, routes[i].hi);
583               pcfg.pcfg_nid3 = MAX(routes[i].lo, routes[i].hi);
584
585               PORTAL_IOC_INIT(data);
586               data.ioc_pbuf1 = (char*)&pcfg;
587               data.ioc_plen1 = sizeof(pcfg);
588               data.ioc_nid = pcfg.pcfg_nid;
589
590               rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_NAL_CMD, &data);
591               if (rc != 0) {
592                       fprintf(stderr, "%s: Unable to add route "
593                               LPX64" : "LPX64" - "LPX64"\n[%d] %s\n",
594                               progname, routes[i].gw, routes[i].lo,
595                               routes[i].hi, errno, strerror(errno));
596                       err = 2;
597                       break;
598               }
599        }
600
601        unregister_ioc_dev(PORTALS_DEV_ID);
602        return err;
603 }
604
605 int main(int argc, char *const argv[])
606 {
607         char *source, *target, *options = "";
608         int i, nargs = 3, opt, rc;
609         struct lustre_mount_data lmd;
610         static struct option long_opt[] = {
611                 {"fake", 0, 0, 'f'},
612                 {"force", 0, 0, 1},
613                 {"help", 0, 0, 'h'},
614                 {"nomtab", 0, 0, 'n'},
615                 {"options", 1, 0, 'o'},
616                 {"verbose", 0, 0, 'v'},
617                 {0, 0, 0, 0}
618         };
619
620         progname = strrchr(argv[0], '/');
621         progname = progname ? progname + 1 : argv[0];
622
623         while ((opt = getopt_long(argc, argv, "fhno:v", long_opt,NULL)) != EOF){
624                 switch (opt) {
625                 case 1:
626                         ++force;
627                         printf("force: %d\n", force);
628                         nargs++;
629                         break;
630                 case 'f':
631                         ++fake;
632                         printf("fake: %d\n", fake);
633                         nargs++;
634                         break;
635                 case 'h':
636                         usage(stdout);
637                         break;
638                 case 'n':
639                         ++nomtab;
640                         printf("nomtab: %d\n", nomtab);
641                         nargs++;
642                         break;
643                 case 'o':
644                         options = optarg;
645                         nargs++;
646                         break;
647                 case 'v':
648                         ++verbose;
649                         printf("verbose: %d\n", verbose);
650                         nargs++;
651                         break;
652                 default:
653                         fprintf(stderr, "%s: unknown option '%c'\n",
654                                 progname, opt);
655                         usage(stderr);
656                         break;
657                 }
658         }
659
660         if (optind + 2 > argc) {
661                 fprintf(stderr, "%s: too few arguments\n", progname);
662                 usage(stderr);
663         }
664
665         source = argv[optind];
666         target = argv[optind + 1];
667
668         if (verbose) {
669                 for (i = 0; i < argc; i++)
670                         printf("arg[%d] = %s\n", i, argv[i]);
671                 printf("source = %s, target = %s\n", source, target);
672         }
673
674         if (!force && check_mtab_entry(source, target, "lustre"))
675                 exit(32);
676
677         init_options(&lmd);
678         rc = build_data(source, options, &lmd);
679         if (rc) {
680                 exit(1);
681         }
682
683         if (!fake) {
684                 rc = set_routes(&lmd);
685                 if (rc)
686                         exit(2);
687         }
688
689         rc = access(target, F_OK);
690         if (rc) {
691                 rc = errno;
692                 fprintf(stderr, "%s: %s inaccessible: %s\n", progname, target,
693                         strerror(errno));
694                 return 1;
695         }
696
697         if (!fake)
698                 rc = mount(source, target, "lustre", 0, (void *)&lmd);
699         if (rc) {
700                 fprintf(stderr, "%s: mount(%s, %s) failed: %s\n", source,
701                         target, progname, strerror(errno));
702                 if (errno == ENODEV)
703                         fprintf(stderr, "Are the lustre modules loaded?\n"
704                              "Check /etc/modules.conf and /proc/filesystems\n");
705                 rc = 32;
706         } else if (!nomtab) {
707                 rc = update_mtab_entry(source, target, "lustre", options,0,0,0);
708         }
709         return rc;
710 }