aboutsummaryrefslogtreecommitdiffstats
path: root/fs/quota/quota_v2.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/quota/quota_v2.c')
-rw-r--r--fs/quota/quota_v2.c167
1 files changed, 133 insertions, 34 deletions
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c
index a5475fb1ae4..3dfc23e0213 100644
--- a/fs/quota/quota_v2.c
+++ b/fs/quota/quota_v2.c
@@ -23,14 +23,23 @@ MODULE_LICENSE("GPL");
23 23
24#define __QUOTA_V2_PARANOIA 24#define __QUOTA_V2_PARANOIA
25 25
26static void v2_mem2diskdqb(void *dp, struct dquot *dquot); 26static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot);
27static void v2_disk2memdqb(struct dquot *dquot, void *dp); 27static void v2r0_disk2memdqb(struct dquot *dquot, void *dp);
28static int v2_is_id(void *dp, struct dquot *dquot); 28static int v2r0_is_id(void *dp, struct dquot *dquot);
29 29static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot);
30static struct qtree_fmt_operations v2_qtree_ops = { 30static void v2r1_disk2memdqb(struct dquot *dquot, void *dp);
31 .mem2disk_dqblk = v2_mem2diskdqb, 31static int v2r1_is_id(void *dp, struct dquot *dquot);
32 .disk2mem_dqblk = v2_disk2memdqb, 32
33 .is_id = v2_is_id, 33static struct qtree_fmt_operations v2r0_qtree_ops = {
34 .mem2disk_dqblk = v2r0_mem2diskdqb,
35 .disk2mem_dqblk = v2r0_disk2memdqb,
36 .is_id = v2r0_is_id,
37};
38
39static struct qtree_fmt_operations v2r1_qtree_ops = {
40 .mem2disk_dqblk = v2r1_mem2diskdqb,
41 .disk2mem_dqblk = v2r1_disk2memdqb,
42 .is_id = v2r1_is_id,
34}; 43};
35 44
36#define QUOTABLOCK_BITS 10 45#define QUOTABLOCK_BITS 10
@@ -46,23 +55,33 @@ static inline qsize_t v2_qbtos(qsize_t blocks)
46 return blocks << QUOTABLOCK_BITS; 55 return blocks << QUOTABLOCK_BITS;
47} 56}
48 57
58static int v2_read_header(struct super_block *sb, int type,
59 struct v2_disk_dqheader *dqhead)
60{
61 ssize_t size;
62
63 size = sb->s_op->quota_read(sb, type, (char *)dqhead,
64 sizeof(struct v2_disk_dqheader), 0);
65 if (size != sizeof(struct v2_disk_dqheader)) {
66 printk(KERN_WARNING "quota_v2: Failed header read:"
67 " expected=%zd got=%zd\n",
68 sizeof(struct v2_disk_dqheader), size);
69 return 0;
70 }
71 return 1;
72}
73
49/* Check whether given file is really vfsv0 quotafile */ 74/* Check whether given file is really vfsv0 quotafile */
50static int v2_check_quota_file(struct super_block *sb, int type) 75static int v2_check_quota_file(struct super_block *sb, int type)
51{ 76{
52 struct v2_disk_dqheader dqhead; 77 struct v2_disk_dqheader dqhead;
53 ssize_t size;
54 static const uint quota_magics[] = V2_INITQMAGICS; 78 static const uint quota_magics[] = V2_INITQMAGICS;
55 static const uint quota_versions[] = V2_INITQVERSIONS; 79 static const uint quota_versions[] = V2_INITQVERSIONS;
56 80
57 size = sb->s_op->quota_read(sb, type, (char *)&dqhead, 81 if (!v2_read_header(sb, type, &dqhead))
58 sizeof(struct v2_disk_dqheader), 0);
59 if (size != sizeof(struct v2_disk_dqheader)) {
60 printk("quota_v2: failed read expected=%zd got=%zd\n",
61 sizeof(struct v2_disk_dqheader), size);
62 return 0; 82 return 0;
63 }
64 if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] || 83 if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
65 le32_to_cpu(dqhead.dqh_version) != quota_versions[type]) 84 le32_to_cpu(dqhead.dqh_version) > quota_versions[type])
66 return 0; 85 return 0;
67 return 1; 86 return 1;
68} 87}
@@ -71,14 +90,20 @@ static int v2_check_quota_file(struct super_block *sb, int type)
71static int v2_read_file_info(struct super_block *sb, int type) 90static int v2_read_file_info(struct super_block *sb, int type)
72{ 91{
73 struct v2_disk_dqinfo dinfo; 92 struct v2_disk_dqinfo dinfo;
93 struct v2_disk_dqheader dqhead;
74 struct mem_dqinfo *info = sb_dqinfo(sb, type); 94 struct mem_dqinfo *info = sb_dqinfo(sb, type);
75 struct qtree_mem_dqinfo *qinfo; 95 struct qtree_mem_dqinfo *qinfo;
76 ssize_t size; 96 ssize_t size;
97 unsigned int version;
98
99 if (!v2_read_header(sb, type, &dqhead))
100 return 0;
101 version = le32_to_cpu(dqhead.dqh_version);
77 102
78 size = sb->s_op->quota_read(sb, type, (char *)&dinfo, 103 size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
79 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); 104 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
80 if (size != sizeof(struct v2_disk_dqinfo)) { 105 if (size != sizeof(struct v2_disk_dqinfo)) {
81 printk(KERN_WARNING "Can't read info structure on device %s.\n", 106 printk(KERN_WARNING "quota_v2: Can't read info structure on device %s.\n",
82 sb->s_id); 107 sb->s_id);
83 return -1; 108 return -1;
84 } 109 }
@@ -89,9 +114,15 @@ static int v2_read_file_info(struct super_block *sb, int type)
89 return -1; 114 return -1;
90 } 115 }
91 qinfo = info->dqi_priv; 116 qinfo = info->dqi_priv;
92 /* limits are stored as unsigned 32-bit data */ 117 if (version == 0) {
93 info->dqi_maxblimit = 0xffffffff; 118 /* limits are stored as unsigned 32-bit data */
94 info->dqi_maxilimit = 0xffffffff; 119 info->dqi_maxblimit = 0xffffffff;
120 info->dqi_maxilimit = 0xffffffff;
121 } else {
122 /* used space is stored as unsigned 64-bit value */
123 info->dqi_maxblimit = 0xffffffffffffffff; /* 2^64-1 */
124 info->dqi_maxilimit = 0xffffffffffffffff;
125 }
95 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); 126 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
96 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); 127 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
97 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); 128 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
@@ -103,8 +134,13 @@ static int v2_read_file_info(struct super_block *sb, int type)
103 qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS; 134 qinfo->dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
104 qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS; 135 qinfo->dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
105 qinfo->dqi_qtree_depth = qtree_depth(qinfo); 136 qinfo->dqi_qtree_depth = qtree_depth(qinfo);
106 qinfo->dqi_entry_size = sizeof(struct v2_disk_dqblk); 137 if (version == 0) {
107 qinfo->dqi_ops = &v2_qtree_ops; 138 qinfo->dqi_entry_size = sizeof(struct v2r0_disk_dqblk);
139 qinfo->dqi_ops = &v2r0_qtree_ops;
140 } else {
141 qinfo->dqi_entry_size = sizeof(struct v2r1_disk_dqblk);
142 qinfo->dqi_ops = &v2r1_qtree_ops;
143 }
108 return 0; 144 return 0;
109} 145}
110 146
@@ -135,9 +171,9 @@ static int v2_write_file_info(struct super_block *sb, int type)
135 return 0; 171 return 0;
136} 172}
137 173
138static void v2_disk2memdqb(struct dquot *dquot, void *dp) 174static void v2r0_disk2memdqb(struct dquot *dquot, void *dp)
139{ 175{
140 struct v2_disk_dqblk *d = dp, empty; 176 struct v2r0_disk_dqblk *d = dp, empty;
141 struct mem_dqblk *m = &dquot->dq_dqb; 177 struct mem_dqblk *m = &dquot->dq_dqb;
142 178
143 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit); 179 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
@@ -149,15 +185,15 @@ static void v2_disk2memdqb(struct dquot *dquot, void *dp)
149 m->dqb_curspace = le64_to_cpu(d->dqb_curspace); 185 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
150 m->dqb_btime = le64_to_cpu(d->dqb_btime); 186 m->dqb_btime = le64_to_cpu(d->dqb_btime);
151 /* We need to escape back all-zero structure */ 187 /* We need to escape back all-zero structure */
152 memset(&empty, 0, sizeof(struct v2_disk_dqblk)); 188 memset(&empty, 0, sizeof(struct v2r0_disk_dqblk));
153 empty.dqb_itime = cpu_to_le64(1); 189 empty.dqb_itime = cpu_to_le64(1);
154 if (!memcmp(&empty, dp, sizeof(struct v2_disk_dqblk))) 190 if (!memcmp(&empty, dp, sizeof(struct v2r0_disk_dqblk)))
155 m->dqb_itime = 0; 191 m->dqb_itime = 0;
156} 192}
157 193
158static void v2_mem2diskdqb(void *dp, struct dquot *dquot) 194static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot)
159{ 195{
160 struct v2_disk_dqblk *d = dp; 196 struct v2r0_disk_dqblk *d = dp;
161 struct mem_dqblk *m = &dquot->dq_dqb; 197 struct mem_dqblk *m = &dquot->dq_dqb;
162 struct qtree_mem_dqinfo *info = 198 struct qtree_mem_dqinfo *info =
163 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; 199 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
@@ -175,9 +211,60 @@ static void v2_mem2diskdqb(void *dp, struct dquot *dquot)
175 d->dqb_itime = cpu_to_le64(1); 211 d->dqb_itime = cpu_to_le64(1);
176} 212}
177 213
178static int v2_is_id(void *dp, struct dquot *dquot) 214static int v2r0_is_id(void *dp, struct dquot *dquot)
215{
216 struct v2r0_disk_dqblk *d = dp;
217 struct qtree_mem_dqinfo *info =
218 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
219
220 if (qtree_entry_unused(info, dp))
221 return 0;
222 return le32_to_cpu(d->dqb_id) == dquot->dq_id;
223}
224
225static void v2r1_disk2memdqb(struct dquot *dquot, void *dp)
226{
227 struct v2r1_disk_dqblk *d = dp, empty;
228 struct mem_dqblk *m = &dquot->dq_dqb;
229
230 m->dqb_ihardlimit = le64_to_cpu(d->dqb_ihardlimit);
231 m->dqb_isoftlimit = le64_to_cpu(d->dqb_isoftlimit);
232 m->dqb_curinodes = le64_to_cpu(d->dqb_curinodes);
233 m->dqb_itime = le64_to_cpu(d->dqb_itime);
234 m->dqb_bhardlimit = v2_qbtos(le64_to_cpu(d->dqb_bhardlimit));
235 m->dqb_bsoftlimit = v2_qbtos(le64_to_cpu(d->dqb_bsoftlimit));
236 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
237 m->dqb_btime = le64_to_cpu(d->dqb_btime);
238 /* We need to escape back all-zero structure */
239 memset(&empty, 0, sizeof(struct v2r1_disk_dqblk));
240 empty.dqb_itime = cpu_to_le64(1);
241 if (!memcmp(&empty, dp, sizeof(struct v2r1_disk_dqblk)))
242 m->dqb_itime = 0;
243}
244
245static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot)
246{
247 struct v2r1_disk_dqblk *d = dp;
248 struct mem_dqblk *m = &dquot->dq_dqb;
249 struct qtree_mem_dqinfo *info =
250 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
251
252 d->dqb_ihardlimit = cpu_to_le64(m->dqb_ihardlimit);
253 d->dqb_isoftlimit = cpu_to_le64(m->dqb_isoftlimit);
254 d->dqb_curinodes = cpu_to_le64(m->dqb_curinodes);
255 d->dqb_itime = cpu_to_le64(m->dqb_itime);
256 d->dqb_bhardlimit = cpu_to_le64(v2_stoqb(m->dqb_bhardlimit));
257 d->dqb_bsoftlimit = cpu_to_le64(v2_stoqb(m->dqb_bsoftlimit));
258 d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
259 d->dqb_btime = cpu_to_le64(m->dqb_btime);
260 d->dqb_id = cpu_to_le32(dquot->dq_id);
261 if (qtree_entry_unused(info, dp))
262 d->dqb_itime = cpu_to_le64(1);
263}
264
265static int v2r1_is_id(void *dp, struct dquot *dquot)
179{ 266{
180 struct v2_disk_dqblk *d = dp; 267 struct v2r1_disk_dqblk *d = dp;
181 struct qtree_mem_dqinfo *info = 268 struct qtree_mem_dqinfo *info =
182 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv; 269 sb_dqinfo(dquot->dq_sb, dquot->dq_type)->dqi_priv;
183 270
@@ -207,7 +294,7 @@ static int v2_free_file_info(struct super_block *sb, int type)
207 return 0; 294 return 0;
208} 295}
209 296
210static struct quota_format_ops v2_format_ops = { 297static const struct quota_format_ops v2_format_ops = {
211 .check_quota_file = v2_check_quota_file, 298 .check_quota_file = v2_check_quota_file,
212 .read_file_info = v2_read_file_info, 299 .read_file_info = v2_read_file_info,
213 .write_file_info = v2_write_file_info, 300 .write_file_info = v2_write_file_info,
@@ -217,20 +304,32 @@ static struct quota_format_ops v2_format_ops = {
217 .release_dqblk = v2_release_dquot, 304 .release_dqblk = v2_release_dquot,
218}; 305};
219 306
220static struct quota_format_type v2_quota_format = { 307static struct quota_format_type v2r0_quota_format = {
221 .qf_fmt_id = QFMT_VFS_V0, 308 .qf_fmt_id = QFMT_VFS_V0,
222 .qf_ops = &v2_format_ops, 309 .qf_ops = &v2_format_ops,
223 .qf_owner = THIS_MODULE 310 .qf_owner = THIS_MODULE
224}; 311};
225 312
313static struct quota_format_type v2r1_quota_format = {
314 .qf_fmt_id = QFMT_VFS_V1,
315 .qf_ops = &v2_format_ops,
316 .qf_owner = THIS_MODULE
317};
318
226static int __init init_v2_quota_format(void) 319static int __init init_v2_quota_format(void)
227{ 320{
228 return register_quota_format(&v2_quota_format); 321 int ret;
322
323 ret = register_quota_format(&v2r0_quota_format);
324 if (ret)
325 return ret;
326 return register_quota_format(&v2r1_quota_format);
229} 327}
230 328
231static void __exit exit_v2_quota_format(void) 329static void __exit exit_v2_quota_format(void)
232{ 330{
233 unregister_quota_format(&v2_quota_format); 331 unregister_quota_format(&v2r0_quota_format);
332 unregister_quota_format(&v2r1_quota_format);
234} 333}
235 334
236module_init(init_v2_quota_format); 335module_init(init_v2_quota_format);