Document update
[ct-quota-pq.git] / tree-quota-support.patch
blob5a6c7390d8bacf55ce04c205ce871e48e4e75081
1 ext4: add treeid quota support
3 Implement directory tree quota support.
4 - Quota transfer performed in EXT4_IOC_SET_TREEID
5 STATUS: Seems to work, more testing is needed.
6 note: Journalled quota is broken for now due to incorrect block reservation.
8 diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
9 index bd76c0f..615c622 100644
10 --- a/fs/ext4/ext4.h
11 +++ b/fs/ext4/ext4.h
12 @@ -756,6 +756,7 @@ struct ext4_inode_info {
13 #define EXT4_MOUNT_DATA_ERR_ABORT 0x10000000 /* Abort on file data write */
14 #define EXT4_MOUNT_BLOCK_VALIDITY 0x20000000 /* Block validity checking */
15 #define EXT4_MOUNT_TREEID 0x40000000 /* Dirtectory tree id */
16 +#define EXT4_MOUNT_TRQUOTA 0x80000000 /* Dir tree quota support */
18 #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt
19 #define set_opt(o, opt) o |= EXT4_MOUNT_##opt
20 diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c
21 index bf6b500..a5387a4 100644
22 --- a/fs/ext4/ioctl.c
23 +++ b/fs/ext4/ioctl.c
24 @@ -185,6 +185,7 @@ setversion_out:
25 int err;
26 struct ext4_iloc iloc;
27 unsigned int treeid;
28 + qid_t new[MAXQUOTAS];
29 handle_t *handle = NULL;
30 struct inode *dir = IS_ROOT(filp->f_dentry) ?
31 NULL : filp->f_dentry->d_parent->d_inode;
32 @@ -247,7 +248,12 @@ setversion_out:
33 if (err)
34 goto settree_err;
36 - ////FIXME: tree quota transfer here
37 + new[TRQUOTA] = treeid;
38 + err = inode->i_sb->dq_op->transfer(inode, new, 1 << TRQUOTA);
39 + if (err == NO_QUOTA) {
40 + err = -EDQUOT;
41 + goto settree_err;
42 + }
43 ei->i_tree_id = treeid;
44 inode->i_mtime = ext4_current_time(inode);
45 err = ext4_mark_iloc_dirty(handle, inode, &iloc);
46 diff --git a/fs/ext4/super.c b/fs/ext4/super.c
47 index 6b9e4f3..d5c26d9 100644
48 --- a/fs/ext4/super.c
49 +++ b/fs/ext4/super.c
50 @@ -784,11 +784,17 @@ static inline void ext4_show_quota_options(struct seq_file *seq,
51 if (sbi->s_qf_names[GRPQUOTA])
52 seq_printf(seq, ",grpjquota=%s", sbi->s_qf_names[GRPQUOTA]);
54 + if (sbi->s_qf_names[TRQUOTA])
55 + seq_printf(seq, ",trjquota=%s", sbi->s_qf_names[TRQUOTA]);
57 if (test_opt(sb, USRQUOTA))
58 seq_puts(seq, ",usrquota");
60 if (test_opt(sb, GRPQUOTA))
61 seq_puts(seq, ",grpquota");
63 + if (test_opt(sb, TRQUOTA))
64 + seq_puts(seq, ",trquota");
65 #endif
68 @@ -999,7 +1005,7 @@ static ssize_t ext4_quota_read(struct super_block *sb, int type, char *data,
69 size_t len, loff_t off);
70 static ssize_t ext4_quota_write(struct super_block *sb, int type,
71 const char *data, size_t len, loff_t off);
73 +static qid_t ext4_get_quotid(struct inode *inode, int type);
74 static const struct dquot_operations ext4_quota_operations = {
75 .initialize = dquot_initialize,
76 .drop = dquot_drop,
77 @@ -1012,7 +1018,7 @@ static const struct dquot_operations ext4_quota_operations = {
78 .free_space = dquot_free_space,
79 .free_inode = dquot_free_inode,
80 .transfer = dquot_transfer,
81 - .get_id = dquot_get_id,
82 + .get_id = ext4_get_quotid,
83 .write_dquot = ext4_write_dquot,
84 .acquire_dquot = ext4_acquire_dquot,
85 .release_dquot = ext4_release_dquot,
86 @@ -1092,6 +1098,7 @@ enum {
87 Opt_abort, Opt_data_journal, Opt_data_ordered, Opt_data_writeback,
88 Opt_data_err_abort, Opt_data_err_ignore,
89 Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota,
90 + Opt_trquota, Opt_trjquota, Opt_offtrjquota,
91 Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota,
92 Opt_ignore, Opt_barrier, Opt_nobarrier, Opt_err, Opt_resize,
93 Opt_usrquota, Opt_grpquota, Opt_i_version,
94 @@ -1143,9 +1150,12 @@ static const match_table_t tokens = {
95 {Opt_usrjquota, "usrjquota=%s"},
96 {Opt_offgrpjquota, "grpjquota="},
97 {Opt_grpjquota, "grpjquota=%s"},
98 + {Opt_offtrjquota, "trjquota="},
99 + {Opt_trjquota, "trjquota=%s"},
100 {Opt_jqfmt_vfsold, "jqfmt=vfsold"},
101 {Opt_jqfmt_vfsv0, "jqfmt=vfsv0"},
102 {Opt_grpquota, "grpquota"},
103 + {Opt_trquota, "trquota"},
104 {Opt_noquota, "noquota"},
105 {Opt_quota, "quota"},
106 {Opt_usrquota, "usrquota"},
107 @@ -1450,6 +1460,10 @@ static int parse_options(char *options, struct super_block *sb,
108 if (!set_qf_name(sb, GRPQUOTA, &args[0]))
109 return 0;
110 break;
111 + case Opt_trjquota:
112 + if (!set_qf_name(sb, TRQUOTA, &args[0]))
113 + return 0;
114 + break;
115 case Opt_offusrjquota:
116 if (!clear_qf_name(sb, USRQUOTA))
117 return 0;
118 @@ -1458,6 +1472,10 @@ static int parse_options(char *options, struct super_block *sb,
119 if (!clear_qf_name(sb, GRPQUOTA))
120 return 0;
121 break;
122 + case Opt_offtrjquota:
123 + if (!clear_qf_name(sb, TRQUOTA))
124 + return 0;
125 + break;
127 case Opt_jqfmt_vfsold:
128 qfmt = QFMT_VFS_OLD;
129 @@ -1483,6 +1501,10 @@ set_qf_format:
130 set_opt(sbi->s_mount_opt, QUOTA);
131 set_opt(sbi->s_mount_opt, GRPQUOTA);
132 break;
133 + case Opt_trquota:
134 + set_opt(sbi->s_mount_opt, QUOTA);
135 + set_opt(sbi->s_mount_opt, TRQUOTA);
136 + break;
137 case Opt_noquota:
138 if (sb_any_quota_loaded(sb)) {
139 ext4_msg(sb, KERN_ERR, "Cannot change quota "
140 @@ -1492,18 +1514,22 @@ set_qf_format:
141 clear_opt(sbi->s_mount_opt, QUOTA);
142 clear_opt(sbi->s_mount_opt, USRQUOTA);
143 clear_opt(sbi->s_mount_opt, GRPQUOTA);
144 + clear_opt(sbi->s_mount_opt, TRQUOTA);
145 break;
146 #else
147 case Opt_quota:
148 case Opt_usrquota:
149 case Opt_grpquota:
150 + case Opt_trquota:
151 ext4_msg(sb, KERN_ERR,
152 "quota options not supported");
153 break;
154 case Opt_usrjquota:
155 case Opt_grpjquota:
156 + case Opt_trjquota:
157 case Opt_offusrjquota:
158 case Opt_offgrpjquota:
159 + case Opt_offjquota:
160 case Opt_jqfmt_vfsold:
161 case Opt_jqfmt_vfsv0:
162 ext4_msg(sb, KERN_ERR,
163 @@ -1632,15 +1658,30 @@ set_qf_format:
166 #ifdef CONFIG_QUOTA
167 - if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA]) {
168 + if (test_opt(sb, TRQUOTA) && !test_opt(sb, TREEID)) {
169 + if (!EXT4_HAS_INCOMPAT_FEATURE(sb,
170 + EXT4_FEATURE_INCOMPAT_TREEID)){
171 + ext4_msg(sb, KERN_ERR, "treeid option specified"
172 + " with no directory treeid feature "
173 + "enabled. run tune2fs");
174 + return 0;
176 + set_opt(sbi->s_mount_opt, TREEID);
178 + if (sbi->s_qf_names[USRQUOTA] || sbi->s_qf_names[GRPQUOTA] ||
179 + sbi->s_qf_names[TRQUOTA]) {
180 if (test_opt(sb, USRQUOTA) && sbi->s_qf_names[USRQUOTA])
181 clear_opt(sbi->s_mount_opt, USRQUOTA);
183 if (test_opt(sb, GRPQUOTA) && sbi->s_qf_names[GRPQUOTA])
184 clear_opt(sbi->s_mount_opt, GRPQUOTA);
186 + if (test_opt(sb, TRQUOTA) && sbi->s_qf_names[GRPQUOTA])
187 + clear_opt(sbi->s_mount_opt, TRQUOTA);
189 if (sbi->s_mount_opt & (EXT4_MOUNT_USRQUOTA |
190 - EXT4_MOUNT_GRPQUOTA)) {
191 + EXT4_MOUNT_GRPQUOTA |
192 + EXT4_MOUNT_TRQUOTA)) {
193 ext4_msg(sb, KERN_ERR, "old and new quota "
194 "format mixing");
195 return 0;
196 @@ -3737,6 +3778,21 @@ static inline struct inode *dquot_to_inode(struct dquot *dquot)
197 return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type];
200 +static qid_t ext4_get_quotid(struct inode *inode, int type)
202 + switch (type) {
203 + case USRQUOTA:
204 + return inode->i_uid;
205 + case GRPQUOTA:
206 + return inode->i_gid;
207 + case TRQUOTA:
208 + BUG_ON(!test_opt(inode->i_sb, TRQUOTA) &&
209 + !(EXT4_SB(inode->i_sb)->s_qf_names[TRQUOTA]));
210 + return EXT4_I(inode)->i_tree_id;
211 + default:
212 + BUG();
215 static int ext4_write_dquot(struct dquot *dquot)
217 int ret, err;
218 diff --git a/fs/quota/quota.c b/fs/quota/quota.c
219 index a957a72..280703c 100644
220 --- a/fs/quota/quota.c
221 +++ b/fs/quota/quota.c
222 @@ -83,6 +83,7 @@ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd,
223 if (cmd == Q_GETQUOTA) {
224 if (((type == USRQUOTA && current_euid() != id) ||
225 (type == GRPQUOTA && !in_egroup_p(id))) &&
226 + //// FIXME: add directory tree quota related code
227 !capable(CAP_SYS_ADMIN))
228 //// FIXME: Figure out in which container this task
229 //// belongs to. It is strange, but seems it is