Skip to contentSkip to conversation

Btrfs: add ioctl to set compress or cow per file/dir

RFC PATCH In review liubo 3 participants 6 messages Feb 24, 2011 – Feb 25, 2011

Subsystems (2)
lore
Share & tools
lore

liubo

author
#0 lore raw

RFC PATCH 1/1 Btrfs: add ioctl to set compress or cow per file/dir

Data compression and data cow are controlled across the entire FS by mount options right now. ioctls are needed to set this on a per file or per directory basis. This has been proposed previously, but VFS developers wanted us to use generic ioctls rather than btrfs-specific ones.

We need to fit these into the existing per-inode flags, and to use the generic FS_IOCTL_SETFLAGS ioctl. For data compression, there are the existing compression flags of vfs inode, while for datacow, there is no flag to indicate it, which we need to add.
So, what we will do is to add datacow flag in vfs inode flags and then to set or to unset btrfs compress/cow flag on the corresponding btrfs inode's flag per file or per directory. Moreover, we also add a compression type ioctl to make this feature more flexible.

I really expect some advices and comments on the followings:

- In this patch, I made a special ioctl to set compress type, and to record the compress_type per inode on disk, I've consumed some reserved space of btrfs_inode_item, so is this acceptable?
Meanwhile, I got another idea from my collegue, could we just owe the whole compress type thing to new proper mount options, ie,
mount xxx xxx -o compress=a,inode_compress=b?
Seems that this makes mount more flexible.

- When we are inclined to set inode's compression type, should it be a "force" mode?
This is much like the difference between mount as compress and mount as compress-force.

- For directory basis, after compress/cow ioctl on it, any files that are created or renamed in it, or moved into it, will inherit the directory's compress and datacow attribute.
Here comes to some disputes, is it right that renamed and moved files also inherit the father directory's compress & datacow attribute? And if what we are dealing with is directory, should this behaviour be recursive or not?
I'm inclined to leave these recursive things to btrfs-progs if this is necessary.

After this patch, I'll fulfill the corresponding btrfs-progs.

---
 fs/btrfs/ctree.h   |    9 +++++-
 fs/btrfs/inode.c   |   37 ++++++++++++++++++++++++-
 fs/btrfs/ioctl.c   |   76 +++++++++++++++++++++++++++++++++++++++++++++++++--
 fs/btrfs/ioctl.h   |    1 +
 include/linux/fs.h |    2 +
 5 files changed, 119 insertions(+), 6 deletions(-)
fs/btrfs/ctree.h +8 -1
index 7219537..c189183 100644
@@ -587,11 +587,16 @@ struct btrfs_inode_item {
 	/* modification sequence number for NFS */
 	__le64 sequence;
 
+	u8 compress_type;
+
 	/*
 	 * a little future expansion, for more than this we can
 	 * just grow the inode item and version it
 	 */
-	__le64 reserved[4];
+	u8 reserved_8;
+	__le16 reserved_16;
+	__le32 reserved_32;
+	__le64 reserved_64[3];
 	struct btrfs_timespec atime;
 	struct btrfs_timespec ctime;
 	struct btrfs_timespec mtime;
@@ -1478,6 +1483,8 @@ BTRFS_SETGET_FUNCS(inode_gid, struct btrfs_inode_item, gid, 32);
 BTRFS_SETGET_FUNCS(inode_mode, struct btrfs_inode_item, mode, 32);
 BTRFS_SETGET_FUNCS(inode_rdev, struct btrfs_inode_item, rdev, 64);
 BTRFS_SETGET_FUNCS(inode_flags, struct btrfs_inode_item, flags, 64);
+BTRFS_SETGET_FUNCS(inode_compress_type, struct btrfs_inode_item,
+						 compress_type, 8);
 
 static inline struct btrfs_timespec *
 btrfs_inode_atime(struct btrfs_inode_item *inode_item)
fs/btrfs/inode.c +35 -2
index c9bc0af..0e11ad3 100644
@@ -2515,6 +2515,9 @@ static void btrfs_read_locked_inode(struct inode *inode)
 	BTRFS_I(inode)->block_group = btrfs_find_block_group(root, 0,
 						alloc_group_block, 0);
 	btrfs_free_path(path);
+
+	BTRFS_I(inode)->force_compress = btrfs_inode_compress_type(leaf,
+								   inode_item);
 	inode_item = NULL;
 
 	switch (inode->i_mode & S_IFMT) {
@@ -2587,6 +2590,8 @@ static void fill_inode_item(struct btrfs_trans_handle *trans,
 	btrfs_set_inode_rdev(leaf, item, inode->i_rdev);
 	btrfs_set_inode_flags(leaf, item, BTRFS_I(inode)->flags);
 	btrfs_set_inode_block_group(leaf, item, BTRFS_I(inode)->block_group);
+	btrfs_set_inode_compress_type(leaf, item,
+				      BTRFS_I(inode)->force_compress);
 }
 
 /*
@@ -4539,6 +4544,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 	BTRFS_I(inode)->block_group =
 			btrfs_find_block_group(root, 0, alloc_hint, owner);
 
+	BTRFS_I(inode)->force_compress = BTRFS_I(dir)->force_compress;
+
 	key[0].objectid = objectid;
 	btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
 	key[0].offset = 0;
@@ -4578,8 +4585,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 	location->offset = 0;
 	btrfs_set_key_type(location, BTRFS_INODE_ITEM_KEY);
 
-	btrfs_inherit_iflags(inode, dir);
-
 	if ((mode & S_IFREG)) {
 		if (btrfs_test_opt(root, NODATASUM))
 			BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
@@ -4587,6 +4592,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 			BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW;
 	}
 
+	btrfs_inherit_iflags(inode, dir);
+
 	insert_inode_hash(inode);
 	inode_tree_add(inode);
 	return inode;
@@ -6676,6 +6683,30 @@ static int btrfs_getattr(struct vfsmount *mnt,
 	return 0;
 }
 
+/*
+ * If directory is set by cow/compress ioctl, files that be moved/renamed here
+ * will update their inode flags.
+ */
+static inline void btrfs_change_cow_and_compress(struct inode *dir,
+						 struct inode *inode)
+{
+	struct btrfs_inode *b_dir = BTRFS_I(dir);
+	struct btrfs_inode *b_inode = BTRFS_I(inode);
+
+	if (b_dir->flags & BTRFS_INODE_NODATACOW)
+		b_inode->flags |= BTRFS_INODE_NODATACOW;
+	else
+		b_inode->flags &= ~BTRFS_INODE_NODATACOW;
+
+	if (b_dir->flags & BTRFS_INODE_NOCOMPRESS) {
+		b_inode->flags |= BTRFS_INODE_NOCOMPRESS;
+		b_inode->force_compress = BTRFS_COMPRESS_NONE;
+	} else {
+		b_inode->flags &= ~BTRFS_INODE_NOCOMPRESS;
+		b_inode->force_compress = b_dir->force_compress;
+	}
+}
+
 static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 			   struct inode *new_dir, struct dentry *new_dentry)
 {
@@ -6809,6 +6840,8 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		}
 	}
 
+	btrfs_change_cow_and_compress(new_dir, old_inode);
+
 	ret = btrfs_add_link(trans, new_dir, old_inode,
 			     new_dentry->d_name.name,
 			     new_dentry->d_name.len, 0, index);
fs/btrfs/ioctl.c +73 -3

107 lines not on this page · raw message

fs/btrfs/ioctl.h +1 -0
index 8fb3821..a45a0b7 100644
@@ -203,4 +203,5 @@ struct btrfs_ioctl_space_args {
 				   struct btrfs_ioctl_vol_args_v2)
 #define BTRFS_IOC_SUBVOL_GETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 25, __u64)
 #define BTRFS_IOC_SUBVOL_SETFLAGS _IOW(BTRFS_IOCTL_MAGIC, 26, __u64)
+#define BTRFS_IOC_SET_COMPRESS_TYPE _IOW(BTRFS_IOCTL_MAGIC, 27, unsigned int)
 #endif
include/linux/fs.h +2 -0
index 63d069b..235c75e 100644
@@ -353,6 +353,8 @@ struct inodes_stat_t {
 #define FS_TOPDIR_FL			0x00020000 /* Top of directory hierarchies*/
 #define FS_EXTENT_FL			0x00080000 /* Extents */
 #define FS_DIRECTIO_FL			0x00100000 /* Use direct i/o */
+#define FS_NOCOW_FL			0x00200000 /* Do not cow file */
+#define FS_COW_FL			0x00100000 /* Cow file */
 #define FS_RESERVED_FL			0x80000000 /* reserved for ext2 lib */
 
 #define FS_FL_USER_VISIBLE		0x0003DFFF /* User visible flags */
Signature · 1 line
1.6.5.2
#1 lore raw

Excerpts from liubo's message of 2011-02-24 04:40:55 -0500:

Quoted 15 lines

Data compression and data cow are controlled across the entire FS by mount options right now. ioctls are needed to set this on a per file or per directory basis. This has been proposed previously, but VFS developers wanted us to use generic ioctls rather than btrfs-specific ones.

We need to fit these into the existing per-inode flags, and to use the generic FS_IOCTL_SETFLAGS ioctl. For data compression, there are the existing compression flags of vfs inode, while for datacow, there is no flag to indicate it, which we need to add.
So, what we will do is to add datacow flag in vfs inode flags and then to set or to unset btrfs compress/cow flag on the corresponding btrfs inode's flag per file or per directory. Moreover, we also add a compression type ioctl to make this feature more flexible.

Quoted 5 lines

I really expect some advices and comments on the followings:

- In this patch, I made a special ioctl to set compress type, and to record the compress_type per inode on disk, I've consumed some reserved space of btrfs_inode_item, so is this acceptable?

I don't expect people to mix compression types on the disk. There really should just be one true compression method (probably LZO once it has been established for a while). So, I'd prefer that we store this in the super, and just have flags in the inode for enabling or disabling compression.

Quoted 4 lines

Meanwhile, I got another idea from my collegue, could we just owe the whole compress type thing to new proper mount options, ie,
mount xxx xxx -o compress=a,inode_compress=b?
Seems that this makes mount more flexible.

It does make it more flexible, but I think sometimes extra flexibility leads to more QA time and isn't often used by the actual users ;)

Quoted 5 lines

- When we are inclined to set inode's compression type, should it be a "force" mode?
This is much like the difference between mount as compress and mount as compress-force.

I'd store this as flags in the super too.

Quoted 10 lines

- For directory basis, after compress/cow ioctl on it, any files that are created or renamed in it, or moved into it, will inherit the directory's compress and datacow attribute.
Here comes to some disputes, is it right that renamed and moved files also inherit the father directory's compress & datacow attribute? And if what we are dealing with is directory, should this behaviour be recursive or not?
I'm inclined to leave these recursive things to btrfs-progs if this is necessary.

I'd say that if we rename a file into a directory it does inherit, but not make it recursive.

-chris

author
#2 lore raw
Quoted 21 lines · Chris Mason

Excerpts from liubo's message of 2011-02-24 04:40:55 -0500:

Quoted 14 lines

Data compression and data cow are controlled across the entire FS by mount options right now. ioctls are needed to set this on a per file or per directory basis. This has been proposed previously, but VFS developers wanted us to use generic ioctls rather than btrfs-specific ones.

We need to fit these into the existing per-inode flags, and to use the generic FS_IOCTL_SETFLAGS ioctl. For data compression, there are the existing compression flags of vfs inode, while for datacow, there is no flag to indicate it, which we need to add.
So, what we will do is to add datacow flag in vfs inode flags and then to set or to unset btrfs compress/cow flag on the corresponding btrfs inode's flag per file or per directory. Moreover, we also add a compression type ioctl to make this feature more flexible.

Quoted 5 lines

I really expect some advices and comments on the followings:

- In this patch, I made a special ioctl to set compress type, and to record the compress_type per inode on disk, I've consumed some reserved space of btrfs_inode_item, so is this acceptable?

Quoted 5 lines

I don't expect people to mix compression types on the disk. There really should just be one true compression method (probably LZO once it has been established for a while). So, I'd prefer that we store this in the super, and just have flags in the inode for enabling or disabling compression.

It sounds nice and will make code neatly. :)
So, all files & directories will share the same compress type stored in the super.

Quoted 8 lines
Quoted 5 lines

Meanwhile, I got another idea from my collegue, could we just owe the whole compress type thing to new proper mount options, ie,
mount xxx xxx -o compress=a,inode_compress=b?
Seems that this makes mount more flexible.

It does make it more flexible, but I think sometimes extra flexibility leads to more QA time and isn't often used by the actual users ;)

ok.

Quoted 7 lines
Quoted 5 lines

- When we are inclined to set inode's compression type, should it be a "force" mode?
This is much like the difference between mount as compress and mount as compress-force.

I'd store this as flags in the super too.

ok.

Quoted 11 lines
Quoted 10 lines

- For directory basis, after compress/cow ioctl on it, any files that are created or renamed in it, or moved into it, will inherit the directory's compress and datacow attribute.
Here comes to some disputes, is it right that renamed and moved files also inherit the father directory's compress & datacow attribute? And if what we are dealing with is directory, should this behaviour be recursive or not?
I'm inclined to leave these recursive things to btrfs-progs if this is necessary.

Quoted 3 lines

I'd say that if we rename a file into a directory it does inherit, but not make it recursive.

ok, got it.
I will send a new version based on this thread.

Thanks a lot for reviewing!

thanks,
liubo

Quoted 2 lines

-chris

#3 lore raw
In reply to liubo

include/linux/fs.h struct inodes_stat_t { · line 358

Quoted 4 lines · liubo

#define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */

include/linux/fs.h +2 -0
+#define FS_NOCOW_FL			0x00200000 /* Do not cow file */
+#define FS_COW_FL			0x00100000 /* Cow file */
 #define FS_RESERVED_FL			0x80000000 /* reserved for ext2 lib */

I'm assuming that FS_COW_FL should not be the same as FS_DIRECTIO_FL?

Cheers, Andreas

#4 lore raw

Excerpts from Andreas Dilger's message of 2011-02-24 13:37:52 -0500:

Quoted 7 lines · liubo

include/linux/fs.h struct inodes_stat_t { · line 358

Quoted 4 lines

#define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */

include/linux/fs.h +2 -0
+#define FS_NOCOW_FL            0x00200000 /* Do not cow file */
+#define FS_COW_FL            0x00100000 /* Cow file */
 #define FS_RESERVED_FL            0x80000000 /* reserved for ext2 lib */

I'm assuming that FS_COW_FL should not be the same as FS_DIRECTIO_FL?

No, we can do DIRECTIO with COW.

-chris

author
#5 lore raw
Quoted 10 lines · Chris Mason

Excerpts from Andreas Dilger's message of 2011-02-24 13:37:52 -0500:

Quoted 6 lines · liubo

include/linux/fs.h struct inodes_stat_t { · line 358

Quoted 4 lines

#define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */

include/linux/fs.h +2 -0
+#define FS_NOCOW_FL            0x00200000 /* Do not cow file */
+#define FS_COW_FL            0x00100000 /* Cow file */
 #define FS_RESERVED_FL            0x80000000 /* reserved for ext2 lib */

I'm assuming that FS_COW_FL should not be the same as FS_DIRECTIO_FL?

No, we can do DIRECTIO with COW.

Sorry for my fault, thanks for pointing it out.

thanks,
liubo

Quoted 6 lines

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