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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [quota_v2.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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