2 * mkjournal.c --- make a journal for a filesystem
4 * Copyright (C) 2000 Theodore Ts'o.
7 * This file may be redistributed under the terms of the GNU Library
8 * General Public License, version 2.
27 #include <sys/types.h>
30 #include <sys/ioctl.h>
33 #include <netinet/in.h>
36 #include <sys/utsname.h>
37 #define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
46 * This function automatically sets up the journal superblock and
47 * returns it as an allocated block.
49 errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
50 __u32 num_blocks, int flags,
54 journal_superblock_t *jsb;
56 if (num_blocks < JFS_MIN_JOURNAL_BLOCKS)
57 return EXT2_ET_JOURNAL_TOO_SMALL;
59 if ((retval = ext2fs_get_mem(fs->blocksize, &jsb)))
62 memset (jsb, 0, fs->blocksize);
64 jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
65 if (flags & EXT2_MKJOURNAL_V1_SUPER)
66 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1);
68 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
69 jsb->s_blocksize = htonl(fs->blocksize);
70 jsb->s_maxlen = htonl(num_blocks);
71 jsb->s_nr_users = htonl(1);
72 jsb->s_first = htonl(1);
73 jsb->s_sequence = htonl(1);
74 memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid));
76 * If we're creating an external journal device, we need to
77 * adjust these fields.
79 if (fs->super->s_feature_incompat &
80 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
82 jsb->s_first = htonl(ext2fs_journal_sb_start(fs->blocksize) + 1);
85 *ret_jsb = (char *) jsb;
90 * This function writes a journal using POSIX routines. It is used
91 * for creating external journals and creating journals on live
94 static errcode_t write_journal_file(ext2_filsys fs, char *filename,
95 blk_t num_blocks, int flags)
102 if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
106 /* Open the device or journal file */
107 if ((fd = open(filename, O_WRONLY)) < 0) {
112 /* Write the superblock out */
113 retval = EXT2_ET_SHORT_WRITE;
114 ret_size = write(fd, buf, fs->blocksize);
119 if (ret_size != (int) fs->blocksize)
121 memset(buf, 0, fs->blocksize);
123 if (flags & EXT2_MKJOURNAL_LAZYINIT)
126 for (i = 1; i < num_blocks; i++) {
127 ret_size = write(fd, buf, fs->blocksize);
132 if (ret_size != (int) fs->blocksize)
141 ext2fs_free_mem(&buf);
146 * Convenience function which zeros out _num_ blocks starting at
147 * _blk_. In case of an error, the details of the error is returned
148 * via _ret_blk_ and _ret_count_ if they are non-NULL pointers.
149 * Returns 0 on success, and an error code on an error.
151 * As a special case, if the first argument is NULL, then it will
152 * attempt to free the static zeroizing buffer. (This is to keep
153 * programs that check for memory leaks happy.)
155 #define STRIDE_LENGTH 8
156 errcode_t ext2fs_zero_blocks2(ext2_filsys fs, blk64_t blk, int num,
157 blk64_t *ret_blk, int *ret_count)
163 /* If fs is null, clean up the static buffer and return */
171 /* Allocate the zeroizing buffer if necessary */
173 buf = malloc(fs->blocksize * STRIDE_LENGTH);
176 memset(buf, 0, fs->blocksize * STRIDE_LENGTH);
178 /* OK, do the write loop */
181 if (blk % STRIDE_LENGTH) {
182 count = STRIDE_LENGTH - (blk % STRIDE_LENGTH);
183 if (count > (num - j))
187 if (count > STRIDE_LENGTH)
188 count = STRIDE_LENGTH;
190 retval = io_channel_write_blk64(fs->io, blk, count, buf);
198 j += count; blk += count;
203 errcode_t ext2fs_zero_blocks(ext2_filsys fs, blk_t blk, int num,
204 blk_t *ret_blk, int *ret_count)
209 retval = ext2fs_zero_blocks2(fs, blk, num, &ret_blk2, ret_count);
211 *ret_blk = (blk_t) ret_blk2;
216 * Helper function for creating the journal using direct I/O routines
218 struct mkjournal_struct {
229 static int mkjournal_proc(ext2_filsys fs,
231 e2_blkcnt_t blockcnt,
232 blk64_t ref_block EXT2FS_ATTR((unused)),
233 int ref_offset EXT2FS_ATTR((unused)),
236 struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
245 (EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1)))
246 new_blk = es->goal+1;
248 es->goal &= ~EXT2FS_CLUSTER_MASK(fs);
249 retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk);
254 ext2fs_block_alloc_stats2(fs, new_blk, +1);
262 retval = io_channel_write_blk64(fs->io, new_blk, 1, es->buf);
263 else if (!(es->flags & EXT2_MKJOURNAL_LAZYINIT)) {
264 if (es->zero_count) {
265 if ((es->blk_to_zero + es->zero_count == new_blk) &&
266 (es->zero_count < 1024))
269 retval = ext2fs_zero_blocks2(fs,
276 if (es->zero_count == 0) {
277 es->blk_to_zero = new_blk;
283 memset(es->buf, 0, fs->blocksize);
289 *blocknr = es->goal = new_blk;
291 if (es->num_blocks == 0)
292 return (BLOCK_CHANGED | BLOCK_ABORT);
294 return BLOCK_CHANGED;
299 * Calculate the initial goal block to be roughly at the middle of the
300 * filesystem. Pick a group that has the largest number of free
303 static blk64_t get_midpoint_journal_block(ext2_filsys fs)
305 dgrp_t group, start, end, i, log_flex;
307 group = ext2fs_group_of_blk2(fs, (ext2fs_blocks_count(fs->super) -
308 fs->super->s_first_data_block) / 2);
309 log_flex = 1 << fs->super->s_log_groups_per_flex;
310 if (fs->super->s_log_groups_per_flex && (group > log_flex)) {
311 group = group & ~(log_flex - 1);
312 while ((group < fs->group_desc_count) &&
313 ext2fs_bg_free_blocks_count(fs, group) == 0)
315 if (group == fs->group_desc_count)
319 start = (group > 0) ? group-1 : group;
320 end = ((group+1) < fs->group_desc_count) ? group+1 : group;
322 for (i = start + 1; i <= end; i++)
323 if (ext2fs_bg_free_blocks_count(fs, i) >
324 ext2fs_bg_free_blocks_count(fs, group))
326 return ext2fs_group_first_block2(fs, group);
330 * This function creates a journal using direct I/O routines.
332 static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
333 blk_t num_blocks, blk64_t goal, int flags)
337 struct ext2_inode inode;
338 unsigned long long inode_size;
339 struct mkjournal_struct es;
341 if ((retval = ext2fs_create_journal_superblock(fs, num_blocks, flags,
345 if ((retval = ext2fs_read_bitmaps(fs)))
348 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
351 if (inode.i_blocks > 0) {
356 es.num_blocks = num_blocks;
362 es.goal = (goal != ~0ULL) ? goal : get_midpoint_journal_block(fs);
364 if (fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_EXTENTS) {
365 inode.i_flags |= EXT4_EXTENTS_FL;
366 if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
370 retval = ext2fs_block_iterate3(fs, journal_ino, BLOCK_FLAG_APPEND,
371 0, mkjournal_proc, &es);
377 retval = ext2fs_zero_blocks2(fs, es.blk_to_zero,
378 es.zero_count, 0, 0);
383 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
386 inode_size = (unsigned long long)fs->blocksize * num_blocks;
387 ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
388 inode.i_mtime = inode.i_ctime = fs->now ? fs->now : time(0);
389 inode.i_links_count = 1;
390 inode.i_mode = LINUX_S_IFREG | 0600;
391 retval = ext2fs_inode_size_set(fs, &inode, inode_size);
395 if ((retval = ext2fs_write_new_inode(fs, journal_ino, &inode)))
399 memcpy(fs->super->s_jnl_blocks, inode.i_block, EXT2_N_BLOCKS*4);
400 fs->super->s_jnl_blocks[15] = inode.i_size_high;
401 fs->super->s_jnl_blocks[16] = inode.i_size;
402 fs->super->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
403 ext2fs_mark_super_dirty(fs);
406 ext2fs_zero_blocks2(0, 0, 0, 0, 0);
408 ext2fs_free_mem(&buf);
413 static int parse_version_number(const char *s)
415 int major, minor, rev;
421 major = strtol(cp, &endptr, 10);
422 if (cp == endptr || *endptr != '.')
425 minor = strtol(cp, &endptr, 10);
426 if (cp == endptr || *endptr != '.')
429 rev = strtol(cp, &endptr, 10);
432 return KERNEL_VERSION(major, minor, rev);
435 int ext2fs_is_before_linux_ver(unsigned int major, unsigned int minor,
439 static int linux_version_code = -1;
445 if (linux_version_code < 0)
446 linux_version_code = parse_version_number(ut.release);
447 if (linux_version_code == 0)
450 return linux_version_code < KERNEL_VERSION(major, minor, rev);
453 int ext2fs_is_before_linux_ver(unsigned int major, unsigned int minor,
461 * Find a reasonable journal file size (in blocks) given the number of blocks
462 * in the filesystem. For very small filesystems, it is not reasonable to
463 * have a journal that fills more than half of the filesystem.
465 int ext2fs_default_journal_size(__u64 num_blocks)
467 if (num_blocks < 2048)
469 if (num_blocks <= 8192)
471 if (num_blocks < 32768)
473 if (num_blocks < 256*1024)
475 if (num_blocks < 512*1024)
477 if (num_blocks < 1024*1024)
482 int ext2fs_journal_sb_start(int blocksize)
484 if (blocksize == EXT2_MIN_BLOCK_SIZE)
490 * This function adds a journal device to a filesystem
492 errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
496 char buf[SUPERBLOCK_SIZE];
497 journal_superblock_t *jsb;
501 /* Make sure the device exists and is a block device */
502 if (stat(journal_dev->device_name, &st) < 0)
505 if (!S_ISBLK(st.st_mode))
506 return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
508 /* Get the journal superblock */
509 start = ext2fs_journal_sb_start(journal_dev->blocksize);
510 if ((retval = io_channel_read_blk64(journal_dev->io, start,
515 jsb = (journal_superblock_t *) buf;
516 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
517 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
518 return EXT2_ET_NO_JOURNAL_SB;
520 if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize)
521 return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
523 /* Check and see if this filesystem has already been added */
524 nr_users = ntohl(jsb->s_nr_users);
525 for (i=0; i < nr_users; i++) {
526 if (memcmp(fs->super->s_uuid,
527 &jsb->s_users[i*16], 16) == 0)
531 memcpy(&jsb->s_users[nr_users*16],
532 fs->super->s_uuid, 16);
533 jsb->s_nr_users = htonl(nr_users+1);
536 /* Writeback the journal superblock */
537 if ((retval = io_channel_write_blk64(journal_dev->io, start,
538 -SUPERBLOCK_SIZE, buf)))
541 fs->super->s_journal_inum = 0;
542 fs->super->s_journal_dev = st.st_rdev;
543 memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
544 sizeof(fs->super->s_journal_uuid));
545 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
546 ext2fs_mark_super_dirty(fs);
551 * This function adds a journal inode to a filesystem, using either
552 * POSIX routines if the filesystem is mounted, or using direct I/O
553 * functions if it is not.
555 errcode_t ext2fs_add_journal_inode2(ext2_filsys fs, blk_t num_blocks,
556 blk64_t goal, int flags)
559 ext2_ino_t journal_ino;
565 if (flags & EXT2_MKJOURNAL_NO_MNT_CHECK)
567 else if ((retval = ext2fs_check_mount_point(fs->device_name,
569 jfile, sizeof(jfile)-10)))
572 if (mount_flags & EXT2_MF_MOUNTED) {
576 strcat(jfile, "/.journal");
579 * If .../.journal already exists, make sure any
580 * immutable or append-only flags are cleared.
582 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
583 (void) chflags (jfile, 0);
586 fd = open(jfile, O_RDONLY);
588 retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
596 /* Create the journal file */
597 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
600 /* Note that we can't do lazy journal initialization for mounted
601 * filesystems, since the zero writing is also allocating the
602 * journal blocks. We could use fallocate, but not all kernels
603 * support that, and creating a journal on a mounted ext2
604 * filesystems is extremely rare these days... Ignore it. */
605 flags &= ~EXT2_MKJOURNAL_LAZYINIT;
607 if ((retval = write_journal_file(fs, jfile, num_blocks, flags)))
610 /* Get inode number of the journal file */
611 if (fstat(fd, &st) < 0) {
616 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
617 retval = fchflags (fd, UF_NODUMP|UF_IMMUTABLE);
620 if (ioctl(fd, EXT2_IOC_GETFLAGS, &f) < 0) {
624 f |= EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL;
625 retval = ioctl(fd, EXT2_IOC_SETFLAGS, &f);
638 journal_ino = st.st_ino;
639 memset(fs->super->s_jnl_blocks, 0,
640 sizeof(fs->super->s_jnl_blocks));
642 if ((mount_flags & EXT2_MF_BUSY) &&
643 !(fs->flags & EXT2_FLAG_EXCLUSIVE)) {
647 journal_ino = EXT2_JOURNAL_INO;
648 if ((retval = write_journal_inode(fs, journal_ino,
649 num_blocks, goal, flags)))
653 fs->super->s_journal_inum = journal_ino;
654 fs->super->s_journal_dev = 0;
655 memset(fs->super->s_journal_uuid, 0,
656 sizeof(fs->super->s_journal_uuid));
657 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
659 ext2fs_mark_super_dirty(fs);
667 errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t num_blocks, int flags)
669 return ext2fs_add_journal_inode2(fs, num_blocks, ~0ULL, flags);
674 main(int argc, char **argv)
681 fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
684 device_name = argv[1];
686 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
687 unix_io_manager, &fs);
689 com_err(argv[0], retval, "while opening %s", device_name);
693 retval = ext2fs_add_journal_inode(fs, JFS_MIN_JOURNAL_BLOCKS, 0);
695 com_err(argv[0], retval, "while adding journal to %s",
699 retval = ext2fs_flush(fs);
701 printf("Warning, had trouble writing out superblocks.\n");
703 ext2fs_close_free(&fs);