diff mbox series

btrfs-progs: btrfs-convert: copy ext4 extra timespec

Message ID 20201225074538.461837-1-farseerfc@gmail.com (mailing list archive)
State New, archived
Headers show
Series btrfs-progs: btrfs-convert: copy ext4 extra timespec | expand

Commit Message

Jiachen YANG Dec. 25, 2020, 7:45 a.m. UTC
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(-)

Comments

David Sterba Jan. 5, 2021, 4:12 p.m. UTC | #1
On Fri, Dec 25, 2020 at 04:45:38PM +0900, Jiachen YANG wrote:
> 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.

Thanks, added to devel, with some coding style fixups. I've also added a
simple test.
diff mbox series

Patch

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) |