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