Skip to contentSkip to conversation

btrfs-convert: add reiserfs support

PATCH In review Sean Bartell 2 participants 2 messages May 17, 2010 Btrfs file system

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 btrfs-convert: add reiserfs support

Now that the semester's over, I've finally gotten around to finishing this. Ironically, I no longer have a ReiserFS partition I want to convert :P.

This depends on my previous four patches for btrfs-convert.

This version is usable and quite complete, but I'm unsure about the way it handles xattrs (which will end up both converted and left in the .reiserfs_priv directory) and some of the code that loops over btrfs trees. I've also found some problems with the generic conversion code that I'll look into later.

What should work:
- ReiserFS versions 3.5 and 3.6.
- Files with direct, indirect, and sparse blocks.
- All stat information, file types, and modes.
- Attributes, extended attributes, and ACLs.
- Everything else btrfs-convert supports for ext2.

What doesn't:
- The old, supposedly extinct ReiserFS layout with the superblock at 8K.
- xattrs too big to fit in a leaf block. This is a current limitation of btrfs.

What hasn't been tested:
- Multiple real-world filesystems (I only have one)
- 8192-byte blocks (ReiserFS crashes horribly on mount)

---
 convert/convert.c  |  140 ++++++++-
 convert/convert.h  |    7 +
 convert/reiserfs.c |  890 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 ctree.h            |   11 +
 4 files changed, 1046 insertions(+), 2 deletions(-)
 create mode 100644 convert/reiserfs.c
convert/convert.c +138 -2
index 357d585..30aaf96 100644
@@ -171,8 +171,8 @@ struct btrfs_extent_ops extent_ops = {
 	.free_extent = custom_free_extent,
 };
 
-static int read_disk_extent(struct btrfs_root *root, u64 bytenr,
-		            u64 num_bytes, char *buffer)
+int read_disk_extent(struct btrfs_root *root, u64 bytenr, u64 num_bytes,
+		     char *buffer)
 {
 	int ret;
 	struct btrfs_fs_devices *fs_devs = root->fs_info->fs_devices;
@@ -1794,6 +1794,141 @@ err:
 	return ret;
 }
 
+static u8 imode_to_type(u32 imode)
+{
+#define S_SHIFT 12
+	static unsigned char btrfs_type_by_mode[S_IFMT >> S_SHIFT] = {
+		[S_IFREG >> S_SHIFT]	= BTRFS_FT_REG_FILE,
+		[S_IFDIR >> S_SHIFT]	= BTRFS_FT_DIR,
+		[S_IFCHR >> S_SHIFT]	= BTRFS_FT_CHRDEV,
+		[S_IFBLK >> S_SHIFT]	= BTRFS_FT_BLKDEV,
+		[S_IFIFO >> S_SHIFT]	= BTRFS_FT_FIFO,
+		[S_IFSOCK >> S_SHIFT]	= BTRFS_FT_SOCK,
+		[S_IFLNK >> S_SHIFT]	= BTRFS_FT_SYMLINK,
+	};
+
+	return btrfs_type_by_mode[(imode & S_IFMT) >> S_SHIFT];
+#undef S_SHIFT
+}
+
+static int fix_dir_item_type(struct btrfs_trans_handle *trans,
+			     struct btrfs_root *root, u64 dir, u64 index,
+			     const char *name, int name_len, int type)
+{
+	struct btrfs_path path;
+	struct btrfs_dir_item *di;
+
+	btrfs_init_path(&path);
+
+	di = btrfs_lookup_dir_item(trans, root, &path, dir, name, name_len, 1);
+	if (IS_ERR(di))
+		return PTR_ERR(di);
+	if (!di)
+		return -ENOENT;
+	btrfs_set_dir_type(path.nodes[0], di, type);
+	btrfs_mark_buffer_dirty(path.nodes[0]);
+	btrfs_release_path(root, &path);
+
+	di = btrfs_lookup_dir_index_item(trans, root, &path, dir, index,
+					 name, name_len, 1);
+	if (IS_ERR(di))
+		return PTR_ERR(di);
+	if (!di)
+		return -ENOENT;
+	btrfs_set_dir_type(path.nodes[0], di, type);
+	btrfs_mark_buffer_dirty(path.nodes[0]);
+	btrfs_release_path(root, &path);
+
+	return 0;
+}
+
+int fix_dir_item_types(struct btrfs_trans_handle *trans,
+		       struct btrfs_root *root)
+{
+	struct btrfs_path path;
+	int ret;
+	struct btrfs_key key;
+	struct btrfs_key found_key;
+	struct extent_buffer *node;
+	int slot;
+	int cur_type = BTRFS_FT_UNKNOWN;
+
+	btrfs_init_path(&path);
+
+	key.objectid = BTRFS_FIRST_FREE_OBJECTID;
+	key.type = BTRFS_INODE_ITEM_KEY;
+	key.offset = 0;
+
+	while (1) {
+		ret = btrfs_search_slot(trans, root, &key, &path, 0, 0);
+		if (ret < 0)
+			return ret;
+		node = path.nodes[0];
+		slot = path.slots[0];
+		if (slot >= btrfs_header_nritems(node)) {
+			ret = btrfs_next_leaf(root, &path);
+			if (ret < 0)
+				return ret;
+			if (ret > 0)
+				break; /* finished the whole tree */
+			node = path.nodes[0];
+			slot = path.slots[0];
+		}
+		btrfs_item_key_to_cpu(node, &found_key, slot);
+
+		if (btrfs_key_type(&found_key) == BTRFS_INODE_ITEM_KEY) {
+			/* found an inode, look for refs */
+			struct btrfs_inode_item *ii =
+				btrfs_item_ptr(node, slot,
+					       struct btrfs_inode_item);
+			cur_type = imode_to_type(btrfs_inode_mode(node, ii));
+			key.objectid = found_key.objectid;
+			key.type = BTRFS_INODE_REF_KEY;
+			key.offset = 0;
+			goto next;
+		}
+		if (key.objectid != found_key.objectid
+		    || btrfs_key_type(&key) != btrfs_key_type(&found_key)) {
+			/* no more refs, look for next inode */
+			key.objectid = found_key.objectid + 1;
+			key.type = BTRFS_INODE_ITEM_KEY;
+			key.offset = 0;
+			goto next;
+		}
+		key.offset = found_key.offset + 1;
+		/* leave the root dir's ".." entry alone */
+		if (found_key.objectid == BTRFS_FIRST_FREE_OBJECTID
+		    && found_key.offset == BTRFS_FIRST_FREE_OBJECTID)
+			goto next;
+
+		struct btrfs_inode_ref *ref;
+		ref = btrfs_item_ptr(node, slot, struct btrfs_inode_ref);
+		u32 size = btrfs_item_size_nr(node, slot);
+		while (size) {
+			u64 index = btrfs_inode_ref_index(node, ref);
+			char namebuf[BTRFS_NAME_LEN];
+			u32 name_len = btrfs_inode_ref_name_len(node, ref);
+			BUG_ON(name_len > sizeof(namebuf));
+			read_extent_buffer(node, namebuf, (u64)(ref + 1),
+					   name_len);
+
+			ret = fix_dir_item_type(trans, root, found_key.offset,
+						index, namebuf, name_len,
+						cur_type);
+			if (ret)
+				return ret;
+
+			u32 len = sizeof(*ref) + name_len;
+			ref = (struct btrfs_inode_ref *)((char *)ref + len);
+			size -= len;
+		}
+next:
+		btrfs_release_path(root, &path);
+	}
+	btrfs_release_path(root, &path);
+	return 0;
+}
+
 static int copy_dirtiness(struct extent_io_tree *out,
 			  struct extent_io_tree *in)
 {
@@ -1818,6 +1953,7 @@ static int open_fs(struct convert_fs *fs, const char *devname)
 		{"ext3", ext2_open},
 		{"ext4", ext2_open},
 		{"ext4dev", ext2_open},
+		{"reiserfs", reiserfs_open},
 	};
 
 	int i;
convert/convert.h +7 -0
index 4f31775..d13e929 100644
@@ -41,6 +41,7 @@ struct convert_fs {
 };
 
 int ext2_open(struct convert_fs *fs, const char *name);
+int reiserfs_open(struct convert_fs *fs, const char *name);
 
 struct extent_iterate_data {
 	struct btrfs_trans_handle *trans;
@@ -73,4 +74,10 @@ int add_file_mem_extent(struct extent_iterate_data *priv, u64 file_off,
 int add_file_disk_extent(struct extent_iterate_data *priv, u64 file_off,
 			 u64 disk_off, u64 size);
 
+int fix_dir_item_types(struct btrfs_trans_handle *trans,
+		       struct btrfs_root *root);
+
+int read_disk_extent(struct btrfs_root *root, u64 bytenr, u64 num_bytes,
+		     char *buffer);
+
 #endif
convert/reiserfs.c new file +890 -0

890 lines not on this page · raw message

ctree.h +11 -0
index 64ecf12..eaf5b9f 100644
@@ -290,6 +290,9 @@ struct btrfs_header {
 #define BTRFS_MAX_INLINE_DATA_SIZE(r) (BTRFS_LEAF_DATA_SIZE(r) - \
 					sizeof(struct btrfs_item) - \
 					sizeof(struct btrfs_file_extent_item))
+#define BTRFS_MAX_XATTR_SIZE(r)	(BTRFS_LEAF_DATA_SIZE(r) - \
+				 sizeof(struct btrfs_item) -\
+				 sizeof(struct btrfs_dir_item))
 
 
 /*
@@ -858,6 +861,14 @@ struct btrfs_root {
 #define BTRFS_INODE_NODATASUM		(1 << 0)
 #define BTRFS_INODE_NODATACOW		(1 << 1)
 #define BTRFS_INODE_READONLY		(1 << 2)
+#define BTRFS_INODE_NOCOMPRESS		(1 << 3)
+#define BTRFS_INODE_PREALLOC		(1 << 4)
+#define BTRFS_INODE_SYNC		(1 << 5)
+#define BTRFS_INODE_IMMUTABLE		(1 << 6)
+#define BTRFS_INODE_APPEND		(1 << 7)
+#define BTRFS_INODE_NODUMP		(1 << 8)
+#define BTRFS_INODE_NOATIME		(1 << 9)
+#define BTRFS_INODE_DIRSYNC		(1 << 10)
 
 #define read_eb_member(eb, ptr, type, member, result) (			\
 	read_extent_buffer(eb, (char *)(result),			\
Signature · 1 line
1.7.1
#1 lore raw
Quoted 3 lines · On Monday 17 May 2010 08:26:00 Sean Bartell wrote:

What hasn't been tested:
- Multiple real-world filesystems (I only have one)
- 8192-byte blocks (ReiserFS crashes horribly on mount)

Well, AFAIK 8192 blocks are supported only on platforms that have 8kb m= emory=20
pages (e.g. Alpha), it's a bug it even tries to mount it on x86.

Regards,=20
--=20
Hubert Kario
QBS - Quality Business Software
02-656 Warszawa, ul. Ksawer=C3=B3w 30/85 tel. +48 (22) 646-61-51, 646-74-24 www.qbs.com.pl

System Zarz=C4=85dzania Jako=C5=9Bci=C4=85
zgodny z norm=C4=85 ISO 9001:2000
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" = in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html