diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index 54ef0294..0a0c4982 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,30 @@ +2001-01-15 Theodore Ts'o + + * initialize.c (ext2fs_initialize): Add support for initializing + the ext2 superblock for external journal devices. This + basically means we don't bother to allocate any block + group descriptors. + + * openfs.c (ext2fs_open): Only open external journal devices if + the new flag EXT2_FLAG_JOURNAL_DEV_OK is passed to + ext2fs_open. When opening such devices, don't try to read + the block group descriptors, since they're not there. + + * ext2_err.et.in (EXT2_NO_JOURNAL_SB): Add new error code + + * mkjournal.c: Export a new function, + ext2fs_create_journal_superblock(), which allocates and + returns a buffer containing a journal superblock. This is + needed by mke2fs to create an external journal. Rewrote + ext2fs_add_journal_device() so that it no longer creates + the external journal, but rather adds a filesystem to an + existing external journal. It handles all of the UUID + manipulation. + + * ext2fs.h: List the EXT3_FEATURE_JOURNAL_DEV as a flag supported + by the library. Define the EXT2_FLAG_JOURNAL_DEV_OK. + Changed function prototype for ext2fs_add_journal_device(). + 2001-01-14 Theodore Ts'o * closefs.c (ext2fs_flush): Don't write out anything beyond the diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in index bc79a47d..24bce498 100644 --- a/lib/ext2fs/ext2_err.et.in +++ b/lib/ext2fs/ext2_err.et.in @@ -260,5 +260,8 @@ ec EXT2_ET_FILE_TOO_BIG, ec EXT2_JOURNAL_NOT_BLOCK, "Supplied journal device not a block device" +ec EXT2_NO_JOURNAL_SB, + "Journal superblock not found" + end diff --git a/lib/ext2fs/ext2fs.h b/lib/ext2fs/ext2fs.h index 3b5d2e6d..74bcb5df 100644 --- a/lib/ext2fs/ext2fs.h +++ b/lib/ext2fs/ext2fs.h @@ -159,7 +159,7 @@ typedef struct ext2_file *ext2_file_t; #define EXT2_SEEK_END 2 /* - * Flags for the ext2_filsys structure + * Flags for the ext2_filsys structure and for ext2fs_open() */ #define EXT2_FLAG_RW 0x01 #define EXT2_FLAG_CHANGED 0x02 @@ -173,6 +173,7 @@ typedef struct ext2_file *ext2_file_t; #define EXT2_FLAG_MASTER_SB_ONLY 0x200 #define EXT2_FLAG_FORCE 0x400 #define EXT2_FLAG_SUPER_ONLY 0x800 +#define EXT2_FLAG_JOURNAL_DEV_OK 0x1000 /* * Special flag in the ext2 inode i_flag field that means that this is @@ -412,9 +413,11 @@ typedef struct ext2_icount *ext2_icount_t; #endif #define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\ EXT2_FEATURE_INCOMPAT_COMPRESSION|\ + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\ EXT3_FEATURE_INCOMPAT_RECOVER) #else #define EXT2_LIB_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE|\ + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV|\ EXT3_FEATURE_INCOMPAT_RECOVER) #endif #define EXT2_LIB_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER|\ @@ -717,8 +720,11 @@ extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum const char *name); /* mkjournal.c */ -extern errcode_t ext2fs_add_journal_device(ext2_filsys fs, char *device, - blk_t size, int flags); +extern errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, + __u32 size, int flags, + char **ret_jsb); +extern errcode_t ext2fs_add_journal_device(ext2_filsys fs, + ext2_filsys journal_dev); extern errcode_t ext2fs_add_journal_inode(ext2_filsys fs, blk_t size, int flags); diff --git a/lib/ext2fs/initialize.c b/lib/ext2fs/initialize.c index 9fe76a4b..6251339d 100644 --- a/lib/ext2fs/initialize.c +++ b/lib/ext2fs/initialize.c @@ -144,6 +144,18 @@ errcode_t ext2fs_initialize(const char *name, int flags, goto cleanup; } + /* + * If we're creating an external journal device, we don't need + * to bother with the rest. + */ + if (super->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { + fs->group_desc_count = 0; + ext2fs_mark_super_dirty(fs); + *ret_fs = fs; + return 0; + } + retry: fs->group_desc_count = (super->s_blocks_count - super->s_first_data_block + diff --git a/lib/ext2fs/mkjournal.c b/lib/ext2fs/mkjournal.c index e8ab6836..73b4b029 100644 --- a/lib/ext2fs/mkjournal.c +++ b/lib/ext2fs/mkjournal.c @@ -39,20 +39,45 @@ #include "ext2fs.h" #include "jfs_user.h" -static void init_journal_superblock(journal_superblock_t *jsb, - __u32 blocksize, __u32 size, int flags) +/* + * This function automatically sets up the journal superblock and + * returns it as an allocated block. + */ +errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, + __u32 size, int flags, + char **ret_jsb) { - memset (jsb, 0, sizeof(*jsb)); + errcode_t retval; + journal_superblock_t *jsb; + + if ((retval = ext2fs_get_mem(fs->blocksize, (void **) &jsb))) + return retval; + + memset (jsb, 0, fs->blocksize); jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); if (flags & EXT2_MKJOURNAL_V1_SUPER) jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1); else jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); - jsb->s_blocksize = htonl(blocksize); + jsb->s_blocksize = htonl(fs->blocksize); jsb->s_maxlen = htonl(size); jsb->s_first = htonl(1); jsb->s_sequence = htonl(1); + memcpy(jsb->s_uuid, fs->super->s_uuid, sizeof(fs->super->s_uuid)); + jsb->s_nr_users = 1; + /* + * Now for the special settings if we're creating an external + * journal device + */ + if (fs->super->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { + jsb->s_nr_users = 0; + jsb->s_first = htonl(fs->super->s_first_data_block+2); + } + + *ret_jsb = (char *) jsb; + return 0; } /* @@ -60,34 +85,27 @@ static void init_journal_superblock(journal_superblock_t *jsb, * for creating external journals and creating journals on live * filesystems. */ -static errcode_t write_journal_file(ext2_filsys fs, char *device, +static errcode_t write_journal_file(ext2_filsys fs, char *filename, blk_t size, int flags) { errcode_t retval; char *buf = 0; - journal_superblock_t jsb; int i, fd, ret_size; - init_journal_superblock(&jsb, fs->blocksize, size, flags); + if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) + return retval; - /* Create a block buffer */ - buf = malloc(fs->blocksize); - if (!buf) - return ENOMEM; - - /* Open the device */ - if ((fd = open(device, O_WRONLY)) < 0) { + /* Open the device or journal file */ + if ((fd = open(filename, 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; + retval = errno; goto errout; } if (ret_size != fs->blocksize) @@ -107,7 +125,7 @@ static errcode_t write_journal_file(ext2_filsys fs, char *device, retval = 0; errout: - free(buf); + ext2fs_free_mem((void **) &buf); return retval; } @@ -177,14 +195,14 @@ static int mkjournal_proc(ext2_filsys fs, static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, blk_t size, int flags) { - journal_superblock_t jsb; + char *buf; errcode_t retval; struct ext2_inode inode; struct mkjournal_struct es; - char *buf; - - init_journal_superblock(&jsb, fs->blocksize, size, flags); + if ((retval = ext2fs_create_journal_superblock(fs, size, flags, &buf))) + return retval; + if ((retval = ext2fs_read_bitmaps(fs))) return retval; @@ -194,14 +212,6 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, 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; @@ -209,12 +219,13 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, retval = ext2fs_block_iterate2(fs, journal_ino, BLOCK_FLAG_APPEND, 0, mkjournal_proc, &es); - free(buf); - if (es.err) - return es.err; + if (es.err) { + retval = es.err; + goto errout; + } if ((retval = ext2fs_read_inode(fs, journal_ino, &inode))) - return retval; + goto errout; inode.i_size += fs->blocksize * size; inode.i_blocks += (fs->blocksize / 512) * es.newblocks; @@ -223,44 +234,65 @@ static errcode_t write_journal_inode(ext2_filsys fs, ext2_ino_t journal_ino, inode.i_mode = LINUX_S_IFREG | 0600; if ((retval = ext2fs_write_inode(fs, journal_ino, &inode))) - return retval; + goto errout; + retval = 0; - return 0; +errout: + ext2fs_free_mem((void **) &buf); + return retval; } /* * This function adds a journal device to a filesystem */ -errcode_t ext2fs_add_journal_device(ext2_filsys fs, char *device, - blk_t size, int flags) +errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) { struct stat st; errcode_t retval; - blk_t dev_size; + char buf[1024]; + journal_superblock_t *jsb; + int i; + __u32 nr_users; /* Make sure the device exists and is a block device */ - if (stat(device, &st) < 0) + if (stat(fs->device_name, &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))) + /* Get the journal superblock */ + if ((retval = io_channel_read_blk(journal_dev->io, 1, -1024, buf))) 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 */ + jsb = (journal_superblock_t *) buf; + if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || + (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) + return EXT2_NO_JOURNAL_SB; - retval = write_journal_file(fs, device, size, flags); - if (retval) + if (ntohl(jsb->s_blocksize) != fs->blocksize) + return EXT2_ET_UNEXPECTED_BLOCK_SIZE; + + /* Check and see if this filesystem has already been added */ + nr_users = ntohl(jsb->s_nr_users); + for (i=0; i < nr_users; i++) { + if (memcmp(fs->super->s_uuid, + &jsb->s_users[i*16], 16) == 0) + break; + } + if (i >= nr_users) { + memcpy(&jsb->s_users[nr_users*16], + fs->super->s_uuid, 16); + jsb->s_nr_users = htonl(nr_users+1); + } + + /* Writeback the journal superblock */ + if ((retval = io_channel_write_blk(journal_dev->io, 1, -1024, buf))) return retval; fs->super->s_journal_inum = 0; fs->super->s_journal_dev = st.st_rdev; - memset(fs->super->s_journal_uuid, 0, + memcpy(fs->super->s_journal_uuid, jsb->s_uuid, sizeof(fs->super->s_journal_uuid)); fs->super->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; ext2fs_mark_super_dirty(fs); diff --git a/lib/ext2fs/openfs.c b/lib/ext2fs/openfs.c index 1b1430d8..3b9531a1 100644 --- a/lib/ext2fs/openfs.c +++ b/lib/ext2fs/openfs.c @@ -138,6 +138,12 @@ errcode_t ext2fs_open(const char *name, int flags, int superblock, retval = EXT2_ET_RO_UNSUPP_FEATURE; goto cleanup; } + if (!(flags & EXT2_FLAG_JOURNAL_DEV_OK) && + (fs->super->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { + retval = EXT2_ET_UNSUPP_FEATURE; + goto cleanup; + } } fs->blocksize = EXT2_BLOCK_SIZE(fs->super); @@ -160,6 +166,17 @@ errcode_t ext2fs_open(const char *name, int flags, int superblock, * Set the blocksize to the filesystem's blocksize. */ io_channel_set_blksize(fs->io, fs->blocksize); + + /* + * If this is an external journal device, don't try to read + * the group descriptors, because they're not there. + */ + if (fs->super->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_JOURNAL_DEV) { + fs->group_desc_count = 0; + *ret_fs = fs; + return 0; + } /* * Read group descriptors