Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / lvfs / lustre_quota_fmt.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * Lustre administrative quota format.
5  *
6  *  from
7  *  linux/fs/quota_v2.c
8  */
9
10 #ifndef EXPORT_SYMTAB
11 # define EXPORT_SYMTAB
12 #endif
13
14 #include <linux/errno.h>
15 #include <linux/fs.h>
16 #include <linux/mount.h>
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19 #include <linux/module.h>
20 #include <linux/slab.h>
21 #include <linux/quotaio_v1.h>
22
23 #include <asm/byteorder.h>
24 #include <asm/uaccess.h>
25
26 #include <lustre_quota.h>
27 #include "lustre_quota_fmt.h"
28
29 typedef char *dqbuf_t;
30
31 #define GETIDINDEX(id, depth) (((id) >> ((LUSTRE_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
32 #define GETENTRIES(buf) ((struct lustre_disk_dqblk *)(((char *)buf)+sizeof(struct lustre_disk_dqdbheader)))
33
34 static int check_quota_file(struct file *f, struct inode *inode, int type)
35 {
36         struct lustre_disk_dqheader dqhead;
37         mm_segment_t fs;
38         ssize_t size;
39         loff_t offset = 0;
40         static const uint quota_magics[] = LUSTRE_INITQMAGICS;
41         static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
42
43         if (f) {
44                 fs = get_fs();
45                 set_fs(KERNEL_DS);
46                 size = f->f_op->read(f, (char *)&dqhead,
47                                      sizeof(struct lustre_disk_dqheader), 
48                                      &offset);
49                 set_fs(fs);
50         } else { 
51 #ifndef KERNEL_SUPPORTS_QUOTA_READ
52                 size = 0;
53 #else
54                 struct super_block *sb = inode->i_sb;
55                 size = sb->s_op->quota_read(sb, type, (char *)&dqhead, 
56                                             sizeof(struct lustre_disk_dqheader), 0);
57 #endif
58         }
59         if (size != sizeof(struct lustre_disk_dqheader))
60                 return 0;
61         if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
62             le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
63                 return 0;
64         return 1;
65 }
66
67 /* Check whether given file is really lustre admin quotafile */
68 int lustre_check_quota_file(struct lustre_quota_info *lqi, int type)
69 {
70         struct file *f = lqi->qi_files[type];
71         return check_quota_file(f, NULL, type);
72 }
73
74 /* Read information header from quota file */
75 int lustre_read_quota_info(struct lustre_quota_info *lqi, int type)
76 {
77         mm_segment_t fs;
78         struct lustre_disk_dqinfo dinfo;
79         struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
80         struct file *f = lqi->qi_files[type];
81         ssize_t size;
82         loff_t offset = LUSTRE_DQINFOOFF;
83
84         fs = get_fs();
85         set_fs(KERNEL_DS);
86         size = f->f_op->read(f, (char *)&dinfo, 
87                              sizeof(struct lustre_disk_dqinfo), &offset);
88         set_fs(fs);
89         if (size != sizeof(struct lustre_disk_dqinfo)) {
90                 printk(KERN_WARNING "Can't read info structure on device %s.\n",
91                        f->f_vfsmnt->mnt_sb->s_id);
92                 return -1;
93         }
94         info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
95         info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
96         info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
97         info->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
98         info->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
99         info->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
100         return 0;
101 }
102
103 /* Write information header to quota file */
104 int lustre_write_quota_info(struct lustre_quota_info *lqi, int type)
105 {
106         mm_segment_t fs;
107         struct lustre_disk_dqinfo dinfo;
108         struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
109         struct file *f = lqi->qi_files[type];
110         ssize_t size;
111         loff_t offset = LUSTRE_DQINFOOFF;
112
113         info->dqi_flags &= ~DQF_INFO_DIRTY;
114         dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
115         dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
116         dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
117         dinfo.dqi_blocks = cpu_to_le32(info->dqi_blocks);
118         dinfo.dqi_free_blk = cpu_to_le32(info->dqi_free_blk);
119         dinfo.dqi_free_entry = cpu_to_le32(info->dqi_free_entry);
120         fs = get_fs();
121         set_fs(KERNEL_DS);
122         size = f->f_op->write(f, (char *)&dinfo, 
123                               sizeof(struct lustre_disk_dqinfo), &offset);
124         set_fs(fs);
125         if (size != sizeof(struct lustre_disk_dqinfo)) {
126                 printk(KERN_WARNING
127                        "Can't write info structure on device %s.\n",
128                        f->f_vfsmnt->mnt_sb->s_id);
129                 return -1;
130         }
131         return 0;
132 }
133
134 static void disk2memdqb(struct mem_dqblk *m, struct lustre_disk_dqblk *d)
135 {
136         m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
137         m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
138         m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
139         m->dqb_itime = le64_to_cpu(d->dqb_itime);
140         m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
141         m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
142         m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
143         m->dqb_btime = le64_to_cpu(d->dqb_btime);
144 }
145
146 static void mem2diskdqb(struct lustre_disk_dqblk *d, struct mem_dqblk *m,
147                         qid_t id)
148 {
149         d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
150         d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
151         d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
152         d->dqb_itime = cpu_to_le64(m->dqb_itime);
153         d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
154         d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
155         d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
156         d->dqb_btime = cpu_to_le64(m->dqb_btime);
157         d->dqb_id = cpu_to_le32(id);
158 }
159
160 static dqbuf_t getdqbuf(void)
161 {
162         dqbuf_t buf = kmalloc(LUSTRE_DQBLKSIZE, GFP_NOFS);
163         if (!buf)
164                 printk(KERN_WARNING
165                        "VFS: Not enough memory for quota buffers.\n");
166         return buf;
167 }
168
169 static inline void freedqbuf(dqbuf_t buf)
170 {
171         kfree(buf);
172 }
173
174 static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
175 {
176         mm_segment_t fs;
177         ssize_t ret;
178         loff_t offset = blk << LUSTRE_DQBLKSIZE_BITS;
179
180         memset(buf, 0, LUSTRE_DQBLKSIZE);
181         fs = get_fs();
182         set_fs(KERNEL_DS);
183         ret = filp->f_op->read(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
184         set_fs(fs);
185         return ret;
186 }
187
188 static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
189 {
190         mm_segment_t fs;
191         ssize_t ret;
192         loff_t offset = blk << LUSTRE_DQBLKSIZE_BITS;
193
194         fs = get_fs();
195         set_fs(KERNEL_DS);
196         ret = filp->f_op->write(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
197         set_fs(fs);
198         return ret;
199
200 }
201
202 static void lustre_mark_info_dirty(struct lustre_mem_dqinfo *info)
203 {
204         set_bit(DQF_INFO_DIRTY_B, &info->dqi_flags);
205 }
206
207 #define lustre_info_dirty(info) test_bit(DQF_INFO_DIRTY_B, &(info)->dqi_flags)
208
209 /* Remove empty block from list and return it */
210 static int get_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info)
211 {
212         dqbuf_t buf = getdqbuf();
213         struct lustre_disk_dqdbheader *dh =
214             (struct lustre_disk_dqdbheader *)buf;
215         int ret, blk;
216
217         if (!buf)
218                 return -ENOMEM;
219         if (info->dqi_free_blk) {
220                 blk = info->dqi_free_blk;
221                 if ((ret = read_blk(filp, blk, buf)) < 0)
222                         goto out_buf;
223                 info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
224         } else {
225                 memset(buf, 0, LUSTRE_DQBLKSIZE);
226                 if ((ret = write_blk(filp, info->dqi_blocks, buf)) < 0) /* Assure block allocation... */
227                         goto out_buf;
228                 blk = info->dqi_blocks++;
229         }
230         lustre_mark_info_dirty(info);
231         ret = blk;
232 out_buf:
233         freedqbuf(buf);
234         return ret;
235 }
236
237 /* Insert empty block to the list */
238 static int put_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info,
239                           dqbuf_t buf, uint blk)
240 {
241         struct lustre_disk_dqdbheader *dh =
242             (struct lustre_disk_dqdbheader *)buf;
243         int err;
244
245         dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
246         dh->dqdh_prev_free = cpu_to_le32(0);
247         dh->dqdh_entries = cpu_to_le16(0);
248         info->dqi_free_blk = blk;
249         lustre_mark_info_dirty(info);
250         if ((err = write_blk(filp, blk, buf)) < 0)
251                 /* Some strange block. We had better leave it... */
252                 return err;
253         return 0;
254 }
255
256 /* Remove given block from the list of blocks with free entries */
257 static int remove_free_dqentry(struct file *filp,
258                                struct lustre_mem_dqinfo *info, dqbuf_t buf,
259                                uint blk)
260 {
261         dqbuf_t tmpbuf = getdqbuf();
262         struct lustre_disk_dqdbheader *dh =
263             (struct lustre_disk_dqdbheader *)buf;
264         uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk =
265             le32_to_cpu(dh->dqdh_prev_free);
266         int err;
267
268         if (!tmpbuf)
269                 return -ENOMEM;
270         if (nextblk) {
271                 if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
272                         goto out_buf;
273                 ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
274                     dh->dqdh_prev_free;
275                 if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
276                         goto out_buf;
277         }
278         if (prevblk) {
279                 if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
280                         goto out_buf;
281                 ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_next_free =
282                     dh->dqdh_next_free;
283                 if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
284                         goto out_buf;
285         } else {
286                 info->dqi_free_entry = nextblk;
287                 lustre_mark_info_dirty(info);
288         }
289         freedqbuf(tmpbuf);
290         dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
291         if (write_blk(filp, blk, buf) < 0)      /* No matter whether write succeeds block is out of list */
292                 printk(KERN_ERR
293                        "VFS: Can't write block (%u) with free entries.\n", blk);
294         return 0;
295 out_buf:
296         freedqbuf(tmpbuf);
297         return err;
298 }
299
300 /* Insert given block to the beginning of list with free entries */
301 static int insert_free_dqentry(struct file *filp,
302                                struct lustre_mem_dqinfo *info, dqbuf_t buf,
303                                uint blk)
304 {
305         dqbuf_t tmpbuf = getdqbuf();
306         struct lustre_disk_dqdbheader *dh =
307             (struct lustre_disk_dqdbheader *)buf;
308         int err;
309
310         if (!tmpbuf)
311                 return -ENOMEM;
312         dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
313         dh->dqdh_prev_free = cpu_to_le32(0);
314         if ((err = write_blk(filp, blk, buf)) < 0)
315                 goto out_buf;
316         if (info->dqi_free_entry) {
317                 if ((err = read_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
318                         goto out_buf;
319                 ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
320                     cpu_to_le32(blk);
321                 if ((err = write_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
322                         goto out_buf;
323         }
324         freedqbuf(tmpbuf);
325         info->dqi_free_entry = blk;
326         lustre_mark_info_dirty(info);
327         return 0;
328 out_buf:
329         freedqbuf(tmpbuf);
330         return err;
331 }
332
333 /* Find space for dquot */
334 static uint find_free_dqentry(struct lustre_dquot *dquot, int *err)
335 {
336         struct lustre_quota_info *lqi = dquot->dq_info;
337         struct file *filp = lqi->qi_files[dquot->dq_type];
338         struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
339         uint blk, i;
340         struct lustre_disk_dqdbheader *dh;
341         struct lustre_disk_dqblk *ddquot;
342         struct lustre_disk_dqblk fakedquot;
343         dqbuf_t buf;
344
345         *err = 0;
346         if (!(buf = getdqbuf())) {
347                 *err = -ENOMEM;
348                 return 0;
349         }
350         dh = (struct lustre_disk_dqdbheader *)buf;
351         ddquot = GETENTRIES(buf);
352         if (info->dqi_free_entry) {
353                 blk = info->dqi_free_entry;
354                 if ((*err = read_blk(filp, blk, buf)) < 0)
355                         goto out_buf;
356         } else {
357                 blk = get_free_dqblk(filp, info);
358                 if ((int)blk < 0) {
359                         *err = blk;
360                         freedqbuf(buf);
361                         return 0;
362                 }
363                 memset(buf, 0, LUSTRE_DQBLKSIZE);
364                 info->dqi_free_entry = blk;     /* This is enough as block is already zeroed and entry list is empty... */
365                 lustre_mark_info_dirty(info);
366         }
367         if (le16_to_cpu(dh->dqdh_entries) + 1 >= LUSTRE_DQSTRINBLK)     /* Block will be full? */
368                 if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) {
369                         printk(KERN_ERR
370                                "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n",
371                                blk);
372                         goto out_buf;
373                 }
374         dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries) + 1);
375         memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
376         /* Find free structure in block */
377         for (i = 0; i < LUSTRE_DQSTRINBLK && 
378              memcmp(&fakedquot, ddquot + i, sizeof(fakedquot)); i++) ;
379
380         if (i == LUSTRE_DQSTRINBLK) {
381                 printk(KERN_ERR
382                        "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
383                 *err = -EIO;
384                 goto out_buf;
385         }
386
387         if ((*err = write_blk(filp, blk, buf)) < 0) {
388                 printk(KERN_ERR
389                        "VFS: find_free_dqentry(): Can't write quota data block %u.\n",
390                        blk);
391                 goto out_buf;
392         }
393         dquot->dq_off =
394             (blk << LUSTRE_DQBLKSIZE_BITS) +
395             sizeof(struct lustre_disk_dqdbheader) +
396             i * sizeof(struct lustre_disk_dqblk);
397         freedqbuf(buf);
398         return blk;
399 out_buf:
400         freedqbuf(buf);
401         return 0;
402 }
403
404 /* Insert reference to structure into the trie */
405 static int do_insert_tree(struct lustre_dquot *dquot, uint * treeblk, int depth)
406 {
407         struct lustre_quota_info *lqi = dquot->dq_info;
408         struct file *filp = lqi->qi_files[dquot->dq_type];
409         struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
410         dqbuf_t buf;
411         int ret = 0, newson = 0, newact = 0;
412         u32 *ref;
413         uint newblk;
414
415         if (!(buf = getdqbuf()))
416                 return -ENOMEM;
417         if (!*treeblk) {
418                 ret = get_free_dqblk(filp, info);
419                 if (ret < 0)
420                         goto out_buf;
421                 *treeblk = ret;
422                 memset(buf, 0, LUSTRE_DQBLKSIZE);
423                 newact = 1;
424         } else {
425                 if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
426                         printk(KERN_ERR
427                                "VFS: Can't read tree quota block %u.\n",
428                                *treeblk);
429                         goto out_buf;
430                 }
431         }
432         ref = (u32 *) buf;
433         newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
434         if (!newblk)
435                 newson = 1;
436         if (depth == LUSTRE_DQTREEDEPTH - 1) {
437
438                 if (newblk) {
439                         printk(KERN_ERR
440                                "VFS: Inserting already present quota entry (block %u).\n",
441                                ref[GETIDINDEX(dquot->dq_id, depth)]);
442                         ret = -EIO;
443                         goto out_buf;
444                 }
445
446                 newblk = find_free_dqentry(dquot, &ret);
447         } else
448                 ret = do_insert_tree(dquot, &newblk, depth + 1);
449         if (newson && ret >= 0) {
450                 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
451                 ret = write_blk(filp, *treeblk, buf);
452         } else if (newact && ret < 0)
453                 put_free_dqblk(filp, info, buf, *treeblk);
454 out_buf:
455         freedqbuf(buf);
456         return ret;
457 }
458
459 /* Wrapper for inserting quota structure into tree */
460 static inline int dq_insert_tree(struct lustre_dquot *dquot)
461 {
462         int tmp = LUSTRE_DQTREEOFF;
463         return do_insert_tree(dquot, &tmp, 0);
464 }
465
466 /*
467  *      We don't have to be afraid of deadlocks as we never have quotas on quota files...
468  */
469 static int lustre_write_dquot(struct lustre_dquot *dquot)
470 {
471         int type = dquot->dq_type;
472         struct file *filp;
473         mm_segment_t fs;
474         loff_t offset;
475         ssize_t ret;
476         struct lustre_disk_dqblk ddquot, empty;
477
478         if (!dquot->dq_off)
479                 if ((ret = dq_insert_tree(dquot)) < 0) {
480                         printk(KERN_ERR
481                                "VFS: Error %Zd occurred while creating quota.\n",
482                                ret);
483                         return ret;
484                 }
485         filp = dquot->dq_info->qi_files[type];
486         offset = dquot->dq_off;
487         mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
488         /* Argh... We may need to write structure full of zeroes but that would be
489          * treated as an empty place by the rest of the code. Format change would
490          * be definitely cleaner but the problems probably are not worth it */
491         memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
492         if (!memcmp(&empty, &ddquot, sizeof(struct lustre_disk_dqblk)))
493                 ddquot.dqb_itime = cpu_to_le64(1);
494         fs = get_fs();
495         set_fs(KERNEL_DS);
496         ret = filp->f_op->write(filp, (char *)&ddquot,
497                                 sizeof(struct lustre_disk_dqblk), &offset);
498         set_fs(fs);
499         if (ret != sizeof(struct lustre_disk_dqblk)) {
500                 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
501                        filp->f_dentry->d_sb->s_id);
502                 if (ret >= 0)
503                         ret = -ENOSPC;
504         } else
505                 ret = 0;
506
507         return ret;
508 }
509
510 /* Free dquot entry in data block */
511 static int free_dqentry(struct lustre_dquot *dquot, uint blk)
512 {
513         struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
514         struct lustre_mem_dqinfo *info =
515             &dquot->dq_info->qi_info[dquot->dq_type];
516         struct lustre_disk_dqdbheader *dh;
517         dqbuf_t buf = getdqbuf();
518         int ret = 0;
519
520         if (!buf)
521                 return -ENOMEM;
522         if (dquot->dq_off >> LUSTRE_DQBLKSIZE_BITS != blk) {
523                 printk(KERN_ERR
524                        "VFS: Quota structure has offset to other block (%u) than it should (%u).\n",
525                        blk, (uint) (dquot->dq_off >> LUSTRE_DQBLKSIZE_BITS));
526                 goto out_buf;
527         }
528         if ((ret = read_blk(filp, blk, buf)) < 0) {
529                 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
530                 goto out_buf;
531         }
532         dh = (struct lustre_disk_dqdbheader *)buf;
533         dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries) - 1);
534         if (!le16_to_cpu(dh->dqdh_entries)) {   /* Block got free? */
535                 if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
536                     (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
537                         printk(KERN_ERR
538                                "VFS: Can't move quota data block (%u) to free list.\n",
539                                blk);
540                         goto out_buf;
541                 }
542         } else {
543                 memset(buf +
544                        (dquot->dq_off & ((1 << LUSTRE_DQBLKSIZE_BITS) - 1)), 0,
545                        sizeof(struct lustre_disk_dqblk));
546                 if (le16_to_cpu(dh->dqdh_entries) == LUSTRE_DQSTRINBLK - 1) {
547                         /* Insert will write block itself */
548                         if ((ret =
549                              insert_free_dqentry(filp, info, buf, blk)) < 0) {
550                                 printk(KERN_ERR
551                                        "VFS: Can't insert quota data block (%u) to free entry list.\n",
552                                        blk);
553                                 goto out_buf;
554                         }
555                 } else if ((ret = write_blk(filp, blk, buf)) < 0) {
556                         printk(KERN_ERR
557                                "VFS: Can't write quota data block %u\n", blk);
558                         goto out_buf;
559                 }
560         }
561         dquot->dq_off = 0;      /* Quota is now unattached */
562 out_buf:
563         freedqbuf(buf);
564         return ret;
565 }
566
567 /* Remove reference to dquot from tree */
568 static int remove_tree(struct lustre_dquot *dquot, uint * blk, int depth)
569 {
570         struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
571         struct lustre_mem_dqinfo *info =
572             &dquot->dq_info->qi_info[dquot->dq_type];
573         dqbuf_t buf = getdqbuf();
574         int ret = 0;
575         uint newblk;
576         u32 *ref = (u32 *) buf;
577
578         if (!buf)
579                 return -ENOMEM;
580         if ((ret = read_blk(filp, *blk, buf)) < 0) {
581                 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
582                 goto out_buf;
583         }
584         newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
585         if (depth == LUSTRE_DQTREEDEPTH - 1) {
586                 ret = free_dqentry(dquot, newblk);
587                 newblk = 0;
588         } else
589                 ret = remove_tree(dquot, &newblk, depth + 1);
590         if (ret >= 0 && !newblk) {
591                 int i;
592                 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
593                 for (i = 0; i < LUSTRE_DQBLKSIZE && !buf[i]; i++) ;     /* Block got empty? */
594                 /* don't put the root block into free blk list! */
595                 if (i == LUSTRE_DQBLKSIZE && *blk != LUSTRE_DQTREEOFF) {
596                         put_free_dqblk(filp, info, buf, *blk);
597                         *blk = 0;
598                 } else if ((ret = write_blk(filp, *blk, buf)) < 0)
599                         printk(KERN_ERR
600                                "VFS: Can't write quota tree block %u.\n", *blk);
601         }
602 out_buf:
603         freedqbuf(buf);
604         return ret;
605 }
606
607 /* Delete dquot from tree */
608 static int lustre_delete_dquot(struct lustre_dquot *dquot)
609 {
610         uint tmp = LUSTRE_DQTREEOFF;
611
612         if (!dquot->dq_off)     /* Even not allocated? */
613                 return 0;
614         return remove_tree(dquot, &tmp, 0);
615 }
616
617 /* Find entry in block */
618 static loff_t find_block_dqentry(struct lustre_dquot *dquot, uint blk)
619 {
620         struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
621         dqbuf_t buf = getdqbuf();
622         loff_t ret = 0;
623         int i;
624         struct lustre_disk_dqblk *ddquot = GETENTRIES(buf);
625
626         if (!buf)
627                 return -ENOMEM;
628         if ((ret = read_blk(filp, blk, buf)) < 0) {
629                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
630                 goto out_buf;
631         }
632         if (dquot->dq_id)
633                 for (i = 0;
634                      i < LUSTRE_DQSTRINBLK
635                      && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++) ;
636         else {                  /* ID 0 as a bit more complicated searching... */
637                 struct lustre_disk_dqblk fakedquot;
638
639                 memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
640                 for (i = 0; i < LUSTRE_DQSTRINBLK; i++)
641                         if (!le32_to_cpu(ddquot[i].dqb_id)
642                             && memcmp(&fakedquot, ddquot + i,
643                                       sizeof(struct lustre_disk_dqblk)))
644                                 break;
645         }
646         if (i == LUSTRE_DQSTRINBLK) {
647                 printk(KERN_ERR
648                        "VFS: Quota for id %u referenced but not present.\n",
649                        dquot->dq_id);
650                 ret = -EIO;
651                 goto out_buf;
652         } else
653                 ret =
654                     (blk << LUSTRE_DQBLKSIZE_BITS) +
655                     sizeof(struct lustre_disk_dqdbheader) +
656                     i * sizeof(struct lustre_disk_dqblk);
657 out_buf:
658         freedqbuf(buf);
659         return ret;
660 }
661
662 /* Find entry for given id in the tree */
663 static loff_t find_tree_dqentry(struct lustre_dquot *dquot, uint blk, int depth)
664 {
665         struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
666         dqbuf_t buf = getdqbuf();
667         loff_t ret = 0;
668         u32 *ref = (u32 *) buf;
669
670         if (!buf)
671                 return -ENOMEM;
672         if ((ret = read_blk(filp, blk, buf)) < 0) {
673                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
674                 goto out_buf;
675         }
676         ret = 0;
677         blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
678         if (!blk)               /* No reference? */
679                 goto out_buf;
680         if (depth < LUSTRE_DQTREEDEPTH - 1)
681                 ret = find_tree_dqentry(dquot, blk, depth + 1);
682         else
683                 ret = find_block_dqentry(dquot, blk);
684 out_buf:
685         freedqbuf(buf);
686         return ret;
687 }
688
689 /* Find entry for given id in the tree - wrapper function */
690 static inline loff_t find_dqentry(struct lustre_dquot *dquot)
691 {
692         return find_tree_dqentry(dquot, LUSTRE_DQTREEOFF, 0);
693 }
694
695 int lustre_read_dquot(struct lustre_dquot *dquot)
696 {
697         int type = dquot->dq_type;
698         struct file *filp;
699         mm_segment_t fs;
700         loff_t offset;
701         struct lustre_disk_dqblk ddquot, empty;
702         int ret = 0;
703
704         /* Invalidated quota? */
705         if (!dquot->dq_info || !(filp = dquot->dq_info->qi_files[type])) {
706                 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
707                 return -EIO;
708         }
709
710         offset = find_dqentry(dquot);
711         if (offset <= 0) {      /* Entry not present? */
712                 if (offset < 0)
713                         printk(KERN_ERR
714                                "VFS: Can't read quota structure for id %u.\n",
715                                dquot->dq_id);
716                 dquot->dq_off = 0;
717                 set_bit(DQ_FAKE_B, &dquot->dq_flags);
718                 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
719                 ret = offset;
720         } else {
721                 dquot->dq_off = offset;
722                 fs = get_fs();
723                 set_fs(KERNEL_DS);
724                 if ((ret = filp->f_op->read(filp, (char *)&ddquot,
725                                             sizeof(struct lustre_disk_dqblk),
726                                             &offset)) !=
727                     sizeof(struct lustre_disk_dqblk)) {
728                         if (ret >= 0)
729                                 ret = -EIO;
730                         printk(KERN_ERR
731                                "VFS: Error while reading quota structure for id %u.\n",
732                                dquot->dq_id);
733                         memset(&ddquot, 0, sizeof(struct lustre_disk_dqblk));
734                 } else {
735                         ret = 0;
736                         /* We need to escape back all-zero structure */
737                         memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
738                         empty.dqb_itime = cpu_to_le64(1);
739                         if (!memcmp(&empty, &ddquot,
740                                     sizeof(struct lustre_disk_dqblk)))
741                                 ddquot.dqb_itime = 0;
742                 }
743                 set_fs(fs);
744                 disk2memdqb(&dquot->dq_dqb, &ddquot);
745         }
746
747         return ret;
748 }
749
750 /* Commit changes of dquot to disk - it might also mean deleting it when quota became fake */
751 int lustre_commit_dquot(struct lustre_dquot *dquot)
752 {
753         int rc = 0;
754         /* always clear the flag so we don't loop on an IO error... */
755         clear_bit(DQ_MOD_B, &dquot->dq_flags);
756
757         /* The block/inode usage in admin quotafile isn't the real usage
758          * over all cluster, so keep the fake dquot entry on disk is
759          * meaningless, just remove it */
760         if (test_bit(DQ_FAKE_B, &dquot->dq_flags))
761                 rc = lustre_delete_dquot(dquot);
762         else
763                 rc = lustre_write_dquot(dquot);
764
765         if (rc < 0)
766                 return rc;
767
768         if (lustre_info_dirty(&dquot->dq_info->qi_info[dquot->dq_type]))
769                 rc = lustre_write_quota_info(dquot->dq_info, dquot->dq_type);
770
771         return rc;
772 }
773
774 /* We need to export this function to initialize quotafile, because we haven't
775  * user level check utility */
776 int lustre_init_quota_info(struct lustre_quota_info *lqi, int type)
777 {
778         struct lustre_mem_dqinfo *dqinfo = &lqi->qi_info[type];
779         struct lustre_disk_dqheader dqhead;
780         struct file *fp = lqi->qi_files[type];
781         ssize_t size;
782         loff_t offset = 0;
783         int rc = 0;
784         static const uint quota_magics[] = LUSTRE_INITQMAGICS;
785         static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
786
787         /* write quotafile header */
788         dqhead.dqh_magic = cpu_to_le32(quota_magics[type]);
789         dqhead.dqh_version = cpu_to_le32(quota_versions[type]);
790         size = fp->f_op->write(fp, (char *)&dqhead,
791                                sizeof(struct lustre_disk_dqheader), &offset);
792
793         if (size != sizeof(struct lustre_disk_dqheader)) {
794                 printk(KERN_ERR "error writing quoafile header (rc:%d)\n", rc);
795                 rc = size;
796         }
797         if (rc)
798                 return rc;
799
800         /* write init quota info */
801         memset(dqinfo, 0, sizeof(*dqinfo));
802         dqinfo->dqi_bgrace = MAX_DQ_TIME;
803         dqinfo->dqi_igrace = MAX_IQ_TIME;
804         dqinfo->dqi_blocks = LUSTRE_DQTREEOFF + 1;
805
806         return lustre_write_quota_info(lqi, type);
807 }
808
809 struct dqblk {
810         struct list_head link;
811         uint blk;
812 };
813
814 static ssize_t quota_read(struct file *file, struct inode *inode, int type,
815                           uint blk, dqbuf_t buf)
816 {
817         if (file) {
818                 return read_blk(file, blk, buf);
819         } else {
820 #ifndef KERNEL_SUPPORTS_QUOTA_READ
821                 return -ENOTSUPP;
822 #else
823                 struct super_block *sb = inode->i_sb;
824                 memset(buf, 0, LUSTRE_DQBLKSIZE);
825                 return sb->s_op->quota_read(sb, type, (char *)buf,
826                                             LUSTRE_DQBLKSIZE, 
827                                             blk << LUSTRE_DQBLKSIZE_BITS);
828 #endif
829         }
830 }
831
832 static int walk_block_dqentry(struct file *filp, struct inode *inode, int type,
833                               uint blk, struct list_head *list)
834 {
835         dqbuf_t buf = getdqbuf();
836         loff_t ret = 0;
837         struct lustre_disk_dqdbheader *dqhead =
838             (struct lustre_disk_dqdbheader *)buf;
839         struct dqblk *blk_item;
840         struct dqblk *pos;
841         struct list_head *tmp;
842
843         if (!buf)
844                 return -ENOMEM;
845         if ((ret = quota_read(filp, inode, type, blk, buf)) < 0) {
846                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
847                 goto out_buf;
848         }
849         ret = 0;
850
851         if (!le32_to_cpu(dqhead->dqdh_entries))
852                 goto out_buf;
853
854         if (list_empty(list)) {
855                 tmp = list;
856                 goto done;
857         }
858
859         list_for_each_entry(pos, list, link) {
860                 if (blk == pos->blk)    /* we got this blk already */
861                         goto out_buf;
862                 if (blk > pos->blk)
863                         continue;
864                 break;
865         }
866         tmp = &pos->link;
867 done:
868         blk_item = kmalloc(sizeof(*blk_item), GFP_NOFS);
869         if (!blk_item) {
870                 ret = -ENOMEM;
871                 goto out_buf;
872         }
873         blk_item->blk = blk;
874         INIT_LIST_HEAD(&blk_item->link);
875
876         list_add_tail(&blk_item->link, tmp);
877
878 out_buf:
879         freedqbuf(buf);
880         return ret;
881 }
882
883 static int walk_tree_dqentry(struct file *filp, struct inode *inode, int type, 
884                              uint blk, int depth, struct list_head *list)
885 {
886         dqbuf_t buf = getdqbuf();
887         loff_t ret = 0;
888         int index;
889         u32 *ref = (u32 *) buf;
890
891         if (!buf)
892                 return -ENOMEM;
893         if ((ret = quota_read(filp, inode, type, blk, buf)) < 0) {
894                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
895                 goto out_buf;
896         }
897         ret = 0;
898
899         for (index = 0; index <= 0xff && !ret; index++) {
900                 blk = le32_to_cpu(ref[index]);
901                 if (!blk)       /* No reference */
902                         continue;
903
904                 if (depth < LUSTRE_DQTREEDEPTH - 1)
905                         ret = walk_tree_dqentry(filp, inode, type, blk, 
906                                                 depth + 1, list);
907                 else
908                         ret = walk_block_dqentry(filp, inode, type, blk, list);
909         }
910 out_buf:
911         freedqbuf(buf);
912         return ret;
913 }
914
915 /* Walk through the quota file (v2 format) to get all ids with quota limit */
916 int lustre_get_qids(struct file *fp, struct inode *inode, int type,
917                     struct list_head *list)
918 {
919         struct list_head blk_list;
920         struct dqblk *blk_item, *tmp;
921         dqbuf_t buf = NULL;
922         struct lustre_disk_dqblk *ddquot;
923         int rc;
924
925         if (!check_quota_file(fp, inode, type)) {
926                 printk(KERN_ERR "unknown quota file format!\n");
927                 return -EINVAL;
928         }
929         if (!list_empty(list)) {
930                 printk(KERN_ERR "not empty list\n");
931                 return -EINVAL;
932         }
933
934         INIT_LIST_HEAD(&blk_list);
935         rc = walk_tree_dqentry(fp, inode, type, LUSTRE_DQTREEOFF, 0, &blk_list);
936         if (rc) {
937                 printk(KERN_ERR "walk through quota file failed!(%d)\n", rc);
938                 goto out_free;
939         }
940         if (list_empty(&blk_list))
941                 return 0;
942
943         buf = getdqbuf();
944         if (!buf)
945                 return -ENOMEM;
946         ddquot = GETENTRIES(buf);
947
948         list_for_each_entry(blk_item, &blk_list, link) {
949                 loff_t ret = 0;
950                 int i;
951                 struct lustre_disk_dqblk fakedquot;
952
953                 memset(buf, 0, LUSTRE_DQBLKSIZE);
954                 if ((ret = quota_read(fp, inode, type, blk_item->blk, buf))<0) {
955                         printk(KERN_ERR
956                                "VFS: Can't read quota tree block %u.\n",
957                                blk_item->blk);
958                         rc = ret;
959                         goto out_free;
960                 }
961
962                 memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
963                 for (i = 0; i < LUSTRE_DQSTRINBLK; i++) {
964                         struct dquot_id *dqid;
965                         /* skip empty entry */
966                         if (!memcmp
967                             (&fakedquot, ddquot + i,
968                              sizeof(struct lustre_disk_dqblk)))
969                                 continue;
970
971                         dqid = kmalloc(sizeof(*dqid), GFP_NOFS);
972                         if (!dqid) {
973                                 rc = -ENOMEM;
974                                 goto out_free;
975                         }
976                         dqid->di_id = le32_to_cpu(ddquot[i].dqb_id);
977                         INIT_LIST_HEAD(&dqid->di_link);
978                         list_add(&dqid->di_link, list);
979                 }
980         }
981
982 out_free:
983         list_for_each_entry_safe(blk_item, tmp, &blk_list, link) {
984                 list_del_init(&blk_item->link);
985                 kfree(blk_item);
986         }
987         if (buf)
988                 freedqbuf(buf);
989         return rc;
990 }
991
992 EXPORT_SYMBOL(lustre_check_quota_file);
993 EXPORT_SYMBOL(lustre_read_quota_info);
994 EXPORT_SYMBOL(lustre_write_quota_info);
995 EXPORT_SYMBOL(lustre_read_dquot);
996 EXPORT_SYMBOL(lustre_commit_dquot);
997 EXPORT_SYMBOL(lustre_init_quota_info);
998 EXPORT_SYMBOL(lustre_get_qids);