diff options
Diffstat (limited to 'fs/quota/quota_v2.c')
-rw-r--r-- | fs/quota/quota_v2.c | 167 |
1 files changed, 133 insertions, 34 deletions
diff --git a/fs/quota/quota_v2.c b/fs/quota/quota_v2.c index a5475fb1ae44..3dfc23e02135 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 | ||
26 | static void v2_mem2diskdqb(void *dp, struct dquot *dquot); | 26 | static void v2r0_mem2diskdqb(void *dp, struct dquot *dquot); |
27 | static void v2_disk2memdqb(struct dquot *dquot, void *dp); | 27 | static void v2r0_disk2memdqb(struct dquot *dquot, void *dp); |
28 | static int v2_is_id(void *dp, struct dquot *dquot); | 28 | static int v2r0_is_id(void *dp, struct dquot *dquot); |
29 | 29 | static void v2r1_mem2diskdqb(void *dp, struct dquot *dquot); | |
30 | static struct qtree_fmt_operations v2_qtree_ops = { | 30 | static void v2r1_disk2memdqb(struct dquot *dquot, void *dp); |
31 | .mem2disk_dqblk = v2_mem2diskdqb, | 31 | static int v2r1_is_id(void *dp, struct dquot *dquot); |
32 | .disk2mem_dqblk = v2_disk2memdqb, | 32 | |
33 | .is_id = v2_is_id, | 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, | ||
37 | }; | ||
38 | |||
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, | ||
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 | ||
58 | static 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 */ |
50 | static int v2_check_quota_file(struct super_block *sb, int type) | 75 | static 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) | |||
71 | static int v2_read_file_info(struct super_block *sb, int type) | 90 | static 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 | ||
138 | static void v2_disk2memdqb(struct dquot *dquot, void *dp) | 174 | static 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 | ||
158 | static void v2_mem2diskdqb(void *dp, struct dquot *dquot) | 194 | static 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 | ||
178 | static int v2_is_id(void *dp, struct dquot *dquot) | 214 | static 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 | |||
225 | static 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 | |||
245 | static 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 | |||
265 | static 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 | ||
210 | static struct quota_format_ops v2_format_ops = { | 297 | static 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 | ||
220 | static struct quota_format_type v2_quota_format = { | 307 | static 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 | ||
313 | static 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 | |||
226 | static int __init init_v2_quota_format(void) | 319 | static 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 | ||
231 | static void __exit exit_v2_quota_format(void) | 329 | static 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 | ||
236 | module_init(init_v2_quota_format); | 335 | module_init(init_v2_quota_format); |