Whamcloud - gitweb
9db3f3fed8a51aeefbc4f48bab5b6fff90278f5d
[fs/lustre-release.git] / lustre / ldiskfs / 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 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
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         filp = dquot->dq_info->qi_files[type];
705
706         if (!filp || !dquot->dq_info) { /* Invalidated quota? */
707                 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
708                 return -EIO;
709         }
710
711         offset = find_dqentry(dquot);
712         if (offset <= 0) {      /* Entry not present? */
713                 if (offset < 0)
714                         printk(KERN_ERR
715                                "VFS: Can't read quota structure for id %u.\n",
716                                dquot->dq_id);
717                 dquot->dq_off = 0;
718                 set_bit(DQ_FAKE_B, &dquot->dq_flags);
719                 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
720                 ret = offset;
721         } else {
722                 dquot->dq_off = offset;
723                 fs = get_fs();
724                 set_fs(KERNEL_DS);
725                 if ((ret = filp->f_op->read(filp, (char *)&ddquot,
726                                             sizeof(struct lustre_disk_dqblk),
727                                             &offset)) !=
728                     sizeof(struct lustre_disk_dqblk)) {
729                         if (ret >= 0)
730                                 ret = -EIO;
731                         printk(KERN_ERR
732                                "VFS: Error while reading quota structure for id %u.\n",
733                                dquot->dq_id);
734                         memset(&ddquot, 0, sizeof(struct lustre_disk_dqblk));
735                 } else {
736                         ret = 0;
737                         /* We need to escape back all-zero structure */
738                         memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
739                         empty.dqb_itime = cpu_to_le64(1);
740                         if (!memcmp(&empty, &ddquot,
741                                     sizeof(struct lustre_disk_dqblk)))
742                                 ddquot.dqb_itime = 0;
743                 }
744                 set_fs(fs);
745                 disk2memdqb(&dquot->dq_dqb, &ddquot);
746         }
747
748         return ret;
749 }
750
751 /* Commit changes of dquot to disk - it might also mean deleting it when quota became fake */
752 int lustre_commit_dquot(struct lustre_dquot *dquot)
753 {
754         int rc = 0;
755         /* always clear the flag so we don't loop on an IO error... */
756         clear_bit(DQ_MOD_B, &dquot->dq_flags);
757
758         /* The block/inode usage in admin quotafile isn't the real usage
759          * over all cluster, so keep the fake dquot entry on disk is
760          * meaningless, just remove it */
761         if (test_bit(DQ_FAKE_B, &dquot->dq_flags))
762                 rc = lustre_delete_dquot(dquot);
763         else
764                 rc = lustre_write_dquot(dquot);
765
766         if (rc < 0)
767                 return rc;
768
769         if (lustre_info_dirty(&dquot->dq_info->qi_info[dquot->dq_type]))
770                 rc = lustre_write_quota_info(dquot->dq_info, dquot->dq_type);
771
772         return rc;
773 }
774
775 /* We need to export this function to initialize quotafile, because we haven't
776  * user level check utility */
777 int lustre_init_quota_info(struct lustre_quota_info *lqi, int type)
778 {
779         struct lustre_mem_dqinfo *dqinfo = &lqi->qi_info[type];
780         struct lustre_disk_dqheader dqhead;
781         struct file *fp = lqi->qi_files[type];
782         ssize_t size;
783         loff_t offset = 0;
784         int rc = 0;
785         static const uint quota_magics[] = LUSTRE_INITQMAGICS;
786         static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
787
788         /* write quotafile header */
789         dqhead.dqh_magic = cpu_to_le32(quota_magics[type]);
790         dqhead.dqh_version = cpu_to_le32(quota_versions[type]);
791         size = fp->f_op->write(fp, (char *)&dqhead,
792                                sizeof(struct lustre_disk_dqheader), &offset);
793
794         if (size != sizeof(struct lustre_disk_dqheader)) {
795                 printk(KERN_ERR "error writing quoafile header (rc:%d)\n", rc);
796                 rc = size;
797         }
798         if (rc)
799                 return rc;
800
801         /* write init quota info */
802         memset(dqinfo, 0, sizeof(*dqinfo));
803         dqinfo->dqi_bgrace = MAX_DQ_TIME;
804         dqinfo->dqi_igrace = MAX_IQ_TIME;
805         dqinfo->dqi_blocks = LUSTRE_DQTREEOFF + 1;
806
807         return lustre_write_quota_info(lqi, type);
808 }
809
810 struct dqblk {
811         struct list_head link;
812         uint blk;
813 };
814
815 static ssize_t quota_read(struct file *file, struct inode *inode, int type,
816                           uint blk, dqbuf_t buf)
817 {
818         if (file) {
819                 return read_blk(file, blk, buf);
820         } else {
821 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,12)
822                 return -ENOTSUPP;
823 #else
824                 struct super_block *sb = inode->i_sb;
825                 memset(buf, 0, LUSTRE_DQBLKSIZE);
826                 return sb->s_op->quota_read(sb, type, (char *)buf,
827                                             LUSTRE_DQBLKSIZE, 
828                                             blk << LUSTRE_DQBLKSIZE_BITS);
829 #endif
830         }
831 }
832
833 static int walk_block_dqentry(struct file *filp, struct inode *inode, int type,
834                               uint blk, struct list_head *list)
835 {
836         dqbuf_t buf = getdqbuf();
837         loff_t ret = 0;
838         struct lustre_disk_dqdbheader *dqhead =
839             (struct lustre_disk_dqdbheader *)buf;
840         struct dqblk *blk_item;
841         struct dqblk *pos;
842         struct list_head *tmp;
843
844         if (!buf)
845                 return -ENOMEM;
846         if ((ret = quota_read(filp, inode, type, blk, buf)) < 0) {
847                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
848                 goto out_buf;
849         }
850         ret = 0;
851
852         if (!le32_to_cpu(dqhead->dqdh_entries))
853                 goto out_buf;
854
855         if (list_empty(list)) {
856                 tmp = list;
857                 goto done;
858         }
859
860         list_for_each_entry(pos, list, link) {
861                 if (blk == pos->blk)    /* we got this blk already */
862                         goto out_buf;
863                 if (blk > pos->blk)
864                         continue;
865                 break;
866         }
867         tmp = &pos->link;
868 done:
869         blk_item = kmalloc(sizeof(*blk_item), GFP_NOFS);
870         if (!blk_item) {
871                 ret = -ENOMEM;
872                 goto out_buf;
873         }
874         blk_item->blk = blk;
875         INIT_LIST_HEAD(&blk_item->link);
876
877         list_add_tail(&blk_item->link, tmp);
878
879 out_buf:
880         freedqbuf(buf);
881         return ret;
882 }
883
884 static int walk_tree_dqentry(struct file *filp, struct inode *inode, int type, 
885                              uint blk, int depth, struct list_head *list)
886 {
887         dqbuf_t buf = getdqbuf();
888         loff_t ret = 0;
889         int index;
890         u32 *ref = (u32 *) buf;
891
892         if (!buf)
893                 return -ENOMEM;
894         if ((ret = quota_read(filp, inode, type, blk, buf)) < 0) {
895                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
896                 goto out_buf;
897         }
898         ret = 0;
899
900         for (index = 0; index <= 0xff && !ret; index++) {
901                 blk = le32_to_cpu(ref[index]);
902                 if (!blk)       /* No reference */
903                         continue;
904
905                 if (depth < LUSTRE_DQTREEDEPTH - 1)
906                         ret = walk_tree_dqentry(filp, inode, type, blk, 
907                                                 depth + 1, list);
908                 else
909                         ret = walk_block_dqentry(filp, inode, type, blk, list);
910         }
911 out_buf:
912         freedqbuf(buf);
913         return ret;
914 }
915
916 /* Walk through the quota file (v2 format) to get all ids with quota limit */
917 int lustre_get_qids(struct file *fp, struct inode *inode, int type,
918                     struct list_head *list)
919 {
920         struct list_head blk_list;
921         struct dqblk *blk_item, *tmp;
922         dqbuf_t buf = NULL;
923         struct lustre_disk_dqblk *ddquot;
924         int rc;
925
926         if (!check_quota_file(fp, inode, type)) {
927                 printk(KERN_ERR "unknown quota file format!\n");
928                 return -EINVAL;
929         }
930         if (!list_empty(list)) {
931                 printk(KERN_ERR "not empty list\n");
932                 return -EINVAL;
933         }
934
935         INIT_LIST_HEAD(&blk_list);
936         rc = walk_tree_dqentry(fp, inode, type, LUSTRE_DQTREEOFF, 0, &blk_list);
937         if (rc) {
938                 printk(KERN_ERR "walk through quota file failed!(%d)\n", rc);
939                 goto out_free;
940         }
941         if (list_empty(&blk_list))
942                 return 0;
943
944         buf = getdqbuf();
945         if (!buf)
946                 return -ENOMEM;
947         ddquot = GETENTRIES(buf);
948
949         list_for_each_entry(blk_item, &blk_list, link) {
950                 loff_t ret = 0;
951                 int i;
952                 struct lustre_disk_dqblk fakedquot;
953
954                 memset(buf, 0, LUSTRE_DQBLKSIZE);
955                 if ((ret = quota_read(fp, inode, type, blk_item->blk, buf))<0) {
956                         printk(KERN_ERR
957                                "VFS: Can't read quota tree block %u.\n",
958                                blk_item->blk);
959                         rc = ret;
960                         goto out_free;
961                 }
962
963                 memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
964                 for (i = 0; i < LUSTRE_DQSTRINBLK; i++) {
965                         struct dquot_id *dqid;
966                         /* skip empty entry */
967                         if (!memcmp
968                             (&fakedquot, ddquot + i,
969                              sizeof(struct lustre_disk_dqblk)))
970                                 continue;
971
972                         dqid = kmalloc(sizeof(*dqid), GFP_NOFS);
973                         if (!dqid) {
974                                 rc = -ENOMEM;
975                                 goto out_free;
976                         }
977                         dqid->di_id = le32_to_cpu(ddquot[i].dqb_id);
978                         INIT_LIST_HEAD(&dqid->di_link);
979                         list_add(&dqid->di_link, list);
980                 }
981         }
982
983 out_free:
984         list_for_each_entry_safe(blk_item, tmp, &blk_list, link) {
985                 list_del_init(&blk_item->link);
986                 kfree(blk_item);
987         }
988         if (buf)
989                 freedqbuf(buf);
990         return rc;
991 }
992
993 EXPORT_SYMBOL(lustre_check_quota_file);
994 EXPORT_SYMBOL(lustre_read_quota_info);
995 EXPORT_SYMBOL(lustre_write_quota_info);
996 EXPORT_SYMBOL(lustre_read_dquot);
997 EXPORT_SYMBOL(lustre_commit_dquot);
998 EXPORT_SYMBOL(lustre_init_quota_info);
999 EXPORT_SYMBOL(lustre_get_qids);