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 for (i=0; i < nr_users; i++) { 405 if (memcmp(fs->super->s_uuid, 406 &jsb->s_users[i*16], 16) == 0) 407 break; 408 } 409 if (i >= nr_users) { 410 memcpy(&jsb->s_users[nr_users*16], 411 fs->super->s_uuid, 16); 412 jsb->s_nr_users = htonl(nr_users+1); 413 } 414 415 /* Writeback the journal superblock */ 416 if ((retval = io_channel_write_blk64(journal_dev->io, start, 417 -SUPERBLOCK_SIZE, buf))) 418 return retval; 419 420 fs->super->s_journal_inum = 0; 421 fs->super->s_journal_dev = st.st_rdev; 422 memcpy(fs->super->s_journal_uuid, jsb->s_uuid, 423 sizeof(fs->super->s_journal_uuid)); 424 memset(fs->super->s_jnl_blocks, 0, sizeof(fs->super->s_jnl_blocks)); 425 ext2fs_set_feature_journal(fs->super); 426 ext2fs_mark_super_dirty(fs); 427 return 0; 428 } 429 430 /* 431 * This function adds a journal inode to a filesystem, using either 432 * POSIX routines if the filesystem is mounted, or using direct I/O 433 * functions if it is not. 434 */ 435 errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks, 436 blk64_t goal, int flags) 437 { 438 errcode_t retval; 439 ext2_ino_t journal_ino; 440 struct stat st; 441 char jfile[1024]; 442 int mount_flags; 443 int fd = -1; 444 445 if (flags & EXT2_MKJOURNAL_NO_MNT_CHECK) 446 mount_flags = 0; 447 else if ((retval = ext2fs_check_mount_point(fs->device_name, 448 &mount_flags, 449 jfile, sizeof(jfile)-10))) 450 return retval; 451 452 if (mount_flags & EXT2_MF_MOUNTED) { 453 #if HAVE_EXT2_IOCTLS 454 int f = 0; 455 #endif 456 strcat(jfile, "/.journal"); 457 458 /* 459 * If .../.journal already exists, make sure any 460 * immutable or append-only flags are cleared. 461 */ 462 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) 463 (void) chflags (jfile, 0); 464 #else 465 #if HAVE_EXT2_IOCTLS 466 fd = open(jfile, O_RDONLY); 467 if (fd >= 0) { 468 retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f); 469 close(fd); 470 if (retval) 471 return retval; 472 } 473 #endif 474 #endif 475 476 /* Create the journal file */ 477 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0) 478 return errno; 479 480 /* Note that we can't do lazy journal initialization for mounted 481 * filesystems, since the zero writing is also allocating the 482 * journal blocks. We could use fallocate, but not all kernels 483 * support that, and creating a journal on a mounted ext2 484 * filesystems is extremely rare these days... Ignore it. */ 485 flags &= ~EXT2_MKJOURNAL_LAZYINIT; 486 487 if ((retval = write_journal_file(fs, jfile, num_blocks, flags))) 488 goto errout; 489 490 /* Get inode number of the journal file */ 491 if (fstat(fd, &st) < 0) { 492 retval = errno; 493 goto errout; 494 } 495 496 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP) 497 retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE); 498 #else 499 #if HAVE_EXT2_IOCTLS 500 if (ioctl(fd, EXT2_IOC_GETFLAGS, &f) < 0) { 501 retval = errno; 502 goto errout; 503 } 504 f |= EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL; 505 retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f); 506 #endif 507 #endif 508 if (retval) { 509 retval = errno; 510 goto errout; 511 } 512 513 if (close(fd) < 0) { 514 retval = errno; 515 fd = -1; 516 goto errout; 517 } 518 journal_ino = st.st_ino; 519 memset(fs->super->s_jnl_blocks, 0, 520 sizeof(fs->super->s_jnl_blocks)); 521 } else { 522 if ((mount_flags & EXT2_MF_BUSY) && 523 !(fs->flags & EXT2_FLAG_EXCLUSIVE)) { 524 retval = EBUSY; 525 goto errout; 526 } 527 journal_ino = EXT2_JOURNAL_INO; 528 if ((retval = write_journal_inode(fs, journal_ino, 529 num_blocks, goal, flags))) 530 return retval; 531 } 532 533 fs->super->s_journal_inum = journal_ino; 534 fs->super->s_journal_dev = 0; 535 memset(fs->super->s_journal_uuid, 0, 536 sizeof(fs->super->s_journal_uuid)); 537 ext2fs_set_feature_journal(fs->super); 538 539 ext2fs_mark_super_dirty(fs); 540 return 0; 541 errout: 542 if (fd >= 0) 543 close(fd); 544 return retval; 545 } 546 547 errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags) 548 { 549 return ext2fs_add_journal_inode2(fs, num_blocks, ~0ULL, flags); 550 } 551 552 553 #ifdef DEBUG 554 main(int argc, char **argv) 555 { 556 errcode_t retval; 557 char *device_name; 558 ext2_filsys fs; 559 560 if (argc < 2) { 561 fprintf(stderr, "Usage: %s filesystem\n", argv[0]); 562 exit(1); 563 } 564 device_name = argv[1]; 565 566 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, 567 unix_io_manager, &fs); 568 if (retval) { 569 com_err(argv[0], retval, "while opening %s", device_name); 570 exit(1); 571 } 572 573 retval = ext2fs_add_journal_inode(fs, JFS_MIN_JOURNAL_BLOCKS, 0); 574 if (retval) { 575 com_err(argv[0], retval, "while adding journal to %s", 576 device_name); 577 exit(1); 578 } 579 retval = ext2fs_flush(fs); 580 if (retval) { 581 printf("Warning, had trouble writing out superblocks.\n"); 582 } 583 ext2fs_close_free(&fs); 584 exit(0); 585 586 } 587 #endif 588