[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-id: <1265635693-12182-12-git-send-email-dmonakhov@openvz.org>
Date: Mon, 08 Feb 2010 16:28:13 +0300
From: Dmitry Monakhov <dmonakhov@...nvz.org>
To: linux-ext4@...r.kernel.org
Cc: Jan Kara <jack@...e.cz>, Dmitry Monakhov <dmonakhov@...nvz.org>
Subject: [PATCH 11/11] ext4: add subtree quota support
This patch add full subtree quota support to ext4
mount option: sbtrquota, sbtrjquota, nosbtrjquota
Signed-off-by: Dmitry Monakhov <dmonakhov@...nvz.org>
---
fs/ext4/ext4.h | 1 +
fs/ext4/subtree.c | 15 ++++++++-
fs/ext4/super.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++--
3 files changed, 92 insertions(+), 6 deletions(-)
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index c707c7c..2799c6c 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -766,6 +766,7 @@ struct ext4_inode_info {
#define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000LL /* Block validity checking */
#define EXT4_MOUNT_DISCARD 0x40000000LL /* Issue DISCARD requests */
#define EXT4_MOUNT_SUBTREE 0x80000000LL /* Dedicated subtree */
+#define EXT4_MOUNT_SBTRQUOTA 0x100000000LL /* Subtree quota support */
#define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt
#define set_opt(o, opt) o |= EXT4_MOUNT_##opt
diff --git a/fs/ext4/subtree.c b/fs/ext4/subtree.c
index 40d3d85..a27c245 100644
--- a/fs/ext4/subtree.c
+++ b/fs/ext4/subtree.c
@@ -198,14 +198,25 @@ retry:
/*
* Quota transfer only after xattr update. Because it may be
* impossible to roll back quota changed due to -EDQUOT
- * TODO: add quota transfer here
*/
+ if (sb_any_quota_active(inode->i_sb) && !IS_NOQUOTA(inode)) {
+ unsigned msk = 1 << SBTRQUOTA;
+ qid_t new[MAXQUOTAS];
+ new[SBTRQUOTA] = subtree;
+ vfs_dq_init(inode);
+ ret = inode->i_sb->dq_op->transfer(inode, new, msk);
+ if (ret) {
+ ret = -EDQUOT;
+ goto err;
+ }
+ }
+
EXT4_I_SUBTREE(inode) = subtree;
ret2 = ext4_journal_stop(handle);
if (!ret)
ret = ret2;
return ret;
-
+err:
/*
* Restore xattr to previous value. Xattr is already allocated, so
* operation may fail only due to some serious error.
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 2684453..7efa7c6 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -798,11 +798,17 @@ static inline void ext4_show_quota_options(struct seq_file *seq,
if (sbi->s_qf_names[GRPQUOTA])
seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
+ if (sbi->s_qf_names[SBTRQUOTA])
+ seq_printf(seq, ",trjquota=%s", sbi->s_qf_names[SBTRQUOTA]);
+
if (test_opt(sb, USRQUOTA))
seq_puts(seq, ",usrquota");
if (test_opt(sb, GRPQUOTA))
seq_puts(seq, ",grpquota");
+
+ if (test_opt(sb, SBTRQUOTA))
+ seq_puts(seq, ",trquota");
#endif
}
@@ -1017,7 +1023,7 @@ static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
size_t len, loff_t off);
static ssize_t ext4_quota_write(struct super_block *sb, int type,
const char *data, size_t len, loff_t off);
-
+static qid_t ext4_get_quotid(struct inode *inode, int type, qid_t *new);
static const struct dquot_operations ext4_quota_operations = {
.initialize = dquot_initialize,
.drop = dquot_drop,
@@ -1032,7 +1038,7 @@ static const struct dquot_operations ext4_quota_operations = {
.free_space = dquot_free_space,
.free_inode = dquot_free_inode,
.transfer = dquot_transfer,
- .get_id = dquot_get_id,
+ .get_id = ext4_get_quotid,
.write_dquot = ext4_write_dquot,
.acquire_dquot = ext4_acquire_dquot,
.release_dquot = ext4_release_dquot,
@@ -1111,6 +1117,7 @@ enum {
Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
Opt_data_err_abort, Opt_data_err_ignore,
Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
+ Opt_sbtrquota, Opt_sbtrjquota, Opt_offtsbrquota, Opt_offsbtrjquota,
Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_jqfmt_vfsv1, Opt_quota,
Opt_noquota, Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err,
Opt_resize, Opt_usrquota, Opt_grpquota, Opt_i_version,
@@ -1163,6 +1170,8 @@ static const match_table_t tokens = {
{Opt_usrjquota, "usrjquota=%s"},
{Opt_offgrpjquota, "grpjquota="},
{Opt_grpjquota, "grpjquota=%s"},
+ {Opt_offsbtrjquota, "sbtrjquota="},
+ {Opt_sbtrjquota, "sbtrjquota=%s"},
{Opt_jqfmt_vfsold, "jqfmt=vfsold"},
{Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
{Opt_jqfmt_vfsv1, "jqfmt=vfsv1"},
@@ -1170,6 +1179,7 @@ static const match_table_t tokens = {
{Opt_noquota, "noquota"},
{Opt_quota, "quota"},
{Opt_usrquota, "usrquota"},
+ {Opt_sbtrquota, "sbtrquota"},
{Opt_barrier, "barrier=%u"},
{Opt_barrier, "barrier"},
{Opt_nobarrier, "nobarrier"},
@@ -1472,6 +1482,37 @@ static int parse_options(char *options, struct super_block *sb,
if (!set_qf_name(sb, GRPQUOTA, &args[0]))
return 0;
break;
+#ifdef CONFIG_EXT4_SUBTREE
+ case Opt_sbtrjquota:
+ if (!test_opt(sb, SUBTREE)) {
+ ext4_msg(sb, KERN_ERR, "Cannot use subtree_"
+ "quota without subtree support");
+ return 0;
+ }
+ if (!set_qf_name(sb, SBTRQUOTA, &args[0]))
+ return 0;
+ break;
+ case Opt_offsbtrjquota:
+ if (!clear_qf_name(sb, SBTRQUOTA))
+ return 0;
+ break;
+ case Opt_sbtrquota:
+ if (!test_opt(sb, SUBTREE)) {
+ ext4_msg(sb, KERN_ERR, "Cannot use subtree_"
+ "quota without subtree support");
+ return 0;
+ }
+ set_opt(sbi->s_mount_opt, QUOTA);
+ set_opt(sbi->s_mount_opt, SBTRQUOTA);
+ break;
+#else
+ case Opt_sbtrjquota:
+ case Opt_offsbtrjquota:
+ case Opt_sbtrquota:
+ ext4_msg(sb, KERN_ERR,
+ "subtree quota options not supported");
+ break;
+#endif
case Opt_offusrjquota:
if (!clear_qf_name(sb, USRQUOTA))
return 0;
@@ -1517,18 +1558,22 @@ set_qf_format:
clear_opt(sbi->s_mount_opt, QUOTA);
clear_opt(sbi->s_mount_opt, USRQUOTA);
clear_opt(sbi->s_mount_opt, GRPQUOTA);
+ clear_opt(sbi->s_mount_opt, SBTRQUOTA);
break;
#else
case Opt_quota:
case Opt_usrquota:
case Opt_grpquota:
+ case Opt_sbtrquota:
ext4_msg(sb, KERN_ERR,
"quota options not supported");
break;
case Opt_usrjquota:
case Opt_grpjquota:
+ case Opt_sbtrjquota:
case Opt_offusrjquota:
case Opt_offgrpjquota:
+ case Opt_offsbtrjquota:
case Opt_jqfmt_vfsold:
case Opt_jqfmt_vfsv0:
case Opt_jqfmt_vfsv1:
@@ -1661,14 +1706,19 @@ set_qf_format:
}
}
#ifdef CONFIG_QUOTA
- if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
+ if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA] ||
+ sbi->s_qf_names[SBTRQUOTA]) {
if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
clear_opt(sbi->s_mount_opt, USRQUOTA);
if (test_opt(sb, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA])
clear_opt(sbi->s_mount_opt, GRPQUOTA);
- if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA)) {
+ if (test_opt(sb, SBTRQUOTA) && sbi->s_qf_names[SBTRQUOTA])
+ clear_opt(sbi->s_mount_opt, SBTRQUOTA);
+
+ if (test_opt(sb, GRPQUOTA) || test_opt(sb, USRQUOTA) ||
+ test_opt(sb, SBTRQUOTA)) {
ext4_msg(sb, KERN_ERR, "old and new quota "
"format mixing");
return 0;
@@ -3769,6 +3819,30 @@ static inline struct inode *dquot_to_inode(struct dquot *dquot)
return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
}
+static qid_t ext4_get_quotid(struct inode *inode, int type, qid_t *new)
+{
+ switch (type) {
+ case USRQUOTA:
+ if (new)
+ return new[USRQUOTA];
+ else
+ return inode->i_uid;
+ case GRPQUOTA:
+ if (new)
+ return new[GRPQUOTA];
+ else
+ return inode->i_gid;
+ case SBTRQUOTA:
+ BUG_ON(!test_opt(inode->i_sb, SBTRQUOTA) &&
+ !(EXT4_SB(inode->i_sb)->s_qf_names[SBTRQUOTA]));
+ if (new)
+ return new[SBTRQUOTA];
+ else
+ return EXT4_I(inode)->i_subtree;
+ default:
+ BUG();
+ }
+}
static int ext4_write_dquot(struct dquot *dquot)
{
int ret, err;
--
1.6.3.3
--
To unsubscribe from this list: send the line "unsubscribe linux-ext4" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists