aboutsummaryrefslogtreecommitdiffstats
path: root/fs/quota_v2.c
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2008-09-21 23:54:49 -0400
committerMark Fasheh <mfasheh@suse.com>2009-01-05 11:40:21 -0500
commit1ccd14b9c271c1ac6eec5c5ec5def433100e7248 (patch)
tree959756aa5b68c568a18697464df3f0acdd0387cf /fs/quota_v2.c
parentcf770c137122b78470a67ebd5498947869a09197 (diff)
quota: Split off quota tree handling into a separate file
There is going to be a new version of quota format having 64-bit quota limits and a new quota format for OCFS2. They are both going to use the same tree structure as VFSv0 quota format. So split out tree handling into a separate file and make size of leaf blocks, amount of space usable in each block (needed for checksumming) and structures contained in them configurable so that the code can be shared. Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: Mark Fasheh <mfasheh@suse.com>
Diffstat (limited to 'fs/quota_v2.c')
-rw-r--r--fs/quota_v2.c596
1 files changed, 52 insertions, 544 deletions
diff --git a/fs/quota_v2.c b/fs/quota_v2.c
index a21d1a7c356a..a87f1028a425 100644
--- a/fs/quota_v2.c
+++ b/fs/quota_v2.c
@@ -14,6 +14,7 @@
14 14
15#include <asm/byteorder.h> 15#include <asm/byteorder.h>
16 16
17#include "quota_tree.h"
17#include "quotaio_v2.h" 18#include "quotaio_v2.h"
18 19
19MODULE_AUTHOR("Jan Kara"); 20MODULE_AUTHOR("Jan Kara");
@@ -22,10 +23,15 @@ MODULE_LICENSE("GPL");
22 23
23#define __QUOTA_V2_PARANOIA 24#define __QUOTA_V2_PARANOIA
24 25
25typedef char *dqbuf_t; 26static void v2_mem2diskdqb(void *dp, struct dquot *dquot);
27static void v2_disk2memdqb(struct dquot *dquot, void *dp);
28static int v2_is_id(void *dp, struct dquot *dquot);
26 29
27#define GETIDINDEX(id, depth) (((id) >> ((V2_DQTREEDEPTH-(depth)-1)*8)) & 0xff) 30static struct qtree_fmt_operations v2_qtree_ops = {
28#define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader))) 31 .mem2disk_dqblk = v2_mem2diskdqb,
32 .disk2mem_dqblk = v2_disk2memdqb,
33 .is_id = v2_is_id,
34};
29 35
30#define QUOTABLOCK_BITS 10 36#define QUOTABLOCK_BITS 10
31#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS) 37#define QUOTABLOCK_SIZE (1 << QUOTABLOCK_BITS)
@@ -64,7 +70,7 @@ static int v2_check_quota_file(struct super_block *sb, int type)
64static int v2_read_file_info(struct super_block *sb, int type) 70static int v2_read_file_info(struct super_block *sb, int type)
65{ 71{
66 struct v2_disk_dqinfo dinfo; 72 struct v2_disk_dqinfo dinfo;
67 struct mem_dqinfo *info = sb_dqopt(sb)->info+type; 73 struct mem_dqinfo *info = sb_dqinfo(sb, type);
68 ssize_t size; 74 ssize_t size;
69 75
70 size = sb->s_op->quota_read(sb, type, (char *)&dinfo, 76 size = sb->s_op->quota_read(sb, type, (char *)&dinfo,
@@ -80,9 +86,16 @@ static int v2_read_file_info(struct super_block *sb, int type)
80 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace); 86 info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
81 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace); 87 info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
82 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags); 88 info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
83 info->u.v2_i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks); 89 info->u.v2_i.i.dqi_sb = sb;
84 info->u.v2_i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk); 90 info->u.v2_i.i.dqi_type = type;
85 info->u.v2_i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry); 91 info->u.v2_i.i.dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
92 info->u.v2_i.i.dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
93 info->u.v2_i.i.dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
94 info->u.v2_i.i.dqi_blocksize_bits = V2_DQBLKSIZE_BITS;
95 info->u.v2_i.i.dqi_usable_bs = 1 << V2_DQBLKSIZE_BITS;
96 info->u.v2_i.i.dqi_qtree_depth = qtree_depth(&info->u.v2_i.i);
97 info->u.v2_i.i.dqi_entry_size = sizeof(struct v2_disk_dqblk);
98 info->u.v2_i.i.dqi_ops = &v2_qtree_ops;
86 return 0; 99 return 0;
87} 100}
88 101
@@ -90,7 +103,7 @@ static int v2_read_file_info(struct super_block *sb, int type)
90static int v2_write_file_info(struct super_block *sb, int type) 103static int v2_write_file_info(struct super_block *sb, int type)
91{ 104{
92 struct v2_disk_dqinfo dinfo; 105 struct v2_disk_dqinfo dinfo;
93 struct mem_dqinfo *info = sb_dqopt(sb)->info+type; 106 struct mem_dqinfo *info = sb_dqinfo(sb, type);
94 ssize_t size; 107 ssize_t size;
95 108
96 spin_lock(&dq_data_lock); 109 spin_lock(&dq_data_lock);
@@ -99,9 +112,9 @@ static int v2_write_file_info(struct super_block *sb, int type)
99 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace); 112 dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
100 dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK); 113 dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
101 spin_unlock(&dq_data_lock); 114 spin_unlock(&dq_data_lock);
102 dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.dqi_blocks); 115 dinfo.dqi_blocks = cpu_to_le32(info->u.v2_i.i.dqi_blocks);
103 dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.dqi_free_blk); 116 dinfo.dqi_free_blk = cpu_to_le32(info->u.v2_i.i.dqi_free_blk);
104 dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.dqi_free_entry); 117 dinfo.dqi_free_entry = cpu_to_le32(info->u.v2_i.i.dqi_free_entry);
105 size = sb->s_op->quota_write(sb, type, (char *)&dinfo, 118 size = sb->s_op->quota_write(sb, type, (char *)&dinfo,
106 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF); 119 sizeof(struct v2_disk_dqinfo), V2_DQINFOOFF);
107 if (size != sizeof(struct v2_disk_dqinfo)) { 120 if (size != sizeof(struct v2_disk_dqinfo)) {
@@ -112,8 +125,11 @@ static int v2_write_file_info(struct super_block *sb, int type)
112 return 0; 125 return 0;
113} 126}
114 127
115static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d) 128static void v2_disk2memdqb(struct dquot *dquot, void *dp)
116{ 129{
130 struct v2_disk_dqblk *d = dp, empty;
131 struct mem_dqblk *m = &dquot->dq_dqb;
132
117 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit); 133 m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
118 m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit); 134 m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
119 m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes); 135 m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
@@ -122,10 +138,20 @@ static void disk2memdqb(struct mem_dqblk *m, struct v2_disk_dqblk *d)
122 m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit)); 138 m->dqb_bsoftlimit = v2_qbtos(le32_to_cpu(d->dqb_bsoftlimit));
123 m->dqb_curspace = le64_to_cpu(d->dqb_curspace); 139 m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
124 m->dqb_btime = le64_to_cpu(d->dqb_btime); 140 m->dqb_btime = le64_to_cpu(d->dqb_btime);
141 /* We need to escape back all-zero structure */
142 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
143 empty.dqb_itime = cpu_to_le64(1);
144 if (!memcmp(&empty, dp, sizeof(struct v2_disk_dqblk)))
145 m->dqb_itime = 0;
125} 146}
126 147
127static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id) 148static void v2_mem2diskdqb(void *dp, struct dquot *dquot)
128{ 149{
150 struct v2_disk_dqblk *d = dp;
151 struct mem_dqblk *m = &dquot->dq_dqb;
152 struct qtree_mem_dqinfo *info =
153 &sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i;
154
129 d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit); 155 d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
130 d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit); 156 d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
131 d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes); 157 d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
@@ -134,553 +160,35 @@ static void mem2diskdqb(struct v2_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
134 d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit)); 160 d->dqb_bsoftlimit = cpu_to_le32(v2_stoqb(m->dqb_bsoftlimit));
135 d->dqb_curspace = cpu_to_le64(m->dqb_curspace); 161 d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
136 d->dqb_btime = cpu_to_le64(m->dqb_btime); 162 d->dqb_btime = cpu_to_le64(m->dqb_btime);
137 d->dqb_id = cpu_to_le32(id); 163 d->dqb_id = cpu_to_le32(dquot->dq_id);
138} 164 if (qtree_entry_unused(info, dp))
139 165 d->dqb_itime = cpu_to_le64(1);
140static dqbuf_t getdqbuf(void)
141{
142 dqbuf_t buf = kmalloc(V2_DQBLKSIZE, GFP_NOFS);
143 if (!buf)
144 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
145 return buf;
146}
147
148static inline void freedqbuf(dqbuf_t buf)
149{
150 kfree(buf);
151}
152
153static inline ssize_t read_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
154{
155 memset(buf, 0, V2_DQBLKSIZE);
156 return sb->s_op->quota_read(sb, type, (char *)buf,
157 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
158}
159
160static inline ssize_t write_blk(struct super_block *sb, int type, uint blk, dqbuf_t buf)
161{
162 return sb->s_op->quota_write(sb, type, (char *)buf,
163 V2_DQBLKSIZE, blk << V2_DQBLKSIZE_BITS);
164}
165
166/* Remove empty block from list and return it */
167static int get_free_dqblk(struct super_block *sb, int type)
168{
169 dqbuf_t buf = getdqbuf();
170 struct mem_dqinfo *info = sb_dqinfo(sb, type);
171 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
172 int ret, blk;
173
174 if (!buf)
175 return -ENOMEM;
176 if (info->u.v2_i.dqi_free_blk) {
177 blk = info->u.v2_i.dqi_free_blk;
178 if ((ret = read_blk(sb, type, blk, buf)) < 0)
179 goto out_buf;
180 info->u.v2_i.dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
181 }
182 else {
183 memset(buf, 0, V2_DQBLKSIZE);
184 /* Assure block allocation... */
185 if ((ret = write_blk(sb, type, info->u.v2_i.dqi_blocks, buf)) < 0)
186 goto out_buf;
187 blk = info->u.v2_i.dqi_blocks++;
188 }
189 mark_info_dirty(sb, type);
190 ret = blk;
191out_buf:
192 freedqbuf(buf);
193 return ret;
194}
195
196/* Insert empty block to the list */
197static int put_free_dqblk(struct super_block *sb, int type, dqbuf_t buf, uint blk)
198{
199 struct mem_dqinfo *info = sb_dqinfo(sb, type);
200 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
201 int err;
202
203 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_blk);
204 dh->dqdh_prev_free = cpu_to_le32(0);
205 dh->dqdh_entries = cpu_to_le16(0);
206 info->u.v2_i.dqi_free_blk = blk;
207 mark_info_dirty(sb, type);
208 /* Some strange block. We had better leave it... */
209 if ((err = write_blk(sb, type, blk, buf)) < 0)
210 return err;
211 return 0;
212} 166}
213 167
214/* Remove given block from the list of blocks with free entries */ 168static int v2_is_id(void *dp, struct dquot *dquot)
215static int remove_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
216{ 169{
217 dqbuf_t tmpbuf = getdqbuf(); 170 struct v2_disk_dqblk *d = dp;
218 struct mem_dqinfo *info = sb_dqinfo(sb, type); 171 struct qtree_mem_dqinfo *info =
219 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf; 172 &sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i;
220 uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
221 int err;
222 173
223 if (!tmpbuf) 174 if (qtree_entry_unused(info, dp))
224 return -ENOMEM;
225 if (nextblk) {
226 if ((err = read_blk(sb, type, nextblk, tmpbuf)) < 0)
227 goto out_buf;
228 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
229 if ((err = write_blk(sb, type, nextblk, tmpbuf)) < 0)
230 goto out_buf;
231 }
232 if (prevblk) {
233 if ((err = read_blk(sb, type, prevblk, tmpbuf)) < 0)
234 goto out_buf;
235 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
236 if ((err = write_blk(sb, type, prevblk, tmpbuf)) < 0)
237 goto out_buf;
238 }
239 else {
240 info->u.v2_i.dqi_free_entry = nextblk;
241 mark_info_dirty(sb, type);
242 }
243 freedqbuf(tmpbuf);
244 dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
245 /* No matter whether write succeeds block is out of list */
246 if (write_blk(sb, type, blk, buf) < 0)
247 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
248 return 0;
249out_buf:
250 freedqbuf(tmpbuf);
251 return err;
252}
253
254/* Insert given block to the beginning of list with free entries */
255static int insert_free_dqentry(struct super_block *sb, int type, dqbuf_t buf, uint blk)
256{
257 dqbuf_t tmpbuf = getdqbuf();
258 struct mem_dqinfo *info = sb_dqinfo(sb, type);
259 struct v2_disk_dqdbheader *dh = (struct v2_disk_dqdbheader *)buf;
260 int err;
261
262 if (!tmpbuf)
263 return -ENOMEM;
264 dh->dqdh_next_free = cpu_to_le32(info->u.v2_i.dqi_free_entry);
265 dh->dqdh_prev_free = cpu_to_le32(0);
266 if ((err = write_blk(sb, type, blk, buf)) < 0)
267 goto out_buf;
268 if (info->u.v2_i.dqi_free_entry) {
269 if ((err = read_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
270 goto out_buf;
271 ((struct v2_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
272 if ((err = write_blk(sb, type, info->u.v2_i.dqi_free_entry, tmpbuf)) < 0)
273 goto out_buf;
274 }
275 freedqbuf(tmpbuf);
276 info->u.v2_i.dqi_free_entry = blk;
277 mark_info_dirty(sb, type);
278 return 0;
279out_buf:
280 freedqbuf(tmpbuf);
281 return err;
282}
283
284/* Find space for dquot */
285static uint find_free_dqentry(struct dquot *dquot, int *err)
286{
287 struct super_block *sb = dquot->dq_sb;
288 struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type;
289 uint blk, i;
290 struct v2_disk_dqdbheader *dh;
291 struct v2_disk_dqblk *ddquot;
292 struct v2_disk_dqblk fakedquot;
293 dqbuf_t buf;
294
295 *err = 0;
296 if (!(buf = getdqbuf())) {
297 *err = -ENOMEM;
298 return 0; 175 return 0;
299 } 176 return le32_to_cpu(d->dqb_id) == dquot->dq_id;
300 dh = (struct v2_disk_dqdbheader *)buf;
301 ddquot = GETENTRIES(buf);
302 if (info->u.v2_i.dqi_free_entry) {
303 blk = info->u.v2_i.dqi_free_entry;
304 if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0)
305 goto out_buf;
306 }
307 else {
308 blk = get_free_dqblk(sb, dquot->dq_type);
309 if ((int)blk < 0) {
310 *err = blk;
311 freedqbuf(buf);
312 return 0;
313 }
314 memset(buf, 0, V2_DQBLKSIZE);
315 /* This is enough as block is already zeroed and entry list is empty... */
316 info->u.v2_i.dqi_free_entry = blk;
317 mark_info_dirty(sb, dquot->dq_type);
318 }
319 if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */
320 if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) {
321 printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
322 goto out_buf;
323 }
324 le16_add_cpu(&dh->dqdh_entries, 1);
325 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
326 /* Find free structure in block */
327 for (i = 0; i < V2_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)); i++);
328#ifdef __QUOTA_V2_PARANOIA
329 if (i == V2_DQSTRINBLK) {
330 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
331 *err = -EIO;
332 goto out_buf;
333 }
334#endif
335 if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) {
336 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
337 goto out_buf;
338 }
339 dquot->dq_off = (blk<<V2_DQBLKSIZE_BITS)+sizeof(struct v2_disk_dqdbheader)+i*sizeof(struct v2_disk_dqblk);
340 freedqbuf(buf);
341 return blk;
342out_buf:
343 freedqbuf(buf);
344 return 0;
345} 177}
346 178
347/* Insert reference to structure into the trie */ 179static int v2_read_dquot(struct dquot *dquot)
348static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth)
349{
350 struct super_block *sb = dquot->dq_sb;
351 dqbuf_t buf;
352 int ret = 0, newson = 0, newact = 0;
353 __le32 *ref;
354 uint newblk;
355
356 if (!(buf = getdqbuf()))
357 return -ENOMEM;
358 if (!*treeblk) {
359 ret = get_free_dqblk(sb, dquot->dq_type);
360 if (ret < 0)
361 goto out_buf;
362 *treeblk = ret;
363 memset(buf, 0, V2_DQBLKSIZE);
364 newact = 1;
365 }
366 else {
367 if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) {
368 printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
369 goto out_buf;
370 }
371 }
372 ref = (__le32 *)buf;
373 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
374 if (!newblk)
375 newson = 1;
376 if (depth == V2_DQTREEDEPTH-1) {
377#ifdef __QUOTA_V2_PARANOIA
378 if (newblk) {
379 printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]));
380 ret = -EIO;
381 goto out_buf;
382 }
383#endif
384 newblk = find_free_dqentry(dquot, &ret);
385 }
386 else
387 ret = do_insert_tree(dquot, &newblk, depth+1);
388 if (newson && ret >= 0) {
389 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
390 ret = write_blk(sb, dquot->dq_type, *treeblk, buf);
391 }
392 else if (newact && ret < 0)
393 put_free_dqblk(sb, dquot->dq_type, buf, *treeblk);
394out_buf:
395 freedqbuf(buf);
396 return ret;
397}
398
399/* Wrapper for inserting quota structure into tree */
400static inline int dq_insert_tree(struct dquot *dquot)
401{ 180{
402 int tmp = V2_DQTREEOFF; 181 return qtree_read_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot);
403 return do_insert_tree(dquot, &tmp, 0);
404} 182}
405 183
406/*
407 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
408 */
409static int v2_write_dquot(struct dquot *dquot) 184static int v2_write_dquot(struct dquot *dquot)
410{ 185{
411 int type = dquot->dq_type; 186 return qtree_write_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot);
412 ssize_t ret;
413 struct v2_disk_dqblk ddquot, empty;
414
415 /* dq_off is guarded by dqio_mutex */
416 if (!dquot->dq_off)
417 if ((ret = dq_insert_tree(dquot)) < 0) {
418 printk(KERN_ERR "VFS: Error %zd occurred while creating quota.\n", ret);
419 return ret;
420 }
421 spin_lock(&dq_data_lock);
422 mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
423 /* Argh... We may need to write structure full of zeroes but that would be
424 * treated as an empty place by the rest of the code. Format change would
425 * be definitely cleaner but the problems probably are not worth it */
426 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
427 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
428 ddquot.dqb_itime = cpu_to_le64(1);
429 spin_unlock(&dq_data_lock);
430 ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,
431 (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);
432 if (ret != sizeof(struct v2_disk_dqblk)) {
433 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id);
434 if (ret >= 0)
435 ret = -ENOSPC;
436 }
437 else
438 ret = 0;
439 dqstats.writes++;
440
441 return ret;
442} 187}
443 188
444/* Free dquot entry in data block */
445static int free_dqentry(struct dquot *dquot, uint blk)
446{
447 struct super_block *sb = dquot->dq_sb;
448 int type = dquot->dq_type;
449 struct v2_disk_dqdbheader *dh;
450 dqbuf_t buf = getdqbuf();
451 int ret = 0;
452
453 if (!buf)
454 return -ENOMEM;
455 if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {
456 printk(KERN_ERR "VFS: Quota structure has offset to other "
457 "block (%u) than it should (%u).\n", blk,
458 (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));
459 goto out_buf;
460 }
461 if ((ret = read_blk(sb, type, blk, buf)) < 0) {
462 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
463 goto out_buf;
464 }
465 dh = (struct v2_disk_dqdbheader *)buf;
466 le16_add_cpu(&dh->dqdh_entries, -1);
467 if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */
468 if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||
469 (ret = put_free_dqblk(sb, type, buf, blk)) < 0) {
470 printk(KERN_ERR "VFS: Can't move quota data block (%u) "
471 "to free list.\n", blk);
472 goto out_buf;
473 }
474 }
475 else {
476 memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0,
477 sizeof(struct v2_disk_dqblk));
478 if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) {
479 /* Insert will write block itself */
480 if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) {
481 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
482 goto out_buf;
483 }
484 }
485 else
486 if ((ret = write_blk(sb, type, blk, buf)) < 0) {
487 printk(KERN_ERR "VFS: Can't write quota data "
488 "block %u\n", blk);
489 goto out_buf;
490 }
491 }
492 dquot->dq_off = 0; /* Quota is now unattached */
493out_buf:
494 freedqbuf(buf);
495 return ret;
496}
497
498/* Remove reference to dquot from tree */
499static int remove_tree(struct dquot *dquot, uint *blk, int depth)
500{
501 struct super_block *sb = dquot->dq_sb;
502 int type = dquot->dq_type;
503 dqbuf_t buf = getdqbuf();
504 int ret = 0;
505 uint newblk;
506 __le32 *ref = (__le32 *)buf;
507
508 if (!buf)
509 return -ENOMEM;
510 if ((ret = read_blk(sb, type, *blk, buf)) < 0) {
511 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
512 goto out_buf;
513 }
514 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
515 if (depth == V2_DQTREEDEPTH-1) {
516 ret = free_dqentry(dquot, newblk);
517 newblk = 0;
518 }
519 else
520 ret = remove_tree(dquot, &newblk, depth+1);
521 if (ret >= 0 && !newblk) {
522 int i;
523 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
524 for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */
525 /* Don't put the root block into the free block list */
526 if (i == V2_DQBLKSIZE && *blk != V2_DQTREEOFF) {
527 put_free_dqblk(sb, type, buf, *blk);
528 *blk = 0;
529 }
530 else
531 if ((ret = write_blk(sb, type, *blk, buf)) < 0)
532 printk(KERN_ERR "VFS: Can't write quota tree "
533 "block %u.\n", *blk);
534 }
535out_buf:
536 freedqbuf(buf);
537 return ret;
538}
539
540/* Delete dquot from tree */
541static int v2_delete_dquot(struct dquot *dquot)
542{
543 uint tmp = V2_DQTREEOFF;
544
545 if (!dquot->dq_off) /* Even not allocated? */
546 return 0;
547 return remove_tree(dquot, &tmp, 0);
548}
549
550/* Find entry in block */
551static loff_t find_block_dqentry(struct dquot *dquot, uint blk)
552{
553 dqbuf_t buf = getdqbuf();
554 loff_t ret = 0;
555 int i;
556 struct v2_disk_dqblk *ddquot = GETENTRIES(buf);
557
558 if (!buf)
559 return -ENOMEM;
560 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
561 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
562 goto out_buf;
563 }
564 if (dquot->dq_id)
565 for (i = 0; i < V2_DQSTRINBLK &&
566 le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
567 else { /* ID 0 as a bit more complicated searching... */
568 struct v2_disk_dqblk fakedquot;
569
570 memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk));
571 for (i = 0; i < V2_DQSTRINBLK; i++)
572 if (!le32_to_cpu(ddquot[i].dqb_id) &&
573 memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))
574 break;
575 }
576 if (i == V2_DQSTRINBLK) {
577 printk(KERN_ERR "VFS: Quota for id %u referenced "
578 "but not present.\n", dquot->dq_id);
579 ret = -EIO;
580 goto out_buf;
581 }
582 else
583 ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct
584 v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);
585out_buf:
586 freedqbuf(buf);
587 return ret;
588}
589
590/* Find entry for given id in the tree */
591static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth)
592{
593 dqbuf_t buf = getdqbuf();
594 loff_t ret = 0;
595 __le32 *ref = (__le32 *)buf;
596
597 if (!buf)
598 return -ENOMEM;
599 if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) {
600 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
601 goto out_buf;
602 }
603 ret = 0;
604 blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
605 if (!blk) /* No reference? */
606 goto out_buf;
607 if (depth < V2_DQTREEDEPTH-1)
608 ret = find_tree_dqentry(dquot, blk, depth+1);
609 else
610 ret = find_block_dqentry(dquot, blk);
611out_buf:
612 freedqbuf(buf);
613 return ret;
614}
615
616/* Find entry for given id in the tree - wrapper function */
617static inline loff_t find_dqentry(struct dquot *dquot)
618{
619 return find_tree_dqentry(dquot, V2_DQTREEOFF, 0);
620}
621
622static int v2_read_dquot(struct dquot *dquot)
623{
624 int type = dquot->dq_type;
625 loff_t offset;
626 struct v2_disk_dqblk ddquot, empty;
627 int ret = 0;
628
629#ifdef __QUOTA_V2_PARANOIA
630 /* Invalidated quota? */
631 if (!dquot->dq_sb || !sb_dqopt(dquot->dq_sb)->files[type]) {
632 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
633 return -EIO;
634 }
635#endif
636 offset = find_dqentry(dquot);
637 if (offset <= 0) { /* Entry not present? */
638 if (offset < 0)
639 printk(KERN_ERR "VFS: Can't read quota "
640 "structure for id %u.\n", dquot->dq_id);
641 dquot->dq_off = 0;
642 set_bit(DQ_FAKE_B, &dquot->dq_flags);
643 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
644 ret = offset;
645 }
646 else {
647 dquot->dq_off = offset;
648 if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,
649 (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))
650 != sizeof(struct v2_disk_dqblk)) {
651 if (ret >= 0)
652 ret = -EIO;
653 printk(KERN_ERR "VFS: Error while reading quota "
654 "structure for id %u.\n", dquot->dq_id);
655 memset(&ddquot, 0, sizeof(struct v2_disk_dqblk));
656 }
657 else {
658 ret = 0;
659 /* We need to escape back all-zero structure */
660 memset(&empty, 0, sizeof(struct v2_disk_dqblk));
661 empty.dqb_itime = cpu_to_le64(1);
662 if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk)))
663 ddquot.dqb_itime = 0;
664 }
665 disk2memdqb(&dquot->dq_dqb, &ddquot);
666 if (!dquot->dq_dqb.dqb_bhardlimit &&
667 !dquot->dq_dqb.dqb_bsoftlimit &&
668 !dquot->dq_dqb.dqb_ihardlimit &&
669 !dquot->dq_dqb.dqb_isoftlimit)
670 set_bit(DQ_FAKE_B, &dquot->dq_flags);
671 }
672 dqstats.reads++;
673
674 return ret;
675}
676
677/* Check whether dquot should not be deleted. We know we are
678 * the only one operating on dquot (thanks to dq_lock) */
679static int v2_release_dquot(struct dquot *dquot) 189static int v2_release_dquot(struct dquot *dquot)
680{ 190{
681 if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) 191 return qtree_release_dquot(&sb_dqinfo(dquot->dq_sb, dquot->dq_type)->u.v2_i.i, dquot);
682 return v2_delete_dquot(dquot);
683 return 0;
684} 192}
685 193
686static struct quota_format_ops v2_format_ops = { 194static struct quota_format_ops v2_format_ops = {