]> git.neil.brown.name Git - lafs-utils.git/blob - tools/mkfs.lafs.c
Split open_device out of mkfs.lafs
[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         long scale = 1;
100         char *endp;
101
102         if (*valp != 0) {
103                 fprintf(stderr, "mkfs.lafs: %s has already been given, value \"%s\" not permitted.\n",
104                         name, arg);
105                 exit(2);
106         }
107
108         val = strtol(arg, &endp, 0);
109
110         if (endp == arg) {
111                 fprintf(stderr, "mkfs.lafs: Unrecognised size \"%s\" for %s\n", arg, name);
112                 exit(2);
113         }
114
115         switch(*endp) {
116         case 'k':
117         case 'K':
118                 scale = 1024;
119                 break;
120         case 'M':
121                 scale = 1024*1024;
122                 break;
123         case 'G':
124                 scale = 1024*1024*1024;
125                 break;
126         case '\0':
127                 scale = 1;
128                 break;
129         default:
130                 fprintf(stderr, "mkfs.lafs: unrecognised modifier \"%s\" for %s\n", endp, name);
131                 exit(2);
132         }
133         if (val == 0) {
134                 fprintf(stderr, "mkfs.lafs: 0 is not a valid number for %s\n", name);
135                 exit(2);
136         }
137         val *= scale;
138         *valp = val;
139 }
140
141 void get_num(int *valp, char *arg, char *name)
142 {
143         long val;
144         char *endp;
145
146         if (*valp != 0) {
147                 fprintf(stderr, "mkfs.lafs: %s has already been given, value \"%s\" not permitted.\n",
148                         name, arg);
149                 exit(2);
150         }
151
152         val = strtol(arg, &endp, 0);
153         if (endp == arg || *endp) {
154                 fprintf(stderr, "mkfs.lafs: Unrecognised number \"%s\" for %s\n", arg, name);
155                 exit(2);
156         }
157         if (val == 0) {
158                 fprintf(stderr, "mkfs.lafs: 0 is not a valid number for %s\n", name);
159                 exit(2);
160         }
161         *valp = val;
162 }
163
164 int main(int argc, char *argv[])
165 {
166         int verbose = 0;
167         long block_bytes = 0;
168         long segment_bytes = 0;
169         int width = 0;
170         long stride_bytes = 0;
171         long long device_bytes;
172         char *devname = NULL;
173         int create_atime = 1;
174         int regular_file = 0;
175         int opt;
176         int dev_fd;
177         char *error;
178         struct lafs *lafs;
179         struct lafs_device *dev;
180         struct lafs_ino *ifile, *imfile, *rootdir, *orphans, *segmap;
181         struct lafs_ino *atimefile = NULL;
182
183         while ((opt = getopt_long(argc, argv,
184                                   short_options, long_options,
185                                   NULL)) != -1) {
186                 switch(opt) {
187                 case 'h':
188                         fputs(help_text, stdout);
189                         fputs(usage_text, stdout);
190                         exit(0);
191                 case 'V':
192                         fputs(version_text, stdout);
193                         exit(0);
194                 case 'v':
195                         verbose++;
196                         break;
197                 case 'b':
198                         get_size(&block_bytes, optarg, "block size");
199                         break;
200                 case opt_segsize:
201                         get_size(&segment_bytes, optarg, "segment size");
202                         break;
203                 case opt_stride:
204                         get_size(&stride_bytes, optarg, "stride size");
205                         break;
206                 case opt_width:
207                         get_num(&width, optarg, "device width");
208                         break;
209                 case opt_noatime:
210                         create_atime = 0;
211                         break;
212                 case opt_regular:
213                         regular_file = 1;
214                         break;
215
216                 case 1:
217                         if (devname == NULL) {
218                                 devname = optarg;
219                                 break;
220                         }
221                         fprintf(stderr, "mkfs.lafs: multiple device names not supported: %s and %s\n",
222                                 devname, optarg);
223                         exit(2);
224
225                 case '?':
226                 default:
227                         fputs(usage_text, stderr);
228                         exit(2);
229                 }
230         }
231
232         if (devname == NULL) {
233                 fputs("mkfs.lafs: no device name given\n", stderr);
234                 fputs(usage_text, stderr);
235                 exit(2);
236         }
237
238         /* Validate device */
239         dev_fd = open_device(devname, &device_bytes, regular_file, &error);
240         if (dev_fd < 0) {
241                 fprintf(stderr, "mkfs.lafs: %s\n", error);
242                 free(error);
243                 exit(2);
244         }
245
246         /* Validate parameters */
247         error = lafs_validate_geometry(&block_bytes, &segment_bytes,
248                                        &stride_bytes, &width,
249                                        device_bytes);
250         if (error) {
251                 fprintf(stderr, "mkfs.lafs: %s\n", error);
252                 free(error);
253                 exit(2);
254         }
255
256         /* Create filesystem handle */
257         lafs = lafs_alloc();
258
259         /* Initialise filesystem */
260         lafs_new(lafs, block_bytes);
261
262         /* Add device */
263         dev = lafs_add_device(lafs, devname, dev_fd,
264                               segment_bytes / block_bytes,
265                               stride_bytes / block_bytes,
266                               width,
267                               16);
268
269         /* Write device blocks */
270         lafs_write_dev(dev);
271
272         /* create files */
273         ifile = lafs_get_itable(lafs);
274         imfile = lafs_add_inode(ifile, 1, TypeInodeMap);
275         rootdir = lafs_add_inode(ifile, 2, TypeDir);
276         if (create_atime)
277                 atimefile = lafs_add_inode(ifile, 3, TypeAccessTime);
278         rootdir->md.file.linkcount = 2;
279         rootdir->md.file.mode = 0755;
280         rootdir->md.file.parent = 2;
281         lafs_dirty_inode(rootdir);
282         orphans = lafs_add_inode(ifile, 8, TypeOrphanList);
283         segmap = lafs_add_inode(ifile, 16, TypeSegmentMap);
284         lafs->devs->segsum = segmap;
285         segmap->md.segmentusage.table_size = lafs->devs->tablesize * 16;
286         lafs->devs->tablesize = segmap->md.segmentusage.table_size;
287         lafs_dirty_inode(segmap);
288
289         lafs_imap_set(imfile, 1);
290         lafs_imap_set(imfile, 2);
291         lafs_imap_set(imfile, 8);
292         lafs_imap_set(imfile, 16);
293
294         lafs_cluster_init(lafs, 0, 0, 0, 1);
295         lafs_add_free_seg(lafs, dev->devnum, 0);
296         /* Write checkpoint and state blocks */
297         lafs_checkpoint(lafs);
298         /* Write state blocks a second time, so all 4 copies are written */
299         lafs_write_state(lafs);
300
301         printf("Filesystem created with %llu segments of %llu %dK blocks\n",
302                (unsigned long long)dev->segment_count,
303                (unsigned long long)dev->segment_size,
304                lafs->blocksize/1024);
305
306         talloc_free(lafs);
307
308         exit(0);
309 }