From d3cd93cabeac8c153c8ae7b1b7358d6ced86b15e Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Tue, 24 Oct 2000 18:33:16 +0000 Subject: [PATCH] ChangeLog, Makefile.in, ext2_err.et.in, ext2fs.h, jfs_dat.h, mkjournal.c: Makefile.in, ext2fs.h, jfs_dat.h, mkjournal.c: Add functions for creating an ext3 journal on a filesystem. ext2_err.et.in (EXT2_JOURNAL_NOT_BLOCK): Add new error code. .del-ext2_fs.h~7a460879, ChangeLog: ext2_fs.h (EXT2_JOURNAL_INO): Add definition for EXT2_JOURNAL_INO; reserve inode #7 for EXT2_RESIZE_INO. TODO: Commit TOOD suggestion. --- TODO | 6 + include/linux/ChangeLog | 5 + include/linux/ext2_fs.h | 7 ++ lib/ext2fs/ChangeLog | 9 ++ lib/ext2fs/Makefile.in | 5 + lib/ext2fs/ext2_err.et.in | 3 + lib/ext2fs/ext2fs.h | 5 + lib/ext2fs/jfs_dat.h | 64 +++++++++++ lib/ext2fs/mkjournal.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 387 insertions(+) create mode 100644 lib/ext2fs/jfs_dat.h create mode 100644 lib/ext2fs/mkjournal.c diff --git a/TODO b/TODO index cfa08d5..57da4b7 100644 --- a/TODO +++ b/TODO @@ -201,3 +201,9 @@ check_if_mounted() should check to see if the file is in /proc/swaps, to avoid mkfs's or checking a active swap partition. ---------------------------------------------------------------- + +Add a check in configure.in on Linux systems making sure that +/usr/include/linux and /usr/include/asm exist. Otherwise you can have +some very obscure errors! + +----------------------------------------------------------------- diff --git a/include/linux/ChangeLog b/include/linux/ChangeLog index 3d0ccb9..0067f46 100644 --- a/include/linux/ChangeLog +++ b/include/linux/ChangeLog @@ -1,3 +1,8 @@ +2000-10-24 + + * ext2_fs.h (EXT2_JOURNAL_INO): Add definition for + EXT2_JOURNAL_INO; reserve inode #7 for EXT2_RESIZE_INO. + 2000-08-14 * ext2_fs.h: Add comment explaining when journal fields are valid. diff --git a/include/linux/ext2_fs.h b/include/linux/ext2_fs.h index eca1a48..479c9e8 100644 --- a/include/linux/ext2_fs.h +++ b/include/linux/ext2_fs.h @@ -48,6 +48,13 @@ #define EXT2_ACL_DATA_INO 4 /* ACL inode */ #define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ #define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ +/* + * 7 is reserved for EXT2_RESIZE_INO; was used for this in the past + * for the on-line resizing patches, but there is a better way of + * doing this which sct, andreas, and tytso discussed at the + * Filesystem/Storage Management Workshop in Miami (October, 2000). + */ +#define EXT2_JOURNAL_INO 8 /* Journal inode */ /* First non-reserved inode for old ext2 filesystems */ #define EXT2_GOOD_OLD_FIRST_INO 11 diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index 39e4e9e..a996397 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,12 @@ +2000-10-24 + + * Makefile.in, ext2fs.h, jfs_dat.h, mkjournal.c: Add functions for + creating an ext3 journal on a filesystem. + +2000-08-21 + + * ext2_err.et.in (EXT2_JOURNAL_NOT_BLOCK): Add new error code. + 2000-08-22 * unix_io.c: Make massive changes to support a multiple block diff --git a/lib/ext2fs/Makefile.in b/lib/ext2fs/Makefile.in index 428a1ee..6d21d60 100644 --- a/lib/ext2fs/Makefile.in +++ b/lib/ext2fs/Makefile.in @@ -40,6 +40,7 @@ OBJS= ext2_err.o \ llseek.o \ lookup.o \ mkdir.o \ + mkjournal.o \ namei.o \ native.o \ newdir.o \ @@ -89,6 +90,7 @@ SRCS= ext2_err.c \ $(srcdir)/llseek.c \ $(srcdir)/lookup.c \ $(srcdir)/mkdir.c \ + $(srcdir)/mkjournal.c \ $(srcdir)/namei.c \ $(srcdir)/native.c \ $(srcdir)/newdir.c \ @@ -171,6 +173,9 @@ tst_getsize: tst_getsize.o getsize.o $(STATIC_LIBEXT2FS) $(CC) -o tst_getsize tst_getsize.o getsize.o $(STATIC_LIBEXT2FS) \ $(LIBCOM_ERR) +mkjournal: mkjournal.c $(STATIC_LIBEXT2FS) + $(CC) -o mkjournal $(srcdir)/mkjournal.c -DDEBUG $(STATIC_LIBEXT2FS) $(LIBCOM_ERR) $(ALL_CFLAGS) + check:: tst_badblocks tst_iscan ./tst_badblocks ./tst_iscan diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in index e47e141..41a439d 100644 --- a/lib/ext2fs/ext2_err.et.in +++ b/lib/ext2fs/ext2_err.et.in @@ -257,5 +257,8 @@ ec EXT2_ET_CANCEL_REQUESTED, ec EXT2_ET_FILE_TOO_BIG, "Ext2 file too big" +ec EXT2_JOURNAL_NOT_BLOCK, + "Supplied journal device not a block device" + end diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 7c15c4b..da46b69 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -793,6 +793,11 @@ extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ino_t dir_ino, extern errcode_t ext2fs_mkdir(ext2_filsys fs, ino_t parent, ino_t inum, const char *name); +/* mkjournal.c */ +extern errcode_t ext2fs_add_journal_device(ext2_filsys fs, char *device, + blk_t size); +extern errcode_t ext2fs_add_journal_fs(ext2_filsys fs, blk_t size); + /* openfs.c */ extern errcode_t ext2fs_open(const char *name, int flags, int superblock, int block_size, io_manager manager, diff --git a/lib/ext2fs/jfs_dat.h b/lib/ext2fs/jfs_dat.h new file mode 100644 index 0000000..d6ad9c4 --- /dev/null +++ b/lib/ext2fs/jfs_dat.h @@ -0,0 +1,64 @@ +/* + * jfs_dat.h --- stripped down header file which only contains the JFS + * on-disk data structures + */ + +#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ + +/* + * On-disk structures + */ + +/* + * Descriptor block types: + */ + +#define JFS_DESCRIPTOR_BLOCK 1 +#define JFS_COMMIT_BLOCK 2 +#define JFS_SUPERBLOCK 3 + +/* + * Standard header for all descriptor blocks: + */ +typedef struct journal_header_s +{ + __u32 h_magic; + __u32 h_blocktype; + __u32 h_sequence; +} journal_header_t; + + +/* + * The block tag: used to describe a single buffer in the journal + */ +typedef struct journal_block_tag_s +{ + __u32 t_blocknr; /* The on-disk block number */ + __u32 t_flags; /* See below */ +} journal_block_tag_t; + +/* Definitions for the journal tag flags word: */ +#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */ +#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */ +#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */ +#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ + + +/* + * The journal superblock + */ +typedef struct journal_superblock_s +{ + journal_header_t s_header; + + /* Static information describing the journal */ + __u32 s_blocksize; /* journal device blocksize */ + __u32 s_maxlen; /* total blocks in journal file */ + __u32 s_first; /* first block of log information */ + + /* Dynamic information describing the current state of the log */ + __u32 s_sequence; /* first commit ID expected in log */ + __u32 s_start; /* blocknr of start of log */ + +} journal_superblock_t; + diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c new file mode 100644 index 0000000..31a20e3 --- /dev/null +++ b/lib/ext2fs/mkjournal.c @@ -0,0 +1,283 @@ +/* + * mkjournal.c --- make a journal for a filesystem + * + * Copyright (C) 2000 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Public + * License. + * %End-Header% + */ + +#include +#include +#if HAVE_UNISTD_H +#include +#endif +#if HAVE_ERRNO_H +#include +#endif +#include +#include +#if HAVE_SYS_STAT_H +#include +#endif +#if HAVE_SYS_TYPES_H +#include +#endif + +#if EXT2_FLAT_INCLUDES +#include "ext2_fs.h" +#else +#include +#endif + +#include "ext2fs.h" +#include "jfs_dat.h" + +static void init_journal_superblock(journal_superblock_t *jsb, + __u32 blocksize, __u32 size) +{ + jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); + jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK); + jsb->s_header.h_sequence = 0; + jsb->s_blocksize = htonl(blocksize); + jsb->s_maxlen = htonl(size); + jsb->s_first = htonl(1); + jsb->s_sequence = htonl(1); + jsb->s_start = 0; +} + +/* + * This function adds a journal device to a filesystem + */ +errcode_t ext2fs_add_journal_device(ext2_filsys fs, char *device, + blk_t size) +{ + journal_superblock_t jsb; + struct stat st; + errcode_t retval; + char *buf = 0; + blk_t dev_size; + int i, fd, ret_size; + + /* Make sure the device exists and is a block device */ + if (stat(device, &st) < 0) + return errno; + if (!S_ISBLK(st.st_mode)) + return EXT2_JOURNAL_NOT_BLOCK; /* Must be a block device */ + + /* Get the size of the device */ + if ((retval = ext2fs_get_device_size(device, fs->blocksize, + &dev_size))) + return retval; + + if (!size) + size = dev_size; /* Default to the size of the device */ + else if (size > dev_size) + return EINVAL; /* Requested size bigger than device */ + + init_journal_superblock(&jsb, fs->blocksize, size); + + /* Create a block buffer */ + buf = malloc(fs->blocksize); + if (!buf) + return ENOMEM; + + /* Open the device */ + if ((fd = open(device, O_WRONLY)) < 0) { + retval = errno; + goto errout; + } + + /* Write the superblock out */ + memset(buf, 0, fs->blocksize); + memcpy(buf, &jsb, sizeof(jsb)); + retval = EXT2_ET_SHORT_WRITE; + ret_size = write(fd, buf, fs->blocksize); + if (ret_size < 0) { + errno = retval; + goto errout; + } + if (ret_size != fs->blocksize) + goto errout; + memset(buf, 0, fs->blocksize); + + for (i=1; i < size; i++) { + ret_size = write(fd, buf, fs->blocksize); + if (ret_size < 0) { + retval = errno; + goto errout; + } + if (ret_size != fs->blocksize) + goto errout; + } + close(fd); + + fs->super->s_journal_dev = st.st_rdev; + fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; + ext2fs_mark_super_dirty(fs); + + return 0; +errout: + if (buf) + free(buf); + return retval; +} + +/* + * Helper function for creating the journal in the filesystem + */ +struct mkjournal_struct { + int num_blocks; + int newblocks; + char *buf; + errcode_t err; +}; + +static int mkjournal_proc(ext2_filsys fs, + blk_t *blocknr, + e2_blkcnt_t blockcnt, + blk_t ref_block, + int ref_offset, + void *priv_data) +{ + struct mkjournal_struct *es = (struct mkjournal_struct *) priv_data; + blk_t new_blk; + static blk_t last_blk = 0; + char *block; + errcode_t retval; + int group; + + if (*blocknr) { + last_blk = *blocknr; + return 0; + } + retval = ext2fs_new_block(fs, last_blk, 0, &new_blk); + if (retval) { + es->err = retval; + return BLOCK_ABORT; + } + if (blockcnt > 0) + es->num_blocks--; + + es->newblocks++; + retval = io_channel_write_blk(fs->io, new_blk, 1, es->buf); + + if (blockcnt == 0) + memset(es->buf, 0, fs->blocksize); + + if (retval) { + es->err = retval; + return BLOCK_ABORT; + } + *blocknr = new_blk; + ext2fs_mark_block_bitmap(fs->block_map, new_blk); + ext2fs_mark_bb_dirty(fs); + group = ext2fs_group_of_blk(fs, new_blk); + fs->group_desc[group].bg_free_blocks_count--; + fs->super->s_free_blocks_count--; + ext2fs_mark_super_dirty(fs); + + if (es->num_blocks == 0) + return (BLOCK_CHANGED | BLOCK_ABORT); + else + return BLOCK_CHANGED; + +} + +/* + * This function adds a journal inode to a filesystem + */ +errcode_t ext2fs_add_journal_fs(ext2_filsys fs, blk_t size) +{ + journal_superblock_t jsb; + errcode_t retval; + struct ext2_inode inode; + struct mkjournal_struct es; + char *buf; + + init_journal_superblock(&jsb, fs->blocksize, size); + + if ((retval = ext2fs_read_bitmaps(fs))) + return retval; + + if ((retval = ext2fs_read_inode(fs, EXT2_JOURNAL_INO, &inode))) + return retval; + + if (inode.i_blocks > 0) + return EEXIST; + + /* Create the block buffer */ + buf = malloc(fs->blocksize); + if (!buf) + return ENOMEM; + + memset(buf, 0, fs->blocksize); + memcpy(buf, &jsb, sizeof(jsb)); + + es.num_blocks = size; + es.newblocks = 0; + es.buf = buf; + es.err = 0; + + retval = ext2fs_block_iterate2(fs, EXT2_JOURNAL_INO, BLOCK_FLAG_APPEND, + 0, mkjournal_proc, &es); + free(buf); + if (es.err) + return es.err; + + if ((retval = ext2fs_read_inode(fs, EXT2_JOURNAL_INO, &inode))) + return retval; + + inode.i_size += fs->blocksize * size; + inode.i_blocks += (fs->blocksize / 512) * es.newblocks; + inode.i_mtime = inode.i_ctime = time(0); + inode.i_links_count = 1; + inode.i_mode = LINUX_S_IFREG | 0600; + + if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode))) + return retval; + + fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; + fs->super->s_journal_inum = EXT2_JOURNAL_INO; + + ext2fs_mark_super_dirty(fs); + return 0; +} + +#ifdef DEBUG +main(int argc, char **argv) +{ + errcode_t retval; + char *device_name; + ext2_filsys fs; + + if (argc < 2) { + fprintf(stderr, "Usage: %s filesystem\n", argv[0]); + exit(1); + } + device_name = argv[1]; + + retval = ext2fs_open (device_name, EXT2_FLAG_RW, 0, 0, + unix_io_manager, &fs); + if (retval) { + com_err(argv[0], retval, "while opening %s", device_name); + exit(1); + } + + retval = ext2fs_add_journal_fs(fs, 1024); + if (retval) { + com_err(argv[0], retval, "while adding journal to %s", + device_name); + exit(1); + } + retval = ext2fs_flush(fs); + if (retval) { + printf("Warning, had trouble writing out superblocks.\n"); + } + ext2fs_close(fs); + exit(0); + +} +#endif -- 1.8.3.1