Whamcloud - gitweb
41a19b69c1da759173d116ceae7c3232bd1fcccf
[fs/lustre-release.git] / lustre / utils / mkfs_lustre.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: Lin Song Tao <lincent@clusterfs.com>
6  *   Author: Nathan Rutman <nathan@clusterfs.com>
7  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  */
24
25 #define _GNU_SOURCE
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <stdarg.h>
31 #include <mntent.h>
32
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <sys/mount.h>
36
37 #include <string.h>
38 #include <getopt.h>
39
40 #include <linux/types.h>
41 //#define HAVE_SYS_VFS_H 1
42 #include <linux/fs.h> // for BLKGETSIZE64
43 #include <lustre_disk.h>
44 #include <lustre_param.h>
45 #include <lnet/lnetctl.h>
46 #include <lustre_ver.h>
47
48
49 #define MAX_LOOP_DEVICES 16
50 #define L_BLOCK_SIZE 4096
51 #define INDEX_UNASSIGNED 0xFFFF
52
53 static char *progname;
54 static int verbose = 0;
55 static int print_only = 0;
56
57
58 void usage(FILE *out)
59 {
60         fprintf(out, "%s v"LUSTRE_VERSION_STRING"\n", progname);
61         fprintf(out, "usage: %s <target types> [options] <device>\n", progname);
62         fprintf(out,
63                 "\t<device>:block device or file (e.g /dev/sda or /tmp/ost1)\n"
64                 "\ttarget types:\n"
65                 "\t\t--ost: object storage, mutually exclusive with mdt\n"
66                 "\t\t--mdt: metadata storage, mutually exclusive with ost\n"
67                 "\t\t--mgs: configuration management service - one per site\n"
68                 "\toptions (in order of popularity):\n"
69                 "\t\t--mgsnode=<nid>[,<...>] : NID(s) of a remote mgs node\n"
70                 "\t\t\trequired for all targets other than the mgs node\n"
71                 "\t\t--fsname=<filesystem_name> : default is 'lustre'\n"
72                 "\t\t--failnode=<nid>[,<...>] : NID(s) of a failover partner\n"
73                 "\t\t--param <key>=<value> : set a permanent parameter\n"
74                 "\t\t--index=#N : target index\n"
75                 /* FIXME implement 1.6.x
76                 "\t\t--configdev=<altdevice|file>: store configuration info\n"
77                 "\t\t\tfor this device on an alternate device\n"
78                 */
79                 "\t\t--mountfsoptions=<opts> : permanent mount options\n"
80                 "\t\t--backfstype=<fstype> : backing fs type (ext3, ldiskfs)\n"
81                 "\t\t--device-size=#N(KB) : device size for loop devices\n"
82 #ifndef TUNEFS
83                 "\t\t--mkfsoptions=<opts> : format options\n"
84                 "\t\t--reformat: overwrite an existing disk\n"
85                 "\t\t--stripe-count-hint=#N : used for optimizing MDT inode size\n"
86 #else
87                 "\t\t--erase-params : erase all old parameter settings\n"
88                 "\t\t--nomgs: turn off MGS service on this MDT\n"
89                 "\t\t--writeconf: erase all config logs for this fs.\n"
90 #endif
91                 "\t\t--print: just report what we would do; don't write to "
92                 "disk\n"
93                 "\t\t--verbose\n"
94                 "\t\t--quiet\n");
95         return;
96 }
97
98 #define vprint(i, fmt, arg...) if(verbose > i) printf(fmt, ## arg)
99
100 static void fatal(void)
101 {
102         verbose = 0;
103         fprintf(stderr, "\n%s FATAL: ", progname);
104 }
105
106 /*================ utility functions =====================*/
107
108 inline unsigned int
109 dev_major (unsigned long long int __dev)
110 {
111         return ((__dev >> 8) & 0xfff) | ((unsigned int) (__dev >> 32) & ~0xfff);
112 }
113
114 inline unsigned int
115 dev_minor (unsigned long long int __dev)
116 {
117         return (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff);
118 }
119
120 int get_os_version()
121 {
122         static int version = 0;
123
124         if (!version) {
125                 int fd;
126                 char release[4] = "";
127
128                 fd = open("/proc/sys/kernel/osrelease", O_RDONLY);
129                 if (fd < 0)
130                         fprintf(stderr, "%s: Warning: Can't resolve kernel "
131                                 "version, assuming 2.6\n", progname);
132                 else {
133                         read(fd, release, 4);
134                         close(fd);
135                 }
136                 if (strncmp(release, "2.4.", 4) == 0)
137                         version = 24;
138                 else
139                         version = 26;
140         }
141         return version;
142 }
143
144 int run_command(char *cmd)
145 {
146         char log[] = "/tmp/mkfs_logXXXXXX";
147         int fd, rc;
148
149         vprint(1, "cmd: %s\n", cmd);
150         if ((fd = mkstemp(log)) >= 0) {
151                 close(fd);
152                 strcat(cmd, " >");
153                 strcat(cmd, log);
154         }
155         strcat(cmd, " 2>&1");
156
157         /* Can't use popen because we need the rv of the command */
158         rc = system(cmd);
159         if (rc && fd >= 0) {
160                 char buf[128];
161                 FILE *fp;
162                 fp = fopen(log, "r");
163                 if (fp) {
164                         while (fgets(buf, sizeof(buf), fp) != NULL) {
165                                 vprint(2, "   %s", buf);
166                         }
167                         fclose(fp);
168                 }
169         }
170         if (fd >= 0)
171                 remove(log);
172         return rc;
173 }
174
175 static int check_mtab_entry(char *spec, char *type)
176 {
177         FILE *fp;
178         struct mntent *mnt;
179
180         fp = setmntent(MOUNTED, "r");
181         if (fp == NULL)
182                 return(0);
183
184         while ((mnt = getmntent(fp)) != NULL) {
185                 if ((strcmp(mnt->mnt_fsname, spec) == 0) &&
186                         (strcmp(mnt->mnt_type, type) == 0)) {
187                         endmntent(fp);
188                         fprintf(stderr, "%s: according to %s %s is "
189                                 "already mounted on %s\n",
190                                 progname, MOUNTED, spec, mnt->mnt_dir);
191                         return(EEXIST);
192                 }
193         }
194         endmntent(fp);
195
196         return(0);
197 }
198
199 /*============ disk dev functions ===================*/
200
201 /* Setup a file in the first unused loop_device */
202 int loop_setup(struct mkfs_opts *mop)
203 {
204         char loop_base[20];
205         char l_device[64];
206         int i;
207         int ret = 0;
208
209         /* Figure out the loop device names */
210         if (!access("/dev/loop0", F_OK | R_OK)) {
211                 strcpy(loop_base, "/dev/loop\0");
212         } else if (!access("/dev/loop/0", F_OK | R_OK)) {
213                 strcpy(loop_base, "/dev/loop/\0");
214         } else {
215                 fprintf(stderr, "%s: can't access loop devices\n", progname);
216                 return 1;
217         }
218
219         /* Find unused loop device */
220         for (i = 0; i < MAX_LOOP_DEVICES; i++) {
221                 char cmd[128];
222                 sprintf(l_device, "%s%d", loop_base, i);
223                 if (access(l_device, F_OK | R_OK))
224                         break;
225                 sprintf(cmd, "losetup %s > /dev/null 2>&1", l_device);
226                 ret = system(cmd);
227                 /* losetup gets 1 (ret=256) for non-set-up device */
228                 if (ret) {
229                         /* Set up a loopback device to our file */
230                         sprintf(cmd, "losetup %s %s", l_device, mop->mo_device);
231                         ret = run_command(cmd);
232                         if (ret) {
233                                 fprintf(stderr, "%s: error %d on losetup: %s\n",
234                                         progname, ret, strerror(ret));
235                                 return ret;
236                         }
237                         strcpy(mop->mo_loopdev, l_device);
238                         return ret;
239                 }
240         }
241
242         fprintf(stderr, "%s: out of loop devices!\n", progname);
243         return EMFILE;
244 }
245
246 int loop_cleanup(struct mkfs_opts *mop)
247 {
248         char cmd[128];
249         int ret = 1;
250         if ((mop->mo_flags & MO_IS_LOOP) && *mop->mo_loopdev) {
251                 sprintf(cmd, "losetup -d %s", mop->mo_loopdev);
252                 ret = run_command(cmd);
253         }
254         return ret;
255 }
256
257 /* Determine if a device is a block device (as opposed to a file) */
258 int is_block(char* devname)
259 {
260         struct stat st;
261         int ret = 0;
262
263         ret = access(devname, F_OK);
264         if (ret != 0)
265                 return 0;
266         ret = stat(devname, &st);
267         if (ret != 0) {
268                 fprintf(stderr, "%s: cannot stat %s\n", progname, devname);
269                 return -1;
270         }
271         return S_ISBLK(st.st_mode);
272 }
273
274 __u64 get_device_size(char* device)
275 {
276         int ret, fd;
277         __u64 size = 0;
278
279         fd = open(device, O_RDONLY);
280         if (fd < 0) {
281                 fprintf(stderr, "%s: cannot open %s: %s\n",
282                         progname, device, strerror(errno));
283                 return 0;
284         }
285
286         /* size in bytes. bz5831 */
287         ret = ioctl(fd, BLKGETSIZE64, (void*)&size);
288         close(fd);
289         if (ret < 0) {
290                 fprintf(stderr, "%s: size ioctl failed: %s\n",
291                         progname, strerror(errno));
292                 return 0;
293         }
294
295         vprint(0, "device size = "LPU64"MB\n", size >> 20);
296         /* return value in KB */
297         return size >> 10;
298 }
299
300 int loop_format(struct mkfs_opts *mop)
301 {
302         int ret = 0;
303
304         if (mop->mo_device_sz == 0) {
305                 fatal();
306                 fprintf(stderr, "loop device requires a --device-size= "
307                         "param\n");
308                 return EINVAL;
309         }
310
311         ret = creat(mop->mo_device, S_IRUSR|S_IWUSR);
312         if (ret < 0) {
313                 ret = errno;
314                 fprintf(stderr, "%s: Unable to create backing store: %d\n",
315                         progname, ret);
316         } else {
317                 close(ret);
318         }
319
320         ret = truncate(mop->mo_device, mop->mo_device_sz * 1024);
321         if (ret != 0) {
322                 ret = errno;
323                 fprintf(stderr, "%s: Unable to truncate backing store: %d\n",
324                         progname, ret);
325         }
326
327         return ret;
328 }
329
330 /* Check whether the file exists in the device */
331 static int file_in_dev(char *file_name, char *dev_name)
332 {
333         FILE *fp;
334         char debugfs_cmd[256];
335         unsigned int inode_num;
336         int i;
337
338         /* Construct debugfs command line. */
339         memset(debugfs_cmd, 0, sizeof(debugfs_cmd));
340         sprintf(debugfs_cmd,
341                 "debugfs -c -R 'stat %s' %s 2>&1 | egrep '(Inode|unsupported)'",
342                 file_name, dev_name);
343
344         fp = popen(debugfs_cmd, "r");
345         if (!fp) {
346                 fprintf(stderr, "%s: %s\n", progname, strerror(errno));
347                 return 0;
348         }
349
350         if (fscanf(fp, "Inode: %u", &inode_num) == 1) { /* exist */
351                 pclose(fp);
352                 return 1;
353         }
354         i = fread(debugfs_cmd, 1, sizeof(debugfs_cmd), fp);
355         if (i) {
356                 /* Filesystem has unsupported feature */
357                 vprint(0, "%.*s", i, debugfs_cmd);
358                 /* in all likelihood, the "unsupported feature" is
359                   'extents', which older debugfs does not understand.
360                   Use e2fsprogs-1.38-cfs1 or later, available from
361                   ftp://ftp.lustre.org/pub/lustre/other/e2fsprogs/ */
362                 return -1;
363         }
364         pclose(fp);
365         return 0;
366 }
367
368 /* Check whether the device has already been used with lustre */
369 static int is_lustre_target(struct mkfs_opts *mop)
370 {
371         int rc;
372
373         vprint(0, "checking for existing Lustre data\n");
374         if ((rc = file_in_dev(MOUNT_DATA_FILE, mop->mo_device))
375             || (rc = file_in_dev(LAST_RCVD, mop->mo_device))) {
376                 vprint(0, "found Lustre data\n");
377                 /* in the -1 case, 'extents' means this really IS a lustre
378                    target */
379                 return rc;
380         }
381
382         return 0; /* The device is not a lustre target. */
383 }
384
385 /* Build fs according to type */
386 int make_lustre_backfs(struct mkfs_opts *mop)
387 {
388         char mkfs_cmd[512];
389         char buf[40];
390         char *dev;
391         int ret = 0;
392         int block_count = 0;
393
394         if (mop->mo_device_sz != 0) {
395                 if (mop->mo_device_sz < 8096){
396                         fprintf(stderr, "%s: size of filesystem must be larger "
397                                 "than 8MB, but is set to %lldKB\n",
398                                 progname, mop->mo_device_sz);
399                         return EINVAL;
400                 }
401                 block_count = mop->mo_device_sz / (L_BLOCK_SIZE >> 10);
402         }
403
404         if ((mop->mo_ldd.ldd_mount_type == LDD_MT_EXT3) ||
405             (mop->mo_ldd.ldd_mount_type == LDD_MT_LDISKFS)) {
406                 __u64 device_sz = mop->mo_device_sz;
407
408                 /* we really need the size */
409                 if (device_sz == 0) {
410                         device_sz = get_device_size(mop->mo_device);
411                         if (device_sz == 0)
412                                 return ENODEV;
413                 }
414
415                 /* Journal size in MB */
416                 if (strstr(mop->mo_mkfsopts, "-J") == NULL) {
417                         /* Choose our own default journal size */
418                         long journal_sz = 0, max_sz;
419                         if (device_sz > 1024 * 1024) /* 1GB */
420                                 journal_sz = (device_sz / 102400) * 4;
421                         /* man mkfs.ext3 */
422                         max_sz = (102400 * L_BLOCK_SIZE) >> 20; /* 400MB */
423                         if (journal_sz > max_sz)
424                                 journal_sz = max_sz;
425                         if (journal_sz) {
426                                 sprintf(buf, " -J size=%ld", journal_sz);
427                                 strcat(mop->mo_mkfsopts, buf);
428                         }
429                 }
430
431                 /* Default bytes_per_inode is block size */
432                 if (strstr(mop->mo_mkfsopts, "-i") == NULL) {
433                         long bytes_per_inode = 0;
434
435                         if (IS_MDT(&mop->mo_ldd))
436                                 bytes_per_inode = 4096;
437
438                         /* Allocate fewer inodes on large OST devices.  Most
439                            filesystems can be much more aggressive than even
440                            this. */
441                         if ((IS_OST(&mop->mo_ldd) && (device_sz > 1000000)))
442                                 bytes_per_inode = 16384;
443
444                         if (bytes_per_inode > 0) {
445                                 sprintf(buf, " -i %ld", bytes_per_inode);
446                                 strcat(mop->mo_mkfsopts, buf);
447                         }
448                 }
449
450                 /* This is an undocumented mke2fs option. Default is 128. */
451                 if (strstr(mop->mo_mkfsopts, "-I") == NULL) {
452                         long inode_size = 0;
453                         if (IS_MDT(&mop->mo_ldd)) {
454                                 if (mop->mo_stripe_count > 77)
455                                         inode_size = 512; /* bz 7241 */
456                                 /* cray stripes across all osts (>60) */
457                                 else if (mop->mo_stripe_count > 34)
458                                         inode_size = 2048;
459                                 else if (mop->mo_stripe_count > 13)
460                                         inode_size = 1024;
461                                 else
462                                         inode_size = 512;
463                         } else if (IS_OST(&mop->mo_ldd)) {
464                                 /* now as we store fids in EA on OST we need
465                                    to make inode bigger */
466                                 inode_size = 256;
467                         }
468
469                         if (inode_size > 0) {
470                                 sprintf(buf, " -I %ld", inode_size);
471                                 strcat(mop->mo_mkfsopts, buf);
472                         }
473
474                 }
475
476                 if (verbose < 2) {
477                         strcat(mop->mo_mkfsopts, " -q");
478                 }
479
480                 /* Enable hashed b-tree directory lookup in large dirs bz6224 */
481                 if (strstr(mop->mo_mkfsopts, "-O") == NULL) {
482                         strcat(mop->mo_mkfsopts, " -O dir_index");
483                 }
484
485                 /* Allow reformat of full devices (as opposed to
486                    partitions.)  We already checked for mounted dev. */
487                 strcat(mop->mo_mkfsopts, " -F");
488
489                 sprintf(mkfs_cmd, "mkfs.ext2 -j -b %d -L %s ", L_BLOCK_SIZE,
490                         mop->mo_ldd.ldd_svname);
491
492         } else if (mop->mo_ldd.ldd_mount_type == LDD_MT_REISERFS) {
493                 long journal_sz = 0; /* FIXME default journal size */
494                 if (journal_sz > 0) {
495                         sprintf(buf, " --journal_size %ld", journal_sz);
496                         strcat(mop->mo_mkfsopts, buf);
497                 }
498                 sprintf(mkfs_cmd, "mkreiserfs -ff ");
499
500         } else {
501                 fprintf(stderr,"%s: unsupported fs type: %d (%s)\n",
502                         progname, mop->mo_ldd.ldd_mount_type,
503                         MT_STR(&mop->mo_ldd));
504                 return EINVAL;
505         }
506
507         /* For loop device format the dev, not the filename */
508         dev = mop->mo_device;
509         if (mop->mo_flags & MO_IS_LOOP)
510                 dev = mop->mo_loopdev;
511
512         vprint(0, "formatting backing filesystem %s on %s\n",
513                MT_STR(&mop->mo_ldd), dev);
514         vprint(0, "\ttarget name  %s\n", mop->mo_ldd.ldd_svname);
515         vprint(0, "\t4k blocks     %d\n", block_count);
516         vprint(0, "\toptions       %s\n", mop->mo_mkfsopts);
517
518         /* mkfs_cmd's trailing space is important! */
519         strcat(mkfs_cmd, mop->mo_mkfsopts);
520         strcat(mkfs_cmd, " ");
521         strcat(mkfs_cmd, dev);
522         if (block_count != 0) {
523                 sprintf(buf, " %d", block_count);
524                 strcat(mkfs_cmd, buf);
525         }
526
527         vprint(0, "mkfs_cmd = %s\n", mkfs_cmd);
528         ret = run_command(mkfs_cmd);
529         if (ret) {
530                 fatal();
531                 fprintf(stderr, "Unable to build fs %s (%d)\n", dev, ret);
532                 goto out;
533         }
534
535 out:
536         return ret;
537 }
538
539 /* ==================== Lustre config functions =============*/
540
541 void print_ldd(char *str, struct lustre_disk_data *ldd)
542 {
543         printf("\n   %s:\n", str);
544         printf("Target:     %s\n", ldd->ldd_svname);
545         if (ldd->ldd_svindex == INDEX_UNASSIGNED)
546                 printf("Index:      unassigned\n");
547         else
548                 printf("Index:      %d\n", ldd->ldd_svindex);
549         printf("UUID:       %s\n", (char *)ldd->ldd_uuid);
550         printf("Lustre FS:  %s\n", ldd->ldd_fsname);
551         printf("Mount type: %s\n", MT_STR(ldd));
552         printf("Flags:      %#x\n", ldd->ldd_flags);
553         printf("              (%s%s%s%s%s%s%s%s)\n",
554                IS_MDT(ldd) ? "MDT ":"",
555                IS_OST(ldd) ? "OST ":"",
556                IS_MGS(ldd) ? "MGS ":"",
557                ldd->ldd_flags & LDD_F_NEED_INDEX ? "needs_index ":"",
558                ldd->ldd_flags & LDD_F_VIRGIN     ? "first_time ":"",
559                ldd->ldd_flags & LDD_F_UPDATE     ? "update ":"",
560                ldd->ldd_flags & LDD_F_WRITECONF  ? "writeconf ":"",
561                ldd->ldd_flags & LDD_F_UPGRADE14  ? "upgrade1.4 ":"");
562         printf("Persistent mount opts: %s\n", ldd->ldd_mount_opts);
563         printf("Parameters:%s\n", ldd->ldd_params);
564         printf("\n");
565 }
566
567 /* Write the server config files */
568 int write_local_files(struct mkfs_opts *mop)
569 {
570         char mntpt[] = "/tmp/mntXXXXXX";
571         char filepnm[128];
572         char *dev;
573         FILE *filep;
574         int ret = 0;
575
576         /* Mount this device temporarily in order to write these files */
577         if (!mkdtemp(mntpt)) {
578                 fprintf(stderr, "%s: Can't create temp mount point %s: %s\n",
579                         progname, mntpt, strerror(errno));
580                 return errno;
581         }
582
583         dev = mop->mo_device;
584         if (mop->mo_flags & MO_IS_LOOP)
585                 dev = mop->mo_loopdev;
586
587         ret = mount(dev, mntpt, MT_STR(&mop->mo_ldd), 0, NULL);
588         if (ret) {
589                 fprintf(stderr, "%s: Unable to mount %s: %s\n",
590                         progname, dev, strerror(errno));
591                 if (errno == ENODEV) {
592                         fprintf(stderr, "Is the %s module available?\n",
593                                 MT_STR(&mop->mo_ldd));
594                 }
595                 goto out_rmdir;
596         }
597
598         /* Set up initial directories */
599         sprintf(filepnm, "%s/%s", mntpt, MOUNT_CONFIGS_DIR);
600         ret = mkdir(filepnm, 0777);
601         if ((ret != 0) && (errno != EEXIST)) {
602                 fprintf(stderr, "%s: Can't make configs dir %s (%d)\n",
603                         progname, filepnm, ret);
604                 goto out_umnt;
605         } else if (errno == EEXIST) {
606                 ret = 0;
607         }
608
609         sprintf(filepnm, "%s/%s", mntpt, "ROOT");
610         ret = mkdir(filepnm, 0777);
611         if ((ret != 0) && (errno != EEXIST)) {
612                 fprintf(stderr, "%s: Can't make ROOT dir %s (%d)\n",
613                         progname, filepnm, ret);
614                 goto out_umnt;
615         } else if (errno == EEXIST) {
616                 ret = 0;
617         }
618
619         /* Save the persistent mount data into a file. Lustre must pre-read
620            this file to get the real mount options. */
621         vprint(0, "Writing %s\n", MOUNT_DATA_FILE);
622         sprintf(filepnm, "%s/%s", mntpt, MOUNT_DATA_FILE);
623         filep = fopen(filepnm, "w");
624         if (!filep) {
625                 fprintf(stderr, "%s: Unable to create %s file\n",
626                         progname, filepnm);
627                 goto out_umnt;
628         }
629         fwrite(&mop->mo_ldd, sizeof(mop->mo_ldd), 1, filep);
630         fclose(filep);
631         
632         /* COMPAT_146 */
633 #ifdef TUNEFS
634         /* Check for upgrade */
635         if ((mop->mo_ldd.ldd_flags & (LDD_F_UPGRADE14 | LDD_F_SV_TYPE_MGS)) 
636             == (LDD_F_UPGRADE14 | LDD_F_SV_TYPE_MGS)) {
637                 char cmd[128];
638                 char *term;
639                 vprint(0, "Copying old logs\n");
640 #if 0
641  /* Generate new client log as servers upgrade.  Starting a new client 
642     may end up with short lov's, so will be degraded until all servers
643     upgrade */
644                 /* Copy the old client log to fsname-client */
645                 sprintf(filepnm, "%s/%s/%s-client", 
646                         mntpt, MOUNT_CONFIGS_DIR, mop->mo_ldd.ldd_fsname);
647                 sprintf(cmd, "cp %s/%s/client %s", mntpt, MDT_LOGS_DIR,
648                         filepnm);
649                 vprint(1, "cmd: %s\n", cmd);
650                 ret = run_command(cmd);
651                 if (ret) {
652                         fprintf(stderr, "%s: Can't copy 1.4 config %s/client "
653                                 "(%d)\n", progname, MDT_LOGS_DIR, ret);
654                         fprintf(stderr, "mount -t ext3 %s somewhere, "
655                                 "find the client log for fs %s and "
656                                 "copy it manually into %s/%s-client, "
657                                 "then umount.\n",
658                                 mop->mo_device, 
659                                 mop->mo_ldd.ldd_fsname, MOUNT_CONFIGS_DIR,
660                                 mop->mo_ldd.ldd_fsname);
661                         goto out_umnt;
662                 }
663  #endif
664                 /* We need to use the old mdt log because otherwise mdt won't
665                    have complete lov if old clients connect before all 
666                    servers upgrade. */
667                 /* Copy the old mdt log to fsname-MDT0000 (get old
668                    name from mdt_UUID) */
669                 ret = 1;
670                 strcpy(filepnm, mop->mo_ldd.ldd_uuid);
671                 term = strstr(filepnm, "_UUID");
672                 if (term) {
673                         *term = '\0';
674                         sprintf(cmd, "cp %s/%s/%s %s/%s/%s",
675                                 mntpt, MDT_LOGS_DIR, filepnm, 
676                                 mntpt, MOUNT_CONFIGS_DIR,
677                                 mop->mo_ldd.ldd_svname);
678                         vprint(1, "cmd: %s\n", cmd);
679                         ret = run_command(cmd);
680                 }
681                 if (ret) {
682                         fprintf(stderr, "%s: Can't copy 1.4 config %s/%s "
683                                 "(%d)\n", progname, MDT_LOGS_DIR, filepnm, ret);
684                         fprintf(stderr, "mount -t ext3 %s somewhere, "
685                                 "find the MDT log for fs %s and "
686                                 "copy it manually into %s/%s, "
687                                 "then umount.\n",
688                                 mop->mo_device, 
689                                 mop->mo_ldd.ldd_fsname, MOUNT_CONFIGS_DIR,
690                                 mop->mo_ldd.ldd_svname);
691                         goto out_umnt;
692                 }
693         }
694 #endif
695         /* end COMPAT_146 */
696
697
698 out_umnt:
699         umount(mntpt);    
700 out_rmdir:
701         rmdir(mntpt);
702         return ret;
703 }
704
705 int read_local_files(struct mkfs_opts *mop)
706 {
707         char mntpt[] = "/tmp/mntXXXXXX";
708         char filepnm[128];
709         char *dev;
710         FILE *filep;
711         int ret = 0;
712
713         /* Mount this device temporarily in order to read these files */
714         if (!mkdtemp(mntpt)) {
715                 fprintf(stderr, "%s: Can't create temp mount point %s: %s\n",
716                         progname, mntpt, strerror(errno));
717                 return errno;
718         }
719
720         dev = mop->mo_device;
721         if (mop->mo_flags & MO_IS_LOOP) 
722                 dev = mop->mo_loopdev;
723         
724         ret = mount(dev, mntpt, MT_STR(&mop->mo_ldd), 0, NULL);
725         if (ret) {
726                 fprintf(stderr, "%s: Unable to mount %s: %s\n", 
727                         progname, dev, strerror(errno));
728                 goto out_rmdir;
729         }
730
731         sprintf(filepnm, "%s/%s", mntpt, MOUNT_DATA_FILE);
732         filep = fopen(filepnm, "r");
733         if (filep) {
734                 vprint(0, "Reading %s\n", MOUNT_DATA_FILE);
735                 fread(&mop->mo_ldd, sizeof(mop->mo_ldd), 1, filep);
736         } else {
737                 /* COMPAT_146 */
738                 /* Try to read pre-1.6 config from last_rcvd */
739                 struct lr_server_data lsd;
740                 vprint(0, "%s: Unable to read %s, trying last_rcvd\n",
741                        progname, MOUNT_DATA_FILE);
742                 sprintf(filepnm, "%s/%s", mntpt, LAST_RCVD);
743                 filep = fopen(filepnm, "r");
744                 if (!filep) {
745                         fprintf(stderr, "%s: Unable to read old data\n",
746                                 progname);
747                         ret = -errno;
748                         goto out_umnt;
749                 }
750                 vprint(0, "Reading %s\n", LAST_RCVD);
751                 ret = fread(&lsd, 1, sizeof(lsd), filep);
752                 if (ret < sizeof(lsd)) {
753                         fprintf(stderr, "%s: Short read (%d of %d)\n",
754                                 progname, ret, sizeof(lsd));
755                         ret = -ferror(filep);
756                         if (ret) 
757                                 goto out_close;
758                 }
759                 ret = 0;
760                 if (lsd.lsd_feature_compat & OBD_COMPAT_OST) {
761                         mop->mo_ldd.ldd_flags = LDD_F_SV_TYPE_OST;
762                         mop->mo_ldd.ldd_svindex = lsd.lsd_ost_index;
763                 } else if (lsd.lsd_feature_compat & OBD_COMPAT_MDT) {
764                         /* We must co-locate so mgs can see old logs.
765                            If user doesn't want this, they can copy the old
766                            logs manually and re-tunefs. */
767                         mop->mo_ldd.ldd_flags = 
768                                 LDD_F_SV_TYPE_MDT | LDD_F_SV_TYPE_MGS;
769                         mop->mo_ldd.ldd_svindex = lsd.lsd_mdt_index;
770                 } else  {
771                         /* If neither is set, we're pre-1.4.6, make a guess. */
772                         sprintf(filepnm, "%s/%s", mntpt, MDT_LOGS_DIR);
773                         if (lsd.lsd_ost_index > 0) {
774                                 mop->mo_ldd.ldd_flags = LDD_F_SV_TYPE_OST;
775                                 mop->mo_ldd.ldd_svindex = lsd.lsd_ost_index;
776                         } else {
777                                 /* If there's a LOGS dir, it's an MDT */
778                                 if ((ret = access(filepnm, F_OK)) == 0) {
779                                         mop->mo_ldd.ldd_flags =
780                                         LDD_F_SV_TYPE_MDT | 
781                                         LDD_F_SV_TYPE_MGS;
782                                         /* Old MDT's are always index 0 
783                                            (pre CMD) */
784                                         mop->mo_ldd.ldd_svindex = 0;
785                                 } else {
786                                         /* The index won't be correct */
787                                         mop->mo_ldd.ldd_flags =
788                                         LDD_F_SV_TYPE_OST | LDD_F_NEED_INDEX;
789                                 }
790                         }
791                 }
792
793                 memcpy(mop->mo_ldd.ldd_uuid, lsd.lsd_uuid, 
794                        sizeof(mop->mo_ldd.ldd_uuid));
795                 mop->mo_ldd.ldd_flags |= LDD_F_UPGRADE14;
796         }
797         /* end COMPAT_146 */
798 out_close:        
799         fclose(filep);
800         
801 out_umnt:
802         umount(mntpt);    
803 out_rmdir:
804         rmdir(mntpt);
805         return ret;
806 }
807
808
809 void set_defaults(struct mkfs_opts *mop)
810 {
811         mop->mo_ldd.ldd_magic = LDD_MAGIC;
812         mop->mo_ldd.ldd_config_ver = 1;
813         mop->mo_ldd.ldd_flags = LDD_F_NEED_INDEX | LDD_F_UPDATE | LDD_F_VIRGIN;
814         mop->mo_mgs_failnodes = 0;
815         strcpy(mop->mo_ldd.ldd_fsname, "lustre");
816         if (get_os_version() == 24) 
817                 mop->mo_ldd.ldd_mount_type = LDD_MT_EXT3;
818         else 
819                 mop->mo_ldd.ldd_mount_type = LDD_MT_LDISKFS;
820         
821         mop->mo_ldd.ldd_svindex = INDEX_UNASSIGNED;
822         mop->mo_stripe_count = 1;
823 }
824
825 static inline void badopt(const char *opt, char *type)
826 {
827         fprintf(stderr, "%s: '--%s' only valid for %s\n",
828                 progname, opt, type);
829         usage(stderr);
830 }
831
832 static int add_param(char *buf, char *key, char *val)
833 {
834         int end = sizeof(((struct lustre_disk_data *)0)->ldd_params);
835         int start = strlen(buf);
836         int keylen = 0;
837
838         if (key) 
839                 keylen = strlen(key);
840         if (start + 1 + keylen + strlen(val) >= end) {
841                 fprintf(stderr, "%s: params are too long-\n%s %s%s\n",
842                         progname, buf, key ? key : "", val);
843                 return 1;
844         }
845
846         sprintf(buf + start, " %s%s", key ? key : "", val);
847         return 0;
848 }
849
850 /* from mount_lustre */
851 /* Get rid of symbolic hostnames for tcp, since kernel can't do lookups */
852 #define MAXNIDSTR 1024
853 static char *convert_hostnames(char *s1)
854 {
855         char *converted, *s2 = 0, *c;
856         int left = MAXNIDSTR;
857         lnet_nid_t nid;
858         
859         converted = malloc(left);
860         if (converted == NULL) {
861                 return NULL;
862         }
863
864         c = converted;
865         while ((left > 0) && ((s2 = strsep(&s1, ",: \0")))) {
866                 nid = libcfs_str2nid(s2);
867                 if (nid == LNET_NID_ANY) {
868                         if (*s2 == '/') 
869                                 /* end of nids */
870                                 break;
871                         fprintf(stderr, "%s: Can't parse NID '%s'\n", 
872                                 progname, s2);
873                         free(converted);
874                         return NULL;
875                 }
876                 if (LNET_NETTYP(LNET_NIDNET(nid)) == SOCKLND) {
877                         __u32 addr = LNET_NIDADDR(nid);
878                         c += snprintf(c, left, "%u.%u.%u.%u@%s%u,",
879                                       (addr >> 24) & 0xff, (addr >> 16) & 0xff,
880                                       (addr >> 8) & 0xff, addr & 0xff,
881                                       libcfs_lnd2str(SOCKLND), 
882                                       LNET_NETNUM(LNET_NIDNET(nid)));
883                 } else {
884                         c += snprintf(c, left, "%s,", s2);
885                 }
886                 left = converted + MAXNIDSTR - c;
887         }
888         *(c - 1) = '\0';
889         return converted;
890 }
891
892 int parse_opts(int argc, char *const argv[], struct mkfs_opts *mop,
893                char **mountopts)
894 {
895         static struct option long_opt[] = {
896                 {"backfstype", 1, 0, 'b'},
897                 {"stripe-count-hint", 1, 0, 'c'},
898                 {"configdev", 1, 0, 'C'},
899                 {"device-size", 1, 0, 'd'},
900                 {"erase-params", 0, 0, 'e'},
901                 {"failnode", 1, 0, 'f'},
902                 {"failover", 1, 0, 'f'},
903                 {"mgs", 0, 0, 'G'},
904                 {"help", 0, 0, 'h'},
905                 {"index", 1, 0, 'i'},
906                 {"mkfsoptions", 1, 0, 'k'},
907                 {"mgsnode", 1, 0, 'm'},
908                 {"mgsnid", 1, 0, 'm'},
909                 {"mdt", 0, 0, 'M'},
910                 {"fsname",1, 0, 'n'},
911                 {"nomgs", 0, 0, 'N'},
912                 {"mountfsoptions", 1, 0, 'o'},
913                 {"ost", 0, 0, 'O'},
914                 {"param", 1, 0, 'p'},
915                 {"print", 0, 0, 'P'},
916                 {"quiet", 0, 0, 'q'},
917                 {"reformat", 0, 0, 'r'},
918                 {"verbose", 0, 0, 'v'},
919                 {"writeconf", 0, 0, 'w'},
920                 {0, 0, 0, 0}
921         };
922         char *optstring = "b:c:C:d:ef:Ghi:k:m:Mn:No:Op:Pqrvw";
923         char opt;
924         int rc, longidx;
925
926         while ((opt = getopt_long(argc, argv, optstring, long_opt, &longidx)) != 
927                EOF) {
928                 switch (opt) {
929                 case 'b': {
930                         int i = 0;
931                         while (i < LDD_MT_LAST) {
932                                 if (strcmp(optarg, mt_str(i)) == 0) {
933                                         mop->mo_ldd.ldd_mount_type = i;
934                                         break;
935                                 }
936                                 i++;
937                         }
938                         break;
939                 }
940                 case 'c':
941                         if (IS_MDT(&mop->mo_ldd)) {
942                                 int stripe_count = atol(optarg);
943                                 if (stripe_count <= 0) {
944                                         fprintf(stderr, "%s: bad stripe count "
945                                                 "%d\n", progname, stripe_count);
946                                         return 1;
947                                 }
948                                 mop->mo_stripe_count = stripe_count;
949                         } else {
950                                 badopt(long_opt[longidx].name, "MDT");
951                                 return 1;
952                         }
953                         break;
954                 case 'C': /* Configdev */
955                         //FIXME
956                         printf("Configdev not implemented\n");
957                         return 1;
958                 case 'd':
959                         mop->mo_device_sz = atol(optarg); 
960                         break;
961                 case 'e':
962                         mop->mo_ldd.ldd_params[0] = '\0';
963                         break;
964                 case 'f': {
965                         char *nids = convert_hostnames(optarg);
966                         if (!nids) 
967                                 return 1;
968                         rc = add_param(mop->mo_ldd.ldd_params, PARAM_FAILNODE, 
969                                        nids); 
970                         free(nids);
971                         if (rc) 
972                                 return rc;
973                         break;
974                 }
975                 case 'G':
976                         mop->mo_ldd.ldd_flags |= LDD_F_SV_TYPE_MGS;
977                         break;
978                 case 'h':
979                         usage(stdout);
980                         return 1;
981                 case 'i':
982                         if (IS_MDT(&mop->mo_ldd) || IS_OST(&mop->mo_ldd)) {
983                                 mop->mo_ldd.ldd_svindex = atol(optarg);
984                                 mop->mo_ldd.ldd_flags &= ~LDD_F_NEED_INDEX;
985                         } else {
986                                 badopt(long_opt[longidx].name, "MDT,OST");
987                                 return 1;
988                         }
989                         break;
990                 case 'k':
991                         strncpy(mop->mo_mkfsopts, optarg, 
992                                 sizeof(mop->mo_mkfsopts) - 1);
993                         break;
994                 case 'm': {
995                         char *nids = convert_hostnames(optarg);
996                         if (!nids) 
997                                 return 1;
998                         rc = add_param(mop->mo_ldd.ldd_params, PARAM_MGSNODE, 
999                                        nids); 
1000                         free(nids);
1001                         if (rc) 
1002                                 return rc;
1003                         mop->mo_mgs_failnodes++;
1004                         break;
1005                 }
1006                 case 'M':
1007                         mop->mo_ldd.ldd_flags |= LDD_F_SV_TYPE_MDT;
1008                         break;
1009                 case 'n':
1010                         if (!(IS_MDT(&mop->mo_ldd) || IS_OST(&mop->mo_ldd))) {
1011                                 badopt(long_opt[longidx].name, "MDT,OST");
1012                                 return 1;
1013                         }
1014                         if (strlen(optarg) > 8) {
1015                                 fprintf(stderr, "%s: filesystem name must be "
1016                                         "<= 8 chars\n", progname);
1017                                 return 1;
1018                         }
1019                         if (optarg[0] != 0) 
1020                                 strncpy(mop->mo_ldd.ldd_fsname, optarg, 
1021                                         sizeof(mop->mo_ldd.ldd_fsname) - 1);
1022                         break;
1023                 case 'N':
1024                         mop->mo_ldd.ldd_flags &= ~LDD_F_SV_TYPE_MGS;
1025                         break;
1026                 case 'o':
1027                         *mountopts = optarg;
1028                         break;
1029                 case 'O':
1030                         mop->mo_ldd.ldd_flags |= LDD_F_SV_TYPE_OST;
1031                         break;
1032                 case 'p':
1033                         rc = add_param(mop->mo_ldd.ldd_params, NULL, optarg);
1034                         if (rc) 
1035                                 return rc;
1036                         break;
1037                 case 'P':
1038                         print_only++;
1039                         break;
1040                 case 'q':
1041                         verbose--;
1042                         break;
1043                 case 'r':
1044                         mop->mo_flags |= MO_FORCEFORMAT;
1045                         break;
1046                 case 'v':
1047                         verbose++;
1048                         break;
1049                 case 'w':
1050                         mop->mo_ldd.ldd_flags |= LDD_F_WRITECONF;
1051                         break;
1052                 default:
1053                         if (opt != '?') {
1054                                 fatal();
1055                                 fprintf(stderr, "Unknown option '%c'\n", opt);
1056                         }
1057                         usage(stderr);
1058                         return 1;
1059                 }
1060         }//while
1061         if (optind >= argc) {
1062                 fatal();
1063                 fprintf(stderr, "Bad arguments\n");
1064                 usage(stderr);
1065                 return 1;
1066         }
1067
1068         return 0;
1069 }
1070
1071 #include <lustre/libiam.h>
1072
1073 #define LDISKFS_IOC_GETVERSION _IOR('f', 3, long)
1074
1075 static int mkfs_iam_insert(int key_need_convert, char *keybuf,
1076                            int rec_need_convert, char *recbuf, char *filename)
1077 {
1078         int fd;
1079         int ret;
1080         struct iam_uapi_info ua;
1081
1082         fd = iam_open(filename, &ua);
1083         if (fd < 0) {
1084                 fprintf(stderr, "failed to iam_open %s\n", filename);
1085                 return 1;
1086         }
1087
1088         ret = iam_insert(fd, &ua,
1089                          key_need_convert, keybuf,
1090                          rec_need_convert, recbuf);
1091         iam_close(fd);
1092         if (ret) {
1093                 fprintf(stderr, "failed to iam_insert %s\n", filename);
1094                 return 1;
1095         } else {
1096                 return 0;
1097         }
1098 }
1099
1100 static int touch_file(char *filename)
1101 {
1102         int fd;
1103
1104         if (filename == NULL) {
1105                 return 1;
1106         }
1107
1108         fd = open(filename, O_CREAT | O_TRUNC, 0600);
1109         if (fd < 0) {
1110                 return 1;
1111         } else {
1112                 close(fd);
1113                 return 0;
1114         }
1115 }
1116
1117 static int get_generation(char *filename, unsigned long *result)
1118 {
1119         int fd;
1120         int ret;
1121
1122         if (filename == NULL) {
1123                 return 1;
1124         }
1125
1126         fd = open(filename, O_RDONLY);
1127         if (fd < 0) {
1128                 fprintf(stderr, "%s: failed to open %s\n",
1129                         __FUNCTION__, filename);
1130                 return 1;
1131         }
1132
1133         ret = ioctl(fd, LDISKFS_IOC_GETVERSION, result);
1134         close(fd);
1135
1136         return ((ret < 0) ? ret : 0);
1137 }
1138
1139 static int mkfs_mdt(struct mkfs_opts *mop)
1140 {
1141         char mntpt[] = "/tmp/mntXXXXXX";
1142         char fstype[] = "ldiskfs";
1143         char filepnm[128];
1144         char recbuf[64];
1145         char *source;
1146         int ret;
1147         unsigned long generation;
1148         struct stat st;
1149
1150         source = mop->mo_device;
1151         if (mop->mo_flags & MO_IS_LOOP) { 
1152                 source = mop->mo_loopdev;
1153         }
1154
1155         if ((source == NULL) || (*source == 0)) {
1156                 return 1;
1157         }
1158
1159         if (!mkdtemp(mntpt)) {
1160                 fprintf(stderr, "%s: failed to mkdtemp %s\n",
1161                         __FUNCTION__, mntpt);
1162                 return errno;
1163         }
1164
1165         ret = mount(source, mntpt, fstype, 0, NULL);
1166         if (ret) {
1167                 goto out_rmdir;
1168         }
1169
1170         snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "seq");
1171         ret = touch_file(filepnm);
1172         if (ret) {
1173                 goto out_umount;
1174         }
1175
1176         snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "last_rcvd");
1177         ret = touch_file(filepnm);
1178         if (ret) {
1179                 goto out_umount;
1180         }
1181
1182         snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "lov_objid");
1183         ret = touch_file(filepnm);
1184         if (ret) {
1185                 goto out_umount;
1186         }
1187
1188         snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "root");
1189         ret = iam_creat(filepnm, FMT_LVAR,
1190                         SET_DEFAULT, SET_DEFAULT, 16, SET_DEFAULT);
1191         if (ret) {
1192                 goto out_umount;
1193         }
1194
1195         snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "fld");
1196         ret = iam_creat(filepnm, FMT_LFIX,
1197                         SET_DEFAULT, 8, 8, SET_DEFAULT);
1198         if (ret) {
1199                 goto out_umount;
1200         }
1201
1202         snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "oi");
1203         ret = iam_creat(filepnm, FMT_LFIX,
1204                         SET_DEFAULT, 16, 16, SET_DEFAULT);
1205         if (ret) {
1206                 goto out_umount;
1207         }
1208
1209         umount(mntpt);
1210         ret = mount(source, mntpt, fstype, 0, NULL);
1211         if (ret) {
1212                 goto out_rmdir;
1213         }
1214
1215         snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "root");
1216         ret = iam_polymorph(filepnm, 040755);
1217         if (ret) {
1218                 perror("IAM_IOC_POLYMORPH");
1219                 goto out_umount;
1220         }
1221
1222         umount(mntpt);
1223         ret = mount(source, mntpt, fstype, 0, NULL);
1224         if (ret) {
1225                 goto out_rmdir;
1226         }
1227
1228         snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "fld");
1229         ret = mkfs_iam_insert(1, "0000000000000002", 1, "0000000000000000", filepnm);
1230         if (ret) {
1231                 goto out_umount;
1232         }
1233
1234         ret = mkfs_iam_insert(1, "0000000000000001", 1, "0000000000000000", filepnm);
1235         if (ret) {
1236                 goto out_umount;
1237         }
1238
1239         snprintf(filepnm, sizeof(filepnm) - 1, "%s/%s", mntpt, "root");
1240         ret = stat(filepnm, &st);
1241         if (ret) {
1242                 goto out_umount;
1243         }
1244
1245         ret = get_generation(filepnm, &generation);
1246         if (ret) {
1247                 goto out_umount;
1248         }
1249
1250         snprintf(recbuf, sizeof(recbuf) - 1, "0000000000000001%8.8x%8.8x",
1251                  (unsigned int)generation, (unsigned int)st.st_ino);
1252         ret = mkfs_iam_insert(0, ".", 1, recbuf, filepnm);
1253         if (ret) {
1254                 goto out_umount;
1255         }
1256
1257         ret = mkfs_iam_insert(0, "..", 1, recbuf, filepnm);
1258         if (ret) {
1259                 goto out_umount;
1260         }
1261
1262 out_umount:
1263         umount(mntpt);
1264 out_rmdir:
1265         rmdir(mntpt);
1266         return ret;
1267 }
1268
1269 int main(int argc, char *argv[])
1270 {
1271         struct mkfs_opts mop;
1272         struct lustre_disk_data *ldd;
1273         char *mountopts = NULL;
1274         char always_mountopts[512] = "";
1275         char default_mountopts[512] = "";
1276         int ret = 0;
1277
1278         //printf("pad %d\n", offsetof(struct lustre_disk_data, ldd_padding));
1279         assert(offsetof(struct lustre_disk_data, ldd_padding) == 200);
1280         
1281         if ((progname = strrchr(argv[0], '/')) != NULL)
1282                 progname++;
1283         else
1284                 progname = argv[0];
1285
1286         if (argc < 2) {
1287                 usage(stderr);
1288                 ret = 1;
1289                 goto out;
1290         }
1291
1292         memset(&mop, 0, sizeof(mop));
1293         set_defaults(&mop);
1294
1295         /* device is last arg */
1296         strcpy(mop.mo_device, argv[argc - 1]);
1297
1298         if (check_mtab_entry(mop.mo_device, "lustre"))
1299                 return(EEXIST);
1300
1301         /* Are we using a loop device? */
1302         ret = is_block(mop.mo_device);
1303         if (ret < 0) 
1304                 goto out;
1305         if (ret == 0) 
1306                 mop.mo_flags |= MO_IS_LOOP;
1307
1308 #ifdef TUNEFS
1309         /* For tunefs, we must read in the old values before parsing any
1310            new ones. */
1311         /* Create the loopback file */
1312         if (mop.mo_flags & MO_IS_LOOP) {
1313                 ret = access(mop.mo_device, F_OK);
1314                 if (ret == 0)  
1315                         ret = loop_setup(&mop);
1316                 if (ret) {
1317                         fatal();
1318                         fprintf(stderr, "Loop device setup for %s failed: %s\n", 
1319                                 mop.mo_device, strerror(ret));
1320                         goto out;
1321                 }
1322         }
1323         
1324         /* Check whether the disk has already been formatted by mkfs.lustre */
1325         ret = is_lustre_target(&mop);
1326         if (ret == 0) {
1327                 fatal();
1328                 fprintf(stderr, "Device %s has not been formatted with "
1329                         "mkfs.lustre\n", mop.mo_device);
1330                 goto out;
1331         }
1332
1333         ret = read_local_files(&mop);
1334         if (ret) {
1335                 fatal();
1336                 fprintf(stderr, "Failed to read previous Lustre data from %s\n",
1337                         mop.mo_device);
1338                 goto out;
1339         }
1340
1341         if (verbose > 0) 
1342                 print_ldd("Read previous values", &(mop.mo_ldd));
1343 #endif
1344
1345         ret = parse_opts(argc, argv, &mop, &mountopts);
1346         if (ret) 
1347                 goto out;
1348
1349         ldd = &mop.mo_ldd;
1350         if (!(IS_MDT(ldd) || IS_OST(ldd) || IS_MGS(ldd))) {
1351                 fatal();
1352                 fprintf(stderr, "must set target type :{mdt,ost,mgs}\n");
1353                 usage(stderr);
1354                 ret = 1;
1355                 goto out;
1356         }
1357
1358         if (IS_MDT(ldd) && !IS_MGS(ldd) && (mop.mo_mgs_failnodes == 0)) {
1359                 vprint(0, "No management node specified, adding MGS to this "
1360                        "MDT\n");
1361                 ldd->ldd_flags |= LDD_F_SV_TYPE_MGS;
1362         }
1363
1364         if (!IS_MGS(ldd) && (mop.mo_mgs_failnodes == 0)) {
1365                 fatal();
1366                 fprintf(stderr, "Must specify either --mgs or --mgsnode\n");
1367                 usage(stderr);
1368                 goto out;
1369         }
1370
1371         /* These are the permanent mount options (always included) */ 
1372         switch (ldd->ldd_mount_type) {
1373                 case LDD_MT_EXT3:
1374                 case LDD_MT_LDISKFS: {
1375                         sprintf(always_mountopts, "errors=remount-ro");
1376                         if (IS_MDT(ldd) || IS_MGS(ldd))
1377                                 strcat(always_mountopts,
1378                                        ",iopen_nopriv,user_xattr");
1379                         if ((get_os_version() == 24) && IS_OST(ldd))
1380                                 strcat(always_mountopts, ",asyncdel");
1381 #if 0
1382                         /* Files created while extents are enabled cannot be
1383                            read if mounted with a kernel that doesn't include
1384                            the CFS patches.*/
1385                         if (IS_OST(ldd) && 
1386                             ldd->ldd_mount_type == LDD_MT_LDISKFS) {
1387                                 strcat(default_mountopts, ",extents,mballoc");
1388                         }
1389 #endif 
1390                         break;
1391                 }
1392                 case LDD_MT_SMFS: {
1393                         mop.mo_flags |= MO_IS_LOOP;
1394                         sprintf(always_mountopts, "type=ext3,dev=%s",
1395                                 mop.mo_device);
1396                         break;
1397                 }
1398                 default: {
1399                         fatal();
1400                         fprintf(stderr, "unknown fs type %d '%s'\n",
1401                                 ldd->ldd_mount_type, MT_STR(ldd));
1402                         ret = EINVAL;
1403                         goto out;
1404                 }
1405         }               
1406
1407         if (mountopts) {
1408                 /* If user specifies mount opts, don't use defaults,
1409                    but always use always_mountopts */
1410                 sprintf(ldd->ldd_mount_opts, "%s,%s", 
1411                         always_mountopts, mountopts);
1412         } else {
1413 #ifdef TUNEFS
1414                 if (ldd->ldd_mount_opts[0] == 0) 
1415                         /* use the defaults unless old opts exist */
1416 #endif
1417                 {
1418                         if (default_mountopts[0]) 
1419                                 sprintf(ldd->ldd_mount_opts, "%s,%s", 
1420                                         always_mountopts, default_mountopts);
1421                         else
1422                                 strcpy(ldd->ldd_mount_opts,
1423                                        always_mountopts);
1424                 }
1425         }
1426
1427         server_make_name(ldd->ldd_flags, ldd->ldd_svindex,
1428                          ldd->ldd_fsname, ldd->ldd_svname);
1429
1430         if (verbose > 0)
1431                 print_ldd("Permanent disk data", ldd);
1432
1433         if (print_only) {
1434                 printf("exiting before disk write.\n");
1435                 goto out;
1436         }
1437
1438 #ifndef TUNEFS /* mkfs.lustre */
1439         /* Create the loopback file of the correct size */
1440         if (mop.mo_flags & MO_IS_LOOP) {
1441                 ret = access(mop.mo_device, F_OK);
1442                 /* Don't destroy the loopback file if no FORCEFORMAT */
1443                 if (ret || (mop.mo_flags & MO_FORCEFORMAT))
1444                         ret = loop_format(&mop);
1445                 if (ret == 0)  
1446                         ret = loop_setup(&mop);
1447                 if (ret) {
1448                         fatal();
1449                         fprintf(stderr, "Loop device setup failed: %s\n", 
1450                                 strerror(ret));
1451                         goto out;
1452                 }
1453         }
1454
1455         /* Check whether the disk has already been formatted by mkfs.lustre */
1456         if (!(mop.mo_flags & MO_FORCEFORMAT)) {
1457                 ret = is_lustre_target(&mop);
1458                 if (ret) {
1459                         fatal();
1460                         fprintf(stderr, "Device %s was previously formatted " 
1461                                 "for lustre. Use --reformat to reformat it, "
1462                                 "or tunefs.lustre to modify.\n",
1463                                 mop.mo_device);
1464                         goto out;
1465                 }
1466         }
1467
1468         /* Format the backing filesystem */
1469         ret = make_lustre_backfs(&mop);
1470         if (ret != 0) {
1471                 fatal();
1472                 fprintf(stderr, "mkfs failed %d\n", ret);
1473                 goto out;
1474         }
1475 #endif
1476
1477         ret = write_local_files(&mop);
1478         if (ret != 0) {
1479                 fatal();
1480                 fprintf(stderr, "failed to write local files\n");
1481                 goto out;
1482         }
1483
1484         if (IS_MDT(ldd)) {
1485                 ret = mkfs_mdt(&mop);
1486                 if (ret != 0) {
1487                         fprintf(stderr, "failed to mkfs_mdt\n");
1488                         goto out;
1489                 }
1490         }
1491
1492 out:
1493         loop_cleanup(&mop);      
1494         return ret;
1495 }