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