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