Line data Source code
1 : #include "clusterautoconfig.h"
2 :
3 : #include <stdio.h>
4 : #include <stdlib.h>
5 : #include <string.h>
6 : #include <stdint.h>
7 : #include <inttypes.h>
8 : #include <sys/types.h>
9 : #include <dirent.h>
10 : #include <sys/stat.h>
11 : #include <sys/ioctl.h>
12 : #include <sys/mount.h>
13 : #include <fcntl.h>
14 : #include <unistd.h>
15 : #include <time.h>
16 : #include <errno.h>
17 : #include <stdarg.h>
18 : #include <blkid.h>
19 : #include <libintl.h>
20 : #include <locale.h>
21 : #define _(String) gettext(String)
22 :
23 : #include <logging.h>
24 : #include "libgfs2.h"
25 : #include "gfs2_mkfs.h"
26 : #include "metafs.h"
27 :
28 : #define BUF_SIZE 4096
29 : #define MB (1024 * 1024)
30 :
31 : static uint64_t override_device_size = 0;
32 : static int test = 0;
33 : static uint64_t fssize = 0, fsgrowth;
34 : int print_level = MSG_NOTICE;
35 :
36 : extern int create_new_inode(struct lgfs2_sbd *sdp);
37 : extern int rename2system(struct lgfs2_sbd *sdp, char *new_dir, char *new_name);
38 :
39 : #ifndef FALLOC_FL_KEEP_SIZE
40 : #define FALLOC_FL_KEEP_SIZE 0x01
41 : #endif
42 : #ifndef BLKDISCARD
43 : #define BLKDISCARD _IO(0x12,119)
44 : #endif
45 :
46 0 : static int discard_blocks(int fd, uint64_t start, uint64_t len)
47 : {
48 0 : uint64_t range[2] = { start, len };
49 :
50 0 : if (ioctl(fd, BLKDISCARD, &range) < 0)
51 0 : return errno;
52 0 : return 0;
53 : }
54 :
55 : /**
56 : * usage - Print out the usage message
57 : *
58 : * This function does not include documentation for the -D option
59 : * since normal users have no use for it at all. The -D option is
60 : * only for developers. It intended use is in combination with the
61 : * -T flag to find out what the result would be of trying different
62 : * device sizes without actually having to try them manually.
63 : */
64 :
65 0 : static void usage(void)
66 : {
67 : int i;
68 : const char *option, *param, *desc;
69 0 : const char *options[] = {
70 0 : "-h", NULL, _("Display this usage information"),
71 0 : "-q", NULL, _("Quiet, reduce verbosity"),
72 0 : "-T", NULL, _("Do everything except update file system"),
73 0 : "-V", NULL, _("Display version information"),
74 0 : "-v", NULL, _("Increase verbosity"),
75 : NULL, NULL, NULL /* Must be kept at the end */
76 : };
77 :
78 0 : printf("%s\n", _("Usage:"));
79 0 : printf(" gfs2_grow [%s] <%s>\n\n", _("options"), _("device"));
80 0 : printf(_("Expands a GFS2 file system after the device containing the file system has been expanded"));
81 0 : printf("\n\n%s\n", _("Options:"));
82 :
83 0 : for (i = 0; options[i] != NULL; i += 3) {
84 0 : option = options[i];
85 0 : param = options[i+1];
86 0 : desc = options[i+2];
87 0 : printf("%3s %-15s %s\n", option, param ? param : "", desc);
88 : }
89 0 : }
90 :
91 0 : static void decode_arguments(int argc, char *argv[], struct lgfs2_sbd *sdp)
92 : {
93 : int opt;
94 :
95 0 : while ((opt = getopt(argc, argv, "VD:hqTv?")) != EOF) {
96 0 : switch (opt) {
97 0 : case 'D': /* This option is for testing only */
98 0 : override_device_size = atoi(optarg);
99 0 : override_device_size <<= 20;
100 0 : break;
101 0 : case 'V':
102 0 : printf(_("%s %s (built %s %s)\n"), argv[0],
103 : VERSION, __DATE__, __TIME__);
104 0 : printf(REDHAT_COPYRIGHT "\n");
105 0 : exit(0);
106 0 : case 'h':
107 0 : usage();
108 0 : exit(0);
109 0 : case 'q':
110 0 : decrease_verbosity();
111 0 : break;
112 0 : case 'T':
113 0 : printf( _("(Test mode - file system will not "
114 : "be changed)\n"));
115 0 : test = 1;
116 0 : break;
117 0 : case 'v':
118 0 : increase_verbosity();
119 0 : break;
120 0 : case ':':
121 : case '?':
122 : /* Unknown flag */
123 0 : fprintf(stderr, _("Please use '-h' for help.\n"));
124 0 : exit(EXIT_FAILURE);
125 0 : default:
126 0 : fprintf(stderr, _("Invalid option '%c'\n"), opt);
127 0 : exit(EXIT_FAILURE);
128 : break;
129 : }
130 : }
131 :
132 0 : if (optind == argc) {
133 0 : usage();
134 0 : exit(EXIT_FAILURE);
135 : }
136 0 : }
137 :
138 0 : static lgfs2_rgrps_t rgrps_init(struct lgfs2_sbd *sdp)
139 : {
140 : int ret;
141 : int error;
142 0 : uint64_t al_base = 0;
143 0 : uint64_t al_off = 0;
144 : struct stat st;
145 0 : blkid_probe pr = blkid_new_probe();
146 0 : if (pr == NULL || blkid_probe_set_device(pr, sdp->device_fd, 0, 0) != 0
147 0 : || blkid_probe_enable_superblocks(pr, 1) != 0
148 0 : || blkid_probe_enable_partitions(pr, 1) != 0) {
149 0 : fprintf(stderr, _("Failed to create probe\n"));
150 0 : return NULL;
151 : }
152 :
153 0 : error = fstat(sdp->device_fd, &st);
154 0 : if (error < 0) {
155 0 : fprintf(stderr, _("fstat failed\n"));
156 0 : return NULL;
157 : }
158 :
159 0 : if (!S_ISREG(st.st_mode) && blkid_probe_enable_topology(pr, 1) != 0) {
160 0 : fprintf(stderr, _("Failed to create probe\n"));
161 0 : return NULL;
162 : }
163 :
164 0 : ret = blkid_do_fullprobe(pr);
165 0 : if (ret == 0 && !S_ISREG(st.st_mode)) {
166 0 : blkid_topology tp = blkid_probe_get_topology(pr);
167 0 : if (tp != NULL) {
168 0 : unsigned long min_io_sz = blkid_topology_get_minimum_io_size(tp);
169 0 : unsigned long opt_io_sz = blkid_topology_get_optimal_io_size(tp);
170 0 : unsigned long phy_sector_sz = blkid_topology_get_physical_sector_size(tp);
171 : /* If optimal_io_size is not a multiple of minimum_io_size then
172 : the values are not reliable swidth and sunit values, so don't
173 : attempt rgrp alignment */
174 0 : if ((min_io_sz > phy_sector_sz) &&
175 0 : (opt_io_sz > phy_sector_sz) &&
176 0 : (opt_io_sz % min_io_sz == 0)) {
177 0 : al_base = opt_io_sz / sdp->sd_bsize;
178 0 : al_off = min_io_sz / sdp->sd_bsize;
179 : }
180 :
181 : }
182 : }
183 :
184 0 : blkid_free_probe(pr);
185 0 : return lgfs2_rgrps_init(sdp, al_base, al_off);
186 : }
187 :
188 : /**
189 : * Calculate the size of the filesystem
190 : * Reads the lists of resource groups in order to work out where the last block
191 : * of the filesystem is located.
192 : * Returns: The calculated size
193 : */
194 0 : static uint64_t filesystem_size(lgfs2_rgrps_t rgs)
195 : {
196 0 : lgfs2_rgrp_t rg = lgfs2_rgrp_last(rgs);
197 : struct gfs2_rindex ri;
198 :
199 0 : lgfs2_rindex_out(rg, &ri);
200 0 : return be64_to_cpu(ri.ri_data0) + be32_to_cpu(ri.ri_data);
201 : }
202 :
203 : /**
204 : * Write the new rg information to disk.
205 : */
206 0 : static unsigned initialize_new_portion(struct lgfs2_sbd *sdp, lgfs2_rgrps_t rgs)
207 : {
208 0 : unsigned rgcount = 0;
209 0 : uint64_t rgaddr = fssize;
210 :
211 0 : discard_blocks(sdp->device_fd, rgaddr * sdp->sd_bsize, fsgrowth * sdp->sd_bsize);
212 : /* Build the remaining resource groups */
213 0 : while (1) {
214 0 : int err = 0;
215 : lgfs2_rgrp_t rg;
216 : struct gfs2_rindex ri;
217 : uint64_t nextaddr;
218 :
219 0 : nextaddr = lgfs2_rindex_entry_new(rgs, &ri, rgaddr, 0);
220 0 : if (nextaddr == 0)
221 0 : break;
222 0 : rg = lgfs2_rgrps_append(rgs, &ri, nextaddr - rgaddr);
223 0 : if (rg == NULL) {
224 0 : perror(_("Failed to create resource group"));
225 0 : return 0;
226 : }
227 0 : rgaddr = nextaddr;
228 0 : if (metafs_interrupted)
229 0 : return 0;
230 0 : if (!test)
231 0 : err = lgfs2_rgrp_write(sdp->device_fd, rg);
232 0 : if (err != 0) {
233 0 : perror(_("Failed to write resource group"));
234 0 : return 0;
235 : }
236 0 : rgcount++;
237 : }
238 0 : if (lgfs2_rgrps_write_final(sdp->device_fd, rgs) != 0) {
239 0 : perror(_("Failed to write final resource group"));
240 0 : return 0;
241 : }
242 0 : fsync(sdp->device_fd);
243 0 : return rgcount;
244 : }
245 :
246 0 : static char *rindex_buffer(lgfs2_rgrps_t rgs, unsigned count)
247 : {
248 : lgfs2_rgrp_t rg;
249 0 : unsigned i = 0;
250 : char *buf;
251 :
252 0 : buf = calloc(count, sizeof(struct gfs2_rindex));
253 0 : if (buf == NULL) {
254 0 : perror(__FUNCTION__);
255 0 : exit(EXIT_FAILURE);
256 : }
257 0 : for (rg = lgfs2_rgrp_first(rgs); rg; rg = lgfs2_rgrp_next(rg)) {
258 0 : lgfs2_rindex_out(rg, buf + (sizeof(struct gfs2_rindex) * i));
259 0 : i++;
260 : }
261 0 : return buf;
262 : }
263 :
264 : /**
265 : * fix_rindex - Add the new entries to the end of the rindex file.
266 : */
267 0 : static void fix_rindex(int rindex_fd, lgfs2_rgrps_t rgs, unsigned old_rg_count, unsigned rgcount)
268 : {
269 : char *buf;
270 : ssize_t count;
271 : ssize_t writelen;
272 : off_t rindex_size;
273 0 : const size_t entrysize = sizeof(struct gfs2_rindex);
274 :
275 0 : log_info( _("%d new rindex entries.\n"), rgcount);
276 0 : buf = rindex_buffer(rgs, rgcount);
277 0 : writelen = rgcount * entrysize;
278 :
279 0 : if (test)
280 0 : goto out;
281 :
282 0 : rindex_size = lseek(rindex_fd, 0, SEEK_END);
283 0 : if (rindex_size != old_rg_count * entrysize) {
284 0 : log_crit(_("Incorrect rindex size. Want %ld (%d resource groups), have %ld\n"),
285 : (long)(old_rg_count * entrysize), old_rg_count,
286 : (long)rindex_size);
287 0 : goto out;
288 : }
289 : /* Write the first entry separately to ensure there's enough
290 : space in the fs for the rest */
291 0 : count = write(rindex_fd, buf, entrysize);
292 0 : if (count != entrysize) {
293 0 : log_crit(_("Error writing first new rindex entry; aborted.\n"));
294 0 : if (count > 0)
295 0 : goto trunc;
296 : else
297 0 : goto out;
298 : }
299 0 : count = write(rindex_fd, (buf + entrysize), (writelen - entrysize));
300 0 : if (count != (writelen - entrysize)) {
301 0 : log_crit(_("Error writing new rindex entries; aborted.\n"));
302 0 : if (count > 0)
303 0 : goto trunc;
304 : else
305 0 : goto out;
306 : }
307 0 : if (fallocate(rindex_fd, FALLOC_FL_KEEP_SIZE, (rindex_size + writelen), entrysize) != 0)
308 0 : perror("fallocate");
309 0 : fsync(rindex_fd);
310 0 : out:
311 0 : free(buf);
312 0 : return;
313 0 : trunc:
314 0 : count = (count / sizeof(struct gfs2_rindex)) + old_rg_count;
315 0 : log_crit(_("truncating rindex to %ld entries\n"),
316 : (long)count * sizeof(struct gfs2_rindex));
317 0 : if (ftruncate(rindex_fd, (off_t)count * sizeof(struct gfs2_rindex)))
318 0 : log_crit(_("Could not truncate rindex: %s\n"), strerror(errno));
319 0 : free(buf);
320 : }
321 :
322 : /**
323 : * print_info - Print out various bits of (interesting?) information
324 : */
325 0 : static void print_info(struct lgfs2_sbd *sdp, char *device, char *mnt_path)
326 : {
327 0 : log_notice(_("Mount point: %s\n"), mnt_path);
328 0 : log_notice(_("Device: %s\n"), device);
329 0 : log_notice(_("Size: %"PRIu64" blocks\n"), fssize);
330 0 : log_notice(_("Length: %"PRIu64" blocks\n"), sdp->device.length);
331 0 : log_notice(_("The file system will grow by %"PRIu64"MB.\n"),
332 : (fsgrowth * sdp->sd_bsize) / MB);
333 0 : }
334 :
335 0 : static int open_rindex(char *metafs_path, int mode)
336 : {
337 : char *path;
338 : int fd;
339 :
340 0 : if (asprintf(&path, "%s/rindex", metafs_path) < 0) {
341 0 : perror(_("Failed to open rindex"));
342 0 : return -1;
343 : }
344 0 : fd = open(path, (mode | O_CLOEXEC));
345 0 : if (fd < 0) {
346 0 : perror(path);
347 0 : fprintf(stderr, _("Please run fsck.gfs2\n"));
348 : }
349 0 : free(path);
350 0 : return fd;
351 : }
352 :
353 : #ifndef UNITTESTS
354 : int main(int argc, char *argv[])
355 : {
356 : struct lgfs2_sbd sbd, *sdp = &sbd;
357 : int rindex_fd;
358 : int error = EXIT_SUCCESS;
359 : int devflags = (test ? O_RDONLY : O_RDWR) | O_CLOEXEC;
360 :
361 : setlocale(LC_ALL, "");
362 : textdomain("gfs2-utils");
363 : srandom(time(NULL) ^ getpid());
364 :
365 : memset(sdp, 0, sizeof(struct lgfs2_sbd));
366 : sdp->sd_bsize = LGFS2_DEFAULT_BSIZE;
367 : sdp->rgsize = -1;
368 : sdp->jsize = LGFS2_DEFAULT_JSIZE;
369 : sdp->qcsize = LGFS2_DEFAULT_QCSIZE;
370 : sdp->md.journals = 1;
371 : decode_arguments(argc, argv, sdp);
372 :
373 : for(; (argc - optind) > 0; optind++) {
374 : struct metafs mfs = {0};
375 : struct mntent *mnt;
376 : unsigned rgcount;
377 : unsigned old_rg_count;
378 : lgfs2_rgrps_t rgs;
379 :
380 : error = lgfs2_open_mnt(argv[optind], O_RDONLY|O_CLOEXEC, &sdp->path_fd,
381 : devflags, &sdp->device_fd, &mnt);
382 : if (error != 0) {
383 : fprintf(stderr, _("Error looking up mount '%s': %s\n"), argv[optind], strerror(errno));
384 : exit(EXIT_FAILURE);
385 : }
386 : if (mnt == NULL) {
387 : fprintf(stderr, _("%s: not a mounted gfs2 file system\n"), argv[optind]);
388 : continue;
389 : }
390 :
391 : if (lgfs2_get_dev_info(sdp->device_fd, &sdp->dinfo) < 0) {
392 : perror(mnt->mnt_fsname);
393 : exit(EXIT_FAILURE);
394 : }
395 : sdp->sd_bsize = LGFS2_DEFAULT_BSIZE;
396 : if (lgfs2_compute_constants(sdp)) {
397 : log_crit("%s\n", _("Failed to compute file system constants"));
398 : exit(EXIT_FAILURE);
399 : }
400 : if (lgfs2_read_sb(sdp) < 0) {
401 : fprintf(stderr, _("Error reading superblock.\n"));
402 : exit(EXIT_FAILURE);
403 : }
404 : lgfs2_fix_device_geometry(sdp);
405 : mfs.context = copy_context_opt(mnt);
406 : if (mount_gfs2_meta(&mfs, mnt->mnt_dir, (print_level > MSG_NOTICE))) {
407 : perror(_("Failed to mount GFS2 meta file system"));
408 : exit(EXIT_FAILURE);
409 : }
410 : rindex_fd = open_rindex(mfs.path, (test ? O_RDONLY : O_RDWR));
411 : if (rindex_fd < 0) {
412 : cleanup_metafs(&mfs);
413 : exit(EXIT_FAILURE);
414 : }
415 : /* Get master dinode */
416 : sdp->master_dir = lgfs2_inode_read(sdp, sdp->sd_meta_dir.in_addr);
417 : if (sdp->master_dir == NULL) {
418 : perror(_("Could not read master directory"));
419 : exit(EXIT_FAILURE);
420 : }
421 : rgs = rgrps_init(sdp);
422 : if (rgs == NULL) {
423 : perror(_("Could not initialise resource groups"));
424 : error = -1;
425 : goto out;
426 : }
427 : /* Fetch the rindex from disk. We aren't using gfs2 here, */
428 : /* which means that the bitmaps will most likely be cached */
429 : /* and therefore out of date. It shouldn't matter because */
430 : /* we're only going to write out new RG information after */
431 : /* the existing RGs, and only write to the index at EOF. */
432 : log_info(_("Gathering resource group information for %s\n"), argv[optind]);
433 : old_rg_count = lgfs2_rindex_read_fd(rindex_fd, rgs);
434 : if (old_rg_count == 0) {
435 : perror(_("Failed to scan existing resource groups"));
436 : error = -EXIT_FAILURE;
437 : goto out;
438 : }
439 : if (metafs_interrupted)
440 : goto out;
441 : fssize = lgfs2_rgrp_align_addr(rgs, filesystem_size(rgs) + 1);
442 : /* We're done with the old rgs now that we have the fssize and rg count */
443 : lgfs2_rgrps_free(&rgs);
444 : /* Now lets set up the new ones with alignment and all */
445 : rgs = rgrps_init(sdp);
446 : if (rgs == NULL) {
447 : perror(_("Could not initialise new resource groups"));
448 : error = -1;
449 : goto out;
450 : }
451 : fsgrowth = (sdp->device.length - fssize);
452 : rgcount = lgfs2_rgrps_plan(rgs, fsgrowth, ((LGFS2_MAX_RGSIZE << 20) / sdp->sd_bsize));
453 : if (rgcount == 0) {
454 : log_err( _("The calculated resource group size is too small.\n"));
455 : log_err( _("%s has not grown.\n"), argv[optind]);
456 : error = -1;
457 : goto out;
458 : }
459 : print_info(sdp, mnt->mnt_fsname, mnt->mnt_dir);
460 : rgcount = initialize_new_portion(sdp, rgs);
461 : if (rgcount == 0 || metafs_interrupted)
462 : goto out;
463 : fsync(sdp->device_fd);
464 : fix_rindex(rindex_fd, rgs, old_rg_count, rgcount);
465 : out:
466 : if (rgs != NULL)
467 : lgfs2_rgrps_free(&rgs);
468 : close(rindex_fd);
469 : cleanup_metafs(&mfs);
470 : close(sdp->device_fd);
471 :
472 : if (metafs_interrupted)
473 : break;
474 : }
475 : close(sdp->path_fd);
476 : sync();
477 : if (metafs_interrupted) {
478 : log_notice( _("gfs2_grow interrupted.\n"));
479 : exit(1);
480 : }
481 : log_notice( _("gfs2_grow complete.\n"));
482 : return error;
483 : }
484 : #endif /* UNITTESTS */
|