]> git.neil.brown.name Git - lafs-utils.git/blob - tools/mkfs.lafs.c
484920c4918d5307c8ae145b14ae8ceb4970ca10
[lafs-utils.git] / tools / mkfs.lafs.c
1 /*
2  * mkfs.lafs - Create an empty LAFS filesystem
3  *
4  * Copyright (C) 2010 NeilBrown <neil@brown.name>
5  *
6  *    This program is free software; you can redistribute it and/or modify
7  *    it under the terms of the GNU General Public License as published by
8  *    the Free Software Foundation; either version 2 of the License, or
9  *    (at your option) any later version.
10  *
11  *    This program is distributed in the hope that it will be useful,
12  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *    GNU General Public License for more details.
15  *
16  *    You should have received a copy of the GNU General Public License
17  *    along with this program; if not, write to the Free Software
18  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *    Author: Neil Brown
21  *    Email: <neil@brown.name>
22  *
23  */
24
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <getopt.h>
30 #include <lafs/lafs.h>
31 #include <talloc.h>
32
33 #include "internal.h"
34
35 /*
36  * A new filesystem must contain:
37  *   inode 0 - TypeInodeFile with all the files listed here
38  *   inode 1 - TypeInodeMap - empty
39  *   inode 2 - TypeDir - empty
40  *   inode 8 - TypeOrphanList - empty
41  *   inode 16 - TypeSegmentMap - youth block and usage block for first segment
42  *
43  * These can all be in one checkpoint and could be in a single
44  * write-cluster, though that could be a bit awkward.
45  *
46  * As well as the write-clusters we need device-blocks and state-blocks.
47  *
48  * Configurable values are:
49  *  - block size, 512 to 4096  -b or --block-size
50  *  - segment size - up to 64k, but multiple of width --segment-size
51  *  - width - spindles across which device is striped --width
52  *  - stride - chunk-size when device is striped --stride
53  *
54  */
55
56 enum {
57         opt_segsize = 1000,
58         opt_width,
59         opt_stride,
60         opt_noatime,
61         opt_regular,
62 };
63
64 char short_options[] = "-b:Vvh";
65 struct option long_options[] = {
66         {"block-size",   1, 0, 'b'},
67         {"segment-size", 1, 0, opt_segsize},
68         {"width",        1, 0, opt_width},
69         {"stride",       1, 0, opt_stride},
70         {"version",      0, 0, 'V'},
71         {"verbose",      0, 0, 'v'},
72         {"help",         0, 0, 'h'},
73         {"no-atime-file",0, 0, opt_noatime},
74         {"regular-file", 0, 0, opt_regular},
75         {0, 0, 0, 0}
76 };
77
78 char version_text[] = "mkfs.lafs - unreleased\n";
79
80 char help_text[] =
81         "mkfs.lafs: create a lafs filesystem\n" 
82         ;
83
84 char usage_text[] =
85         "Usage: mkfs.lafs [options] device-name\n"
86         " Options:\n"
87         "   --block-size (-b)      size of basic block, up to 4096 (e.g. 2K)\n"
88         "   --segment-size         size of segments, up to 65536 blocks (e.g. 32M)\n"
89         "   --width                number of members of a striped device (e.g. 3)\n"
90         "   --stride               chunk size of a striped device (e.g. 64K)\n"
91         "   --help (-h)            This help message\n"
92         "   --version (-V)         Report version information\n"
93         "   --verbose (-v)         Be more verbose\n"
94         ;
95
96 static void get_size(long *valp, char *arg, char *name)
97 {
98         long val;
99         char *error;
100
101         if (*valp != 0) {
102                 fprintf(stderr, "mkfs.lafs: %s has already been given,"
103                         " value \"%s\" not permitted.\n",
104                         name, arg);
105                 exit(2);
106         }
107
108         val = parse_size(arg, &error);
109         if (error) {
110                 fprintf(stderr, "mkfs.lafs: %s: \"%s\" for %s\n",
111                         error, arg, name);
112                 exit(2);
113         }
114         *valp = val;
115 }
116
117 void get_num(int *valp, char *arg, char *name)
118 {
119         long val;
120         char *endp;
121
122         if (*valp != 0) {
123                 fprintf(stderr, "mkfs.lafs: %s has already been given,"
124                         " value \"%s\" not permitted.\n",
125                         name, arg);
126                 exit(2);
127         }
128
129         val = strtol(arg, &endp, 0);
130         if (endp == arg || *endp) {
131                 fprintf(stderr, "mkfs.lafs: Unrecognised number \"%s\""
132                         " for %s\n", arg, name);
133                 exit(2);
134         }
135         if (val == 0) {
136                 fprintf(stderr, "mkfs.lafs: 0 is not a valid number for %s\n", name);
137                 exit(2);
138         }
139         *valp = val;
140 }
141
142 int main(int argc, char *argv[])
143 {
144         int verbose = 0;
145         long block_bytes = 0;
146         long segment_bytes = 0;
147         int width = 0;
148         long stride_bytes = 0;
149         long long device_bytes;
150         char *devname = NULL;
151         int create_atime = 1;
152         int regular_file = 0;
153         int opt;
154         int dev_fd;
155         char *error;
156         struct lafs *lafs;
157         struct lafs_device *dev;
158         struct lafs_ino *ifile, *imfile, *rootdir, *orphans, *segmap;
159         struct lafs_ino *atimefile = NULL;
160
161         while ((opt = getopt_long(argc, argv,
162                                   short_options, long_options,
163                                   NULL)) != -1) {
164                 switch(opt) {
165                 case 'h':
166                         fputs(help_text, stdout);
167                         fputs(usage_text, stdout);
168                         exit(0);
169                 case 'V':
170                         fputs(version_text, stdout);
171                         exit(0);
172                 case 'v':
173                         verbose++;
174                         break;
175                 case 'b':
176                         get_size(&block_bytes, optarg, "block size");
177                         break;
178                 case opt_segsize:
179                         get_size(&segment_bytes, optarg, "segment size");
180                         break;
181                 case opt_stride:
182                         get_size(&stride_bytes, optarg, "stride size");
183                         break;
184                 case opt_width:
185                         get_num(&width, optarg, "device width");
186                         break;
187                 case opt_noatime:
188                         create_atime = 0;
189                         break;
190                 case opt_regular:
191                         regular_file = 1;
192                         break;
193
194                 case 1:
195                         if (devname == NULL) {
196                                 devname = optarg;
197                                 break;
198                         }
199                         fprintf(stderr, "mkfs.lafs: multiple device names not supported: %s and %s\n",
200                                 devname, optarg);
201                         exit(2);
202
203                 case '?':
204                 default:
205                         fputs(usage_text, stderr);
206                         exit(2);
207                 }
208         }
209
210         if (devname == NULL) {
211                 fputs("mkfs.lafs: no device name given\n", stderr);
212                 fputs(usage_text, stderr);
213                 exit(2);
214         }
215
216         /* Validate device */
217         dev_fd = open_device(devname, &device_bytes, regular_file, &error);
218         if (dev_fd < 0) {
219                 fprintf(stderr, "mkfs.lafs: %s\n", error);
220                 free(error);
221                 exit(2);
222         }
223
224         /* Validate parameters */
225         error = lafs_validate_geometry(&block_bytes, &segment_bytes,
226                                        &stride_bytes, &width,
227                                        device_bytes);
228         if (error) {
229                 fprintf(stderr, "mkfs.lafs: %s\n", error);
230                 free(error);
231                 exit(2);
232         }
233
234         /* Create filesystem handle */
235         lafs = lafs_alloc();
236
237         /* Initialise filesystem */
238         lafs_new(lafs, block_bytes);
239
240         /* Add device */
241         dev = lafs_add_device(lafs, devname, dev_fd,
242                               segment_bytes / block_bytes,
243                               stride_bytes / block_bytes,
244                               width,
245                               16);
246
247         /* Write device blocks */
248         lafs_write_dev(dev);
249
250         /* create files */
251         ifile = lafs_get_itable(lafs);
252         imfile = lafs_add_inode(ifile, 1, TypeInodeMap);
253         rootdir = lafs_add_inode(ifile, 2, TypeDir);
254         if (create_atime)
255                 atimefile = lafs_add_inode(ifile, 3, TypeAccessTime);
256         rootdir->md.file.linkcount = 2;
257         rootdir->md.file.mode = 0755;
258         rootdir->md.file.parent = 2;
259         lafs_dirty_inode(rootdir);
260         orphans = lafs_add_inode(ifile, 8, TypeOrphanList);
261         segmap = lafs_add_inode(ifile, 16, TypeSegmentMap);
262         lafs->devs->segsum = segmap;
263         segmap->md.segmentusage.table_size = lafs->devs->tablesize * 16;
264         lafs->devs->tablesize = segmap->md.segmentusage.table_size;
265         lafs_dirty_inode(segmap);
266
267         lafs_imap_set(imfile, 1);
268         lafs_imap_set(imfile, 2);
269         lafs_imap_set(imfile, 8);
270         lafs_imap_set(imfile, 16);
271
272         lafs_cluster_init(lafs, 0, 0, 0, 1);
273         /* Write checkpoint and state blocks */
274         lafs_checkpoint(lafs);
275         /* Write state blocks a second time, so all 4 copies are written */
276         lafs_write_state(lafs);
277
278         printf("Filesystem created with %llu segments of %llu %dK blocks\n",
279                (unsigned long long)dev->segment_count,
280                (unsigned long long)dev->segment_size,
281                lafs->blocksize/1024);
282
283         talloc_free(lafs);
284
285         exit(0);
286 }