OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [fs/] [quota_v2.c] - Blame information for rev 3

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.