1 /* vi: set sw=4 ts=4: */
3 * mkjournal.c --- make a journal for a filesystem
5 * Copyright (C) 2000 Theodore Ts'o.
8 * This file may be redistributed under the terms of the GNU Public
27 #include <sys/types.h>
30 #include <sys/ioctl.h>
33 #include <netinet/in.h>
37 #include "../e2p/e2p.h"
38 #include "../e2fsck.h"
40 #include "kernel-jbd.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
, &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 if (fs
->blocksize
== 1024)
80 jsb
->s_first
= htonl(3);
82 jsb
->s_first
= htonl(2);
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 size
, int flags
)
102 if ((retval
= ext2fs_create_journal_superblock(fs
, size
, flags
, &buf
)))
105 /* Open the device or journal file */
106 if ((fd
= open(filename
, O_WRONLY
)) < 0) {
111 /* Write the superblock out */
112 retval
= EXT2_ET_SHORT_WRITE
;
113 ret_size
= write(fd
, buf
, fs
->blocksize
);
118 if (ret_size
!= (int) fs
->blocksize
)
120 memset(buf
, 0, fs
->blocksize
);
122 for (i
= 1; i
< size
; i
++) {
123 ret_size
= write(fd
, buf
, fs
->blocksize
);
128 if (ret_size
!= (int) fs
->blocksize
)
135 ext2fs_free_mem(&buf
);
140 * Helper function for creating the journal using direct I/O routines
142 struct mkjournal_struct
{
149 static int mkjournal_proc(ext2_filsys fs
,
151 e2_blkcnt_t blockcnt
,
152 blk_t ref_block
EXT2FS_ATTR((unused
)),
153 int ref_offset
EXT2FS_ATTR((unused
)),
156 struct mkjournal_struct
*es
= (struct mkjournal_struct
*) priv_data
;
158 static blk_t last_blk
= 0;
165 retval
= ext2fs_new_block(fs
, last_blk
, 0, &new_blk
);
174 retval
= io_channel_write_blk(fs
->io
, new_blk
, 1, es
->buf
);
177 memset(es
->buf
, 0, fs
->blocksize
);
185 ext2fs_block_alloc_stats(fs
, new_blk
, +1);
187 if (es
->num_blocks
== 0)
188 return (BLOCK_CHANGED
| BLOCK_ABORT
);
190 return BLOCK_CHANGED
;
194 * This function creates a journal using direct I/O routines.
196 static errcode_t
write_journal_inode(ext2_filsys fs
, ext2_ino_t journal_ino
,
197 blk_t size
, int flags
)
201 struct ext2_inode inode
;
202 struct mkjournal_struct es
;
204 if ((retval
= ext2fs_create_journal_superblock(fs
, size
, flags
, &buf
)))
207 if ((retval
= ext2fs_read_bitmaps(fs
)))
210 if ((retval
= ext2fs_read_inode(fs
, journal_ino
, &inode
)))
213 if (inode
.i_blocks
> 0)
216 es
.num_blocks
= size
;
221 retval
= ext2fs_block_iterate2(fs
, journal_ino
, BLOCK_FLAG_APPEND
,
222 0, mkjournal_proc
, &es
);
228 if ((retval
= ext2fs_read_inode(fs
, journal_ino
, &inode
)))
231 inode
.i_size
+= fs
->blocksize
* size
;
232 inode
.i_blocks
+= (fs
->blocksize
/ 512) * es
.newblocks
;
233 inode
.i_mtime
= inode
.i_ctime
= time(NULL
);
234 inode
.i_links_count
= 1;
235 inode
.i_mode
= LINUX_S_IFREG
| 0600;
237 if ((retval
= ext2fs_write_inode(fs
, journal_ino
, &inode
)))
241 memcpy(fs
->super
->s_jnl_blocks
, inode
.i_block
, EXT2_N_BLOCKS
*4);
242 fs
->super
->s_jnl_blocks
[16] = inode
.i_size
;
243 fs
->super
->s_jnl_backup_type
= EXT3_JNL_BACKUP_BLOCKS
;
244 ext2fs_mark_super_dirty(fs
);
247 ext2fs_free_mem(&buf
);
252 * This function adds a journal device to a filesystem
254 errcode_t
ext2fs_add_journal_device(ext2_filsys fs
, ext2_filsys journal_dev
)
259 journal_superblock_t
*jsb
;
263 /* Make sure the device exists and is a block device */
264 if (stat(journal_dev
->device_name
, &st
) < 0)
267 if (!S_ISBLK(st
.st_mode
))
268 return EXT2_ET_JOURNAL_NOT_BLOCK
; /* Must be a block device */
270 /* Get the journal superblock */
272 if (journal_dev
->blocksize
== 1024)
274 if ((retval
= io_channel_read_blk(journal_dev
->io
, start
, -1024, buf
)))
277 jsb
= (journal_superblock_t
*) buf
;
278 if ((jsb
->s_header
.h_magic
!= (unsigned) ntohl(JFS_MAGIC_NUMBER
)) ||
279 (jsb
->s_header
.h_blocktype
!= (unsigned) ntohl(JFS_SUPERBLOCK_V2
)))
280 return EXT2_ET_NO_JOURNAL_SB
;
282 if (ntohl(jsb
->s_blocksize
) != (unsigned long) fs
->blocksize
)
283 return EXT2_ET_UNEXPECTED_BLOCK_SIZE
;
285 /* Check and see if this filesystem has already been added */
286 nr_users
= ntohl(jsb
->s_nr_users
);
287 for (i
=0; i
< nr_users
; i
++) {
288 if (memcmp(fs
->super
->s_uuid
,
289 &jsb
->s_users
[i
*16], 16) == 0)
293 memcpy(&jsb
->s_users
[nr_users
*16],
294 fs
->super
->s_uuid
, 16);
295 jsb
->s_nr_users
= htonl(nr_users
+1);
298 /* Writeback the journal superblock */
299 if ((retval
= io_channel_write_blk(journal_dev
->io
, start
, -1024, buf
)))
302 fs
->super
->s_journal_inum
= 0;
303 fs
->super
->s_journal_dev
= st
.st_rdev
;
304 memcpy(fs
->super
->s_journal_uuid
, jsb
->s_uuid
,
305 sizeof(fs
->super
->s_journal_uuid
));
306 fs
->super
->s_feature_compat
|= EXT3_FEATURE_COMPAT_HAS_JOURNAL
;
307 ext2fs_mark_super_dirty(fs
);
312 * This function adds a journal inode to a filesystem, using either
313 * POSIX routines if the filesystem is mounted, or using direct I/O
314 * functions if it is not.
316 errcode_t
ext2fs_add_journal_inode(ext2_filsys fs
, blk_t size
, int flags
)
319 ext2_ino_t journal_ino
;
322 int fd
, mount_flags
, f
;
324 retval
= ext2fs_check_mount_point(fs
->device_name
, &mount_flags
,
325 jfile
, sizeof(jfile
)-10);
329 if (mount_flags
& EXT2_MF_MOUNTED
) {
330 strcat(jfile
, "/.journal");
333 * If .../.journal already exists, make sure any
334 * immutable or append-only flags are cleared.
336 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
337 (void) chflags (jfile
, 0);
340 fd
= open(jfile
, O_RDONLY
);
343 ioctl(fd
, EXT2_IOC_SETFLAGS
, &f
);
349 /* Create the journal file */
350 if ((fd
= open(jfile
, O_CREAT
|O_WRONLY
, 0600)) < 0)
353 if ((retval
= write_journal_file(fs
, jfile
, size
, flags
)))
356 /* Get inode number of the journal file */
357 if (fstat(fd
, &st
) < 0)
360 #if defined(HAVE_CHFLAGS) && defined(UF_NODUMP)
361 retval
= fchflags (fd
, UF_NODUMP
|UF_IMMUTABLE
);
364 f
= EXT2_NODUMP_FL
| EXT2_IMMUTABLE_FL
;
365 retval
= ioctl(fd
, EXT2_IOC_SETFLAGS
, &f
);
372 journal_ino
= st
.st_ino
;
374 journal_ino
= EXT2_JOURNAL_INO
;
375 if ((retval
= write_journal_inode(fs
, journal_ino
,
380 fs
->super
->s_journal_inum
= journal_ino
;
381 fs
->super
->s_journal_dev
= 0;
382 memset(fs
->super
->s_journal_uuid
, 0,
383 sizeof(fs
->super
->s_journal_uuid
));
384 fs
->super
->s_feature_compat
|= EXT3_FEATURE_COMPAT_HAS_JOURNAL
;
386 ext2fs_mark_super_dirty(fs
);
394 main(int argc
, char **argv
)
401 fprintf(stderr
, "Usage: %s filesystem\n", argv
[0]);
404 device_name
= argv
[1];
406 retval
= ext2fs_open (device_name
, EXT2_FLAG_RW
, 0, 0,
407 unix_io_manager
, &fs
);
409 com_err(argv
[0], retval
, "while opening %s", device_name
);
413 retval
= ext2fs_add_journal_inode(fs
, 1024);
415 com_err(argv
[0], retval
, "while adding journal to %s",
419 retval
= ext2fs_flush(fs
);
421 printf("Warning, had trouble writing out superblocks.\n");