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

Subversion Repositories or1k

[/] [or1k/] [tags/] [before_ORP/] [uclinux/] [uClinux-2.0.x/] [fs/] [dquot.c] - Blame information for rev 199

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 * Implementation of the diskquota system for the LINUX operating
3
 * system. QUOTA is implemented using the BSD systemcall interface as
4
 * the means of communication with the user level. Currently only the
5
 * ext2-filesystem has support for diskquotas. Other filesystems may
6
 * be added in future time. This file contains the generic routines
7
 * called by the different filesystems on allocation of an inode or
8
 * block. These routines take care of the administration needed to
9
 * have a consistent diskquota tracking system. The ideas of both
10
 * user and group quotas are based on the Melbourne quota system as
11
 * used on BSD derived systems. The internal implementation is
12
 * based on the LINUX inode-subsystem with added complexity of the
13
 * diskquota system. This implementation is not based on any BSD
14
 * kernel sourcecode.
15
 *
16
 * Version: $Id: dquot.c,v 1.1.1.1 2001-09-10 07:44:38 simons Exp $
17
 *
18
 * Author:  Marco van Wieringen <mvw@mcs.ow.nl> <mvw@tnix.net>
19
 *
20
 * Fixes:   Dmitry Gorodchanin <pgmdsg@ibi.com>, 11 Feb 96
21
 *          removed race conditions in dqput(), dqget() and iput().
22
 *          Nick Kralevich <nickkral@cal.alumni.berkeley.edu>, 21 Jul 97
23
 *          Fixed a condition where user and group quotas could get mixed up.
24
 *
25
 * (C) Copyright 1994, 1995 Marco van Wieringen
26
 *
27
 */
28
 
29
#include <linux/errno.h>
30
#include <linux/kernel.h>
31
#include <linux/sched.h>
32
#include <linux/types.h>
33
#include <linux/string.h>
34
#include <linux/fcntl.h>
35
#include <linux/stat.h>
36
#include <linux/tty.h>
37
#include <linux/malloc.h>
38
#include <linux/mount.h>
39
 
40
#include <asm/segment.h>
41
 
42
#define __DQUOT_VERSION__       "dquot_5.6.0"
43
 
44
static char quotamessage[MAX_QUOTA_MESSAGE];
45
static char *quotatypes[] = INITQFNAMES;
46
 
47
static int nr_dquots = 0, nr_free_dquots = 0;
48
static struct dquot *hash_table[NR_DQHASH];
49
static struct dquot *first_dquot;
50
static struct dqstats dqstats;
51
 
52
static struct wait_queue *dquot_wait = (struct wait_queue *)NULL;
53
 
54
extern void add_dquot_ref(kdev_t dev, short type);
55
extern void reset_dquot_ptrs(kdev_t dev, short type);
56
 
57
#ifndef min
58
#define min(a,b) ((a) < (b)) ? (a) : (b)
59
#endif
60
 
61
/*
62
 * Functions for management of the hashlist.
63
 */
64
static inline int const hashfn(kdev_t dev, unsigned int id, short type)
65
{
66
        return((HASHDEV(dev) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH;
67
}
68
 
69
static inline struct dquot **const hash(kdev_t dev, unsigned int id, short type)
70
{
71
        return(hash_table + hashfn(dev, id, type));
72
}
73
 
74
static inline int has_quota_enabled(kdev_t dev, short type)
75
{
76
        struct vfsmount *vfsmnt;
77
 
78
        return((vfsmnt = lookup_vfsmnt(dev)) != (struct vfsmount *)NULL &&
79
               (vfsmnt->mnt_quotas[type] != (struct file *)NULL));
80
}
81
 
82
static void insert_dquot_free(struct dquot *dquot)
83
{
84
        dquot->dq_next = first_dquot;
85
        dquot->dq_prev = first_dquot->dq_prev;
86
        dquot->dq_next->dq_prev = dquot;
87
        dquot->dq_prev->dq_next = dquot;
88
        first_dquot = dquot;
89
}
90
 
91
static void remove_dquot_free(struct dquot *dquot)
92
{
93
        if (first_dquot == dquot)
94
                first_dquot = first_dquot->dq_next;
95
        if (dquot->dq_next)
96
                dquot->dq_next->dq_prev = dquot->dq_prev;
97
        if (dquot->dq_prev)
98
                dquot->dq_prev->dq_next = dquot->dq_next;
99
        dquot->dq_next = dquot->dq_prev = NODQUOT;
100
}
101
 
102
static void insert_dquot_hash(struct dquot *dquot)
103
{
104
        struct dquot **hash_ent;
105
 
106
        hash_ent = hash(dquot->dq_dev, dquot->dq_id, dquot->dq_type);
107
        dquot->dq_hash_next = *hash_ent;
108
        dquot->dq_hash_prev = NODQUOT;
109
        if (dquot->dq_hash_next)
110
                dquot->dq_hash_next->dq_hash_prev = dquot;
111
        *hash_ent = dquot;
112
}
113
 
114
static void remove_dquot_hash(struct dquot *dquot)
115
{
116
        struct dquot **hash_ent;
117
 
118
        hash_ent = hash(dquot->dq_dev, dquot->dq_id, dquot->dq_type);
119
        if (*hash_ent == dquot)
120
                *hash_ent = dquot->dq_hash_next;
121
        if (dquot->dq_hash_next)
122
                dquot->dq_hash_next->dq_hash_prev = dquot->dq_hash_prev;
123
        if (dquot->dq_hash_prev)
124
                dquot->dq_hash_prev->dq_hash_next = dquot->dq_hash_next;
125
        dquot->dq_hash_prev = dquot->dq_hash_next = NODQUOT;
126
}
127
 
128
static void put_last_free(struct dquot *dquot)
129
{
130
        remove_dquot_free(dquot);
131
        dquot->dq_prev = first_dquot->dq_prev;
132
        dquot->dq_prev->dq_next = dquot;
133
        dquot->dq_next = first_dquot;
134
        dquot->dq_next->dq_prev = dquot;
135
}
136
 
137
static void grow_dquots(void)
138
{
139
        struct dquot *dquot;
140
        int cnt;
141
 
142
        if (!(dquot = (struct dquot*) get_free_page(GFP_KERNEL)))
143
                return;
144
        dqstats.pages_allocated++;
145
        cnt = PAGE_SIZE / sizeof(struct dquot);
146
        nr_dquots += cnt;
147
        nr_free_dquots += cnt;
148
        if (!first_dquot) {
149
                dquot->dq_next = dquot->dq_prev = first_dquot = dquot++;
150
                cnt--;
151
        }
152
        for (; cnt; cnt--)
153
                insert_dquot_free(dquot++);
154
}
155
 
156
/*
157
 * Functions for locking and waiting on dquots.
158
 */
159
static void __wait_on_dquot(struct dquot *dquot)
160
{
161
        struct wait_queue wait = {current, NULL};
162
 
163
        add_wait_queue(&dquot->dq_wait, &wait);
164
repeat:
165
        current->state = TASK_UNINTERRUPTIBLE;
166
        if (dquot->dq_flags & DQ_LOCKED) {
167
                dquot->dq_flags |= DQ_WANT;
168
                schedule();
169
                goto repeat;
170
        }
171
        remove_wait_queue(&dquot->dq_wait, &wait);
172
        current->state = TASK_RUNNING;
173
}
174
 
175
static inline void wait_on_dquot(struct dquot *dquot)
176
{
177
        if (dquot->dq_flags & DQ_LOCKED)
178
                __wait_on_dquot(dquot);
179
}
180
 
181
static inline void lock_dquot(struct dquot *dquot)
182
{
183
        wait_on_dquot(dquot);
184
        dquot->dq_flags |= DQ_LOCKED;
185
}
186
 
187
static inline void unlock_dquot(struct dquot *dquot)
188
{
189
        dquot->dq_flags &= ~DQ_LOCKED;
190
        if (dquot->dq_flags & DQ_WANT) {
191
                dquot->dq_flags &= ~DQ_WANT;
192
                wake_up(&dquot->dq_wait);
193
        }
194
}
195
/*
196
 * Note that we don't want to disturb any wait-queues when we discard
197
 * an dquot.
198
 *
199
 * FIXME: As soon as we have a nice solution for the inode problem we
200
 *                can also fix this one. I.e. the volatile part.
201
 */
202
static void clear_dquot(struct dquot * dquot)
203
{
204
        struct wait_queue *wait;
205
 
206
        wait_on_dquot(dquot);
207
        remove_dquot_hash(dquot);
208
        remove_dquot_free(dquot);
209
        wait = ((volatile struct dquot *) dquot)->dq_wait;
210
        if (dquot->dq_count)
211
                nr_free_dquots++;
212
        memset(dquot, 0, sizeof(*dquot));
213
        ((volatile struct dquot *) dquot)->dq_wait = wait;
214
        insert_dquot_free(dquot);
215
}
216
 
217
static void write_dquot(struct dquot *dquot)
218
{
219
        short type = dquot->dq_type;
220
        struct file *filp = dquot->dq_mnt->mnt_quotas[type];
221
        unsigned short fs;
222
 
223
        if (!(dquot->dq_flags & DQ_MOD) || (filp == (struct file *)NULL))
224
                return;
225
        lock_dquot(dquot);
226
        down(&dquot->dq_mnt->mnt_sem);
227
        if (filp->f_op->lseek) {
228
                if (filp->f_op->lseek(filp->f_inode, filp,
229
                    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
230
                        up(&dquot->dq_mnt->mnt_sem);
231
                        unlock_dquot(dquot);
232
                        return;
233
                }
234
        }
235
        else
236
        {
237
                int p = dqoff(dquot->dq_id);
238
                if(p>=0)
239
                        filp->f_pos = p;
240
        }
241
        fs = get_fs();
242
        set_fs(KERNEL_DS);
243
        if (filp->f_op->write(filp->f_inode, filp,
244
           (char *)&dquot->dq_dqb, sizeof(struct dqblk)) == sizeof(struct dqblk))
245
                dquot->dq_flags &= ~DQ_MOD;
246
        up(&dquot->dq_mnt->mnt_sem);
247
        set_fs(fs);
248
        unlock_dquot(dquot);
249
        dqstats.writes++;
250
}
251
 
252
static void read_dquot(struct dquot *dquot)
253
{
254
        short type = dquot->dq_type;
255
        struct file *filp = dquot->dq_mnt->mnt_quotas[type];
256
        unsigned short fs;
257
 
258
        if (filp == (struct file *)NULL)
259
                return;
260
        lock_dquot(dquot);
261
        down(&dquot->dq_mnt->mnt_sem);
262
        if (filp->f_op->lseek) {
263
                if (filp->f_op->lseek(filp->f_inode, filp,
264
                    dqoff(dquot->dq_id), 0) != dqoff(dquot->dq_id)) {
265
                        up(&dquot->dq_mnt->mnt_sem);
266
                        unlock_dquot(dquot);
267
                        return;
268
                }
269
        } else
270
                filp->f_pos = dqoff(dquot->dq_id);
271
        fs = get_fs();
272
        set_fs(KERNEL_DS);
273
        filp->f_op->read(filp->f_inode, filp, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
274
        up(&dquot->dq_mnt->mnt_sem);
275
        set_fs(fs);
276
        if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 &&
277
            dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0)
278
                dquot->dq_flags |= DQ_FAKE;
279
        unlock_dquot(dquot);
280
        dqstats.reads++;
281
}
282
 
283
int sync_dquots(kdev_t dev, short type)
284
{
285
        struct dquot *dquot = first_dquot;
286
        int i;
287
 
288
        dqstats.syncs++;
289
        for (i = 0; i < nr_dquots * 2; i++, dquot = dquot->dq_next) {
290
                if (dev == NODEV || dquot->dq_count == 0 || dquot->dq_dev != dev)
291
                        continue;
292
                if (type != -1 && dquot->dq_type != type)
293
                        continue;
294
                wait_on_dquot(dquot);
295
                if (dquot->dq_flags & DQ_MOD)
296
                        write_dquot(dquot);
297
        }
298
        return(0);
299
}
300
 
301
/*
302
 * Trash the cache for a certain type on a device.
303
 */
304
void invalidate_dquots(kdev_t dev, short type)
305
{
306
        struct dquot *dquot, *next;
307
        int cnt;
308
 
309
        next = first_dquot;
310
        for (cnt = nr_dquots ; cnt > 0 ; cnt--) {
311
                dquot = next;
312
                next = dquot->dq_next;
313
                if (dquot->dq_dev != dev || dquot->dq_type != type)
314
                        continue;
315
                if (dquot->dq_flags & DQ_LOCKED) {
316
                        printk("VFS: dquot busy on removed device %s\n", kdevname(dev));
317
                        continue;
318
                }
319
                if (dquot->dq_flags & DQ_MOD)
320
                        write_dquot(dquot);
321
                dqstats.drops++;
322
                clear_dquot(dquot);
323
        }
324
}
325
 
326
static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number)
327
{
328
        lock_dquot(dquot);
329
        dquot->dq_curinodes += number;
330
        dquot->dq_flags |= DQ_MOD;
331
        unlock_dquot(dquot);
332
}
333
 
334
static inline void dquot_incr_blocks(struct dquot *dquot, unsigned long number)
335
{
336
        lock_dquot(dquot);
337
        dquot->dq_curblocks += number;
338
        dquot->dq_flags |= DQ_MOD;
339
        unlock_dquot(dquot);
340
}
341
 
342
static inline void dquot_decr_inodes(struct dquot *dquot, unsigned long number)
343
{
344
        lock_dquot(dquot);
345
        if (dquot->dq_curinodes > number)
346
                dquot->dq_curinodes -= number;
347
        else
348
                dquot->dq_curinodes = 0;
349
        if (dquot->dq_curinodes < dquot->dq_isoftlimit)
350
                dquot->dq_itime = (time_t) 0;
351
        dquot->dq_flags &= ~DQ_INODES;
352
        dquot->dq_flags |= DQ_MOD;
353
        unlock_dquot(dquot);
354
}
355
 
356
static inline void dquot_decr_blocks(struct dquot *dquot, unsigned long number)
357
{
358
        lock_dquot(dquot);
359
        if (dquot->dq_curblocks > number)
360
                dquot->dq_curblocks -= number;
361
        else
362
                dquot->dq_curblocks = 0;
363
        if (dquot->dq_curblocks < dquot->dq_bsoftlimit)
364
                dquot->dq_btime = (time_t) 0;
365
        dquot->dq_flags &= ~DQ_BLKS;
366
        dquot->dq_flags |= DQ_MOD;
367
        unlock_dquot(dquot);
368
}
369
 
370
static inline int need_print_warning(short type, struct dquot *dquot)
371
{
372
        switch (type) {
373
                case USRQUOTA:
374
                        return(current->fsuid == dquot->dq_id);
375
                case GRPQUOTA:
376
                        return(current->fsgid == dquot->dq_id);
377
        }
378
        return(0);
379
}
380
 
381
static int check_idq(struct dquot *dquot, short type, u_long short inodes)
382
{
383
        if (inodes <= 0 || dquot->dq_flags & DQ_FAKE)
384
                return(QUOTA_OK);
385
        if (dquot->dq_ihardlimit &&
386
           (dquot->dq_curinodes + inodes) > dquot->dq_ihardlimit && !fsuser()) {
387
                if ((dquot->dq_flags & DQ_INODES) == 0 &&
388
                     need_print_warning(type, dquot)) {
389
                        sprintf(quotamessage, "%s: write failed, %s file limit reached\r\n",
390
                                dquot->dq_mnt->mnt_dirname, quotatypes[type]);
391
                        tty_write_message(current->tty, quotamessage);
392
                        dquot->dq_flags |= DQ_INODES;
393
                }
394
                return(NO_QUOTA);
395
        }
396
        if (dquot->dq_isoftlimit &&
397
           (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
398
            dquot->dq_itime && CURRENT_TIME >= dquot->dq_itime && !fsuser()) {
399
                if (need_print_warning(type, dquot)) {
400
                        sprintf(quotamessage, "%s: warning, %s file quota exceeded too long.\r\n",
401
                                dquot->dq_mnt->mnt_dirname, quotatypes[type]);
402
                        tty_write_message(current->tty, quotamessage);
403
                }
404
                return(NO_QUOTA);
405
        }
406
        if (dquot->dq_isoftlimit &&
407
           (dquot->dq_curinodes + inodes) > dquot->dq_isoftlimit &&
408
            dquot->dq_itime == 0 && !fsuser()) {
409
                if (need_print_warning(type, dquot)) {
410
                        sprintf(quotamessage, "%s: warning, %s file quota exceeded\r\n",
411
                                dquot->dq_mnt->mnt_dirname, quotatypes[type]);
412
                        tty_write_message(current->tty, quotamessage);
413
                }
414
                dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_iexp[type];
415
        }
416
        return(QUOTA_OK);
417
}
418
 
419
static int check_bdq(struct dquot *dquot, short type, u_long blocks)
420
{
421
        if (blocks <= 0 || dquot->dq_flags & DQ_FAKE)
422
                return(QUOTA_OK);
423
        if (dquot->dq_bhardlimit &&
424
           (dquot->dq_curblocks + blocks) > dquot->dq_bhardlimit && !fsuser()) {
425
                if ((dquot->dq_flags & DQ_BLKS) == 0 &&
426
                     need_print_warning(type, dquot)) {
427
                        sprintf(quotamessage, "%s: write failed, %s disk limit reached.\r\n",
428
                                dquot->dq_mnt->mnt_dirname, quotatypes[type]);
429
                        tty_write_message(current->tty, quotamessage);
430
                        dquot->dq_flags |= DQ_BLKS;
431
                }
432
                return(NO_QUOTA);
433
        }
434
        if (dquot->dq_bsoftlimit &&
435
           (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
436
            dquot->dq_btime && CURRENT_TIME >= dquot->dq_btime && !fsuser()) {
437
                if (need_print_warning(type, dquot)) {
438
                        sprintf(quotamessage, "%s: write failed, %s disk quota exceeded too long.\r\n",
439
                                dquot->dq_mnt->mnt_dirname, quotatypes[type]);
440
                        tty_write_message(current->tty, quotamessage);
441
                }
442
                return(NO_QUOTA);
443
        }
444
        if (dquot->dq_bsoftlimit &&
445
           (dquot->dq_curblocks + blocks) > dquot->dq_bsoftlimit &&
446
            dquot->dq_btime == 0 && !fsuser()) {
447
                if (need_print_warning(type, dquot)) {
448
                        sprintf(quotamessage, "%s: warning, %s disk quota exceeded\r\n",
449
                                dquot->dq_mnt->mnt_dirname, quotatypes[type]);
450
                        tty_write_message(current->tty, quotamessage);
451
                }
452
                dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_bexp[type];
453
        }
454
        return(QUOTA_OK);
455
}
456
 
457
static void dqput(struct dquot *dquot)
458
{
459
        if (!dquot)
460
                return;
461
        /*
462
         * If the dq_mnt pointer isn't initialized this entry needs no
463
         * checking and doesn't need to be written. It just an empty
464
         * dquot that is put back into the freelist.
465
         */
466
        if (dquot->dq_mnt != (struct vfsmount *)NULL) {
467
                dqstats.drops++;
468
                wait_on_dquot(dquot);
469
                if (!dquot->dq_count) {
470
                        printk("VFS: dqput: trying to free free dquot\n");
471
                        printk("VFS: device %s, dquot of %s %d\n", kdevname(dquot->dq_dev),
472
                               quotatypes[dquot->dq_type], dquot->dq_id);
473
                        return;
474
                }
475
repeat:
476
                if (dquot->dq_count > 1) {
477
                        dquot->dq_count--;
478
                        return;
479
                }
480
                wake_up(&dquot_wait);
481
                if (dquot->dq_flags & DQ_MOD) {
482
                        write_dquot(dquot);     /* we can sleep - so do again */
483
                        wait_on_dquot(dquot);
484
                        goto repeat;
485
                }
486
        }
487
        if (dquot->dq_count) {
488
                dquot->dq_count--;
489
                nr_free_dquots++;
490
        }
491
        return;
492
}
493
 
494
static struct dquot *get_empty_dquot(void)
495
{
496
        struct dquot *dquot, *best;
497
        int cnt;
498
 
499
        if (nr_dquots < NR_DQUOTS && nr_free_dquots < (nr_dquots >> 2))
500
                grow_dquots();
501
 
502
repeat:
503
        dquot = first_dquot;
504
        best = NODQUOT;
505
        for (cnt = 0; cnt < nr_dquots; dquot = dquot->dq_next, cnt++) {
506
                if (!dquot->dq_count) {
507
                        if (!best)
508
                                best = dquot;
509
                        if (!(dquot->dq_flags & DQ_MOD) && !(dquot->dq_flags & DQ_LOCKED)) {
510
                                best = dquot;
511
                                break;
512
                        }
513
                }
514
        }
515
        if (!best || best->dq_flags & DQ_MOD || best->dq_flags & DQ_LOCKED)
516
                if (nr_dquots < NR_DQUOTS) {
517
                        grow_dquots();
518
                        goto repeat;
519
                }
520
        dquot = best;
521
        if (!dquot) {
522
                printk("VFS: No free dquots - contact mvw@mcs.ow.org\n");
523
                sleep_on(&dquot_wait);
524
                goto repeat;
525
        }
526
        if (dquot->dq_flags & DQ_LOCKED) {
527
                wait_on_dquot(dquot);
528
                goto repeat;
529
        }
530
        if (dquot->dq_flags & DQ_MOD) {
531
                write_dquot(dquot);
532
                goto repeat;
533
        }
534
        if (dquot->dq_count)
535
                goto repeat;
536
        clear_dquot(dquot);
537
        dquot->dq_count = 1;
538
        nr_free_dquots--;
539
        if (nr_free_dquots < 0) {
540
                printk ("VFS: get_empty_dquot: bad free dquot count.\n");
541
                nr_free_dquots = 0;
542
        }
543
        return(dquot);
544
}
545
 
546
static struct dquot *dqget(kdev_t dev, unsigned int id, short type)
547
{
548
        struct dquot *dquot, *empty;
549
        struct vfsmount *vfsmnt;
550
 
551
        if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL ||
552
            (vfsmnt->mnt_quotas[type] == (struct file *)0))
553
                return(NODQUOT);
554
        dqstats.lookups++;
555
        empty = get_empty_dquot();
556
repeat:
557
        dquot = *(hash(dev, id, type));
558
        while (dquot) {
559
                if (dquot->dq_dev != dev || dquot->dq_id != id ||
560
                    dquot->dq_type != type) {
561
                        dquot = dquot->dq_hash_next;
562
                        continue;
563
                }
564
                wait_on_dquot(dquot);
565
                if (dquot->dq_dev != dev || dquot->dq_id != id ||
566
                    dquot->dq_type != type)
567
                        goto repeat;
568
                if (!dquot->dq_count)
569
                        nr_free_dquots--;
570
                dquot->dq_count++;
571
                if (empty)
572
                        dqput(empty);
573
                dqstats.cache_hits++;
574
                return(dquot);
575
        }
576
        if (!empty)
577
                return(NODQUOT);
578
        dquot = empty;
579
        dquot->dq_id = id;
580
        dquot->dq_type = type;
581
        dquot->dq_dev = dev;
582
        dquot->dq_mnt = vfsmnt;
583
        put_last_free(dquot);
584
        insert_dquot_hash(dquot);
585
        read_dquot(dquot);
586
        return(dquot);
587
}
588
 
589
/*
590
 * Initialize a dquot-struct with new quota info. This is used by the
591
 * systemcall interface functions.
592
 */
593
static int set_dqblk(kdev_t dev, int id, short type, int flags, struct dqblk *dqblk)
594
{
595
        struct dquot *dquot;
596
        struct dqblk dq_dqblk;
597
        int error;
598
 
599
        if (dqblk == (struct dqblk *)NULL)
600
                return(-EFAULT);
601
 
602
        if (flags & QUOTA_SYSCALL) {
603
                if ((error = verify_area(VERIFY_READ, dqblk, sizeof(struct dqblk))) != 0)
604
                        return(error);
605
                memcpy_fromfs(&dq_dqblk, dqblk, sizeof(struct dqblk));
606
        } else {
607
                memcpy(&dq_dqblk, dqblk, sizeof(struct dqblk));
608
        }
609
        if ((dquot = dqget(dev, id, type)) != NODQUOT) {
610
                lock_dquot(dquot);
611
                if (id > 0 && ((flags & SET_QUOTA) || (flags & SET_QLIMIT))) {
612
                        dquot->dq_bhardlimit = dq_dqblk.dqb_bhardlimit;
613
                        dquot->dq_bsoftlimit = dq_dqblk.dqb_bsoftlimit;
614
                        dquot->dq_ihardlimit = dq_dqblk.dqb_ihardlimit;
615
                        dquot->dq_isoftlimit = dq_dqblk.dqb_isoftlimit;
616
                }
617
                if ((flags & SET_QUOTA) || (flags & SET_USE)) {
618
                        if (dquot->dq_isoftlimit &&
619
                            dquot->dq_curinodes < dquot->dq_isoftlimit &&
620
                            dq_dqblk.dqb_curinodes >= dquot->dq_isoftlimit)
621
                                dquot->dq_itime = CURRENT_TIME + dquot->dq_mnt->mnt_iexp[type];
622
                        dquot->dq_curinodes = dq_dqblk.dqb_curinodes;
623
                        if (dquot->dq_curinodes < dquot->dq_isoftlimit)
624
                                dquot->dq_flags &= ~DQ_INODES;
625
                        if (dquot->dq_bsoftlimit &&
626
                            dquot->dq_curblocks < dquot->dq_bsoftlimit &&
627
                            dq_dqblk.dqb_curblocks >= dquot->dq_bsoftlimit)
628
                                dquot->dq_btime = CURRENT_TIME + dquot->dq_mnt->mnt_bexp[type];
629
                        dquot->dq_curblocks = dq_dqblk.dqb_curblocks;
630
                        if (dquot->dq_curblocks < dquot->dq_bsoftlimit)
631
                                dquot->dq_flags &= ~DQ_BLKS;
632
                }
633
                if (id == 0) {
634
                        /*
635
                         * Change in expiretimes, change them in dq_mnt.
636
                         */
637
                        dquot->dq_mnt->mnt_bexp[type] = dquot->dq_btime = dq_dqblk.dqb_btime;
638
                        dquot->dq_mnt->mnt_iexp[type] = dquot->dq_itime = dq_dqblk.dqb_itime;
639
                }
640
                if (dq_dqblk.dqb_bhardlimit == 0 && dq_dqblk.dqb_bsoftlimit == 0 &&
641
                    dq_dqblk.dqb_ihardlimit == 0 && dq_dqblk.dqb_isoftlimit == 0)
642
                        dquot->dq_flags |= DQ_FAKE;
643
                else
644
                        dquot->dq_flags &= ~DQ_FAKE;
645
                dquot->dq_flags |= DQ_MOD;
646
                unlock_dquot(dquot);
647
                dqput(dquot);
648
        }
649
        return(0);
650
}
651
 
652
static int get_quota(kdev_t dev, int id, short type, struct dqblk *dqblk)
653
{
654
        struct dquot *dquot;
655
        int error;
656
 
657
        if (has_quota_enabled(dev, type)) {
658
                if (dqblk == (struct dqblk *)NULL)
659
                        return(-EFAULT);
660
 
661
                if ((error = verify_area(VERIFY_WRITE, dqblk, sizeof(struct dqblk))) != 0)
662
                        return(error);
663
 
664
                if ((dquot = dqget(dev, id, type)) != NODQUOT) {
665
                        memcpy_tofs(dqblk, (char *)&dquot->dq_dqb, sizeof(struct dqblk));
666
                        dqput(dquot);
667
                        return(0);
668
                }
669
        }
670
        return(-ESRCH);
671
}
672
 
673
static int get_stats(caddr_t addr)
674
{
675
        int error;
676
 
677
        if ((error = verify_area(VERIFY_WRITE, addr, sizeof(struct dqstats))) != 0)
678
                return(error);
679
 
680
        dqstats.allocated_dquots = nr_dquots;
681
        dqstats.free_dquots = nr_free_dquots;
682
        memcpy_tofs(addr, (caddr_t)&dqstats, sizeof(struct dqstats));
683
        return(0);
684
}
685
 
686
/*
687
 * Initialize pointer in a inode to the right dquots.
688
 */
689
void dquot_initialize(struct inode *inode, short type)
690
{
691
        unsigned int id = 0;
692
        short cnt;
693
        struct dquot *tmp;
694
 
695
        if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
696
                for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
697
                        if (type != -1 && cnt != type)
698
                                continue;
699
                        if (!has_quota_enabled(inode->i_dev, cnt))
700
                                continue;
701
                        if (inode->i_dquot[cnt] == NODQUOT) {
702
                                switch (cnt) {
703
                                        case USRQUOTA:
704
                                                id = inode->i_uid;
705
                                                break;
706
                                        case GRPQUOTA:
707
                                                id = inode->i_gid;
708
                                                break;
709
                                }
710
 
711
                                tmp = dqget(inode->i_dev, id, cnt);
712
                                /* We may sleep in dqget(), so check it again.
713
                                 *      Dmitry Gorodchanin 02/11/96
714
                                 */
715
                                if (inode->i_dquot[cnt] != NODQUOT) {
716
                                        dqput(tmp);
717
                                        continue;
718
                                }
719
                                inode->i_dquot[cnt] = tmp;
720
                                inode->i_flags |= S_WRITE;
721
                        }
722
                }
723
        }
724
}
725
 
726
void dquot_drop(struct inode *inode)
727
{
728
        short cnt;
729
        struct dquot * tmp;
730
 
731
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
732
                if (inode->i_dquot[cnt] == NODQUOT)
733
                        continue;
734
                /* We can sleep at dqput(). So we must do it this way.
735
                 *      Dmitry Gorodchanin 02/11/96
736
                 */
737
                tmp = inode->i_dquot[cnt];
738
                inode->i_dquot[cnt] = NODQUOT;
739
                dqput(tmp);
740
        }
741
        inode->i_flags &= ~S_WRITE;
742
}
743
 
744
/*
745
 * This is a simple algorithm that calculates the size of a file in blocks.
746
 * This is only used on filesystems that do not have a i_blocks count.
747
 */
748
static u_long isize_to_blocks(size_t isize, size_t blksize)
749
{
750
        u_long blocks;
751
        u_long indirect;
752
 
753
        if (!blksize)
754
                blksize = BLOCK_SIZE;
755
        blocks = (isize / blksize) + ((isize % blksize) ? 1 : 0);
756
        if (blocks > 10) {
757
                indirect = ((blocks - 11) >> 8) + 1; /* single indirect blocks */
758
                if (blocks > (10 + 256)) {
759
                        indirect += ((blocks - 267) >> 16) + 1; /* double indirect blocks */
760
                        if (blocks > (10 + 256 + (256 << 8)))
761
                                indirect++; /* triple indirect blocks */
762
                }
763
                blocks += indirect;
764
        }
765
        return(blocks);
766
}
767
 
768
/*
769
 * Externally referenced functions through dquot_operations.
770
 */
771
int dquot_alloc_block(const struct inode *inode, unsigned long number)
772
{
773
        unsigned short cnt;
774
 
775
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
776
                if (inode->i_dquot[cnt] == NODQUOT)
777
                        continue;
778
                if (check_bdq(inode->i_dquot[cnt], cnt, number))
779
                        return(NO_QUOTA);
780
        }
781
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
782
                if (inode->i_dquot[cnt] == NODQUOT)
783
                        continue;
784
                dquot_incr_blocks(inode->i_dquot[cnt], number);
785
        }
786
        return(QUOTA_OK);
787
}
788
 
789
int dquot_alloc_inode(const struct inode *inode, unsigned long number)
790
{
791
        unsigned short cnt;
792
 
793
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
794
                if (inode->i_dquot[cnt] == NODQUOT)
795
                        continue;
796
                if (check_idq(inode->i_dquot[cnt], cnt, number))
797
                        return(NO_QUOTA);
798
        }
799
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
800
                if (inode->i_dquot[cnt] == NODQUOT)
801
                        continue;
802
                dquot_incr_inodes(inode->i_dquot[cnt], number);
803
        }
804
        return(QUOTA_OK);
805
}
806
 
807
void dquot_free_block(const struct inode *inode, unsigned long number)
808
{
809
        unsigned short cnt;
810
 
811
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
812
                if (inode->i_dquot[cnt] == NODQUOT)
813
                        continue;
814
                dquot_decr_blocks(inode->i_dquot[cnt], number);
815
        }
816
}
817
 
818
void dquot_free_inode(const struct inode *inode, unsigned long number)
819
{
820
        unsigned short cnt;
821
 
822
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
823
                if (inode->i_dquot[cnt] == NODQUOT)
824
                        continue;
825
                dquot_decr_inodes(inode->i_dquot[cnt], number);
826
        }
827
}
828
 
829
/*
830
 * Transfer the number of inode and blocks from one diskquota to an other.
831
 */
832
int dquot_transfer(struct inode *inode, struct iattr *iattr, char direction)
833
{
834
        unsigned long blocks;
835
        struct dquot *transfer_from[MAXQUOTAS];
836
        struct dquot *transfer_to[MAXQUOTAS];
837
        short cnt, disc;
838
 
839
        /*
840
         * Find out if this filesystems uses i_blocks.
841
         */
842
        if (inode->i_blksize == 0)
843
                blocks = isize_to_blocks(inode->i_size, BLOCK_SIZE);
844
        else
845
                blocks = (inode->i_blocks / 2);
846
 
847
 
848
        /*
849
         *      This shouldnt be needed but the goal is to fix 2.0 not
850
         *      do things in best of Torvalds style. Thats for 2.1...
851
         */
852
 
853
        if(S_ISFIFO(inode->i_mode)||S_ISSOCK(inode->i_mode))
854
                blocks = 0;
855
 
856
        /*
857
         * Build the transfer_from and transfer_to lists and check quotas to see
858
         * if operation is permitted.
859
         */
860
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
861
                transfer_from[cnt] = NODQUOT;
862
                transfer_to[cnt] = NODQUOT;
863
 
864
                if (!has_quota_enabled(inode->i_dev, cnt))
865
                        continue;
866
 
867
                switch (cnt) {
868
                        case USRQUOTA:
869
                                if (inode->i_uid == iattr->ia_uid)
870
                                        continue;
871
                                transfer_from[cnt] = dqget(inode->i_dev, (direction) ? iattr->ia_uid : inode->i_uid, cnt);
872
                                transfer_to[cnt] = dqget(inode->i_dev, (direction) ? inode->i_uid : iattr->ia_uid, cnt);
873
                                break;
874
                        case GRPQUOTA:
875
                                if (inode->i_gid == iattr->ia_gid)
876
                                        continue;
877
                                transfer_from[cnt] = dqget(inode->i_dev, (direction) ? iattr->ia_gid : inode->i_gid, cnt);
878
                                transfer_to[cnt] = dqget(inode->i_dev, (direction) ? inode->i_gid : iattr->ia_gid, cnt);
879
                                break;
880
                }
881
 
882
                if (check_idq(transfer_to[cnt], cnt, 1) == NO_QUOTA ||
883
                    check_bdq(transfer_to[cnt], cnt, blocks) == NO_QUOTA) {
884
                        for (disc = 0; disc <= cnt; disc++) {
885
                                dqput(transfer_from[disc]);
886
                                dqput(transfer_to[disc]);
887
                        }
888
                        return(NO_QUOTA);
889
                }
890
        }
891
 
892
        /*
893
         * Finally perform the needed transfer from transfer_from to transfer_to.
894
         * And release any pointer to dquots not needed anymore.
895
         */
896
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
897
                /*
898
                 * Skip changes for same uid or gid or for non-existing quota-type.
899
                 */
900
                if (transfer_from[cnt] == NODQUOT && transfer_to[cnt] == NODQUOT)
901
                        continue;
902
 
903
                if (transfer_from[cnt] != NODQUOT) {
904
                        dquot_decr_inodes(transfer_from[cnt], 1);
905
                        dquot_decr_blocks(transfer_from[cnt], blocks);
906
                }
907
                if (transfer_to[cnt] != NODQUOT) {
908
                        dquot_incr_inodes(transfer_to[cnt], 1);
909
                        dquot_incr_blocks(transfer_to[cnt], blocks);
910
                }
911
                if (inode->i_dquot[cnt] != NODQUOT) {
912
                        dqput(transfer_from[cnt]);
913
                        dqput(inode->i_dquot[cnt]);
914
                        inode->i_dquot[cnt] = transfer_to[cnt];
915
                } else {
916
                        dqput(transfer_from[cnt]);
917
                        dqput(transfer_to[cnt]);
918
                }
919
        }
920
        return(QUOTA_OK);
921
}
922
 
923
void dquot_init(void)
924
{
925
        printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\r\n",
926
               __DQUOT_VERSION__);
927
        memset(hash_table, 0, sizeof(hash_table));
928
        memset((caddr_t)&dqstats, 0, sizeof(dqstats));
929
        first_dquot = NODQUOT;
930
}
931
 
932
/*
933
 * Definitions of diskquota operations.
934
 */
935
struct dquot_operations dquot_operations = {
936
        dquot_initialize,
937
        dquot_drop,
938
        dquot_alloc_block,
939
        dquot_alloc_inode,
940
        dquot_free_block,
941
        dquot_free_inode,
942
        dquot_transfer
943
};
944
 
945
/*
946
 * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount)
947
 */
948
int quota_off(kdev_t dev, short type)
949
{
950
        struct vfsmount *vfsmnt;
951
        short cnt;
952
 
953
        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
954
                if (type != -1 && cnt != type)
955
                        continue;
956
                if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL ||
957
                     vfsmnt->mnt_quotas[cnt] == (struct file *)NULL)
958
                        continue;
959
                vfsmnt->mnt_sb->dq_op = (struct dquot_operations *)NULL;
960
                reset_dquot_ptrs(dev, cnt);
961
                invalidate_dquots(dev, cnt);
962
                close_fp(vfsmnt->mnt_quotas[cnt]);
963
                vfsmnt->mnt_quotas[cnt] = (struct file *)NULL;
964
                vfsmnt->mnt_iexp[cnt] = vfsmnt->mnt_bexp[cnt] = (time_t)NULL;
965
        }
966
        return(0);
967
}
968
 
969
int quota_on(kdev_t dev, short type, char *path)
970
{
971
        struct file *filp = (struct file *)NULL;
972
        struct vfsmount *vfsmnt;
973
        struct inode *inode;
974
        struct dquot *dquot;
975
        char *tmp;
976
        int error;
977
 
978
        if ((vfsmnt = lookup_vfsmnt(dev)) == (struct vfsmount *)NULL)
979
                return(-ENODEV);
980
        if (vfsmnt->mnt_quotas[type] != (struct file *)NULL)
981
                return(-EBUSY);
982
        if ((error = getname(path, &tmp)) != 0)
983
                return(error);
984
        error = open_namei(tmp, O_RDWR, 0600, &inode, 0);
985
        putname(tmp);
986
        if (error)
987
                return(error);
988
        if (!S_ISREG(inode->i_mode)) {
989
                iput(inode);
990
                return(-EACCES);
991
        }
992
        if ((filp = get_empty_filp()) != (struct file *)NULL) {
993
                filp->f_mode = (O_RDWR + 1) & O_ACCMODE;
994
                filp->f_flags = O_RDWR;
995
                filp->f_inode = inode;
996
                filp->f_pos = 0;
997
                filp->f_reada = 0;
998
                filp->f_op = inode->i_op->default_file_ops;
999
                if (filp->f_op->read || filp->f_op->write) {
1000
                        if ((error = get_write_access(inode)) == 0) {
1001
                                if (filp->f_op && filp->f_op->open)
1002
                                        error = filp->f_op->open(inode, filp);
1003
                                if (error == 0) {
1004
                                        vfsmnt->mnt_quotas[type] = filp;
1005
                                        dquot = dqget(dev, 0, type);
1006
                                        vfsmnt->mnt_iexp[type] = (dquot) ? dquot->dq_itime : MAX_IQ_TIME;
1007
                                        vfsmnt->mnt_bexp[type] = (dquot) ? dquot->dq_btime : MAX_DQ_TIME;
1008
                                        dqput(dquot);
1009
                                        vfsmnt->mnt_sb->dq_op = &dquot_operations;
1010
                                        add_dquot_ref(dev, type);
1011
                                        return(0);
1012
                                }
1013
                                put_write_access(inode);
1014
                        }
1015
                } else
1016
                        error = -EIO;
1017
          filp->f_count--;
1018
        } else
1019
                error = -EMFILE;
1020
        iput(inode);
1021
        return(error);
1022
}
1023
 
1024
/*
1025
 * Ok this is the systemcall interface, this communicates with
1026
 * the userlevel programs. Currently this only supports diskquota
1027
 * calls. Maybe we need to add the process quotas etc in the future.
1028
 * But we probably better use rlimits for that.
1029
 */
1030
asmlinkage int sys_quotactl(int cmd, const char *special, int id, caddr_t addr)
1031
{
1032
        int cmds = 0, type = 0, flags = 0;
1033
        struct inode *ino;
1034
        kdev_t dev;
1035
 
1036
        cmds = cmd >> SUBCMDSHIFT;
1037
        type = cmd & SUBCMDMASK;
1038
 
1039
        if ((u_int) type >= MAXQUOTAS)
1040
                return(-EINVAL);
1041
        switch (cmds) {
1042
                case Q_SYNC:
1043
                case Q_GETSTATS:
1044
                        break;
1045
                case Q_GETQUOTA:
1046
                        if (((type == USRQUOTA && current->uid != id) ||
1047
                             (type == GRPQUOTA && current->gid != id)) && !fsuser())
1048
                                return(-EPERM);
1049
                        break;
1050
                default:
1051
                        if (!fsuser())
1052
                                return(-EPERM);
1053
        }
1054
 
1055
        if (special == (char *)NULL && (cmds == Q_SYNC || cmds == Q_GETSTATS))
1056
                dev = 0;
1057
        else {
1058
                if (namei(special, &ino))
1059
                        return(-EINVAL);
1060
                dev = ino->i_rdev;
1061
                if (!S_ISBLK(ino->i_mode)) {
1062
                        iput(ino);
1063
                        return(-ENOTBLK);
1064
                }
1065
                iput(ino);
1066
        }
1067
 
1068
        switch (cmds) {
1069
                case Q_QUOTAON:
1070
                        return(quota_on(dev, type, (char *) addr));
1071
                case Q_QUOTAOFF:
1072
                        return(quota_off(dev, type));
1073
                case Q_GETQUOTA:
1074
                        return(get_quota(dev, id, type, (struct dqblk *) addr));
1075
                case Q_SETQUOTA:
1076
                        flags |= SET_QUOTA;
1077
                        break;
1078
                case Q_SETUSE:
1079
                        flags |= SET_USE;
1080
                        break;
1081
                case Q_SETQLIM:
1082
                        flags |= SET_QLIMIT;
1083
                        break;
1084
                case Q_SYNC:
1085
                        return(sync_dquots(dev, type));
1086
                case Q_GETSTATS:
1087
                        return(get_stats(addr));
1088
                default:
1089
                        return(-EINVAL);
1090
        }
1091
 
1092
        if (id & ~0xFFFF)
1093
                return(-EINVAL);
1094
 
1095
        flags |= QUOTA_SYSCALL;
1096
        if (has_quota_enabled(dev, type))
1097
                return(set_dqblk(dev, id, type, flags, (struct dqblk *) addr));
1098
        return(-ESRCH);
1099
}

powered by: WebSVN 2.1.0

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