Whamcloud - gitweb
Branch b1_4
[fs/lustre-release.git] / lustre / ldiskfs / lustre_quota_fmt.c
1 /*
2  * Lustre administrative quota format.
3  *
4  *  from
5  *  linux/fs/quota_v2.c
6  */
7
8
9 #ifndef EXPORT_SYMTAB
10 # define EXPORT_SYMTAB
11 #endif
12
13 #include <linux/errno.h>
14 #include <linux/fs.h>
15 #include <linux/mount.h>
16 #include <linux/kernel.h>
17 #include <linux/init.h>
18 #include <linux/module.h>
19 #include <linux/slab.h>
20 #include <linux/quotaio_v1.h>
21
22 #include <asm/byteorder.h>
23 #include <asm/uaccess.h>
24
25 #include <linux/lustre_quota.h>
26 #include "lustre_quota_fmt.h"
27
28 typedef char *dqbuf_t;
29
30 #define GETIDINDEX(id, depth) (((id) >> ((LUSTRE_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
31 #define GETENTRIES(buf) ((struct lustre_disk_dqblk *)(((char *)buf)+sizeof(struct lustre_disk_dqdbheader)))
32
33 /* Check whether given file is really lustre admin quotafile */
34 int lustre_check_quota_file(struct lustre_quota_info *lqi, int type)
35 {
36         struct lustre_disk_dqheader dqhead;
37         struct file *f = lqi->qi_files[type];
38         mm_segment_t fs;
39         ssize_t size;
40         loff_t offset = 0;
41         static const uint quota_magics[] = LUSTRE_INITQMAGICS;
42         static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
43  
44         fs = get_fs();
45         set_fs(KERNEL_DS);
46         size = f->f_op->read(f, (char *)&dqhead, sizeof(struct lustre_disk_dqheader), &offset);
47         set_fs(fs);
48         if (size != sizeof(struct lustre_disk_dqheader))
49                 return 0;
50         if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
51             le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
52                 return 0;
53         return 1;
54 }
55
56 /* Read information header from quota file */
57 int lustre_read_quota_info(struct lustre_quota_info *lqi, int type)
58 {
59         mm_segment_t fs;
60         struct lustre_disk_dqinfo dinfo;
61         struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
62         struct file *f = lqi->qi_files[type];
63         ssize_t size;
64         loff_t offset = LUSTRE_DQINFOOFF;
65
66         fs = get_fs();
67         set_fs(KERNEL_DS);
68         size = f->f_op->read(f, (char *)&dinfo, sizeof(struct lustre_disk_dqinfo), &offset);
69         set_fs(fs);
70         if (size != sizeof(struct lustre_disk_dqinfo)) {
71                 printk(KERN_WARNING "Can't read info structure on device %s.\n",
72                         f->f_vfsmnt->mnt_sb->s_id);
73                 return -1;
74         }
75         info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
76         info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
77         info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
78         info->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
79         info->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
80         info->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
81         return 0;
82 }
83
84 /* Write information header to quota file */
85 int lustre_write_quota_info(struct lustre_quota_info *lqi, int type)
86 {
87         mm_segment_t fs;
88         struct lustre_disk_dqinfo dinfo;
89         struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
90         struct file *f = lqi->qi_files[type];
91         ssize_t size;
92         loff_t offset = LUSTRE_DQINFOOFF;
93
94         info->dqi_flags &= ~DQF_INFO_DIRTY;
95         dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
96         dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
97         dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
98         dinfo.dqi_blocks = cpu_to_le32(info->dqi_blocks);
99         dinfo.dqi_free_blk = cpu_to_le32(info->dqi_free_blk);
100         dinfo.dqi_free_entry = cpu_to_le32(info->dqi_free_entry);
101         fs = get_fs();
102         set_fs(KERNEL_DS);
103         size = f->f_op->write(f, (char *)&dinfo, sizeof(struct lustre_disk_dqinfo), &offset);
104         set_fs(fs);
105         if (size != sizeof(struct lustre_disk_dqinfo)) {
106                 printk(KERN_WARNING "Can't write info structure on device %s.\n",
107                         f->f_vfsmnt->mnt_sb->s_id);
108                 return -1;
109         }
110         return 0;
111 }
112
113 static void disk2memdqb(struct mem_dqblk *m, struct lustre_disk_dqblk *d)
114 {
115         m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
116         m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
117         m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
118         m->dqb_itime = le64_to_cpu(d->dqb_itime);
119         m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
120         m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
121         m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
122         m->dqb_btime = le64_to_cpu(d->dqb_btime);
123 }
124
125 static void mem2diskdqb(struct lustre_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
126 {
127         d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
128         d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
129         d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
130         d->dqb_itime = cpu_to_le64(m->dqb_itime);
131         d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
132         d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
133         d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
134         d->dqb_btime = cpu_to_le64(m->dqb_btime);
135         d->dqb_id = cpu_to_le32(id);
136 }
137
138 static dqbuf_t getdqbuf(void)
139 {
140         dqbuf_t buf = kmalloc(LUSTRE_DQBLKSIZE, GFP_NOFS);
141         if (!buf)
142                 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
143         return buf;
144 }
145
146 static inline void freedqbuf(dqbuf_t buf)
147 {
148         kfree(buf);
149 }
150
151 static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
152 {
153         mm_segment_t fs;
154         ssize_t ret;
155         loff_t offset = blk<<LUSTRE_DQBLKSIZE_BITS;
156
157         memset(buf, 0, LUSTRE_DQBLKSIZE);
158         fs = get_fs();
159         set_fs(KERNEL_DS);
160         ret = filp->f_op->read(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
161         set_fs(fs);
162         return ret;
163 }
164
165 static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
166 {
167         mm_segment_t fs;
168         ssize_t ret;
169         loff_t offset = blk<<LUSTRE_DQBLKSIZE_BITS;
170
171         fs = get_fs();
172         set_fs(KERNEL_DS);
173         ret = filp->f_op->write(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
174         set_fs(fs);
175         return ret;
176
177 }
178
179 static void lustre_mark_info_dirty(struct lustre_mem_dqinfo *info)
180 {
181         set_bit(DQF_INFO_DIRTY_B, &info->dqi_flags);
182 }
183
184 #define lustre_info_dirty(info) test_bit(DQF_INFO_DIRTY_B, &(info)->dqi_flags)
185
186 /* Remove empty block from list and return it */
187 static int get_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info)
188 {
189         dqbuf_t buf = getdqbuf();
190         struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
191         int ret, blk;
192
193         if (!buf)
194                 return -ENOMEM;
195         if (info->dqi_free_blk) {
196                 blk = info->dqi_free_blk;
197                 if ((ret = read_blk(filp, blk, buf)) < 0)
198                         goto out_buf;
199                 info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
200         }
201         else {
202                 memset(buf, 0, LUSTRE_DQBLKSIZE);
203                 if ((ret = write_blk(filp, info->dqi_blocks, buf)) < 0) /* Assure block allocation... */
204                         goto out_buf;
205                 blk = info->dqi_blocks++;
206         }
207         lustre_mark_info_dirty(info);
208         ret = blk;
209 out_buf:
210         freedqbuf(buf);
211         return ret;
212 }
213
214 /* Insert empty block to the list */
215 static int put_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info, 
216                           dqbuf_t buf, uint blk)
217 {
218         struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
219         int err;
220
221         dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
222         dh->dqdh_prev_free = cpu_to_le32(0);
223         dh->dqdh_entries = cpu_to_le16(0);
224         info->dqi_free_blk = blk;
225         lustre_mark_info_dirty(info);
226         if ((err = write_blk(filp, blk, buf)) < 0)      /* Some strange block. We had better leave it... */
227                 return err;
228         return 0;
229 }
230
231 /* Remove given block from the list of blocks with free entries */
232 static int remove_free_dqentry(struct file *filp, struct lustre_mem_dqinfo *info, dqbuf_t buf, uint blk)
233 {
234         dqbuf_t tmpbuf = getdqbuf();
235         struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
236         uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
237         int err;
238
239         if (!tmpbuf)
240                 return -ENOMEM;
241         if (nextblk) {
242                 if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
243                         goto out_buf;
244                 ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
245                 if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
246                         goto out_buf;
247         }
248         if (prevblk) {
249                 if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
250                         goto out_buf;
251                 ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
252                 if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
253                         goto out_buf;
254         }
255         else {
256                 info->dqi_free_entry = nextblk;
257                 lustre_mark_info_dirty(info);
258         }
259         freedqbuf(tmpbuf);
260         dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
261         if (write_blk(filp, blk, buf) < 0)      /* No matter whether write succeeds block is out of list */
262                 printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
263         return 0;
264 out_buf:
265         freedqbuf(tmpbuf);
266         return err;
267 }
268
269 /* Insert given block to the beginning of list with free entries */
270 static int insert_free_dqentry(struct file *filp, struct lustre_mem_dqinfo *info, dqbuf_t buf, uint blk)
271 {
272         dqbuf_t tmpbuf = getdqbuf();
273         struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
274         int err;
275
276         if (!tmpbuf)
277                 return -ENOMEM;
278         dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
279         dh->dqdh_prev_free = cpu_to_le32(0);
280         if ((err = write_blk(filp, blk, buf)) < 0)
281                 goto out_buf;
282         if (info->dqi_free_entry) {
283                 if ((err = read_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
284                         goto out_buf;
285                 ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
286                 if ((err = write_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
287                         goto out_buf;
288         }
289         freedqbuf(tmpbuf);
290         info->dqi_free_entry = blk;
291         lustre_mark_info_dirty(info);
292         return 0;
293 out_buf:
294         freedqbuf(tmpbuf);
295         return err;
296 }
297
298 /* Find space for dquot */
299 static uint find_free_dqentry(struct lustre_dquot *dquot, int *err)
300 {
301         struct lustre_quota_info *lqi = dquot->dq_info;
302         struct file *filp = lqi->qi_files[dquot->dq_type];
303         struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
304         uint blk, i;
305         struct lustre_disk_dqdbheader *dh;
306         struct lustre_disk_dqblk *ddquot;
307         struct lustre_disk_dqblk fakedquot;
308         dqbuf_t buf;
309
310         *err = 0;
311         if (!(buf = getdqbuf())) {
312                 *err = -ENOMEM;
313                 return 0;
314         }
315         dh = (struct lustre_disk_dqdbheader *)buf;
316         ddquot = GETENTRIES(buf);
317         if (info->dqi_free_entry) {
318                 blk = info->dqi_free_entry;
319                 if ((*err = read_blk(filp, blk, buf)) < 0)
320                         goto out_buf;
321         }
322         else {
323                 blk = get_free_dqblk(filp, info);
324                 if ((int)blk < 0) {
325                         *err = blk;
326                         freedqbuf(buf);
327                         return 0;
328                 }
329                 memset(buf, 0, LUSTRE_DQBLKSIZE);
330                 info->dqi_free_entry = blk;     /* This is enough as block is already zeroed and entry list is empty... */
331                 lustre_mark_info_dirty(info);
332         }
333         if (le16_to_cpu(dh->dqdh_entries)+1 >= LUSTRE_DQSTRINBLK)       /* Block will be full? */
334                 if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) {
335                         printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
336                         goto out_buf;
337                 }
338         dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
339         memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
340         /* Find free structure in block */
341         for (i = 0; i < LUSTRE_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct lustre_disk_dqblk)); i++);
342         
343         if (i == LUSTRE_DQSTRINBLK) {
344                 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
345                 *err = -EIO;
346                 goto out_buf;
347         }
348         
349         if ((*err = write_blk(filp, blk, buf)) < 0) {
350                 printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
351                 goto out_buf;
352         }
353         dquot->dq_off = (blk<<LUSTRE_DQBLKSIZE_BITS)+sizeof(struct lustre_disk_dqdbheader)+i*sizeof(struct lustre_disk_dqblk);
354         freedqbuf(buf);
355         return blk;
356 out_buf:
357         freedqbuf(buf);
358         return 0;
359 }
360
361 /* Insert reference to structure into the trie */
362 static int do_insert_tree(struct lustre_dquot *dquot, uint *treeblk, int depth)
363 {
364         struct lustre_quota_info *lqi = dquot->dq_info;
365         struct file *filp = lqi->qi_files[dquot->dq_type];
366         struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
367         dqbuf_t buf;
368         int ret = 0, newson = 0, newact = 0;
369         u32 *ref;
370         uint newblk;
371
372         if (!(buf = getdqbuf()))
373                 return -ENOMEM;
374         if (!*treeblk) {
375                 ret = get_free_dqblk(filp, info);
376                 if (ret < 0)
377                         goto out_buf;
378                 *treeblk = ret;
379                 memset(buf, 0, LUSTRE_DQBLKSIZE);
380                 newact = 1;
381         }
382         else {
383                 if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
384                         printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
385                         goto out_buf;
386                 }
387         }
388         ref = (u32 *)buf;
389         newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
390         if (!newblk)
391                 newson = 1;
392         if (depth == LUSTRE_DQTREEDEPTH-1) {
393                 
394                 if (newblk) {
395                         printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", ref[GETIDINDEX(dquot->dq_id, depth)]);
396                         ret = -EIO;
397                         goto out_buf;
398                 }
399                 
400                 newblk = find_free_dqentry(dquot, &ret);
401         }
402         else
403                 ret = do_insert_tree(dquot, &newblk, depth+1);
404         if (newson && ret >= 0) {
405                 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
406                 ret = write_blk(filp, *treeblk, buf);
407         }
408         else if (newact && ret < 0)
409                 put_free_dqblk(filp, info, buf, *treeblk);
410 out_buf:
411         freedqbuf(buf);
412         return ret;
413 }
414
415 /* Wrapper for inserting quota structure into tree */
416 static inline int dq_insert_tree(struct lustre_dquot *dquot)
417 {
418         int tmp = LUSTRE_DQTREEOFF;
419         return do_insert_tree(dquot, &tmp, 0);
420 }
421
422 /*
423  *      We don't have to be afraid of deadlocks as we never have quotas on quota files...
424  */
425 static int lustre_write_dquot(struct lustre_dquot *dquot)
426 {
427         int type = dquot->dq_type;
428         struct file *filp;
429         mm_segment_t fs;
430         loff_t offset;
431         ssize_t ret;
432         struct lustre_disk_dqblk ddquot, empty;
433
434         if (!dquot->dq_off)
435                 if ((ret = dq_insert_tree(dquot)) < 0) {
436                         printk(KERN_ERR "VFS: Error %Zd occurred while creating quota.\n", ret);
437                         return ret;
438                 }
439         filp = dquot->dq_info->qi_files[type];
440         offset = dquot->dq_off;
441         mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
442         /* Argh... We may need to write structure full of zeroes but that would be
443          * treated as an empty place by the rest of the code. Format change would
444          * be definitely cleaner but the problems probably are not worth it */
445         memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
446         if (!memcmp(&empty, &ddquot, sizeof(struct lustre_disk_dqblk)))
447                 ddquot.dqb_itime = cpu_to_le64(1);
448         fs = get_fs();
449         set_fs(KERNEL_DS);
450         ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct lustre_disk_dqblk), &offset);
451         set_fs(fs);
452         if (ret != sizeof(struct lustre_disk_dqblk)) {
453                 printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", filp->f_dentry->d_sb->s_id);
454                 if (ret >= 0)
455                         ret = -ENOSPC;
456         }
457         else
458                 ret = 0;
459
460         return ret;
461 }
462
463 /* Free dquot entry in data block */
464 static int free_dqentry(struct lustre_dquot *dquot, uint blk)
465 {
466         struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
467         struct lustre_mem_dqinfo *info = &dquot->dq_info->qi_info[dquot->dq_type];
468         struct lustre_disk_dqdbheader *dh;
469         dqbuf_t buf = getdqbuf();
470         int ret = 0;
471
472         if (!buf)
473                 return -ENOMEM;
474         if (dquot->dq_off >> LUSTRE_DQBLKSIZE_BITS != blk) {
475                 printk(KERN_ERR "VFS: Quota structure has offset to other block (%u) than it should (%u).\n", blk, (uint)(dquot->dq_off >> LUSTRE_DQBLKSIZE_BITS));
476                 goto out_buf;
477         }
478         if ((ret = read_blk(filp, blk, buf)) < 0) {
479                 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
480                 goto out_buf;
481         }
482         dh = (struct lustre_disk_dqdbheader *)buf;
483         dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
484         if (!le16_to_cpu(dh->dqdh_entries)) {   /* Block got free? */
485                 if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
486                     (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
487                         printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
488                         goto out_buf;
489                 }
490         }
491         else {
492                 memset(buf+(dquot->dq_off & ((1 << LUSTRE_DQBLKSIZE_BITS)-1)), 0, sizeof(struct lustre_disk_dqblk));
493                 if (le16_to_cpu(dh->dqdh_entries) == LUSTRE_DQSTRINBLK-1) {
494                         /* Insert will write block itself */
495                         if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) {
496                                 printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
497                                 goto out_buf;
498                         }
499                 }
500                 else
501                         if ((ret = write_blk(filp, blk, buf)) < 0) {
502                                 printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);
503                                 goto out_buf;
504                         }
505         }
506         dquot->dq_off = 0;      /* Quota is now unattached */
507 out_buf:
508         freedqbuf(buf);
509         return ret;
510 }
511
512 /* Remove reference to dquot from tree */
513 static int remove_tree(struct lustre_dquot *dquot, uint *blk, int depth)
514 {
515         struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
516         struct lustre_mem_dqinfo *info = &dquot->dq_info->qi_info[dquot->dq_type];
517         dqbuf_t buf = getdqbuf();
518         int ret = 0;
519         uint newblk;
520         u32 *ref = (u32 *)buf;
521         
522         if (!buf)
523                 return -ENOMEM;
524         if ((ret = read_blk(filp, *blk, buf)) < 0) {
525                 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
526                 goto out_buf;
527         }
528         newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
529         if (depth == LUSTRE_DQTREEDEPTH-1) {
530                 ret = free_dqentry(dquot, newblk);
531                 newblk = 0;
532         }
533         else
534                 ret = remove_tree(dquot, &newblk, depth+1);
535         if (ret >= 0 && !newblk) {
536                 int i;
537                 ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
538                 for (i = 0; i < LUSTRE_DQBLKSIZE && !buf[i]; i++);      /* Block got empty? */
539                 /* don't put the root block into free blk list! */
540                 if (i == LUSTRE_DQBLKSIZE && *blk != LUSTRE_DQTREEOFF) {
541                         put_free_dqblk(filp, info, buf, *blk);
542                         *blk = 0;
543                 }
544                 else
545                         if ((ret = write_blk(filp, *blk, buf)) < 0)
546                                 printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);
547         }
548 out_buf:
549         freedqbuf(buf);
550         return ret;     
551 }
552
553 /* Delete dquot from tree */
554 #ifndef QFMT_NO_DELETE
555 static int lustre_delete_dquot(struct lustre_dquot *dquot)
556 {
557         uint tmp = LUSTRE_DQTREEOFF;
558
559         if (!dquot->dq_off)     /* Even not allocated? */
560                 return 0;
561         return remove_tree(dquot, &tmp, 0);
562 }
563 #endif
564
565 /* Find entry in block */
566 static loff_t find_block_dqentry(struct lustre_dquot *dquot, uint blk)
567 {
568         struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
569         dqbuf_t buf = getdqbuf();
570         loff_t ret = 0;
571         int i;
572         struct lustre_disk_dqblk *ddquot = GETENTRIES(buf);
573
574         if (!buf)
575                 return -ENOMEM;
576         if ((ret = read_blk(filp, blk, buf)) < 0) {
577                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
578                 goto out_buf;
579         }
580         if (dquot->dq_id)
581                 for (i = 0; i < LUSTRE_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
582         else {  /* ID 0 as a bit more complicated searching... */
583                 struct lustre_disk_dqblk fakedquot;
584
585                 memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
586                 for (i = 0; i < LUSTRE_DQSTRINBLK; i++)
587                         if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct lustre_disk_dqblk)))
588                                 break;
589         }
590         if (i == LUSTRE_DQSTRINBLK) {
591                 printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id);
592                 ret = -EIO;
593                 goto out_buf;
594         }
595         else
596                 ret = (blk << LUSTRE_DQBLKSIZE_BITS) + sizeof(struct lustre_disk_dqdbheader) + i * sizeof(struct lustre_disk_dqblk);
597 out_buf:
598         freedqbuf(buf);
599         return ret;
600 }
601
602 /* Find entry for given id in the tree */
603 static loff_t find_tree_dqentry(struct lustre_dquot *dquot, uint blk, int depth)
604 {
605         struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
606         dqbuf_t buf = getdqbuf();
607         loff_t ret = 0;
608         u32 *ref = (u32 *)buf;
609
610         if (!buf)
611                 return -ENOMEM;
612         if ((ret = read_blk(filp, blk, buf)) < 0) {
613                 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
614                 goto out_buf;
615         }
616         ret = 0;
617         blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
618         if (!blk)       /* No reference? */
619                 goto out_buf;
620         if (depth < LUSTRE_DQTREEDEPTH-1)
621                 ret = find_tree_dqentry(dquot, blk, depth+1);
622         else
623                 ret = find_block_dqentry(dquot, blk);
624 out_buf:
625         freedqbuf(buf);
626         return ret;
627 }
628
629 /* Find entry for given id in the tree - wrapper function */
630 static inline loff_t find_dqentry(struct lustre_dquot *dquot)
631 {
632         return find_tree_dqentry(dquot, LUSTRE_DQTREEOFF, 0);
633 }
634
635 int lustre_read_dquot(struct lustre_dquot *dquot)
636 {
637         int type = dquot->dq_type;
638         struct file *filp;
639         mm_segment_t fs;
640         loff_t offset;
641         struct lustre_disk_dqblk ddquot, empty;
642         int ret = 0;
643
644         filp = dquot->dq_info->qi_files[type];
645
646         if (!filp || !dquot->dq_info) { /* Invalidated quota? */
647                 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
648                 return -EIO;
649         }
650         
651         offset = find_dqentry(dquot);
652         if (offset <= 0) {      /* Entry not present? */
653                 if (offset < 0)
654                         printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
655                 dquot->dq_off = 0;
656                 set_bit(DQ_FAKE_B, &dquot->dq_flags);
657                 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
658                 ret = offset;
659         }
660         else {
661                 dquot->dq_off = offset;
662                 fs = get_fs();
663                 set_fs(KERNEL_DS);
664                 if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct lustre_disk_dqblk), &offset)) != sizeof(struct lustre_disk_dqblk)) {
665                         if (ret >= 0)
666                                 ret = -EIO;
667                         printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id);
668                         memset(&ddquot, 0, sizeof(struct lustre_disk_dqblk));
669                 }
670                 else {
671                         ret = 0;
672                         /* We need to escape back all-zero structure */
673                         memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
674                         empty.dqb_itime = cpu_to_le64(1);
675                         if (!memcmp(&empty, &ddquot,
676                                     sizeof(struct lustre_disk_dqblk)))
677                                 ddquot.dqb_itime = 0;
678                 }
679                 set_fs(fs);
680                 disk2memdqb(&dquot->dq_dqb, &ddquot);
681         }
682
683         return ret;
684 }
685
686 /* Commit changes of dquot to disk - it might also mean deleting it when quota became fake */
687 int lustre_commit_dquot(struct lustre_dquot *dquot)
688 {
689         int rc = 0;
690         /* always clear the flag so we don't loop on an IO error... */
691         clear_bit(DQ_MOD_B, &dquot->dq_flags);
692
693         /* The block/inode usage in admin quotafile isn't the real usage
694          * over all cluster, so keep the fake dquot entry on disk is
695          * meaningless, just remove it */
696         if (test_bit(DQ_FAKE_B, &dquot->dq_flags))
697                 rc = lustre_delete_dquot(dquot);
698         else
699                 rc = lustre_write_dquot(dquot);
700         if (rc < 0)
701                 return rc;
702
703         if (lustre_info_dirty(&dquot->dq_info->qi_info[dquot->dq_type]))
704                 rc = lustre_write_quota_info(dquot->dq_info, dquot->dq_type);
705
706         return rc;
707 }
708
709 /* We need to export this function to initialize quotafile, because we haven't
710  * user level check utility */
711 int lustre_init_quota_info(struct lustre_quota_info *lqi, int type)
712 {
713         struct lustre_mem_dqinfo *dqinfo = &lqi->qi_info[type];
714         struct lustre_disk_dqheader dqhead;
715         struct file *fp = lqi->qi_files[type];
716         ssize_t size;
717         loff_t offset = 0;
718         int rc = 0;
719         static const uint quota_magics[] = LUSTRE_INITQMAGICS;
720         static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
721
722         /* write quotafile header */
723         dqhead.dqh_magic = cpu_to_le32(quota_magics[type]);
724         dqhead.dqh_version = cpu_to_le32(quota_versions[type]);
725         size = fp->f_op->write(fp, (char *)&dqhead, 
726                                sizeof(struct lustre_disk_dqheader), &offset);
727         
728         if (size != sizeof(struct lustre_disk_dqheader)) {
729                 printk(KERN_ERR "error writing quoafile header (rc:%d)\n", rc);
730                 rc = size;
731         }
732         if (rc)
733                 return rc;
734
735         /* write init quota info */
736         memset(dqinfo, 0, sizeof(*dqinfo));
737         dqinfo->dqi_bgrace = MAX_DQ_TIME;
738         dqinfo->dqi_igrace = MAX_IQ_TIME;
739         dqinfo->dqi_blocks = LUSTRE_DQTREEOFF + 1;
740
741         return lustre_write_quota_info(lqi, type);
742 }
743
744 EXPORT_SYMBOL(lustre_check_quota_file);
745 EXPORT_SYMBOL(lustre_read_quota_info);
746 EXPORT_SYMBOL(lustre_write_quota_info);
747 EXPORT_SYMBOL(lustre_read_dquot);
748 EXPORT_SYMBOL(lustre_commit_dquot);
749 EXPORT_SYMBOL(lustre_init_quota_info);