2 * Lustre administrative quota format.
10 # define EXPORT_SYMTAB
13 #include <linux/errno.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>
22 #include <asm/byteorder.h>
23 #include <asm/uaccess.h>
25 #include <linux/lustre_quota.h>
26 #include "lustre_quota_fmt.h"
28 typedef char *dqbuf_t;
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)))
33 /* Check whether given file is really lustre admin quotafile */
34 int lustre_check_quota_file(struct lustre_quota_info *lqi, int type)
36 struct lustre_disk_dqheader dqhead;
37 struct file *f = lqi->qi_files[type];
41 static const uint quota_magics[] = LUSTRE_INITQMAGICS;
42 static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
46 size = f->f_op->read(f, (char *)&dqhead, sizeof(struct lustre_disk_dqheader), &offset);
48 if (size != sizeof(struct lustre_disk_dqheader))
50 if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
51 le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
56 /* Read information header from quota file */
57 int lustre_read_quota_info(struct lustre_quota_info *lqi, int type)
60 struct lustre_disk_dqinfo dinfo;
61 struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
62 struct file *f = lqi->qi_files[type];
64 loff_t offset = LUSTRE_DQINFOOFF;
68 size = f->f_op->read(f, (char *)&dinfo, sizeof(struct lustre_disk_dqinfo), &offset);
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);
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);
84 /* Write information header to quota file */
85 int lustre_write_quota_info(struct lustre_quota_info *lqi, int type)
88 struct lustre_disk_dqinfo dinfo;
89 struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
90 struct file *f = lqi->qi_files[type];
92 loff_t offset = LUSTRE_DQINFOOFF;
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);
103 size = f->f_op->write(f, (char *)&dinfo, sizeof(struct lustre_disk_dqinfo), &offset);
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);
113 static void disk2memdqb(struct mem_dqblk *m, struct lustre_disk_dqblk *d)
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);
125 static void mem2diskdqb(struct lustre_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
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);
138 static dqbuf_t getdqbuf(void)
140 dqbuf_t buf = kmalloc(LUSTRE_DQBLKSIZE, GFP_NOFS);
142 printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
146 static inline void freedqbuf(dqbuf_t buf)
151 static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
155 loff_t offset = blk<<LUSTRE_DQBLKSIZE_BITS;
157 memset(buf, 0, LUSTRE_DQBLKSIZE);
160 ret = filp->f_op->read(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
165 static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
169 loff_t offset = blk<<LUSTRE_DQBLKSIZE_BITS;
173 ret = filp->f_op->write(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
179 static void lustre_mark_info_dirty(struct lustre_mem_dqinfo *info)
181 set_bit(DQF_INFO_DIRTY_B, &info->dqi_flags);
184 #define lustre_info_dirty(info) test_bit(DQF_INFO_DIRTY_B, &(info)->dqi_flags)
186 /* Remove empty block from list and return it */
187 static int get_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info)
189 dqbuf_t buf = getdqbuf();
190 struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
195 if (info->dqi_free_blk) {
196 blk = info->dqi_free_blk;
197 if ((ret = read_blk(filp, blk, buf)) < 0)
199 info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
202 memset(buf, 0, LUSTRE_DQBLKSIZE);
203 if ((ret = write_blk(filp, info->dqi_blocks, buf)) < 0) /* Assure block allocation... */
205 blk = info->dqi_blocks++;
207 lustre_mark_info_dirty(info);
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)
218 struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
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... */
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)
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);
242 if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
244 ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
245 if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
249 if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
251 ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
252 if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
256 info->dqi_free_entry = nextblk;
257 lustre_mark_info_dirty(info);
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);
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)
272 dqbuf_t tmpbuf = getdqbuf();
273 struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
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)
282 if (info->dqi_free_entry) {
283 if ((err = read_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
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)
290 info->dqi_free_entry = blk;
291 lustre_mark_info_dirty(info);
298 /* Find space for dquot */
299 static uint find_free_dqentry(struct lustre_dquot *dquot, int *err)
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];
305 struct lustre_disk_dqdbheader *dh;
306 struct lustre_disk_dqblk *ddquot;
307 struct lustre_disk_dqblk fakedquot;
311 if (!(buf = getdqbuf())) {
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)
323 blk = get_free_dqblk(filp, info);
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);
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);
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++);
343 if (i == LUSTRE_DQSTRINBLK) {
344 printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
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);
353 dquot->dq_off = (blk<<LUSTRE_DQBLKSIZE_BITS)+sizeof(struct lustre_disk_dqdbheader)+i*sizeof(struct lustre_disk_dqblk);
361 /* Insert reference to structure into the trie */
362 static int do_insert_tree(struct lustre_dquot *dquot, uint *treeblk, int depth)
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];
368 int ret = 0, newson = 0, newact = 0;
372 if (!(buf = getdqbuf()))
375 ret = get_free_dqblk(filp, info);
379 memset(buf, 0, LUSTRE_DQBLKSIZE);
383 if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
384 printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
389 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
392 if (depth == LUSTRE_DQTREEDEPTH-1) {
395 printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", ref[GETIDINDEX(dquot->dq_id, depth)]);
400 newblk = find_free_dqentry(dquot, &ret);
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);
408 else if (newact && ret < 0)
409 put_free_dqblk(filp, info, buf, *treeblk);
415 /* Wrapper for inserting quota structure into tree */
416 static inline int dq_insert_tree(struct lustre_dquot *dquot)
418 int tmp = LUSTRE_DQTREEOFF;
419 return do_insert_tree(dquot, &tmp, 0);
423 * We don't have to be afraid of deadlocks as we never have quotas on quota files...
425 static int lustre_write_dquot(struct lustre_dquot *dquot)
427 int type = dquot->dq_type;
432 struct lustre_disk_dqblk ddquot, empty;
435 if ((ret = dq_insert_tree(dquot)) < 0) {
436 printk(KERN_ERR "VFS: Error %Zd occurred while creating quota.\n", ret);
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);
450 ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct lustre_disk_dqblk), &offset);
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);
463 /* Free dquot entry in data block */
464 static int free_dqentry(struct lustre_dquot *dquot, uint blk)
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();
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));
478 if ((ret = read_blk(filp, blk, buf)) < 0) {
479 printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
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);
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);
501 if ((ret = write_blk(filp, blk, buf)) < 0) {
502 printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);
506 dquot->dq_off = 0; /* Quota is now unattached */
512 /* Remove reference to dquot from tree */
513 static int remove_tree(struct lustre_dquot *dquot, uint *blk, int depth)
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();
520 u32 *ref = (u32 *)buf;
524 if ((ret = read_blk(filp, *blk, buf)) < 0) {
525 printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
528 newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
529 if (depth == LUSTRE_DQTREEDEPTH-1) {
530 ret = free_dqentry(dquot, newblk);
534 ret = remove_tree(dquot, &newblk, depth+1);
535 if (ret >= 0 && !newblk) {
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);
545 if ((ret = write_blk(filp, *blk, buf)) < 0)
546 printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);
553 /* Delete dquot from tree */
554 #ifndef QFMT_NO_DELETE
555 static int lustre_delete_dquot(struct lustre_dquot *dquot)
557 uint tmp = LUSTRE_DQTREEOFF;
559 if (!dquot->dq_off) /* Even not allocated? */
561 return remove_tree(dquot, &tmp, 0);
565 /* Find entry in block */
566 static loff_t find_block_dqentry(struct lustre_dquot *dquot, uint blk)
568 struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
569 dqbuf_t buf = getdqbuf();
572 struct lustre_disk_dqblk *ddquot = GETENTRIES(buf);
576 if ((ret = read_blk(filp, blk, buf)) < 0) {
577 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
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;
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)))
590 if (i == LUSTRE_DQSTRINBLK) {
591 printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id);
596 ret = (blk << LUSTRE_DQBLKSIZE_BITS) + sizeof(struct lustre_disk_dqdbheader) + i * sizeof(struct lustre_disk_dqblk);
602 /* Find entry for given id in the tree */
603 static loff_t find_tree_dqentry(struct lustre_dquot *dquot, uint blk, int depth)
605 struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
606 dqbuf_t buf = getdqbuf();
608 u32 *ref = (u32 *)buf;
612 if ((ret = read_blk(filp, blk, buf)) < 0) {
613 printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
617 blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
618 if (!blk) /* No reference? */
620 if (depth < LUSTRE_DQTREEDEPTH-1)
621 ret = find_tree_dqentry(dquot, blk, depth+1);
623 ret = find_block_dqentry(dquot, blk);
629 /* Find entry for given id in the tree - wrapper function */
630 static inline loff_t find_dqentry(struct lustre_dquot *dquot)
632 return find_tree_dqentry(dquot, LUSTRE_DQTREEOFF, 0);
635 int lustre_read_dquot(struct lustre_dquot *dquot)
637 int type = dquot->dq_type;
641 struct lustre_disk_dqblk ddquot, empty;
644 filp = dquot->dq_info->qi_files[type];
646 if (!filp || !dquot->dq_info) { /* Invalidated quota? */
647 printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
651 offset = find_dqentry(dquot);
652 if (offset <= 0) { /* Entry not present? */
654 printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
656 set_bit(DQ_FAKE_B, &dquot->dq_flags);
657 memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
661 dquot->dq_off = offset;
664 if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct lustre_disk_dqblk), &offset)) != sizeof(struct lustre_disk_dqblk)) {
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));
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;
680 disk2memdqb(&dquot->dq_dqb, &ddquot);
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)
690 /* always clear the flag so we don't loop on an IO error... */
691 clear_bit(DQ_MOD_B, &dquot->dq_flags);
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);
699 rc = lustre_write_dquot(dquot);
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);
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)
713 struct lustre_mem_dqinfo *dqinfo = &lqi->qi_info[type];
714 struct lustre_disk_dqheader dqhead;
715 struct file *fp = lqi->qi_files[type];
719 static const uint quota_magics[] = LUSTRE_INITQMAGICS;
720 static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
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);
728 if (size != sizeof(struct lustre_disk_dqheader)) {
729 printk(KERN_ERR "error writing quoafile header (rc:%d)\n", rc);
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;
741 return lustre_write_quota_info(lqi, type);
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);