1 From: Jan Kara <jack@suse.cz>
3 Implement conversion functions for new version (version 1) of quota format
4 which supports 64-bit block and inode limits and 64-bit inode usage. The
5 original implementation has been written by Andrew Perepechko.
7 Signed-off-by: Andrew Perepechko <andrew.perepechko@sun.com>
8 Signed-off-by: Jan Kara <jack@suse.cz>
9 Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
11 diff --git a/fs/quota/quota_v2.c a/fs/quota/quota_v2.c
12 --- a/fs/quota/quota_v2.c
13 +++ b/fs/quota/quota_v2.c
16 #define __QUOTA_V2_PARANOIA
18 -static void v2_mem2diskdqb(void *dp, struct dquot *dquot);
19 -static void v2_disk2memdqb(struct dquot *dquot, void *dp);
20 -static int v2_is_id(void *dp, struct dquot *dquot);
22 -static struct qtree_fmt_operations v2_qtree_ops = {
23 - .mem2disk_dqblk = v2_mem2diskdqb,
24 - .disk2mem_dqblk = v2_disk2memdqb,
26 +static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot);
27 +static void v2r0_disk2memdqb(struct dquot *dquot, void *dp);
28 +static int v2r0_is_id(void *dp, struct dquot *dquot);
29 +static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
30 +static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
31 +static int v2r1_is_id(void *dp, struct dquot *dquot);
33 +static struct qtree_fmt_operations v2r0_qtree_ops = {
34 + .mem2disk_dqblk = v2r0_mem2diskdqb,
35 + .disk2mem_dqblk = v2r0_disk2memdqb,
36 + .is_id = v2r0_is_id,
39 +static struct qtree_fmt_operations v2r1_qtree_ops = {
40 + .mem2disk_dqblk = v2r1_mem2diskdqb,
41 + .disk2mem_dqblk = v2r1_disk2memdqb,
42 + .is_id = v2r1_is_id,
45 #define QUOTABLOCK_BITS 10
47 return blocks << QUOTABLOCK_BITS;
50 +static int v2_read_header(struct super_block *sb, int type,
51 + struct v2_disk_dqheader *dqhead)
55 + size = sb->s_op->quota_read(sb, type, (char *)dqhead,
56 + sizeof(struct v2_disk_dqheader), 0);
57 + if (size != sizeof(struct v2_disk_dqheader)) {
58 + printk("quota_v2: failed read expected=%zd got=%zd",
59 + sizeof(struct v2_disk_dqheader), size);
65 /* Check whether given file is really vfsv0 quotafile */
66 static int v2_check_quota_file(struct super_block *sb, int type)
68 struct v2_disk_dqheader dqhead;
70 static const uint quota_magics[] = V2_INITQMAGICS;
71 static const uint quota_versions[] = V2_INITQVERSIONS;
73 - size = sb->s_op->quota_read(sb, type, (char *)&dqhead,
74 - sizeof(struct v2_disk_dqheader), 0);
75 - if (size != sizeof(struct v2_disk_dqheader)) {
76 - printk("quota_v2: failed read expected=%zd got=%zd\n",
77 - sizeof(struct v2_disk_dqheader), size);
78 + if (!v2_read_header(sb, type, &dqhead))
81 if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
82 - le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
83 + le32_to_cpu(dqhead.dqh_version) > quota_versions[type])
88 static int v2_read_file_info(struct super_block *sb, int type)
90 struct v2_disk_dqinfo dinfo;
91 + struct v2_disk_dqheader dqhead;
92 struct mem_dqinfo *info = sb_dqinfo(sb, type);
93 struct qtree_mem_dqinfo *qinfo;
95 + unsigned int version;
97 + if (!v2_read_header(sb, type, &dqhead))
99 + version = le32_to_cpu(dqhead.dqh_version);
101 size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
102 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
106 qinfo = info->dqi_priv;
107 - /* limits are stored as unsigned 32-bit data */
108 - info->dqi_maxblimit = 0xffffffff;
109 - info->dqi_maxilimit = 0xffffffff;
110 + if (version == 0) {
111 + /* limits are stored as unsigned 32-bit data */
112 + info->dqi_maxblimit = 0xffffffff;
113 + info->dqi_maxilimit = 0xffffffff;
115 + /* used space is stored as unsigned 64-bit value */
116 + info->dqi_maxblimit = 0xffffffffffffffffULL; /* 2^64-1 */
117 + info->dqi_maxilimit = 0xffffffffffffffffULL;
119 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
120 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
121 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
123 qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
124 qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
125 qinfo->dqi_qtree_depth = qtree_depth(qinfo);
126 - qinfo->dqi_entry_size = sizeof(struct v2_disk_dqblk);
127 - qinfo->dqi_ops = &v2_qtree_ops;
128 + if (version == 0) {
129 + qinfo->dqi_entry_size = sizeof(struct v2r0_disk_dqblk);
130 + qinfo->dqi_ops = &v2r0_qtree_ops;
132 + qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk);
133 + qinfo->dqi_ops = &v2r1_qtree_ops;
142 -static void v2_disk2memdqb(struct dquot *dquot, void *dp)
143 +static void v2r0_disk2memdqb(struct dquot *dquot, void *dp)
145 - struct v2_disk_dqblk *d = dp, empty;
146 + struct v2r0_disk_dqblk *d = dp, empty;
147 struct mem_dqblk *m = &dquot->dq_dqb;
149 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
150 @@ -149,15 +184,15 @@
151 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
152 m->dqb_btime = le64_to_cpu(d->dqb_btime);
153 /* We need to escape back all-zero structure */
154 - memset(&empty, 0, sizeof(struct v2_disk_dqblk));
155 + memset(&empty, 0, sizeof(struct v2r0_disk_dqblk));
156 empty.dqb_itime = cpu_to_le64(1);
157 - if (!memcmp(&empty, dp, sizeof(struct v2_disk_dqblk)))
158 + if (!memcmp(&empty, dp, sizeof(struct v2r0_disk_dqblk)))
162 -static void v2_mem2diskdqb(void *dp, struct dquot *dquot)
163 +static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
165 - struct v2_disk_dqblk *d = dp;
166 + struct v2r0_disk_dqblk *d = dp;
167 struct mem_dqblk *m = &dquot->dq_dqb;
168 struct qtree_mem_dqinfo *info =
169 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
171 d->dqb_itime = cpu_to_le64(1);
174 -static int v2_is_id(void *dp, struct dquot *dquot)
175 +static int v2r0_is_id(void *dp, struct dquot *dquot)
177 + struct v2r0_disk_dqblk *d = dp;
178 + struct qtree_mem_dqinfo *info =
179 + sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
181 + if (qtree_entry_unused(info, dp))
183 + return le32_to_cpu(d->dqb_id) == dquot->dq_id;
186 +static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
188 + struct v2r1_disk_dqblk *d = dp, empty;
189 + struct mem_dqblk *m = &dquot->dq_dqb;
191 + m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
192 + m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
193 + m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
194 + m->dqb_itime = le64_to_cpu(d->dqb_itime);
195 + m->dqb_bhardlimit = v2_qbtos(le64_to_cpu(d->dqb_bhardlimit));
196 + m->dqb_bsoftlimit = v2_qbtos(le64_to_cpu(d->dqb_bsoftlimit));
197 + m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
198 + m->dqb_btime = le64_to_cpu(d->dqb_btime);
199 + /* We need to escape back all-zero structure */
200 + memset(&empty, 0, sizeof(struct v2r1_disk_dqblk));
201 + empty.dqb_itime = cpu_to_le64(1);
202 + if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk)))
206 +static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
208 + struct v2r1_disk_dqblk *d = dp;
209 + struct mem_dqblk *m = &dquot->dq_dqb;
210 + struct qtree_mem_dqinfo *info =
211 + sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
213 + d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
214 + d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
215 + d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
216 + d->dqb_itime = cpu_to_le64(m->dqb_itime);
217 + d->dqb_bhardlimit = cpu_to_le64(v2_stoqb(m->dqb_bhardlimit));
218 + d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
219 + d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
220 + d->dqb_btime = cpu_to_le64(m->dqb_btime);
221 + d->dqb_id = cpu_to_le32(dquot->dq_id);
222 + if (qtree_entry_unused(info, dp))
223 + d->dqb_itime = cpu_to_le64(1);
226 +static int v2r1_is_id(void *dp, struct dquot *dquot)
228 - struct v2_disk_dqblk *d = dp;
229 + struct v2r1_disk_dqblk *d = dp;
230 struct qtree_mem_dqinfo *info =
231 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
233 @@ -301,20 +303,32 @@ static struct quota_format_ops v2_format
234 .release_dqblk = v2_release_dquot,
237 -static struct quota_format_type v2_quota_format = {
238 +static struct quota_format_type v2r0_quota_format = {
239 .qf_fmt_id = QFMT_VFS_V0,
240 .qf_ops = &v2_format_ops,
241 .qf_owner = THIS_MODULE
244 +static struct quota_format_type v2r1_quota_format = {
245 + .qf_fmt_id = QFMT_VFS_V1,
246 + .qf_ops = &v2_format_ops,
247 + .qf_owner = THIS_MODULE
250 static int __init init_v2_quota_format(void)
252 - return register_quota_format(&v2_quota_format);
255 + ret = register_quota_format(&v2r0_quota_format);
258 + return register_quota_format(&v2r1_quota_format);
261 static void __exit exit_v2_quota_format(void)
263 - unregister_quota_format(&v2_quota_format);
264 + unregister_quota_format(&v2r0_quota_format);
265 + unregister_quota_format(&v2r1_quota_format);
268 module_init(init_v2_quota_format);
269 diff --git a/fs/quota/quotaio_v2.h b/fs/quota/quotaio_v2.h
270 --- a/fs/quota/quotaio_v2.h
271 +++ b/fs/quota/quotaio_v2.h
275 #define V2_INITQVERSIONS {\
282 /* First generic header */
283 @@ -28,11 +28,11 @@ struct v2_disk_dqheader {
287 - * The following structure defines the format of the disk quota file
288 - * (as it appears on disk) - the file is a radix tree whose leaves point
289 - * to blocks of these structures.
290 + * The following structure defines the format of the disk quota file in version
291 + * 0 - the file is a radix tree whose leaves point to blocks of these
294 -struct v2_disk_dqblk {
295 +struct v2r0_disk_dqblk {
296 __le32 dqb_id; /* id this quota applies to */
297 __le32 dqb_ihardlimit; /* absolute limit on allocated inodes */
298 __le32 dqb_isoftlimit; /* preferred inode limit */
299 @@ -44,6 +44,20 @@ struct v2_disk_dqblk {
300 __le64 dqb_itime; /* time limit for excessive inode use */
303 +/* The same structure in quota file version 1 */
304 +struct v2r1_disk_dqblk {
305 + __le32 dqb_id; /* id this quota applies to */
306 + __le32 dqb_padding; /* padding field */
307 + __le64 dqb_ihardlimit; /* absolute limit on allocated inodes */
308 + __le64 dqb_isoftlimit; /* preferred inode limit */
309 + __le64 dqb_curinodes; /* current # allocated inodes */
310 + __le64 dqb_bhardlimit; /* absolute limit on disk space */
311 + __le64 dqb_bsoftlimit; /* preferred limit on disk space */
312 + __le64 dqb_curspace; /* current space occupied (in bytes) */
313 + __le64 dqb_btime; /* time limit for excessive disk use */
314 + __le64 dqb_itime; /* time limit for excessive inode use */
317 /* Header with type and version specific information */
318 struct v2_disk_dqinfo {
319 __le32 dqi_bgrace; /* Time before block soft limit becomes hard limit */
321 diff --git a/include/linux/quota.h b/include/linux/quota.h
322 --- a/include/linux/quota.h
323 +++ b/include/linux/quota.h
325 /* Quota format type IDs */
326 #define QFMT_VFS_OLD 1
327 #define QFMT_VFS_V0 2
328 +#define QFMT_OCFS2 3
329 +#define QFMT_VFS_V1 4
331 /* Size of block in which space limits are passed through the quota
333 @@ -398,6 +398,7 @@ struct quota_module_name {
334 #define INIT_QUOTA_MODULE_NAMES {\
335 {QFMT_VFS_OLD, "quota_v1"},\
336 {QFMT_VFS_V0, "quota_v2"},\
337 + {QFMT_VFS_V1, "quota_v2"},\