Currently btrfs-convert only copies ext2 inode timestamps i_[cma]time from ext4, while filling 0 to nsec and crtime fields.
This change copies nsec and crtime by parsing i_[cma]time_extra fields. --- convert/source-ext2.c | 81 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 80 insertions(+), 1 deletion(-) diff --git a/convert/source-ext2.c b/convert/source-ext2.c index efe73742..e397e89f 100644 --- a/convert/source-ext2.c +++ b/convert/source-ext2.c @@ -691,6 +691,77 @@ static void ext2_copy_inode_item(struct btrfs_inode_item *dst, } memset(&dst->reserved, 0, sizeof(dst->reserved)); } + +/* + * Copied and modified from fs/ext4/ext4.h + */ +static inline void ext4_decode_extra_time(__le32 * tv_sec, __le32 * tv_nsec, + __le32 extra) +{ + if (extra & cpu_to_le32(EXT4_EPOCH_MASK)) + *tv_sec += (u64)(le32_to_cpu(extra) & EXT4_EPOCH_MASK) << 32; + *tv_nsec = (le32_to_cpu(extra) & EXT4_NSEC_MASK) >> EXT4_EPOCH_BITS; +} + +#define EXT4_COPY_XTIME(xtime, dst, tv_sec, tv_nsec) \ +do { \ + tv_sec = src->i_ ## xtime ; \ + if(inode_includes(inode_size, i_ ## xtime ## _extra)) { \ + tv_sec = src->i_ ## xtime ; \ + ext4_decode_extra_time(&tv_sec, &tv_nsec, src->i_ ## xtime ## _extra); \ + btrfs_set_stack_timespec_sec(&dst->xtime , tv_sec); \ + btrfs_set_stack_timespec_nsec(&dst->xtime , tv_nsec); \ + }else{ \ + btrfs_set_stack_timespec_sec(&dst->xtime , tv_sec); \ + btrfs_set_stack_timespec_nsec(&dst->xtime , 0); \ + } \ +}while (0); + +/* + * Decode and copy i_[cma]time_extra and i_crtime{,_extra} field + */ +static int ext4_copy_inode_timespec_extra(struct btrfs_inode_item *dst, + ext2_ino_t ext2_ino, u32 s_inode_size, ext2_filsys ext2_fs) +{ + + struct ext2_inode_large *src; + u32 inode_size, tv_sec, tv_nsec; + int ret, err; + ret = 0; + + src = (struct ext2_inode_large *)malloc(s_inode_size); + if (!src) + return -ENOMEM; + err = ext2fs_read_inode_full(ext2_fs, ext2_ino, (void *)src, + s_inode_size); + if (err) { + fprintf(stderr, "ext2fs_read_inode_full: %s\n", + error_message(err)); + ret = -1; + goto out; + } + + inode_size = EXT2_GOOD_OLD_INODE_SIZE + src->i_extra_isize; + + EXT4_COPY_XTIME(atime, dst, tv_sec, tv_nsec); + EXT4_COPY_XTIME(mtime, dst, tv_sec, tv_nsec); + EXT4_COPY_XTIME(ctime, dst, tv_sec, tv_nsec); + + tv_sec = src->i_crtime ; + if(inode_includes(inode_size, i_crtime_extra)) { + tv_sec = src->i_crtime; + ext4_decode_extra_time(&tv_sec, &tv_nsec, src->i_crtime_extra); + btrfs_set_stack_timespec_sec(&dst-> otime , tv_sec); + btrfs_set_stack_timespec_nsec(&dst-> otime , tv_nsec); + }else{ + btrfs_set_stack_timespec_sec(&dst-> otime , tv_sec); + btrfs_set_stack_timespec_nsec(&dst-> otime , 0); + } +out: + free(src); + return ret; +} + static int ext2_check_state(struct btrfs_convert_context *cctx) { ext2_filsys fs = cctx->fs_data; @@ -738,13 +809,21 @@ static int ext2_copy_single_inode(struct btrfs_trans_handle *trans, struct ext2_inode *ext2_inode, u32 convert_flags) { - int ret; + int ret, s_inode_size; struct btrfs_inode_item btrfs_inode; if (ext2_inode->i_links_count == 0) return 0; ext2_copy_inode_item(&btrfs_inode, ext2_inode, ext2_fs->blocksize); + s_inode_size = EXT2_INODE_SIZE(ext2_fs->super); + if (s_inode_size > EXT2_GOOD_OLD_INODE_SIZE) { + ret = ext4_copy_inode_timespec_extra(&btrfs_inode, + ext2_ino, s_inode_size, ext2_fs); + if (ret) + return ret; + } + if (!(convert_flags & CONVERT_FLAG_DATACSUM) && S_ISREG(ext2_inode->i_mode)) { u32 flags = btrfs_stack_inode_flags(&btrfs_inode) | -- 2.29.2