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 Public
26 #include <sys/types.h>
29 #include <netinet/in.h>
32 #if EXT2_FLAT_INCLUDES
35 #include <linux/ext2_fs.h>
43 * This function automatically sets up the journal superblock and
44 * returns it as an allocated block.
46 errcode_t ext2fs_create_journal_superblock(ext2_filsys fs,
47 __u32 size, int flags,
51 journal_superblock_t *jsb;
54 return EXT2_ET_JOURNAL_TOO_SMALL;
56 if ((retval = ext2fs_get_mem(fs->blocksize, (void **) &jsb)))
59 memset (jsb, 0, fs->blocksize);
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);
65 jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
66 jsb->s_blocksize = htonl(fs->blocksize);
67 jsb->s_maxlen = htonl(size);
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));
73 * If we're creating an external journal device, we need to
74 * adjust these fields.
76 if (fs->super->s_feature_incompat &
77 EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) {
79 jsb->s_first = htonl(1);
82 *ret_jsb = (char *) jsb;
87 * This function writes a journal using POSIX routines. It is used
88 * for creating external journals and creating journals on live
91 static errcode_t write_journal_file(ext2_filsys fs, char *filename,
92 blk_t size, int flags)
98 if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
101 /* Open the device or journal file */
102 if ((fd = open(filename, O_WRONLY)) < 0) {
107 /* Write the superblock out */
108 retval = EXT2_ET_SHORT_WRITE;
109 ret_size = write(fd, buf, fs->blocksize);
114 if (ret_size != fs->blocksize)
116 memset(buf, 0, fs->blocksize);
118 for (i = 1; i < size; i++) {
119 ret_size = write(fd, buf, fs->blocksize);
124 if (ret_size != fs->blocksize)
131 ext2fs_free_mem((void **) &buf);
136 * Helper function for creating the journal using direct I/O routines
138 struct mkjournal_struct {
145 static int mkjournal_proc(ext2_filsys fs,
147 e2_blkcnt_t blockcnt,
152 struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data;
154 static blk_t last_blk = 0;
162 retval = ext2fs_new_block(fs, last_blk, 0, &new_blk);
171 retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf);
174 memset(es->buf, 0, fs->blocksize);
181 ext2fs_mark_block_bitmap(fs->block_map, new_blk);
182 ext2fs_mark_bb_dirty(fs);
183 group = ext2fs_group_of_blk(fs, new_blk);
184 fs->group_desc[group].bg_free_blocks_count--;
185 fs->super->s_free_blocks_count--;
186 ext2fs_mark_super_dirty(fs);
188 if (es->num_blocks == 0)
189 return (BLOCK_CHANGED | BLOCK_ABORT);
191 return BLOCK_CHANGED;
196 * This function creates a journal using direct I/O routines.
198 static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino,
199 blk_t size, int flags)
203 struct ext2_inode inode;
204 struct mkjournal_struct es;
206 if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf)))
209 if ((retval = ext2fs_read_bitmaps(fs)))
212 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
215 if (inode.i_blocks > 0)
218 es.num_blocks = size;
223 retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND,
224 0, mkjournal_proc, &es);
230 if ((retval = ext2fs_read_inode(fs, journal_ino, &inode)))
233 inode.i_size += fs->blocksize * size;
234 inode.i_blocks += (fs->blocksize / 512) * es.newblocks;
235 inode.i_mtime = inode.i_ctime = time(0);
236 inode.i_links_count = 1;
237 inode.i_mode = LINUX_S_IFREG | 0600;
239 if ((retval = ext2fs_write_inode(fs, journal_ino, &inode)))
244 ext2fs_free_mem((void **) &buf);
249 * This function adds a journal device to a filesystem
251 errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev)
256 journal_superblock_t *jsb;
260 /* Make sure the device exists and is a block device */
261 if (stat(journal_dev->device_name, &st) < 0)
264 if (!S_ISBLK(st.st_mode))
265 return EXT2_ET_JOURNAL_NOT_BLOCK; /* Must be a block device */
267 /* Get the journal superblock */
268 if ((retval = io_channel_read_blk(journal_dev->io, 1, -1024, buf)))
271 jsb = (journal_superblock_t *) buf;
272 if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) ||
273 (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2)))
274 return EXT2_ET_NO_JOURNAL_SB;
276 if (ntohl(jsb->s_blocksize) != fs->blocksize)
277 return EXT2_ET_UNEXPECTED_BLOCK_SIZE;
279 /* Check and see if this filesystem has already been added */
280 nr_users = ntohl(jsb->s_nr_users);
281 for (i=0; i < nr_users; i++) {
282 if (memcmp(fs->super->s_uuid,
283 &jsb->s_users[i*16], 16) == 0)
287 memcpy(&jsb->s_users[nr_users*16],
288 fs->super->s_uuid, 16);
289 jsb->s_nr_users = htonl(nr_users+1);
292 /* Writeback the journal superblock */
293 if ((retval = io_channel_write_blk(journal_dev->io, 1, -1024, buf)))
296 fs->super->s_journal_inum = 0;
297 fs->super->s_journal_dev = st.st_rdev;
298 memcpy(fs->super->s_journal_uuid, jsb->s_uuid,
299 sizeof(fs->super->s_journal_uuid));
300 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
301 ext2fs_mark_super_dirty(fs);
306 * This function adds a journal inode to a filesystem, using either
307 * POSIX routines if the filesystem is mounted, or using direct I/O
308 * functions if it is not.
310 errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags)
313 ext2_ino_t journal_ino;
318 if ((retval = ext2fs_check_mount_point(fs->device_name, &mount_flags,
319 jfile, sizeof(jfile)-10)))
322 if (mount_flags & EXT2_MF_MOUNTED) {
323 strcat(jfile, "/.journal");
325 /* Create the journal file */
326 if ((fd = open(jfile, O_CREAT|O_WRONLY, 0600)) < 0)
330 if ((retval = write_journal_file(fs, jfile, size, flags)))
333 /* Get inode number of the journal file */
334 if (stat(jfile, &st) < 0)
337 if ((retval = fsetflags(jfile,
338 EXT2_NODUMP_FL | EXT2_IMMUTABLE_FL)))
341 journal_ino = st.st_ino;
343 journal_ino = EXT2_JOURNAL_INO;
344 if ((retval = write_journal_inode(fs, journal_ino,
349 fs->super->s_journal_inum = journal_ino;
350 fs->super->s_journal_dev = 0;
351 memset(fs->super->s_journal_uuid, 0,
352 sizeof(fs->super->s_journal_uuid));
353 fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
355 ext2fs_mark_super_dirty(fs);
360 main(int argc, char **argv)
367 fprintf(stderr, "Usage: %s filesystem\n", argv[0]);
370 device_name = argv[1];
372 retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0,
373 unix_io_manager, &fs);
375 com_err(argv[0], retval, "while opening %s", device_name);
379 retval = ext2fs_add_journal_inode(fs, 1024);
381 com_err(argv[0], retval, "while adding journal to %s",
385 retval = ext2fs_flush(fs);
387 printf("Warning, had trouble writing out superblocks.\n");