1 /* 2 * mkjournal.c --- make a journal for a filesystem 3 * 4 * Copyright (C) 2000 Theodore Ts'o. 5 * 6 * %Begin-Header% 7 * This file may be redistributed under the terms of the GNU Library 8 * General Public License, version 2. 9 * %End-Header% 10 */ 11 12 #include "config.h" 13 #include <stdio.h> 14 #include <string.h> 15 #include <assert.h> 16 #if HAVE_UNISTD_H 17 #include <unistd.h> 18 #endif 19 #if HAVE_ERRNO_H 20 #include <errno.h> 21 #endif 22 #include <fcntl.h> 23 #include <time.h> 24 #if HAVE_SYS_STAT_H 25 #include <sys/stat.h> 26 #endif 27 #if HAVE_SYS_TYPES_H 28 #include <sys/types.h> 29 #endif 30 #if HAVE_SYS_IOCTL_H 31 #include <sys/ioctl.h> 32 #endif 33 #if HAVE_NETINET_IN_H 34 #include <netinet/in.h> 35 #endif 36 37 #include "ext2_fs.h" 38 #include "e2p/e2p.h" 39 #include "ext2fs.h" 40 41 #include "kernel-jbd.h" 42 43 /* 44 * This function automatically sets up the journal superblock and 45 * returns it as an allocated block. 46 */ 47 errcode_t ext2fs_create_journal_superblock2(ext2_filsys fs, 48 struct ext2fs_journal_params *jparams, 49 int flags, char **ret_jsb) 50 { 51 errcode_t retval; 52 journal_superblock_t *jsb; 53 54 if (jparams->num_journal_blocks < JBD2_MIN_JOURNAL_BLOCKS) 55 return EXT2_ET_JOURNAL_TOO_SMALL; 56 57 if ((retval = ext2fs_get_mem(fs->blocksize, &jsb))) 58 return retval; 59 60 memset (jsb, 0, fs->blocksize); 61 62 jsb->s_header.h_magic = htonl(JBD2_MAGIC_NUMBER); 63 if (flags & EXT2_MKJOURNAL_V1_SUPER) 64 jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V1); 65 else 66 jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V2); 67 jsb->s_blocksize = htonl(fs->blocksize); 68 jsb->s_maxlen = htonl(jparams->num_journal_blocks + jparams->num_fc_blocks); 69 jsb->s_nr_users = htonl(1); 70 jsb->s_first = htonl(1); 71 jsb->s_sequence = htonl(1); 72 jsb->s_num_fc_blks = htonl(jparams->num_fc_blocks); 73 memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid)); 74 /* 75 * If we're creating an external journal device, we need to 76 * adjust these fields. 77 */ 78 if (ext2fs_has_feature_journal_dev(fs->super)) { 79 jsb->s_nr_users = 0; 80 jsb->s_first = htonl(ext2fs_journal_sb_start(fs->blocksize) + 1); 81 } 82 83 *ret_jsb = (char *) jsb; 84 return 0; 85 } 86 87 errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, __u32 num_blocks, 88 int flags, char **ret_sb) 89 { 90 struct ext2fs_journal_params jparams; 91 92 jparams.num_journal_blocks = num_blocks; 93 jparams.num_fc_blocks = 0; 94 95 return ext2fs_create_journal_superblock2(fs, &jparams, flags, ret_sb); 96 } 97 98 /* 99 * This function writes a journal using POSIX routines. It is used 100 * for creating external journals and creating journals on live 101 * filesystems. 102 */ 103 static errcode_t write_journal_file(ext2_filsys fs, char *filename, 104 struct ext2fs_journal_params *jparams, 105 int flags) 106 { 107 errcode_t retval; 108 char *buf = 0; 109 int fd, ret_size; 110 blk_t i; 111 112 if ((retval = ext2fs_create_journal_superblock2(fs, jparams, flags, 113 &buf))) 114 return retval; 115 116 /* Open the device or journal file */ 117 if ((fd = open(filename, O_WRONLY)) < 0) { 118 retval = errno; 119 goto errfree; 120 } 121 122 /* Write the superblock out */ 123 retval = EXT2_ET_SHORT_WRITE; 124 ret_size = write(fd, buf, fs->blocksize); 125 if (ret_size < 0) { 126 retval = errno; 127 goto errout; 128 } 129 if (ret_size != (int) fs->blocksize) 130 goto errout; 131 memset(buf, 0, fs->blocksize); 132 133 if (flags & EXT2_MKJOURNAL_LAZYINIT) 134 goto success; 135 136 for (i = 1; i < jparams->num_journal_blocks + jparams->num_fc_blocks; i++) { 137 ret_size = write(fd, buf, fs->blocksize); 138 if (ret_size < 0) { 139 retval = errno; 140 goto errout; 141 } 142 if (ret_size != (int) fs->blocksize) 143 goto errout; 144 } 145 146 success: 147 retval = 0; 148 errout: 149 close(fd); 150 errfree: 151 ext2fs_free_mem(&buf); 152 return retval; 153 } 154 155 /* 156 * Convenience function which zeros out _num_ blocks starting at 157 * _blk_. In case of an error, the details of the error is returned 158 * via _ret_blk_ and _ret_count_ if they are non-NULL pointers. 159 * Returns 0 on success, and an error code on an error. 160 * 161 * As a special case, if the first argument is NULL, then it will 162 * attempt to free the static zeroizing buffer. (This is to keep 163 * programs that check for memory leaks happy.) 164 */ 165 #define MAX_STRIDE_LENGTH (4194304 / (int) fs->blocksize) 166 errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num, 167 blk64_t *ret_blk, int *ret_count) 168 { 169 int j, count; 170 static void *buf; 171 static int stride_length; 172 errcode_t retval; 173 174 /* If fs is null, clean up the static buffer and return */ 175 if (!fs) { 176 if (buf) { 177 free(buf); 178 buf = 0; 179 stride_length = 0; 180 } 181 return 0; 182 } 183 184 /* Deal with zeroing less than 1 block */ 185 if (num <= 0) 186 return 0; 187 188 /* Try a zero out command, if supported */ 189 retval = io_channel_zeroout(fs->io, blk, num); 190 if (retval == 0) 191 return 0; 192 193 /* Allocate the zeroizing buffer if necessary */ 194 if (num > stride_length && stride_length < MAX_STRIDE_LENGTH) { 195 void *p; 196 int new_stride = num; 197 198 if (new_stride > MAX_STRIDE_LENGTH) 199 new_stride = MAX_STRIDE_LENGTH; 200 p = realloc(buf, fs->blocksize * new_stride); 201 if (!p) 202 return EXT2_ET_NO_MEMORY; 203 buf = p; 204 stride_length = new_stride; 205 memset(buf, 0, fs->blocksize * stride_length); 206 } 207 /* OK, do the write loop */ 208 j=0; 209 while (j < num) { 210 if (blk % stride_length) { 211 count = stride_length - (blk % stride_length); 212 if (count > (num - j)) 213 count = num - j; 214 } else { 215 count = num - j; 216 if (count > stride_length) 217 count = stride_length; 218 } 219 retval = io_channel_write_blk64(fs->io, blk, count, buf); 220 if (retval) { 221 if (ret_count) 222 *ret_count = count; 223 if (ret_blk) 224 *ret_blk = blk; 225 return retval; 226 } 227 j += count; blk += count; 228 } 229 return 0; 230 } 231 232 errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num, 233 blk_t *ret_blk, int *ret_count) 234 { 235 blk64_t ret_blk2; 236 errcode_t retval; 237 238 retval = ext2fs_zero_blocks2(fs, blk, num, &ret_blk2, ret_count); 239 if (retval) 240 *ret_blk = (blk_t) ret_blk2; 241 return retval; 242 } 243 244 /* 245 * Calculate the initial goal block to be roughly at the middle of the 246 * filesystem. Pick a group that has the largest number of free 247 * blocks. 248 */ 249 static blk64_t get_midpoint_journal_block(ext2_filsys fs) 250 { 251 dgrp_t group, start, end, i, log_flex; 252 253 group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) - 254 fs->super->s_first_data_block) / 2); 255 log_flex = 1 << fs->super->s_log_groups_per_flex; 256 if (fs->super->s_log_groups_per_flex && (group > log_flex)) { 257 group = group & ~(log_flex - 1); 258 while ((group < fs->group_desc_count) && 259 ext2fs_bg_free_blocks_count(fs, group) == 0) 260 group++; 261 if (group == fs->group_desc_count) 262 group = 0; 263 start = group; 264 } else 265 start = (group > 0) ? group-1 : group; 266 end = ((group+1) < fs->group_desc_count) ? group+1 : group; 267 group = start; 268 for (i = start + 1; i <= end; i++) 269 if (ext2fs_bg_free_blocks_count(fs, i) > 270 ext2fs_bg_free_blocks_count(fs, group)) 271 group = i; 272 return ext2fs_group_first_block2(fs, group); 273 } 274 275 /* 276 * This function creates a journal using direct I/O routines. 277 */ 278 static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, 279 struct ext2fs_journal_params *jparams, 280 blk64_t goal, int flags) 281 { 282 char *buf; 283 errcode_t retval; 284 struct ext2_inode inode; 285 unsigned long long inode_size; 286 int falloc_flags = EXT2_FALLOCATE_FORCE_INIT; 287 blk64_t zblk; 288 289 if ((retval = ext2fs_create_journal_superblock2(fs, jparams, flags, 290 &buf))) 291 return retval; 292 293 if ((retval = ext2fs_read_bitmaps(fs))) 294 goto out2; 295 296 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) 297 goto out2; 298 299 if (inode.i_blocks > 0) { 300 retval = EEXIST; 301 goto out2; 302 } 303 304 if (goal == ~0ULL) 305 goal = get_midpoint_journal_block(fs); 306 307 if (ext2fs_has_feature_extents(fs->super)) 308 inode.i_flags |= EXT4_EXTENTS_FL; 309 310 if (!(flags & EXT2_MKJOURNAL_LAZYINIT)) 311 falloc_flags |= EXT2_FALLOCATE_ZERO_BLOCKS; 312 313 inode_size = (unsigned long long)fs->blocksize * 314 (jparams->num_journal_blocks + jparams->num_fc_blocks); 315 inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0); 316 inode.i_links_count = 1; 317 inode.i_mode = LINUX_S_IFREG | 0600; 318 retval = ext2fs_inode_size_set(fs, &inode, inode_size); 319 if (retval) 320 goto out2; 321 322 retval = ext2fs_fallocate(fs, falloc_flags, journal_ino, 323 &inode, goal, 0, 324 jparams->num_journal_blocks + jparams->num_fc_blocks); 325 if (retval) 326 goto out2; 327 328 if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode))) 329 goto out2; 330 331 retval = ext2fs_bmap2(fs, journal_ino, &inode, NULL, 0, 0, NULL, &zblk); 332 if (retval) 333 goto out2; 334 335 retval = io_channel_write_blk64(fs->io, zblk, 1, buf); 336 if (retval) 337 goto out2; 338 339 memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4); 340 fs->super->s_jnl_blocks[15] = inode.i_size_high; 341 fs->super->s_jnl_blocks[16] = inode.i_size; 342 fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS; 343 ext2fs_mark_super_dirty(fs); 344 345 out2: 346 ext2fs_free_mem(&buf); 347 return retval; 348 } 349 350 /* 351 * Find a reasonable journal file size (in blocks) given the number of blocks 352 * in the filesystem. For very small filesystems, it is not reasonable to 353 * have a journal that fills more than half of the filesystem. 354 * 355 * n.b. comments assume 4k blocks 356 */ 357 int ext2fs_default_journal_size(__u64 num_blocks) 358 { 359 if (num_blocks < 2048) 360 return -1; 361 if (num_blocks < 32768) /* 128 MB */ 362 return (1024); /* 4 MB */ 363 if (num_blocks < 256*1024) /* 1 GB */ 364 return (4096); /* 16 MB */ 365 if (num_blocks < 512*1024) /* 2 GB */ 366 return (8192); /* 32 MB */ 367 if (num_blocks < 4096*1024) /* 16 GB */ 368 return (16384); /* 64 MB */ 369 if (num_blocks < 8192*1024) /* 32 GB */ 370 return (32768); /* 128 MB */ 371 if (num_blocks < 16384*1024) /* 64 GB */ 372 return (65536); /* 256 MB */ 373 if (num_blocks < 32768*1024) /* 128 GB */ 374 return (131072); /* 512 MB */ 375 return 262144; /* 1 GB */ 376 } 377 378 errcode_t ext2fs_get_journal_params(struct ext2fs_journal_params *params, 379 ext2_filsys fs) 380 { 381 blk_t total_blks; 382 int ret; 383 384 memset(params, 0, sizeof(*params)); 385 if (ext2fs_has_feature_journal_dev(fs->super)) { 386 total_blks = ext2fs_blocks_count(fs->super); 387 if (total_blks < JBD2_MIN_JOURNAL_BLOCKS) 388 return EXT2_ET_JOURNAL_TOO_SMALL; 389 390 if (!ext2fs_has_feature_fast_commit(fs->super)) { 391 params->num_journal_blocks = total_blks; 392 params->num_fc_blocks = 0; 393 return 0; 394 } 395 params->num_journal_blocks = ext2fs_blocks_count(fs->super) * 396 EXT2_JOURNAL_TO_FC_BLKS_RATIO / 397 (EXT2_JOURNAL_TO_FC_BLKS_RATIO + 1); 398 if (JBD2_MIN_JOURNAL_BLOCKS > params->num_journal_blocks) 399 params->num_journal_blocks = JBD2_MIN_JOURNAL_BLOCKS; 400 params->num_fc_blocks = total_blks - params->num_journal_blocks; 401 return 0; 402 } 403 404 ret = ext2fs_default_journal_size(ext2fs_blocks_count(fs->super)); 405 if (ret < 0) 406 return EXT2_ET_JOURNAL_TOO_SMALL; 407 408 params->num_journal_blocks = ret; 409 if (ext2fs_has_feature_fast_commit(fs->super)) 410 params->num_fc_blocks = params->num_journal_blocks / 411 EXT2_JOURNAL_TO_FC_BLKS_RATIO; 412 return 0; 413 } 414 415 int ext2fs_journal_sb_start(int blocksize) 416 { 417 if (blocksize == EXT2_MIN_BLOCK_SIZE) 418 return 2; 419 return 1; 420 } 421 422 /* 423 * This function adds a journal device to a filesystem 424 */ 425 errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) 426 { 427 struct stat st; 428 errcode_t retval; 429 char buf[SUPERBLOCK_SIZE]; 430 journal_superblock_t *jsb; 431 int start; 432 __u32 i, nr_users; 433 434 /* Make sure the device exists and is a block device */ 435 if (stat(journal_dev->device_name, &st) < 0) 436 return errno; 437 438 if (!S_ISBLK(st.st_mode)) 439 return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */ 440 441 /* Get the journal superblock */ 442 start = ext2fs_journal_sb_start(journal_dev->blocksize); 443 if ((retval = io_channel_read_blk64(journal_dev->io, start, 444 -SUPERBLOCK_SIZE, 445 buf))) 446 return retval; 447 448 jsb = (journal_superblock_t *) buf; 449 if ((jsb->s_header.h_magic != (unsigned) ntohl(JBD2_MAGIC_NUMBER)) || 450 (jsb->s_header.h_blocktype != (unsigned) ntohl(JBD2_SUPERBLOCK_V2))) 451 return EXT2_ET_NO_JOURNAL_SB; 452 453 if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize) 454 return EXT2_ET_UNEXPECTED_BLOCK_SIZE; 455 456 /* Check and see if this filesystem has already been added */ 457 nr_users = ntohl(jsb->s_nr_users); 458 if (nr_users > JBD2_USERS_MAX) 459 return EXT2_ET_CORRUPT_JOURNAL_SB; 460 for (i=0; i < nr_users; i++) { 461 if (memcmp(fs->super->s_uuid, 462 &jsb->s_users[i*16], 16) == 0) 463 break; 464 } 465 if (i >= nr_users) { 466 memcpy(&jsb->s_users[nr_users*16], 467 fs->super->s_uuid, 16); 468 jsb->s_nr_users = htonl(nr_users+1); 469 } 470 471 /* Writeback the journal superblock */ 472 if ((retval = io_channel_write_blk64(journal_dev->io, start, 473 -SUPERBLOCK_SIZE, buf))) 474 return retval; 475 476 fs->super->s_journal_inum = 0; 477 fs->super->s_journal_dev = st.st_rdev; 478 memcpy(fs->super->s_journal_uuid, jsb->s_uuid, 479 sizeof(fs->super->s_journal_uuid)); 480 memset(fs->super->s_jnl_blocks, 0, sizeof(fs->super->s_jnl_blocks)); 481 ext2fs_set_feature_journal(fs->super); 482 ext2fs_mark_super_dirty(fs); 483 return 0; 484 } 485 486 /* 487 * This function adds a journal inode to a filesystem, using either 488 * POSIX routines if the filesystem is mounted, or using direct I/O 489 * functions if it is not. 490 */ 491 errcode_t ext2fs_add_journal_inode3(ext2_filsys fs, struct ext2fs_journal_params *jparams, 492 blk64_t goal, int flags) 493 { 494 errcode_t retval; 495 ext2_ino_t journal_ino; 496 struct stat st; 497 char jfile[1024]; 498 int mount_flags; 499 int fd = -1; 500 501 if (flags & EXT2_MKJOURNAL_NO_MNT_CHECK) 502 mount_flags = 0; 503 else if ((retval = ext2fs_check_mount_point(fs->device_name, 504 &mount_flags, 505 jfile, sizeof(jfile)-10))) 506 return retval; 507 508 if (mount_flags & EXT2_MF_MOUNTED) { 509 #if HAVE_EXT2_IOCTLS 510 int f = 0; 511 #endif 512 strcat(jfile, "/.journal"); 513 514 /* 515 * If .../.journal already exists, make sure any 516 * immutable or append-only flags are cleared. 517 */ 518 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) 519 (void) chflags (jfile, 0); 520 #else 521 #if HAVE_EXT2_IOCTLS 522 fd = open(jfile, O_RDONLY); 523 if (fd >= 0) { 524 retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f); 525 close(fd); 526 if (retval) 527 return errno; 528 } 529 #endif 530 #endif 531 532 /* Create the journal file */ 533 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0) 534 return errno; 535 536 /* Note that we can't do lazy journal initialization for mounted 537 * filesystems, since the zero writing is also allocating the 538 * journal blocks. We could use fallocate, but not all kernels 539 * support that, and creating a journal on a mounted ext2 540 * filesystems is extremely rare these days... Ignore it. */ 541 flags &= ~EXT2_MKJOURNAL_LAZYINIT; 542 543 if ((retval = write_journal_file(fs, jfile, jparams, flags))) 544 goto errout; 545 546 /* Get inode number of the journal file */ 547 if (fstat(fd, &st) < 0) { 548 retval = errno; 549 goto errout; 550 } 551 552 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) 553 retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE); 554 #else 555 #if HAVE_EXT2_IOCTLS 556 if (ioctl(fd, EXT2_IOC_GETFLAGS, &f) < 0) { 557 retval = errno; 558 goto errout; 559 } 560 f |= EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL; 561 retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f); 562 #endif 563 #endif 564 if (retval) { 565 retval = errno; 566 goto errout; 567 } 568 569 if (close(fd) < 0) { 570 retval = errno; 571 fd = -1; 572 goto errout; 573 } 574 journal_ino = st.st_ino; 575 memset(fs->super->s_jnl_blocks, 0, 576 sizeof(fs->super->s_jnl_blocks)); 577 } else { 578 if ((mount_flags & EXT2_MF_BUSY) && 579 !(fs->flags & EXT2_FLAG_EXCLUSIVE)) { 580 retval = EBUSY; 581 goto errout; 582 } 583 journal_ino = EXT2_JOURNAL_INO; 584 if ((retval = write_journal_inode(fs, journal_ino, 585 jparams, goal, flags))) 586 return retval; 587 } 588 589 fs->super->s_journal_inum = journal_ino; 590 fs->super->s_journal_dev = 0; 591 memset(fs->super->s_journal_uuid, 0, 592 sizeof(fs->super->s_journal_uuid)); 593 ext2fs_set_feature_journal(fs->super); 594 595 ext2fs_mark_super_dirty(fs); 596 return 0; 597 errout: 598 if (fd >= 0) 599 close(fd); 600 return retval; 601 } 602 603 errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks, 604 blk64_t goal, int flags) 605 { 606 struct ext2fs_journal_params jparams; 607 errcode_t ret; 608 609 jparams.num_journal_blocks = num_blocks; 610 jparams.num_fc_blocks = 0; 611 612 return ext2fs_add_journal_inode3(fs, &jparams, goal, flags); 613 } 614 615 errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags) 616 { 617 return ext2fs_add_journal_inode2(fs, num_blocks, ~0ULL, flags); 618 } 619 620 621 #ifdef DEBUG 622 main(int argc, char **argv) 623 { 624 errcode_t retval; 625 char *device_name; 626 ext2_filsys fs; 627 628 if (argc < 2) { 629 fprintf(stderr, "Usage: %s filesystem\n", argv[0]); 630 exit(1); 631 } 632 device_name = argv[1]; 633 634 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, 635 unix_io_manager, &fs); 636 if (retval) { 637 com_err(argv[0], retval, "while opening %s", device_name); 638 exit(1); 639 } 640 641 retval = ext2fs_add_journal_inode(fs, JBD2_MIN_JOURNAL_BLOCKS, 0); 642 if (retval) { 643 com_err(argv[0], retval, "while adding journal to %s", 644 device_name); 645 exit(1); 646 } 647 retval = ext2fs_flush(fs); 648 if (retval) { 649 printf("Warning, had trouble writing out superblocks.\n"); 650 } 651 ext2fs_close_free(&fs); 652 exit(0); 653 654 } 655 #endif