[PATCH 6/6] ext4: Implement metagroup support for ext4 filesystem

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Dmitry Monakhov <dmonakhov@xxxxxxxxxx>
---
 fs/ext4/Kconfig           |    8 +++
 fs/ext4/Makefile          |    1 +
 fs/ext4/ext4.h            |    8 ++-
 fs/ext4/ialloc.c          |    5 +-
 fs/ext4/inode.c           |   13 ++++-
 fs/ext4/super.c           |    9 +++-
 fs/ext4/xattr.c           |    7 ++
 fs/ext4/xattr.h           |   11 +++
 fs/ext4/xattr_metagroup.c |  153 +++++++++++++++++++++++++++++++++++++++++++++
 9 files changed, 211 insertions(+), 4 deletions(-)
 create mode 100644 fs/ext4/xattr_metagroup.c

diff --git a/fs/ext4/Kconfig b/fs/ext4/Kconfig
index 9ed1bb1..e3365db 100644
--- a/fs/ext4/Kconfig
+++ b/fs/ext4/Kconfig
@@ -74,6 +74,14 @@ config EXT4_FS_SECURITY
 
 	  If you are not using a security module that requires using
 	  extended attributes for file security labels, say N.
+config EXT4_METAGROUP
+	bool "Ext4 metagroup support"
+	depends on METAGROUP
+	depends on EXT4_FS_XATTR
+	help
+	  Enables metagroup inode identifier support for ext4 filesystem.
+	  This feature allow to assign some id to inodes similar to
+	  uid/gid. 
 
 config EXT4_DEBUG
 	bool "EXT4 debugging support"
diff --git a/fs/ext4/Makefile b/fs/ext4/Makefile
index 8867b2a..62f75b8 100644
--- a/fs/ext4/Makefile
+++ b/fs/ext4/Makefile
@@ -11,3 +11,4 @@ ext4-y	:= balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
 ext4-$(CONFIG_EXT4_FS_XATTR)		+= xattr.o xattr_user.o xattr_trusted.o
 ext4-$(CONFIG_EXT4_FS_POSIX_ACL)	+= acl.o
 ext4-$(CONFIG_EXT4_FS_SECURITY)		+= xattr_security.o
+ext4-$(CONFIG_EXT4_METAGROUP)		+= xattr_metagroup.o
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index b2c01a2..c3f95e7 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -719,6 +719,10 @@ struct ext4_inode_info {
 	 */
 	tid_t i_sync_tid;
 	tid_t i_datasync_tid;
+#ifdef CONFIG_EXT4_METAGROUP
+	/* metagroup id, additional owner identifier similar to uid/gid */
+	unsigned int i_mid;
+#endif
 };
 
 /*
@@ -766,7 +770,9 @@ struct ext4_inode_info {
 #define EXT4_MOUNT_DELALLOC		0x8000000LL /* Delalloc support */
 #define EXT4_MOUNT_DATA_ERR_ABORT	0x10000000LL /* Abort on file data write */
 #define EXT4_MOUNT_BLOCK_VALIDITY	0x20000000LL /* Block validity checking */
-#define EXT4_MOUNT_DISCARD		0x40000000LL /* Issue DISCARD requests */
+#define EXT4_MOUNT_DISCARD		0x40000000LL /* Issue DISCARD requests 
+*/
+#define EXT4_MOUNT_METAGROUP		0x80000000LL /* extended owner id */
 
 #define clear_opt(o, opt)		o &= ~EXT4_MOUNT_##opt
 #define set_opt(o, opt)			o |= EXT4_MOUNT_##opt
diff --git a/fs/ext4/ialloc.c b/fs/ext4/ialloc.c
index f3624ea..535b905 100644
--- a/fs/ext4/ialloc.c
+++ b/fs/ext4/ialloc.c
@@ -1032,7 +1032,10 @@ got:
 	ei->i_state = EXT4_STATE_NEW;
 
 	ei->i_extra_isize = EXT4_SB(sb)->s_want_extra_isize;
-
+#ifdef CONFIG_EXT4_METAGROUP
+	// XXX: move this to generic inode init helper
+	EXT4_I(inode)->i_mid = EXT4_I(dir)->i_mid;
+#endif
 	ret = inode;
 	if (vfs_dq_alloc_inode(inode)) {
 		err = -EDQUOT;
diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c
index e119524..b1b5fdc 100644
--- a/fs/ext4/inode.c
+++ b/fs/ext4/inode.c
@@ -4936,7 +4936,18 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
 	}
 	if (ret)
 		goto bad_inode;
-
+#ifdef CONFIG_EXT4_METAGROUP
+	if(test_opt(inode->i_sb, METAGROUP)) {
+		ret = ext4_metagroup_read(inode, &ei->i_mid);
+		if (ret == -ENODATA) {
+			ei->i_mid = 0;
+			ret = 0;
+		}
+		if (ret)
+			goto bad_inode;
+	} else
+		ei->i_mid = 0;
+#endif
 	if (S_ISREG(inode->i_mode)) {
 		inode->i_op = &ext4_file_inode_operations;
 		inode->i_fop = &ext4_file_operations;
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 80d6c14..cb169f8 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -923,6 +923,9 @@ static int ext4_show_options(struct seq_file *seq, struct vfsmount *vfs)
 	if (test_opt(sb, DISCARD))
 		seq_puts(seq, ",discard");
 
+	if (test_opt(sb, METAGROUP))
+		seq_puts(seq, ",metagroup");
+
 	if (test_opt(sb, NOLOAD))
 		seq_puts(seq, ",norecovery");
 
@@ -1112,7 +1115,7 @@ enum {
 	Opt_stripe, Opt_delalloc, Opt_nodelalloc,
 	Opt_block_validity, Opt_noblock_validity,
 	Opt_inode_readahead_blks, Opt_journal_ioprio,
-	Opt_discard, Opt_nodiscard,
+	Opt_discard, Opt_nodiscard, Opt_metagroup,
 };
 
 static const match_table_t tokens = {
@@ -1181,6 +1184,7 @@ static const match_table_t tokens = {
 	{Opt_noauto_da_alloc, "noauto_da_alloc"},
 	{Opt_discard, "discard"},
 	{Opt_nodiscard, "nodiscard"},
+	{Opt_metagroup, "metagroup"},
 	{Opt_err, NULL},
 };
 
@@ -1612,6 +1616,9 @@ set_qf_format:
 		case Opt_nodiscard:
 			clear_opt(sbi->s_mount_opt, DISCARD);
 			break;
+		case Opt_metagroup:
+			set_opt(sbi->s_mount_opt, METAGROUP);
+			break;
 		default:
 			ext4_msg(sb, KERN_ERR,
 			       "Unrecognized mount option \"%s\" "
diff --git a/fs/ext4/xattr.c b/fs/ext4/xattr.c
index f3a2f7e..a97294b 100644
--- a/fs/ext4/xattr.c
+++ b/fs/ext4/xattr.c
@@ -107,6 +107,10 @@ static struct xattr_handler *ext4_xattr_handler_map[] = {
 #ifdef CONFIG_EXT4_FS_SECURITY
 	[EXT4_XATTR_INDEX_SECURITY]	     = &ext4_xattr_security_handler,
 #endif
+#ifdef CONFIG_EXT4_METAGROUP
+	[EXT4_XATTR_INDEX_METAGROUP]	     = &ext4_xattr_metagroup_handler,
+#endif
+
 };
 
 struct xattr_handler *ext4_xattr_handlers[] = {
@@ -119,6 +123,9 @@ struct xattr_handler *ext4_xattr_handlers[] = {
 #ifdef CONFIG_EXT4_FS_SECURITY
 	&ext4_xattr_security_handler,
 #endif
+#ifdef CONFIG_EXT4_METAGROUP
+	&ext4_xattr_metagroup_handler,
+#endif
 	NULL
 };
 
diff --git a/fs/ext4/xattr.h b/fs/ext4/xattr.h
index 8ede88b..46b8369 100644
--- a/fs/ext4/xattr.h
+++ b/fs/ext4/xattr.h
@@ -21,6 +21,7 @@
 #define EXT4_XATTR_INDEX_TRUSTED		4
 #define	EXT4_XATTR_INDEX_LUSTRE			5
 #define EXT4_XATTR_INDEX_SECURITY	        6
+#define EXT4_XATTR_INDEX_METAGROUP	        7
 
 struct ext4_xattr_header {
 	__le32	h_magic;	/* magic number for identification */
@@ -70,6 +71,7 @@ extern struct xattr_handler ext4_xattr_trusted_handler;
 extern struct xattr_handler ext4_xattr_acl_access_handler;
 extern struct xattr_handler ext4_xattr_acl_default_handler;
 extern struct xattr_handler ext4_xattr_security_handler;
+extern struct xattr_handler ext4_xattr_metagroup_handler;
 
 extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
 
@@ -153,3 +155,12 @@ static inline int ext4_init_security(handle_t *handle, struct inode *inode,
 	return 0;
 }
 #endif
+
+#ifdef CONFIG_EXT4_METAGROUP
+extern int ext4_metagroup_read(struct inode *inode, unsigned int *mid);
+#else
+inline int ext4_metagroup_read(struct inode *inode, unsigned int *mid)
+{
+	return -ENOTSUPP;
+}
+#endif
diff --git a/fs/ext4/xattr_metagroup.c b/fs/ext4/xattr_metagroup.c
new file mode 100644
index 0000000..5585d4d
--- /dev/null
+++ b/fs/ext4/xattr_metagroup.c
@@ -0,0 +1,153 @@
+/*
+ * linux/fs/ext4/xattr_metagroup.c
+ *
+ * Copyright (C) 2010 Parallels Inc
+ * Dmitry Monakhov <dmonakhov@xxxxxxxxxx>
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/quotaops.h>
+#include "ext4_jbd2.h"
+#include "ext4.h"
+#include "xattr.h"
+
+/*
+ * Read metagroup id from inode's xattr
+ * Locking: none
+ */
+int ext4_metagroup_read(struct inode *inode, unsigned int *mid)
+{
+	__le32 dsk_mid;
+	int retval;
+	retval = ext4_xattr_get(inode, EXT4_XATTR_INDEX_METAGROUP, "",
+				&dsk_mid, sizeof (dsk_mid));
+	if (retval > 0 && retval != sizeof(dsk_mid))
+		return -EIO;
+	*mid = le32_to_cpu(dsk_mid);
+	return retval;
+
+}
+
+/*
+ * Save metagroup id to inode's xattr
+ * Locking: none
+ */
+static int ext4_metagroup_write(handle_t *handle, struct inode *inode,
+				unsigned int mid, int xflags)
+{
+	__le32 dsk_mid;
+	int retval;
+	retval = ext4_xattr_set_handle(handle, inode, EXT4_XATTR_INDEX_METAGROUP, "",
+				&dsk_mid, sizeof (dsk_mid), xflags);
+	if (retval > 0 && retval != sizeof(dsk_mid))
+		return -EIO;
+	return retval;
+}
+
+/*
+ * Change metagroup id.
+ * Called under inode->i_mutex
+ */
+static int ext4_metagroup_change(struct inode *inode, unsigned int new_mid)
+{
+	/*
+	 * One data_trans_blocks chunk for xattr update.
+	 * One quota_trans_blocks chunk for quota transfer, and one
+	 * quota_trans_block chunk for emergency quota rollback transfer,
+	 * because quota rollback may result new quota blocks allocation.
+	 */
+	unsigned credits = EXT4_DATA_TRANS_BLOCKS(inode->i_sb) +
+		EXT4_QUOTA_TRANS_BLOCKS(inode->i_sb) * 2;
+	qid_t qid[MAXQUOTAS];
+	int ret, ret2 = 0;
+	unsigned retries = 0;
+	handle_t *handle;
+
+	vfs_dq_init(inode);
+retry:
+	handle = ext4_journal_start(inode, credits);
+	if (IS_ERR(handle)) {
+		ret = PTR_ERR(handle);
+		ext4_std_error(inode->i_sb, ret);
+		goto out;
+	}
+	/* Inode may not have metagroup xattr yet. Create it explicitly */
+	ret = ext4_metagroup_write(handle, inode, EXT4_I(inode)->i_mid,
+			XATTR_CREATE);
+	if (ret == -EEXIST)
+		ret = 0;
+	if (ret) {
+		ret2 = ext4_journal_stop(handle);
+		if (ret2)
+			ret = ret2;
+		if (ret == -ENOSPC &&
+			ext4_should_retry_alloc(inode->i_sb, &retries))
+			goto retry;
+	}
+#ifdef CONFIG_QUOTA
+	qid[MGRQUOTA] = new_mid;
+	if (inode->i_sb->dq_op->transfer(inode, qid, 1 << MGRQUOTA))
+		ret = -EDQUOT;
+#endif
+	ret = ext4_metagroup_write(handle, inode, new_mid, XATTR_REPLACE);
+	if (ret) {
+		/*
+		 * Function may fail only due to fatal error, Nor than less
+		 * we have try to rollback quota changes.
+		 */
+#ifdef CONFIG_QUOTA
+		qid[MGRQUOTA] = EXT4_I(inode)->i_mid;
+		if (inode->i_sb->dq_op->transfer(inode, qid, 1 << MGRQUOTA))
+			ret = -EDQUOT;
+#endif
+		ext4_std_error(inode->i_sb, ret);
+
+	}
+	EXT4_I(inode)->i_mid = new_mid;
+	ret2 = ext4_journal_stop(handle);
+out:
+	if (ret2)
+		ret = ret2;
+	return ret;
+}
+static size_t
+ext4_xattr_metagroup_list(struct dentry *dentry, char *list, size_t list_size,
+		const char *name, size_t name_len, int type)
+{
+	if (list && XATTR_METAGROUP_LEN <= list_size)
+		memcpy(list, XATTR_METAGROUP_PREFIX, XATTR_METAGROUP_LEN);
+	return XATTR_METAGROUP_LEN;
+
+}
+
+static int
+ext4_xattr_metagroup_get(struct dentry *dentry, const char *name,
+		       void *buffer, size_t size, int type)
+{
+	if (strcmp(name, "") != 0)
+		return -EINVAL;
+	return ext4_xattr_get(dentry->d_inode, EXT4_XATTR_INDEX_METAGROUP,
+			      name, buffer, size);
+}
+
+static int
+ext4_xattr_metagroup_set(struct dentry *dentry, const char *name,
+		const void *value, size_t size, int flags, int type)
+{
+	unsigned int new_mid;
+	if (strcmp(name, "") != 0)
+		return -EINVAL;
+	new_mid = simple_strtoul(value, (char **)&value, 0);
+	return ext4_metagroup_change(dentry->d_inode, new_mid);
+}
+
+struct xattr_handler ext4_xattr_metagroup_handler = {
+	.prefix	= XATTR_METAGROUP,
+	.list	= ext4_xattr_metagroup_list,
+	.get	= ext4_xattr_metagroup_get,
+	.set	= ext4_xattr_metagroup_set,
+};
-- 
1.6.6

--
To unsubscribe from this list: send the line "unsubscribe linux-fsdevel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Ext4 Filesystem]     [Union Filesystem]     [Filesystem Testing]     [Ceph Users]     [Ecryptfs]     [AutoFS]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux Cachefs]     [Reiser Filesystem]     [Linux RAID]     [Samba]     [Device Mapper]     [CEPH Development]
  Powered by Linux