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