Whamcloud - gitweb
c27e4ca4ca79c7d7a643ac512ffd1537a21340c8
[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
32 #include <sys/types.h>
33 #include <sys/stat.h>
34
35 #include <string.h>
36 #include <getopt.h>
37
38 #include <linux/types.h>
39 #include <linux/lustre_disk.h>
40 #include <portals/ptlctl.h>
41 #include "obdctl.h"
42
43 /* So obd.o will link */
44 #include "parser.h"
45 command_t cmdlist[] = {
46         { 0, 0, 0, NULL }
47 };
48
49 /* FIXME */
50 #define MAX_LOOP_DEVICES 256
51
52 static char *progname;
53 static int verbose = 1;
54
55 /* for running system() */
56 static char cmd[128];
57 static char cmd_out[32][128];
58 static char *ret_file = "/tmp/mkfs.log";
59         
60 /* for init loop */
61 static char loop_base[20];
62
63 void usage(FILE *out)
64 {
65         fprintf(out, "usage: %s [options] <device>\n", progname);
66
67         fprintf(out, 
68                 "\t<device>:block device or file (e.g /dev/sda or /tmp/ost1)\n"
69                 "\toptions:\n"
70                 "\t\t--ost: object storage, mutually exclusive with mdt\n"
71                 "\t\t--mdt: metadata storage, mutually exclusive with ost\n"
72                 "\t\t--mgmt: configuration management service - one per site\n"
73                 "\t\t--mgmtnode=<mgtnode>[,<failover-mgtnode>]:nid of a remote\n"
74                 "\t\t\tmgmt node [and the failover mgmt node]\n"
75                 "\t\t--fsname=<filesystem_name>\n"
76                 "\t\t--configdev=<altdevice|file>: store configuration info\n"
77                 "\t\t\tfor this device on an alternate device\n"
78                 "\t\t--failover=<failover-address>\n"
79                 "\t\t--backfstype=<fstype>: backing fs type (ext3, ldiskfs)\n"
80                 "\t\t--device_size=#N(KB):device size \n"
81                 "\t\t--stripe_count=#N:number of stripe\n"
82                 "\t\t--stripe_size=#N(KB):stripe size\n"
83                 "\t\t--index=#N:target index\n"
84                 "\t\t--mountfsoptions=<opts>: permanent mount options\n"
85                 "\t\t--mkfsoptions=<opts>: format options\n"
86                 "\t\t--timeout=<secs>: system timeout period\n"
87                 "\t\t--startupwait=<secs>: time to wait for other servers to join\n"
88                 "\t\t--reformat: overwrite an existing disk\n"
89                 "\t\t--verbose\n");
90         exit(out != stdout);
91 }
92
93 #define vprint if (verbose) printf
94
95 static void fatal(void)
96 {
97         verbose = 0;
98         fprintf(stderr, "\n%s FATAL: ", progname);
99 }
100
101 inline unsigned int 
102 dev_major (unsigned long long int __dev)
103 {
104         return ((__dev >> 8) & 0xfff) | ((unsigned int) (__dev >> 32) & ~0xfff);
105 }
106
107 inline unsigned int
108 dev_minor (unsigned long long int __dev)
109 {
110         return (__dev & 0xff) | ((unsigned int) (__dev >> 12) & ~0xff);
111 }
112
113 int get_os_version()
114 {
115         static int version = 0;
116
117         if (!version) {
118                 int fd;
119                 char release[4] = "";
120
121                 fd = open("/proc/sys/kernel/osrelease", O_RDONLY);
122                 if (fd < 0) 
123                         fprintf(stderr, "Warning: Can't resolve kernel version,"
124                         " assuming 2.6\n");
125                 else {
126                         read(fd, release, 4);
127                         close(fd);
128                 }
129                 if (strncmp(release, "2.4.", 4) == 0) 
130                         version = 24;
131                 else 
132                         version = 26;
133         }
134         return version;
135 }
136
137 //Ugly implement. FIXME 
138 int run_command(char *cmd)
139 {
140        int i = 0,ret = 0;
141        FILE *rfile = NULL;
142
143        vprint("cmd: %s\n", cmd);
144        
145        strcat(cmd, " >");
146        strcat(cmd, ret_file);
147        strcat(cmd, " 2>&1");
148   
149        ret = system(cmd);
150
151        rfile = fopen(ret_file, "r");
152        if (rfile == NULL){
153                 fprintf(stderr,"Could not open %s \n",ret_file);
154                 exit(2);
155        }
156       
157        memset(cmd_out, 0, sizeof(cmd_out));
158        while (fgets(cmd_out[i], 128, rfile) != NULL) {
159                if (verbose > 2) printf("  _ %s", cmd_out[i]); 
160                i++;
161                if (i >= 32) {
162                        fprintf(stderr,"WARNING losing some output from %s",
163                                cmd);
164                        break;
165                }
166        }
167        fclose(rfile);
168
169        return ret;
170 }
171
172 static void run_command_out()
173 {
174         int i;
175         for (i = 0; i < 32; i++) {
176                 if (strlen(cmd_out[i]) == 0)
177                         break;
178                 fprintf(stderr, cmd_out[i]);
179         }
180 }
181
182 /* Figure out the loop device names */
183 void loop_init()
184 {
185         if (!access("/dev/loop0", F_OK | R_OK))
186                 strcpy(loop_base, "/dev/loop\0");
187         else if (!access("/dev/loop/0", F_OK | R_OK))
188                 strcpy(loop_base, "/dev/loop/\0");
189         else {
190                 fprintf(stderr, "can't access loop devices\n");
191                 exit(1);
192         }
193         return;
194 }
195
196 /* Setup a file in the first unused loop_device */
197 int loop_setup(struct mkfs_opts *mop)
198 {
199         char l_device[64];
200         int i,ret = 0;
201
202         for (i = 0; i < MAX_LOOP_DEVICES; i++) {
203                 sprintf(l_device, "%s%d", loop_base, i);
204                 if (access(l_device, F_OK | R_OK)) 
205                         break;
206
207                 sprintf(cmd, "losetup %s", l_device);
208                 ret = run_command(cmd);
209                 /* losetup gets 1 (256?) for good non-set-up device */
210                 if (ret) {
211                         sprintf(cmd, "losetup %s %s", l_device, mop->mo_device);
212                         ret = run_command(cmd);
213                         if (ret) {
214                                 fprintf(stderr, "error %d on losetup: %s\n",
215                                         ret, strerror(ret));
216                                 exit(8);
217                         }
218                         strcpy(mop->mo_loopdev, l_device);
219                         return ret;
220                 }
221         }
222         
223         fprintf(stderr,"out of loop devices!\n");
224         return EMFILE;
225 }
226
227 int loop_cleanup(struct mkfs_opts *mop)
228 {
229         int ret = 1;
230         if (mop->mo_flags & MO_IS_LOOP) {
231                 sprintf(cmd, "losetup -d %s", mop->mo_loopdev);
232                 ret = run_command(cmd);
233         }
234         return ret;
235 }
236
237 /* Determine if a device is a block device (as opposed to a file) */
238 int is_block(char* devname)
239 {
240         struct stat st;
241         int ret = 0;
242
243         ret = access(devname, F_OK);
244         if (ret != 0) 
245                 return 0;
246         ret = stat(devname, &st);
247         if (ret != 0) {
248                 fprintf(stderr, "cannot stat %s\n",devname);
249                 exit(4);
250         }
251         return S_ISBLK(st.st_mode);
252 }
253
254 /* Get the devsize from /proc/partitions with the major and minor number */
255 int device_size_proc(char* device) 
256 {
257         int major,minor,i,ret;
258         char *ma, *mi, *sz;
259         struct stat st;
260
261         ret = stat(device,&st);
262         if (ret != 0) {
263                 fprintf(stderr,"can not stat %s\n",device);
264                 exit(4);
265         }
266         major = dev_major(st.st_rdev);
267         minor = dev_minor(st.st_rdev);
268
269         sprintf(cmd, "cat /proc/partitions");
270         ret = run_command(cmd);
271         for (i = 0; i < 32; i++) {
272                 if (strlen(cmd_out[i]) == 0) 
273                         break;
274                 ma = strtok(cmd_out[i], " ");
275                 mi = strtok(NULL, " ");
276                 if ((major == atol(ma)) && (minor == atol(mi))) {
277                         sz = strtok(NULL," ");
278                         return atol(sz);
279                 }
280         }
281
282         return 0; //FIXME : no entries in /proc/partitions
283 }
284
285 void set_nid_pair(struct host_desc *nids, char *str)
286 {
287         nids->primary = libcfs_str2nid(str);
288         // FIXME secondary too (,altnid)
289 }
290
291 /* Write the server config files */
292 int write_local_files(struct mkfs_opts *mop)
293 {
294         struct lr_server_data lsd;
295         char mntpt[] = "/tmp/mntXXXXXX";
296         char filepnm[128];
297         char local_mount_opts[sizeof(mop->mo_ldd.ldd_mount_opts)] = "";
298         FILE *filep;
299         int ret = 0;
300
301         /* Mount this device temporarily in order to write these files */
302         vprint("mounting backing device\n");
303         if (!mkdtemp(mntpt)) {
304                 fprintf(stderr, "Can't create temp mount point %s: %s\n",
305                         mntpt, strerror(errno));
306                 return errno;
307         }
308
309         if (mop->mo_flags & MO_IS_LOOP) {
310                 /* ext3 can't understand iopen_nopriv, others */
311                 // FIXME ext3 on 2.6 can't. So use ldiskfs on 2.6
312                 if (strlen(mop->mo_ldd.ldd_mount_opts)) 
313                         snprintf(local_mount_opts, sizeof(local_mount_opts),
314                                  "loop,%s", mop->mo_ldd.ldd_mount_opts);
315                 else 
316                         sprintf(local_mount_opts, "loop");
317         }
318         sprintf(cmd, "mount -t %s %s%s %s %s",
319                 MT_STR(&mop->mo_ldd), strlen(local_mount_opts) ? "-o ": "", 
320                 local_mount_opts, mop->mo_device, mntpt);
321         ret = run_command(cmd);
322         if (ret) {
323                 fprintf(stderr, "Unable to mount %s\n", mop->mo_device);
324                 run_command_out();
325                 goto out_rmdir;
326         }
327
328         /* Set up initial directories */
329         sprintf(filepnm, "%s/%s", mntpt, MOUNT_CONFIGS_DIR);
330         ret = mkdir(filepnm, 0777);
331         if (ret) {
332                 fprintf(stderr, "Can't make configs dir %s (%d)\n", 
333                         filepnm, ret);
334                 goto out_umnt;
335         }
336
337         /* Save the persistent mount data into a file. Lustre must pre-read
338            this file to get the real mount options. */
339         vprint("Writing %s\n", MOUNT_DATA_FILE);
340         sprintf(filepnm, "%s/%s", mntpt, MOUNT_DATA_FILE);
341         filep = fopen(filepnm, "w");
342         if (!filep) {
343                 fprintf(stderr, "Unable to create %s file\n", filepnm);
344                 goto out_umnt;
345         }
346         fwrite(&mop->mo_ldd, sizeof(mop->mo_ldd), 1, filep);
347         fclose(filep);
348         
349         /* Create the inital last_rcvd file */
350         vprint("Writing %s\n", LAST_RCVD);
351         sprintf(filepnm, "%s/%s", mntpt, LAST_RCVD);
352         filep = fopen(filepnm, "w");
353         if (!filep) {
354                 ret = errno;
355                 fprintf(stderr,"Unable to create %s file\n", filepnm);
356                 goto out_umnt;
357         }
358         memset(&lsd, 0, sizeof(lsd));
359         strncpy(lsd.lsd_uuid, mop->mo_ldd.ldd_svname, sizeof(lsd.lsd_uuid));
360         lsd.lsd_index = mop->mo_index;
361         lsd.lsd_feature_compat |= cpu_to_le32(LR_COMPAT_COMMON_LR);
362         lsd.lsd_server_size = cpu_to_le32(LR_SERVER_SIZE);
363         lsd.lsd_client_start = cpu_to_le32(LR_CLIENT_START);
364         lsd.lsd_client_size = cpu_to_le16(LR_CLIENT_SIZE);
365         if (IS_MDT(&mop->mo_ldd))
366                 lsd.lsd_feature_rocompat = cpu_to_le32(MDS_ROCOMPAT_LOVOBJID);
367         
368         fwrite(&lsd, sizeof(lsd), 1, filep);
369         ret = 0;
370         fclose(filep);
371 out_umnt:
372         vprint("unmounting backing device\n");
373         sprintf(cmd, "umount %s", mntpt);
374         run_command(cmd);
375 out_rmdir:
376         rmdir(mntpt);
377         return ret;
378 }
379
380 int loop_format(struct mkfs_opts *mop)
381 {
382         int ret = 0;
383        
384         loop_init();
385
386         sprintf(cmd, "dd if=/dev/zero bs=1k count=0 seek=%ld of=%s", 
387                 mop->mo_device_sz, mop->mo_device);
388         ret = run_command(cmd);
389         if (ret != 0){
390                 fprintf(stderr, "Unable to create backing store: %d\n", ret);
391         }
392         return ret;
393 }
394
395 /* Build fs according to type */
396 int make_lustre_backfs(struct mkfs_opts *mop)
397 {
398         char mkfs_cmd[256];
399         char buf[40];
400         char *dev;
401         int ret = 0;
402         int block_count = 0;
403
404         if (mop->mo_device_sz != 0) {
405                 if (mop->mo_device_sz < 8096){
406                         fprintf(stderr, "size of filesystem must be larger "
407                                 "than 8MB, but is set to %ldKB\n",
408                                 mop->mo_device_sz);
409                         return EINVAL;
410                 }
411                 block_count = mop->mo_device_sz / 4; /* block size is 4096 */
412         }       
413         
414         if ((mop->mo_ldd.ldd_mount_type == LDD_MT_EXT3) ||
415             (mop->mo_ldd.ldd_mount_type == LDD_MT_LDISKFS)) { 
416                 long device_sz = mop->mo_device_sz;
417
418                 /* we really need the size */
419                 if (device_sz == 0){
420                         sprintf(cmd, "sfdisk -s %s", mop->mo_device);
421                         ret = run_command(cmd);
422                         if (ret == 0)
423                                 device_sz = atol(cmd_out[0]);
424                         else 
425                                 device_sz = device_size_proc(mop->mo_device);
426                 }           
427
428                 if (strstr(mop->mo_mkfsopts, "-J") == NULL) {
429                         /* Choose our own default journal size */
430                         long journal_sz = 0;
431                         if (device_sz > 1024 * 1024) 
432                                 journal_sz = (device_sz / 102400) * 4;
433                         if (journal_sz > 400)
434                                 journal_sz = 400;
435                         if (journal_sz) {
436                                 sprintf(buf, " -J size=%ld", journal_sz);
437                                 strcat(mop->mo_mkfsopts, buf);
438                         }
439                 }
440
441                 /* Default is block size */
442                 if (strstr(mop->mo_mkfsopts, "-i") == NULL) {
443                         long bytes_per_inode = 0;
444                                         
445                         if (IS_MDT(&mop->mo_ldd)) 
446                                 bytes_per_inode = 4096;
447
448                         /* Allocate fewer inodes on large OST devices.  Most
449                            filesystems can be much more aggressive than even 
450                            this. */
451                         if ((IS_OST(&mop->mo_ldd) && (device_sz > 1000000))) 
452                                 bytes_per_inode = 16384;
453                         
454                         if (bytes_per_inode > 0) {
455                                 sprintf(buf, " -i %ld", bytes_per_inode);
456                                 strcat(mop->mo_mkfsopts, buf);
457                         }
458                 }
459                 
460                 /* This is an undocumented mke2fs option. Default is 128. */
461                 if (strstr(mop->mo_mkfsopts, "-I") == NULL) {
462                         long inode_size = 0;
463                         if (IS_MDT(&mop->mo_ldd)) {
464                                 if (mop->mo_stripe_count > 77)
465                                         inode_size = 512; /* bz 7241 */
466                                 else if (mop->mo_stripe_count > 34)
467                                         inode_size = 2048;
468                                 else if (mop->mo_stripe_count > 13)
469                                         inode_size = 1024;
470                                 else 
471                                         inode_size = 512;
472                         }
473                         
474                         if (inode_size > 0) {
475                                 sprintf(buf, " -I %ld", inode_size);
476                                 strcat(mop->mo_mkfsopts, buf);
477                         }
478                         
479                 }
480
481                 sprintf(mkfs_cmd, "mkfs.ext2 -j -b 4096 -L %s ",
482                         mop->mo_ldd.ldd_svname);
483
484         } else if (mop->mo_ldd.ldd_mount_type == LDD_MT_REISERFS) {
485                 long journal_sz = 0;
486                 if (journal_sz > 0) { /* FIXME */
487                         sprintf(buf, " --journal_size %ld", journal_sz);
488                         strcat(mop->mo_mkfsopts, buf);
489                 }
490                 sprintf(mkfs_cmd, "mkreiserfs -ff ");
491
492         } else {
493                 fprintf(stderr,"unsupported fs type: %d (%s)\n",
494                         mop->mo_ldd.ldd_mount_type, 
495                         MT_STR(&mop->mo_ldd));
496                 return EINVAL;
497         }
498
499         /* Loop device? */
500         dev = mop->mo_device;
501         if (mop->mo_flags & MO_IS_LOOP) {
502                 ret = loop_format(mop);
503                 if (!ret)
504                         ret = loop_setup(mop);
505                 if (ret) {
506                         fatal();
507                         fprintf(stderr, "Loop device setup failed %d\n", ret);
508                         return ret;
509                 }
510                 dev = mop->mo_loopdev;
511         }
512         
513         vprint("formatting backing filesystem %s on %s\n",
514                MT_STR(&mop->mo_ldd), dev);
515         vprint("\tservice name  %s\n", mop->mo_ldd.ldd_svname);
516         vprint("\t4k blocks     %d\n", block_count);
517         vprint("\toptions       %s\n", mop->mo_mkfsopts);
518
519         /* mkfs_cmd's trailing space is important! */
520         strcat(mkfs_cmd, mop->mo_mkfsopts);
521         strcat(mkfs_cmd, " ");
522         strcat(mkfs_cmd, dev);
523         if (block_count != 0) {
524                 sprintf(buf, " %d", block_count);
525                 strcat(mkfs_cmd, buf);
526         }
527
528         vprint("mkfs_cmd = %s\n", mkfs_cmd);
529         ret = run_command(mkfs_cmd);
530         if (ret != 0) {
531                 fatal();
532                 fprintf(stderr, "Unable to build fs: %s \n", dev);
533                 run_command_out();
534                 goto out;
535         }
536
537         /* Enable hashed b-tree directory lookup in large dirs 
538            FIXME MDT only? */
539         if ((mop->mo_ldd.ldd_mount_type == LDD_MT_EXT3) ||
540             (mop->mo_ldd.ldd_mount_type == LDD_MT_LDISKFS)) { 
541                 sprintf(cmd, "tune2fs -O dir_index %s", dev);
542                 ret = run_command(cmd);
543                 if (ret) {
544                         fatal();
545                         fprintf(stderr,"Unable to enable htree: %s\n",
546                                 mop->mo_device);
547                         goto out;
548                 }
549         }
550
551 out:
552         loop_cleanup(mop);      
553         return ret;
554 }
555
556 static int load_module(char *module_name)
557 {
558         char buf[256];
559         int rc;
560         
561         vprint("loading %s\n", module_name);
562         sprintf(buf, "/sbin/modprobe %s", module_name);
563         rc = system(buf);
564         if (rc) {
565                 fprintf(stderr, "%s: failed to modprobe %s (%d)\n", 
566                         progname, module_name, rc);
567                 fprintf(stderr, "Check /etc/modules.conf\n");
568         }
569         return rc;
570 }
571
572 static int load_modules(struct mkfs_opts *mop)
573 {
574         int rc = 0;
575
576         //client: rc = load_module("lustre");
577         vprint("Loading modules...");
578
579         /* portals, ksocknal, fsfilt, etc. in modules.conf */
580         rc = load_module("_lustre");
581         if (rc) return rc;
582
583         /* FIXME currently use the MDT to write llogs, should be a MGS */
584         rc = load_module("mds");
585         vprint("done\n");
586         return rc;
587 }
588
589 static int jt_setup()
590 {
591         int ret;
592         /* FIXME uneeded? */
593         ret = access(PORTALS_DEV_PATH, F_OK);
594         if (ret) 
595                 system("mknod "PORTALS_DEV_PATH" c 10 240");
596         ret = access(OBD_DEV_PATH, F_OK);
597         if (ret) 
598                 system("mknod "OBD_DEV_PATH" c 10 241");
599
600         ptl_initialize(0, NULL);
601         obd_initialize(0, NULL);
602         return 0; 
603 }
604
605 /* see jt_ptl_network */
606 int jt_getnids(ptl_nid_t *nidarray, int maxnids)
607 {
608         struct portal_ioctl_data data;
609         int                      count;
610         int                      rc;
611
612         for (count = 0; count < maxnids; count++) {
613                 PORTAL_IOC_INIT (data);
614                 data.ioc_count = count;
615                 rc = l_ioctl(PORTALS_DEV_ID, IOC_PORTAL_GET_NI, &data);
616
617                 if (rc >= 0) {
618                         vprint("%s\n", libcfs_nid2str(data.ioc_nid));
619                         nidarray[count] = data.ioc_nid;
620                         continue;
621                 }
622
623                 if (errno == ENOENT)
624                         break;
625
626                 fprintf(stderr,"IOC_PORTAL_GET_NI error %d: %s\n",
627                         errno, strerror(errno));
628                 return -1;
629         }
630         
631         if (count == 0)
632                 printf("<no local networks>\n");
633         return count;
634 }
635
636 static void jt_print(char *cmd_name, int argc, char **argv)
637 {
638         int i = 0;
639         printf("%-20.20s: ", cmd_name);
640         while (i < argc) {
641                 printf("%s ", argv[i]);
642                 i++;
643         }
644         printf("\n");
645 }
646         
647 static int _do_jt(int (*cmd)(int argc, char **argv), char *cmd_name, ...)
648 {
649         va_list ap;
650         char *jt_cmds[10];
651         char *s;
652         int i = 0;
653         int ret;
654                 
655         va_start(ap, cmd_name);
656         while (i < 10) {
657                 s = va_arg(ap, char *);
658                 if (!s) 
659                         break;
660                 jt_cmds[i] = malloc(strlen(s) + 1);
661                 strcpy(jt_cmds[i], s);
662                 i++;
663         }
664         va_end(ap);
665
666         if (verbose) 
667                 jt_print(cmd_name, i, jt_cmds);
668
669         ret = (*cmd)(i, jt_cmds);
670         if (ret) 
671                 fprintf(stderr, "%s: jt_cmd %s: (%d) %s\n",
672                         progname, jt_cmds[0], ret, strerror(abs(ret)));
673
674         while (i) 
675                 free(jt_cmds[--i]);
676
677         return ret;
678 }
679
680 #define do_jt(cmd, a...)  if ((ret = _do_jt(cmd, #cmd, ## a))) goto out_jt
681 #define do_jt_noret(cmd, a...)  _do_jt(cmd, #cmd, ## a) 
682
683 int write_llog_files(struct mkfs_opts *mop)
684 {
685         char confname[] = "llog_writer";
686         char name[128];
687         char *dev;
688         int  ret = 0;
689
690         load_modules(mop);
691
692         vprint("Creating Lustre logs\n"); 
693         if ((ret = jt_setup()))
694                 return ret;
695         
696         /* debug info */
697         if (verbose >= 2) {
698                 do_jt_noret(jt_dbg_modules, "modules", 0);
699         }
700
701         dev = mop->mo_device;
702         if (mop->mo_flags & MO_IS_LOOP) {
703                 ret = loop_setup(mop);
704                 if (ret)
705                         return ret;
706                 dev = mop->mo_loopdev;
707         }
708
709         /* FIXME can't we just write these log files ourselves? Why do we 
710            have to go through an obd at all? jt_ioc_dump()? */
711         /* FIXME use mgmt server obd to write logs. Can start it by mounting
712            I think. */
713         /* Set up a temporary obd for writing logs. 
714            mds and confobd can handle OBD_IOC_DORECORD */
715         ret = do_jt_noret(jt_lcfg_attach, "attach", "mds"/*confobd*/, confname,
716                           mop->mo_ldd.ldd_svname/*uuid*/, 0);
717         if (ret)
718                 return ENODEV;
719         ret = do_jt_noret(jt_lcfg_device, "cfg_device", confname, 0);
720         if (ret)
721                 return ENODEV;
722         do_jt(jt_lcfg_setup,  "setup", dev,  
723               MT_STR(&mop->mo_ldd), /*mop->mo_ldd.ldd_mount_opts,*/ 0);
724         /* Record on this device. */
725         do_jt(jt_obd_device,  "device", confname, 0);
726
727         snprintf(name, sizeof(name), "%s-conf", mop->mo_ldd.ldd_svname);
728
729         if (IS_OST(&mop->mo_ldd)) {
730                 do_jt(jt_cfg_clear_log, "clear_log", name, 0);
731                 do_jt(jt_cfg_record,    "record", name, 0);
732                 do_jt(jt_lcfg_attach,   "attach", "obdfilter", 
733                       mop->mo_ldd.ldd_svname, mop->mo_ldd.ldd_svname/*uuid*/, 0);
734                 do_jt(jt_lcfg_device,   "cfg_device", mop->mo_ldd.ldd_svname, 0);
735                 /* FIXME setup needs to change - no disk info */
736                 do_jt(jt_lcfg_setup,    "setup", mop->mo_device, 
737                       MT_STR(&mop->mo_ldd),
738                       "f", /* f=recovery enabled, n=disabled */
739                       mop->mo_ldd.ldd_mount_opts, 0);
740                 do_jt(jt_cfg_endrecord, "endrecord", 0);
741                 do_jt(jt_cfg_dump_log,  "dump_log", name, 0);
742
743                 do_jt(jt_cfg_clear_log, "clear_log", "OSS-conf", 0);
744                 do_jt(jt_cfg_record,    "record", "OSS-conf", 0);
745                 do_jt(jt_lcfg_attach,   "attach", "ost", "OSS", "OSS_UUID", 0);
746                 do_jt(jt_lcfg_device,   "cfg_device", "OSS", 0);
747                 do_jt(jt_lcfg_setup,    "setup", 0);
748                 if (mop->mo_timeout)
749                         do_jt(jt_lcfg_set_timeout, "set_timeout", 
750                               mop->mo_timeout, 0);
751                 do_jt(jt_cfg_endrecord, "endrecord", 0);
752         }
753         
754         if (IS_MDT(&mop->mo_ldd)) {
755                 ptl_nid_t nidarray[128];
756                 char scnt[20], ssz[20], soff[20], spat[20];
757                 char cliname[sizeof(mop->mo_ldd.ldd_fsname)];
758                 char mdcname[sizeof(mop->mo_ldd.ldd_fsname)];
759                 ptl_nid_t nid;
760                 int numnids;
761
762                 /* Write mds-conf log */
763                 do_jt(jt_cfg_clear_log, "clear_log", name, 0);
764                 do_jt(jt_cfg_record,    "record", name, 0);
765                 do_jt(jt_lcfg_attach,   "attach", "mdt", "MDT", "MDT_UUID", 0);
766                 do_jt(jt_lcfg_device,   "cfg_device", "MDT", 0);
767                 do_jt(jt_lcfg_setup,    "setup", 0);
768                 do_jt(jt_lcfg_attach,   "attach", "mds", mop->mo_ldd.ldd_svname,
769                       mop->mo_ldd.ldd_svname/*uuid*/, 0);
770                 do_jt(jt_lcfg_device,   "cfg_device", mop->mo_ldd.ldd_svname, 0);
771                 do_jt(jt_lcfg_setup,    "setup", mop->mo_device,
772                       MT_STR(&mop->mo_ldd), mop->mo_ldd.ldd_svname, 
773                       mop->mo_ldd.ldd_mount_opts, 0);
774                 if (mop->mo_timeout)
775                         do_jt(jt_lcfg_set_timeout, "set_timeout", 
776                               mop->mo_timeout, 0);
777                 do_jt(jt_cfg_endrecord, "endrecord", 0);
778
779                 /* Write mds startup log */
780                 do_jt(jt_cfg_clear_log,  "clear_log", mop->mo_ldd.ldd_svname, 0);
781                 do_jt(jt_cfg_record,     "record", mop->mo_ldd.ldd_svname, 0);
782                 /*attach lov lov_conf_mdsA f0591_lov_conf_mdsA_224a85b5fc
783                   lov_setup lovA_UUID 0 1048576 0 0 ost1_UUID
784                   mount_option mdsA lov_conf_mdsA
785                 */
786                 snprintf(name, sizeof(name), "lov-%s", mop->mo_ldd.ldd_svname);
787                 do_jt(jt_lcfg_attach,    "attach", "lov", name, 
788                       name/*uuid*/, 0);
789                 snprintf(scnt, sizeof(scnt), "%d", mop->mo_stripe_count);
790                 snprintf(ssz, sizeof(ssz), "%d", mop->mo_stripe_sz);
791                 snprintf(soff, sizeof(soff), "%d", 0 /*FIXME?*/);
792                 snprintf(spat, sizeof(spat), "%d", mop->mo_stripe_pattern);
793                 do_jt(jt_lcfg_lov_setup, "lov_setup", name/*uuid*/,
794                       scnt, ssz, soff, spat, 0);
795                 /* Then for every failover ost pair we would add to mdt and client:
796 #03 L add_uuid nid=c0a80203 nal_type=0 0:(null) 1:NID_uml3_UUID
797 #04 L attach   0:OSC_uml1_ost1_MNT_client 1:osc 2:e61f5_lov1_84b41a5f41
798 #05 L setup    0:OSC_uml1_ost1_MNT_client 1:ost1_UUID 2:NID_uml3_UUID
799 #06 L add_uuid nid=c0a80204 nal_type=0 0:(null) 1:NID_uml4_UUID
800 #07 L add_conn 0:OSC_uml1_ost1_MNT_client 1:NID_uml4_UUID
801 #08 L lov_modify_tgts add 0:lov1 1:ost1_UUID 2: 3:
802                 */
803                 /* This was an old hack to pass the lov name to the MDS:
804                    mds_postsetup calls class_get_profile
805                    to lookup the lov name: (profile=mds,osc=lov,mdc=0);
806                    This command was originally intended for clients: 
807                    class_add_profile(profile,osc,mdc).  
808                    FIXME if we always make lovname=f(mdsname), we probably
809                    don't need this. */
810                 do_jt(jt_lcfg_mount_option, "mount_option", 
811                       mop->mo_ldd.ldd_svname/*mds*/, name/*lov*/, 0);
812                 if (mop->mo_timeout)
813                         do_jt(jt_lcfg_set_timeout, "set_timeout", 
814                               mop->mo_timeout, 0);
815                 do_jt(jt_cfg_endrecord, "endrecord", 0);
816
817                 /* Write client startup logs */
818                 numnids = jt_getnids(nidarray, 
819                                      sizeof(nidarray) / sizeof(nidarray[0]));
820 #if 0
821 //Let the MGS create the client logs after the MDT has registered 
822                 if (numnids <= 0) {
823                         fprintf(stderr, "%s: Can't figure out local nids, "
824                                 "skipping client log creation\n", progname);
825                         goto out_jt;
826                 }
827
828                 snprintf(mdcname, sizeof(mdcname), "%s-mdc", 
829                          mop->mo_ldd.ldd_fsname);
830                 while (numnids) {
831                         numnids--;
832                         nid = nidarray[numnids];
833                         snprintf(cliname, sizeof(cliname), "client-%s",
834                                  libcfs_net2str(PTL_NIDNET(nid)));
835                         vprint("log for %s\n", cliname);
836                         do_jt(jt_cfg_clear_log,  "clear_log", cliname, 0);
837                         do_jt(jt_cfg_record,     "record", cliname, 0);
838                         do_jt(jt_lcfg_attach,    "attach", "lov", name, 
839                               name/*uuid*/, 0);
840                         do_jt(jt_lcfg_lov_setup, "lov_setup", name/*uuid*/,
841                               scnt, ssz, soff, spat, 0);
842                 /* add osts here as in mdt above */
843                 /* add mdc
844 #09 L add_uuid nid=c0a80201 nal_type=0 0:(null) 1:NID_uml1_UUID
845 #10 L attach   0:MDC_uml1_mdsA_MNT_client 1:mdc 2:efdac_MNT_client_fec96dc7f9
846 #11 L setup    0:MDC_uml1_mdsA_MNT_client 1:mdsA_UUID 2:NID_uml1_UUID
847 #12 L add_uuid nid=c0a80202 nal_type=0 0:(null) 1:NID_uml2_UUID
848 #13 L add_conn 0:MDC_uml1_mdsA_MNT_client 1:NID_uml2_UUID
849                 */
850                         /* FIXME we need to put _all_possible_nids_ for 
851                            every server in the client startup llog.  client
852                            will then choose which nid to use. */
853                         do_jt(jt_lcfg_add_uuid, "add_uuid", 
854                               mop->mo_ldd.ldd_svname /*FIXME mds name */,
855                               libcfs_nid2str(mop->mo_hostnid.primary), 0);
856                         do_jt(jt_lcfg_attach,   "attach", "mdc", mdcname, 
857                               mdcname/*uuid*/, 0);
858                         do_jt(jt_lcfg_device,   "cfg_device", mdcname, 0);
859                         /* mdc_setup client_uuid server_uuid */
860                         do_jt(jt_lcfg_setup,    "setup", cliname, 
861                               mop->mo_ldd.ldd_svname, 0);
862                         if (mop->mo_hostnid.backup != PTL_NID_ANY) {
863                                 do_jt(jt_lcfg_add_uuid, "add_uuid", 
864                                       libcfs_nid2str(mop->mo_hostnid.backup),
865                                       mop->mo_hostnid.backup, 0);
866                                 do_jt(jt_lcfg_add_conn, "add_conn", 
867                                       libcfs_nid2str(mop->mo_hostnid.backup)/*uuid*/, 0);
868                         }
869                         do_jt(jt_lcfg_mount_option, "mount_option", 
870                               cliname, name/*osc(lov)*/, mdcname, 0);
871                         if (mop->mo_timeout)
872                                 do_jt(jt_lcfg_set_timeout, "set_timeout", 
873                                       mop->mo_timeout, 0);
874                 }
875 #endif
876         }
877
878 out_jt:        
879         if (ret)
880                 /* Assume we erred while writing a record */
881                 do_jt_noret(jt_cfg_endrecord, "endrecord", 0);
882         /* Clean up the confobd when we're done writing logs */
883         do_jt_noret(jt_lcfg_device, "cfg_device", confname, 0);
884         do_jt_noret(jt_obd_cleanup, "cleanup", 0);
885         do_jt_noret(jt_obd_detach,  "detach", 0);
886
887         obd_finalize(1, (char **)&name /*dummy*/);
888         loop_cleanup(mop);
889         return ret;
890 }
891
892 /* Make the mdt/ost server obd name based on the filesystem name */
893 static void make_sv_name(struct mkfs_opts *mop)
894 {
895         /* FIXME if we're not given an index, we have to change our name
896            later -- can't have two servers with the same name. 
897            So rewrite ost log, last_rcvd, and disk label, or we need to talk
898            to MGMT now to get index # */
899
900         if (IS_MDT(&mop->mo_ldd) || IS_OST(&mop->mo_ldd)) {
901                 sprintf(mop->mo_ldd.ldd_svname, "%.8s-%s%04x",
902                         mop->mo_ldd.ldd_fsname,
903                         IS_MDT(&mop->mo_ldd) ? "MDT" : "OST",  
904                         mop->mo_index);
905         } else {
906                 sprintf(mop->mo_ldd.ldd_svname, "MGMT");
907         }
908         vprint("Server name: %s\n", mop->mo_ldd.ldd_svname);
909 }
910
911 void set_defaults(struct mkfs_opts *mop)
912 {
913         char hostname[128];
914         mop->mo_ldd.ldd_magic = LDD_MAGIC;
915         mop->mo_ldd.ldd_flags = LDD_F_NEED_INDEX;
916
917         if (get_os_version() == 24) 
918                 mop->mo_ldd.ldd_mount_type = LDD_MT_EXT3;
919         else 
920                 mop->mo_ldd.ldd_mount_type = LDD_MT_LDISKFS;
921         
922         strcpy(mop->mo_ldd.ldd_fsname, "lustre");
923         mop->mo_stripe_count = 1;
924         mop->mo_index = -1;
925
926         gethostname(hostname, sizeof(hostname));
927         //mop->mo_hostnid.primary = libcfs_str2nid(hostname);
928 }
929
930 static inline void badopt(char opt, char *type)
931 {
932         fprintf(stderr, "%s: '%c' only valid for %s\n",
933                 progname, opt, type);
934         usage(stderr);
935         exit(1);
936 }
937
938 int main(int argc , char *const argv[])
939 {
940         struct mkfs_opts mop;
941         static struct option long_opt[] = {
942                 {"backfstype", 1, 0, 'b'},
943                 {"configdev", 1, 0, 'C'},
944                 {"device_size", 1, 0, 'd'},
945                 {"fsname",1, 0, 'n'},
946                 {"failover", 1, 0, 'f'},
947                 {"help", 0, 0, 'h'},
948                 {"mdt", 0, 0, 'M'},
949                 {"mgmt", 0, 0, 'G'},
950                 {"mgmtnode", 1, 0, 'm'},
951                 {"mkfsoptions", 1, 0, 'k'},
952                 {"mountfsoptions", 1, 0, 'o'},
953                 {"ost", 0, 0, 'O'},
954                 {"reformat", 0, 0, 'r'},
955                 {"startupwait", 1, 0, 'w'},
956                 {"stripe_count", 1, 0, 'c'},
957                 {"stripe_size", 1, 0, 's'},
958                 {"stripe_index", 1, 0, 'i'},
959                 {"index", 1, 0, 'i'},
960                 {"timeout", 1, 0, 't'},
961                 {"verbose", 0, 0, 'v'},
962                 {0, 0, 0, 0}
963         };
964         char *optstring = "b:C:d:n:f:hI:MGm:k:o:Orw:c:s:i:t:v";
965         char opt;
966         char *mountopts = NULL;
967         int  ret = 0;
968
969         progname = argv[0];
970         if (argc < 3) 
971                 usage(stderr);
972            
973         memset(&mop, 0, sizeof(mop));
974         set_defaults(&mop);
975
976         while ((opt = getopt_long(argc, argv, optstring, long_opt, NULL)) != 
977                EOF) {
978                 switch (opt) {
979                 case 'b': {
980                         int i = 0;
981                         while (i < LDD_MT_LAST) {
982                                 if (strcmp(optarg, mt_str(i)) == 0) {
983                                         mop.mo_ldd.ldd_mount_type = i;
984                                         break;
985                                 }
986                                 i++;
987                         }
988                         break;
989                 }
990                 case 'C':
991                         //FIXME
992                         exit(2);
993                 case 'c':
994                         if (IS_MDT(&mop.mo_ldd)) {
995                                 int stripe_count = atol(optarg);
996                                 mop.mo_stripe_count = stripe_count;
997                         } else {
998                                 badopt(opt, "MDT");
999                         }
1000                         break;
1001                 case 'd':
1002                         mop.mo_device_sz = atol(optarg); 
1003                         break;
1004                 case 'k':
1005                         strncpy(mop.mo_mkfsopts, optarg, 
1006                                 sizeof(mop.mo_mkfsopts) - 1);
1007                         break;
1008                 case 'f':
1009                         /* we must pass this info on when we register with
1010                            the mgs */
1011                         //mop.mo_hostnid.backup = libcfs_str2nid(optarg);
1012                         break;
1013                 case 'G':
1014                         mop.mo_ldd.ldd_flags |= LDD_F_SV_TYPE_MGMT;
1015                         break;
1016                 case 'h':
1017                         usage(stdout);
1018                         break;
1019                 case 'i':
1020                         if (IS_MDT(&mop.mo_ldd) || IS_OST(&mop.mo_ldd)) {
1021                                 mop.mo_index = atol(optarg);
1022                                 mop.mo_ldd.ldd_flags &= ~LDD_F_NEED_INDEX;
1023                         } else {
1024                                 badopt(opt, "MDT,OST");
1025                         }
1026                         break;
1027                 case 'm':
1028                         if (IS_MGMT(&mop.mo_ldd))
1029                                 badopt(opt, "non-MGMT MDT,OST");
1030                         set_nid_pair(&mop.mo_ldd.ldd_mgmtnid, optarg);
1031                         break;
1032                 case 'M':
1033                         mop.mo_ldd.ldd_flags |= LDD_F_SV_TYPE_MDT;
1034                         break;
1035                 case 'n':
1036                         if (!(IS_MDT(&mop.mo_ldd) || IS_OST(&mop.mo_ldd)))
1037                                 badopt(opt, "MDT,OST");
1038                         if (strlen(optarg) > 8) {
1039                                 fprintf(stderr, "%s: filesystem name must be "
1040                                         "<= 8 chars\n", progname);
1041                                 exit(1);
1042                         }
1043                         if (optarg[0] != 0) 
1044                                 strncpy(mop.mo_ldd.ldd_fsname, optarg, 
1045                                         sizeof(mop.mo_ldd.ldd_fsname) - 1);
1046                         break;
1047                 case 'o':
1048                         mountopts = optarg;
1049                         break;
1050                 case 'O':
1051                         mop.mo_ldd.ldd_flags |= LDD_F_SV_TYPE_OST;
1052                         break;
1053                 case 'r':
1054                         mop.mo_flags |= MO_FORCEFORMAT;
1055                         break;
1056                 case 's':
1057                         if (IS_MDT(&mop.mo_ldd)) 
1058                                 mop.mo_stripe_sz = atol(optarg) * 1024;
1059                         else 
1060                                 badopt(opt, "MDT");
1061                         break;
1062                 case 't':
1063                         mop.mo_timeout = atol(optarg);
1064                         break;
1065                 case 'v':
1066                         verbose++;
1067                         break;
1068                 default:
1069                         if (opt != '?') {
1070                                 fatal();
1071                                 fprintf(stderr, "Unknown option '%c'\n", opt);
1072                         }
1073                         usage(stderr);
1074                         break;
1075                 }
1076         }//while
1077         if (optind >= argc) {
1078                 fatal();
1079                 fprintf(stderr, "Bad arguments\n");
1080                 usage(stderr);
1081         }
1082
1083         if (!(IS_MDT(&mop.mo_ldd) || IS_OST(&mop.mo_ldd) || 
1084               IS_MGMT(&mop.mo_ldd))) {
1085                 fatal();
1086                 fprintf(stderr, "must set server type :{mdt,ost,mgmt}\n");
1087                 usage(stderr);
1088         }
1089
1090         if (IS_MDT(&mop.mo_ldd) && !IS_MGMT(&mop.mo_ldd) && 
1091             mop.mo_ldd.ldd_mgmtnid.primary == PTL_NID_ANY) {
1092                 vprint("No MGMT specified, adding to this MDT\n");
1093                 mop.mo_ldd.ldd_flags |= LDD_F_SV_TYPE_MGMT;
1094                 //FIXME mop.mo_ldd.ldd_mgmt.primary == libcfs_str2nid(localhost);
1095         }
1096
1097         if (mop.mo_ldd.ldd_mgmtnid.primary == PTL_NID_ANY) {
1098                 fatal();
1099                 fprintf(stderr, "Must specify either --mgmt or --mgmtnode\n");
1100                 usage(stderr);
1101         }
1102
1103         if (IS_MDT(&mop.mo_ldd) && (mop.mo_stripe_sz == 0))
1104                 mop.mo_stripe_sz = 1024 * 1024;
1105         
1106         strcpy(mop.mo_device, argv[optind]);
1107         
1108         /* These are the permanent mount options. */ 
1109         if ((mop.mo_ldd.ldd_mount_type == LDD_MT_EXT3) ||
1110             (mop.mo_ldd.ldd_mount_type == LDD_MT_LDISKFS)) {
1111                 sprintf(mop.mo_ldd.ldd_mount_opts, "errors=remount-ro");
1112                 // extents,mballoc? 
1113                 if (IS_MDT(&mop.mo_ldd))
1114                         strcat(mop.mo_ldd.ldd_mount_opts, ",iopen_nopriv");
1115                 if ((get_os_version() == 24) && IS_OST(&mop.mo_ldd))
1116                         strcat(mop.mo_ldd.ldd_mount_opts, ",asyncdel");
1117         } else if (mop.mo_ldd.ldd_mount_type == LDD_MT_SMFS) {
1118                 sprintf(mop.mo_ldd.ldd_mount_opts, "type=ext3,dev=%s",
1119                         mop.mo_device);
1120         } else {
1121                 fatal();
1122                 fprintf(stderr, "%s: unknown fs type %d '%s'\n",
1123                         progname, mop.mo_ldd.ldd_mount_type,
1124                         MT_STR(&mop.mo_ldd));
1125                 return EINVAL;
1126         }
1127         if (mountopts) {
1128                 strcat(mop.mo_ldd.ldd_mount_opts, ",");
1129                 strcat(mop.mo_ldd.ldd_mount_opts, mountopts);
1130         }
1131
1132         if ((mop.mo_ldd.ldd_mount_type == LDD_MT_SMFS) ||
1133             !is_block(mop.mo_device)) {
1134                 mop.mo_flags |= MO_IS_LOOP;
1135                 if (mop.mo_device_sz == 0) {
1136                         fatal();
1137                         fprintf(stderr, "loop device requires a --device_size= "
1138                                 "param\n");
1139                         return EINVAL;
1140                 }
1141         }
1142                 
1143         make_sv_name(&mop);
1144
1145         ret = make_lustre_backfs(&mop);
1146         if (ret != 0) {
1147                 fatal();
1148                 fprintf(stderr, "mkfs failed %d\n", ret);
1149                 return ret;
1150         }
1151         
1152         ret = write_local_files(&mop);
1153         if (ret != 0) {
1154                 fatal();
1155                 fprintf(stderr, "failed to write local files\n");
1156                 return ret;
1157         }
1158
1159         ret = write_llog_files(&mop);
1160         if (ret != 0) {
1161                 fatal();
1162                 fprintf(stderr, "failed to write setup logs\n");
1163                 return ret;
1164         }
1165         
1166         return ret;
1167 }