Whamcloud - gitweb
Branch b1_6
[fs/lustre-release.git] / lustre / quota / quota_interface.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  *  lustre/quota/quota_interface.c
5  *
6  *  Copyright (c) 2001-2005 Cluster File Systems, Inc.
7  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
11  *
12  */
13 #ifndef EXPORT_SYMTAB
14 # define EXPORT_SYMTAB
15 #endif
16 #define DEBUG_SUBSYSTEM S_MDS
17
18 #ifdef __KERNEL__
19 # include <linux/version.h>
20 # include <linux/module.h>
21 # include <linux/init.h>
22 # include <linux/fs.h>
23 # include <linux/jbd.h>
24 # include <linux/ext3_fs.h>
25 # if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
26 #  include <linux/smp_lock.h>
27 #  include <linux/buffer_head.h>
28 #  include <linux/workqueue.h>
29 #  include <linux/mount.h>
30 # else
31 #  include <linux/locks.h>
32 # endif
33 #else /* __KERNEL__ */
34 # include <liblustre.h>
35 #endif
36
37 #include <obd_class.h>
38 #include <lustre_mds.h>
39 #include <lustre_dlm.h>
40 #include <lustre_cfg.h>
41 #include <obd_ost.h>
42 #include <lustre_fsfilt.h>
43 #include <lustre_quota.h>
44 #include <lprocfs_status.h>
45 #include "quota_internal.h"
46
47
48 #ifdef __KERNEL__
49
50 /* quota proc file handling functions */
51 #ifdef LPROCFS
52 int lprocfs_rd_bunit(char *page, char **start, off_t off, int count, 
53                      int *eof, void *data)
54 {
55         struct obd_device *obd = (struct obd_device *)data;
56         LASSERT(obd != NULL);
57
58         return snprintf(page, count, "%lu\n", 
59                         obd->u.obt.obt_qctxt.lqc_bunit_sz);
60 }
61 EXPORT_SYMBOL(lprocfs_rd_bunit);
62
63 int lprocfs_rd_iunit(char *page, char **start, off_t off, int count, 
64                      int *eof, void *data)
65 {
66         struct obd_device *obd = (struct obd_device *)data;
67         LASSERT(obd != NULL);
68
69         return snprintf(page, count, "%lu\n", 
70                         obd->u.obt.obt_qctxt.lqc_iunit_sz);
71 }
72 EXPORT_SYMBOL(lprocfs_rd_iunit);
73
74 int lprocfs_wr_bunit(struct file *file, const char *buffer,
75                      unsigned long count, void *data)
76 {
77         struct obd_device *obd = (struct obd_device *)data;
78         int val, rc;
79         LASSERT(obd != NULL);
80
81         rc = lprocfs_write_helper(buffer, count, &val);
82         if (rc)
83                 return rc;
84
85         if (val % QUOTABLOCK_SIZE ||
86             val <= obd->u.obt.obt_qctxt.lqc_btune_sz)
87                 return -EINVAL;
88
89         obd->u.obt.obt_qctxt.lqc_bunit_sz = val;
90         return count;
91 }
92 EXPORT_SYMBOL(lprocfs_wr_bunit);
93
94 int lprocfs_wr_iunit(struct file *file, const char *buffer,
95                      unsigned long count, void *data)
96 {
97         struct obd_device *obd = (struct obd_device *)data;
98         int val, rc;
99         LASSERT(obd != NULL);
100
101         rc = lprocfs_write_helper(buffer, count, &val);
102         if (rc)
103                 return rc;
104
105         if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz)
106                 return -EINVAL;
107
108         obd->u.obt.obt_qctxt.lqc_iunit_sz = val;
109         return count;
110 }
111 EXPORT_SYMBOL(lprocfs_wr_iunit);
112
113 int lprocfs_rd_btune(char *page, char **start, off_t off, int count, 
114                      int *eof, void *data)
115 {
116         struct obd_device *obd = (struct obd_device *)data;
117         LASSERT(obd != NULL);
118
119         return snprintf(page, count, "%lu\n", 
120                         obd->u.obt.obt_qctxt.lqc_btune_sz);
121 }
122 EXPORT_SYMBOL(lprocfs_rd_btune);
123
124 int lprocfs_rd_itune(char *page, char **start, off_t off, int count, 
125                      int *eof, void *data)
126 {
127         struct obd_device *obd = (struct obd_device *)data;
128         LASSERT(obd != NULL);
129
130         return snprintf(page, count, "%lu\n", 
131                         obd->u.obt.obt_qctxt.lqc_itune_sz);
132 }
133 EXPORT_SYMBOL(lprocfs_rd_itune);
134
135 int lprocfs_wr_btune(struct file *file, const char *buffer,
136                      unsigned long count, void *data)
137 {
138         struct obd_device *obd = (struct obd_device *)data;
139         int val, rc;
140         LASSERT(obd != NULL);
141
142         rc = lprocfs_write_helper(buffer, count, &val);
143         if (rc)
144                 return rc;
145         
146         if (val <= QUOTABLOCK_SIZE * MIN_QLIMIT || val % QUOTABLOCK_SIZE || 
147             val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
148                 return -EINVAL;
149
150         obd->u.obt.obt_qctxt.lqc_btune_sz = val;
151         return count;
152 }
153 EXPORT_SYMBOL(lprocfs_wr_btune);
154
155 int lprocfs_wr_itune(struct file *file, const char *buffer,
156                      unsigned long count, void *data)
157 {
158         struct obd_device *obd = (struct obd_device *)data;
159         int val, rc;
160         LASSERT(obd != NULL);
161
162         rc = lprocfs_write_helper(buffer, count, &val);
163         if (rc)
164                 return rc;
165         
166         if (val <= MIN_QLIMIT || 
167             val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
168                 return -EINVAL;
169
170         obd->u.obt.obt_qctxt.lqc_itune_sz = val;
171         return count;
172 }
173 EXPORT_SYMBOL(lprocfs_wr_itune);
174
175 #define USER_QUOTA      1
176 #define GROUP_QUOTA     2
177
178 #define MAX_STYPE_SIZE  5
179 int lprocfs_rd_type(char *page, char **start, off_t off, int count, 
180                     int *eof, void *data)
181 {
182         struct obd_device *obd = (struct obd_device *)data;
183         char stype[MAX_STYPE_SIZE + 1] = "";
184         int type = obd->u.obt.obt_qctxt.lqc_atype;
185         LASSERT(obd != NULL);
186
187         if (type == 0) {
188                 strcpy(stype, "off");
189         } else {
190                 if (type & USER_QUOTA)
191                         strcat(stype, "u");
192                 if (type & GROUP_QUOTA)
193                         strcat(stype, "g");
194         }
195
196         /* append with quota version on MDS */
197         if (!strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME)) {
198                 int rc;
199                 lustre_quota_version_t version;
200
201                 rc = mds_quota_get_version(obd, &version);
202                 if (rc)
203                         return rc;
204
205                 switch (version) {
206                         case LUSTRE_QUOTA_V1:
207                                 strcat(stype, "1");
208                                 break;
209                         case LUSTRE_QUOTA_V2:
210                                 strcat(stype, "2");
211                                 break;
212                         default:
213                                 return -ENOSYS;
214                 }
215         }
216
217         return snprintf(page, count, "%s\n", stype);
218 }
219 EXPORT_SYMBOL(lprocfs_rd_type);
220
221 static int auto_quota_on(struct obd_device *obd, int type, 
222                          struct super_block *sb, int is_master)
223 {
224         struct obd_quotactl *oqctl;
225         struct lvfs_run_ctxt saved;
226         int rc;
227         ENTRY;
228
229         LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
230
231         /* quota already turned on */
232         if (obd->u.obt.obt_qctxt.lqc_status)
233                 RETURN(0);
234
235         OBD_ALLOC_PTR(oqctl);
236         if (!oqctl)
237                 RETURN(-ENOMEM);
238
239         oqctl->qc_type = type;
240         oqctl->qc_cmd = Q_QUOTAON;
241         oqctl->qc_id = QFMT_LDISKFS;
242
243         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
244
245         if (!is_master)
246                 goto local_quota;
247
248         /* turn on cluster wide quota */
249         rc = mds_admin_quota_on(obd, oqctl);
250         if (rc) {
251                 CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR, 
252                        "auto-enable admin quota failed. rc=%d\n", rc);
253                 GOTO(out_pop, rc);
254         }
255 local_quota:
256         /* turn on local quota */
257         rc = fsfilt_quotactl(obd, sb, oqctl);
258         if (rc) {
259                 CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR, 
260                        "auto-enable local quota failed. rc=%d\n", rc);
261                 if (is_master)
262                         mds_quota_off(obd, oqctl);
263         } else {
264                 obd->u.obt.obt_qctxt.lqc_status = 1;
265         }
266 out_pop:
267         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
268
269         OBD_FREE_PTR(oqctl);
270         RETURN(rc);
271 }
272
273 int lprocfs_wr_type(struct file *file, const char *buffer,
274                     unsigned long count, void *data)
275 {
276         struct obd_device *obd = (struct obd_device *)data;
277         struct obd_device_target *obt = &obd->u.obt;
278         int type = 0;
279         unsigned long i;
280         char stype[MAX_STYPE_SIZE + 1] = "";
281         LASSERT(obd != NULL);
282
283         if (count > MAX_STYPE_SIZE)
284                 return -EINVAL;
285
286         if (copy_from_user(stype, buffer, count))
287                 return -EFAULT;
288
289         for (i = 0 ; i < count ; i++) {
290                 int rc;
291
292                 switch (stype[i]) {
293                 case 'u' : 
294                         type |= USER_QUOTA;
295                         break;
296                 case 'g' : 
297                         type |= GROUP_QUOTA;
298                         break;
299                 /* quota version specifiers */
300                 case '1' : 
301                         if (strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME))
302                                 break;
303
304                         rc = mds_quota_set_version(obd, LUSTRE_QUOTA_V1);
305                         if (rc) {
306                                 CDEBUG(D_QUOTA, "failed to set quota v1! %d\n", rc);
307                                 return rc;
308                         }
309                         break;
310                 case '2' : 
311                         if (strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME))
312                                 break;
313
314                         rc = mds_quota_set_version(obd, LUSTRE_QUOTA_V2);
315                         if (rc) {
316                                 CDEBUG(D_QUOTA, "could not set quota v2! %d\n", rc);
317                                 return rc;
318                         }
319                         break;
320                 default  : /* just skip stray symbols like \n */
321                         break;
322                 }
323         }
324
325         obt->obt_qctxt.lqc_atype = type;
326
327         if (type == 0)
328                 return count;
329
330         if (!strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME))
331                 auto_quota_on(obd, type - 1, obt->obt_sb, 1);
332         else if (!strcmp(obd->obd_type->typ_name, LUSTRE_OST_NAME))
333                 auto_quota_on(obd, type - 1, obt->obt_sb, 0);
334         else 
335                 return -EFAULT;
336
337         return count;
338 }
339 EXPORT_SYMBOL(lprocfs_wr_type);
340
341 int lprocfs_filter_rd_limit(char *page, char **start, off_t off, int count, 
342                                    int *eof, void *data)
343 {
344         struct obd_device *obd = (struct obd_device *)data;
345         LASSERT(obd != NULL);
346         
347         return snprintf(page, count, "%lu\n", 
348                         obd->u.obt.obt_qctxt.lqc_limit_sz);
349 }
350 EXPORT_SYMBOL(lprocfs_filter_rd_limit);
351
352 int lprocfs_filter_wr_limit(struct file *file, const char *buffer,
353                                    unsigned long count, void *data)
354 {
355         struct obd_device *obd = (struct obd_device *)data;
356         int val, rc;
357         LASSERT(obd != NULL);
358         
359         rc = lprocfs_write_helper(buffer, count, &val);
360         if (rc)
361                 return rc;
362         
363         if (val <= 1 << 20)
364                 return -EINVAL;
365         
366         obd->u.obt.obt_qctxt.lqc_limit_sz = val;
367         return count;
368
369 EXPORT_SYMBOL(lprocfs_filter_wr_limit);
370
371 #endif /* LPROCFS */
372
373 static int filter_quota_setup(struct obd_device *obd)
374 {
375         int rc = 0;
376         struct obd_device_target *obt = &obd->u.obt;
377         ENTRY;
378
379         atomic_set(&obt->obt_quotachecking, 1);
380         rc = qctxt_init(&obt->obt_qctxt, obt->obt_sb, NULL);
381         if (rc) {
382                 CERROR("initialize quota context failed! (rc:%d)\n", rc);
383                 RETURN(rc);
384         }
385         RETURN(rc);
386 }
387
388 static int filter_quota_cleanup(struct obd_device *obd)
389 {
390         qctxt_cleanup(&obd->u.obt.obt_qctxt, 0);
391         return 0;
392 }
393
394 static int filter_quota_setinfo(struct obd_export *exp, struct obd_device *obd)
395 {
396         struct obd_import *imp;
397
398         /* setup the quota context import */
399         spin_lock(&obd->u.obt.obt_qctxt.lqc_lock);
400         obd->u.obt.obt_qctxt.lqc_import = exp->exp_imp_reverse;
401         spin_unlock(&obd->u.obt.obt_qctxt.lqc_lock);
402
403         /* make imp's connect flags equal relative exp's connect flags 
404          * adding it to avoid the scan export list
405          */
406         imp = exp->exp_imp_reverse;
407         if (imp)
408                 imp->imp_connect_data.ocd_connect_flags |= 
409                         (exp->exp_connect_flags & OBD_CONNECT_QUOTA64);
410
411         /* start quota slave recovery thread. (release high limits) */
412         qslave_start_recovery(obd, &obd->u.obt.obt_qctxt);
413         return 0;
414 }
415
416 static int filter_quota_clearinfo(struct obd_export *exp, struct obd_device *obd)
417 {
418         struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
419
420         /* when exp->exp_imp_reverse is destroyed, the corresponding lqc_import
421          * should be invalid b=12374 */
422         if (qctxt->lqc_import == exp->exp_imp_reverse) {
423                 spin_lock(&qctxt->lqc_lock);
424                 qctxt->lqc_import = NULL;
425                 spin_unlock(&qctxt->lqc_lock);
426         }
427
428         return 0;
429 }
430
431 static int filter_quota_enforce(struct obd_device *obd, unsigned int ignore)
432 {
433         ENTRY;
434
435         if (!sb_any_quota_enabled(obd->u.obt.obt_sb))
436                 RETURN(0);
437
438         if (ignore)
439                 cap_raise(current->cap_effective, CAP_SYS_RESOURCE);
440         else
441                 cap_lower(current->cap_effective, CAP_SYS_RESOURCE);
442
443         RETURN(0);
444 }
445
446 static int filter_quota_getflag(struct obd_device *obd, struct obdo *oa)
447 {
448         struct obd_device_target *obt = &obd->u.obt;
449         int err, cnt, rc = 0;
450         struct obd_quotactl *oqctl;
451         ENTRY;
452
453         if (!sb_any_quota_enabled(obt->obt_sb))
454                 RETURN(0);
455
456         oa->o_flags &= ~(OBD_FL_NO_USRQUOTA | OBD_FL_NO_GRPQUOTA);
457
458         OBD_ALLOC_PTR(oqctl);
459         if (!oqctl) {
460                 CERROR("Not enough memory!");
461                 RETURN(-ENOMEM);
462         }
463
464         for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
465                 memset(oqctl, 0, sizeof(*oqctl));
466
467                 oqctl->qc_cmd = Q_GETQUOTA;
468                 oqctl->qc_type = cnt;
469                 oqctl->qc_id = (cnt == USRQUOTA) ? oa->o_uid : oa->o_gid;
470                 err = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
471                 if (err) {
472                         if (!rc)
473                                 rc = err;
474                         continue;
475                 }
476
477                 /* set over quota flags for a uid/gid */
478                 oa->o_valid |= (cnt == USRQUOTA) ?
479                                OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA;
480                 if (oqctl->qc_dqblk.dqb_bhardlimit &&
481                    (toqb(oqctl->qc_dqblk.dqb_curspace) > 
482                     oqctl->qc_dqblk.dqb_bhardlimit))
483                         oa->o_flags |= (cnt == USRQUOTA) ? 
484                                 OBD_FL_NO_USRQUOTA : OBD_FL_NO_GRPQUOTA;
485         }
486         OBD_FREE_PTR(oqctl);
487         RETURN(rc);
488 }
489
490 static int filter_quota_acquire(struct obd_device *obd, unsigned int uid, 
491                                 unsigned int gid)
492 {
493         struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
494         int rc;
495         ENTRY;
496
497         rc = qctxt_adjust_qunit(obd, qctxt, uid, gid, 1, 1);
498         RETURN(rc == -EAGAIN);
499 }
500
501 /* check whether the left quota of certain uid and uid can satisfy a write rpc
502  * when need to acquire quota, return QUOTA_RET_ACQUOTA */
503 static int filter_quota_check(struct obd_device *obd, unsigned int uid, 
504                               unsigned int gid, int npage)
505 {
506         struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
507         int i;
508         __u32 id[MAXQUOTAS] = { uid, gid };
509         __u64 limit;
510         struct qunit_data qdata[MAXQUOTAS];
511         int rc;
512         ENTRY;
513
514         CLASSERT(MAXQUOTAS < 4);
515         if (!sb_any_quota_enabled(qctxt->lqc_sb))
516                 RETURN(0);
517
518         for (i = 0; i < MAXQUOTAS; i++) {
519                 qdata[i].qd_id = id[i];
520                 qdata[i].qd_flags = i;
521                 qdata[i].qd_flags |= QUOTA_IS_BLOCK;
522                 qdata[i].qd_count = 0;
523
524                 qctxt_wait_pending_dqacq(qctxt, id[i], i, 1);
525                 rc = compute_remquota(obd, qctxt, &qdata[i]);
526                 limit = npage * CFS_PAGE_SIZE;
527                 if (limit < qctxt->lqc_limit_sz )
528                         limit =  qctxt->lqc_limit_sz;
529                 if (rc == QUOTA_RET_OK && 
530                     qdata[i].qd_count < limit)
531                         RETURN(QUOTA_RET_ACQUOTA);
532         }
533
534         RETURN(rc);
535 }
536
537 static int mds_quota_init(void)
538 {
539         return lustre_dquot_init();
540 }
541
542 static int mds_quota_exit(void)
543 {
544         lustre_dquot_exit();
545         return 0;
546 }
547
548 static int mds_quota_setup(struct obd_device *obd)
549 {
550         struct obd_device_target *obt = &obd->u.obt;
551         struct mds_obd *mds = &obd->u.mds;
552         int rc;
553         ENTRY;
554
555         mds->mds_quota_info.qi_version = LUSTRE_QUOTA_V2;
556         atomic_set(&obt->obt_quotachecking, 1);
557         /* initialize quota master and quota context */
558         sema_init(&mds->mds_qonoff_sem, 1);
559         rc = qctxt_init(&obt->obt_qctxt, obt->obt_sb, dqacq_handler);
560         if (rc) {
561                 CERROR("initialize quota context failed! (rc:%d)\n", rc);
562                 RETURN(rc);
563         }
564         RETURN(rc);
565 }
566
567 static int mds_quota_cleanup(struct obd_device *obd)
568 {
569         qctxt_cleanup(&obd->u.obt.obt_qctxt, 0);
570         RETURN(0);
571 }
572
573 static int mds_quota_fs_cleanup(struct obd_device *obd)
574 {
575         struct mds_obd *mds = &obd->u.mds;
576         int i;
577         ENTRY;
578
579         /* close admin quota files */
580         down(&mds->mds_qonoff_sem);
581         for (i = 0; i < MAXQUOTAS; i++) {
582                 if (mds->mds_quota_info.qi_files[i]) {
583                         filp_close(mds->mds_quota_info.qi_files[i], 0);
584                         mds->mds_quota_info.qi_files[i] = NULL;
585                 }
586         }
587         up(&mds->mds_qonoff_sem);
588         RETURN(0);
589 }
590 #endif /* __KERNEL__ */
591
592 struct osc_quota_info {
593         struct list_head        oqi_hash;       /* hash list */
594         struct client_obd      *oqi_cli;        /* osc obd */
595         unsigned int            oqi_id;         /* uid/gid of a file */
596         short                   oqi_type;       /* quota type */
597 };
598
599 spinlock_t qinfo_list_lock = SPIN_LOCK_UNLOCKED;
600
601 static struct list_head qinfo_hash[NR_DQHASH];
602 /* SLAB cache for client quota context */
603 cfs_mem_cache_t *qinfo_cachep = NULL;
604
605 static inline int hashfn(struct client_obd *cli, unsigned long id, int type)
606                          __attribute__((__const__));
607
608 static inline int hashfn(struct client_obd *cli, unsigned long id, int type)
609 {
610         unsigned long tmp = ((unsigned long)cli>>6) ^ id;
611         tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
612         return tmp;
613 }
614
615 /* caller must hold qinfo_list_lock */
616 static inline void insert_qinfo_hash(struct osc_quota_info *oqi)
617 {
618         struct list_head *head = qinfo_hash + 
619                 hashfn(oqi->oqi_cli, oqi->oqi_id, oqi->oqi_type);
620
621         LASSERT_SPIN_LOCKED(&qinfo_list_lock);
622         list_add(&oqi->oqi_hash, head);
623 }
624
625 /* caller must hold qinfo_list_lock */
626 static inline void remove_qinfo_hash(struct osc_quota_info *oqi)
627 {
628         LASSERT_SPIN_LOCKED(&qinfo_list_lock);
629         list_del_init(&oqi->oqi_hash);
630 }
631
632 /* caller must hold qinfo_list_lock */
633 static inline struct osc_quota_info *find_qinfo(struct client_obd *cli,
634                                                 unsigned int id, int type)
635 {
636         unsigned int hashent = hashfn(cli, id, type);
637         struct osc_quota_info *oqi;
638
639         LASSERT_SPIN_LOCKED(&qinfo_list_lock);
640         list_for_each_entry(oqi, &qinfo_hash[hashent], oqi_hash) {
641                 if (oqi->oqi_cli == cli &&
642                     oqi->oqi_id == id && oqi->oqi_type == type)
643                         return oqi;
644         }
645         return NULL;
646 }
647
648 static struct osc_quota_info *alloc_qinfo(struct client_obd *cli,
649                                           unsigned int id, int type)
650 {
651         struct osc_quota_info *oqi;
652         ENTRY;
653
654         OBD_SLAB_ALLOC(oqi, qinfo_cachep, CFS_ALLOC_STD, sizeof(*oqi));
655         if(!oqi)
656                 RETURN(NULL);
657
658         INIT_LIST_HEAD(&oqi->oqi_hash);
659         oqi->oqi_cli = cli;
660         oqi->oqi_id = id;
661         oqi->oqi_type = type;
662
663         RETURN(oqi);
664 }
665
666 static void free_qinfo(struct osc_quota_info *oqi)
667 {
668         OBD_SLAB_FREE(oqi, qinfo_cachep, sizeof(*oqi));
669 }
670
671 int osc_quota_chkdq(struct client_obd *cli, 
672                     unsigned int uid, unsigned int gid)
673 {
674         unsigned int id;
675         int cnt, rc = QUOTA_OK;
676         ENTRY;
677
678         spin_lock(&qinfo_list_lock);
679         for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
680                 struct osc_quota_info *oqi = NULL;
681
682                 id = (cnt == USRQUOTA) ? uid : gid;
683                 oqi = find_qinfo(cli, id, cnt);
684                 if (oqi) {
685                         rc = NO_QUOTA;
686                         break;
687                 }
688         }
689         spin_unlock(&qinfo_list_lock);
690
691         RETURN(rc);
692 }
693
694 int osc_quota_setdq(struct client_obd *cli, 
695                     unsigned int uid, unsigned int gid,
696                     obd_flag valid, obd_flag flags)
697 {
698         unsigned int id;
699         obd_flag noquota;
700         int cnt, rc = 0;
701         ENTRY;
702
703
704         for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
705                 struct osc_quota_info *oqi, *old;
706
707                 if (!(valid & ((cnt == USRQUOTA) ? 
708                     OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA)))
709                         continue;
710
711                 id = (cnt == USRQUOTA) ? uid : gid;
712                 noquota = (cnt == USRQUOTA) ? 
713                     (flags & OBD_FL_NO_USRQUOTA) : (flags & OBD_FL_NO_GRPQUOTA);
714
715                 oqi = alloc_qinfo(cli, id, cnt);
716                 if (oqi) {
717                         spin_lock(&qinfo_list_lock);
718
719                         old = find_qinfo(cli, id, cnt);
720                         if (old && !noquota)
721                                 remove_qinfo_hash(old);
722                         else if (!old && noquota)
723                                 insert_qinfo_hash(oqi);
724
725                         spin_unlock(&qinfo_list_lock);
726
727                         if (old || !noquota)
728                                 free_qinfo(oqi);
729                         if (old && !noquota)
730                                 free_qinfo(old);
731                 } else {
732                         CERROR("not enough mem!\n");
733                         rc = -ENOMEM;
734                         break;
735                 }
736         }
737
738         RETURN(rc);
739 }
740
741 int osc_quota_cleanup(struct obd_device *obd)
742 {
743         struct client_obd *cli = &obd->u.cli;
744         struct osc_quota_info *oqi, *n;
745         int i;
746         ENTRY;
747
748         spin_lock(&qinfo_list_lock);
749         for (i = 0; i < NR_DQHASH; i++) {
750                 list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
751                         if (oqi->oqi_cli != cli)
752                                 continue;
753                         remove_qinfo_hash(oqi);
754                         free_qinfo(oqi);
755                 }
756         }
757         spin_unlock(&qinfo_list_lock);
758
759         RETURN(0);
760 }
761
762 int osc_quota_init(void)
763 {
764         int i;
765         ENTRY;
766
767         LASSERT(qinfo_cachep == NULL);
768         qinfo_cachep = cfs_mem_cache_create("osc_quota_info",
769                                             sizeof(struct osc_quota_info),
770                                             0, 0);
771         if (!qinfo_cachep)
772                 RETURN(-ENOMEM);
773
774         for (i = 0; i < NR_DQHASH; i++)
775                 INIT_LIST_HEAD(qinfo_hash + i);
776
777         RETURN(0);
778 }
779
780 int osc_quota_exit(void)
781 {
782         struct osc_quota_info *oqi, *n;
783         int i, rc;
784         ENTRY;
785
786         spin_lock(&qinfo_list_lock);
787         for (i = 0; i < NR_DQHASH; i++) {
788                 list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
789                         remove_qinfo_hash(oqi);
790                         free_qinfo(oqi);
791                 }
792         }
793         spin_unlock(&qinfo_list_lock);
794
795         rc = cfs_mem_cache_destroy(qinfo_cachep);
796         LASSERTF(rc == 0, "couldn't destory qinfo_cachep slab\n");
797         qinfo_cachep = NULL;
798
799         RETURN(0);
800 }
801
802 #ifdef __KERNEL__
803 quota_interface_t mds_quota_interface = {
804         .quota_init     = mds_quota_init,
805         .quota_exit     = mds_quota_exit,
806         .quota_setup    = mds_quota_setup,
807         .quota_cleanup  = mds_quota_cleanup,
808         .quota_check    = target_quota_check,
809         .quota_ctl      = mds_quota_ctl,
810         .quota_fs_cleanup       =mds_quota_fs_cleanup,
811         .quota_recovery = mds_quota_recovery,
812         .quota_adjust   = mds_quota_adjust,
813 };
814
815 quota_interface_t filter_quota_interface = {
816         .quota_setup    = filter_quota_setup,
817         .quota_cleanup  = filter_quota_cleanup,
818         .quota_check    = target_quota_check,
819         .quota_ctl      = filter_quota_ctl,
820         .quota_setinfo  = filter_quota_setinfo,
821         .quota_clearinfo = filter_quota_clearinfo,
822         .quota_enforce  = filter_quota_enforce,
823         .quota_getflag  = filter_quota_getflag,
824         .quota_acquire  = filter_quota_acquire,
825         .quota_adjust   = filter_quota_adjust,
826         .quota_chkquota = filter_quota_check,
827 };
828 #endif /* __KERNEL__ */
829
830 quota_interface_t mdc_quota_interface = {
831         .quota_ctl      = client_quota_ctl,
832         .quota_check    = client_quota_check,
833         .quota_poll_check = client_quota_poll_check,
834 };
835
836 quota_interface_t osc_quota_interface = {
837         .quota_ctl      = client_quota_ctl,
838         .quota_check    = client_quota_check,
839         .quota_poll_check = client_quota_poll_check,
840         .quota_init     = osc_quota_init,
841         .quota_exit     = osc_quota_exit,
842         .quota_chkdq    = osc_quota_chkdq,
843         .quota_setdq    = osc_quota_setdq,
844         .quota_cleanup  = osc_quota_cleanup,
845 };
846
847 quota_interface_t lov_quota_interface = {
848         .quota_check    = lov_quota_check,
849         .quota_ctl      = lov_quota_ctl,
850 };
851
852 #ifdef __KERNEL__
853 static int __init init_lustre_quota(void)
854 {
855         int rc = qunit_cache_init();
856         if (rc)
857                 return rc;
858         PORTAL_SYMBOL_REGISTER(filter_quota_interface);
859         PORTAL_SYMBOL_REGISTER(mds_quota_interface);
860         PORTAL_SYMBOL_REGISTER(mdc_quota_interface);
861         PORTAL_SYMBOL_REGISTER(osc_quota_interface);
862         PORTAL_SYMBOL_REGISTER(lov_quota_interface);
863         return 0;
864 }
865
866 static void /*__exit*/ exit_lustre_quota(void)
867 {
868         PORTAL_SYMBOL_UNREGISTER(filter_quota_interface);
869         PORTAL_SYMBOL_UNREGISTER(mds_quota_interface);
870         PORTAL_SYMBOL_UNREGISTER(mdc_quota_interface);
871         PORTAL_SYMBOL_UNREGISTER(osc_quota_interface);
872         PORTAL_SYMBOL_UNREGISTER(lov_quota_interface);
873
874         qunit_cache_cleanup();
875 }
876
877 MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
878 MODULE_DESCRIPTION("Lustre Quota");
879 MODULE_LICENSE("GPL");
880
881 cfs_module(lquota, "1.0.0", init_lustre_quota, exit_lustre_quota);
882
883 EXPORT_SYMBOL(mds_quota_interface);
884 EXPORT_SYMBOL(filter_quota_interface);
885 EXPORT_SYMBOL(mdc_quota_interface);
886 EXPORT_SYMBOL(osc_quota_interface);
887 EXPORT_SYMBOL(lov_quota_interface);
888 #endif /* __KERNEL */