Whamcloud - gitweb
land b1_4_quota (20051104_1137)
authorniu <niu>
Fri, 4 Nov 2005 05:46:41 +0000 (05:46 +0000)
committerniu <niu>
Fri, 4 Nov 2005 05:46:41 +0000 (05:46 +0000)
85 files changed:
ldiskfs/ldiskfs/Makefile.in
lustre/Makefile.in
lustre/autoMakefile.am
lustre/autoconf/lustre-core.m4
lustre/doc/lfs.1
lustre/doc/lfs.lyx
lustre/include/linux/lustre_compat25.h
lustre/include/linux/lustre_fsfilt.h
lustre/include/linux/lustre_idl.h
lustre/include/linux/lustre_log.h
lustre/include/linux/lustre_quota.h
lustre/include/linux/obd.h
lustre/include/linux/obd_class.h
lustre/include/linux/obd_ost.h
lustre/include/linux/obd_support.h
lustre/include/lustre/liblustreapi.h
lustre/include/lustre/lustre_user.h
lustre/kernel_patches/kernel_configs/uml-2.6.10-fc3.config
lustre/kernel_patches/patches/kallsyms-2.4-bgl.patch
lustre/ldiskfs/Makefile.in
lustre/ldiskfs/lustre_quota_fmt.c
lustre/ldiskfs/lustre_quota_fmt.h
lustre/ldiskfs/quotafmt_test.c
lustre/ldlm/ldlm_lib.c
lustre/liblustre/Makefile.am
lustre/liblustre/genlib.sh
lustre/liblustre/lutil.c
lustre/llite/dir.c
lustre/llite/llite_internal.h
lustre/llite/rw.c
lustre/lov/lov_internal.h
lustre/lov/lov_log.c
lustre/lov/lov_obd.c
lustre/lvfs/Makefile.in
lustre/lvfs/fsfilt_ext3.c
lustre/mdc/mdc_internal.h
lustre/mdc/mdc_request.c
lustre/mds/Makefile.in
lustre/mds/handler.c
lustre/mds/lproc_mds.c
lustre/mds/mds_fs.c
lustre/mds/mds_internal.h
lustre/mds/mds_log.c
lustre/mds/mds_lov.c
lustre/mds/mds_open.c
lustre/mds/mds_reint.c
lustre/mds/quota_context.c [deleted file]
lustre/obdclass/genops.c
lustre/obdclass/llog_obd.c
lustre/obdfilter/filter.c
lustre/obdfilter/filter_internal.h
lustre/obdfilter/filter_io.c
lustre/obdfilter/filter_io_26.c
lustre/obdfilter/filter_log.c
lustre/obdfilter/lproc_obdfilter.c
lustre/osc/osc_internal.h
lustre/osc/osc_quota.c [deleted file]
lustre/osc/osc_request.c
lustre/ost/ost_handler.c
lustre/ost/ost_internal.h
lustre/ptlrpc/Makefile.in
lustre/ptlrpc/llog_net.c
lustre/quota/.cvsignore [new file with mode: 0644]
lustre/quota/Makefile.in [new file with mode: 0644]
lustre/quota/autoMakefile.am [new file with mode: 0644]
lustre/quota/quota_check.c [new file with mode: 0644]
lustre/quota/quota_context.c [new file with mode: 0644]
lustre/quota/quota_ctl.c [new file with mode: 0644]
lustre/quota/quota_interface.c [new file with mode: 0644]
lustre/quota/quota_internal.h [new file with mode: 0644]
lustre/quota/quota_master.c [moved from lustre/mds/quota_master.c with 56% similarity]
lustre/quota/quotacheck_test.c [moved from lustre/lvfs/quotacheck_test.c with 85% similarity]
lustre/quota/quotactl_test.c [moved from lustre/lvfs/quotactl_test.c with 94% similarity]
lustre/tests/Makefile.am
lustre/tests/chownmany.c [new file with mode: 0644]
lustre/tests/llog-test.sh [new file with mode: 0644]
lustre/tests/local.sh
lustre/tests/lov.sh
lustre/tests/quota_sanity.sh [deleted file]
lustre/tests/sanity-quota.sh [new file with mode: 0644]
lustre/utils/lconf
lustre/utils/lfs.c
lustre/utils/liblustreapi.c
lustre/utils/lmc
lustre/utils/lustre_cfg.c

index 2f0cdc7..92d9b6b 100644 (file)
@@ -1,6 +1,8 @@
 default: all
 
-MODULES := ldiskfs #quotafmt_test
+MODULES := ldiskfs
+
+@QUOTA_TRUE@MODULES += quotafmt_test
 
 # copy makefile over to not break patches
 ext3_extra := $(wildcard @LINUX@/fs/ext3/Makefile)
@@ -11,13 +13,16 @@ linux_headers := $(wildcard @LINUX@/include/linux/ext3*.h)
 ext3_sources := $(filter-out %.mod.c,$(wildcard @LINUX@/fs/ext3/*.c))
 new_sources := iopen.c iopen.h extents.c mballoc.c proc.c
 new_headers := ext3_extents.h
-#quotafmt_sources := lustre_quota_fmt.c
-#quotafmt_headers := lustre_quota_fmt.h
 ldiskfs_patched_sources := $(notdir $(ext3_sources) $(ext3_headers)) $(new_sources) $(new_headers)
-ldiskfs_sources := $(ldiskfs_patched_sources) #$(quotafmt_sources) $(quotafmt_headers)
+ldiskfs_sources := $(ldiskfs_patched_sources)
+
+quotafmt_sources := lustre_quota_fmt.c
+quotafmt_headers := lustre_quota_fmt.h
+@QUOTA_TRUE@ldiskfs_sources += $(quotafmt_sources) $(quotafmt_headers)
 
 ldiskfs-objs := $(filter %.o,$(ldiskfs_sources:.c=.o))
-#quotafmt-objs := quotafmt_test.o
+
+@QUOTA_TRUE@quotafmt-objs := quotafmt_test.o
 
 EXTRA_PRE_CFLAGS := -I@LINUX@/fs -I@LUSTRE@ -I@LUSTRE@/ldiskfs
 
index d6e7684..6da79a1 100644 (file)
@@ -9,5 +9,6 @@ subdir-m += obdecho
 
 @SERVER_TRUE@subdir-m += mds obdfilter ost
 @CLIENT_TRUE@subdir-m += mdc llite
+@QUOTA_TRUE@subdir-m += quota
 
 @INCLUDE_RULES@
index 92426b5..1e38c7a 100644 (file)
@@ -12,6 +12,8 @@ SERVER_SUBDIRS := ldiskfs obdfilter ost mds
 
 CLIENT_SUBDIRS := mdc llite
 
+QUOTA_SUBDIRS := quota
+
 LIBLUSTRE_SUBDIRS := liblustre
 
 SUBDIRS := $(ALWAYS_SUBDIRS)
@@ -24,6 +26,10 @@ if CLIENT
 SUBDIRS += $(CLIENT_SUBDIRS)
 endif
 
+if QUOTA
+SUBDIRS += $(QUOTA_SUBDIRS)
+endif
+
 # this needs to be after the client subdirs
 if LIBLUSTRE
 if !CLIENT
@@ -33,7 +39,7 @@ SUBDIRS += $(LIBLUSTRE_SUBDIRS)
 endif
 
 DIST_SUBDIRS := $(ALWAYS_SUBDIRS) $(SERVER_SUBDIRS) $(CLIENT_SUBDIRS)  \
-       $(LIBLUSTRE_SUBDIRS)
+       $(LIBLUSTRE_SUBDIRS) $(QUOTA_SUBDIRS)
 
 EXTRA_DIST = BUGS FDL kernel_patches
 
index 5b48d1c..e6cdb7b 100644 (file)
@@ -439,6 +439,7 @@ AC_DEFUN([LC_PROG_LINUX],
        LC_CONFIG_BACKINGFS
 fi
 LC_CONFIG_PINGER
+LC_CONFIG_QUOTA
 
 LC_STRUCT_KIOBUF
 LC_FUNC_COND_RESCHED
@@ -512,6 +513,23 @@ ac_configure_args="$ac_configure_args --with-lustre-hack --with-sockets"
 ])
 
 #
+# LC_CONFIG_QUOTA
+#
+# whether to enable quota support
+#
+AC_DEFUN([LC_CONFIG_QUOTA],
+[AC_MSG_CHECKING([whether to enable quota support])
+AC_ARG_ENABLE([quota], 
+       AC_HELP_STRING([--enable-quota],
+                       [enable quota support]),
+       [],[enable_quota='yes'])
+AC_MSG_RESULT([$enable_quota])
+if test x$enable_quota != xno ; then
+   AC_DEFINE(HAVE_QUOTA_SUPPORT, 1, [Enable quota support])
+fi
+])
+  
+#
 # LC_CONFIGURE
 #
 # other configure checks
@@ -526,16 +544,6 @@ AC_CHECK_HEADERS([asm/page.h sys/user.h stdint.h])
 # See note there re: __ASM_X86_64_PROCESSOR_H
 AC_CHECK_HEADERS([linux/quota.h])
 
-AC_CHECK_TYPES([struct if_dqinfo],[],[],[
-#define __ASM_X86_64_PROCESSOR_H
-#include <linux/quota.h>
-])
-
-AC_CHECK_TYPES([struct if_dqblk],[],[],[
-#define __ASM_X86_64_PROCESSOR_H
-#include <linux/quota.h>
-])
-
 # liblustre/llite_lib.h
 AC_CHECK_HEADERS([xtio.h file.h])
 
@@ -573,6 +581,7 @@ AM_CONDITIONAL(LIBLUSTRE_TESTS, test x$enable_liblustre_tests = xyes)
 AM_CONDITIONAL(MPITESTS, test x$enable_mpitests = xyes, Build MPI Tests)
 AM_CONDITIONAL(CLIENT, test x$enable_client = xyes)
 AM_CONDITIONAL(SERVER, test x$enable_server = xyes)
+AM_CONDITIONAL(QUOTA, test x$enable_quota = xyes)
 ])
 
 #
@@ -625,6 +634,8 @@ lustre/ost/Makefile
 lustre/ost/autoMakefile
 lustre/ptlrpc/Makefile
 lustre/ptlrpc/autoMakefile
+lustre/quota/Makefile
+lustre/quota/autoMakefile
 lustre/scripts/Makefile
 lustre/scripts/version_tag.pl
 lustre/tests/Makefile
index 4d63cad..b31f5ff 100644 (file)
@@ -11,6 +11,20 @@ lfs \- Lustre utility to create a file with specific striping pattern, find the
 .br
 .B lfs setstripe <filename> <stripe-size> <start-ost> <stripe-cnt>
 .br
+.B lfs quotachown [-i] <filesystem>
+.br
+.B lfs quotacheck [-ug] <filesystem>
+.br
+.B lfs quotaon [-ugf] <filesystem>
+.br
+.B lfs quotaoff [-ug] <filesystem>
+.br
+.B lfs setquota [-u|-g] <name> <block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> <filesystem>
+.br
+.B lfs quota [-o obd_uuid] [-u|-g] <name> <filesystem>
+.br
+.B lfs setstripe <filename> <stripe-size> <start-ost> <stripe-cnt>
+.br
 .B lfs check <mds| osts| servers>
 .SH DESCRIPTION
 .B lfs
@@ -29,6 +43,24 @@ To list the extended attributes for a given filename or files in a directory or
 .B getstripe 
 To list the striping pattern for given filename
 .TP
+.B quotachown
+To change files' owner and group on OSTs of the specified filesystem
+.TP
+.B quotacheck
+To scan the specified filesystem for disk usage, and create or update quota files
+.TP
+.B quotaon
+To turn filesystem quotas on
+.TP
+.B quotaoff
+To turn filesystem quotas off
+.TP
+.B setquota
+To set filesystem quotas
+.TP
+.B quota
+To display disk usage and limits
+.TP
 .B check 
 Display the status of MDS or OSTs (as specified in the command) or all the servers (MDS and OSTs)
 .TP
@@ -57,6 +89,26 @@ Recursively list the extended attributes of all files in a given directory tree
 .B $lfs find -r --obd OST2-UUID /mnt/lustre/
 List all the files that have objects on a specific OST
 .TP
+.B $lfs quotachown -i /mnt/lustre
+Change file owner and group
+.TP
+.B $lfs quotacheck -ug /mnt/lustre
+Quotacheck for user and group
+.TP
+.B $lfs quotaon -ug /mnt/lustre
+Turn quotas of user and group on
+.TP
+.B $lfs quotaoff -ug /mnt/lustre
+Turn quotas of user and group off
+.TP
+.B $lfs setquota -u bob 0 1000000 0 10000 /mnt/lustre
+Set quotas of user `bob': 1GB block quota and 10,000 file quota
+.TP
+.B $lfs quota -u bob /mnt/lustre
+List quotas of user `bob'
+.TP
+.B $ lfs find -r --obd OST2-UUID /mnt/lustre/
+.TP
 .B $lfs check servers 
 Check the status of all servers(mds, osts)
 .TP
index 091c043..8e08a86 100644 (file)
@@ -32,7 +32,8 @@ LFS
 NAME
 \layout Description
 
-lfs Lustre utility to create a file with specific striping pattern
+lfs Lustre utility to create a file with specific striping pattern and manipulat
+e disk quotas
 \layout Subsection
 
 SYNOPSIS
@@ -70,6 +71,43 @@ setstripe -d <dirname>
 \series bold 
 lfs\SpecialChar ~
 check <mds| osts| servers>
+\layout Standard
+
+
+\series bold 
+lfs\SpecialChar ~
+quotachog [-i] <filesystem>
+\layout Standard
+
+
+\series bold 
+lfs\SpecialChar ~
+quotacheck [-ug] <filesystem>
+\layout Standard
+
+
+\series bold 
+lfs\SpecialChar ~
+quotaon [-ugf] <filesystem>
+\layout Standard
+
+
+\series bold 
+lfs\SpecialChar ~
+quotaoff [-ug] <filesystem>
+\layout Standard
+
+
+\series bold 
+lfs\SpecialChar ~
+setquota [-u|-g] <name> <block-softlimit> <block-hardlimit> <inode-softlimit>
+ <inode-hardlimit> <filesystem>
+\layout Standard
+
+
+\series bold 
+lfs\SpecialChar ~
+quota [-o obd_uuid] [-u|-g] <name> <filesystem>
 \layout Subsection
 
 DESCRIPTION
@@ -77,7 +115,8 @@ DESCRIPTION
 
 This utility can be used to create a new file with a specific striping pattern,
  determine the default striping pattern, gather the extended attributes
- (object numbers and location) for a specific file.
+ (object numbers and location) for a specific file, and manipulate disk
+ quotas.
  It can be invoked interactively without any arguments or in a non-interactive
  mode with one of the arguements listed and explained below:
 \layout List
@@ -129,6 +168,55 @@ osts
 
 
 \series bold 
+quotachog
+\series default 
+ Change files' owner and group on OSTs of the specified filesystem
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold 
+quotacheck
+\series default 
+ Scan the specified filesystem for disk usage, and create or update quota
+ files
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold 
+quotaon
+\series default 
+ Turn filesystem quotas on
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold 
+quotaoff
+\series default 
+ Turn filesystem quotas off
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold 
+setquota
+\series default 
+ Set filesystem quotas
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold 
+quota
+\series default 
+ Display disk usage and limits
+\layout List
+\labelwidthstring 00.00.0000
+
+
+\series bold 
 help
 \series default 
  Provides brief help on the various arguments
@@ -239,6 +327,77 @@ List all the OSTs
 \layout LyX-Code
 
    $
+\layout Description
+
+Change\SpecialChar ~
+file\SpecialChar ~
+owner\SpecialChar ~
+and\SpecialChar ~
+group
+\layout LyX-Code
+
+   $lfs quotachog -i /mnt/lustre
+\layout Description
+
+Quotacheck\SpecialChar ~
+for\SpecialChar ~
+user\SpecialChar ~
+and\SpecialChar ~
+group
+\layout LyX-Code
+
+   $lfs quotacheck -ug /mnt/lustre
+\layout Description
+
+Turn\SpecialChar ~
+quotas\SpecialChar ~
+of\SpecialChar ~
+user\SpecialChar ~
+and\SpecialChar ~
+group\SpecialChar ~
+on
+\layout LyX-Code
+
+   $lfs quotaon -ug /mnt/lustre
+\layout Description
+
+Turn\SpecialChar ~
+quotas\SpecialChar ~
+of\SpecialChar ~
+user\SpecialChar ~
+and\SpecialChar ~
+group\SpecialChar ~
+off
+\layout LyX-Code
+
+   $lfs quotaoff -ug /mnt/lustre
+\layout Description
+
+Set\SpecialChar ~
+quotas\SpecialChar ~
+of\SpecialChar ~
+user\SpecialChar ~
+`bob':\SpecialChar ~
+1GB\SpecialChar ~
+block\SpecialChar ~
+quota\SpecialChar ~
+and\SpecialChar ~
+10,000\SpecialChar ~
+file\SpecialChar ~
+quota
+\layout LyX-Code
+
+   $lfs setquota -u bob 0 1000000 0 10000 /mnt/lustre
+\layout Description
+
+List\SpecialChar ~
+quotas\SpecialChar ~
+of\SpecialChar ~
+user\SpecialChar ~
+`bob'
+\layout LyX-Code
+
+   $lfs quota -u bob /mnt/lustre
 \layout Subsection
 
 BUGS
index e5260f1..6169d34 100644 (file)
@@ -172,8 +172,10 @@ static inline int cleanup_group_info(void)
 #define hlist_node                      list_head
 #define HLIST_HEAD                      LIST_HEAD
 #define INIT_HLIST_HEAD                 INIT_LIST_HEAD
+#define INIT_HLIST_NODE(p)              (p)                 
 #define hlist_del_init                  list_del_init
 #define hlist_add_head                  list_add
+#define hlist_for_each                  list_for_each
 #define hlist_for_each_safe             list_for_each_safe
 #endif
 #define KDEVT_INIT(val)                 (val)
index a446c65..ebb798b 100644 (file)
@@ -94,7 +94,7 @@ struct fsfilt_operations {
         int     (* fs_quotactl)(struct super_block *sb,
                                 struct obd_quotactl *oqctl);
         int     (* fs_quotainfo)(struct lustre_quota_info *lqi, int type,
-                                 int cmd);
+                                 int cmd, struct list_head *list);
         int     (* fs_dquot)(struct lustre_dquot *dquot, int cmd);
 };
 
@@ -327,10 +327,10 @@ static inline int fsfilt_quotactl(struct obd_device *obd,
 
 static inline int fsfilt_quotainfo(struct obd_device *obd,
                                    struct lustre_quota_info *lqi,
-                                   int type, int cmd)
+                                   int type, int cmd, struct list_head *list)
 {
         if (obd->obd_fsops->fs_quotainfo)
-                return obd->obd_fsops->fs_quotainfo(lqi, type, cmd);
+                return obd->obd_fsops->fs_quotainfo(lqi, type, cmd, list);
         return -ENOTSUPP;
 }
 
index f7807c2..b7fc6aa 100644 (file)
@@ -620,28 +620,6 @@ struct mds_body {
 
 extern void lustre_swab_mds_body (struct mds_body *b);
 
-/* XXX: same as if_dqinfo struct in kernel */
-struct obd_dqinfo {
-        __u64 dqi_bgrace;
-        __u64 dqi_igrace;
-        __u32 dqi_flags;
-        __u32 dqi_valid;
-};
-
-/* XXX: same as if_dqblk struct in kernel, plus one padding */
-struct obd_dqblk {
-        __u64 dqb_bhardlimit;
-        __u64 dqb_bsoftlimit;
-        __u64 dqb_curspace;
-        __u64 dqb_ihardlimit;
-        __u64 dqb_isoftlimit;
-        __u64 dqb_curinodes;
-        __u64 dqb_btime;
-        __u64 dqb_itime;
-        __u32 dqb_valid;
-        __u32 padding;
-};
-
 #define Q_QUOTACHECK    0x800100
 #define Q_INITQUOTA     0x800101        /* init slave limits */
 #define Q_GETOINFO      0x800102        /* get obd quota info */
@@ -1201,10 +1179,10 @@ extern void lustre_swab_lustre_cfg(struct lustre_cfg *lcfg);
 
 /* qutoa */
 struct qunit_data {
-        __u32 qd_id;
-        __u32 qd_type;
-        __u32 qd_count;
-        __u32 qd_isblk; /* indicating if it's block quota */
+        __u32 qd_id;    /* ID appiles to (uid, gid) */
+        __u32 qd_type;  /* Quota type (USRQUOTA, GRPQUOTA) */
+        __u32 qd_count; /* acquire/release count (bytes for block quota) */
+        __u32 qd_isblk; /* Block quota or file quota */
 };
 extern void lustre_swab_qdata(struct qunit_data *d);
 
index 4cb00a5..d53a259 100644 (file)
@@ -68,11 +68,6 @@ struct llog_handle {
         } u;
 };
 
-struct llog_fill_rec_data {
-        obd_id          lfd_id;         /* object id */
-        obd_count       lfd_ogen;       /* object group */
-};
-
 /* llog.c  -  general API */
 typedef int (*llog_cb_t)(struct llog_handle *, struct llog_rec_hdr *, void *);
 typedef int (*llog_fill_rec_cb_t)(struct llog_rec_hdr *rec, void *data);
@@ -112,7 +107,7 @@ int llog_cleanup(struct llog_ctxt *);
 int llog_sync(struct llog_ctxt *ctxt, struct obd_export *exp);
 int llog_add(struct llog_ctxt *ctxt, struct llog_rec_hdr *rec,
              struct lov_stripe_md *lsm, struct llog_cookie *logcookies,
-             int numcookies, llog_fill_rec_cb_t fill_cb);
+             int numcookies);
 int llog_cancel(struct llog_ctxt *, struct lov_stripe_md *lsm,
                 int count, struct llog_cookie *cookies, int flags);
 
@@ -122,8 +117,7 @@ int llog_obd_origin_setup(struct obd_device *obd, int index,
 int llog_obd_origin_cleanup(struct llog_ctxt *ctxt);
 int llog_obd_origin_add(struct llog_ctxt *ctxt,
                         struct llog_rec_hdr *rec, struct lov_stripe_md *lsm,
-                        struct llog_cookie *logcookies, int numcookies,
-                        llog_fill_rec_cb_t fill_cb);
+                        struct llog_cookie *logcookies, int numcookies);
 
 int llog_cat_initialize(struct obd_device *obd, int count);
 int obd_llog_init(struct obd_device *obd, struct obd_device *disk_obd,
@@ -173,8 +167,7 @@ struct llog_operations {
         int (*lop_cleanup)(struct llog_ctxt *ctxt);
         int (*lop_add)(struct llog_ctxt *ctxt, struct llog_rec_hdr *rec,
                        struct lov_stripe_md *lsm,
-                       struct llog_cookie *logcookies, int numcookies,
-                       llog_fill_rec_cb_t fill_cb);
+                       struct llog_cookie *logcookies, int numcookies);
         int (*lop_cancel)(struct llog_ctxt *ctxt, struct lov_stripe_md *lsm,
                           int count, struct llog_cookie *cookies, int flags);
         int (*lop_connect)(struct llog_ctxt *ctxt, int count,
index a28c618..3c5f547 100644 (file)
@@ -5,23 +5,91 @@
 #define _LUSTRE_QUOTA_H
 
 #ifdef __KERNEL__
-# include <linux/version.h>
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <linux/quota.h>
+#include <linux/quotaops.h>
 #endif
 #include <linux/lustre_idl.h>
+#include <linux/lustre_net.h>
+#include <linux/lvfs.h>
+
+struct obd_device;
+struct client_obd;
+
+#ifndef NR_DQHASH
+#define NR_DQHASH 45
+#endif
 
 #ifdef HAVE_QUOTA_SUPPORT
-#include <linux/lustre_realquota.h>
-#else
 
+#ifdef __KERNEL__
+
+/* structures to access admin quotafile */
 struct lustre_mem_dqinfo {
+        unsigned int dqi_bgrace;
+        unsigned int dqi_igrace;
+        unsigned long dqi_flags;
+        unsigned int dqi_blocks;
+        unsigned int dqi_free_blk;
+        unsigned int dqi_free_entry;
 };
 
 struct lustre_quota_info {
+        struct file *qi_files[MAXQUOTAS];
+        struct lustre_mem_dqinfo qi_info[MAXQUOTAS];
 };
 
+#define DQ_STATUS_AVAIL         0x0     /* Available dquot */
+#define DQ_STATUS_SET           0x01    /* Sombody is setting dquot */
+#define DQ_STATUS_RECOVERY      0x02    /* dquot is in recovery */
+
 struct lustre_dquot {
+        /* Hash list in memory, protect by dquot_hash_lock */
+        struct list_head dq_hash;
+        /* Protect the data in lustre_dquot */
+        struct semaphore dq_sem;
+        /* Use count */
+        int dq_refcnt;
+        /* Pointer of quota info it belongs to */
+        struct lustre_quota_info *dq_info;
+        
+        loff_t dq_off;                  /* Offset of dquot on disk */
+        unsigned int dq_id;             /* ID this applies to (uid, gid) */
+        int dq_type;                    /* Type fo quota (USRQUOTA, GRPQUOUTA) */
+        unsigned short dq_status;       /* See DQ_STATUS_ */
+        unsigned long dq_flags;         /* See DQ_ in quota.h */
+        struct mem_dqblk dq_dqb;        /* Diskquota usage */
 };
 
+struct dquot_id {
+        struct list_head        di_link;
+        __u32                   di_id;
+};
+
+#define QFILE_CHK               1
+#define QFILE_RD_INFO           2
+#define QFILE_WR_INFO           3
+#define QFILE_INIT_INFO         4
+#define QFILE_GET_QIDS          5
+#define QFILE_RD_DQUOT          6
+#define QFILE_WR_DQUOT          7
+
+/* admin quotafile operations */
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)
+int lustre_check_quota_file(struct lustre_quota_info *lqi, int type);
+int lustre_read_quota_info(struct lustre_quota_info *lqi, int type);
+int lustre_write_quota_info(struct lustre_quota_info *lqi, int type);
+int lustre_read_dquot(struct lustre_dquot *dquot);
+int lustre_commit_dquot(struct lustre_dquot *dquot);
+int lustre_init_quota_info(struct lustre_quota_info *lqi, int type);
+int lustre_get_qids(struct lustre_quota_info *lqi, int type, 
+                    struct list_head *list);
+#else
+
+#ifndef DQ_FAKE_B
+#define DQ_FAKE_B       6
+#endif
 
 static inline int lustre_check_quota_file(struct lustre_quota_info *lqi,
                                           int type)
@@ -38,7 +106,6 @@ static inline int lustre_write_quota_info(struct lustre_quota_info *lqi,
 {
         return 0;
 }
-#ifdef __KERNEL__
 static inline int lustre_read_dquot(struct lustre_dquot *dquot)
 {
         return 0;
@@ -47,51 +114,283 @@ static inline int lustre_commit_dquot(struct lustre_dquot *dquot)
 {
         return 0;
 }
-#endif
 static inline int lustre_init_quota_info(struct lustre_quota_info *lqi,
                                          int type)
 {
         return 0;
 }
+#endif  /* KERNEL_VERSION(2,5,0) */
 
-struct obd_device;
+#define LL_DQUOT_OFF(sb)    DQUOT_OFF(sb)
 
 typedef int (*dqacq_handler_t) (struct obd_device * obd, struct qunit_data * qd,
                                 int opc);
+struct lustre_quota_ctxt {
+        struct super_block *lqc_sb;     /* superblock this applies to */
+        struct obd_import *lqc_import;  /* import used to send dqacq/dqrel RPC */
+        dqacq_handler_t lqc_handler;    /* dqacq/dqrel RPC handler, only for quota master */ 
+        unsigned long lqc_recovery:1;   /* Doing recovery */ 
+        unsigned long lqc_iunit_sz;     /* Unit size of file quota */
+        unsigned long lqc_itune_sz;     /* Trigger dqacq when available file quota less than
+                                         * this value, trigger dqrel when available file quota
+                                         * more than this value + 1 iunit */
+        unsigned long lqc_bunit_sz;     /* Unit size of block quota */
+        unsigned long lqc_btune_sz;     /* See comment of lqc_itune_sz */
+};
+
+#else
+
+struct lustre_quota_info {
+};
+
+struct lustre_quota_ctxt {
+};
+
+#endif  /* !__KERNEL__ */
+
+#else
+
+#define LL_DQUOT_OFF(sb) do {} while(0)
+
+struct lustre_quota_info {
+};
 
 struct lustre_quota_ctxt {
 };
 
-struct lustre_qunit {
+#endif /* !HAVE_QUOTA_SUPPORT */
+
+/* If the (quota limit < qunit * slave count), the slave which can't
+ * acquire qunit should set it's local limit as MIN_QLIMIT */
+#define MIN_QLIMIT      1
+
+struct quotacheck_thread_args {
+        struct obd_export   *qta_exp;   /* obd export */
+        struct obd_quotactl  qta_oqctl; /* obd_quotactl args */
+        struct super_block  *qta_sb;    /* obd super block */
+        atomic_t            *qta_sem;   /* obt_quotachecking */
 };
 
-struct super_block;
-static inline int qctxt_init(struct lustre_quota_ctxt *qctxt,
-                             struct super_block *sb, dqacq_handler_t handler)
+typedef struct {
+        int (*quota_init) (void);
+        int (*quota_exit) (void);
+        int (*quota_setup) (struct obd_device *, struct lustre_cfg *);
+        int (*quota_cleanup) (struct obd_device *);
+        /* For quota master, close admin quota files */
+        int (*quota_fs_cleanup) (struct obd_device *);
+        int (*quota_ctl) (struct obd_export *, struct obd_quotactl *);
+        int (*quota_check) (struct obd_export *, struct obd_quotactl *);
+        int (*quota_recovery) (struct obd_device *);
+        
+        /* For quota master/slave, adjust quota limit after fs operation */
+        int (*quota_adjust) (struct obd_device *, unsigned int[], 
+                             unsigned int[], int, int); 
+        
+        /* For quota slave, set import, trigger quota recovery */
+        int (*quota_setinfo) (struct obd_export *, struct obd_device *);
+        
+        /* For quota slave, set proper thread resoure capability */
+        int (*quota_enforce) (struct obd_device *, unsigned int);
+        
+        /* For quota slave, check whether specified uid/gid is over quota */
+        int (*quota_getflag) (struct obd_device *, struct obdo *);
+        
+        /* For quota slave, acquire/release quota from master if needed */
+        int (*quota_acquire) (struct obd_device *, unsigned int, unsigned int);
+        
+        /* For quota client, poll if the quota check done */
+        int (*quota_poll_check) (struct obd_export *, struct if_quotacheck *);
+        
+        /* For quota client, check whether specified uid/gid is over quota */
+        int (*quota_chkdq) (struct client_obd *, unsigned int, unsigned int);
+        
+        /* For quota client, set over quota flag for specifed uid/gid */
+        int (*quota_setdq) (struct client_obd *, unsigned int, unsigned int,
+                            obd_flag, obd_flag);
+} quota_interface_t;
+
+#define Q_COPY(out, in, member) (out)->member = (in)->member
+
+#define QUOTA_OP(interface, op) interface->quota_ ## op         
+
+#define QUOTA_CHECK_OP(interface, op)                           \
+do {                                                            \
+        if (!interface)                                         \
+                RETURN(0);                                      \
+        if (!QUOTA_OP(interface, op)) {                         \
+                CERROR("no quota operation: " #op "\n");        \
+                RETURN(-EOPNOTSUPP);                            \
+        }                                                       \
+} while(0)
+
+static inline int lquota_init(quota_interface_t *interface)
 {
-        return 0;
+        int rc;
+        ENTRY;
+        
+        QUOTA_CHECK_OP(interface, init);
+        rc = QUOTA_OP(interface, init)();
+        RETURN(rc);
 }
-static inline void qctxt_cleanup(struct lustre_quota_ctxt *qctxt, int force)
+
+static inline int lquota_exit(quota_interface_t *interface) 
 {
-        return;
+        int rc;
+        ENTRY;
+        
+        QUOTA_CHECK_OP(interface, exit);
+        rc = QUOTA_OP(interface, exit)();
+        RETURN(rc);
 }
-static inline int qctxt_adjust_qunit(struct obd_device *obd,
-                                     struct lustre_quota_ctxt *qctxt,
-                                     uid_t uid, gid_t gid, __u32 isblk)
+
+static inline int lquota_setup(quota_interface_t *interface,
+                               struct obd_device *obd, 
+                               struct lustre_cfg *lcfg) 
 {
-        return 0;
+        int rc;
+        ENTRY;
+        
+        QUOTA_CHECK_OP(interface, setup);
+        rc = QUOTA_OP(interface, setup)(obd, lcfg);
+        RETURN(rc);
 }
-static inline int qctxt_wait_on_dqacq(struct obd_device *obd,
-                                      struct lustre_quota_ctxt *qctxt,
-                                      uid_t uid, gid_t gid, __u32 isblk)
+
+static inline int lquota_cleanup(quota_interface_t *interface,
+                                 struct obd_device *obd) 
 {
-        return 0;
+        int rc;
+        ENTRY;
+        
+        QUOTA_CHECK_OP(interface, cleanup);
+        rc = QUOTA_OP(interface, cleanup)(obd);
+        RETURN(rc);
 }
 
-struct quotacheck_info {
-};
+static inline int lquota_fs_cleanup(quota_interface_t *interface,
+                                    struct obd_device *obd)
+{
+        int rc;
+        ENTRY;
+        
+        QUOTA_CHECK_OP(interface, fs_cleanup);
+        rc = QUOTA_OP(interface, fs_cleanup)(obd);
+        RETURN(rc);
+}
 
-#define LL_DQUOT_OFF(sb) do {} while(0)
+static inline int lquota_recovery(quota_interface_t *interface,
+                                  struct obd_device *obd) 
+{        
+        int rc;
+        ENTRY;
+        
+        QUOTA_CHECK_OP(interface, recovery);
+        rc = QUOTA_OP(interface, recovery)(obd);
+        RETURN(rc);
+}
+
+static inline int lquota_adjust(quota_interface_t *interface,
+                                struct obd_device *obd, 
+                                unsigned int qcids[], 
+                                unsigned int qpids[], 
+                                int rc, int opc) 
+{
+        int ret;
+        ENTRY;
+        
+        QUOTA_CHECK_OP(interface, adjust);
+        ret = QUOTA_OP(interface, adjust)(obd, qcids, qpids, rc, opc);
+        RETURN(ret);
+}
+
+static inline int lquota_chkdq(quota_interface_t *interface,
+                               struct client_obd *cli,
+                               unsigned int uid, unsigned int gid)
+{
+        int rc;
+        ENTRY;
+        
+        QUOTA_CHECK_OP(interface, chkdq);
+        rc = QUOTA_OP(interface, chkdq)(cli, uid, gid);
+        RETURN(rc);
+}
+
+static inline int lquota_setdq(quota_interface_t *interface,
+                               struct client_obd *cli,
+                               unsigned int uid, unsigned int gid,
+                               obd_flag valid, obd_flag flags)
+{
+        int rc;
+        ENTRY;
+        
+        QUOTA_CHECK_OP(interface, setdq);
+        rc = QUOTA_OP(interface, setdq)(cli, uid, gid, valid, flags);
+        RETURN(rc);
+}
+
+static inline int lquota_poll_check(quota_interface_t *interface,
+                                    struct obd_export *exp,
+                                    struct if_quotacheck *qchk)
+{
+        int rc;
+        ENTRY;
+        
+        QUOTA_CHECK_OP(interface, poll_check);
+        rc = QUOTA_OP(interface, poll_check)(exp, qchk);
+        RETURN(rc);
+}
+
+       
+static inline int lquota_setinfo(quota_interface_t *interface,
+                                 struct obd_export *exp, 
+                                 struct obd_device *obd) 
+{
+        int rc;
+        ENTRY;
+
+        QUOTA_CHECK_OP(interface, setinfo);
+        rc = QUOTA_OP(interface, setinfo)(exp, obd);
+        RETURN(rc);
+}
+
+static inline int lquota_enforce(quota_interface_t *interface, 
+                                 struct obd_device *obd,
+                                 unsigned int ignore)
+{
+        int rc;
+        ENTRY;
+
+        QUOTA_CHECK_OP(interface, enforce);
+        rc = QUOTA_OP(interface, enforce)(obd, ignore);
+        RETURN(rc);
+}
+
+static inline int lquota_getflag(quota_interface_t *interface,
+                                 struct obd_device *obd, struct obdo *oa)
+{
+        int rc;
+        ENTRY;
+
+        QUOTA_CHECK_OP(interface, getflag);
+        rc = QUOTA_OP(interface, getflag)(obd, oa);
+        RETURN(rc);
+}
+        
+static inline int lquota_acquire(quota_interface_t *interface,
+                                 struct obd_device *obd, 
+                                 unsigned int uid, unsigned int gid)
+{
+        int rc;
+        ENTRY;
+
+        QUOTA_CHECK_OP(interface, acquire);
+        rc = QUOTA_OP(interface, acquire)(obd, uid, gid);
+        RETURN(rc);
+}
+
+#ifndef __KERNEL__
+extern quota_interface_t osc_quota_interface;
+extern quota_interface_t mdc_quota_interface;
+extern quota_interface_t lov_quota_interface;
+#endif
 
-#endif /*!HAVE_QUOTA_SUPPORT */
 #endif /* _LUSTRE_QUOTA_H */
index 86c150b..7daf6f5 100644 (file)
@@ -180,6 +180,13 @@ struct obd_histogram {
 
 struct ost_server_data;
 
+/* hold common fields for "target" device */
+struct obd_device_target {
+        struct super_block       *obt_sb;
+        atomic_t                  obt_quotachecking;
+        struct lustre_quota_ctxt  obt_qctxt;
+};
+
 #define FILTER_GROUP_LLOG 1
 #define FILTER_GROUP_ECHO 2
 
@@ -189,8 +196,9 @@ struct filter_ext {
 };
 
 struct filter_obd {
+        /* NB this field MUST be first */
+        struct obd_device_target fo_obt;
         const char          *fo_fstype;
-        struct super_block  *fo_sb;
         struct vfsmount     *fo_vfsmnt;
         struct dentry       *fo_dentry_O;
         struct dentry      **fo_dentry_O_groups;
@@ -284,11 +292,6 @@ struct mds_server_data;
 #define OSC_MAX_DIRTY_DEFAULT    32
 #define OSC_MAX_DIRTY_MB_MAX    512     /* totally arbitrary */
 
-enum {
-        CL_QUOTACHECKING = 1,
-        CL_NO_QUOTACHECK
-};
-
 struct mdc_rpc_lock;
 struct client_obd {
         struct obd_import       *cl_import;
@@ -343,16 +346,18 @@ struct client_obd {
         struct osc_async_rc      cl_ar;
 
         /* used by quotacheck */
-        spinlock_t               cl_qchk_lock;
         int                      cl_qchk_stat; /* quotacheck stat of the peer */
         struct ptlrpc_request_pool *cl_rq_pool; /* emergency pool of requests */
 };
 
+#define CL_NOT_QUOTACHECKED 1   /* client->cl_qchk_stat init value */
+
 struct mds_obd {
+        /* NB this field MUST be first */
+        struct obd_device_target         mds_obt;
         struct ptlrpc_service           *mds_service;
         struct ptlrpc_service           *mds_setattr_service;
         struct ptlrpc_service           *mds_readpage_service;
-        struct super_block              *mds_sb;
         struct vfsmount                 *mds_vfsmnt;
         struct dentry                   *mds_fid_de;
         int                              mds_max_mdsize;
@@ -382,9 +387,9 @@ struct mds_obd {
         unsigned long                   *mds_client_bitmap;
         struct semaphore                 mds_orphan_recovery_sem;
         struct upcall_cache             *mds_group_hash;
+
         struct lustre_quota_info         mds_quota_info;
-        struct lustre_quota_ctxt         mds_quota_ctxt;
-        atomic_t                         mds_quotachecking;
+        struct semaphore                 mds_qonoff_sem;
         struct semaphore                 mds_health_sem;
         unsigned long                    mds_lov_objids_valid:1,
                                          mds_fl_user_xattr:1,
@@ -594,6 +599,7 @@ struct obd_device {
         time_t                           obd_recovery_end;
 
         union {
+                struct obd_device_target obt;
                 struct filter_obd filter;
                 struct mds_obd mds;
                 struct client_obd cli;
@@ -797,4 +803,15 @@ static inline void obd_transno_commit_cb(struct obd_device *obd, __u64 transno,
         }
 }
 
+static inline void init_obd_quota_ops(quota_interface_t *interface,
+                                      struct obd_ops *obd_ops)
+{
+        if (!interface)
+                return;
+
+        LASSERT(obd_ops);
+        obd_ops->o_quotacheck = QUOTA_OP(interface, check);
+        obd_ops->o_quotactl = QUOTA_OP(interface, ctl);
+}
+
 #endif /* __OBD_H */
index b89063c..38d7da4 100644 (file)
@@ -1102,11 +1102,6 @@ static inline struct obdo *obdo_alloc(void)
         return oa;
 }
 
-/* qunit hash stuff */
-extern kmem_cache_t *qunit_cachep;
-extern struct list_head qunit_hash[];
-extern spinlock_t qunit_hash_lock;
-
 static inline void obdo_free(struct obdo *oa)
 {
         OBD_SLAB_FREE(oa, obdo_cachep, sizeof(*oa));
index 32b9852..0b15af6 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/obd_class.h>
 
+#define LUSTRE_FILTER_NAME "obdfilter"
 #define LUSTRE_OST_NAME "ost"
 #define LUSTRE_OSC_NAME "osc"
 #define LUSTRE_SANOSC_NAME "sanosc"
index 812143d..2ab3d1f 100644 (file)
@@ -163,6 +163,7 @@ extern wait_queue_head_t obd_race_waitq;
 #define OBD_FAIL_OBD_LOG_CANCEL_NET      0x601
 #define OBD_FAIL_OBD_LOGD_NET            0x602
 #define OBD_FAIL_OBD_QC_CALLBACK_NET     0x603
+#define OBD_FAIL_OBD_DQACQ               0x604
 
 #define OBD_FAIL_TGT_REPLY_NET           0x700
 #define OBD_FAIL_TGT_CONN_RACE           0x701
index 6527f40..35da48d 100644 (file)
@@ -8,6 +8,8 @@
 
 #include <lustre/lustre_user.h>
 
+typedef void (*llapi_cb_t)(char *obd_type_name, char *obd_name, char *obd_uuid, void *args);
+
 /* liblustreapi.c */
 extern int llapi_file_create(char *name, long stripe_size, int stripe_offset,
                              int stripe_count, int stripe_pattern);
@@ -19,8 +21,9 @@ extern int llapi_target_check(int num_types, char **obd_types, char *dir);
 extern int llapi_catinfo(char *dir, char *keyword, char *node_name);
 extern int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count);
 extern int llapi_is_lustre_mnttype(char *type);
+extern int llapi_quotachown(char *path, int flag);
 extern int llapi_quotacheck(char *mnt, int check_type);
 extern int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk);
 extern int llapi_quotactl(char *mnt, struct if_quotactl *qctl);
-extern int llapi_quotachog(char *path, int flag);
+extern int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb);
 #endif
index 8aa9939..4d85bfb 100644 (file)
@@ -139,14 +139,20 @@ static inline void obd_str2uuid(struct obd_uuid *uuid, char *tmp)
         uuid->uuid[sizeof(*uuid) - 1] = '\0';
 }
 
+#define LUSTRE_Q_QUOTAON  0x800002     /* turn quotas on */
+#define LUSTRE_Q_QUOTAOFF 0x800003     /* turn quotas off */
+#define LUSTRE_Q_GETINFO  0x800005     /* get information about quota files */
+#define LUSTRE_Q_SETINFO  0x800006     /* set information about quota files */
+#define LUSTRE_Q_GETQUOTA 0x800007     /* get user quota structure */
+#define LUSTRE_Q_SETQUOTA 0x800008     /* set user quota structure */
+
 #define UGQUOTA 2       /* set both USRQUOTA and GRPQUOTA */
 
 #define QFMT_LDISKFS 2  /* QFMT_VFS_V0(2), quota format for ldiskfs */
 
 struct if_quotacheck {
-        char                    obd_type[10];
+        __u8                    obd_type[16];
         struct obd_uuid         obd_uuid;
-        int                     stat;
 };
 
 #define MDS_GRP_DOWNCALL_MAGIC 0x6d6dd620
@@ -170,8 +176,6 @@ struct mds_grp_downcall_data {
 # endif
 #endif
 
-#ifdef HAVE_QUOTA_SUPPORT
-
 #ifdef NEED_QUOTA_DEFS
 #ifndef QUOTABLOCK_BITS
 #define QUOTABLOCK_BITS 10
@@ -185,18 +189,31 @@ struct mds_grp_downcall_data {
 #define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS)
 #endif
 
-/* XXX: these two structs should be in /usr/include/linux/quota.h */
-#ifndef HAVE_STRUCT_IF_DQINFO
-struct if_dqinfo {
+#ifndef QIF_BLIMITS
+#define QIF_BLIMITS     1
+#define QIF_SPACE       2
+#define QIF_ILIMITS     4
+#define QIF_INODES      8
+#define QIF_BTIME       16
+#define QIF_ITIME       32
+#define QIF_LIMITS      (QIF_BLIMITS | QIF_ILIMITS)
+#define QIF_USAGE       (QIF_SPACE | QIF_INODES)
+#define QIF_TIMES       (QIF_BTIME | QIF_ITIME)
+#define QIF_ALL         (QIF_LIMITS | QIF_USAGE | QIF_TIMES)
+#endif
+
+#endif /* !__KERNEL__ */
+
+/* XXX: same as if_dqinfo struct in kernel */
+struct obd_dqinfo {
         __u64 dqi_bgrace;
         __u64 dqi_igrace;
         __u32 dqi_flags;
         __u32 dqi_valid;
 };
-#endif
 
-#ifndef HAVE_STRUCT_IF_DQBLK
-struct if_dqblk {
+/* XXX: same as if_dqblk struct in kernel, plus one padding */
+struct obd_dqblk {
         __u64 dqb_bhardlimit;
         __u64 dqb_bsoftlimit;
         __u64 dqb_curspace;
@@ -206,42 +223,20 @@ struct if_dqblk {
         __u64 dqb_btime;
         __u64 dqb_itime;
         __u32 dqb_valid;
+        __u32 padding;
 };
-#endif
-
-#ifndef QIF_BLIMITS
-#define QIF_BLIMITS     1
-#define QIF_SPACE       2
-#define QIF_ILIMITS     4
-#define QIF_INODES      8
-#define QIF_BTIME       16
-#define QIF_ITIME       32
-#define QIF_LIMITS      (QIF_BLIMITS | QIF_ILIMITS)
-#define QIF_USAGE       (QIF_SPACE | QIF_INODES)
-#define QIF_TIMES       (QIF_BTIME | QIF_ITIME)
-#define QIF_ALL         (QIF_LIMITS | QIF_USAGE | QIF_TIMES)
-#endif
-
-#endif /* NEED_QUOTA_DEFS */
 
 struct if_quotactl {
-        int                     qc_cmd;
-        int                     qc_type;
-        int                     qc_id;
-        int                     qc_stat;
-        struct if_dqinfo        qc_dqinfo;
-        struct if_dqblk         qc_dqblk;
-        char                    obd_type[10];
+        __u32                   qc_cmd;
+        __u32                   qc_type;
+        __u32                   qc_id;
+        __u32                   qc_stat;
+        struct obd_dqinfo       qc_dqinfo;
+        struct obd_dqblk        qc_dqblk;
+        __u8                    obd_type[16];
         struct obd_uuid         obd_uuid;
 };
 
-#else
-
-struct if_quotactl {
-};
-
-#endif /* HAVE_QUOTA_SUPPORT */
-
 #ifndef LPU64
 /* x86_64 defines __u64 as "long" in userspace, but "long long" in the kernel */
 #if defined(__x86_64__) && defined(__KERNEL__)
index 30aab18..e7685c2 100644 (file)
@@ -480,7 +480,9 @@ CONFIG_FS_POSIX_ACL=y
 # CONFIG_XFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_ROMFS_FS is not set
-# CONFIG_QUOTA is not set
+CONFIG_QUOTA=y
+CONFIG_QFMT_V2=y
+CONFIG_QUOTACTL=y
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 CONFIG_AUTOFS4_FS=m
index 6ec26cd..25f7954 100644 (file)
@@ -252,7 +252,7 @@ Index: linux-bgl/kernel/kallsyms.c
 +   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 +  */
 +
-+#ident "$Id: kallsyms-2.4-bgl.patch,v 1.1.20.1 2005/03/24 22:50:28 jacob Exp $"
++#ident "$Id: kallsyms-2.4-bgl.patch,v 1.1.20.2 2005/04/01 21:30:19 green Exp $"
 +
 +/*
 +   This code uses the list of all kernel and module symbols to :-
@@ -568,7 +568,7 @@ Index: linux-bgl/include/linux/kallsyms.h
 +   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 + */
 +
-+#ident "$Id: kallsyms-2.4-bgl.patch,v 1.1.20.1 2005/03/24 22:50:28 jacob Exp $"
++#ident "$Id: kallsyms-2.4-bgl.patch,v 1.1.20.2 2005/04/01 21:30:19 green Exp $"
 +
 +#ifndef MODUTILS_KALLSYMS_H
 +#define MODUTILS_KALLSYMS_H 1
index 2f0cdc7..92d9b6b 100644 (file)
@@ -1,6 +1,8 @@
 default: all
 
-MODULES := ldiskfs #quotafmt_test
+MODULES := ldiskfs
+
+@QUOTA_TRUE@MODULES += quotafmt_test
 
 # copy makefile over to not break patches
 ext3_extra := $(wildcard @LINUX@/fs/ext3/Makefile)
@@ -11,13 +13,16 @@ linux_headers := $(wildcard @LINUX@/include/linux/ext3*.h)
 ext3_sources := $(filter-out %.mod.c,$(wildcard @LINUX@/fs/ext3/*.c))
 new_sources := iopen.c iopen.h extents.c mballoc.c proc.c
 new_headers := ext3_extents.h
-#quotafmt_sources := lustre_quota_fmt.c
-#quotafmt_headers := lustre_quota_fmt.h
 ldiskfs_patched_sources := $(notdir $(ext3_sources) $(ext3_headers)) $(new_sources) $(new_headers)
-ldiskfs_sources := $(ldiskfs_patched_sources) #$(quotafmt_sources) $(quotafmt_headers)
+ldiskfs_sources := $(ldiskfs_patched_sources)
+
+quotafmt_sources := lustre_quota_fmt.c
+quotafmt_headers := lustre_quota_fmt.h
+@QUOTA_TRUE@ldiskfs_sources += $(quotafmt_sources) $(quotafmt_headers)
 
 ldiskfs-objs := $(filter %.o,$(ldiskfs_sources:.c=.o))
-#quotafmt-objs := quotafmt_test.o
+
+@QUOTA_TRUE@quotafmt-objs := quotafmt_test.o
 
 EXTRA_PRE_CFLAGS := -I@LINUX@/fs -I@LUSTRE@ -I@LUSTRE@/ldiskfs
 
index cf2a23f..82bd9a6 100644 (file)
@@ -7,7 +7,6 @@
  *  linux/fs/quota_v2.c
  */
 
-
 #ifndef EXPORT_SYMTAB
 # define EXPORT_SYMTAB
 #endif
@@ -32,155 +31,166 @@ typedef char *dqbuf_t;
 #define GETIDINDEX(id, depth) (((id) >> ((LUSTRE_DQTREEDEPTH-(depth)-1)*8)) & 0xff)
 #define GETENTRIES(buf) ((struct lustre_disk_dqblk *)(((char *)buf)+sizeof(struct lustre_disk_dqdbheader)))
 
+static int check_quota_file(struct file *f, int type)
+{
+        struct lustre_disk_dqheader dqhead;
+        mm_segment_t fs;
+        ssize_t size;
+        loff_t offset = 0;
+        static const uint quota_magics[] = LUSTRE_INITQMAGICS;
+        static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
+
+        fs = get_fs();
+        set_fs(KERNEL_DS);
+        size = f->f_op->read(f, (char *)&dqhead,
+                             sizeof(struct lustre_disk_dqheader), &offset);
+        set_fs(fs);
+        if (size != sizeof(struct lustre_disk_dqheader))
+                return 0;
+        if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
+            le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
+                return 0;
+        return 1;
+}
+
 /* Check whether given file is really lustre admin quotafile */
 int lustre_check_quota_file(struct lustre_quota_info *lqi, int type)
 {
-       struct lustre_disk_dqheader dqhead;
-       struct file *f = lqi->qi_files[type];
-       mm_segment_t fs;
-       ssize_t size;
-       loff_t offset = 0;
-       static const uint quota_magics[] = LUSTRE_INITQMAGICS;
-       static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
-
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       size = f->f_op->read(f, (char *)&dqhead, sizeof(struct lustre_disk_dqheader), &offset);
-       set_fs(fs);
-       if (size != sizeof(struct lustre_disk_dqheader))
-               return 0;
-       if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type] ||
-           le32_to_cpu(dqhead.dqh_version) != quota_versions[type])
-               return 0;
-       return 1;
+        struct file *f = lqi->qi_files[type];
+        return check_quota_file(f, type);
 }
 
 /* Read information header from quota file */
 int lustre_read_quota_info(struct lustre_quota_info *lqi, int type)
 {
-       mm_segment_t fs;
-       struct lustre_disk_dqinfo dinfo;
-       struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
-       struct file *f = lqi->qi_files[type];
-       ssize_t size;
-       loff_t offset = LUSTRE_DQINFOOFF;
-
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       size = f->f_op->read(f, (char *)&dinfo, sizeof(struct lustre_disk_dqinfo), &offset);
-       set_fs(fs);
-       if (size != sizeof(struct lustre_disk_dqinfo)) {
-               printk(KERN_WARNING "Can't read info structure on device %s.\n",
-                       f->f_vfsmnt->mnt_sb->s_id);
-               return -1;
-       }
-       info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
-       info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
-       info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
-       info->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
-       info->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
-       info->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
-       return 0;
+        mm_segment_t fs;
+        struct lustre_disk_dqinfo dinfo;
+        struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
+        struct file *f = lqi->qi_files[type];
+        ssize_t size;
+        loff_t offset = LUSTRE_DQINFOOFF;
+
+        fs = get_fs();
+        set_fs(KERNEL_DS);
+        size = f->f_op->read(f, (char *)&dinfo, 
+                             sizeof(struct lustre_disk_dqinfo), &offset);
+        set_fs(fs);
+        if (size != sizeof(struct lustre_disk_dqinfo)) {
+                printk(KERN_WARNING "Can't read info structure on device %s.\n",
+                       f->f_vfsmnt->mnt_sb->s_id);
+                return -1;
+        }
+        info->dqi_bgrace = le32_to_cpu(dinfo.dqi_bgrace);
+        info->dqi_igrace = le32_to_cpu(dinfo.dqi_igrace);
+        info->dqi_flags = le32_to_cpu(dinfo.dqi_flags);
+        info->dqi_blocks = le32_to_cpu(dinfo.dqi_blocks);
+        info->dqi_free_blk = le32_to_cpu(dinfo.dqi_free_blk);
+        info->dqi_free_entry = le32_to_cpu(dinfo.dqi_free_entry);
+        return 0;
 }
 
 /* Write information header to quota file */
 int lustre_write_quota_info(struct lustre_quota_info *lqi, int type)
 {
-       mm_segment_t fs;
-       struct lustre_disk_dqinfo dinfo;
-       struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
-       struct file *f = lqi->qi_files[type];
-       ssize_t size;
-       loff_t offset = LUSTRE_DQINFOOFF;
-
-       info->dqi_flags &= ~DQF_INFO_DIRTY;
-       dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
-       dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
-       dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
-       dinfo.dqi_blocks = cpu_to_le32(info->dqi_blocks);
-       dinfo.dqi_free_blk = cpu_to_le32(info->dqi_free_blk);
-       dinfo.dqi_free_entry = cpu_to_le32(info->dqi_free_entry);
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       size = f->f_op->write(f, (char *)&dinfo, sizeof(struct lustre_disk_dqinfo), &offset);
-       set_fs(fs);
-       if (size != sizeof(struct lustre_disk_dqinfo)) {
-               printk(KERN_WARNING "Can't write info structure on device %s.\n",
-                       f->f_vfsmnt->mnt_sb->s_id);
-               return -1;
-       }
-       return 0;
+        mm_segment_t fs;
+        struct lustre_disk_dqinfo dinfo;
+        struct lustre_mem_dqinfo *info = &lqi->qi_info[type];
+        struct file *f = lqi->qi_files[type];
+        ssize_t size;
+        loff_t offset = LUSTRE_DQINFOOFF;
+
+        info->dqi_flags &= ~DQF_INFO_DIRTY;
+        dinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
+        dinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
+        dinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK);
+        dinfo.dqi_blocks = cpu_to_le32(info->dqi_blocks);
+        dinfo.dqi_free_blk = cpu_to_le32(info->dqi_free_blk);
+        dinfo.dqi_free_entry = cpu_to_le32(info->dqi_free_entry);
+        fs = get_fs();
+        set_fs(KERNEL_DS);
+        size = f->f_op->write(f, (char *)&dinfo, 
+                              sizeof(struct lustre_disk_dqinfo), &offset);
+        set_fs(fs);
+        if (size != sizeof(struct lustre_disk_dqinfo)) {
+                printk(KERN_WARNING
+                       "Can't write info structure on device %s.\n",
+                       f->f_vfsmnt->mnt_sb->s_id);
+                return -1;
+        }
+        return 0;
 }
 
 static void disk2memdqb(struct mem_dqblk *m, struct lustre_disk_dqblk *d)
 {
-       m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
-       m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
-       m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
-       m->dqb_itime = le64_to_cpu(d->dqb_itime);
-       m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
-       m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
-       m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
-       m->dqb_btime = le64_to_cpu(d->dqb_btime);
+        m->dqb_ihardlimit = le32_to_cpu(d->dqb_ihardlimit);
+        m->dqb_isoftlimit = le32_to_cpu(d->dqb_isoftlimit);
+        m->dqb_curinodes = le32_to_cpu(d->dqb_curinodes);
+        m->dqb_itime = le64_to_cpu(d->dqb_itime);
+        m->dqb_bhardlimit = le32_to_cpu(d->dqb_bhardlimit);
+        m->dqb_bsoftlimit = le32_to_cpu(d->dqb_bsoftlimit);
+        m->dqb_curspace = le64_to_cpu(d->dqb_curspace);
+        m->dqb_btime = le64_to_cpu(d->dqb_btime);
 }
 
-static void mem2diskdqb(struct lustre_disk_dqblk *d, struct mem_dqblk *m, qid_t id)
+static void mem2diskdqb(struct lustre_disk_dqblk *d, struct mem_dqblk *m,
+                        qid_t id)
 {
-       d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
-       d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
-       d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
-       d->dqb_itime = cpu_to_le64(m->dqb_itime);
-       d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
-       d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
-       d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
-       d->dqb_btime = cpu_to_le64(m->dqb_btime);
-       d->dqb_id = cpu_to_le32(id);
+        d->dqb_ihardlimit = cpu_to_le32(m->dqb_ihardlimit);
+        d->dqb_isoftlimit = cpu_to_le32(m->dqb_isoftlimit);
+        d->dqb_curinodes = cpu_to_le32(m->dqb_curinodes);
+        d->dqb_itime = cpu_to_le64(m->dqb_itime);
+        d->dqb_bhardlimit = cpu_to_le32(m->dqb_bhardlimit);
+        d->dqb_bsoftlimit = cpu_to_le32(m->dqb_bsoftlimit);
+        d->dqb_curspace = cpu_to_le64(m->dqb_curspace);
+        d->dqb_btime = cpu_to_le64(m->dqb_btime);
+        d->dqb_id = cpu_to_le32(id);
 }
 
 static dqbuf_t getdqbuf(void)
 {
-       dqbuf_t buf = kmalloc(LUSTRE_DQBLKSIZE, GFP_NOFS);
-       if (!buf)
-               printk(KERN_WARNING "VFS: Not enough memory for quota buffers.\n");
-       return buf;
+        dqbuf_t buf = kmalloc(LUSTRE_DQBLKSIZE, GFP_NOFS);
+        if (!buf)
+                printk(KERN_WARNING
+                       "VFS: Not enough memory for quota buffers.\n");
+        return buf;
 }
 
 static inline void freedqbuf(dqbuf_t buf)
 {
-       kfree(buf);
+        kfree(buf);
 }
 
 static ssize_t read_blk(struct file *filp, uint blk, dqbuf_t buf)
 {
-       mm_segment_t fs;
-       ssize_t ret;
-       loff_t offset = blk<<LUSTRE_DQBLKSIZE_BITS;
-
-       memset(buf, 0, LUSTRE_DQBLKSIZE);
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       ret = filp->f_op->read(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
-       set_fs(fs);
-       return ret;
+        mm_segment_t fs;
+        ssize_t ret;
+        loff_t offset = blk << LUSTRE_DQBLKSIZE_BITS;
+
+        memset(buf, 0, LUSTRE_DQBLKSIZE);
+        fs = get_fs();
+        set_fs(KERNEL_DS);
+        ret = filp->f_op->read(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
+        set_fs(fs);
+        return ret;
 }
 
 static ssize_t write_blk(struct file *filp, uint blk, dqbuf_t buf)
 {
-       mm_segment_t fs;
-       ssize_t ret;
-       loff_t offset = blk<<LUSTRE_DQBLKSIZE_BITS;
+        mm_segment_t fs;
+        ssize_t ret;
+        loff_t offset = blk << LUSTRE_DQBLKSIZE_BITS;
 
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       ret = filp->f_op->write(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
-       set_fs(fs);
-       return ret;
+        fs = get_fs();
+        set_fs(KERNEL_DS);
+        ret = filp->f_op->write(filp, (char *)buf, LUSTRE_DQBLKSIZE, &offset);
+        set_fs(fs);
+        return ret;
 
 }
 
 static void lustre_mark_info_dirty(struct lustre_mem_dqinfo *info)
 {
-       set_bit(DQF_INFO_DIRTY_B, &info->dqi_flags);
+        set_bit(DQF_INFO_DIRTY_B, &info->dqi_flags);
 }
 
 #define lustre_info_dirty(info) test_bit(DQF_INFO_DIRTY_B, &(info)->dqi_flags)
@@ -188,238 +198,258 @@ static void lustre_mark_info_dirty(struct lustre_mem_dqinfo *info)
 /* Remove empty block from list and return it */
 static int get_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info)
 {
-       dqbuf_t buf = getdqbuf();
-       struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
-       int ret, blk;
-
-       if (!buf)
-               return -ENOMEM;
-       if (info->dqi_free_blk) {
-               blk = info->dqi_free_blk;
-               if ((ret = read_blk(filp, blk, buf)) < 0)
-                       goto out_buf;
-               info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
-       }
-       else {
-               memset(buf, 0, LUSTRE_DQBLKSIZE);
-               if ((ret = write_blk(filp, info->dqi_blocks, buf)) < 0) /* Assure block allocation... */
-                       goto out_buf;
-               blk = info->dqi_blocks++;
-       }
-       lustre_mark_info_dirty(info);
-       ret = blk;
+        dqbuf_t buf = getdqbuf();
+        struct lustre_disk_dqdbheader *dh =
+            (struct lustre_disk_dqdbheader *)buf;
+        int ret, blk;
+
+        if (!buf)
+                return -ENOMEM;
+        if (info->dqi_free_blk) {
+                blk = info->dqi_free_blk;
+                if ((ret = read_blk(filp, blk, buf)) < 0)
+                        goto out_buf;
+                info->dqi_free_blk = le32_to_cpu(dh->dqdh_next_free);
+        } else {
+                memset(buf, 0, LUSTRE_DQBLKSIZE);
+                if ((ret = write_blk(filp, info->dqi_blocks, buf)) < 0) /* Assure block allocation... */
+                        goto out_buf;
+                blk = info->dqi_blocks++;
+        }
+        lustre_mark_info_dirty(info);
+        ret = blk;
 out_buf:
-       freedqbuf(buf);
-       return ret;
+        freedqbuf(buf);
+        return ret;
 }
 
 /* Insert empty block to the list */
 static int put_free_dqblk(struct file *filp, struct lustre_mem_dqinfo *info,
-                         dqbuf_t buf, uint blk)
+                          dqbuf_t buf, uint blk)
 {
-       struct lustre_disk_dqdbheader *dh =(struct lustre_disk_dqdbheader *)buf;
-       int err;
-
-       dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
-       dh->dqdh_prev_free = cpu_to_le32(0);
-       dh->dqdh_entries = cpu_to_le16(0);
-       info->dqi_free_blk = blk;
-       lustre_mark_info_dirty(info);
-       if ((err = write_blk(filp, blk, buf)) < 0)
-               /* Some strange block. We had better leave it... */
-               return err;
-       return 0;
+        struct lustre_disk_dqdbheader *dh =
+            (struct lustre_disk_dqdbheader *)buf;
+        int err;
+
+        dh->dqdh_next_free = cpu_to_le32(info->dqi_free_blk);
+        dh->dqdh_prev_free = cpu_to_le32(0);
+        dh->dqdh_entries = cpu_to_le16(0);
+        info->dqi_free_blk = blk;
+        lustre_mark_info_dirty(info);
+        if ((err = write_blk(filp, blk, buf)) < 0)
+                /* Some strange block. We had better leave it... */
+                return err;
+        return 0;
 }
 
 /* Remove given block from the list of blocks with free entries */
-static int remove_free_dqentry(struct file *filp, struct lustre_mem_dqinfo *info, dqbuf_t buf, uint blk)
+static int remove_free_dqentry(struct file *filp,
+                               struct lustre_mem_dqinfo *info, dqbuf_t buf,
+                               uint blk)
 {
-       dqbuf_t tmpbuf = getdqbuf();
-       struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
-       uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk = le32_to_cpu(dh->dqdh_prev_free);
-       int err;
-
-       if (!tmpbuf)
-               return -ENOMEM;
-       if (nextblk) {
-               if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
-                       goto out_buf;
-               ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = dh->dqdh_prev_free;
-               if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
-                       goto out_buf;
-       }
-       if (prevblk) {
-               if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
-                       goto out_buf;
-               ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_next_free = dh->dqdh_next_free;
-               if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
-                       goto out_buf;
-       }
-       else {
-               info->dqi_free_entry = nextblk;
-               lustre_mark_info_dirty(info);
-       }
-       freedqbuf(tmpbuf);
-       dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
-       if (write_blk(filp, blk, buf) < 0)      /* No matter whether write succeeds block is out of list */
-               printk(KERN_ERR "VFS: Can't write block (%u) with free entries.\n", blk);
-       return 0;
+        dqbuf_t tmpbuf = getdqbuf();
+        struct lustre_disk_dqdbheader *dh =
+            (struct lustre_disk_dqdbheader *)buf;
+        uint nextblk = le32_to_cpu(dh->dqdh_next_free), prevblk =
+            le32_to_cpu(dh->dqdh_prev_free);
+        int err;
+
+        if (!tmpbuf)
+                return -ENOMEM;
+        if (nextblk) {
+                if ((err = read_blk(filp, nextblk, tmpbuf)) < 0)
+                        goto out_buf;
+                ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
+                    dh->dqdh_prev_free;
+                if ((err = write_blk(filp, nextblk, tmpbuf)) < 0)
+                        goto out_buf;
+        }
+        if (prevblk) {
+                if ((err = read_blk(filp, prevblk, tmpbuf)) < 0)
+                        goto out_buf;
+                ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_next_free =
+                    dh->dqdh_next_free;
+                if ((err = write_blk(filp, prevblk, tmpbuf)) < 0)
+                        goto out_buf;
+        } else {
+                info->dqi_free_entry = nextblk;
+                lustre_mark_info_dirty(info);
+        }
+        freedqbuf(tmpbuf);
+        dh->dqdh_next_free = dh->dqdh_prev_free = cpu_to_le32(0);
+        if (write_blk(filp, blk, buf) < 0)      /* No matter whether write succeeds block is out of list */
+                printk(KERN_ERR
+                       "VFS: Can't write block (%u) with free entries.\n", blk);
+        return 0;
 out_buf:
-       freedqbuf(tmpbuf);
-       return err;
+        freedqbuf(tmpbuf);
+        return err;
 }
 
 /* Insert given block to the beginning of list with free entries */
-static int insert_free_dqentry(struct file *filp, struct lustre_mem_dqinfo *info, dqbuf_t buf, uint blk)
+static int insert_free_dqentry(struct file *filp,
+                               struct lustre_mem_dqinfo *info, dqbuf_t buf,
+                               uint blk)
 {
-       dqbuf_t tmpbuf = getdqbuf();
-       struct lustre_disk_dqdbheader *dh = (struct lustre_disk_dqdbheader *)buf;
-       int err;
-
-       if (!tmpbuf)
-               return -ENOMEM;
-       dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
-       dh->dqdh_prev_free = cpu_to_le32(0);
-       if ((err = write_blk(filp, blk, buf)) < 0)
-               goto out_buf;
-       if (info->dqi_free_entry) {
-               if ((err = read_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
-                       goto out_buf;
-               ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free = cpu_to_le32(blk);
-               if ((err = write_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
-                       goto out_buf;
-       }
-       freedqbuf(tmpbuf);
-       info->dqi_free_entry = blk;
-       lustre_mark_info_dirty(info);
-       return 0;
+        dqbuf_t tmpbuf = getdqbuf();
+        struct lustre_disk_dqdbheader *dh =
+            (struct lustre_disk_dqdbheader *)buf;
+        int err;
+
+        if (!tmpbuf)
+                return -ENOMEM;
+        dh->dqdh_next_free = cpu_to_le32(info->dqi_free_entry);
+        dh->dqdh_prev_free = cpu_to_le32(0);
+        if ((err = write_blk(filp, blk, buf)) < 0)
+                goto out_buf;
+        if (info->dqi_free_entry) {
+                if ((err = read_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
+                        goto out_buf;
+                ((struct lustre_disk_dqdbheader *)tmpbuf)->dqdh_prev_free =
+                    cpu_to_le32(blk);
+                if ((err = write_blk(filp, info->dqi_free_entry, tmpbuf)) < 0)
+                        goto out_buf;
+        }
+        freedqbuf(tmpbuf);
+        info->dqi_free_entry = blk;
+        lustre_mark_info_dirty(info);
+        return 0;
 out_buf:
-       freedqbuf(tmpbuf);
-       return err;
+        freedqbuf(tmpbuf);
+        return err;
 }
 
 /* Find space for dquot */
 static uint find_free_dqentry(struct lustre_dquot *dquot, int *err)
 {
-       struct lustre_quota_info *lqi = dquot->dq_info;
-       struct file *filp = lqi->qi_files[dquot->dq_type];
-       struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
-       uint blk, i;
-       struct lustre_disk_dqdbheader *dh;
-       struct lustre_disk_dqblk *ddquot;
-       struct lustre_disk_dqblk fakedquot;
-       dqbuf_t buf;
-
-       *err = 0;
-       if (!(buf = getdqbuf())) {
-               *err = -ENOMEM;
-               return 0;
-       }
-       dh = (struct lustre_disk_dqdbheader *)buf;
-       ddquot = GETENTRIES(buf);
-       if (info->dqi_free_entry) {
-               blk = info->dqi_free_entry;
-               if ((*err = read_blk(filp, blk, buf)) < 0)
-                       goto out_buf;
-       }
-       else {
-               blk = get_free_dqblk(filp, info);
-               if ((int)blk < 0) {
-                       *err = blk;
-                       freedqbuf(buf);
-                       return 0;
-               }
-               memset(buf, 0, LUSTRE_DQBLKSIZE);
-               info->dqi_free_entry = blk;     /* This is enough as block is already zeroed and entry list is empty... */
-               lustre_mark_info_dirty(info);
-       }
-       if (le16_to_cpu(dh->dqdh_entries)+1 >= LUSTRE_DQSTRINBLK)       /* Block will be full? */
-               if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) {
-                       printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk);
-                       goto out_buf;
-               }
-       dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)+1);
-       memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
-       /* Find free structure in block */
-       for (i = 0; i < LUSTRE_DQSTRINBLK && memcmp(&fakedquot, ddquot+i, sizeof(struct lustre_disk_dqblk)); i++);
-       
-       if (i == LUSTRE_DQSTRINBLK) {
-               printk(KERN_ERR "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
-               *err = -EIO;
-               goto out_buf;
-       }
-       
-       if ((*err = write_blk(filp, blk, buf)) < 0) {
-               printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk);
-               goto out_buf;
-       }
-       dquot->dq_off = (blk<<LUSTRE_DQBLKSIZE_BITS)+sizeof(struct lustre_disk_dqdbheader)+i*sizeof(struct lustre_disk_dqblk);
-       freedqbuf(buf);
-       return blk;
+        struct lustre_quota_info *lqi = dquot->dq_info;
+        struct file *filp = lqi->qi_files[dquot->dq_type];
+        struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
+        uint blk, i;
+        struct lustre_disk_dqdbheader *dh;
+        struct lustre_disk_dqblk *ddquot;
+        struct lustre_disk_dqblk fakedquot;
+        dqbuf_t buf;
+
+        *err = 0;
+        if (!(buf = getdqbuf())) {
+                *err = -ENOMEM;
+                return 0;
+        }
+        dh = (struct lustre_disk_dqdbheader *)buf;
+        ddquot = GETENTRIES(buf);
+        if (info->dqi_free_entry) {
+                blk = info->dqi_free_entry;
+                if ((*err = read_blk(filp, blk, buf)) < 0)
+                        goto out_buf;
+        } else {
+                blk = get_free_dqblk(filp, info);
+                if ((int)blk < 0) {
+                        *err = blk;
+                        freedqbuf(buf);
+                        return 0;
+                }
+                memset(buf, 0, LUSTRE_DQBLKSIZE);
+                info->dqi_free_entry = blk;     /* This is enough as block is already zeroed and entry list is empty... */
+                lustre_mark_info_dirty(info);
+        }
+        if (le16_to_cpu(dh->dqdh_entries) + 1 >= LUSTRE_DQSTRINBLK)     /* Block will be full? */
+                if ((*err = remove_free_dqentry(filp, info, buf, blk)) < 0) {
+                        printk(KERN_ERR
+                               "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n",
+                               blk);
+                        goto out_buf;
+                }
+        dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries) + 1);
+        memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
+        /* Find free structure in block */
+        for (i = 0; i < LUSTRE_DQSTRINBLK && 
+             memcmp(&fakedquot, ddquot + i, sizeof(fakedquot)); i++) ;
+
+        if (i == LUSTRE_DQSTRINBLK) {
+                printk(KERN_ERR
+                       "VFS: find_free_dqentry(): Data block full but it shouldn't.\n");
+                *err = -EIO;
+                goto out_buf;
+        }
+
+        if ((*err = write_blk(filp, blk, buf)) < 0) {
+                printk(KERN_ERR
+                       "VFS: find_free_dqentry(): Can't write quota data block %u.\n",
+                       blk);
+                goto out_buf;
+        }
+        dquot->dq_off =
+            (blk << LUSTRE_DQBLKSIZE_BITS) +
+            sizeof(struct lustre_disk_dqdbheader) +
+            i * sizeof(struct lustre_disk_dqblk);
+        freedqbuf(buf);
+        return blk;
 out_buf:
-       freedqbuf(buf);
-       return 0;
+        freedqbuf(buf);
+        return 0;
 }
 
 /* Insert reference to structure into the trie */
-static int do_insert_tree(struct lustre_dquot *dquot, uint *treeblk, int depth)
+static int do_insert_tree(struct lustre_dquot *dquot, uint * treeblk, int depth)
 {
-       struct lustre_quota_info *lqi = dquot->dq_info;
-       struct file *filp = lqi->qi_files[dquot->dq_type];
-       struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
-       dqbuf_t buf;
-       int ret = 0, newson = 0, newact = 0;
-       u32 *ref;
-       uint newblk;
-
-       if (!(buf = getdqbuf()))
-               return -ENOMEM;
-       if (!*treeblk) {
-               ret = get_free_dqblk(filp, info);
-               if (ret < 0)
-                       goto out_buf;
-               *treeblk = ret;
-               memset(buf, 0, LUSTRE_DQBLKSIZE);
-               newact = 1;
-       }
-       else {
-               if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
-                       printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk);
-                       goto out_buf;
-               }
-       }
-       ref = (u32 *)buf;
-       newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
-       if (!newblk)
-               newson = 1;
-       if (depth == LUSTRE_DQTREEDEPTH-1) {
-               
-               if (newblk) {
-                       printk(KERN_ERR "VFS: Inserting already present quota entry (block %u).\n", ref[GETIDINDEX(dquot->dq_id, depth)]);
-                       ret = -EIO;
-                       goto out_buf;
-               }
-               
-               newblk = find_free_dqentry(dquot, &ret);
-       }
-       else
-               ret = do_insert_tree(dquot, &newblk, depth+1);
-       if (newson && ret >= 0) {
-               ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
-               ret = write_blk(filp, *treeblk, buf);
-       }
-       else if (newact && ret < 0)
-               put_free_dqblk(filp, info, buf, *treeblk);
+        struct lustre_quota_info *lqi = dquot->dq_info;
+        struct file *filp = lqi->qi_files[dquot->dq_type];
+        struct lustre_mem_dqinfo *info = &lqi->qi_info[dquot->dq_type];
+        dqbuf_t buf;
+        int ret = 0, newson = 0, newact = 0;
+        u32 *ref;
+        uint newblk;
+
+        if (!(buf = getdqbuf()))
+                return -ENOMEM;
+        if (!*treeblk) {
+                ret = get_free_dqblk(filp, info);
+                if (ret < 0)
+                        goto out_buf;
+                *treeblk = ret;
+                memset(buf, 0, LUSTRE_DQBLKSIZE);
+                newact = 1;
+        } else {
+                if ((ret = read_blk(filp, *treeblk, buf)) < 0) {
+                        printk(KERN_ERR
+                               "VFS: Can't read tree quota block %u.\n",
+                               *treeblk);
+                        goto out_buf;
+                }
+        }
+        ref = (u32 *) buf;
+        newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+        if (!newblk)
+                newson = 1;
+        if (depth == LUSTRE_DQTREEDEPTH - 1) {
+
+                if (newblk) {
+                        printk(KERN_ERR
+                               "VFS: Inserting already present quota entry (block %u).\n",
+                               ref[GETIDINDEX(dquot->dq_id, depth)]);
+                        ret = -EIO;
+                        goto out_buf;
+                }
+
+                newblk = find_free_dqentry(dquot, &ret);
+        } else
+                ret = do_insert_tree(dquot, &newblk, depth + 1);
+        if (newson && ret >= 0) {
+                ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);
+                ret = write_blk(filp, *treeblk, buf);
+        } else if (newact && ret < 0)
+                put_free_dqblk(filp, info, buf, *treeblk);
 out_buf:
-       freedqbuf(buf);
-       return ret;
+        freedqbuf(buf);
+        return ret;
 }
 
 /* Wrapper for inserting quota structure into tree */
 static inline int dq_insert_tree(struct lustre_dquot *dquot)
 {
-       int tmp = LUSTRE_DQTREEOFF;
-       return do_insert_tree(dquot, &tmp, 0);
+        int tmp = LUSTRE_DQTREEOFF;
+        return do_insert_tree(dquot, &tmp, 0);
 }
 
 /*
@@ -427,321 +457,508 @@ static inline int dq_insert_tree(struct lustre_dquot *dquot)
  */
 static int lustre_write_dquot(struct lustre_dquot *dquot)
 {
-       int type = dquot->dq_type;
-       struct file *filp;
-       mm_segment_t fs;
-       loff_t offset;
-       ssize_t ret;
-       struct lustre_disk_dqblk ddquot, empty;
-
-       if (!dquot->dq_off)
-               if ((ret = dq_insert_tree(dquot)) < 0) {
-                       printk(KERN_ERR "VFS: Error %Zd occurred while creating quota.\n", ret);
-                       return ret;
-               }
-       filp = dquot->dq_info->qi_files[type];
-       offset = dquot->dq_off;
-       mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
-       /* Argh... We may need to write structure full of zeroes but that would be
-        * treated as an empty place by the rest of the code. Format change would
-        * be definitely cleaner but the problems probably are not worth it */
-       memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
-       if (!memcmp(&empty, &ddquot, sizeof(struct lustre_disk_dqblk)))
-               ddquot.dqb_itime = cpu_to_le64(1);
-       fs = get_fs();
-       set_fs(KERNEL_DS);
-       ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct lustre_disk_dqblk), &offset);
-       set_fs(fs);
-       if (ret != sizeof(struct lustre_disk_dqblk)) {
-               printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", filp->f_dentry->d_sb->s_id);
-               if (ret >= 0)
-                       ret = -ENOSPC;
-       }
-       else
-               ret = 0;
-
-       return ret;
+        int type = dquot->dq_type;
+        struct file *filp;
+        mm_segment_t fs;
+        loff_t offset;
+        ssize_t ret;
+        struct lustre_disk_dqblk ddquot, empty;
+
+        if (!dquot->dq_off)
+                if ((ret = dq_insert_tree(dquot)) < 0) {
+                        printk(KERN_ERR
+                               "VFS: Error %Zd occurred while creating quota.\n",
+                               ret);
+                        return ret;
+                }
+        filp = dquot->dq_info->qi_files[type];
+        offset = dquot->dq_off;
+        mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id);
+        /* Argh... We may need to write structure full of zeroes but that would be
+         * treated as an empty place by the rest of the code. Format change would
+         * be definitely cleaner but the problems probably are not worth it */
+        memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
+        if (!memcmp(&empty, &ddquot, sizeof(struct lustre_disk_dqblk)))
+                ddquot.dqb_itime = cpu_to_le64(1);
+        fs = get_fs();
+        set_fs(KERNEL_DS);
+        ret = filp->f_op->write(filp, (char *)&ddquot,
+                                sizeof(struct lustre_disk_dqblk), &offset);
+        set_fs(fs);
+        if (ret != sizeof(struct lustre_disk_dqblk)) {
+                printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
+                       filp->f_dentry->d_sb->s_id);
+                if (ret >= 0)
+                        ret = -ENOSPC;
+        } else
+                ret = 0;
+
+        return ret;
 }
 
 /* Free dquot entry in data block */
 static int free_dqentry(struct lustre_dquot *dquot, uint blk)
 {
-       struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
-       struct lustre_mem_dqinfo *info = &dquot->dq_info->qi_info[dquot->dq_type];
-       struct lustre_disk_dqdbheader *dh;
-       dqbuf_t buf = getdqbuf();
-       int ret = 0;
-
-       if (!buf)
-               return -ENOMEM;
-       if (dquot->dq_off >> LUSTRE_DQBLKSIZE_BITS != blk) {
-               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));
-               goto out_buf;
-       }
-       if ((ret = read_blk(filp, blk, buf)) < 0) {
-               printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
-               goto out_buf;
-       }
-       dh = (struct lustre_disk_dqdbheader *)buf;
-       dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1);
-       if (!le16_to_cpu(dh->dqdh_entries)) {   /* Block got free? */
-               if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
-                   (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
-                       printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);
-                       goto out_buf;
-               }
-       }
-       else {
-               memset(buf+(dquot->dq_off & ((1 << LUSTRE_DQBLKSIZE_BITS)-1)), 0, sizeof(struct lustre_disk_dqblk));
-               if (le16_to_cpu(dh->dqdh_entries) == LUSTRE_DQSTRINBLK-1) {
-                       /* Insert will write block itself */
-                       if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) {
-                               printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk);
-                               goto out_buf;
-                       }
-               }
-               else
-                       if ((ret = write_blk(filp, blk, buf)) < 0) {
-                               printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);
-                               goto out_buf;
-                       }
-       }
-       dquot->dq_off = 0;      /* Quota is now unattached */
+        struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
+        struct lustre_mem_dqinfo *info =
+            &dquot->dq_info->qi_info[dquot->dq_type];
+        struct lustre_disk_dqdbheader *dh;
+        dqbuf_t buf = getdqbuf();
+        int ret = 0;
+
+        if (!buf)
+                return -ENOMEM;
+        if (dquot->dq_off >> LUSTRE_DQBLKSIZE_BITS != blk) {
+                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));
+                goto out_buf;
+        }
+        if ((ret = read_blk(filp, blk, buf)) < 0) {
+                printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk);
+                goto out_buf;
+        }
+        dh = (struct lustre_disk_dqdbheader *)buf;
+        dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries) - 1);
+        if (!le16_to_cpu(dh->dqdh_entries)) {   /* Block got free? */
+                if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||
+                    (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {
+                        printk(KERN_ERR
+                               "VFS: Can't move quota data block (%u) to free list.\n",
+                               blk);
+                        goto out_buf;
+                }
+        } else {
+                memset(buf +
+                       (dquot->dq_off & ((1 << LUSTRE_DQBLKSIZE_BITS) - 1)), 0,
+                       sizeof(struct lustre_disk_dqblk));
+                if (le16_to_cpu(dh->dqdh_entries) == LUSTRE_DQSTRINBLK - 1) {
+                        /* Insert will write block itself */
+                        if ((ret =
+                             insert_free_dqentry(filp, info, buf, blk)) < 0) {
+                                printk(KERN_ERR
+                                       "VFS: Can't insert quota data block (%u) to free entry list.\n",
+                                       blk);
+                                goto out_buf;
+                        }
+                } else if ((ret = write_blk(filp, blk, buf)) < 0) {
+                        printk(KERN_ERR
+                               "VFS: Can't write quota data block %u\n", blk);
+                        goto out_buf;
+                }
+        }
+        dquot->dq_off = 0;      /* Quota is now unattached */
 out_buf:
-       freedqbuf(buf);
-       return ret;
+        freedqbuf(buf);
+        return ret;
 }
 
 /* Remove reference to dquot from tree */
-static int remove_tree(struct lustre_dquot *dquot, uint *blk, int depth)
+static int remove_tree(struct lustre_dquot *dquot, uint * blk, int depth)
 {
-       struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
-       struct lustre_mem_dqinfo *info = &dquot->dq_info->qi_info[dquot->dq_type];
-       dqbuf_t buf = getdqbuf();
-       int ret = 0;
-       uint newblk;
-       u32 *ref = (u32 *)buf;
-       
-       if (!buf)
-               return -ENOMEM;
-       if ((ret = read_blk(filp, *blk, buf)) < 0) {
-               printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
-               goto out_buf;
-       }
-       newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
-       if (depth == LUSTRE_DQTREEDEPTH-1) {
-               ret = free_dqentry(dquot, newblk);
-               newblk = 0;
-       }
-       else
-               ret = remove_tree(dquot, &newblk, depth+1);
-       if (ret >= 0 && !newblk) {
-               int i;
-               ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
-               for (i = 0; i < LUSTRE_DQBLKSIZE && !buf[i]; i++);      /* Block got empty? */
-               /* don't put the root block into free blk list! */
-               if (i == LUSTRE_DQBLKSIZE && *blk != LUSTRE_DQTREEOFF) {
-                       put_free_dqblk(filp, info, buf, *blk);
-                       *blk = 0;
-               }
-               else
-                       if ((ret = write_blk(filp, *blk, buf)) < 0)
-                               printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);
-       }
+        struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
+        struct lustre_mem_dqinfo *info =
+            &dquot->dq_info->qi_info[dquot->dq_type];
+        dqbuf_t buf = getdqbuf();
+        int ret = 0;
+        uint newblk;
+        u32 *ref = (u32 *) buf;
+
+        if (!buf)
+                return -ENOMEM;
+        if ((ret = read_blk(filp, *blk, buf)) < 0) {
+                printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk);
+                goto out_buf;
+        }
+        newblk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+        if (depth == LUSTRE_DQTREEDEPTH - 1) {
+                ret = free_dqentry(dquot, newblk);
+                newblk = 0;
+        } else
+                ret = remove_tree(dquot, &newblk, depth + 1);
+        if (ret >= 0 && !newblk) {
+                int i;
+                ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0);
+                for (i = 0; i < LUSTRE_DQBLKSIZE && !buf[i]; i++) ;     /* Block got empty? */
+                /* don't put the root block into free blk list! */
+                if (i == LUSTRE_DQBLKSIZE && *blk != LUSTRE_DQTREEOFF) {
+                        put_free_dqblk(filp, info, buf, *blk);
+                        *blk = 0;
+                } else if ((ret = write_blk(filp, *blk, buf)) < 0)
+                        printk(KERN_ERR
+                               "VFS: Can't write quota tree block %u.\n", *blk);
+        }
 out_buf:
-       freedqbuf(buf);
-       return ret;     
+        freedqbuf(buf);
+        return ret;
 }
 
 /* Delete dquot from tree */
-#ifndef        QFMT_NO_DELETE
 static int lustre_delete_dquot(struct lustre_dquot *dquot)
 {
-       uint tmp = LUSTRE_DQTREEOFF;
+        uint tmp = LUSTRE_DQTREEOFF;
 
-       if (!dquot->dq_off)     /* Even not allocated? */
-               return 0;
-       return remove_tree(dquot, &tmp, 0);
+        if (!dquot->dq_off)     /* Even not allocated? */
+                return 0;
+        return remove_tree(dquot, &tmp, 0);
 }
-#endif
 
 /* Find entry in block */
 static loff_t find_block_dqentry(struct lustre_dquot *dquot, uint blk)
 {
-       struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
-       dqbuf_t buf = getdqbuf();
-       loff_t ret = 0;
-       int i;
-       struct lustre_disk_dqblk *ddquot = GETENTRIES(buf);
-
-       if (!buf)
-               return -ENOMEM;
-       if ((ret = read_blk(filp, blk, buf)) < 0) {
-               printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
-               goto out_buf;
-       }
-       if (dquot->dq_id)
-               for (i = 0; i < LUSTRE_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);
-       else {  /* ID 0 as a bit more complicated searching... */
-               struct lustre_disk_dqblk fakedquot;
-
-               memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
-               for (i = 0; i < LUSTRE_DQSTRINBLK; i++)
-                       if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct lustre_disk_dqblk)))
-                               break;
-       }
-       if (i == LUSTRE_DQSTRINBLK) {
-               printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id);
-               ret = -EIO;
-               goto out_buf;
-       }
-       else
-               ret = (blk << LUSTRE_DQBLKSIZE_BITS) + sizeof(struct lustre_disk_dqdbheader) + i * sizeof(struct lustre_disk_dqblk);
+        struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
+        dqbuf_t buf = getdqbuf();
+        loff_t ret = 0;
+        int i;
+        struct lustre_disk_dqblk *ddquot = GETENTRIES(buf);
+
+        if (!buf)
+                return -ENOMEM;
+        if ((ret = read_blk(filp, blk, buf)) < 0) {
+                printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+                goto out_buf;
+        }
+        if (dquot->dq_id)
+                for (i = 0;
+                     i < LUSTRE_DQSTRINBLK
+                     && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++) ;
+        else {                  /* ID 0 as a bit more complicated searching... */
+                struct lustre_disk_dqblk fakedquot;
+
+                memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
+                for (i = 0; i < LUSTRE_DQSTRINBLK; i++)
+                        if (!le32_to_cpu(ddquot[i].dqb_id)
+                            && memcmp(&fakedquot, ddquot + i,
+                                      sizeof(struct lustre_disk_dqblk)))
+                                break;
+        }
+        if (i == LUSTRE_DQSTRINBLK) {
+                printk(KERN_ERR
+                       "VFS: Quota for id %u referenced but not present.\n",
+                       dquot->dq_id);
+                ret = -EIO;
+                goto out_buf;
+        } else
+                ret =
+                    (blk << LUSTRE_DQBLKSIZE_BITS) +
+                    sizeof(struct lustre_disk_dqdbheader) +
+                    i * sizeof(struct lustre_disk_dqblk);
 out_buf:
-       freedqbuf(buf);
-       return ret;
+        freedqbuf(buf);
+        return ret;
 }
 
 /* Find entry for given id in the tree */
 static loff_t find_tree_dqentry(struct lustre_dquot *dquot, uint blk, int depth)
 {
-       struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
-       dqbuf_t buf = getdqbuf();
-       loff_t ret = 0;
-       u32 *ref = (u32 *)buf;
-
-       if (!buf)
-               return -ENOMEM;
-       if ((ret = read_blk(filp, blk, buf)) < 0) {
-               printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
-               goto out_buf;
-       }
-       ret = 0;
-       blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
-       if (!blk)       /* No reference? */
-               goto out_buf;
-       if (depth < LUSTRE_DQTREEDEPTH-1)
-               ret = find_tree_dqentry(dquot, blk, depth+1);
-       else
-               ret = find_block_dqentry(dquot, blk);
+        struct file *filp = dquot->dq_info->qi_files[dquot->dq_type];
+        dqbuf_t buf = getdqbuf();
+        loff_t ret = 0;
+        u32 *ref = (u32 *) buf;
+
+        if (!buf)
+                return -ENOMEM;
+        if ((ret = read_blk(filp, blk, buf)) < 0) {
+                printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+                goto out_buf;
+        }
+        ret = 0;
+        blk = le32_to_cpu(ref[GETIDINDEX(dquot->dq_id, depth)]);
+        if (!blk)               /* No reference? */
+                goto out_buf;
+        if (depth < LUSTRE_DQTREEDEPTH - 1)
+                ret = find_tree_dqentry(dquot, blk, depth + 1);
+        else
+                ret = find_block_dqentry(dquot, blk);
 out_buf:
-       freedqbuf(buf);
-       return ret;
+        freedqbuf(buf);
+        return ret;
 }
 
 /* Find entry for given id in the tree - wrapper function */
 static inline loff_t find_dqentry(struct lustre_dquot *dquot)
 {
-       return find_tree_dqentry(dquot, LUSTRE_DQTREEOFF, 0);
+        return find_tree_dqentry(dquot, LUSTRE_DQTREEOFF, 0);
 }
 
 int lustre_read_dquot(struct lustre_dquot *dquot)
 {
-       int type = dquot->dq_type;
-       struct file *filp;
-       mm_segment_t fs;
-       loff_t offset;
-       struct lustre_disk_dqblk ddquot, empty;
-       int ret = 0;
-
-       filp = dquot->dq_info->qi_files[type];
-
-       if (!filp || !dquot->dq_info) { /* Invalidated quota? */
-               printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
-               return -EIO;
-       }
-       
-       offset = find_dqentry(dquot);
-       if (offset <= 0) {      /* Entry not present? */
-               if (offset < 0)
-                       printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);
-               dquot->dq_off = 0;
-               set_bit(DQ_FAKE_B, &dquot->dq_flags);
-               memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
-               ret = offset;
-       }
-       else {
-               dquot->dq_off = offset;
-               fs = get_fs();
-               set_fs(KERNEL_DS);
-               if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct lustre_disk_dqblk), &offset)) != sizeof(struct lustre_disk_dqblk)) {
-                       if (ret >= 0)
-                               ret = -EIO;
-                       printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id);
-                       memset(&ddquot, 0, sizeof(struct lustre_disk_dqblk));
-               }
-               else {
-                       ret = 0;
-                       /* We need to escape back all-zero structure */
-                       memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
-                       empty.dqb_itime = cpu_to_le64(1);
-                       if (!memcmp(&empty, &ddquot,
-                                   sizeof(struct lustre_disk_dqblk)))
-                               ddquot.dqb_itime = 0;
-               }
-               set_fs(fs);
-               disk2memdqb(&dquot->dq_dqb, &ddquot);
-       }
-
-       return ret;
+        int type = dquot->dq_type;
+        struct file *filp;
+        mm_segment_t fs;
+        loff_t offset;
+        struct lustre_disk_dqblk ddquot, empty;
+        int ret = 0;
+
+        filp = dquot->dq_info->qi_files[type];
+
+        if (!filp || !dquot->dq_info) { /* Invalidated quota? */
+                printk(KERN_ERR "VFS: Quota invalidated while reading!\n");
+                return -EIO;
+        }
+
+        offset = find_dqentry(dquot);
+        if (offset <= 0) {      /* Entry not present? */
+                if (offset < 0)
+                        printk(KERN_ERR
+                               "VFS: Can't read quota structure for id %u.\n",
+                               dquot->dq_id);
+                dquot->dq_off = 0;
+                set_bit(DQ_FAKE_B, &dquot->dq_flags);
+                memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));
+                ret = offset;
+        } else {
+                dquot->dq_off = offset;
+                fs = get_fs();
+                set_fs(KERNEL_DS);
+                if ((ret = filp->f_op->read(filp, (char *)&ddquot,
+                                            sizeof(struct lustre_disk_dqblk),
+                                            &offset)) !=
+                    sizeof(struct lustre_disk_dqblk)) {
+                        if (ret >= 0)
+                                ret = -EIO;
+                        printk(KERN_ERR
+                               "VFS: Error while reading quota structure for id %u.\n",
+                               dquot->dq_id);
+                        memset(&ddquot, 0, sizeof(struct lustre_disk_dqblk));
+                } else {
+                        ret = 0;
+                        /* We need to escape back all-zero structure */
+                        memset(&empty, 0, sizeof(struct lustre_disk_dqblk));
+                        empty.dqb_itime = cpu_to_le64(1);
+                        if (!memcmp(&empty, &ddquot,
+                                    sizeof(struct lustre_disk_dqblk)))
+                                ddquot.dqb_itime = 0;
+                }
+                set_fs(fs);
+                disk2memdqb(&dquot->dq_dqb, &ddquot);
+        }
+
+        return ret;
 }
 
 /* Commit changes of dquot to disk - it might also mean deleting it when quota became fake */
 int lustre_commit_dquot(struct lustre_dquot *dquot)
 {
-       int rc = 0;
-       /* always clear the flag so we don't loop on an IO error... */
-       clear_bit(DQ_MOD_B, &dquot->dq_flags);
-
-       /* The block/inode usage in admin quotafile isn't the real usage
-        * over all cluster, so keep the fake dquot entry on disk is
-        * meaningless, just remove it */
-       if (test_bit(DQ_FAKE_B, &dquot->dq_flags))
-               rc = lustre_delete_dquot(dquot);
-       else
-               rc = lustre_write_dquot(dquot);
-       if (rc < 0)
-               return rc;
-
-       if (lustre_info_dirty(&dquot->dq_info->qi_info[dquot->dq_type]))
-               rc = lustre_write_quota_info(dquot->dq_info, dquot->dq_type);
-
-       return rc;
+        int rc = 0;
+        /* always clear the flag so we don't loop on an IO error... */
+        clear_bit(DQ_MOD_B, &dquot->dq_flags);
+
+        /* The block/inode usage in admin quotafile isn't the real usage
+         * over all cluster, so keep the fake dquot entry on disk is
+         * meaningless, just remove it */
+        if (test_bit(DQ_FAKE_B, &dquot->dq_flags))
+                rc = lustre_delete_dquot(dquot);
+        else
+                rc = lustre_write_dquot(dquot);
+
+        if (rc < 0)
+                return rc;
+
+        if (lustre_info_dirty(&dquot->dq_info->qi_info[dquot->dq_type]))
+                rc = lustre_write_quota_info(dquot->dq_info, dquot->dq_type);
+
+        return rc;
 }
 
 /* We need to export this function to initialize quotafile, because we haven't
  * user level check utility */
 int lustre_init_quota_info(struct lustre_quota_info *lqi, int type)
 {
-       struct lustre_mem_dqinfo *dqinfo = &lqi->qi_info[type];
-       struct lustre_disk_dqheader dqhead;
-       struct file *fp = lqi->qi_files[type];
-       ssize_t size;
-       loff_t offset = 0;
-       int rc = 0;
-       static const uint quota_magics[] = LUSTRE_INITQMAGICS;
-       static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
-
-       /* write quotafile header */
-       dqhead.dqh_magic = cpu_to_le32(quota_magics[type]);
-       dqhead.dqh_version = cpu_to_le32(quota_versions[type]);
-       size = fp->f_op->write(fp, (char *)&dqhead,
-                              sizeof(struct lustre_disk_dqheader), &offset);
-       
-       if (size != sizeof(struct lustre_disk_dqheader)) {
-               printk(KERN_ERR "error writing quoafile header (rc:%d)\n", rc);
-               rc = size;
-       }
-       if (rc)
-               return rc;
-
-       /* write init quota info */
-       memset(dqinfo, 0, sizeof(*dqinfo));
-       dqinfo->dqi_bgrace = MAX_DQ_TIME;
-       dqinfo->dqi_igrace = MAX_IQ_TIME;
-       dqinfo->dqi_blocks = LUSTRE_DQTREEOFF + 1;
-
-       return lustre_write_quota_info(lqi, type);
+        struct lustre_mem_dqinfo *dqinfo = &lqi->qi_info[type];
+        struct lustre_disk_dqheader dqhead;
+        struct file *fp = lqi->qi_files[type];
+        ssize_t size;
+        loff_t offset = 0;
+        int rc = 0;
+        static const uint quota_magics[] = LUSTRE_INITQMAGICS;
+        static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
+
+        /* write quotafile header */
+        dqhead.dqh_magic = cpu_to_le32(quota_magics[type]);
+        dqhead.dqh_version = cpu_to_le32(quota_versions[type]);
+        size = fp->f_op->write(fp, (char *)&dqhead,
+                               sizeof(struct lustre_disk_dqheader), &offset);
+
+        if (size != sizeof(struct lustre_disk_dqheader)) {
+                printk(KERN_ERR "error writing quoafile header (rc:%d)\n", rc);
+                rc = size;
+        }
+        if (rc)
+                return rc;
+
+        /* write init quota info */
+        memset(dqinfo, 0, sizeof(*dqinfo));
+        dqinfo->dqi_bgrace = MAX_DQ_TIME;
+        dqinfo->dqi_igrace = MAX_IQ_TIME;
+        dqinfo->dqi_blocks = LUSTRE_DQTREEOFF + 1;
+
+        return lustre_write_quota_info(lqi, type);
+}
+
+struct dqblk {
+        struct list_head link;
+        uint blk;
+};
+
+static int walk_block_dqentry(struct file *filp, uint blk,
+                              struct list_head *list)
+{
+        dqbuf_t buf = getdqbuf();
+        loff_t ret = 0;
+        struct lustre_disk_dqdbheader *dqhead =
+            (struct lustre_disk_dqdbheader *)buf;
+        struct dqblk *blk_item;
+        struct dqblk *pos;
+        struct list_head *tmp;
+
+        if (!buf)
+                return -ENOMEM;
+        if ((ret = read_blk(filp, blk, buf)) < 0) {
+                printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+                goto out_buf;
+        }
+        ret = 0;
+
+        if (!le32_to_cpu(dqhead->dqdh_entries))
+                goto out_buf;
+
+        if (list_empty(list)) {
+                tmp = list;
+                goto done;
+        }
+
+        list_for_each_entry(pos, list, link) {
+                if (blk == pos->blk)    /* we got this blk already */
+                        goto out_buf;
+                if (blk > pos->blk)
+                        continue;
+                break;
+        }
+        tmp = &pos->link;
+done:
+        blk_item = kmalloc(sizeof(*blk_item), GFP_NOFS);
+        if (!blk_item) {
+                ret = -ENOMEM;
+                goto out_buf;
+        }
+        blk_item->blk = blk;
+        INIT_LIST_HEAD(&blk_item->link);
+
+        list_add_tail(&blk_item->link, tmp);
+
+out_buf:
+        freedqbuf(buf);
+        return ret;
+}
+
+static int walk_tree_dqentry(struct file *filp, uint blk, int depth,
+                             struct list_head *list)
+{
+        dqbuf_t buf = getdqbuf();
+        loff_t ret = 0;
+        int index;
+        u32 *ref = (u32 *) buf;
+
+        if (!buf)
+                return -ENOMEM;
+        if ((ret = read_blk(filp, blk, buf)) < 0) {
+                printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk);
+                goto out_buf;
+        }
+        ret = 0;
+
+        for (index = 0; index <= 0xff && !ret; index++) {
+                blk = le32_to_cpu(ref[index]);
+                if (!blk)       /* No reference */
+                        continue;
+
+                if (depth < LUSTRE_DQTREEDEPTH - 1)
+                        ret = walk_tree_dqentry(filp, blk, depth + 1, list);
+                else
+                        ret = walk_block_dqentry(filp, blk, list);
+        }
+out_buf:
+        freedqbuf(buf);
+        return ret;
+}
+
+/* Walk through the quota file (v2 format) to get all ids with quota limit */
+int lustre_get_qids(struct lustre_quota_info *lqi, int type,
+                    struct list_head *list)
+{
+        struct file *fp = lqi->qi_files[type];
+        struct list_head blk_list;
+        struct dqblk *blk_item, *tmp;
+        dqbuf_t buf = NULL;
+        struct lustre_disk_dqblk *ddquot;
+        int rc;
+
+        if (!check_quota_file(fp, type)) {
+                printk(KERN_ERR "unknown quota file format!\n");
+                return -EINVAL;
+        }
+        if (!list_empty(list)) {
+                printk(KERN_ERR "not empty list\n");
+                return -EINVAL;
+        }
+
+        INIT_LIST_HEAD(&blk_list);
+        rc = walk_tree_dqentry(fp, LUSTRE_DQTREEOFF, 0, &blk_list);
+        if (rc) {
+                printk(KERN_ERR "walk through quota file failed!(%d)\n", rc);
+                goto out_free;
+        }
+        if (list_empty(&blk_list))
+                return 0;
+
+        buf = getdqbuf();
+        if (!buf)
+                return -ENOMEM;
+        ddquot = GETENTRIES(buf);
+
+        list_for_each_entry(blk_item, &blk_list, link) {
+                loff_t ret = 0;
+                int i;
+                struct lustre_disk_dqblk fakedquot;
+
+                memset(buf, 0, LUSTRE_DQBLKSIZE);
+                if ((ret = read_blk(fp, blk_item->blk, buf)) < 0) {
+                        printk(KERN_ERR
+                               "VFS: Can't read quota tree block %u.\n",
+                               blk_item->blk);
+                        rc = ret;
+                        goto out_free;
+                }
+
+                memset(&fakedquot, 0, sizeof(struct lustre_disk_dqblk));
+                for (i = 0; i < LUSTRE_DQSTRINBLK; i++) {
+                        struct dquot_id *dqid;
+                        /* skip empty entry */
+                        if (!memcmp
+                            (&fakedquot, ddquot + i,
+                             sizeof(struct lustre_disk_dqblk)))
+                                continue;
+
+                        dqid = kmalloc(sizeof(*dqid), GFP_NOFS);
+                        if (!dqid) {
+                                rc = -ENOMEM;
+                                goto out_free;
+                        }
+                        dqid->di_id = le32_to_cpu(ddquot[i].dqb_id);
+                        INIT_LIST_HEAD(&dqid->di_link);
+                        list_add(&dqid->di_link, list);
+                }
+        }
+
+out_free:
+        list_for_each_entry_safe(blk_item, tmp, &blk_list, link) {
+                list_del_init(&blk_item->link);
+                kfree(blk_item);
+        }
+        if (buf)
+                freedqbuf(buf);
+        return rc;
 }
 
 EXPORT_SYMBOL(lustre_check_quota_file);
@@ -750,3 +967,4 @@ EXPORT_SYMBOL(lustre_write_quota_info);
 EXPORT_SYMBOL(lustre_read_dquot);
 EXPORT_SYMBOL(lustre_commit_dquot);
 EXPORT_SYMBOL(lustre_init_quota_info);
+EXPORT_SYMBOL(lustre_get_qids);
index 73d6120..28f5c15 100644 (file)
@@ -1,4 +1,6 @@
-/*
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
  * Lustre administrative quota format
  *
  * from
  * to blocks of these structures.
  */
 struct lustre_disk_dqblk {
-       __u32 dqb_id;           /* id this quota applies to */
-       __u32 dqb_ihardlimit;   /* absolute limit on allocated inodes */
-       __u32 dqb_isoftlimit;   /* preferred inode limit */
-       __u32 dqb_curinodes;    /* current # allocated inodes */
-       __u32 dqb_bhardlimit;   /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
-       __u32 dqb_bsoftlimit;   /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
-       __u64 dqb_curspace;     /* current space occupied (in bytes) */
-       __u64 dqb_btime;        /* time limit for excessive disk use */
-       __u64 dqb_itime;        /* time limit for excessive inode use */
+        __u32 dqb_id;           /* id this quota applies to */
+        __u32 dqb_ihardlimit;   /* absolute limit on allocated inodes */
+        __u32 dqb_isoftlimit;   /* preferred inode limit */
+        __u32 dqb_curinodes;    /* current # allocated inodes */
+        __u32 dqb_bhardlimit;   /* absolute limit on disk space (in QUOTABLOCK_SIZE) */
+        __u32 dqb_bsoftlimit;   /* preferred limit on disk space (in QUOTABLOCK_SIZE) */
+        __u64 dqb_curspace;     /* current space occupied (in bytes) */
+        __u64 dqb_btime;        /* time limit for excessive disk use */
+        __u64 dqb_itime;        /* time limit for excessive inode use */
 };
 
 /*
@@ -46,18 +48,18 @@ struct lustre_disk_dqblk {
  */
 /* First generic header */
 struct lustre_disk_dqheader {
-       __u32 dqh_magic;        /* Magic number identifying file */
-       __u32 dqh_version;      /* File version */
+        __u32 dqh_magic;        /* Magic number identifying file */
+        __u32 dqh_version;      /* File version */
 };
 
 /* Header with type and version specific information */
 struct lustre_disk_dqinfo {
-       __u32 dqi_bgrace;       /* Time before block soft limit becomes hard limit */
-       __u32 dqi_igrace;       /* Time before inode soft limit becomes hard limit */
-       __u32 dqi_flags;        /* Flags for quotafile (DQF_*) */
-       __u32 dqi_blocks;       /* Number of blocks in file */
-       __u32 dqi_free_blk;     /* Number of first free block in the list */
-       __u32 dqi_free_entry;   /* Number of block with at least one free entry */
+        __u32 dqi_bgrace;       /* Time before block soft limit becomes hard limit */
+        __u32 dqi_igrace;       /* Time before inode soft limit becomes hard limit */
+        __u32 dqi_flags;        /* Flags for quotafile (DQF_*) */
+        __u32 dqi_blocks;       /* Number of blocks in file */
+        __u32 dqi_free_blk;     /* Number of first free block in the list */
+        __u32 dqi_free_entry;   /* Number of block with at least one free entry */
 };
 
 /*
@@ -65,19 +67,18 @@ struct lustre_disk_dqinfo {
  *  there will be space for exactly 21 quota-entries in a block
  */
 struct lustre_disk_dqdbheader {
-       __u32 dqdh_next_free;   /* Number of next block with free entry */
-       __u32 dqdh_prev_free;   /* Number of previous block with free entry */
-       __u16 dqdh_entries;     /* Number of valid entries in block */
-       __u16 dqdh_pad1;
-       __u32 dqdh_pad2;
+        __u32 dqdh_next_free;   /* Number of next block with free entry */
+        __u32 dqdh_prev_free;   /* Number of previous block with free entry */
+        __u16 dqdh_entries;     /* Number of valid entries in block */
+        __u16 dqdh_pad1;
+        __u32 dqdh_pad2;
 };
 
-#define LUSTRE_DQINFOOFF       sizeof(struct lustre_disk_dqheader)     /* Offset of info header in file */
+#define LUSTRE_DQINFOOFF       sizeof(struct lustre_disk_dqheader)     /* Offset of info header in file */
 #define LUSTRE_DQBLKSIZE_BITS  10
-#define LUSTRE_DQBLKSIZE       (1 << LUSTRE_DQBLKSIZE_BITS)    /* Size of block with quota structures */
-#define LUSTRE_DQTREEOFF       1               /* Offset of tree in file in blocks */
-#define LUSTRE_DQTREEDEPTH     4               /* Depth of quota tree */
-#define LUSTRE_DQSTRINBLK      ((LUSTRE_DQBLKSIZE - sizeof(struct lustre_disk_dqdbheader)) / sizeof(struct lustre_disk_dqblk)) /* Number of entries in one blocks */
-
+#define LUSTRE_DQBLKSIZE       (1 << LUSTRE_DQBLKSIZE_BITS)    /* Size of block with quota structures */
+#define LUSTRE_DQTREEOFF       1       /* Offset of tree in file in blocks */
+#define LUSTRE_DQTREEDEPTH     4       /* Depth of quota tree */
+#define LUSTRE_DQSTRINBLK      ((LUSTRE_DQBLKSIZE - sizeof(struct lustre_disk_dqdbheader)) / sizeof(struct lustre_disk_dqblk)) /* Number of entries in one blocks */
 
-#endif /* lustre_quota_fmt.h */
+#endif                          /* lustre_quota_fmt.h */
index 53985d2..3b769b9 100644 (file)
 
 #include "lustre_quota_fmt.h"
 
-char *test_quotafile[2] = {"usrquota_test", "grpquota_test"};
+char *test_quotafile[2] = { "usrquota_test", "grpquota_test" };
 
 static int quotfmt_initialize(struct lustre_quota_info *lqi,
                               struct obd_device *tgt,
-                             struct lvfs_run_ctxt *saved)
+                              struct lvfs_run_ctxt *saved)
 {
-       struct lustre_disk_dqheader dqhead;
-       static const uint quota_magics[] = LUSTRE_INITQMAGICS;
-       static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
-       struct file *fp;
-       struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
-       size_t size;
-       struct dentry *de;
-       int i, rc = 0;
-       ENTRY;
-
-       push_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
-
-       sema_init(&lqi->qi_sem, 1);
-
-       for (i = 0; i < MAXQUOTAS; i++) {
-               loff_t offset = 0;
-               char *name = test_quotafile[i];
-               int namelen = strlen(name);
-
-               /* remove the stale test quotafile */
-               down(&parent_inode->i_sem);
-               de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
-               if (!IS_ERR(de) && de->d_inode)
-                       vfs_unlink(parent_inode, de);
-               if (!IS_ERR(de))
-                       dput(de);
-               up(&parent_inode->i_sem);
-
-               /* create quota file */
-               fp = filp_open(name, O_CREAT | O_EXCL, 0644);
-               if (IS_ERR(fp)) {
-                       rc = PTR_ERR(fp);
-                       CERROR("error creating test quotafile %s (rc = %d)\n",
-                              name, rc);
-                       break;
-               }
-               lqi->qi_files[i] = fp;
-
-               /* write quotafile header */
-               dqhead.dqh_magic = cpu_to_le32(quota_magics[i]);
-               dqhead.dqh_version = cpu_to_le32(quota_versions[i]);
-               size = fp->f_op->write(fp, (char *)&dqhead,
-                                      sizeof(struct lustre_disk_dqheader),
-                                      &offset);
-               if (size != sizeof(struct lustre_disk_dqheader)) {
-                       CERROR("error writing quoafile header %s (rc = %d)\n",
-                              name, rc);
-                       rc = size;
-                       break;
-               }
-       }
-
-       RETURN(rc);
+        struct lustre_disk_dqheader dqhead;
+        static const uint quota_magics[] = LUSTRE_INITQMAGICS;
+        static const uint quota_versions[] = LUSTRE_INITQVERSIONS;
+        struct file *fp;
+        struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
+        size_t size;
+        struct dentry *de;
+        int i, rc = 0;
+        ENTRY;
+
+        push_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
+
+        for (i = 0; i < MAXQUOTAS; i++) {
+                loff_t offset = 0;
+                char *name = test_quotafile[i];
+                int namelen = strlen(name);
+
+                /* remove the stale test quotafile */
+                down(&parent_inode->i_sem);
+                de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
+                if (!IS_ERR(de) && de->d_inode)
+                        vfs_unlink(parent_inode, de);
+                if (!IS_ERR(de))
+                        dput(de);
+                up(&parent_inode->i_sem);
+
+                /* create quota file */
+                fp = filp_open(name, O_CREAT | O_EXCL, 0644);
+                if (IS_ERR(fp)) {
+                        rc = PTR_ERR(fp);
+                        CERROR("error creating test quotafile %s (rc = %d)\n",
+                               name, rc);
+                        break;
+                }
+                lqi->qi_files[i] = fp;
+
+                /* write quotafile header */
+                dqhead.dqh_magic = cpu_to_le32(quota_magics[i]);
+                dqhead.dqh_version = cpu_to_le32(quota_versions[i]);
+                size = fp->f_op->write(fp, (char *)&dqhead,
+                                       sizeof(struct lustre_disk_dqheader),
+                                       &offset);
+                if (size != sizeof(struct lustre_disk_dqheader)) {
+                        CERROR("error writing quoafile header %s (rc = %d)\n",
+                               name, rc);
+                        rc = size;
+                        break;
+                }
+        }
+
+        RETURN(rc);
 }
 
 static int quotfmt_finalize(struct lustre_quota_info *lqi,
-                            struct obd_device *tgt,
-                           struct lvfs_run_ctxt *saved)
+                            struct obd_device *tgt, struct lvfs_run_ctxt *saved)
 {
-       struct dentry *de;
-       struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
-       int i, rc = 0;
-       ENTRY;
-
-       for (i = 0; i < MAXQUOTAS; i++) {
-               char *name = test_quotafile[i];
-               int namelen = strlen(name);
-
-               if (lqi->qi_files[i] == NULL)
-                       continue;
-
-               /* close quota file */
-               filp_close(lqi->qi_files[i], 0);
-
-               /* unlink quota file */
-               down(&parent_inode->i_sem);
-
-               de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
-               if (IS_ERR(de) || de->d_inode == NULL) {
-                       rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
-                       CERROR("error lookup quotafile %s (rc = %d)\n",
-                               name, rc);
-                       goto dput;
-               }
-
-               rc = vfs_unlink(parent_inode, de);
-               if (rc)
-                       CERROR("error unlink quotafile %s (rc = %d)\n",
-                               name, rc);
-dput:
-               if (!IS_ERR(de))
-                       dput(de);
-               up(&parent_inode->i_sem);
-       }
-
-       pop_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
-       RETURN(rc);
+        struct dentry *de;
+        struct inode *parent_inode = tgt->obd_lvfs_ctxt.pwd->d_inode;
+        int i, rc = 0;
+        ENTRY;
+
+        for (i = 0; i < MAXQUOTAS; i++) {
+                char *name = test_quotafile[i];
+                int namelen = strlen(name);
+
+                if (lqi->qi_files[i] == NULL)
+                        continue;
+
+                /* close quota file */
+                filp_close(lqi->qi_files[i], 0);
+
+                /* unlink quota file */
+                down(&parent_inode->i_sem);
+
+                de = lookup_one_len(name, tgt->obd_lvfs_ctxt.pwd, namelen);
+                if (IS_ERR(de) || de->d_inode == NULL) {
+                        rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
+                        CERROR("error lookup quotafile %s (rc = %d)\n",
+                               name, rc);
+                        goto dput;
+                }
+
+                rc = vfs_unlink(parent_inode, de);
+                if (rc)
+                        CERROR("error unlink quotafile %s (rc = %d)\n",
+                               name, rc);
+              dput:
+                if (!IS_ERR(de))
+                        dput(de);
+                up(&parent_inode->i_sem);
+        }
+
+        pop_ctxt(saved, &tgt->obd_lvfs_ctxt, NULL);
+        RETURN(rc);
 }
 
 static int quotfmt_test_1(struct lustre_quota_info *lqi)
 {
-       int i;
-       ENTRY;
-
-       for (i = 0; i < MAXQUOTAS; i++) {
-               if (!lustre_check_quota_file(lqi, i))
-                       RETURN(-EINVAL);
-       }
-       RETURN(0);
+        int i;
+        ENTRY;
+
+        for (i = 0; i < MAXQUOTAS; i++) {
+                if (!lustre_check_quota_file(lqi, i))
+                        RETURN(-EINVAL);
+        }
+        RETURN(0);
 }
 
 static void print_quota_info(struct lustre_quota_info *lqi)
 {
 #if 0
-       struct lustre_mem_dqinfo *dqinfo;
-       int i;
-
-       for (i = 0; i < MAXQUOTAS; i++) {
-               dqinfo = &lqi->qi_info[i];
-               printk("%s quota info:\n", i == USRQUOTA ? "user " : "group");
-               printk("dqi_bgrace(%u) dqi_igrace(%u) dqi_flags(%lu) dqi_blocks(%u) "
-                      "dqi_free_blk(%u) dqi_free_entry(%u)\n",
-                      dqinfo->dqi_bgrace, dqinfo->dqi_igrace, dqinfo->dqi_flags,
-                      dqinfo->dqi_blocks, dqinfo->dqi_free_blk,
-                      dqinfo->dqi_free_entry);
-       }
+        struct lustre_mem_dqinfo *dqinfo;
+        int i;
+
+        for (i = 0; i < MAXQUOTAS; i++) {
+                dqinfo = &lqi->qi_info[i];
+                printk("%s quota info:\n", i == USRQUOTA ? "user " : "group");
+                printk
+                    ("dqi_bgrace(%u) dqi_igrace(%u) dqi_flags(%lu) dqi_blocks(%u) "
+                     "dqi_free_blk(%u) dqi_free_entry(%u)\n",
+                     dqinfo->dqi_bgrace, dqinfo->dqi_igrace, dqinfo->dqi_flags,
+                     dqinfo->dqi_blocks, dqinfo->dqi_free_blk,
+                     dqinfo->dqi_free_entry);
+        }
 #endif
 }
 
 static int quotfmt_test_2(struct lustre_quota_info *lqi)
 {
-       int i, rc = 0;
-       ENTRY;
-
-       for (i = 0; i < MAXQUOTAS; i++) {
-               struct lustre_mem_dqinfo dqinfo;
-
-               rc = lustre_init_quota_info(lqi, i);
-               if (rc) {
-                       CERROR("init quotainfo(%d) failed! (rc:%d)\n", i, rc);
-                       break;
-               }
-               memcpy(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo));
-
-               rc = lustre_read_quota_info(lqi, i);
-               if (rc) {
-                       CERROR("read quotainfo(%d) failed! (rc:%d)\n", i, rc);
-                       break;
-               }
-
-               if(memcmp(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo))) {
-                       rc = -EINVAL;
-                       break;
-               }
-       }
-       RETURN(rc);
+        int i, rc = 0;
+        ENTRY;
+
+        for (i = 0; i < MAXQUOTAS; i++) {
+                struct lustre_mem_dqinfo dqinfo;
+
+                rc = lustre_init_quota_info(lqi, i);
+                if (rc) {
+                        CERROR("init quotainfo(%d) failed! (rc:%d)\n", i, rc);
+                        break;
+                }
+                memcpy(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo));
+
+                rc = lustre_read_quota_info(lqi, i);
+                if (rc) {
+                        CERROR("read quotainfo(%d) failed! (rc:%d)\n", i, rc);
+                        break;
+                }
+
+                if (memcmp(&dqinfo, &lqi->qi_info[i], sizeof(dqinfo))) {
+                        rc = -EINVAL;
+                        break;
+                }
+        }
+        RETURN(rc);
 }
 
 static struct lustre_dquot *get_rand_dquot(struct lustre_quota_info *lqi)
 {
-       struct lustre_dquot *dquot;
-       unsigned int rand;
-
-       OBD_ALLOC(dquot, sizeof(*dquot));
-       if (dquot == NULL)
-               return NULL;
-
-       get_random_bytes(&rand, sizeof(rand));
-       if (!rand)
-               rand = 1000;
-
-       dquot->dq_info = lqi;
-       dquot->dq_id = rand % 1000 + 1;
-       dquot->dq_type = rand % MAXQUOTAS;
-
-       dquot->dq_dqb.dqb_bhardlimit = rand;
-       dquot->dq_dqb.dqb_bsoftlimit = rand / 2;
-       dquot->dq_dqb.dqb_curspace = rand / 3;
-       dquot->dq_dqb.dqb_ihardlimit = rand;
-       dquot->dq_dqb.dqb_isoftlimit = rand / 2;
-       dquot->dq_dqb.dqb_curinodes = rand / 3;
-       dquot->dq_dqb.dqb_btime = jiffies;
-       dquot->dq_dqb.dqb_itime = jiffies;
-
-       return dquot;
+        struct lustre_dquot *dquot;
+        unsigned int rand;
+
+        OBD_ALLOC(dquot, sizeof(*dquot));
+        if (dquot == NULL)
+                return NULL;
+
+        get_random_bytes(&rand, sizeof(rand));
+        if (!rand)
+                rand = 1000;
+
+        dquot->dq_info = lqi;
+        dquot->dq_id = rand % 1000 + 1;
+        dquot->dq_type = rand % MAXQUOTAS;
+
+        dquot->dq_dqb.dqb_bhardlimit = rand;
+        dquot->dq_dqb.dqb_bsoftlimit = rand / 2;
+        dquot->dq_dqb.dqb_curspace = rand / 3;
+        dquot->dq_dqb.dqb_ihardlimit = rand;
+        dquot->dq_dqb.dqb_isoftlimit = rand / 2;
+        dquot->dq_dqb.dqb_curinodes = rand / 3;
+        dquot->dq_dqb.dqb_btime = jiffies;
+        dquot->dq_dqb.dqb_itime = jiffies;
+
+        return dquot;
 }
 
 static void put_rand_dquot(struct lustre_dquot *dquot)
 {
-       OBD_FREE(dquot, sizeof(*dquot));
+        OBD_FREE(dquot, sizeof(*dquot));
 }
 
 static int write_check_dquot(struct lustre_quota_info *lqi)
 {
-       struct lustre_dquot *dquot;
-       struct mem_dqblk dqblk;
-       int rc = 0;
-       ENTRY;
-
-       dquot = get_rand_dquot(lqi);
-       if (dquot == NULL)
-               RETURN(-ENOMEM);
-
-       /* for already exists entry, we set the dq_off by read_dquot */
-       rc = lustre_read_dquot(dquot);
-       if (rc) {
-               CERROR("read dquot failed! (rc:%d)\n", rc);
-               GOTO(out, rc);
-       }
-
-       /* for already exists entry, we rewrite it */
-       rc = lustre_commit_dquot(dquot);
-       if (rc) {
-               CERROR("commit dquot failed! (rc:%d)\n", rc);
-               GOTO(out, rc);
-       }
-       memcpy(&dqblk, &dquot->dq_dqb, sizeof(dqblk));
-       memset(&dquot->dq_dqb, 0, sizeof(dqblk));
-
-       rc = lustre_read_dquot(dquot);
-       if (rc) {
-               CERROR("read dquot failed! (rc:%d)\n", rc);
-               GOTO(out, rc);
-       }
-
-       if (memcmp(&dqblk, &dquot->dq_dqb, sizeof(dqblk))) {
-               rc = -EINVAL;
-               GOTO(out, rc);
-       }
-out:
-       put_rand_dquot(dquot);
-       RETURN(rc);
+        struct lustre_dquot *dquot;
+        struct mem_dqblk dqblk;
+        int rc = 0;
+        ENTRY;
+
+        dquot = get_rand_dquot(lqi);
+        if (dquot == NULL)
+                RETURN(-ENOMEM);
+
+        /* for already exists entry, we set the dq_off by read_dquot */
+        rc = lustre_read_dquot(dquot);
+        if (rc) {
+                CERROR("read dquot failed! (rc:%d)\n", rc);
+                GOTO(out, rc);
+        }
+
+        clear_bit(DQ_FAKE_B, &dquot->dq_flags);
+        /* for already exists entry, we rewrite it */
+        rc = lustre_commit_dquot(dquot);
+        if (rc) {
+                CERROR("commit dquot failed! (rc:%d)\n", rc);
+                GOTO(out, rc);
+        }
+        memcpy(&dqblk, &dquot->dq_dqb, sizeof(dqblk));
+        memset(&dquot->dq_dqb, 0, sizeof(dqblk));
+
+        rc = lustre_read_dquot(dquot);
+        if (rc) {
+                CERROR("read dquot failed! (rc:%d)\n", rc);
+                GOTO(out, rc);
+        }
+
+        if (memcmp(&dqblk, &dquot->dq_dqb, sizeof(dqblk))) {
+                rc = -EINVAL;
+                GOTO(out, rc);
+        }
+      out:
+        put_rand_dquot(dquot);
+        RETURN(rc);
 }
 
 static int quotfmt_test_3(struct lustre_quota_info *lqi)
 {
-       struct lustre_dquot *dquot;
-       int i = 0, rc = 0;
-       ENTRY;
-
-       dquot = get_rand_dquot(lqi);
-       if (dquot == NULL)
-               RETURN(-ENOMEM);
-repeat:
-       clear_bit(DQ_FAKE_B, &dquot->dq_flags);
-       /* write a new dquot */
-       rc = lustre_commit_dquot(dquot);
-       if (rc) {
-               CERROR("commit dquot failed! (rc:%d)\n", rc);
-               GOTO(out, rc);
-       }
-       dquot->dq_off = 0;
-       memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb));
-
-       /* check if this dquot is on disk now */
-       rc = lustre_read_dquot(dquot);
-       if (rc) {
-               CERROR("read dquot failed! (rc:%d)\n", rc);
-               GOTO(out, rc);
-       }
-       if (!dquot->dq_off || test_bit(DQ_FAKE_B, &dquot->dq_flags)) {
-               CERROR("the dquot isn't committed\n");
-               GOTO(out, rc = -EINVAL);
-       }
-
-       /* remove this dquot */
-       set_bit(DQ_FAKE_B, &dquot->dq_flags);
-       dquot->dq_dqb.dqb_curspace = 0;
-       dquot->dq_dqb.dqb_curinodes = 0;
-       rc = lustre_commit_dquot(dquot);
-       if (rc) {
-               CERROR("remove dquot failed! (rc:%d)\n", rc);
-               GOTO(out, rc);
-       }
-
-       /* check if the dquot is really removed */
-       clear_bit(DQ_FAKE_B, &dquot->dq_flags);
-       dquot->dq_off = 0;
-       rc = lustre_read_dquot(dquot);
-       if (rc) {
-               CERROR("read dquot failed! (rc:%d)\n", rc);
-               GOTO(out, rc);
-       }
-       if (!test_bit(DQ_FAKE_B, &dquot->dq_flags) || dquot->dq_off) {
-               CERROR("the dquot isn't removed!\n");
-               GOTO(out, rc = -EINVAL);
-       }
-
-       /* check if this dquot can be write again */
-       if (++i < 2)
-               goto repeat;
+        struct lustre_dquot *dquot;
+        int i = 0, rc = 0;
+        ENTRY;
+
+        dquot = get_rand_dquot(lqi);
+        if (dquot == NULL)
+                RETURN(-ENOMEM);
+      repeat:
+        clear_bit(DQ_FAKE_B, &dquot->dq_flags);
+        /* write a new dquot */
+        rc = lustre_commit_dquot(dquot);
+        if (rc) {
+                CERROR("commit dquot failed! (rc:%d)\n", rc);
+                GOTO(out, rc);
+        }
+        dquot->dq_off = 0;
+        memset(&dquot->dq_dqb, 0, sizeof(dquot->dq_dqb));
+
+        /* check if this dquot is on disk now */
+        rc = lustre_read_dquot(dquot);
+        if (rc) {
+                CERROR("read dquot failed! (rc:%d)\n", rc);
+                GOTO(out, rc);
+        }
+        if (!dquot->dq_off || test_bit(DQ_FAKE_B, &dquot->dq_flags)) {
+                CERROR("the dquot isn't committed\n");
+                GOTO(out, rc = -EINVAL);
+        }
+
+        /* remove this dquot */
+        set_bit(DQ_FAKE_B, &dquot->dq_flags);
+        dquot->dq_dqb.dqb_curspace = 0;
+        dquot->dq_dqb.dqb_curinodes = 0;
+        rc = lustre_commit_dquot(dquot);
+        if (rc) {
+                CERROR("remove dquot failed! (rc:%d)\n", rc);
+                GOTO(out, rc);
+        }
+
+        /* check if the dquot is really removed */
+        clear_bit(DQ_FAKE_B, &dquot->dq_flags);
+        dquot->dq_off = 0;
+        rc = lustre_read_dquot(dquot);
+        if (rc) {
+                CERROR("read dquot failed! (rc:%d)\n", rc);
+                GOTO(out, rc);
+        }
+        if (!test_bit(DQ_FAKE_B, &dquot->dq_flags) || dquot->dq_off) {
+                CERROR("the dquot isn't removed!\n");
+                GOTO(out, rc = -EINVAL);
+        }
+
+        /* check if this dquot can be write again */
+        if (++i < 2)
+                goto repeat;
 
         print_quota_info(lqi);
 
-out:
-       put_rand_dquot(dquot);
-       RETURN(rc);
+      out:
+        put_rand_dquot(dquot);
+        RETURN(rc);
 }
 
 static int quotfmt_test_4(struct lustre_quota_info *lqi)
 {
-       int i, rc = 0;
-       ENTRY;
-
-       for (i = 0; i < 30000; i++) {
-               rc = write_check_dquot(lqi);
-               if (rc) {
-                       CERROR("write/check dquot failed at %d! (rc:%d)\n",
-                               i, rc);
-                       break;
-               }
-       }
-       print_quota_info(lqi);
-       RETURN(rc);
+        int i, rc = 0;
+        ENTRY;
+
+        for (i = 0; i < 30000; i++) {
+                rc = write_check_dquot(lqi);
+                if (rc) {
+                        CERROR("write/check dquot failed at %d! (rc:%d)\n",
+                               i, rc);
+                        break;
+                }
+        }
+        print_quota_info(lqi);
+        RETURN(rc);
+}
+
+static int quotfmt_test_5(struct lustre_quota_info *lqi)
+{
+        int i, rc = 0;
+
+        for (i = USRQUOTA; i < MAXQUOTAS && !rc; i++) {
+                struct list_head list;
+                struct dquot_id *dqid, *tmp;
+
+                INIT_LIST_HEAD(&list);
+                rc = lustre_get_qids(lqi, i, &list);
+                if (rc) {
+                        CERROR("%s get all %ss (rc:%d):\n",
+                               rc ? "error" : "success",
+                               i == USRQUOTA ? "uid" : "gid", rc);
+                }
+                list_for_each_entry_safe(dqid, tmp, &list, di_link) {
+                        list_del_init(&dqid->di_link);
+                        if (rc == 0)
+                                printk("%d ", dqid->di_id);
+                        kfree(dqid);
+                }
+                printk("\n");
+        }
+        return rc;
 }
 
 static int quotfmt_run_tests(struct obd_device *obd, struct obd_device *tgt)
 {
         struct lvfs_run_ctxt saved;
-       struct lustre_quota_info *lqi = NULL;
-       int rc = 0;
-       ENTRY;
-
-       OBD_ALLOC(lqi, sizeof(*lqi));
-       if (lqi == NULL) {
-               CERROR("not enough memory\n");
-               RETURN(-ENOMEM);
-       }
-
-       CWARN("=== Initialize quotafile test\n");
-       rc = quotfmt_initialize(lqi, tgt, &saved);
-       if (rc)
-               GOTO(out, rc);
-
-       CWARN("=== test  1: check quota header\n");
-       rc = quotfmt_test_1(lqi);
-       if (rc) {
-               CERROR("check quota header failed! (rc:%d)\n", rc);
-               GOTO(out, rc);
-       }
-
-       CWARN("=== test  2: write/read quota info\n");
-       rc = quotfmt_test_2(lqi);
-       if (rc) {
-               CERROR("write/read quota info failed! (rc:%d)\n", rc);
-               GOTO(out, rc);
-       }
-
-       CWARN("=== test  3: write/remove dquot\n");
-       rc = quotfmt_test_3(lqi);
-       if (rc) {
-               CERROR("write/remove dquot failed! (rc:%d)\n", rc);
-               GOTO(out, rc);
-       }
-
-       CWARN("=== test  4: write/read 30000 dquot\n");
-       rc = quotfmt_test_4(lqi);
-       if (rc) {
-               CERROR("write/read 30000 dquot failed\n");
-               GOTO(out, rc);
-       }
-out:
-       CWARN("=== Finalize quotafile test\n");
-       rc = quotfmt_finalize(lqi, tgt, &saved);
-       OBD_FREE(lqi, sizeof(*lqi));
-       RETURN(rc);
+        struct lustre_quota_info *lqi = NULL;
+        int rc = 0;
+        ENTRY;
+
+        OBD_ALLOC(lqi, sizeof(*lqi));
+        if (lqi == NULL) {
+                CERROR("not enough memory\n");
+                RETURN(-ENOMEM);
+        }
+
+        CWARN("=== Initialize quotafile test\n");
+        rc = quotfmt_initialize(lqi, tgt, &saved);
+        if (rc)
+                GOTO(out, rc);
+
+        CWARN("=== test  1: check quota header\n");
+        rc = quotfmt_test_1(lqi);
+        if (rc) {
+                CERROR("check quota header failed! (rc:%d)\n", rc);
+                GOTO(out, rc);
+        }
+
+        CWARN("=== test  2: write/read quota info\n");
+        rc = quotfmt_test_2(lqi);
+        if (rc) {
+                CERROR("write/read quota info failed! (rc:%d)\n", rc);
+                GOTO(out, rc);
+        }
+
+        CWARN("=== test  3: write/remove dquot\n");
+        rc = quotfmt_test_3(lqi);
+        if (rc) {
+                CERROR("write/remove dquot failed! (rc:%d)\n", rc);
+                GOTO(out, rc);
+        }
+
+        CWARN("=== test  4: write/read 30000 dquot\n");
+        rc = quotfmt_test_4(lqi);
+        if (rc) {
+                CERROR("write/read 30000 dquot failed\n");
+                GOTO(out, rc);
+        }
+
+        CWARN("=== test 5: walk through quota file to get all ids\n");
+        rc = quotfmt_test_5(lqi);
+        if (rc) {
+                CERROR("walk through quota file failed\n");
+                GOTO(out, rc);
+        }
+      out:
+        CWARN("=== Finalize quotafile test\n");
+        rc = quotfmt_finalize(lqi, tgt, &saved);
+        OBD_FREE(lqi, sizeof(*lqi));
+        RETURN(rc);
 }
 
 static int quotfmt_test_cleanup(struct obd_device *obd)
 {
-       ENTRY;
+        ENTRY;
         lprocfs_obd_cleanup(obd);
         RETURN(0);
 }
@@ -406,7 +438,7 @@ static int quotfmt_test_setup(struct obd_device *obd, obd_count len, void *buf)
 {
         struct lprocfs_static_vars lvars;
         struct lustre_cfg *lcfg = buf;
-       struct obd_device *tgt;
+        struct obd_device *tgt;
         int rc;
         ENTRY;
 
@@ -433,24 +465,24 @@ static int quotfmt_test_setup(struct obd_device *obd, obd_count len, void *buf)
 }
 
 static struct obd_ops quotfmt_obd_ops = {
-        .o_owner       = THIS_MODULE,
-        .o_setup       = quotfmt_test_setup,
-        .o_cleanup     = quotfmt_test_cleanup,
+        .o_owner = THIS_MODULE,
+        .o_setup = quotfmt_test_setup,
+        .o_cleanup = quotfmt_test_cleanup,
 };
 
 #ifdef LPROCFS
 static struct lprocfs_vars lprocfs_obd_vars[] = { {0} };
 static struct lprocfs_vars lprocfs_module_vars[] = { {0} };
+
 LPROCFS_INIT_VARS(quotfmt_test, lprocfs_module_vars, lprocfs_obd_vars)
 #endif
-
 static int __init quotfmt_test_init(void)
 {
         struct lprocfs_static_vars lvars;
 
         lprocfs_init_vars(quotfmt_test, &lvars);
         return class_register_type(&quotfmt_obd_ops, lvars.module_vars,
-                                  "quotfmt_test");
+                                   "quotfmt_test");
 }
 
 static void __exit quotfmt_test_exit(void)
index 5475efb..8c9d9cd 100644 (file)
@@ -312,8 +312,7 @@ int client_obd_setup(struct obd_device *obddev, obd_count len, void *buf)
                 }
         }
 
-        spin_lock_init(&cli->cl_qchk_lock);
-        cli->cl_qchk_stat = CL_NO_QUOTACHECK;
+        cli->cl_qchk_stat = CL_NOT_QUOTACHECKED;
 
         RETURN(rc);
 
@@ -1013,7 +1012,7 @@ static void process_recovery_queue(struct obd_device *obd)
                 obd->obd_replayed_requests++;
                 reset_recovery_timer(obd);
                 /* bug 1580: decide how to properly sync() in recovery */
-                //mds_fsync_super(mds->mds_sb);
+                //mds_fsync_super(obd->u.obt.obt_sb);
                 class_export_put(req->rq_export);
                 if (req->rq_reply_state != NULL) {
                         ptlrpc_rs_decref(req->rq_reply_state);
@@ -1340,3 +1339,64 @@ void target_committed_to_req(struct ptlrpc_request *req)
 }
 
 EXPORT_SYMBOL(target_committed_to_req);
+
+#ifdef HAVE_QUOTA_SUPPORT
+int target_handle_qc_callback(struct ptlrpc_request *req)
+{
+        struct obd_quotactl *oqctl;
+        struct client_obd *cli = &req->rq_export->exp_obd->u.cli;
+
+        oqctl = lustre_swab_reqbuf(req, 0, sizeof(*oqctl),
+                                   lustre_swab_obd_quotactl);
+
+        cli->cl_qchk_stat = oqctl->qc_stat;
+
+        return 0;
+}
+
+int target_handle_dqacq_callback(struct ptlrpc_request *req)
+{
+#ifdef __KERNEL__
+        struct obd_device *obd = req->rq_export->exp_obd;
+        struct obd_device *master_obd;
+        struct lustre_quota_ctxt *qctxt;
+        struct qunit_data *qdata, *rep;
+        int rc = 0, repsize = sizeof(struct qunit_data);
+        ENTRY;
+        
+        rc = lustre_pack_reply(req, 1, &repsize, NULL);
+        if (rc) {
+                CERROR("packing reply failed!: rc = %d\n", rc);
+                RETURN(rc);
+        }
+        rep = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*rep));
+        LASSERT(rep);
+        
+        qdata = lustre_swab_reqbuf(req, 0, sizeof(*qdata), lustre_swab_qdata);
+        if (qdata == NULL) {
+                CERROR("unpacking request buffer failed!");
+                RETURN(-EPROTO);
+        }
+
+        /* we use the observer */
+        LASSERT(obd->obd_observer && obd->obd_observer->obd_observer);
+        master_obd = obd->obd_observer->obd_observer;
+        qctxt = &master_obd->u.obt.obt_qctxt;
+        
+        LASSERT(qctxt->lqc_handler);
+        rc = qctxt->lqc_handler(master_obd, qdata, req->rq_reqmsg->opc);
+        if (rc && rc != -EDQUOT)
+                CDEBUG(rc == -EBUSY  ? D_QUOTA : D_ERROR, 
+                       "dqacq failed! (rc:%d)\n", rc);
+        
+        /* the qd_count might be changed in lqc_handler */
+        memcpy(rep, qdata, sizeof(*rep));
+        req->rq_status = rc;
+        rc = ptlrpc_reply(req);
+        
+        RETURN(rc);     
+#else
+        return 0;
+#endif /* !__KERNEL__ */
+}
+#endif /* HAVE_QUOTA_SUPPORT */
index 9b4829a..72b71e6 100644 (file)
@@ -18,6 +18,10 @@ LUSTRE_LIBS = libllite.a \
               $(top_builddir)/lustre/obdclass/liblustreclass.a \
               $(top_builddir)/lustre/lvfs/liblvfs.a
 
+if QUOTA
+QUOTA_LIBS = $(top_builddir)/lustre/quota/libquota.a
+endif
+
 LND_LIBS =
 if BUILD_USOCKLND
 LND_LIBS +=    $(top_builddir)/lnet/ulnds/socklnd/libsocklnd.a
@@ -56,8 +60,8 @@ libllite_a_SOURCES = llite_lib.c super.c namei.c rw.c file.c dir.c \
 liblustre_a_SOURCES = llite_lib.c super.c namei.c rw.c file.c dir.c \
                     llite_lib.h
 
-liblustre.a : $(LUSTRE_LIBS) $(LND_LIBS) $(LNET_LIBS) $(SYSIO_LIBS)
-       sh $(srcdir)/genlib.sh "$(SYSIO)" "$(LIBS)" "$(LND_LIBS)" "$(PTHREAD_LIBS)"
+liblustre.a : $(LUSTRE_LIBS) $(LND_LIBS) $(LNET_LIBS) $(SYSIO_LIBS) $(QUOTA_LIBS)
+       sh $(srcdir)/genlib.sh "$(SYSIO)" "$(LIBS)" "$(LND_LIBS)" "$(PTHREAD_LIBS)" "$(QUOTA_LIBS)" 
 
 EXTRA_DIST = genlib.sh
 
index b615afd..c7e7e06 100755 (executable)
@@ -21,6 +21,7 @@ SYSIO=$1
 LIBS=$2
 LND_LIBS=$3
 PTHREAD_LIBS=$4
+QUOTA_LIBS=$5
 
 if [ ! -f $SYSIO/lib/libsysio.a ]; then
   echo "ERROR: $SYSIO/lib/libsysio.a dosen't exist"
@@ -76,6 +77,10 @@ if $(echo "$LND_LIBS" | grep "ptllnd" >/dev/null) ; then
 fi
 build_obj_list ../../lnet/lnet liblnet.a
 
+if [ "x$QUOTA_LIBS" != "x" ]; then
+  build_obj_list ../quota libquota.a
+fi
+
 # create static lib lsupport
 rm -f $CWD/liblsupport.a
 $AR -cru $CWD/liblsupport.a $ALL_OBJS
index a59ae84..bbb788b 100644 (file)
@@ -62,6 +62,14 @@ void *inter_module_get(char *arg)
                 return ldlm_namespace_cleanup;
         else if (!strcmp(arg, "ldlm_replay_locks"))
                 return ldlm_replay_locks;
+#ifdef HAVE_QUOTA_SUPPORT
+        else if (!strcmp(arg, "osc_quota_interface"))
+                return &osc_quota_interface;
+        else if (!strcmp(arg, "mdc_quota_interface"))
+                return &mdc_quota_interface;
+        else if (!strcmp(arg, "lov_quota_interface"))
+                return &lov_quota_interface;
+#endif
         else
                 return NULL;
 }
index dd5c42d..48838dd 100644 (file)
@@ -366,25 +366,14 @@ done:
         RETURN(rc);
 }
 
-#define Q_CONV(tgt, src, member) (tgt)->member = (src)->member
-
-#define QCTLCONV(tgt, src)                             \
-do {                                                   \
-        Q_CONV(tgt, src, qc_cmd);                      \
-        Q_CONV(tgt, src, qc_type);                     \
-        Q_CONV(tgt, src, qc_id);                       \
-        Q_CONV(tgt, src, qc_stat);                     \
-        Q_CONV(tgt, src, qc_dqinfo.dqi_bgrace);        \
-        Q_CONV(tgt, src, qc_dqinfo.dqi_igrace);        \
-        Q_CONV(tgt, src, qc_dqinfo.dqi_flags);         \
-        Q_CONV(tgt, src, qc_dqblk.dqb_ihardlimit);     \
-        Q_CONV(tgt, src, qc_dqblk.dqb_isoftlimit);     \
-        Q_CONV(tgt, src, qc_dqblk.dqb_curinodes);      \
-        Q_CONV(tgt, src, qc_dqblk.dqb_bhardlimit);     \
-        Q_CONV(tgt, src, qc_dqblk.dqb_bsoftlimit);     \
-        Q_CONV(tgt, src, qc_dqblk.dqb_curspace);       \
-        Q_CONV(tgt, src, qc_dqblk.dqb_btime);          \
-        Q_CONV(tgt, src, qc_dqblk.dqb_itime);          \
+#define QCTL_COPY(out, in)              \
+do {                                    \
+        Q_COPY(out, in, qc_cmd);        \
+        Q_COPY(out, in, qc_type);       \
+        Q_COPY(out, in, qc_id);         \
+        Q_COPY(out, in, qc_stat);       \
+        Q_COPY(out, in, qc_dqinfo);     \
+        Q_COPY(out, in, qc_dqblk);      \
 } while (0)
 
 static int ll_dir_ioctl(struct inode *inode, struct file *file,
@@ -671,114 +660,131 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file,
                 RETURN(rc);
         }
         case OBD_IOC_QUOTACHECK: {
-                struct obd_quotactl oqctl = { 0, };
+                struct obd_quotactl *oqctl;
                 int rc, error = 0;
 
                 if (!capable(CAP_SYS_ADMIN))
                         RETURN(-EPERM);
 
-                oqctl.qc_type = arg;
-                rc = obd_quotacheck(sbi->ll_mdc_exp, &oqctl);
+                OBD_ALLOC_PTR(oqctl);
+                if (!oqctl)
+                        RETURN(-ENOMEM);
+                oqctl->qc_type = arg;
+                rc = obd_quotacheck(sbi->ll_mdc_exp, oqctl);
                 if (rc < 0) {
                         CDEBUG(D_INFO, "mdc_quotacheck failed: rc %d\n", rc);
                         error = rc;
                 }
 
-                rc = obd_quotacheck(sbi->ll_osc_exp, &oqctl);
+                rc = obd_quotacheck(sbi->ll_osc_exp, oqctl);
                 if (rc < 0)
                         CDEBUG(D_INFO, "osc_quotacheck failed: rc %d\n", rc);
 
-                if (error)
-                        rc = error;
-                return rc;
+                OBD_FREE_PTR(oqctl);
+                return error ?: rc;
         }
         case OBD_IOC_POLL_QUOTACHECK: {
-                struct if_quotacheck check;
+                struct if_quotacheck *check;
                 int rc;
 
                 if (!capable(CAP_SYS_ADMIN))
                         RETURN(-EPERM);
 
-                rc = obd_iocontrol(cmd, sbi->ll_mdc_exp, 0, (void *)&check,
+                OBD_ALLOC_PTR(check);
+                if (!check)
+                        RETURN(-ENOMEM);
+
+                rc = obd_iocontrol(cmd, sbi->ll_mdc_exp, 0, (void *)check,
                                    NULL);
-                if (check.stat == -ENODATA)
-                        rc = check.stat;
                 if (rc) {
-                        CDEBUG(D_QUOTA, "mdc ioctl %d failed: rc %d\n",
-                               cmd, check.stat);
-                        if (copy_to_user((void *)arg, &check, sizeof(check)))
-                                RETURN(-EFAULT);
-                        RETURN(rc);
+                        CDEBUG(D_QUOTA, "mdc ioctl %d failed: %d\n", cmd, rc);
+                        if (copy_to_user((void *)arg, check, sizeof(*check)))
+                                rc = -EFAULT;
+                        GOTO(out_poll, rc);
                 }
 
-                rc = obd_iocontrol(cmd, sbi->ll_osc_exp, 0, (void *)&check,
+                rc = obd_iocontrol(cmd, sbi->ll_osc_exp, 0, (void *)check,
                                    NULL);
-                if (check.stat == -ENODATA)
-                        rc = check.stat;
                 if (rc) {
-                        CDEBUG(D_QUOTA, "osc ioctl %d failed: rc %d\n",
-                               cmd, rc);
-                        if (copy_to_user((void *)arg, &check, sizeof(check)))
-                                RETURN(-EFAULT);
-                        RETURN(rc);
+                        CDEBUG(D_QUOTA, "osc ioctl %d failed: %d\n", cmd, rc);
+                        if (copy_to_user((void *)arg, check, sizeof(*check)))
+                                rc = -EFAULT;
+                        GOTO(out_poll, rc);
                 }
-                 
-                RETURN(0);
+        out_poll:                 
+                OBD_FREE_PTR(check);
+                RETURN(rc);
         }
 #if HAVE_QUOTA_SUPPORT
         case OBD_IOC_QUOTACTL: {
-                struct if_quotactl qctl;
-                struct obd_quotactl oqctl;
+                struct if_quotactl *qctl;
+                struct obd_quotactl *oqctl;
                 
-                int cmd, type, id, rc = 0, error = 0;
+                int cmd, type, id, rc = 0;
 
-                if (copy_from_user(&qctl, (void *)arg, sizeof(qctl)))
-                        RETURN(-EFAULT);
+                OBD_ALLOC_PTR(qctl);
+                if (!qctl)
+                        RETURN(-ENOMEM);
 
-                cmd = qctl.qc_cmd;
-                type = qctl.qc_type;
-                id = qctl.qc_id;
+                OBD_ALLOC_PTR(oqctl);
+                if (!oqctl) {
+                        OBD_FREE_PTR(qctl);
+                        RETURN(-ENOMEM);
+                }
+                if (copy_from_user(qctl, (void *)arg, sizeof(*qctl)))
+                        GOTO(out_quotactl, rc = -EFAULT);
+
+                cmd = qctl->qc_cmd;
+                type = qctl->qc_type;
+                id = qctl->qc_id;
                 switch (cmd) {
                 case Q_QUOTAON:
                 case Q_QUOTAOFF:
                 case Q_SETQUOTA:
                 case Q_SETINFO:
                         if (!capable(CAP_SYS_ADMIN))
-                                RETURN(-EPERM);
+                                GOTO(out_quotactl, rc = -EPERM);
                         break;
                 case Q_GETQUOTA:
                         if (((type == USRQUOTA && current->euid != id) ||
                              (type == GRPQUOTA && !in_egroup_p(id))) &&
                             !capable(CAP_SYS_ADMIN))
-                                RETURN(-EPERM);
+                                GOTO(out_quotactl, rc = -EPERM);
+
+                        /* XXX: dqb_valid is borrowed as a flag to mark that
+                         *      only mds quota is wanted */
+                        if (qctl->qc_dqblk.dqb_valid)
+                                qctl->obd_uuid = 
+                                       sbi->ll_mdc_exp->exp_obd->u.cli.
+                                       cl_import->imp_target_uuid;
                         break;
                 case Q_GETINFO:
                         break;
                 default:
-                        RETURN(-EINVAL);
+                        CERROR("unsupported quotactl op: %#x\n", cmd);
+                        GOTO(out_quotactl, -ENOTTY);
                 }
 
-                QCTLCONV(&oqctl, &qctl);
+                QCTL_COPY(oqctl, qctl);
 
-                if (qctl.obd_uuid.uuid[0]) {
+                if (qctl->obd_uuid.uuid[0]) {
                         struct obd_device *obd;
-                        struct obd_uuid *uuid = &qctl.obd_uuid;
-
-                        if (cmd == Q_GETINFO)
-                                oqctl.qc_cmd = Q_GETOINFO;
-                        else if (cmd == Q_GETQUOTA)
-                                oqctl.qc_cmd = Q_GETOQUOTA;
-                        else
-                                RETURN(-EINVAL);
+                        struct obd_uuid *uuid = &qctl->obd_uuid;
 
-                        rc = -ENOENT;
                         obd = class_find_client_notype(uuid,
                                          &sbi->ll_osc_exp->exp_obd->obd_uuid);
                         if (!obd)
-                                RETURN(rc);
+                                GOTO(out_quotactl, rc = -ENOENT);
+
+                        if (cmd == Q_GETINFO)
+                                oqctl->qc_cmd = Q_GETOINFO;
+                        else if (cmd == Q_GETQUOTA)
+                                oqctl->qc_cmd = Q_GETOQUOTA;
+                        else
+                                GOTO(out_quotactl, rc = -EINVAL);
 
                         if (sbi->ll_mdc_exp->exp_obd == obd) {
-                                rc = obd_quotactl(sbi->ll_mdc_exp, &oqctl);
+                                rc = obd_quotactl(sbi->ll_mdc_exp, oqctl);
                         } else {
                                 int i;
                                 struct obd_export *exp;
@@ -792,49 +798,35 @@ static int ll_dir_ioctl(struct inode *inode, struct file *file,
                                                 continue;
 
                                         if (exp->exp_obd == obd) {
-                                                rc = obd_quotactl(exp, &oqctl);
+                                                rc = obd_quotactl(exp, oqctl);
                                                 break;
                                         }
                                 }
                         }
 
-                        QCTLCONV(&qctl, &oqctl);
-
-                        if (copy_to_user((void *)arg, &qctl, sizeof(qctl)))
-                                RETURN(-EFAULT);
-
-                        RETURN(rc);
-                }
+                        oqctl->qc_cmd = cmd;
+                        QCTL_COPY(qctl, oqctl);
 
-                if (cmd == Q_SETQUOTA)
-                        oqctl.qc_dqblk.dqb_valid = QIF_LIMITS;
+                        if (copy_to_user((void *)arg, qctl, sizeof(*qctl)))
+                                rc = -EFAULT;
 
-                rc = obd_quotactl(sbi->ll_mdc_exp, &oqctl);
-                if (rc) {
-                        if (rc == -EBUSY && cmd == Q_QUOTAON)
-                                error = rc;
-                        else
-                                RETURN(rc);
+                        GOTO(out_quotactl, rc);
                 }
 
-                if (cmd == Q_QUOTAON || cmd == Q_QUOTAOFF) {
-                        rc = obd_quotactl(sbi->ll_osc_exp, &oqctl);
-                        if (rc) {
-                                if (rc != -EBUSY && cmd == Q_QUOTAON) {
-                                        oqctl.qc_cmd = Q_QUOTAOFF;
-                                        obd_quotactl(sbi->ll_mdc_exp, &oqctl);
-                                        obd_quotactl(sbi->ll_osc_exp, &oqctl);
-                                }
-                                RETURN(rc);
-                        }
+                rc = obd_quotactl(sbi->ll_mdc_exp, oqctl);
+                if (rc && rc != -EBUSY && cmd == Q_QUOTAON) {
+                        oqctl->qc_cmd = Q_QUOTAOFF;
+                        obd_quotactl(sbi->ll_mdc_exp, oqctl);
                 }
 
-                QCTLCONV(&qctl, &oqctl);
-
-                if (copy_to_user((void *)arg, &qctl, sizeof(qctl)))
-                        return -EFAULT;
+                QCTL_COPY(qctl, oqctl);
 
-                RETURN(rc?:error);
+                if (copy_to_user((void *)arg, qctl, sizeof(*qctl)))
+                        rc = -EFAULT;
+        out_quotactl:
+                OBD_FREE_PTR(qctl);
+                OBD_FREE_PTR(oqctl);
+                RETURN(rc);
         }
 #endif /* HAVE_QUOTA_SUPPORT */
         case OBD_IOC_GETNAME: {  
index c969c0e..35fa8c7 100644 (file)
@@ -271,7 +271,8 @@ struct ll_async_page {
         unsigned int     llap_write_queued:1,
                          llap_defer_uptodate:1,
                          llap_origin:3,
-                         llap_ra_used:1;
+                         llap_ra_used:1,
+                         llap_ignore_quota:1;
         void            *llap_cookie;
         struct page     *llap_page;
         struct list_head llap_pending_write;
index 6d5ea5f..fcbd874 100644 (file)
@@ -370,6 +370,7 @@ static void ll_ap_fill_obdo(void *data, int cmd, struct obdo *oa)
 
         llap = LLAP_FROM_COOKIE(data);
         ll_inode_fill_obdo(llap->llap_page->mapping->host, cmd, oa);
+
         EXIT;
 }
 
@@ -601,7 +602,7 @@ static int queue_or_sync_write(struct obd_export *exp, struct inode *inode,
         unsigned long size_index = inode->i_size >> PAGE_SHIFT;
         struct obd_io_group *oig;
         struct ll_sb_info *sbi = ll_i2sbi(inode);
-        int rc, noquot = capable(CAP_SYS_RESOURCE) ? OBD_BRW_NOQUOTA : 0;
+        int rc, noquot = llap->llap_ignore_quota ? OBD_BRW_NOQUOTA : 0;
         ENTRY;
 
         /* _make_ready only sees llap once we've unlocked the page */
@@ -708,6 +709,8 @@ int ll_commit_write(struct file *file, struct page *page, unsigned from,
         if (exp == NULL)
                 RETURN(-EINVAL);
 
+        llap->llap_ignore_quota = capable(CAP_SYS_RESOURCE);
+
         /* queue a write for some time in the future the first time we
          * dirty the page */
         if (!PageDirty(page)) {
index 097e7c8..7bba3a0 100644 (file)
@@ -221,8 +221,4 @@ int lov_getstripe(struct obd_export *exp,
 /* lproc_lov.c */
 extern struct file_operations lov_proc_target_fops;
 
-/* Quota stuff */
-int lov_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl);
-int lov_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl);
-
 #endif
index 722f42b..e92e430 100644 (file)
@@ -61,8 +61,7 @@
  * Unset cookies should be all-zero (which will never occur naturally). */
 static int lov_llog_origin_add(struct llog_ctxt *ctxt,
                         struct llog_rec_hdr *rec, struct lov_stripe_md *lsm,
-                        struct llog_cookie *logcookies, int numcookies,
-                        llog_fill_rec_cb_t fill_cb)
+                        struct llog_cookie *logcookies, int numcookies)
 {
         struct obd_device *obd = ctxt->loc_obd;
         struct lov_obd *lov = &obd->u.lov;
@@ -75,16 +74,27 @@ static int lov_llog_origin_add(struct llog_ctxt *ctxt,
         for (i = 0,loi = lsm->lsm_oinfo; i < lsm->lsm_stripe_count; i++,loi++) {
                 struct obd_device *child = lov->tgts[loi->loi_ost_idx].ltd_exp->exp_obd; 
                 struct llog_ctxt *cctxt = llog_get_context(child, ctxt->loc_idx);
-                struct llog_fill_rec_data data;
 
                 /* fill mds unlink/setattr log record */
-                data.lfd_id = loi->loi_id;
-                data.lfd_ogen = loi->loi_gr;
-                fill_cb(rec, &data);
+                switch (rec->lrh_type) {
+                case MDS_UNLINK_REC: {
+                        struct llog_unlink_rec *lur = (struct llog_unlink_rec *)rec;
+                        lur->lur_oid = loi->loi_id;
+                        lur->lur_ogen = loi->loi_gr;
+                        break;
+                }
+                case MDS_SETATTR_REC: {
+                        struct llog_setattr_rec *lsr = (struct llog_setattr_rec *)rec;
+                        lsr->lsr_oid = loi->loi_id;
+                        lsr->lsr_ogen = loi->loi_gr;
+                        break;
+                }
+                default:
+                        break;
+                }
 
                 rc += llog_add(cctxt, rec, NULL, logcookies + rc,
-                                numcookies - rc, fill_cb);
-
+                                numcookies - rc);
         }
 
         RETURN(rc);
index 4a1b437..c045db2 100644 (file)
@@ -1292,6 +1292,7 @@ static int lov_ap_make_ready(void *data, int cmd)
 
         return lap->lap_caller_ops->ap_make_ready(lap->lap_caller_data, cmd);
 }
+
 static int lov_ap_refresh_count(void *data, int cmd)
 {
         struct lov_async_page *lap = LAP_FROM_COOKIE(data);
@@ -1299,6 +1300,7 @@ static int lov_ap_refresh_count(void *data, int cmd)
         return lap->lap_caller_ops->ap_refresh_count(lap->lap_caller_data,
                                                      cmd);
 }
+
 static void lov_ap_fill_obdo(void *data, int cmd, struct obdo *oa)
 {
         struct lov_async_page *lap = LAP_FROM_COOKIE(data);
@@ -1896,8 +1898,10 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
                 break;
         default: {
                 int set = 0;
+
                 if (count == 0)
                         RETURN(-ENOTTY);
+
                 rc = 0;
                 for (i = 0; i < count; i++) {
                         int err;
@@ -1908,7 +1912,9 @@ static int lov_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
 
                         err = obd_iocontrol(cmd, lov->tgts[i].ltd_exp,
                                             len, karg, uarg);
-                        if (err) {
+                        if (err == -ENODATA && cmd == OBD_IOC_POLL_QUOTACHECK) {
+                                RETURN(err);
+                        } else if (err) {
                                 if (lov->tgts[i].active) {
                                         CERROR("error: iocontrol OSC %s on OST "
                                                "idx %d cmd %x: err = %d\n",
@@ -2175,7 +2181,6 @@ int lov_complete_many(struct obd_export *exp, struct lov_stripe_md *lsm,
 }
 #endif
 
-
 void lov_stripe_lock(struct lov_stripe_md *md)
 {
         LASSERT(md->lsm_lock_owner != current);
@@ -2233,12 +2238,11 @@ struct obd_ops lov_obd_ops = {
         .o_llog_init           = lov_llog_init,
         .o_llog_finish         = lov_llog_finish,
         .o_notify              = lov_notify,
-#ifdef HAVE_QUOTA_SUPPORT
-        .o_quotacheck          = lov_quotacheck,
-        .o_quotactl            = lov_quotactl,
-#endif
 };
 
+static quota_interface_t *quota_interface = NULL;
+extern quota_interface_t lov_quota_interface;
+
 int __init lov_init(void)
 {
         struct lprocfs_static_vars lvars;
@@ -2246,14 +2250,24 @@ int __init lov_init(void)
         ENTRY;
 
         lprocfs_init_vars(lov, &lvars);
+
+        quota_interface = PORTAL_SYMBOL_GET(lov_quota_interface);
+        init_obd_quota_ops(quota_interface, &lov_obd_ops);
+        
         rc = class_register_type(&lov_obd_ops, lvars.module_vars,
                                  OBD_LOV_DEVICENAME);
+        if (rc && quota_interface)
+                PORTAL_SYMBOL_PUT(osc_quota_interface);
+
         RETURN(rc);
 }
 
 #ifdef __KERNEL__
 static void /*__exit*/ lov_exit(void)
 {
+        if (quota_interface)
+                PORTAL_SYMBOL_PUT(lov_quota_interface);
+
         class_unregister_type(OBD_LOV_DEVICENAME);
 }
 
index dc286b7..585f5a6 100644 (file)
@@ -1,9 +1,7 @@
-MODULES := lvfs #quotactl_test quotacheck_test
+MODULES := lvfs
 @SERVER_TRUE@MODULES += fsfilt_@BACKINGFS@
 
 lvfs-objs := lvfs_common.o lvfs_linux.o fsfilt.o upcall_cache.o
-#quotactl-objs := quotactl_test.o
-#quotaccheck-objs := quotacheck_test.o
 
 ifeq ($(PATCHLEVEL),6)
 fsfilt_@BACKINGFS@-objs := fsfilt-@BACKINGFS@.o
index 25ada73..1b20288 100644 (file)
@@ -1195,6 +1195,248 @@ static int fsfilt_ext3_get_op_len(int op, struct fsfilt_objinfo *fso, int logs)
         return 0;
 }
 
+static const char *op_quotafile[] = { "lquota.user", "lquota.group" };
+
+#define DQINFO_COPY(out, in)                    \
+do {                                            \
+        Q_COPY(out, in, dqi_bgrace);            \
+        Q_COPY(out, in, dqi_igrace);            \
+        Q_COPY(out, in, dqi_flags);             \
+        Q_COPY(out, in, dqi_valid);             \
+} while (0)
+
+#define DQBLK_COPY(out, in)                     \
+do {                                            \
+        Q_COPY(out, in, dqb_bhardlimit);        \
+        Q_COPY(out, in, dqb_bsoftlimit);        \
+        Q_COPY(out, in, dqb_curspace);          \
+        Q_COPY(out, in, dqb_ihardlimit);        \
+        Q_COPY(out, in, dqb_isoftlimit);        \
+        Q_COPY(out, in, dqb_curinodes);         \
+        Q_COPY(out, in, dqb_btime);             \
+        Q_COPY(out, in, dqb_itime);             \
+        Q_COPY(out, in, dqb_valid);             \
+} while (0)
+
+      
+
+static int fsfilt_ext3_quotactl(struct super_block *sb,
+                                struct obd_quotactl *oqc)
+{
+        int i, rc = 0, error = 0;
+        struct quotactl_ops *qcop;
+        struct if_dqinfo *info;
+        struct if_dqblk *dqblk;
+        ENTRY;
+
+        if (!sb->s_qcop)
+                RETURN(-ENOSYS);
+
+        OBD_ALLOC_PTR(info);
+        if (!info)
+                RETURN(-ENOMEM);
+        OBD_ALLOC_PTR(dqblk);
+        if (!dqblk) {
+                OBD_FREE_PTR(info);
+                RETURN(-ENOMEM);
+        }
+
+        DQINFO_COPY(info, &oqc->qc_dqinfo);
+        DQBLK_COPY(dqblk, &oqc->qc_dqblk);
+
+        qcop = sb->s_qcop;
+        if (oqc->qc_cmd == Q_QUOTAON || oqc->qc_cmd == Q_QUOTAOFF) {
+                for (i = 0; i < MAXQUOTAS; i++) {
+                        if (!Q_TYPESET(oqc, i))
+                                continue;
+
+                        if (oqc->qc_cmd == Q_QUOTAON) {
+                                if (!qcop->quota_on)
+                                        GOTO(out, rc = -ENOSYS);
+                                rc = qcop->quota_on(sb, i, oqc->qc_id,
+                                                    (char *)op_quotafile[i]);
+                        } else if (oqc->qc_cmd == Q_QUOTAOFF) {
+                                if (!qcop->quota_off)
+                                        GOTO(out, rc = -ENOSYS);
+                                rc = qcop->quota_off(sb, i);
+                        }
+
+                        if (rc == -EBUSY)
+                                error = rc;
+                        else if (rc)
+                                GOTO(out, rc);
+                }
+                GOTO(out, rc ?: error);
+        }
+
+        switch (oqc->qc_cmd) {
+        case Q_GETOINFO:
+        case Q_GETINFO:
+                if (!qcop->get_info)
+                        GOTO(out, rc = -ENOSYS);
+                rc = qcop->get_info(sb, oqc->qc_type, info);
+                break;
+        case Q_SETQUOTA:
+        case Q_INITQUOTA:
+                if (!qcop->set_dqblk)
+                        GOTO(out, rc = -ENOSYS);
+                rc = qcop->set_dqblk(sb, oqc->qc_type, oqc->qc_id, dqblk);
+                break;
+        case Q_GETOQUOTA:
+        case Q_GETQUOTA:
+                if (!qcop->get_dqblk)
+                        GOTO(out, rc = -ENOSYS);
+                rc = qcop->get_dqblk(sb, oqc->qc_type, oqc->qc_id, dqblk);
+                break;
+        case Q_SYNC:
+                if (!sb->s_qcop->quota_sync)
+                        GOTO(out, rc = -ENOSYS);
+                qcop->quota_sync(sb, oqc->qc_type);
+                break;
+        default:
+                CERROR("unsupported quotactl command: %d", oqc->qc_cmd);
+                LBUG();
+        }
+out:
+        DQINFO_COPY(&oqc->qc_dqinfo, info);
+        DQBLK_COPY(&oqc->qc_dqblk, dqblk);
+
+        OBD_FREE_PTR(info);
+        OBD_FREE_PTR(dqblk);
+
+        if (rc)
+                CDEBUG(D_QUOTA, "quotactl command %#x, id %u, type %d "
+                                "failed: %d\n",
+                       oqc->qc_cmd, oqc->qc_id, oqc->qc_type, rc);
+        RETURN(rc);
+}
+
+struct chk_dqblk{
+        struct hlist_node       dqb_hash;        /* quotacheck hash */
+        struct list_head        dqb_list;        /* in list also */
+        qid_t                   dqb_id;          /* uid/gid */
+        short                   dqb_type;        /* USRQUOTA/GRPQUOTA */
+        __u32                   dqb_bhardlimit;  /* block hard limit */
+        __u32                   dqb_bsoftlimit;  /* block soft limit */
+        qsize_t                 dqb_curspace;    /* current space */
+        __u32                   dqb_ihardlimit;  /* inode hard limit */
+        __u32                   dqb_isoftlimit;  /* inode soft limit */
+        __u32                   dqb_curinodes;   /* current inodes */
+        __u64                   dqb_btime;       /* block grace time */
+        __u64                   dqb_itime;       /* inode grace time */
+        __u32                   dqb_valid;       /* flag for above fields */
+};
+
+static inline unsigned int const
+chkquot_hash(qid_t id, int type)
+{
+        return (id * (MAXQUOTAS - type)) % NR_DQHASH;
+}
+
+static inline struct chk_dqblk *
+find_chkquot(struct hlist_head *head, qid_t id, int type)
+{
+        struct hlist_node *node;
+        struct chk_dqblk *cdqb;
+
+        hlist_for_each(node, head) {
+                cdqb = hlist_entry(node, struct chk_dqblk, dqb_hash);
+                if (cdqb->dqb_id == id && cdqb->dqb_type == type)
+                        return cdqb;
+        }
+
+        return NULL;
+}
+
+static struct chk_dqblk *alloc_chkquot(qid_t id, int type)
+{
+        struct chk_dqblk *cdqb;
+
+        OBD_ALLOC_PTR(cdqb);
+        if (cdqb) {
+                INIT_HLIST_NODE(&cdqb->dqb_hash);
+                INIT_LIST_HEAD(&cdqb->dqb_list);
+                cdqb->dqb_id = id;
+                cdqb->dqb_type = type;
+        }
+
+        return cdqb;
+}
+
+static struct chk_dqblk *
+cqget(struct super_block *sb, struct hlist_head *hash, struct list_head *list,
+      qid_t id, int type, int first_check)
+{
+        struct hlist_head *head = hash + chkquot_hash(id, type);
+        struct if_dqblk dqb;
+        struct chk_dqblk *cdqb;
+        int rc;
+
+        cdqb = find_chkquot(head, id, type);
+        if (cdqb)
+                return cdqb;
+
+        cdqb = alloc_chkquot(id, type);
+        if (!cdqb)
+                return NULL;
+
+        if (!first_check) {
+                rc = sb->s_qcop->get_dqblk(sb, type, id, &dqb);
+                if (rc) {
+                        CERROR("get_dqblk of id %u, type %d failed: %d\n",
+                               id, type, rc);
+                } else {
+                        DQBLK_COPY(cdqb, &dqb);
+                        cdqb->dqb_curspace = 0;
+                        cdqb->dqb_curinodes = 0;
+                }
+        }
+
+        hlist_add_head(&cdqb->dqb_hash, head);
+        list_add_tail(&cdqb->dqb_list, list);
+
+        return cdqb;
+}
+
+static inline int quota_onoff(struct super_block *sb, int cmd, int type)
+{
+        struct obd_quotactl *oqctl;
+        int rc;
+
+        OBD_ALLOC_PTR(oqctl);
+        if (!oqctl)
+                RETURN(-ENOMEM);
+
+        oqctl->qc_cmd = cmd;
+        oqctl->qc_id = QFMT_LDISKFS;
+        oqctl->qc_type = type;
+        rc = fsfilt_ext3_quotactl(sb, oqctl);
+
+        OBD_FREE_PTR(oqctl);
+        return rc;
+}
+
+static inline int read_old_dqinfo(struct super_block *sb, int type,
+                                  struct if_dqinfo *dqinfo)
+{
+        struct obd_quotactl *oqctl;
+        int rc;
+        ENTRY;
+
+        OBD_ALLOC_PTR(oqctl);
+        if (!oqctl)
+                RETURN(-ENOMEM);
+
+        oqctl->qc_cmd = Q_GETINFO;
+        oqctl->qc_type = type;
+        rc = fsfilt_ext3_quotactl(sb, oqctl);
+        if (!rc)
+                ((struct obd_dqinfo *)dqinfo)[type] = oqctl->qc_dqinfo;
+
+        OBD_FREE_PTR(oqctl);
+        RETURN(rc);
+}
+
 static inline struct ext3_group_desc *
 get_group_desc(struct super_block *sb, int group)
 {
@@ -1233,8 +1475,365 @@ static inline struct inode *ext3_iget_inuse(struct super_block *sb,
         return inode;
 }
 
+struct qchk_ctxt {
+        struct hlist_head       qckt_hash[NR_DQHASH];        /* quotacheck hash */
+        struct list_head        qckt_list;                   /* quotacheck list */
+        int                     qckt_first_check[MAXQUOTAS]; /* 1 if no old quotafile */
+        struct if_dqinfo        qckt_dqinfo[MAXQUOTAS];      /* old dqinfo */
+};
+
+static int add_inode_quota(struct inode *inode, struct qchk_ctxt *qctxt,
+                           struct obd_quotactl *oqc)
+{
+        struct chk_dqblk *cdqb[MAXQUOTAS] = { NULL, };
+        loff_t size = 0;
+        qid_t qid[MAXQUOTAS];
+        int cnt, i, rc = 0;
+
+        if (!inode)
+                return 0;
+
+        qid[USRQUOTA] = inode->i_uid;
+        qid[GRPQUOTA] = inode->i_gid;
+
+        if (S_ISDIR(inode->i_mode) ||
+            S_ISREG(inode->i_mode) ||
+            S_ISLNK(inode->i_mode))
+                size = inode_get_bytes(inode);
+
+        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+                if (!Q_TYPESET(oqc, cnt))
+                        continue;
+
+                cdqb[cnt] = cqget(inode->i_sb, qctxt->qckt_hash,
+                                &qctxt->qckt_list, qid[cnt], cnt,
+                                qctxt->qckt_first_check[cnt]);
+                if (!cdqb[cnt]) {
+                        rc = -ENOMEM;
+                        break;
+                }
+
+                cdqb[cnt]->dqb_curspace += size;
+                cdqb[cnt]->dqb_curinodes++;
+        }
+
+        if (rc) {
+                for (i = 0; i < cnt; i++) {
+                        if (!Q_TYPESET(oqc, i))
+                                continue;
+                        LASSERT(cdqb[i]);
+                        cdqb[i]->dqb_curspace -= size;
+                        cdqb[i]->dqb_curinodes--;
+                }
+        }
+
+        return rc;
+}
+
+static int v2_write_dqheader(struct file *f, int type)
+{
+        static const __u32 quota_magics[] = V2_INITQMAGICS;
+        static const __u32 quota_versions[] = V2_INITQVERSIONS;
+        struct v2_disk_dqheader dqhead;
+        loff_t offset = 0;
+
+        CLASSERT(ARRAY_SIZE(quota_magics) == ARRAY_SIZE(quota_versions));
+        LASSERT(0 <= type && type < ARRAY_SIZE(quota_magics));
+
+        dqhead.dqh_magic = cpu_to_le32(quota_magics[type]);
+        dqhead.dqh_version = cpu_to_le32(quota_versions[type]);
+
+        return cfs_user_write(f, (char *)&dqhead, sizeof(dqhead), &offset);
+}
+
+/* write dqinfo struct in a new quota file */
+static int v2_write_dqinfo(struct file *f, int type, struct if_dqinfo *info)
+{
+        struct v2_disk_dqinfo dqinfo;
+        __u32 blocks = V2_DQTREEOFF + 1;
+        loff_t offset = V2_DQINFOOFF;
+
+        if (info) {
+                dqinfo.dqi_bgrace = cpu_to_le32(info->dqi_bgrace);
+                dqinfo.dqi_igrace = cpu_to_le32(info->dqi_igrace);
+                dqinfo.dqi_flags = cpu_to_le32(info->dqi_flags & DQF_MASK &
+                                               ~DQF_INFO_DIRTY);
+        } else {
+                dqinfo.dqi_bgrace = cpu_to_le32(MAX_DQ_TIME);
+                dqinfo.dqi_igrace = cpu_to_le32(MAX_IQ_TIME);
+                dqinfo.dqi_flags = 0;
+        }
+
+        dqinfo.dqi_blocks = cpu_to_le32(blocks);
+        dqinfo.dqi_free_blk = 0;
+        dqinfo.dqi_free_entry = 0;
+
+        return cfs_user_write(f, (char *)&dqinfo, sizeof(dqinfo), &offset);
+}
+
+static int create_new_quota_files(struct qchk_ctxt *qctxt,
+                                  struct obd_quotactl *oqc)
+{
+        int i, rc = 0;
+        ENTRY;
+
+        for (i = 0; i < MAXQUOTAS; i++) {
+                struct if_dqinfo *info = qctxt->qckt_first_check[i]?
+                                         NULL : &qctxt->qckt_dqinfo[i];
+                struct file *file;
+
+                if (!Q_TYPESET(oqc, i))
+                        continue;
+
+                file = filp_open(op_quotafile[i], O_RDWR | O_CREAT | O_TRUNC,
+                                 0644);
+                if (IS_ERR(file)) {
+                        rc = PTR_ERR(file);
+                        CERROR("can't create %s file: rc = %d\n",
+                               op_quotafile[i], rc);
+                        GOTO(out, rc);
+                }
+
+                if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
+                        CERROR("file %s is not regular", op_quotafile[i]);
+                        filp_close(file, 0);
+                        GOTO(out, rc = -EINVAL);
+                }
+
+                rc = v2_write_dqheader(file, i);
+                if (rc) {
+                        filp_close(file, 0);
+                        GOTO(out, rc);
+                }
+
+                rc = v2_write_dqinfo(file, i, info);
+                filp_close(file, 0);
+                if (rc)
+                        GOTO(out, rc);
+        }
+
+out:
+        RETURN(rc);
+}
+
+
+static int commit_chkquot(struct super_block *sb, struct qchk_ctxt *qctxt,
+                          struct chk_dqblk *cdqb)
+{
+        struct obd_quotactl *oqc;
+        struct timeval now;
+        int rc;
+        ENTRY;
+
+        OBD_ALLOC_PTR(oqc);
+        if (!oqc)
+                RETURN(-ENOMEM);
+
+        do_gettimeofday(&now);
+
+        if (cdqb->dqb_bsoftlimit &&
+            toqb(cdqb->dqb_curspace) >= cdqb->dqb_bsoftlimit &&
+            !cdqb->dqb_btime)
+                cdqb->dqb_btime = now.tv_sec +
+                               qctxt->qckt_dqinfo[cdqb->dqb_type].dqi_bgrace;
+
+        if (cdqb->dqb_isoftlimit &&
+            cdqb->dqb_curinodes >= cdqb->dqb_isoftlimit &&
+            !cdqb->dqb_itime)
+                cdqb->dqb_itime = now.tv_sec +
+                               qctxt->qckt_dqinfo[cdqb->dqb_type].dqi_igrace;
+
+        cdqb->dqb_valid = QIF_ALL;
+
+        oqc->qc_cmd = Q_SETQUOTA;
+        oqc->qc_type = cdqb->dqb_type;
+        oqc->qc_id = cdqb->dqb_id;
+        DQBLK_COPY(&oqc->qc_dqblk, cdqb);
+
+        rc = fsfilt_ext3_quotactl(sb, oqc);
+        OBD_FREE_PTR(oqc);
+        RETURN(rc);
+}
+
+static int prune_chkquots(struct super_block *sb,
+                          struct qchk_ctxt *qctxt, int error)
+{
+        struct chk_dqblk *cdqb, *tmp;
+        int rc;
+
+        list_for_each_entry_safe(cdqb, tmp, &qctxt->qckt_list, dqb_list) {
+                if (!error) {
+                        rc = commit_chkquot(sb, qctxt, cdqb);
+                        if (rc)
+                                error = rc;
+                }
+                hlist_del_init(&cdqb->dqb_hash);
+                list_del(&cdqb->dqb_list);
+                OBD_FREE_PTR(cdqb);
+        }
+
+        return error;
+}
+
+static int fsfilt_ext3_quotacheck(struct super_block *sb,
+                                  struct obd_quotactl *oqc)
+{
+        struct ext3_sb_info *sbi = EXT3_SB(sb);
+        int i, group;
+        struct qchk_ctxt *qctxt;
+        struct buffer_head *bitmap_bh = NULL;
+        unsigned long ino;
+        struct inode *inode;
+        int rc = 0;
+        ENTRY;
+
+        /* turn on quota and read dqinfo if existed */
+        OBD_ALLOC_PTR(qctxt);
+        if (!qctxt) {
+                oqc->qc_stat = -ENOMEM;
+                RETURN(-ENOMEM);
+        }
+
+        for (i = 0; i < NR_DQHASH; i++)
+                INIT_HLIST_HEAD(&qctxt->qckt_hash[i]);
+        INIT_LIST_HEAD(&qctxt->qckt_list);
+
+        for (i = 0; i < MAXQUOTAS; i++) {
+                if (!Q_TYPESET(oqc, i))
+                        continue;
+
+                rc = quota_onoff(sb, Q_QUOTAON, i);
+                if (!rc || rc == -EBUSY) {
+                        rc = read_old_dqinfo(sb, i, qctxt->qckt_dqinfo);
+                        if (rc)
+                                GOTO(out, rc);
+                } else if (rc == -ENOENT) {
+                        qctxt->qckt_first_check[i] = 1;
+                } else if (rc) {
+                        GOTO(out, rc);
+                }
+        }
+
+        /* check quota and update in hash */
+        for (group = 0; group < sbi->s_groups_count; group++) {
+                ino = group * sbi->s_inodes_per_group + 1;
+                bitmap_bh = read_inode_bitmap(sb, group);
+                if (!bitmap_bh) {
+                        CERROR("read_inode_bitmap group %d failed", group);
+                        GOTO(out, -EIO);
+                }
+
+                for (i = 0; i < sbi->s_inodes_per_group; i++, ino++) {
+                        if (ino < sbi->s_first_ino)
+                                continue;
+
+                        inode = ext3_iget_inuse(sb, bitmap_bh, i, ino);
+                        rc = add_inode_quota(inode, qctxt, oqc);
+                        iput(inode);
+                        if (rc) {
+                                brelse(bitmap_bh);
+                                GOTO(out, rc);
+                        }
+                }
+
+                brelse(bitmap_bh);
+        }
+
+        /* turn off quota cause we are to dump chk_dqblk to files */
+        quota_onoff(sb, Q_QUOTAOFF, oqc->qc_type);
+
+        rc = create_new_quota_files(qctxt, oqc);
+        if (rc)
+                GOTO(out, rc);
+
+        /* we use vfs functions to set dqblk, so turn quota on */
+        rc = quota_onoff(sb, Q_QUOTAON, oqc->qc_type);
+out:
+        /* dump and free chk_dqblk */
+        rc = prune_chkquots(sb, qctxt, rc);
+        OBD_FREE_PTR(qctxt);
+
+        /* turn off quota, `lfs quotacheck` will turn on when all
+         * nodes quotacheck finish. */
+        quota_onoff(sb, Q_QUOTAOFF, oqc->qc_type);
+
+        oqc->qc_stat = rc;
+        if (rc)
+                CERROR("quotacheck failed: rc = %d\n", rc);
+
+        RETURN(rc);
+}
+
 #ifdef HAVE_QUOTA_SUPPORT
-# include "fsfilt_ext3_quota.h"
+static int fsfilt_ext3_quotainfo(struct lustre_quota_info *lqi, int type, 
+                                 int cmd, struct list_head *list)
+{
+        int rc = 0;
+        ENTRY;
+
+        if (lqi->qi_files[type] == NULL) {
+                CERROR("operate qinfo before it's enabled!\n");
+                RETURN(-EIO);
+        }
+
+        switch (cmd) {
+        case QFILE_CHK:
+                rc = lustre_check_quota_file(lqi, type);
+                break;
+        case QFILE_RD_INFO:
+                rc = lustre_read_quota_info(lqi, type);
+                break;
+        case QFILE_WR_INFO:
+                rc = lustre_write_quota_info(lqi, type);
+                break;
+        case QFILE_INIT_INFO:
+                rc = lustre_init_quota_info(lqi, type);
+                break;
+        case QFILE_GET_QIDS:
+                rc = lustre_get_qids(lqi, type, list);
+                break;
+        default:
+                CERROR("Unsupported admin quota file cmd %d\n", cmd);
+                LBUG();
+                break;
+        }
+        RETURN(rc);
+}
+
+static int fsfilt_ext3_dquot(struct lustre_dquot *dquot, int cmd)
+{
+        int rc = 0;
+        ENTRY;
+
+        if (dquot->dq_info->qi_files[dquot->dq_type] == NULL) {
+                CERROR("operate dquot before it's enabled!\n");
+                RETURN(-EIO);
+        }
+
+        switch (cmd) {
+        case QFILE_RD_DQUOT:
+                rc = lustre_read_dquot(dquot);
+                break;
+        case QFILE_WR_DQUOT:
+                if (dquot->dq_dqb.dqb_ihardlimit ||
+                    dquot->dq_dqb.dqb_isoftlimit ||
+                    dquot->dq_dqb.dqb_bhardlimit ||
+                    dquot->dq_dqb.dqb_bsoftlimit)
+                        clear_bit(DQ_FAKE_B, &dquot->dq_flags);
+                else
+                        set_bit(DQ_FAKE_B, &dquot->dq_flags);
+
+                rc = lustre_commit_dquot(dquot);
+                if (rc >= 0)
+                        rc = 0;
+                break;
+        default:
+                CERROR("Unsupported admin quota file cmd %d\n", cmd);
+                LBUG();
+                break;
+        }
+        RETURN(rc);
+}
 #endif
 
 static struct fsfilt_operations fsfilt_ext3_ops = {
@@ -1260,9 +1859,9 @@ static struct fsfilt_operations fsfilt_ext3_ops = {
         .fs_setup               = fsfilt_ext3_setup,
         .fs_send_bio            = fsfilt_ext3_send_bio,
         .fs_get_op_len          = fsfilt_ext3_get_op_len,
-#ifdef HAVE_QUOTA_SUPPORT
         .fs_quotactl            = fsfilt_ext3_quotactl,
         .fs_quotacheck          = fsfilt_ext3_quotacheck,
+#ifdef HAVE_QUOTA_SUPPORT
         .fs_quotainfo           = fsfilt_ext3_quotainfo,
         .fs_dquot               = fsfilt_ext3_dquot,
 #endif
index 8d79fe3..0d05129 100644 (file)
@@ -70,25 +70,5 @@ static inline void mdc_put_rpc_lock(struct mdc_rpc_lock *lck,
 }
 
 /* Quota stuff */
-#ifdef HAVE_QUOTA_SUPPORT
-int mdc_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl);
-int mdc_poll_quotacheck(struct obd_export *exp, struct if_quotacheck *qchk);
-int mdc_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl);
-#else
-static inline int mdc_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl)
-{
-        return -ENOTSUPP;
-}
-
-static inline int mdc_poll_quotacheck(struct obd_export *exp, struct if_quotacheck *qchk)
-{
-        return -ENOTSUPP;
-}
-
-static inline int mdc_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl)
-{
-        return -ENOTSUPP;
-}
-#endif
-
+extern quota_interface_t *quota_interface;
 
index 0783098..0fbdbc9 100644 (file)
@@ -807,6 +807,7 @@ int mdc_readpage(struct obd_export *exp, struct ll_fid *mdc_fid, __u64 offset,
         return rc;
 }
 
+
 static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
                          void *karg, void *uarg)
 {
@@ -849,7 +850,8 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
         }
 #endif
         case OBD_IOC_POLL_QUOTACHECK:
-                rc = mdc_poll_quotacheck(exp, (struct if_quotacheck *)karg);
+                rc = lquota_poll_check(quota_interface, exp,
+                                       (struct if_quotacheck *)karg);
                 GOTO(out, rc);
         default:
                 CERROR("mdc_ioctl(): unrecognised ioctl %#x\n", cmd);
@@ -1245,21 +1247,34 @@ struct obd_ops mdc_obd_ops = {
         .o_import_event = mdc_import_event,
         .o_llog_init    = mdc_llog_init,
         .o_llog_finish  = mdc_llog_finish,
-        .o_quotacheck   = mdc_quotacheck,
-        .o_quotactl     = mdc_quotactl,
 };
 
+static quota_interface_t *quota_interface = NULL;
+extern quota_interface_t mdc_quota_interface;
+
 int __init mdc_init(void)
 {
+        int rc;
         struct lprocfs_static_vars lvars;
         lprocfs_init_vars(mdc, &lvars);
-        return class_register_type(&mdc_obd_ops, lvars.module_vars,
-                                   LUSTRE_MDC_NAME);
+        quota_interface = PORTAL_SYMBOL_GET(mdc_quota_interface);
+        init_obd_quota_ops(quota_interface, &mdc_obd_ops);
+        
+        rc = class_register_type(&mdc_obd_ops, lvars.module_vars,
+                                 LUSTRE_MDC_NAME);
+        if (rc && quota_interface)
+                PORTAL_SYMBOL_PUT(osc_quota_interface);
+
+        RETURN(rc);
 }
 
 #ifdef __KERNEL__
 static void /*__exit*/ mdc_exit(void)
 {
+        if (quota_interface)
+                PORTAL_SYMBOL_PUT(mdc_quota_interface);
+
         class_unregister_type(LUSTRE_MDC_NAME);
 }
 
index 25eb6f0..919c9aa 100644 (file)
@@ -2,8 +2,4 @@ MODULES := mds
 mds-objs := mds_log.o mds_unlink_open.o mds_lov.o handler.o mds_reint.o
 mds-objs += mds_fs.o lproc_mds.o mds_open.o mds_lib.o mds_xattr.o
 
-ifeq ($(PATCHLEVEL),6)
-#mds-objs += quota_master.o
-endif
-
 @INCLUDE_RULES@
index a07b147..0c331e2 100644 (file)
@@ -207,7 +207,7 @@ struct dentry *mds_fid2dentry(struct mds_obd *mds, struct ll_fid *fid,
         snprintf(fid_name, sizeof(fid_name), "0x%lx", ino);
 
         CDEBUG(D_DENTRY, "--> mds_fid2dentry: ino/gen %lu/%u, sb %p\n",
-               ino, generation, mds->mds_sb);
+               ino, generation, mds->mds_obt.obt_sb);
 
         /* under ext3 this is neither supposed to return bad inodes
            nor NULL inodes. */
@@ -941,7 +941,7 @@ static int mds_obd_statfs(struct obd_device *obd, struct obd_statfs *osfs,
         int rc;
 
         spin_lock(&obd->obd_osfs_lock);
-        rc = fsfilt_statfs(obd, obd->u.mds.mds_sb, max_age);
+        rc = fsfilt_statfs(obd, obd->u.obt.obt_sb, max_age);
         if (rc == 0)
                 memcpy(osfs, &obd->obd_osfs, sizeof(*osfs));
         spin_unlock(&obd->obd_osfs_lock);
@@ -999,7 +999,7 @@ static int mds_sync(struct ptlrpc_request *req)
 
         if (body->fid1.id == 0) {
                 /* a fid of zero is taken to mean "sync whole filesystem" */
-                rc = fsfilt_sync(obd, mds->mds_sb);
+                rc = fsfilt_sync(obd, obd->u.obt.obt_sb);
                 GOTO(out, rc);
         } else {
                 struct dentry *de;
@@ -1203,6 +1203,48 @@ static int mds_set_info(struct obd_export *exp, struct ptlrpc_request *req)
         RETURN(0);
 }
 
+static int mds_handle_quotacheck(struct ptlrpc_request *req)
+{
+        struct obd_quotactl *oqctl;
+        int rc;
+        ENTRY;
+
+        oqctl = lustre_swab_reqbuf(req, 0, sizeof(*oqctl),
+                                   lustre_swab_obd_quotactl);
+        if (oqctl == NULL)
+                RETURN(-EPROTO);
+
+        rc = lustre_pack_reply(req, 0, NULL, NULL);
+        if (rc) {
+                CERROR("mds: out of memory while packing quotacheck reply\n");
+                RETURN(rc);
+        }
+
+        req->rq_status = obd_quotacheck(req->rq_export, oqctl);
+        RETURN(0);
+}
+
+static int mds_handle_quotactl(struct ptlrpc_request *req)
+{
+        struct obd_quotactl *oqctl, *repoqc;
+        int rc, size = sizeof(*repoqc);
+        ENTRY;
+
+        oqctl = lustre_swab_reqbuf(req, 0, sizeof(*oqctl),
+                                   lustre_swab_obd_quotactl);
+        if (oqctl == NULL)
+                RETURN(-EPROTO);
+
+        rc = lustre_pack_reply(req, 1, &size, NULL);
+        if (rc)
+                RETURN(rc);
+
+        repoqc = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*repoqc));
+
+        req->rq_status = obd_quotactl(req->rq_export, oqctl);
+        *repoqc = *oqctl;
+        RETURN(0);
+}
 
 int mds_handle(struct ptlrpc_request *req)
 {
@@ -1411,13 +1453,13 @@ int mds_handle(struct ptlrpc_request *req)
         case MDS_QUOTACHECK:
                 DEBUG_REQ(D_INODE, req, "quotacheck");
                 OBD_FAIL_RETURN(OBD_FAIL_MDS_QUOTACHECK_NET, 0);
-                rc = mds_quotacheck(req);
+                rc = mds_handle_quotacheck(req);
                 break;
 
         case MDS_QUOTACTL:
                 DEBUG_REQ(D_INODE, req, "quotactl");
                 OBD_FAIL_RETURN(OBD_FAIL_MDS_QUOTACTL_NET, 0);
-                rc = mds_quotactl(req);
+                rc = mds_handle_quotactl(req);
                 break;
 
         case OBD_PING:
@@ -1576,6 +1618,9 @@ static int mds_setup(struct obd_device *obd, obd_count len, void *buf)
         int rc = 0;
         ENTRY;
 
+        CLASSERT(offsetof(struct obd_device, u.obt) ==
+                 offsetof(struct obd_device, u.mds.mds_obt));
+
         if (lcfg->lcfg_bufcount < 3)
                 RETURN(rc = -EINVAL);
 
@@ -1662,20 +1707,22 @@ static int mds_setup(struct obd_device *obd, obd_count len, void *buf)
                            "mds_ldlm_client", &obd->obd_ldlm_client);
         obd->obd_replayable = 1;
 
+        rc = lquota_setup(quota_interface, obd, lcfg);
+        if (rc)
+                GOTO(err_fs, rc);
+        
         mds->mds_group_hash = upcall_cache_init(obd->obd_name);
         if (IS_ERR(mds->mds_group_hash)) {
                 rc = PTR_ERR(mds->mds_group_hash);
                 mds->mds_group_hash = NULL;
-                GOTO(err_fs, rc);
+                GOTO(err_qctxt, rc);
         }
 
-        mds_quota_setup(mds);
-
         /* Wait for mds_postrecov trying to clear orphans until 9439 is fixed */
         obd->obd_async_recov = 0;
         rc = mds_postsetup(obd);
         if (rc)
-                GOTO(err_fs, rc);
+                GOTO(err_qctxt, rc);
         obd->obd_async_recov = 0;
 
         lprocfs_init_vars(mds, &lvars);
@@ -1708,6 +1755,8 @@ static int mds_setup(struct obd_device *obd, obd_count len, void *buf)
 
         RETURN(0);
 
+err_qctxt:
+        lquota_cleanup(quota_interface, obd);       
 err_fs:
         /* No extra cleanup needed for llog_init_commit_thread() */
         mds_fs_cleanup(obd);
@@ -1719,7 +1768,7 @@ err_ns:
 err_put:
         unlock_kernel();
         mntput(mds->mds_vfsmnt);
-        mds->mds_sb = 0;
+        obd->u.obt.obt_sb = NULL;
         lock_kernel();
 err_ops:
         fsfilt_put_ops(obd->obd_fsops);
@@ -1806,6 +1855,9 @@ int mds_postrecov(struct obd_device *obd)
         /* Does anyone need this to be synchronous ever? */
         mds_lov_start_synchronize(obd, NULL, obd->obd_async_recov);
 
+        /* quota recovery */
+        lquota_recovery(quota_interface, obd);
+
 out:
         RETURN(rc < 0 ? rc : item);
 }
@@ -1868,9 +1920,9 @@ static int mds_cleanup(struct obd_device *obd)
 
         ping_evictor_stop();
 
-        if (mds->mds_sb == NULL)
+        if (obd->u.obt.obt_sb == NULL)
                 RETURN(0);
-        save_dev = lvfs_sbdev(mds->mds_sb);
+        save_dev = lvfs_sbdev(obd->u.obt.obt_sb);
 
         if (mds->mds_osc_exp)
                 /* lov export was disconnected by mds_lov_clean;
@@ -1879,7 +1931,7 @@ static int mds_cleanup(struct obd_device *obd)
 
         lprocfs_obd_cleanup(obd);
 
-        mds_quota_cleanup(mds);
+        lquota_cleanup(quota_interface, obd);
 
         mds_update_server_data(obd, 1);
         if (mds->mds_lov_objids != NULL) {
@@ -1905,7 +1957,7 @@ static int mds_cleanup(struct obd_device *obd)
         }
 
         mntput(mds->mds_vfsmnt);
-        mds->mds_sb = NULL;
+        obd->u.obt.obt_sb = NULL;
 
         ldlm_namespace_free(obd->obd_namespace, obd->obd_force);
 
@@ -2307,15 +2359,23 @@ static struct obd_ops mdt_obd_ops = {
         .o_health_check    = mdt_health_check,
 };
 
+quota_interface_t *quota_interface = NULL;
+extern quota_interface_t mds_quota_interface;
+
 static int __init mds_init(void)
 {
         int rc;
         struct lprocfs_static_vars lvars;
 
-        rc = lustre_dquot_init();
-        if (rc)
+        quota_interface = PORTAL_SYMBOL_GET(mds_quota_interface);
+        rc = lquota_init(quota_interface);
+        if (rc) {
+                if (quota_interface)
+                        PORTAL_SYMBOL_PUT(mds_quota_interface);
                 return rc;
-
+        }
+        init_obd_quota_ops(quota_interface, &mds_obd_ops);
+        
         lprocfs_init_vars(mds, &lvars);
         class_register_type(&mds_obd_ops, lvars.module_vars, LUSTRE_MDS_NAME);
         lprocfs_init_vars(mdt, &lvars);
@@ -2326,7 +2386,9 @@ static int __init mds_init(void)
 
 static void /*__exit*/ mds_exit(void)
 {
-        lustre_dquot_exit();
+        lquota_exit(quota_interface);
+        if (quota_interface)
+                PORTAL_SYMBOL_PUT(mds_quota_interface);
 
         class_unregister_type(LUSTRE_MDS_NAME);
         class_unregister_type(LUSTRE_MDT_NAME);
index 1964bc2..78d3e3f 100644 (file)
@@ -224,6 +224,123 @@ static int lprocfs_wr_group_flush(struct file *file, const char *buffer,
         return count;
 }
 
+#ifdef HAVE_QUOTA_SUPPORT        
+static int lprocfs_mds_rd_bunit(char *page, char **start, off_t off, int count, 
+                                int *eof, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        LASSERT(obd != NULL);
+
+        return snprintf(page, count, "%lu\n", 
+                        obd->u.obt.obt_qctxt.lqc_bunit_sz);
+}
+
+static int lprocfs_mds_rd_iunit(char *page, char **start, off_t off, int count, 
+                                int *eof, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        LASSERT(obd != NULL);
+
+        return snprintf(page, count, "%lu\n", 
+                        obd->u.obt.obt_qctxt.lqc_iunit_sz);
+}
+
+static int lprocfs_mds_wr_bunit(struct file *file, const char *buffer,
+                                unsigned long count, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        int val, rc;
+        LASSERT(obd != NULL);
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+
+        if (val % QUOTABLOCK_SIZE ||
+            val <= obd->u.obt.obt_qctxt.lqc_btune_sz)
+                return -EINVAL;
+
+        obd->u.obt.obt_qctxt.lqc_bunit_sz = val;
+        return count;
+}
+
+static int lprocfs_mds_wr_iunit(struct file *file, const char *buffer,
+                                unsigned long count, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        int val, rc;
+        LASSERT(obd != NULL);
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+
+        if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz)
+                return -EINVAL;
+
+        obd->u.obt.obt_qctxt.lqc_iunit_sz = val;
+        return count;
+}
+
+static int lprocfs_mds_rd_btune(char *page, char **start, off_t off, int count, 
+                                int *eof, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        LASSERT(obd != NULL);
+
+        return snprintf(page, count, "%lu\n", 
+                        obd->u.obt.obt_qctxt.lqc_btune_sz);
+}
+
+static int lprocfs_mds_rd_itune(char *page, char **start, off_t off, int count, 
+                                int *eof, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        LASSERT(obd != NULL);
+
+        return snprintf(page, count, "%lu\n", 
+                        obd->u.obt.obt_qctxt.lqc_itune_sz);
+}
+
+static int lprocfs_mds_wr_btune(struct file *file, const char *buffer,
+                                unsigned long count, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        int val, rc;
+        LASSERT(obd != NULL);
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+        
+        if (val <= QUOTABLOCK_SIZE * MIN_QLIMIT || val % QUOTABLOCK_SIZE || 
+            val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
+                return -EINVAL;
+
+        obd->u.obt.obt_qctxt.lqc_btune_sz = val;
+        return count;
+}
+
+static int lprocfs_mds_wr_itune(struct file *file, const char *buffer,
+                                unsigned long count, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        int val, rc;
+        LASSERT(obd != NULL);
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+        
+        if (val <= MIN_QLIMIT || 
+            val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
+                return -EINVAL;
+
+        obd->u.obt.obt_qctxt.lqc_itune_sz = val;
+        return count;
+}
+#endif
+
 struct lprocfs_vars lprocfs_mds_obd_vars[] = {
         { "uuid",            lprocfs_rd_uuid,        0, 0 },
         { "blocksize",       lprocfs_rd_blksize,     0, 0 },
index 3ff10d1..39bb8e9 100644 (file)
@@ -416,9 +416,9 @@ int mds_fs_setup(struct obd_device *obd, struct vfsmount *mnt)
                 RETURN(rc);
 
         mds->mds_vfsmnt = mnt;
-        mds->mds_sb = mnt->mnt_root->d_inode->i_sb;
+        obd->u.obt.obt_sb = mnt->mnt_root->d_inode->i_sb;
 
-        fsfilt_setup(obd, mds->mds_sb);
+        fsfilt_setup(obd, obd->u.obt.obt_sb);
 
         OBD_SET_CTXT_MAGIC(&obd->obd_lvfs_ctxt);
         obd->obd_lvfs_ctxt.pwdmnt = mnt;
@@ -577,12 +577,12 @@ int mds_fs_cleanup(struct obd_device *obd)
                 mds->mds_pending_dir = NULL;
         }
 
-        mds_fs_quota_cleanup(mds);
-        
+        lquota_fs_cleanup(quota_interface, obd);
+
         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
         shrink_dcache_parent(mds->mds_fid_de);
         dput(mds->mds_fid_de);
-        LL_DQUOT_OFF(mds->mds_sb);
+        LL_DQUOT_OFF(obd->u.obt.obt_sb);
 
         return rc;
 }
index 0c28e08..4f25fa4 100644 (file)
@@ -205,89 +205,11 @@ int mds_pack_acl(struct mds_export_data *med, struct inode *inode,
                  struct lustre_msg *repmsg, struct mds_body *repbody,
                  int repoff);
 
+/* quota stuff */
+extern quota_interface_t *quota_interface;
+
 /* mds/mds_xattr.c */
 int mds_setxattr(struct ptlrpc_request *req);
 int mds_getxattr(struct ptlrpc_request *req);
 
-/* mds/quota_master.c */
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0)) && defined (HAVE_QUOTA_SUPPORT)
-int lustre_dquot_init(void);
-void lustre_dquot_exit(void);
-int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc);
-void mds_adjust_qunit(struct obd_device *obd, uid_t cuid, gid_t cgid,
-                      uid_t puid, gid_t pgid, int rc);
-int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_set_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_get_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl);
-int mds_get_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl);
-#else
-static inline int lustre_dquot_init(void) { return 0; }
-static inline void lustre_dquot_exit(void) { return; }
-static inline int dqacq_handler(struct obd_device *obd,
-                                struct qunit_data *qdata, int opc) {return 0;}
-static inline void mds_adjust_qunit(struct obd_device *obd, uid_t cuid,
-                                    gid_t cgid, uid_t puid,
-                                    gid_t pgid, int rc) { return; }
-static inline int init_admin_quotafiles(struct obd_device *obd,
-                                        struct obd_quotactl *oqctl) {return 0;}
-static inline int mds_quota_on(struct obd_device *obd,
-                               struct obd_quotactl *oqctl) { return 0; }
-static inline int mds_quota_off(struct obd_device *obd,
-                                struct obd_quotactl *oqctl) { return 0; }
-static inline int mds_set_dqinfo(struct obd_device *obd,
-                                 struct obd_quotactl *oqctl) { return 0; }
-static inline int mds_get_dqinfo(struct obd_device *obd,
-                                 struct obd_quotactl *oqctl) { return 0; }
-static inline int mds_set_dqblk(struct obd_device *obd,
-                                struct obd_quotactl *oqctl) { return 0; }
-static inline int mds_get_dqblk(struct obd_device *obd,
-                                struct obd_quotactl *oqctl) { return 0; }
-#endif /* KERNEL_VERSION(2,5,0) && QUOTA */
-
-#ifdef HAVE_QUOTA_SUPPORT
-/* Internal quota stuff */
-int mds_quotacheck(struct ptlrpc_request *req);
-int mds_quotactl(struct ptlrpc_request *req);
-void mds_quota_setup(struct mds_obd *mds);
-void mds_quota_cleanup(struct mds_obd *mds);
-void mds_fs_quota_cleanup(struct mds_obd *mds);
-
-#ifdef LPROCFS
-int lprocfs_mds_rd_bunit(char *page, char **start, off_t off, int count,
-                                int *eof, void *data);
-int lprocfs_mds_rd_iunit(char *page, char **start, off_t off, int count,
-                                int *eof, void *data);
-int lprocfs_mds_wr_bunit(struct file *file, const char *buffer,
-                                unsigned long count, void *data);
-int lprocfs_mds_wr_iunit(struct file *file, const char *buffer,
-                                unsigned long count, void *data);
-int lprocfs_mds_rd_btune(char *page, char **start, off_t off, int count,
-                                int *eof, void *data);
-int lprocfs_mds_rd_itune(char *page, char **start, off_t off, int count,
-                                int *eof, void *data);
-int lprocfs_mds_wr_btune(struct file *file, const char *buffer,
-                                unsigned long count, void *data);
-int lprocfs_mds_wr_itune(struct file *file, const char *buffer,
-                                unsigned long count, void *data);
-#endif /* LPROCFS */
-#else /* QUOTA */
-static inline int mds_quotacheck(struct ptlrpc_request *req)
-{
-        req->rq_status = -EOPNOTSUPP;
-        return -EOPNOTSUPP;
-}
-static inline int mds_quotactl(struct ptlrpc_request *req)
-{
-        req->rq_status = -EOPNOTSUPP;
-        return -EOPNOTSUPP;
-}
-static inline void mds_quota_setup(struct mds_obd *mds) {}
-static inline void mds_quota_cleanup(struct mds_obd *mds) {}
-static inline void mds_fs_quota_cleanup(struct mds_obd *mds) {}
-#endif /* Quota */
-
-
 #endif /* _MDS_INTERNAL_H */
index 5e2553d..b265d64 100644 (file)
 
 #include "mds_internal.h"
 
-/* callback function of lov to fill unlink log record */
-static int mds_log_fill_unlink_rec(struct llog_rec_hdr *rec, void *data)
-{
-        struct llog_fill_rec_data *lfd = (struct llog_fill_rec_data *)data;
-        struct llog_unlink_rec *lur = (struct llog_unlink_rec *)rec;
-
-        lur->lur_oid = lfd->lfd_id;
-        lur->lur_ogen = lfd->lfd_ogen;
-
-        RETURN(0);
-}
-
-/* callback function of lov to fill setattr log record */
-static int mds_log_fill_setattr_rec(struct llog_rec_hdr *rec, void *data)
-{
-        struct llog_fill_rec_data *lfd = (struct llog_fill_rec_data *)data;
-        struct llog_setattr_rec *lsr = (struct llog_setattr_rec *)rec;
-
-        lsr->lsr_oid = lfd->lfd_id;
-        lsr->lsr_ogen = lfd->lfd_ogen;
-
-        RETURN(0);
-}
-
 static int mds_llog_origin_add(struct llog_ctxt *ctxt,
                         struct llog_rec_hdr *rec, struct lov_stripe_md *lsm,
-                        struct llog_cookie *logcookies, int numcookies,
-                        llog_fill_rec_cb_t fill_cb)
+                        struct llog_cookie *logcookies, int numcookies)
 {
         struct obd_device *obd = ctxt->loc_obd;
         struct obd_device *lov_obd = obd->u.mds.mds_osc_obd;
@@ -77,7 +52,7 @@ static int mds_llog_origin_add(struct llog_ctxt *ctxt,
         ENTRY;
 
         lctxt = llog_get_context(lov_obd, ctxt->loc_idx);
-        rc = llog_add(lctxt, rec, lsm, logcookies, numcookies, fill_cb);
+        rc = llog_add(lctxt, rec, lsm, logcookies, numcookies);
         RETURN(rc);
 }
 
@@ -139,8 +114,7 @@ int mds_log_op_unlink(struct obd_device *obd, struct inode *inode,
 
         ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT);
         rc = llog_add(ctxt, &lur->lur_hdr, lsm, logcookies,
-                      cookies_size / sizeof(struct llog_cookie),
-                      mds_log_fill_unlink_rec);
+                      cookies_size / sizeof(struct llog_cookie));
 
         obd_free_memmd(mds->mds_osc_exp, &lsm);
         OBD_FREE(lur, sizeof(*lur));
@@ -179,8 +153,7 @@ int mds_log_op_setattr(struct obd_device *obd, struct inode *inode,
         /* write setattr log */
         ctxt = llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT);
         rc = llog_add(ctxt, &lsr->lsr_hdr, lsm, logcookies,
-                      cookies_size / sizeof(struct llog_cookie),
-                      mds_log_fill_setattr_rec);
+                      cookies_size / sizeof(struct llog_cookie));
 
         OBD_FREE(lsr, sizeof(*lsr));
  out:
index b963109..900ee04 100644 (file)
@@ -410,25 +410,25 @@ int mds_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
 
         case OBD_IOC_SYNC: {
                 CDEBUG(D_HA, "syncing mds %s\n", obd->obd_name);
-                rc = fsfilt_sync(obd, obd->u.mds.mds_sb);
+                rc = fsfilt_sync(obd, obd->u.obt.obt_sb);
                 RETURN(rc);
         }
 
         case OBD_IOC_SET_READONLY: {
                 void *handle;
-                struct inode *inode = obd->u.mds.mds_sb->s_root->d_inode;
+                struct inode *inode = obd->u.obt.obt_sb->s_root->d_inode;
                 BDEVNAME_DECLARE_STORAGE(tmp);
                 CERROR("*** setting device %s read-only ***\n",
-                       ll_bdevname(obd->u.mds.mds_sb, tmp));
+                       ll_bdevname(obd->u.obt.obt_sb, tmp));
 
                 handle = fsfilt_start(obd, inode, FSFILT_OP_MKNOD, NULL);
                 if (!IS_ERR(handle))
                         rc = fsfilt_commit(obd, inode, handle, 1);
 
                 CDEBUG(D_HA, "syncing mds %s\n", obd->obd_name);
-                rc = fsfilt_sync(obd, obd->u.mds.mds_sb);
+                rc = fsfilt_sync(obd, obd->u.obt.obt_sb);
 
-                lvfs_set_rdonly(lvfs_sbdev(obd->u.mds.mds_sb));
+                lvfs_set_rdonly(lvfs_sbdev(obd->u.obt.obt_sb));
                 RETURN(0);
         }
 
@@ -604,7 +604,14 @@ int mds_notify(struct obd_device *obd, struct obd_device *watched, int active)
                       obd->obd_name, uuid->uuid);
         } else {
                 LASSERT(llog_get_context(obd, LLOG_MDS_OST_ORIG_CTXT) != NULL);
+                
+                rc = obd_set_info(obd->u.mds.mds_osc_exp, strlen("mds_conn"),
+                                  "mds_conn", 0, uuid);
+                if (rc != 0)
+                        RETURN(rc);
+
                 rc = mds_lov_start_synchronize(obd, uuid, 1);
+                lquota_recovery(quota_interface, obd);
         }
         RETURN(rc);
 }
index 8e0d201..c7e40e6 100644 (file)
@@ -307,7 +307,7 @@ cleanup_dentry:
 static int mds_create_objects(struct ptlrpc_request *req, int offset,
                               struct mds_update_record *rec,
                               struct mds_obd *mds, struct obd_device *obd,
-                              struct dentry *dchild, void **handle,
+                              struct dentry *dchild, void **handle, 
                               obd_id **ids)
 {
         struct inode *inode = dchild->d_inode;
@@ -668,7 +668,8 @@ static int accmode(struct inode *inode, int flags)
 /* Handles object creation, actual opening, and I/O epoch */
 static int mds_finish_open(struct ptlrpc_request *req, struct dentry *dchild,
                            struct mds_body *body, int flags, void **handle,
-                           struct mds_update_record *rec,struct ldlm_reply *rep)
+                           struct mds_update_record *rec,
+                           struct ldlm_reply *rep)
 {
         struct mds_obd *mds = mds_req2mds(req);
         struct obd_device *obd = req->rq_export->exp_obd;
@@ -861,10 +862,11 @@ int mds_open(struct mds_update_record *rec, int offset,
         int parent_mode = LCK_CR;
         void *handle = NULL;
         struct dentry_params dp;
-        uid_t parent_uid = 0;
-        gid_t parent_gid = 0;
+        unsigned int qcids[MAXQUOTAS] = {current->fsuid, current->fsgid};
+        unsigned int qpids[MAXQUOTAS] = {0, 0};
         ENTRY;
 
+        CLASSERT(MAXQUOTAS < 4);
         if (offset == 2) { /* intent */
                 rep = lustre_msg_buf(req->rq_repmsg, 0, sizeof (*rep));
                 body = lustre_msg_buf(req->rq_repmsg, 1, sizeof (*body));
@@ -1099,7 +1101,7 @@ int mds_open(struct mds_update_record *rec, int offset,
  cleanup:
         rc = mds_finish_transno(mds, dchild ? dchild->d_inode : NULL, handle,
                                 req, rc, rep ? rep->lock_policy_res1 : 0);
-
+        
  cleanup_no_trans:
         switch (cleanup_phase) {
         case 2:
@@ -1113,9 +1115,8 @@ int mds_open(struct mds_update_record *rec, int offset,
                 } else if (created) {
                         mds_lock_new_child(obd, dchild->d_inode, NULL);
                         /* save uid/gid for quota acquire/release */
-                        parent_uid = dparent->d_inode->i_uid;
-                        parent_gid = dparent->d_inode->i_gid;
-
+                        qpids[USRQUOTA] = dparent->d_inode->i_uid;
+                        qpids[GRPQUOTA] = dparent->d_inode->i_gid;
                 }
                 l_dput(dchild);
         case 1:
@@ -1130,8 +1131,7 @@ int mds_open(struct mds_update_record *rec, int offset,
         }
  
         /* trigger dqacq on the owner of child and parent */
-        mds_adjust_qunit(obd, current->fsuid, current->fsgid, 
-                         parent_uid, parent_gid, rc);
+        lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_CREATE);
         RETURN(rc);
 }
 
index ecc66bf..9fb6b3d 100644 (file)
@@ -452,8 +452,9 @@ static int mds_reint_setattr(struct mds_update_record *rec, int offset,
         struct llog_cookie *logcookies = NULL;
         int lmm_size = 0, need_lock = 1;
         int rc = 0, cleanup_phase = 0, err, locked = 0;
-        uid_t child_uid = 0;
-        gid_t child_gid = 0;
+        unsigned int qcids[MAXQUOTAS] = {0, 0};
+        unsigned int qpids[MAXQUOTAS] = {rec->ur_iattr.ia_uid, 
+                                         rec->ur_iattr.ia_gid};
         ENTRY;
 
         LASSERT(offset == 0);
@@ -487,8 +488,8 @@ static int mds_reint_setattr(struct mds_update_record *rec, int offset,
         LASSERT(inode);
 
         /* save uid/gid for quota acq/rel */
-        child_uid = inode->i_uid;
-        child_gid = inode->i_gid;
+        qcids[USRQUOTA] = inode->i_uid;
+        qcids[GRPQUOTA] = inode->i_gid;
 
         if ((S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) &&
             rec->ur_eadata != NULL) {
@@ -533,8 +534,7 @@ static int mds_reint_setattr(struct mds_update_record *rec, int offset,
         } else if (rec->ur_iattr.ia_valid) {            /* setattr */
                 rc = fsfilt_setattr(obd, de, handle, &rec->ur_iattr, 0);
                 /* journal chown/chgrp in llog, just like unlink */
-                if (rc == 0 && S_ISREG(inode->i_mode) &&
-                    rec->ur_iattr.ia_valid & (ATTR_UID | ATTR_GID) && lmm_size){
+                if (rc == 0 && lmm_size){
                         OBD_ALLOC(logcookies, mds->mds_max_cookiesize);
                         if (logcookies == NULL)
                                 GOTO(cleanup, rc = -ENOMEM);
@@ -657,11 +657,9 @@ static int mds_reint_setattr(struct mds_update_record *rec, int offset,
         req->rq_status = rc;
 
         /* trigger dqrel/dqacq for original owner and new owner */
-        if (ia_valid & (ATTR_UID | ATTR_GID)) {
-                mds_adjust_qunit(obd, rec->ur_iattr.ia_uid,
-                                 rec->ur_iattr.ia_gid, 0, 0, rc);
-                mds_adjust_qunit(obd, child_uid, child_gid, 0, 0, rc);
-        }
+        if (ia_valid & (ATTR_UID | ATTR_GID))
+                lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_SETATTR);
+
         return 0;
 }
 
@@ -702,8 +700,8 @@ static int mds_reint_create(struct mds_update_record *rec, int offset,
         struct lustre_handle lockh;
         int rc = 0, err, type = rec->ur_mode & S_IFMT, cleanup_phase = 0;
         int created = 0;
-        uid_t parent_uid = 0;
-        gid_t parent_gid = 0;
+        unsigned int qcids[MAXQUOTAS] = {current->fsuid, current->fsgid};
+        unsigned int qpids[MAXQUOTAS] = {0, 0};
         struct dentry_params dp;
         ENTRY;
 
@@ -901,8 +899,8 @@ cleanup:
                  * See bug 2029 for more detail.*/
                 mds_lock_new_child(obd, dchild->d_inode, NULL);
                 /* save uid/gid of create inode and parent */
-                parent_uid = dir->i_uid;
-                parent_gid = dir->i_gid;
+                qpids[USRQUOTA] = dir->i_uid;
+                qpids[GRPQUOTA] = dir->i_gid;
         } else {
                 rc = err;
         }
@@ -926,8 +924,7 @@ cleanup:
         req->rq_status = rc;
 
         /* trigger dqacq on the owner of child and parent */
-        mds_adjust_qunit(obd, current->fsuid, current->fsgid,
-                         parent_uid, parent_gid, rc);
+        lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_CREATE);
         return 0;
 }
 
@@ -1414,8 +1411,8 @@ static int mds_reint_unlink(struct mds_update_record *rec, int offset,
         struct lustre_handle parent_lockh, child_lockh, child_reuse_lockh;
         void *handle = NULL;
         int rc = 0, cleanup_phase = 0;
-        uid_t child_uid = 0, parent_uid = 0;
-        gid_t child_gid = 0, parent_gid = 0;
+        unsigned int qcids [MAXQUOTAS] = {0, 0};
+        unsigned int qpids [MAXQUOTAS] = {0, 0};
         ENTRY;
 
         LASSERT(offset == 0 || offset == 2);
@@ -1448,10 +1445,10 @@ static int mds_reint_unlink(struct mds_update_record *rec, int offset,
         }
 
         /* save uid/gid for quota acquire/release */
-        child_uid = child_inode->i_uid;
-        child_gid = child_inode->i_gid;
-        parent_uid = dparent->d_inode->i_uid;
-        parent_gid = dparent->d_inode->i_gid;
+        qcids[USRQUOTA] = child_inode->i_uid;
+        qcids[GRPQUOTA] = child_inode->i_gid;
+        qpids[USRQUOTA] = dparent->d_inode->i_uid;
+        qpids[GRPQUOTA] = dparent->d_inode->i_gid;
 
         cleanup_phase = 2; /* dchild has a lock */
 
@@ -1625,7 +1622,7 @@ cleanup:
         req->rq_status = rc;
 
         /* trigger dqrel on the owner of child and parent */
-        mds_adjust_qunit(obd, child_uid, child_gid, parent_uid, parent_gid, rc);
+        lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_UNLINK);
         return 0;
 }
 
@@ -1983,6 +1980,8 @@ static int mds_reint_rename(struct mds_update_record *rec, int offset,
         struct lov_mds_md *lmm = NULL;
         int rc = 0, lock_count = 3, cleanup_phase = 0;
         void *handle = NULL;
+        unsigned int qcids[MAXQUOTAS] = {0, 0};
+        unsigned int qpids[4] = {0, 0, 0, 0};
         ENTRY;
 
         LASSERT(offset == 0);
@@ -2032,6 +2031,14 @@ static int mds_reint_rename(struct mds_update_record *rec, int offset,
         if (old_inode == new_inode)
                 GOTO(cleanup, rc = 0);
 
+        /* save uids/gids for qunit acquire/release */
+        qcids[USRQUOTA] = old_inode->i_uid;
+        qcids[GRPQUOTA] = old_inode->i_gid;
+        qpids[USRQUOTA] = de_tgtdir->d_inode->i_uid;
+        qpids[GRPQUOTA] = de_tgtdir->d_inode->i_gid;
+        qpids[2] = de_srcdir->d_inode->i_uid;
+        qpids[3] = de_srcdir->d_inode->i_gid;
+
         /* if we are about to remove the target at first, pass the EA of
          * that inode to client to perform and cleanup on OST */
         body = lustre_msg_buf(req->rq_repmsg, 0, sizeof (*body));
@@ -2139,6 +2146,9 @@ cleanup:
                 LBUG();
         }
         req->rq_status = rc;
+
+        /* acquire/release qunit */
+        lquota_adjust(quota_interface, obd, qcids, qpids, rc, FSFILT_OP_RENAME);
         return 0;
 }
 
diff --git a/lustre/mds/quota_context.c b/lustre/mds/quota_context.c
deleted file mode 100644 (file)
index 1672bb2..0000000
+++ /dev/null
@@ -1,584 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
- *  lustre/mds/quota_context.c
- *  Lustre Quota Context
- *
- *  Copyright (c) 2001-2003 Cluster File Systems, Inc.
- *   Author: Niu YaWei <niu@clusterfs.com>
- *
- *   This file is part of Lustre, http://www.lustre.org.
- *
- *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
- *
- */
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
-
-#define DEBUG_SUBSYSTEM S_MDS
-
-#include <linux/version.h>
-#include <linux/fs.h>
-#include <asm/unistd.h>
-#include <linux/slab.h>
-#include <linux/quotaops.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/obd_class.h>
-#include <linux/lustre_quota.h>
-#include <linux/lustre_fsfilt.h>
-
-const unsigned long default_bunit_sz = 100 * 1024 * 1024;       /* 100M bytes */
-const unsigned long default_btune_sz = 50 * 1024 * 1024;        /* 50M bytes */
-const unsigned long default_iunit_sz = 5000;    /* 5000 inodes */
-const unsigned long default_itune_sz = 2500;    /* 2500 inodes */
-
-static inline int const
-qunit_hashfn(struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata)
-{
-        unsigned int id = qdata->qd_id;
-        unsigned int type = qdata->qd_type;
-
-        unsigned long tmp = ((unsigned long)qctxt >> L1_CACHE_SHIFT) ^ id;
-        tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
-        return tmp;
-}
-
-static inline struct lustre_qunit *find_qunit(unsigned int hashent,
-                                              struct lustre_quota_ctxt *qctxt,
-                                              struct qunit_data *qdata)
-{
-        struct list_head *pos;
-        struct lustre_qunit *qunit = NULL;
-        struct qunit_data *tmp;
-
-        list_for_each(pos, qunit_hash + hashent) {
-                qunit = list_entry(pos, struct lustre_qunit, lq_hash);
-                tmp = &qunit->lq_data;
-                if (qunit->lq_ctxt == qctxt &&
-                    qdata->qd_id == tmp->qd_id && qdata->qd_type == tmp->qd_type
-                    && qdata->qd_isblk == tmp->qd_isblk)
-                        return qunit;
-        }
-        return NULL;
-}
-
-/* check_cur_qunit - check the current usage of qunit.
- * @qctxt: quota context
- * @qdata: the type of quota unit to be checked
- *
- * return: 1 - need acquire qunit;
- *        2 - need release qunit;
- *        0 - need do nothing.
- *      < 0 - error.
- */
-static int
-check_cur_qunit(struct obd_device *obd,
-                struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata)
-{
-        struct super_block *sb = qctxt->lqc_sb;
-        unsigned long qunit_sz, tune_sz;
-        __u64 usage, limit;
-        struct obd_quotactl *qctl = NULL;
-        int ret = 0;
-        ENTRY;
-
-        if (!sb_any_quota_enabled(sb))
-                RETURN(0);
-
-        /* ignore root user */
-        if (qdata->qd_id == 0 && qdata->qd_type == USRQUOTA)
-                RETURN(0);
-
-        OBD_ALLOC(qctl, sizeof(*qctl));
-        if (qctl == NULL)
-                RETURN(-ENOMEM);
-
-        /* get fs quota usage & limit */
-        qctl->qc_cmd = Q_GETQUOTA;
-        qctl->qc_id = qdata->qd_id;
-        qctl->qc_type = qdata->qd_type;
-        ret = fsfilt_quotactl(obd, sb, qctl);
-        if (ret) {
-                if (ret == -ESRCH)      /* no limit */
-                        ret = 0;
-                else
-                        CERROR("can't get fs quota usage! (rc:%d)\n", ret);
-                GOTO(out, ret);
-        }
-
-        if (qdata->qd_isblk) {
-                usage = qctl->qc_dqblk.dqb_curspace;
-                limit = qctl->qc_dqblk.dqb_bhardlimit;
-                qunit_sz = qctxt->lqc_bunit_sz;
-                tune_sz = qctxt->lqc_btune_sz;
-
-                LASSERT(!(qunit_sz % QUOTABLOCK_SIZE));
-                LASSERT(limit == MIN_QLIMIT
-                        || !((__u32) limit % toqb(qunit_sz)));
-                limit = limit << QUOTABLOCK_BITS;
-        } else {
-                usage = qctl->qc_dqblk.dqb_curinodes;
-                limit = qctl->qc_dqblk.dqb_ihardlimit;
-                qunit_sz = qctxt->lqc_iunit_sz;
-                tune_sz = qctxt->lqc_itune_sz;
-        }
-
-        /* if it's not first time to set quota, ignore the no quota limit
-         * case */
-        if (!limit)
-                GOTO(out, ret = 0);
-
-        /* we don't count the MIN_QLIMIT */
-        if ((limit == MIN_QLIMIT && !qdata->qd_isblk) ||
-            (toqb(limit) == MIN_QLIMIT && qdata->qd_isblk))
-                limit = 0;
-
-        LASSERT(qdata->qd_count == 0);
-        if (limit <= usage + tune_sz) {
-                while (qdata->qd_count + limit <= usage + tune_sz)
-                        qdata->qd_count += qunit_sz;
-                ret = 1;
-        } else if (limit > usage + qunit_sz + tune_sz) {
-                while (limit - qdata->qd_count > usage + qunit_sz + tune_sz)
-                        qdata->qd_count += qunit_sz;
-                ret = 2;
-        }
-        LASSERT(ret == 0 || qdata->qd_count);
-out:
-        OBD_FREE(qctl, sizeof(*qctl));
-        RETURN(ret);
-}
-
-/* must hold qctxt->lqc_qunit_lock */
-static struct lustre_qunit *dqacq_in_flight(struct lustre_quota_ctxt *qctxt,
-                                            struct qunit_data *qdata)
-{
-        unsigned int hashent = qunit_hashfn(qctxt, qdata);
-        struct lustre_qunit *qunit = NULL;
-        ENTRY;
-
-        qunit = find_qunit(hashent, qctxt, qdata);
-        RETURN(qunit);
-}
-
-static struct lustre_qunit *alloc_qunit(struct lustre_quota_ctxt *qctxt,
-                                        struct qunit_data *qdata, int opc)
-{
-        struct lustre_qunit *qunit = NULL;
-        ENTRY;
-
-        OBD_SLAB_ALLOC(qunit, qunit_cachep, SLAB_NOFS, sizeof(*qunit));
-        if (qunit == NULL)
-                RETURN(NULL);
-
-        INIT_LIST_HEAD(&qunit->lq_hash);
-        INIT_LIST_HEAD(&qunit->lq_waiters);
-        atomic_set(&qunit->lq_refcnt, 1);
-        qunit->lq_ctxt = qctxt;
-        memcpy(&qunit->lq_data, qdata, sizeof(*qdata));
-        qunit->lq_opc = opc;
-
-        RETURN(qunit);
-}
-
-static inline void free_qunit(struct lustre_qunit *qunit)
-{
-        OBD_SLAB_FREE(qunit, qunit_cachep, sizeof(*qunit));
-}
-
-static inline void qunit_get(struct lustre_qunit *qunit)
-{
-        atomic_inc(&qunit->lq_refcnt);
-}
-
-static void qunit_put(struct lustre_qunit *qunit)
-{
-        LASSERT(atomic_read(&qunit->lq_refcnt));
-        if (atomic_dec_and_test(&qunit->lq_refcnt))
-                free_qunit(qunit);
-}
-
-static void
-insert_qunit_nolock(struct lustre_quota_ctxt *qctxt, struct lustre_qunit *qunit)
-{
-        struct list_head *head;
-
-        head = qunit_hash + qunit_hashfn(qctxt, &qunit->lq_data);
-        list_add(&qunit->lq_hash, head);
-}
-
-static void remove_qunit_nolock(struct lustre_qunit *qunit)
-{
-        LASSERT(!list_empty(&qunit->lq_hash));
-        list_del_init(&qunit->lq_hash);
-}
-
-struct qunit_waiter {
-        struct list_head qw_entry;
-        wait_queue_head_t qw_waitq;
-        int qw_rc;
-};
-
-#define QDATA_DEBUG(qd, fmt, arg...)                                    \
-        CDEBUG(D_QUOTA, "id(%u) type(%u) count(%u) isblk(%u):"          \
-               fmt, qd->qd_id, qd->qd_type, qd->qd_count, qd->qd_isblk, \
-               ## arg);                                                 \
-
-#define INC_QLIMIT(limit, count) (limit == MIN_QLIMIT) ? \
-                                 (limit = count) : (limit += count)
-
-static int
-dqacq_completion(struct obd_device *obd,
-                 struct lustre_quota_ctxt *qctxt,
-                 struct qunit_data *qdata, int rc, int opc)
-{
-        struct lustre_qunit *qunit = NULL;
-        struct super_block *sb = qctxt->lqc_sb;
-        unsigned long qunit_sz;
-        struct list_head *pos, *tmp;
-        int err = 0;
-        ENTRY;
-
-        LASSERT(qdata);
-        qunit_sz =
-            (qdata->qd_isblk) ? qctxt->lqc_bunit_sz : qctxt->lqc_iunit_sz;
-        LASSERT(!(qdata->qd_count % qunit_sz));
-
-        /* update local operational quota file */
-        if (rc == 0) {
-                __u32 count = QUSG(qdata->qd_count, qdata->qd_isblk);
-                struct obd_quotactl *qctl = NULL;
-
-                OBD_ALLOC(qctl, sizeof(*qctl));
-                if (qctl == NULL)
-                        GOTO(out, err = -ENOMEM);
-
-                /* acq/rel qunit for specified uid/gid is serialized,
-                 * so there is no race between get fs quota limit and
-                 * set fs quota limit */
-                qctl->qc_cmd = Q_GETQUOTA;
-                qctl->qc_id = qdata->qd_id;
-                qctl->qc_type = qdata->qd_type;
-                err = fsfilt_quotactl(obd, sb, qctl);
-                if (err) {
-                        CERROR("error get quota fs limit! (rc:%d)\n", err);
-                        GOTO(out_mem, err);
-                }
-
-                switch (opc) {
-                case QUOTA_DQACQ:
-                        if (qdata->qd_isblk) {
-                                qctl->qc_dqblk.dqb_valid = QIF_BLIMITS;
-                                INC_QLIMIT(qctl->qc_dqblk.dqb_bhardlimit,
-                                           count);
-                        } else {
-                                qctl->qc_dqblk.dqb_valid = QIF_ILIMITS;
-                                INC_QLIMIT(qctl->qc_dqblk.dqb_ihardlimit,
-                                           count);
-                        }
-                        break;
-                case QUOTA_DQREL:
-                        if (qdata->qd_isblk) {
-                                LASSERT(count < qctl->qc_dqblk.dqb_bhardlimit);
-                                qctl->qc_dqblk.dqb_valid = QIF_BLIMITS;
-                                qctl->qc_dqblk.dqb_bhardlimit -= count;
-                        } else {
-                                LASSERT(count < qctl->qc_dqblk.dqb_ihardlimit);
-                                qctl->qc_dqblk.dqb_valid = QIF_ILIMITS;
-                                qctl->qc_dqblk.dqb_ihardlimit -= count;
-                        }
-                        break;
-                default:
-                        LBUG();
-                        break;
-                }
-
-                /* clear quota limit */
-                if (count == 0) {
-                        if (qdata->qd_isblk)
-                                qctl->qc_dqblk.dqb_bhardlimit = 0;
-                        else
-                                qctl->qc_dqblk.dqb_ihardlimit = 0;
-                }
-
-                qctl->qc_cmd = Q_SETQUOTA;
-                err = fsfilt_quotactl(obd, sb, qctl);
-                if (err)
-                        CERROR("error set quota fs limit! (rc:%d)\n", err);
-
-                QDATA_DEBUG(qdata, "%s completion\n",
-                            opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
-out_mem:
-                OBD_FREE(qctl, sizeof(*qctl));
-        } else if (rc == -EDQUOT) {
-                CWARN("acquire qunit got EDQUOT\n");
-        } else {
-                CERROR("acquire qunit got error! (rc:%d)\n", rc);
-        }
-out:
-        /* remove the qunit from hash */
-        spin_lock(&qunit_hash_lock);
-
-        qunit = dqacq_in_flight(qctxt, qdata);
-
-        LASSERT(qunit);
-        LASSERT(opc == qunit->lq_opc);
-        remove_qunit_nolock(qunit);
-
-        /* wake up all waiters */
-        list_for_each_safe(pos, tmp, &qunit->lq_waiters) {
-                struct qunit_waiter *qw = list_entry(pos, struct qunit_waiter,
-                                                     qw_entry);
-                list_del_init(&qw->qw_entry);
-                qw->qw_rc = rc;
-                wake_up(&qw->qw_waitq);
-        }
-
-        spin_unlock(&qunit_hash_lock);
-
-        qunit_put(qunit);
-        RETURN(err);
-}
-
-struct dqacq_async_args {
-        struct lustre_quota_ctxt *aa_ctxt;
-        struct lustre_qunit *aa_qunit;
-};
-
-static int dqacq_interpret(struct ptlrpc_request *req, void *data, int rc)
-{
-        struct dqacq_async_args *aa = (struct dqacq_async_args *)data;
-        struct lustre_quota_ctxt *qctxt = aa->aa_ctxt;
-        struct lustre_qunit *qunit = aa->aa_qunit;
-        struct obd_device *obd = req->rq_import->imp_obd;
-        struct qunit_data *qdata = NULL;
-        ENTRY;
-
-        qdata = lustre_swab_repbuf(req, 0, sizeof(*qdata), lustre_swab_qdata);
-        if (rc == 0 && qdata == NULL)
-                RETURN(-EPROTO);
-
-        LASSERT(qdata->qd_id == qunit->lq_data.qd_id &&
-                qdata->qd_type == qunit->lq_data.qd_type &&
-                (qdata->qd_count == qunit->lq_data.qd_count ||
-                 qdata->qd_count == 0));
-
-        QDATA_DEBUG(qdata, "%s interpret rc(%d).\n",
-                    req->rq_reqmsg->opc == QUOTA_DQACQ ? "DQACQ" : "DQREL", rc);
-
-        rc = dqacq_completion(obd, qctxt, qdata, rc, req->rq_reqmsg->opc);
-
-        RETURN(rc);
-}
-
-static int got_qunit(struct qunit_waiter *waiter)
-{
-        int rc = 0;
-        ENTRY;
-        spin_lock(&qunit_hash_lock);
-        rc = list_empty(&waiter->qw_entry);
-        spin_unlock(&qunit_hash_lock);
-        RETURN(rc);
-}
-
-static int
-schedule_dqacq(struct obd_device *obd,
-               struct lustre_quota_ctxt *qctxt,
-               struct qunit_data *qdata, int opc, int wait)
-{
-        struct lustre_qunit *qunit = NULL;
-        struct qunit_waiter qw;
-        struct l_wait_info lwi = { 0 };
-        int rc = 0;
-        ENTRY;
-
-        INIT_LIST_HEAD(&qw.qw_entry);
-        init_waitqueue_head(&qw.qw_waitq);
-        qw.qw_rc = 0;
-
-        spin_lock(&qunit_hash_lock);
-
-        qunit = dqacq_in_flight(qctxt, qdata);
-        if (qunit && wait) {
-                list_add_tail(&qw.qw_entry, &qunit->lq_waiters);
-                spin_unlock(&qunit_hash_lock);
-                goto wait_completion;
-        } else if (qunit && !wait) {
-                qunit = NULL;
-        } else if (!qunit && (qunit = alloc_qunit(qctxt, qdata, opc)) != NULL)
-                insert_qunit_nolock(qctxt, qunit);
-
-        spin_unlock(&qunit_hash_lock);
-
-        if (qunit) {
-                struct ptlrpc_request *req;
-                struct qunit_data *reqdata;
-                struct dqacq_async_args *aa;
-                int size = sizeof(*reqdata);
-
-                /* master is going to dqacq/dqrel from itself */
-                if (qctxt->lqc_handler) {
-                        int rc2;
-                        QDATA_DEBUG(qdata, "local %s.\n",
-                                    opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
-                        rc = qctxt->lqc_handler(obd, qdata, opc);
-                        rc2 = dqacq_completion(obd, qctxt, qdata, rc, opc);
-                        RETURN((rc && rc != -EDQUOT) ? rc : rc2);
-                }
-
-                /* build dqacq/dqrel request */
-                LASSERT(qctxt->lqc_import);
-                req = ptlrpc_prep_req(qctxt->lqc_import, opc, 1, &size, NULL);
-                if (!req) {
-                        dqacq_completion(obd, qctxt, qdata, -ENOMEM, opc);
-                        RETURN(-ENOMEM);
-                }
-
-                reqdata = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*reqdata));
-                memcpy(reqdata, qdata, sizeof(*reqdata));
-                size = sizeof(*reqdata);
-                req->rq_replen = lustre_msg_size(1, &size);
-
-                LASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
-                aa = (struct dqacq_async_args *)&req->rq_async_args;
-                aa->aa_ctxt = qctxt;
-                aa->aa_qunit = qunit;
-
-                req->rq_interpret_reply = dqacq_interpret;
-                ptlrpcd_add_req(req);
-
-                QDATA_DEBUG(qdata, "%s scheduled.\n",
-                            opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
-        }
-wait_completion:
-        if (wait && qunit) {
-                struct qunit_data *p = &qunit->lq_data;
-                QDATA_DEBUG(p, "wait for dqacq.\n");
-
-                l_wait_event(qw.qw_waitq, got_qunit(&qw), &lwi);
-                if (qw.qw_rc == 0)
-                        rc = -EAGAIN;
-
-                CDEBUG(D_QUOTA, "wait dqacq done. (rc:%d)\n", qw.qw_rc);
-        }
-        RETURN(rc);
-}
-
-int
-qctxt_adjust_qunit(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
-                   uid_t uid, gid_t gid, __u32 isblk)
-{
-        int ret, rc = 0, i = USRQUOTA;
-        struct qunit_data qdata[MAXQUOTAS];
-        ENTRY;
-
-        if (!sb_any_quota_enabled(qctxt->lqc_sb))
-                RETURN(0);
-
-        qdata[USRQUOTA].qd_id = uid;
-        qdata[USRQUOTA].qd_type = USRQUOTA;
-        qdata[USRQUOTA].qd_isblk = isblk;
-        qdata[USRQUOTA].qd_count = 0;
-        qdata[GRPQUOTA].qd_id = gid;
-        qdata[GRPQUOTA].qd_type = GRPQUOTA;
-        qdata[GRPQUOTA].qd_isblk = isblk;
-        qdata[GRPQUOTA].qd_count = 0;
-
-next:
-        ret = check_cur_qunit(obd, qctxt, &qdata[i]);
-        if (ret > 0) {
-                int opc;
-                /* need acquire or release */
-                opc = ret == 1 ? QUOTA_DQACQ : QUOTA_DQREL;
-                ret = schedule_dqacq(obd, qctxt, &qdata[i], opc, 0);
-                if (!rc)
-                        rc = ret;
-        }
-        if (++i < MAXQUOTAS)
-                goto next;
-
-        RETURN(rc);
-}
-EXPORT_SYMBOL(qctxt_adjust_qunit);
-
-int
-qctxt_wait_on_dqacq(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
-                    uid_t uid, gid_t gid, __u32 isblk)
-{
-        struct qunit_data qdata[MAXQUOTAS];
-        int i = USRQUOTA, ret, rc = -EAGAIN;
-        ENTRY;
-
-        if (!sb_any_quota_enabled(qctxt->lqc_sb))
-                RETURN(0);
-
-        qdata[USRQUOTA].qd_id = uid;
-        qdata[USRQUOTA].qd_type = USRQUOTA;
-        qdata[USRQUOTA].qd_isblk = isblk;
-        qdata[USRQUOTA].qd_count = 0;
-        qdata[GRPQUOTA].qd_id = gid;
-        qdata[GRPQUOTA].qd_type = GRPQUOTA;
-        qdata[GRPQUOTA].qd_isblk = isblk;
-        qdata[GRPQUOTA].qd_count = 0;
-
-next:
-        ret = check_cur_qunit(obd, qctxt, &qdata[i]);
-        if (ret > 0)
-                rc = schedule_dqacq(obd, qctxt, &qdata[i], QUOTA_DQACQ, 1);
-
-        if (++i < MAXQUOTAS)
-                goto next;
-
-        RETURN(rc);
-}
-EXPORT_SYMBOL(qctxt_wait_on_dqacq);
-
-int
-qctxt_init(struct lustre_quota_ctxt *qctxt, struct super_block *sb,
-           dqacq_handler_t handler)
-{
-        int rc = 0;
-        ENTRY;
-
-        rc = ptlrpcd_addref();
-        if (rc)
-                RETURN(rc);
-
-        qctxt->lqc_handler = handler;
-        qctxt->lqc_sb = sb;
-        qctxt->lqc_import = NULL;
-        qctxt->lqc_flags = 0;
-        qctxt->lqc_bunit_sz = default_bunit_sz;
-        qctxt->lqc_btune_sz = default_btune_sz;
-        qctxt->lqc_iunit_sz = default_iunit_sz;
-        qctxt->lqc_itune_sz = default_itune_sz;
-
-        RETURN(0);
-}
-EXPORT_SYMBOL(qctxt_init);
-
-void qctxt_cleanup(struct lustre_quota_ctxt *qctxt, int force)
-{
-        struct list_head *pos, *tmp;
-        struct lustre_qunit *qunit;
-        int i;
-        ENTRY;
-
-        ptlrpcd_decref();
-
-        spin_lock(&qunit_hash_lock);
-
-        for (i = 0; i < NR_DQHASH; i++) {
-                list_for_each_safe(pos, tmp, &qunit_hash[i]) {
-                        qunit = list_entry(pos, struct lustre_qunit, lq_hash);
-                        LASSERT(qunit->lq_ctxt != qctxt);
-                }
-        }
-
-        spin_unlock(&qunit_hash_lock);
-        EXIT;
-}
-EXPORT_SYMBOL(qctxt_cleanup);
index 79c730a..043714d 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/obd_ost.h>
 #include <linux/obd_class.h>
 #include <linux/lprocfs_status.h>
-#include <linux/lustre_quota.h>
 
 extern struct list_head obd_types;
 static spinlock_t obd_types_lock = SPIN_LOCK_UNLOCKED;
@@ -45,16 +44,6 @@ kmem_cache_t *obdo_cachep = NULL;
 EXPORT_SYMBOL(obdo_cachep);
 kmem_cache_t *import_cachep = NULL;
 
-#ifdef HAVE_QUOTA_SUPPORT
-kmem_cache_t *qunit_cachep = NULL;
-struct list_head qunit_hash[NR_DQHASH];
-spinlock_t qunit_hash_lock = SPIN_LOCK_UNLOCKED;
-EXPORT_SYMBOL(qunit_cachep);
-EXPORT_SYMBOL(qunit_hash);
-EXPORT_SYMBOL(qunit_hash_lock);
-#endif
-
-
 int (*ptlrpc_put_connection_superhack)(struct ptlrpc_connection *c);
 void (*ptlrpc_abort_inflight_superhack)(struct obd_import *imp);
 
@@ -365,25 +354,6 @@ struct obd_device * class_devices_in_group(struct obd_uuid *grp_uuid, int *next)
         return NULL;
 }
 
-static void obd_cleanup_qunit_cache(void)
-{
-#ifdef HAVE_QUOTA_SUPPORT
-        int i;
-        ENTRY;
-
-        spin_lock(&qunit_hash_lock);
-        for (i = 0; i < NR_DQHASH; i++)
-                LASSERT(list_empty(qunit_hash + i));
-        spin_unlock(&qunit_hash_lock);
-
-        if (qunit_cachep) {
-                LASSERTF(kmem_cache_destroy(qunit_cachep) == 0,
-                         "Cannot destroy ll_qunit_cache\n");
-                qunit_cachep = NULL;
-        }
-        EXIT;
-#endif
-}
 
 void obd_cleanup_caches(void)
 {
@@ -398,35 +368,11 @@ void obd_cleanup_caches(void)
                          "Cannot destory ll_import_cache\n");
                 import_cachep = NULL;
         }
-        obd_cleanup_qunit_cache();
         EXIT;
 }
 
-static int obd_init_qunit_cache(void)
-{
-
-#ifdef HAVE_QUOTA_SUPPORT
-        int i;
-        ENTRY;
-
-        LASSERT(qunit_cachep == NULL);
-        qunit_cachep = kmem_cache_create("ll_qunit_cache",
-                                         sizeof(struct lustre_qunit),
-                                         0, 0, NULL, NULL);
-        if (!qunit_cachep)
-                RETURN(-ENOMEM);
-
-        spin_lock(&qunit_hash_lock);
-        for (i = 0; i < NR_DQHASH; i++)
-                INIT_LIST_HEAD(qunit_hash + i);
-        spin_unlock(&qunit_hash_lock);
-#endif
-        RETURN(0);
-}
-
 int obd_init_caches(void)
 {
-        int rc = 0;
         ENTRY;
 
         LASSERT(obdo_cachep == NULL);
@@ -442,10 +388,6 @@ int obd_init_caches(void)
         if (!import_cachep)
                 GOTO(out, -ENOMEM);
 
-        rc = obd_init_qunit_cache();
-        if (rc)
-                GOTO(out, rc);
-
         RETURN(0);
  out:
         obd_cleanup_caches();
index 11e41dd..0e64454 100644 (file)
@@ -106,7 +106,7 @@ EXPORT_SYMBOL(llog_sync);
 
 int llog_add(struct llog_ctxt *ctxt, struct llog_rec_hdr *rec,
                 struct lov_stripe_md *lsm, struct llog_cookie *logcookies,
-                int numcookies, llog_fill_rec_cb_t fill_cb)
+                int numcookies)
 {
         int rc;
         ENTRY;
@@ -118,7 +118,7 @@ int llog_add(struct llog_ctxt *ctxt, struct llog_rec_hdr *rec,
         
         CTXT_CHECK_OP(ctxt, add, -EOPNOTSUPP);
 
-        rc = CTXTP(ctxt, add)(ctxt, rec, lsm, logcookies, numcookies, fill_cb);
+        rc = CTXTP(ctxt, add)(ctxt, rec, lsm, logcookies, numcookies);
         RETURN(rc);
 }
 EXPORT_SYMBOL(llog_add);
@@ -283,8 +283,7 @@ EXPORT_SYMBOL(llog_obd_origin_cleanup);
 /* add for obdfilter/sz and mds/unlink */
 int llog_obd_origin_add(struct llog_ctxt *ctxt,
                         struct llog_rec_hdr *rec, struct lov_stripe_md *lsm,
-                        struct llog_cookie *logcookies, int numcookies,
-                        llog_fill_rec_cb_t fill_cb)
+                        struct llog_cookie *logcookies, int numcookies)
 {
         struct llog_handle *cathandle;
         int rc;
index ef684b6..3aba587 100644 (file)
@@ -1406,7 +1406,7 @@ int filter_common_setup(struct obd_device *obd, obd_count len, void *buf,
         }
 
         filter->fo_vfsmnt = mnt;
-        filter->fo_sb = mnt->mnt_sb;
+        obd->u.obt.obt_sb = mnt->mnt_sb;
         filter->fo_fstype = mnt->mnt_sb->s_type->name;
         CDEBUG(D_SUPER, "%s: mnt = %p\n", filter->fo_fstype, mnt);
 
@@ -1459,10 +1459,9 @@ int filter_common_setup(struct obd_device *obd, obd_count len, void *buf,
                 GOTO(err_post, rc);
         }
 
-        rc = filter_quota_setup(filter);
-        if (rc) {
+        rc = lquota_setup(quota_interface, obd, lcfg);
+        if (rc)
                 GOTO(err_post, rc);
-        }
 
         if (obd->obd_recovering) {
                 LCONSOLE_WARN("OST %s now serving %s, but will be in recovery "
@@ -1493,7 +1492,7 @@ err_post:
 err_mntput:
         unlock_kernel();
         mntput(mnt);
-        filter->fo_sb = 0;
+        obd->u.obt.obt_sb = 0;
         lock_kernel();
 err_ops:
         fsfilt_put_ops(obd->obd_fsops);
@@ -1508,6 +1507,9 @@ static int filter_setup(struct obd_device *obd, obd_count len, void *buf)
         unsigned long page;
         int rc;
 
+        CLASSERT(offsetof(struct obd_device, u.obt) ==
+                 offsetof(struct obd_device, u.filter.fo_obt));
+
         if (!LUSTRE_CFG_BUFLEN(lcfg, 1) || !LUSTRE_CFG_BUFLEN(lcfg, 2))
                 RETURN(-EINVAL);
 
@@ -1629,22 +1631,22 @@ static int filter_cleanup(struct obd_device *obd)
 
         ping_evictor_stop();
 
-        filter_quota_cleanup(filter);
+        lquota_cleanup(quota_interface, obd);
 
         ldlm_namespace_free(obd->obd_namespace, obd->obd_force);
 
-        if (filter->fo_sb == NULL)
+        if (obd->u.obt.obt_sb == NULL)
                 RETURN(0);
-        save_dev = lvfs_sbdev(filter->fo_sb);
+        save_dev = lvfs_sbdev(obd->u.obt.obt_sb);
 
         lprocfs_free_obd_stats(obd);
         lprocfs_obd_cleanup(obd);
 
         filter_post(obd);
 
-        shrink_dcache_parent(filter->fo_sb->s_root);
+        shrink_dcache_parent(obd->u.obt.obt_sb->s_root);
 
-        LL_DQUOT_OFF(filter->fo_sb);
+        LL_DQUOT_OFF(obd->u.obt.obt_sb);
 
         if (atomic_read(&filter->fo_vfsmnt->mnt_count) > 1)
                 CERROR("%s: mount point %p busy, mnt_count: %d\n",
@@ -1659,8 +1661,8 @@ static int filter_cleanup(struct obd_device *obd)
         }
 
         mntput(filter->fo_vfsmnt);
-        //destroy_buffers(filter->fo_sb->s_dev);
-        filter->fo_sb = NULL;
+        //destroy_buffers(obd->u.obt.obt_sb->s_dev);
+        obd->u.obt.obt_sb = NULL;
 
         lvfs_clear_rdonly(save_dev);
 
@@ -1881,7 +1883,7 @@ static int filter_disconnect(struct obd_export *exp)
         rc = class_disconnect(exp);
         ldlm_cancel_locks_for_export(exp);
 
-        fsfilt_sync(obd, obd->u.filter.fo_sb);
+        fsfilt_sync(obd, obd->u.obt.obt_sb);
 
         /* flush any remaining cancel messages out to the target */
         ctxt = llog_get_context(obd, LLOG_MDS_OST_REPL_CTXT);
@@ -1951,11 +1953,10 @@ static int filter_getattr(struct obd_export *exp, struct obdo *oa,
 int filter_setattr_internal(struct obd_export *exp, struct dentry *dentry,
                             struct obdo *oa, struct obd_trans_info *oti)
 {
+        unsigned int orig_ids[MAXQUOTAS] = {0, 0};
         struct llog_cookie *fcc = NULL;
         struct filter_obd *filter;
         struct iattr iattr;
-        uid_t orig_uid = 0;
-        gid_t orig_gid = 0;
         void *handle;
         int rc, err;
         ENTRY;
@@ -1977,8 +1978,8 @@ int filter_setattr_internal(struct obd_export *exp, struct dentry *dentry,
                 down(&dentry->d_inode->i_sem);
 
         if (iattr.ia_valid & (ATTR_UID | ATTR_GID)) {
-                orig_uid = dentry->d_inode->i_uid;
-                orig_gid = dentry->d_inode->i_gid;
+                orig_ids[USRQUOTA] = dentry->d_inode->i_uid;
+                orig_ids[GRPQUOTA] = dentry->d_inode->i_gid;
                 handle = fsfilt_start_log(exp->exp_obd, dentry->d_inode,
                                           FSFILT_OP_SETATTR, oti, 1);
         } else {
@@ -2017,17 +2018,12 @@ out_unlock:
                 up(&dentry->d_inode->i_sem);
 
         /* trigger quota release */
-        if (rc == 0 && iattr.ia_valid & (ATTR_SIZE | ATTR_UID | ATTR_GID)) {
-                int rc2 = qctxt_adjust_qunit(exp->exp_obd, &filter->fo_quota_ctxt,
-                                             oa->o_uid, oa->o_gid, 1);
-                if (rc2)
-                        CERROR("error filter adjust qunit! (rc:%d)\n", rc2);
-                
-                /* after owner changed, release quota for the original owner */
-                rc2 = qctxt_adjust_qunit(exp->exp_obd, &filter->fo_quota_ctxt,
-                                         orig_uid, orig_gid, 1);
-                if (rc2)
-                        CERROR("error filter adjust qunit! (rc:%d)\n", rc2);
+        if (iattr.ia_valid & (ATTR_SIZE | ATTR_UID | ATTR_GID)) {
+                unsigned int cur_ids[MAXQUOTAS] = {oa->o_uid, oa->o_gid};
+                int rc2= lquota_adjust(quota_interface, exp->exp_obd, cur_ids,
+                                       orig_ids, rc, FSFILT_OP_SETATTR);
+                CDEBUG(rc2 ? D_ERROR : D_QUOTA, 
+                       "filter adjust qunit. (rc:%d)\n", rc2);
         }
         return rc;
 }
@@ -2141,7 +2137,7 @@ static int filter_statfs(struct obd_device *obd, struct obd_statfs *osfs,
                          unsigned long max_age)
 {
         struct filter_obd *filter = &obd->u.filter;
-        int blockbits = filter->fo_sb->s_blocksize_bits;
+        int blockbits = obd->u.obt.obt_sb->s_blocksize_bits;
         int rc;
         ENTRY;
 
@@ -2149,7 +2145,7 @@ static int filter_statfs(struct obd_device *obd, struct obd_statfs *osfs,
          * might be under-reporting if clients haven't announced their
          * caches with brw recently */
         spin_lock(&obd->obd_osfs_lock);
-        rc = fsfilt_statfs(obd, filter->fo_sb, max_age);
+        rc = fsfilt_statfs(obd, obd->u.obt.obt_sb, max_age);
         memcpy(osfs, &obd->obd_osfs, sizeof(*osfs));
         spin_unlock(&obd->obd_osfs_lock);
 
@@ -2168,7 +2164,8 @@ static int filter_statfs(struct obd_device *obd, struct obd_statfs *osfs,
         /* set EROFS to state field if FS is mounted as RDONLY. The goal is to
          * stop creating files on MDS if OST is not good shape to create
          * objects.*/
-        osfs->os_state = (filter->fo_sb->s_flags & MS_RDONLY) ? EROFS : 0;
+        osfs->os_state = (filter->fo_obt.obt_sb->s_flags & MS_RDONLY) ? 
+                EROFS : 0;
         RETURN(rc);
 }
 
@@ -2351,6 +2348,7 @@ filter_destroy_internal(struct obd_export *exp, struct obdo *oa,
         void *handle = NULL;
         struct llog_cookie *fcc = NULL;
         int rc, rc2, cleanup_phase = 0, have_prepared = 0;
+        unsigned int qcids[MAXQUOTAS] = {0, 0};
         obd_gr group = 0;
         ENTRY;
 
@@ -2459,12 +2457,12 @@ cleanup:
         }
 
         /* trigger quota release */
-        if (rc == 0) {
-                rc2 = qctxt_adjust_qunit(obd, &filter->fo_quota_ctxt,
-                                         oa->o_uid, oa->o_gid, 1);
-                if (rc2)
-                        CERROR("error filter adjust qunit! (rc:%d)\n", rc2);
-        }
+        qcids[USRQUOTA] = oa->o_uid;
+        qcids[GRPQUOTA] = oa->o_gid;
+        rc2 = lquota_adjust(quota_interface, obd, qcids, NULL, rc,
+                            FSFILT_OP_UNLINK); 
+        CDEBUG(rc2 ? D_ERROR : D_QUOTA, 
+               "filter adjust qunit! (rc:%d)\n", rc2);
 
         RETURN(rc);
 }
@@ -2596,7 +2594,7 @@ static int filter_create(struct obd_export *exp, struct obdo *oa,
         struct filter_obd *filter;
         obd_gr group = oa->o_gr;
         struct obd_device *obd;
-        int rc;
+        int rc = 0;
         ENTRY;
 
         obd = exp->exp_obd;
@@ -2636,7 +2634,7 @@ static int filter_create(struct obd_export *exp, struct obdo *oa,
                 rc = filter_statfs(obd, osfs, jiffies - HZ);
                 if (rc == 0 && osfs->os_bavail < (osfs->os_blocks >> 10)) {
                         CDEBUG(D_HA, "OST out of space! avail "LPU64"\n",
-                               osfs->os_bavail << filter->fo_sb->s_blocksize_bits);
+                               osfs->os_bavail << filter->fo_obt.obt_sb->s_blocksize_bits);
                         rc = -ENOSPC;
                 }
 
@@ -2701,7 +2699,7 @@ static int filter_sync(struct obd_export *exp, struct obdo *oa,
 
         /* an objid of zero is taken to mean "sync whole filesystem" */
         if (!oa || !(oa->o_valid & OBD_MD_FLID)) {
-                rc = fsfilt_sync(exp->exp_obd, filter->fo_sb);
+                rc = fsfilt_sync(exp->exp_obd, filter->fo_obt.obt_sb);
                 /* flush any remaining cancel messages out to the target */
                 ctxt = llog_get_context(exp->exp_obd, LLOG_MDS_OST_REPL_CTXT);
                 llog_sync(ctxt, exp);
@@ -2754,7 +2752,7 @@ static int filter_get_info(struct obd_export *exp, __u32 keylen,
             memcmp(key, "blocksize", keylen) == 0) {
                 __u32 *blocksize = val;
                 *vallen = sizeof(*blocksize);
-                *blocksize = obd->u.filter.fo_sb->s_blocksize;
+                *blocksize = obd->u.obt.obt_sb->s_blocksize;
                 RETURN(0);
         }
 
@@ -2762,7 +2760,7 @@ static int filter_get_info(struct obd_export *exp, __u32 keylen,
             memcmp(key, "blocksize_bits", keylen) == 0) {
                 __u32 *blocksize_bits = val;
                 *vallen = sizeof(*blocksize_bits);
-                *blocksize_bits = obd->u.filter.fo_sb->s_blocksize_bits;
+                *blocksize_bits = obd->u.obt.obt_sb->s_blocksize_bits;
                 RETURN(0);
         }
 
@@ -2801,8 +2799,8 @@ static int filter_set_info(struct obd_export *exp, __u32 keylen,
         /* setup llog imports */
         ctxt = llog_get_context(obd, LLOG_MDS_OST_REPL_CTXT);
         rc = llog_receptor_accept(ctxt, exp->exp_imp_reverse);
-
-        filter_quota_set_info(exp, obd);
+        
+        lquota_setinfo(quota_interface, exp, obd);
 
         RETURN(rc);
 }
@@ -2823,13 +2821,13 @@ int filter_iocontrol(unsigned int cmd, struct obd_export *exp,
 
         case OBD_IOC_SYNC: {
                 CDEBUG(D_HA, "syncing ost %s\n", obd->obd_name);
-                rc = fsfilt_sync(obd, obd->u.filter.fo_sb);
+                rc = fsfilt_sync(obd, obd->u.obt.obt_sb);
                 RETURN(rc);
         }
 
         case OBD_IOC_SET_READONLY: {
                 void *handle;
-                struct super_block *sb = obd->u.filter.fo_sb;
+                struct super_block *sb = obd->u.obt.obt_sb;
                 struct inode *inode = sb->s_root->d_inode;
                 BDEVNAME_DECLARE_STORAGE(tmp);
                 CERROR("*** setting device %s read-only ***\n",
@@ -2840,9 +2838,9 @@ int filter_iocontrol(unsigned int cmd, struct obd_export *exp,
                         rc = fsfilt_commit(obd, inode, handle, 1);
 
                 CDEBUG(D_HA, "syncing ost %s\n", obd->obd_name);
-                rc = fsfilt_sync(obd, obd->u.filter.fo_sb);
+                rc = fsfilt_sync(obd, obd->u.obt.obt_sb);
 
-                lvfs_set_rdonly(lvfs_sbdev(obd->u.filter.fo_sb));
+                lvfs_set_rdonly(lvfs_sbdev(obd->u.obt.obt_sb));
                 RETURN(0);
         }
 
@@ -2877,14 +2875,13 @@ int filter_iocontrol(unsigned int cmd, struct obd_export *exp,
 
 static int filter_health_check(struct obd_device *obd)
 {
-        struct filter_obd *filter = &obd->u.filter;
         int rc = 0;
 
         /*
          * health_check to return 0 on healthy
          * and 1 on unhealthy.
          */
-        if(filter->fo_sb->s_flags & MS_RDONLY)
+        if(obd->u.obt.obt_sb->s_flags & MS_RDONLY)
                 rc = 1;
 
         return rc;
@@ -2924,8 +2921,6 @@ static struct obd_ops filter_obd_ops = {
         .o_llog_init      = filter_llog_init,
         .o_llog_finish    = filter_llog_finish,
         .o_iocontrol      = filter_iocontrol,
-        .o_quotacheck     = filter_quotacheck,
-        .o_quotactl       = filter_quotactl,
         .o_health_check   = filter_health_check,
 };
 
@@ -2956,6 +2951,9 @@ static struct obd_ops filter_sanobd_ops = {
         .o_iocontrol      = filter_iocontrol,
 };
 
+quota_interface_t *quota_interface = NULL;
+extern quota_interface_t filter_quota_interface;
+
 static int __init obdfilter_init(void)
 {
         struct lprocfs_static_vars lvars;
@@ -2971,6 +2969,10 @@ static int __init obdfilter_init(void)
         if (obdfilter_created_scratchpad == NULL)
                 return -ENOMEM;
 
+        quota_interface = PORTAL_SYMBOL_GET(filter_quota_interface);
+        init_obd_quota_ops(quota_interface, &filter_obd_ops);
+        init_obd_quota_ops(quota_interface, &filter_sanobd_ops);
+
         rc = class_register_type(&filter_obd_ops, lvars.module_vars,
                                  OBD_FILTER_DEVICENAME);
         if (rc)
@@ -2981,15 +2983,22 @@ static int __init obdfilter_init(void)
         if (rc) {
                 class_unregister_type(OBD_FILTER_DEVICENAME);
 out:
+                if (quota_interface)
+                        PORTAL_SYMBOL_PUT(filter_quota_interface);
+                        
                 OBD_FREE(obdfilter_created_scratchpad,
                          OBDFILTER_CREATED_SCRATCHPAD_ENTRIES *
                          sizeof(*obdfilter_created_scratchpad));
-        }
+        } 
+
         return rc;
 }
 
 static void __exit obdfilter_exit(void)
 {
+        if (quota_interface)
+                PORTAL_SYMBOL_PUT(filter_quota_interface);
+
         class_unregister_type(OBD_FILTER_SAN_DEVICENAME);
         class_unregister_type(OBD_FILTER_DEVICENAME);
         OBD_FREE(obdfilter_created_scratchpad,
index dbbf1df..a2c2267 100644 (file)
@@ -194,71 +194,6 @@ static inline int lproc_filter_attach_seqstat(struct obd_device *dev) {}
 #endif
 
 /* Quota stuff */
-#ifdef HAVE_QUOTA_SUPPORT
-int filter_quota_setup(struct filter_obd *filter);
-void filter_quota_cleanup(struct filter_obd *filter);
-void filter_quota_set_info(struct obd_export *exp, struct obd_device *obd);
-int filter_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl);
-int filter_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl);
-int filter_quota_enforcement(struct obd_device *obd,
-                                    unsigned int fsuid, unsigned int fsgid,
-                                    struct lvfs_ucred **ret_uc);
-int filter_get_quota_flag(struct obd_device *obd, struct obdo *oa);
-int filter_quota_check_master(struct obd_device *obd, struct inode *inode);
-
-#ifdef LPROCFS
-int lprocfs_filter_rd_bunit(char *page, char **start, off_t off,
-                                   int count, int *eof, void *data);
-int lprocfs_filter_rd_iunit(char *page, char **start, off_t off,
-                                   int count, int *eof, void *data);
-int lprocfs_filter_wr_bunit(struct file *file, const char *buffer,
-                                   unsigned long count, void *data);
-int lprocfs_filter_wr_iunit(struct file *file, const char *buffer,
-                                   unsigned long count, void *data);
-int lprocfs_filter_rd_btune(char *page, char **start, off_t off,
-                                   int count, int *eof, void *data);
-int lprocfs_filter_rd_itune(char *page, char **start, off_t off,
-                                   int count, int *eof, void *data);
-int lprocfs_filter_wr_btune(struct file *file, const char *buffer,
-                                   unsigned long count, void *data);
-int lprocfs_filter_wr_itune(struct file *file, const char *buffer,
-                                   unsigned long count, void *data);
-#endif /* LPROCFS */
-#else /* !HAVE_QUOTA_SUPPORT */
-static inline int filter_quota_setup(struct filter_obd *filter)
-{
-        return 0;
-}
-static inline void filter_quota_cleanup(struct filter_obd *filter) {}
-static inline void filter_quota_set_info(struct obd_export *exp,
-                                         struct obd_device *obd) {}
-static inline int filter_quotacheck(struct obd_export *exp,
-                                    struct obd_quotactl *oqctl)
-{
-        return -ENOTSUPP;
-}
-static inline int filter_quotactl(struct obd_export *exp,
-                                  struct obd_quotactl *oqctl)
-{
-        return -ENOTSUPP;
-}
-static inline int filter_quota_enforcement(struct obd_device *obd,
-                                           unsigned int fsuid,
-                                           unsigned int fsgid,
-                                           struct lvfs_ucred **ret_uc)
-{
-        return 0;
-}
-static inline int filter_get_quota_flag(struct obd_device *obd,
-                                        struct obdo *oa)
-{
-        return 0;
-}
-static inline int filter_quota_check_master(struct obd_device *obd,
-                                            struct inode *inode)
-{
-        return 0;
-}
-#endif /* HAVE_QUOTA_SUPPORT */
+extern quota_interface_t *quota_interface;
 
 #endif /* _FILTER_INTERNAL_H */
index b9ca816..0b68a84 100644 (file)
@@ -152,7 +152,7 @@ static void filter_grant_incoming(struct obd_export *exp, struct obdo *oa)
 obd_size filter_grant_space_left(struct obd_export *exp)
 {
         struct obd_device *obd = exp->exp_obd;
-        int blockbits = obd->u.filter.fo_sb->s_blocksize_bits;
+        int blockbits = obd->u.obt.obt_sb->s_blocksize_bits;
         obd_size tot_granted = obd->u.filter.fo_tot_granted, avail, left = 0;
         int rc, statfs_done = 0;
 
@@ -160,7 +160,7 @@ obd_size filter_grant_space_left(struct obd_export *exp)
 
         if (time_before(obd->obd_osfs_age, jiffies - HZ)) {
 restat:
-                rc = fsfilt_statfs(obd, obd->u.filter.fo_sb, jiffies + 1);
+                rc = fsfilt_statfs(obd, obd->u.obt.obt_sb, jiffies + 1);
                 if (rc) /* N.B. statfs can't really fail */
                         RETURN(0);
                 statfs_done = 1;
@@ -209,7 +209,7 @@ long filter_grant(struct obd_export *exp, obd_size current_grant,
 {
         struct obd_device *obd = exp->exp_obd;
         struct filter_export_data *fed = &exp->exp_filter_data;
-        int blockbits = obd->u.filter.fo_sb->s_blocksize_bits;
+        int blockbits = obd->u.obt.obt_sb->s_blocksize_bits;
         __u64 grant = 0;
 
         LASSERT_SPIN_LOCKED(&obd->obd_osfs_lock);
@@ -391,7 +391,7 @@ static int filter_grant_check(struct obd_export *exp, int objcount,
                               struct inode *inode)
 {
         struct filter_export_data *fed = &exp->exp_filter_data;
-        int blocksize = exp->exp_obd->u.filter.fo_sb->s_blocksize;
+        int blocksize = exp->exp_obd->u.obt.obt_sb->s_blocksize;
         unsigned long used = 0, ungranted = 0, using;
         int i, rc = -ENOSPC, obj, n = 0, mask = D_CACHE;
 
@@ -465,7 +465,7 @@ static int filter_grant_check(struct obd_export *exp, int objcount,
 
         /* Rough calc in case we don't refresh cached statfs data */
         using = (used + ungranted + 1 ) >>
-                exp->exp_obd->u.filter.fo_sb->s_blocksize_bits;
+                exp->exp_obd->u.obt.obt_sb->s_blocksize_bits;
         if (exp->exp_obd->obd_osfs.os_bavail > using)
                 exp->exp_obd->obd_osfs.os_bavail -= using;
         else
index a712188..1ab866c 100644 (file)
@@ -53,6 +53,7 @@ struct dio_request {
         unsigned long    *dr_blocks;
         spinlock_t        dr_lock;
         unsigned long     dr_start_time; /* jiffies */
+        unsigned int      dr_ignore_quota:1;
         struct filter_obd *dr_filter;
 };
 
@@ -439,6 +440,8 @@ int filter_direct_io(int rw, struct dentry *dchild, void *iobuf,
                 LASSERT(dreq->dr_npages > 0);
                 create = 1;
                 sem = &obd->u.filter.fo_alloc_lock;
+                
+                lquota_enforce(quota_interface, obd, dreq->dr_ignore_quota);
         }
 remap:
         rc = fsfilt_map_inode_pages(obd, inode, dreq->dr_pages,
@@ -453,7 +456,8 @@ remap:
                  * pre-dqacq in time or this user has exceeded quota limit, we
                  * have to wait for the completion of in flight dqacq/dqrel,
                  * then try again */
-                if (filter_quota_check_master(obd, inode))
+                if (lquota_acquire(quota_interface, obd, inode->i_uid,
+                                   inode->i_gid))
                         goto remap;
         }
 
@@ -528,10 +532,9 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa,
         unsigned long now = jiffies;
         int i, err, cleanup_phase = 0;
         struct obd_device *obd = exp->exp_obd;
-        struct filter_obd *filter = &obd->u.filter;
-        struct lvfs_ucred *uc = NULL;
         void *wait_handle;
         int   total_size = 0;
+        unsigned int qcids[MAXQUOTAS] = {0, 0};
         ENTRY;
 
         LASSERT(oti != NULL);
@@ -548,6 +551,7 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa,
         fso.fso_bufcnt = obj->ioo_bufcnt;
         inode = res->dentry->d_inode;
 
+        dreq->dr_ignore_quota = 0;
         for (i = 0, lnb = res; i < obj->ioo_bufcnt; i++, lnb++) {
                 loff_t this_size;
 
@@ -571,16 +575,15 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa,
                 this_size = lnb->offset + lnb->len;
                 if (this_size > iattr.ia_size)
                         iattr.ia_size = this_size;
+                
+                /* if one page is a write-back page from client cache, or it's
+                 * written by root, then mark the whole io request as ignore 
+                 * quota request */
+                if (lnb->flags & (OBD_BRW_FROM_GRANT | OBD_BRW_NOQUOTA))
+                        dreq->dr_ignore_quota = 1;
         }
 
-        /* The client store the user credit information fsuid and fsgid
-         * in oa->o_uid and oa->o_gid. In case of quota enabled, we use 
-         * them to build the lvfs_ucred so as to enforce oss quota check */
-        rc = filter_quota_enforcement(obd, oa->o_uid, oa->o_gid, &uc);
-        if (rc)
-                GOTO(cleanup, rc);
-
-        push_ctxt(&saved, &obd->obd_lvfs_ctxt, uc);
+        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
         cleanup_phase = 2;
 
         down(&inode->i_sem);
@@ -609,7 +612,7 @@ int filter_commitrw_write(struct obd_export *exp, struct obdo *oa,
         else
                 obdo_from_inode(oa, inode, OBD_MD_FLUID | OBD_MD_FLGID);
 
-        filter_get_quota_flag(obd, oa);
+        lquota_getflag(quota_interface, obd, oa);
 
         fsfilt_check_slow(now, obd_timeout, "direct_io");
 
@@ -629,9 +632,7 @@ cleanup:
 
         switch (cleanup_phase) {
         case 2:
-                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, uc);
-                if (uc)
-                        OBD_FREE(uc, sizeof(*uc));
+                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
                 LASSERT(current->journal_info == NULL);
         case 1:
                 filter_iobuf_put(dreq);
@@ -644,11 +645,12 @@ cleanup:
         }
 
         /* trigger quota pre-acquire */
-        if (rc == 0) {
-                err = qctxt_adjust_qunit(obd, &filter->fo_quota_ctxt, 
-                                         oa->o_uid, oa->o_gid, 1);
-                if (err)
-                        CERROR("error filter ajust qunit! (rc:%d)\n", err);
-        }
+        qcids[USRQUOTA] = oa->o_uid;
+        qcids[GRPQUOTA] = oa->o_gid;
+        err = lquota_adjust(quota_interface, obd, qcids, NULL, rc,
+                            FSFILT_OP_CREATE); 
+        CDEBUG(err ? D_ERROR : D_QUOTA,
+               "error filter adjust qunit! (rc:%d)\n", err);
+
         RETURN(rc);
 }
index 87a2e2a..390a293 100644 (file)
@@ -116,8 +116,7 @@ void filter_cancel_cookies_cb(struct obd_device *obd, __u64 transno,
 }
 
 /* Callback for processing the unlink log record received from MDS by 
- * llog_client_api.
- */
+ * llog_client_api. */
 static int filter_recov_log_unlink_cb(struct llog_ctxt *ctxt,
                                       struct llog_rec_hdr *rec,
                                       struct llog_cookie *cookie)
@@ -155,8 +154,7 @@ static int filter_recov_log_unlink_cb(struct llog_ctxt *ctxt,
 }
 
 /* Callback for processing the setattr log record received from MDS by
- * llog_client_api.
- */
+ * llog_client_api. */
 static int filter_recov_log_setattr_cb(struct llog_ctxt *ctxt,
                                        struct llog_rec_hdr *rec,
                                        struct llog_cookie *cookie)
index 397009e..88da264 100644 (file)
@@ -120,6 +120,123 @@ int lprocfs_filter_wr_readcache(struct file *file, const char *buffer,
         return count;
 }
 
+#ifdef HAVE_QUOTA_SUPPORT
+static int lprocfs_filter_rd_bunit(char *page, char **start, off_t off, int count, 
+                                   int *eof, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        LASSERT(obd != NULL);
+
+        return snprintf(page, count, "%lu\n", 
+                        obd->u.obt.obt_qctxt.lqc_bunit_sz);
+}
+
+static int lprocfs_filter_rd_iunit(char *page, char **start, off_t off, int count, 
+                                   int *eof, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        LASSERT(obd != NULL);
+
+        return snprintf(page, count, "%lu\n", 
+                        obd->u.obt.obt_qctxt.lqc_iunit_sz);
+}
+
+static int lprocfs_filter_wr_bunit(struct file *file, const char *buffer,
+                                   unsigned long count, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        int val, rc;
+        LASSERT(obd != NULL);
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+
+        if (val % QUOTABLOCK_SIZE ||
+            val <= obd->u.obt.obt_qctxt.lqc_btune_sz)
+                return -EINVAL;
+
+        obd->u.obt.obt_qctxt.lqc_bunit_sz = val;
+        return count;
+}
+
+static int lprocfs_filter_wr_iunit(struct file *file, const char *buffer,
+                                   unsigned long count, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        int val, rc;
+        LASSERT(obd != NULL);
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+
+        if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz)
+                return -EINVAL;
+
+        obd->u.obt.obt_qctxt.lqc_iunit_sz = val;
+        return count;
+}
+
+static int lprocfs_filter_rd_btune(char *page, char **start, off_t off, int count, 
+                                   int *eof, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        LASSERT(obd != NULL);
+
+        return snprintf(page, count, "%lu\n", 
+                        obd->u.obt.obt_qctxt.lqc_btune_sz);
+}
+
+static int lprocfs_filter_rd_itune(char *page, char **start, off_t off, int count, 
+                                   int *eof, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        LASSERT(obd != NULL);
+
+        return snprintf(page, count, "%lu\n", 
+                        obd->u.obt.obt_qctxt.lqc_itune_sz);
+}
+
+static int lprocfs_filter_wr_btune(struct file *file, const char *buffer,
+                                   unsigned long count, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        int val, rc;
+        LASSERT(obd != NULL);
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+        
+        if (val <= QUOTABLOCK_SIZE * MIN_QLIMIT || val % QUOTABLOCK_SIZE || 
+            val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
+                return -EINVAL;
+
+        obd->u.obt.obt_qctxt.lqc_btune_sz = val;
+        return count;
+}
+
+static int lprocfs_filter_wr_itune(struct file *file, const char *buffer,
+                                   unsigned long count, void *data)
+{
+        struct obd_device *obd = (struct obd_device *)data;
+        int val, rc;
+        LASSERT(obd != NULL);
+
+        rc = lprocfs_write_helper(buffer, count, &val);
+        if (rc)
+                return rc;
+        
+        if (val <= MIN_QLIMIT || 
+            val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
+                return -EINVAL;
+
+        obd->u.obt.obt_qctxt.lqc_itune_sz = val;
+        return count;
+}
+#endif
+
 static struct lprocfs_vars lprocfs_obd_vars[] = {
         { "uuid",         lprocfs_rd_uuid,          0, 0 },
         { "blocksize",    lprocfs_rd_blksize,       0, 0 },
@@ -151,7 +268,6 @@ static struct lprocfs_vars lprocfs_obd_vars[] = {
         { "quota_itune_sz", lprocfs_filter_rd_itune,
                             lprocfs_filter_wr_itune, 0},
 #endif
-
         { 0 }
 };
 
index 6c6d385..82db660 100644 (file)
@@ -57,55 +57,9 @@ int osc_real_create(struct obd_export *exp, struct obdo *oa,
 void oscc_init(struct obd_device *obd);
 void osc_wake_cache_waiters(struct client_obd *cli);
 
-#ifdef HAVE_QUOTA_SUPPORT
-int osc_get_quota_flag(struct client_obd *cli, unsigned int uid,
-                       unsigned int gid);
-int osc_set_quota_flag(struct client_obd *cli,
-                       unsigned int uid, unsigned int gid,
-                       obd_flag valid, obd_flag flags);
-int osc_qinfo_cleanup(struct client_obd *cli);
-int osc_qinfo_init(void);
-void osc_qinfo_exit(void);
-int osc_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl);
-int osc_poll_quotacheck(struct obd_export *exp, struct if_quotacheck *qchk);
-int osc_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl);
-#else /* !HAVE_QUOTA_SUPPORT */
-static inline int osc_get_quota_flag(struct client_obd *cli,
-                                     unsigned int uid, unsigned int gid)
-{
-       return QUOTA_OK;
-}
-static inline int osc_set_quota_flag(struct client_obd *cli,
-                                     unsigned int uid, unsigned int gid,
-                                     obd_flag valid, obd_flag flags)
-{
-        return 0;
-}
-static inline int osc_qinfo_cleanup(struct client_obd *cli)
-{
-        return 0;
-}
-static inline int osc_qinfo_init(void)
-{
-        return 0;
-}
-static inline void osc_qinfo_exit(void) {}
-static inline int osc_quotacheck(struct obd_export *exp,
-                                 struct obd_quotactl *oqctl)
-{
-        return -ENOTSUPP;
-}
-static inline int osc_poll_quotacheck(struct obd_export *exp,
-                                      struct if_quotacheck *qchk)
-{
-        return -ENOTSUPP;
-}
-static inline int osc_quotactl(struct obd_export *exp,
-                               struct obd_quotactl *oqctl)
-{
-        return -ENOTSUPP;
-}
-#endif /* HAVE_QUOTA_SUPPORT */
+
+/* Quota stuff */
+extern quota_interface_t *quota_interface;
 
 #ifdef LPROCFS
 int lproc_osc_attach_seqstat(struct obd_device *dev);
diff --git a/lustre/osc/osc_quota.c b/lustre/osc/osc_quota.c
deleted file mode 100644 (file)
index 60446b2..0000000
+++ /dev/null
@@ -1,326 +0,0 @@
-/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
- * vim:expandtab:shiftwidth=8:tabstop=8:
- *
- *  Copyright (c) 2003 Cluster File Systems, Inc.
- *
- *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
- *
- */
-
-#ifndef EXPORT_SYMTAB
-# define EXPORT_SYMTAB
-#endif
-#define DEBUG_SUBSYSTEM S_OSC
-
-#ifdef __KERNEL__
-# include <linux/module.h>
-# include <linux/obd_ost.h>
-# include <linux/lustre_net.h>
-# include <linux/lustre_dlm.h>
-# include <linux/lustre_lib.h>
-# include <linux/lustre_compat25.h>
-# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
-#  include <linux/workqueue.h>
-#  include <linux/smp_lock.h>
-# else
-#  include <linux/locks.h>
-# endif
-#else
-# include <liblustre.h>
-#endif
-
-#include <linux/obd.h>
-#include "osc_internal.h"
-
-struct osc_quota_info {
-        struct list_head        oqi_hash;       /* hash list */
-        struct client_obd      *oqi_cli;        /* osc obd */ 
-        unsigned int            oqi_id;         /* uid/gid of a file */
-        short                   oqi_type;       /* quota type */
-        unsigned long           oqi_flag;       /* flag, NO_QUOTA */
-};
-
-spinlock_t qinfo_list_lock = SPIN_LOCK_UNLOCKED;
-
-static struct list_head qinfo_hash[NR_DQHASH];
-/* SLAB cache for client quota context */
-kmem_cache_t *qinfo_cachep = NULL;
-
-static inline int const hashfn(struct client_obd *cli, 
-                               unsigned long id, 
-                               int type)
-{
-        unsigned long tmp = ((unsigned long)cli>>6) ^ id;
-        tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
-        return tmp;
-}
-
-static inline void insert_qinfo_hash(struct osc_quota_info *oqi)
-{
-        struct list_head *head = qinfo_hash + 
-                hashfn(oqi->oqi_cli, oqi->oqi_id, oqi->oqi_type);
-        list_add(&oqi->oqi_hash, head);
-}
-
-static inline void remove_qinfo_hash(struct osc_quota_info *oqi)
-{
-        list_del_init(&oqi->oqi_hash);
-}
-
-static inline struct osc_quota_info *find_qinfo(struct client_obd *cli,
-                                                unsigned int id, int type)
-{
-        unsigned int hashent = hashfn(cli, id, type);
-        struct list_head *head;
-        struct osc_quota_info *oqi;
-
-        for (head = qinfo_hash[hashent].next;
-             head != qinfo_hash+hashent; head = head->next) {
-                oqi = list_entry(head, struct osc_quota_info, oqi_hash);
-                LASSERT(oqi->oqi_flag == NO_QUOTA);
-                if (oqi->oqi_cli == cli &&
-                    oqi->oqi_id == id && oqi->oqi_type == type)
-                        return oqi;
-        }
-        return NULL;
-}
-
-static struct osc_quota_info *alloc_qinfo(struct client_obd *cli,
-                                          unsigned int id, int type)
-{
-        struct osc_quota_info *oqi;
-        ENTRY;
-
-        OBD_SLAB_ALLOC(oqi, qinfo_cachep, SLAB_KERNEL, sizeof(*oqi));
-        if(!oqi)
-                RETURN(NULL);
-
-        INIT_LIST_HEAD(&oqi->oqi_hash);
-        oqi->oqi_cli = cli;
-        oqi->oqi_id = id;
-        oqi->oqi_type = type;
-
-        RETURN(oqi);
-}
-
-static void free_qinfo(struct osc_quota_info *oqi)
-{
-        OBD_SLAB_FREE(oqi, qinfo_cachep, sizeof(*oqi));
-}
-
-int osc_get_quota_flag(struct client_obd *cli, 
-                       unsigned int uid, unsigned int gid)
-{
-        unsigned int id;
-        int cnt, rc = QUOTA_OK;
-        ENTRY;
-
-        spin_lock(&qinfo_list_lock);
-        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-                struct osc_quota_info *oqi = NULL;
-
-                id = (cnt == USRQUOTA) ? uid : gid;
-                oqi = find_qinfo(cli, id, cnt);
-                if (oqi) {
-                        rc = NO_QUOTA;
-                        break;
-                }
-        }
-        spin_unlock(&qinfo_list_lock);
-
-        RETURN(rc);
-}
-
-int osc_set_quota_flag(struct client_obd *cli, 
-                       unsigned int uid, unsigned int gid,
-                       obd_flag valid, obd_flag flags)
-{
-        unsigned int id;
-        obd_flag noquota;
-        int cnt, rc = 0;
-        ENTRY;
-
-        spin_lock(&qinfo_list_lock);
-
-        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
-                struct osc_quota_info *oqi = NULL;
-
-                if (!(valid & ((cnt == USRQUOTA) ? 
-                    OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA)))
-                        continue; 
-
-                id = (cnt == USRQUOTA) ? uid : gid;
-                noquota = (cnt == USRQUOTA) ? 
-                    (flags & OBD_FL_NO_USRQUOTA) : (flags & OBD_FL_NO_GRPQUOTA);
-                
-                oqi = find_qinfo(cli, id, cnt);
-                
-                if (oqi && !noquota) {
-                        remove_qinfo_hash(oqi);
-                        free_qinfo(oqi);
-                } else if (!oqi && noquota) {
-                        oqi = alloc_qinfo(cli, id, cnt);
-                        if (!oqi) {
-                                CERROR("not enough mem!\n");
-                                rc = -ENOMEM;
-                                break;
-                        }
-                        oqi->oqi_flag = NO_QUOTA;
-                        insert_qinfo_hash(oqi);
-                }
-        }
-
-        spin_unlock(&qinfo_list_lock);
-
-        RETURN(rc);
-}
-
-int osc_qinfo_cleanup(struct client_obd *cli)
-{
-        struct osc_quota_info *oqi, *n;
-        int i;
-        ENTRY;
-
-        spin_lock(&qinfo_list_lock);
-        for (i = 0; i < NR_DQHASH; i++) {
-                list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
-                        if (oqi->oqi_cli != cli)
-                                continue;
-                        remove_qinfo_hash(oqi);
-                        free_qinfo(oqi);
-                }
-        }
-        spin_unlock(&qinfo_list_lock);
-
-        RETURN(0);
-}
-
-int osc_qinfo_init(void)
-{
-        int i;
-        ENTRY;
-
-        LASSERT(qinfo_cachep == NULL);
-        qinfo_cachep = kmem_cache_create("osc_quota_info",
-                                         sizeof(struct osc_quota_info),
-                                         0, 0, NULL, NULL);
-        if (!qinfo_cachep)
-                RETURN(-ENOMEM);
-
-        for (i = 0; i < NR_DQHASH; i++)
-                INIT_LIST_HEAD(qinfo_hash + i);
-
-        RETURN(0);        
-}
-
-void osc_qinfo_exit(void)
-{
-        struct osc_quota_info *oqi, *n;
-        int i;
-        ENTRY;
-                                                                                                                             
-        spin_lock(&qinfo_list_lock);
-        for (i = 0; i < NR_DQHASH; i++) {
-                list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
-                        remove_qinfo_hash(oqi);
-                        free_qinfo(oqi);
-                }
-        }
-        spin_unlock(&qinfo_list_lock);
-        
-        LASSERTF(kmem_cache_destroy(qinfo_cachep) == 0,
-                 "couldn't destroy osc quota info slab\n"); 
-}
-
-int osc_quotacheck(struct obd_export *exp, struct obd_quotactl *oqctl)
-{
-        struct client_obd *cli = &exp->exp_obd->u.cli;
-        struct ptlrpc_request *req;
-        struct obd_quotactl *body;
-        int size = sizeof(*body);
-        int rc;
-        ENTRY;
-
-        req = ptlrpc_prep_req(class_exp2cliimp(exp), OST_QUOTACHECK, 1, &size,
-                              NULL);
-        if (!req)
-                GOTO(out, rc = -ENOMEM);
-
-        body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*body));
-        memcpy(body, oqctl, sizeof(*body));
-
-        req->rq_replen = lustre_msg_size(0, NULL);
-
-        spin_lock(&cli->cl_qchk_lock);
-        cli->cl_qchk_stat = CL_QUOTACHECKING;
-        spin_unlock(&cli->cl_qchk_lock);
-
-        rc = ptlrpc_queue_wait(req);
-        if (rc) {
-                spin_lock(&cli->cl_qchk_lock);
-                cli->cl_qchk_stat = rc;
-                spin_unlock(&cli->cl_qchk_lock);
-        }
- out:
-        ptlrpc_req_finished(req);
-        RETURN (rc);
-}
-
-int osc_poll_quotacheck(struct obd_export *exp,
-                                  struct if_quotacheck *qchk)
-{
-        struct client_obd *cli = &exp->exp_obd->u.cli;
-        int stat;
-        ENTRY;
-                                                                                                                 
-        spin_lock(&cli->cl_qchk_lock);
-        stat = cli->cl_qchk_stat;
-        spin_unlock(&cli->cl_qchk_lock);
-                                                                                                                 
-        qchk->stat = stat;
-        if (stat == CL_QUOTACHECKING) {
-                qchk->stat = -ENODATA;
-                stat = 0;
-        } else if (qchk->stat) {
-                if (qchk->stat > CL_QUOTACHECKING)
-                        qchk->stat = stat = -EINTR;
-                                                                                                                 
-                strncpy(qchk->obd_type, "obdfilter", 10);
-                qchk->obd_uuid = cli->cl_import->imp_target_uuid;
-        }
-        RETURN(stat);
-}
-
-int osc_quotactl(struct obd_export *exp, struct obd_quotactl *oqctl)
-{
-        struct ptlrpc_request *req;
-        struct obd_quotactl *oqc;
-        int size = sizeof(*oqctl);
-        int rc;
-        ENTRY;
-
-        req = ptlrpc_prep_req(class_exp2cliimp(exp), OST_QUOTACTL, 1, &size,
-                              NULL);
-        if (!req)
-                GOTO(out, rc = -ENOMEM);
-
-        memcpy(lustre_msg_buf(req->rq_reqmsg, 0, sizeof (*oqctl)), oqctl, size);
-
-        req->rq_replen = lustre_msg_size(1, &size);
-
-        rc = ptlrpc_queue_wait(req);
-        if (!rc) {
-                oqc = lustre_swab_repbuf(req, 0, sizeof (*oqc),
-                                         lustre_swab_obd_quotactl);
-                if (oqc == NULL) {
-                        CERROR ("Can't unpack mds_body\n");
-                        GOTO(out, rc = -EPROTO);
-                }
-
-                memcpy(oqctl, oqc, sizeof(*oqctl));
-        }
-out:
-        ptlrpc_req_finished(req);
-        RETURN (rc);
-}
-
index 5996720..f83f25f 100644 (file)
@@ -938,8 +938,9 @@ static int osc_brw_fini_request(struct ptlrpc_request *req, struct obdo *oa,
         /* set/clear over quota flag for a uid/gid */
         if (req->rq_reqmsg->opc == OST_WRITE &&
             body->oa.o_valid & (OBD_MD_FLUSRQUOTA | OBD_MD_FLGRPQUOTA))
-                osc_set_quota_flag(cli, body->oa.o_uid, body->oa.o_gid,
-                                   body->oa.o_valid, body->oa.o_flags);
+                lquota_setdq(quota_interface, cli, body->oa.o_uid,
+                             body->oa.o_gid, body->oa.o_valid,
+                             body->oa.o_flags);
 
         if (rc < 0)
                 RETURN(rc);
@@ -2045,7 +2046,8 @@ static int osc_queue_async_io(struct obd_export *exp, struct lov_stripe_md *lsm,
 
                 ops = oap->oap_caller_ops;
                 ops->ap_fill_obdo(oap->oap_caller_data, cmd, oa);
-                if (osc_get_quota_flag(cli, oa->o_uid, oa->o_gid) == NO_QUOTA)
+                if (lquota_chkdq(quota_interface, cli, oa->o_uid, oa->o_gid) ==
+                    NO_QUOTA)
                         rc = -EDQUOT;
 
                 obdo_free(oa);
@@ -2874,6 +2876,7 @@ static int osc_getstripe(struct lov_stripe_md *lsm, struct lov_user_md *lump)
         RETURN(rc);
 }
 
+
 static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
                          void *karg, void *uarg)
 {
@@ -2949,7 +2952,8 @@ static int osc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
                                                data->ioc_offset);
                 GOTO(out, err);
         case OBD_IOC_POLL_QUOTACHECK:
-                err = osc_poll_quotacheck(exp, (struct if_quotacheck *)karg);
+                err = lquota_poll_check(quota_interface, exp,
+                                        (struct if_quotacheck *)karg);
                 GOTO(out, err);
         default:
                 CDEBUG(D_INODE, "unrecognised ioctl %#x by %s\n",
@@ -3264,7 +3268,7 @@ int osc_cleanup(struct obd_device *obd)
         spin_unlock(&oscc->oscc_lock);
 
         /* free memory of osc quota cache */
-        osc_qinfo_cleanup(cli);
+        lquota_cleanup(quota_interface, obd);
 
         ptlrpc_free_rq_pool(cli->cl_rq_pool);
 
@@ -3314,8 +3318,6 @@ struct obd_ops osc_obd_ops = {
         .o_import_event         = osc_import_event,
         .o_llog_init            = osc_llog_init,
         .o_llog_finish          = osc_llog_finish,
-        .o_quotacheck           = osc_quotacheck,
-        .o_quotactl             = osc_quotactl,
 };
 
 #if defined(__KERNEL__) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
@@ -3351,6 +3353,9 @@ struct obd_ops sanosc_obd_ops = {
 };
 #endif
 
+static quota_interface_t *quota_interface = NULL;
+extern quota_interface_t osc_quota_interface;
+
 int __init osc_init(void)
 {
         struct lprocfs_static_vars lvars;
@@ -3365,27 +3370,39 @@ int __init osc_init(void)
         lprocfs_init_vars(osc, &sanlvars);
 #endif
 
+        quota_interface = PORTAL_SYMBOL_GET(osc_quota_interface);
+        lquota_init(quota_interface);
+        init_obd_quota_ops(quota_interface, &osc_obd_ops);
+
         rc = class_register_type(&osc_obd_ops, lvars.module_vars,
                                  LUSTRE_OSC_NAME);
-        if (rc)
+        if (rc) {
+                if (quota_interface)
+                        PORTAL_SYMBOL_PUT(osc_quota_interface);
                 RETURN(rc);
+        }
 
 #if defined(__KERNEL__) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
         rc = class_register_type(&sanosc_obd_ops, sanlvars.module_vars,
                                  LUSTRE_SANOSC_NAME);
-        if (rc)
+        if (rc) {
                 class_unregister_type(LUSTRE_OSC_NAME);
+                if (quota_interface)
+                        PORTAL_SYMBOL_PUT(osc_quota_interface);
+                RETURN(rc);
+        }
 #endif
 
-        rc = osc_qinfo_init();
-
         RETURN(rc);
 }
 
 #ifdef __KERNEL__
 static void /*__exit*/ osc_exit(void)
 {
-        osc_qinfo_exit();
+        lquota_exit(quota_interface);
+        if (quota_interface)
+                PORTAL_SYMBOL_PUT(osc_quota_interface);
+
 #if defined(__KERNEL__) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
         class_unregister_type(LUSTRE_SANOSC_NAME);
 #endif
index cc54ac0..3c534d0 100644 (file)
@@ -1075,6 +1075,50 @@ static int ost_get_info(struct obd_export *exp, struct ptlrpc_request *req)
         RETURN(rc);
 }
 
+static int ost_handle_quotactl(struct ptlrpc_request *req)
+{
+        struct obd_quotactl *oqctl, *repoqc;
+        int rc, size = sizeof(*repoqc);
+        ENTRY;
+
+        oqctl = lustre_swab_reqbuf(req, 0, sizeof(*oqctl),
+                                   lustre_swab_obd_quotactl);
+        if (oqctl == NULL)
+                GOTO(out, rc = -EPROTO);
+
+        rc = lustre_pack_reply(req, 1, &size, NULL);
+        if (rc)
+                GOTO(out, rc);
+
+        repoqc = lustre_msg_buf(req->rq_repmsg, 0, sizeof(*repoqc));
+
+        req->rq_status = obd_quotactl(req->rq_export, oqctl);
+        *repoqc = *oqctl;
+out:
+        RETURN(rc);
+}
+
+static int ost_handle_quotacheck(struct ptlrpc_request *req)
+{
+        struct obd_quotactl *oqctl;
+        int rc;
+        ENTRY;
+
+        oqctl = lustre_swab_reqbuf(req, 0, sizeof(*oqctl),
+                                   lustre_swab_obd_quotactl);
+        if (oqctl == NULL) 
+                RETURN(-EPROTO);
+
+        rc = lustre_pack_reply(req, 0, NULL, NULL);
+        if (rc) {
+                CERROR("ost: out of memory while packing quotacheck reply\n");
+                RETURN(-ENOMEM);
+        }
+
+        req->rq_status = obd_quotacheck(req->rq_export, oqctl);
+        RETURN(0);
+}
+
 static int ost_filter_recovery_request(struct ptlrpc_request *req,
                                        struct obd_device *obd, int *process)
 {
@@ -1242,12 +1286,12 @@ static int ost_handle(struct ptlrpc_request *req)
         case OST_QUOTACHECK:
                 CDEBUG(D_INODE, "quotacheck\n");
                 OBD_FAIL_RETURN(OBD_FAIL_OST_QUOTACHECK_NET, 0);
-                rc = ost_quotacheck(req);
+                rc = ost_handle_quotacheck(req);
                 break;
         case OST_QUOTACTL:
                 CDEBUG(D_INODE, "quotactl\n");
                 OBD_FAIL_RETURN(OBD_FAIL_OST_QUOTACTL_NET, 0);
-                rc = ost_quotactl(req);
+                rc = ost_handle_quotactl(req);
                 break;
         case OBD_PING:
                 DEBUG_REQ(D_INODE, req, "ping");
@@ -1516,14 +1560,17 @@ static struct obd_ops ost_obd_ops = {
         .o_health_check = ost_health_check,
 };
 
+
 static int __init ost_init(void)
 {
         struct lprocfs_static_vars lvars;
+        int rc;
         ENTRY;
 
         lprocfs_init_vars(ost,&lvars);
-        RETURN(class_register_type(&ost_obd_ops, lvars.module_vars,
-                                   LUSTRE_OST_NAME));
+        rc = class_register_type(&ost_obd_ops, lvars.module_vars,
+                                 LUSTRE_OST_NAME);
+        RETURN(rc);
 }
 
 static void /*__exit*/ ost_exit(void)
index 9c7fecc..51ae8c9 100644 (file)
@@ -45,21 +45,7 @@ struct ost_thread_local_cache {
 
 struct ost_thread_local_cache *ost_tls(struct ptlrpc_request *r);
 
-#ifdef HAVE_QUOTA_SUPPORT
 /* Quota stuff */
-int ost_quotacheck(struct ptlrpc_request *req);
-int ost_quotactl(struct ptlrpc_request *req);
-#else
-static inline int ost_quotacheck(struct ptlrpc_request *req)
-{
-        req->rq_status = -ENOTSUPP;
-        return -ENOTSUPP;
-}
-static inline int ost_quotactl(struct ptlrpc_request *req)
-{
-        req->rq_status = -ENOTSUPP;
-        return -ENOTSUPP;
-}
-#endif
+extern quota_interface_t *quota_interface;
 
 #endif /* OST_INTERNAL_H */
index ac1a021..244925b 100644 (file)
@@ -16,10 +16,6 @@ ptlrpc_objs += pers.o lproc_ptlrpc.o
 
 ptlrpc-objs := $(ldlm_objs) $(ptlrpc_objs)
 
-ifeq ($(PATCHLEVEL),6)
-#ptlrpc-objs += @top_srcdir@/lustre/mds/quota_context.o
-endif
-
 default: all
 
 ldlm_%.c: @LUSTRE@/ldlm/ldlm_%.c
index 0e08bb6..bdd8dbb 100644 (file)
@@ -74,7 +74,7 @@ int llog_origin_connect(struct llog_ctxt *ctxt, int count,
         lgr->lgr_hdr.lrh_len = lgr->lgr_tail.lrt_len = sizeof(*lgr);
         lgr->lgr_hdr.lrh_type = LLOG_GEN_REC;
         lgr->lgr_gen = ctxt->loc_gen;
-        rc = llog_add(ctxt, &lgr->lgr_hdr, NULL, NULL, 1, NULL);
+        rc = llog_add(ctxt, &lgr->lgr_hdr, NULL, NULL, 1);
         OBD_FREE(lgr, sizeof(*lgr));
         if (rc != 1)
                 RETURN(rc);
diff --git a/lustre/quota/.cvsignore b/lustre/quota/.cvsignore
new file mode 100644 (file)
index 0000000..d5103fa
--- /dev/null
@@ -0,0 +1,15 @@
+.Xrefs
+config.log
+config.status
+configure
+Makefile
+.deps
+TAGS
+.*.cmd
+autoMakefile.in
+autoMakefile
+*.ko
+*.mod.c
+.*.o.flags
+.tmp_versions
+.depend
diff --git a/lustre/quota/Makefile.in b/lustre/quota/Makefile.in
new file mode 100644 (file)
index 0000000..19a37ca
--- /dev/null
@@ -0,0 +1,10 @@
+MODULES := lquota
+MODULES += quotactl_test quotacheck_test
+
+lquota-objs := quota_check.o quota_context.o quota_ctl.o quota_interface.o
+lquota-objs += quota_master.o
+quotactl-objs := quotactl_test.o
+quotaccheck-objs := quotacheck_test.o
+
+@INCLUDE_RULES@
+
diff --git a/lustre/quota/autoMakefile.am b/lustre/quota/autoMakefile.am
new file mode 100644 (file)
index 0000000..c23c370
--- /dev/null
@@ -0,0 +1,19 @@
+# Copyright (C) 2005  Cluster File Systems, Inc.
+#
+# This code is issued under the GNU General Public License.
+# See the file COPYING in this distribution
+
+if LIBLUSTRE
+noinst_LIBRARIES = libquota.a
+libquota_a_SOURCES = quota_check.c quota_ctl.c quota_interface.c
+libquota_a_CPPFLAGS = $(LLCPPFLAGS)
+libquota_a_CFLAGS = $(LLCFLAGS)
+endif
+
+if MODULES
+modulefs_DATA = lquota$(KMODEXT)
+endif
+
+MOSTLYCLEANFILES := @MOSTLYCLEANFILES@ 
+DIST_SOURCES := $(lquota-objs:%.o=%.c) quota_internal.h
+DIST_SOURCES += quotactl_test.c quotacheck_test.c
diff --git a/lustre/quota/quota_check.c b/lustre/quota/quota_check.c
new file mode 100644 (file)
index 0000000..55a33a6
--- /dev/null
@@ -0,0 +1,245 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  lustre/quota/quota_check.c
+ *
+ *  Copyright (c) 2005 Cluster File Systems, Inc.
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
+ *
+ */
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+#define DEBUG_SUBSYSTEM S_MDS
+
+#ifdef __KERNEL__
+# include <linux/version.h>
+# include <linux/module.h>
+# include <linux/init.h>
+# include <linux/fs.h>
+# include <linux/jbd.h>
+# include <linux/ext3_fs.h>
+# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+#  include <linux/smp_lock.h>
+#  include <linux/buffer_head.h>
+#  include <linux/workqueue.h>
+#  include <linux/mount.h>
+# else
+#  include <linux/locks.h>
+# endif
+#else /* __KERNEL__ */
+# include <liblustre.h>
+#endif
+
+#include <linux/obd_class.h>
+#include <linux/lustre_mds.h>
+#include <linux/lustre_dlm.h>
+#include <linux/lustre_cfg.h>
+#include <linux/obd_ost.h>
+#include <linux/lustre_fsfilt.h>
+#include <linux/lustre_quota.h>
+#include "quota_internal.h"
+
+#ifdef __KERNEL__
+static int target_quotacheck_callback(struct obd_export *exp,
+                                      struct obd_quotactl *oqctl)
+{
+        struct ptlrpc_request *req;
+        struct obd_quotactl *body;
+        int rc, size = sizeof(*oqctl);
+        ENTRY;
+
+        req = ptlrpc_prep_req(exp->exp_imp_reverse, OBD_QC_CALLBACK,
+                              1, &size, NULL);
+        if (!req)
+                RETURN(-ENOMEM);
+
+        body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*body));
+        *body = *oqctl;
+
+        req->rq_replen = lustre_msg_size(0, NULL);
+
+        rc = ptlrpc_queue_wait(req);
+        ptlrpc_req_finished(req);
+
+        RETURN(rc);
+}
+
+static int target_quotacheck_thread(void *data)
+{
+        unsigned long flags;
+        struct quotacheck_thread_args *qta = data;
+        struct obd_export *exp;
+        struct obd_device *obd;
+        struct obd_quotactl *oqctl;
+        struct lvfs_run_ctxt saved;
+        int rc;
+
+        lock_kernel();
+        ptlrpc_daemonize();
+
+        SIGNAL_MASK_LOCK(current, flags);
+        sigfillset(&current->blocked);
+        RECALC_SIGPENDING;
+        SIGNAL_MASK_UNLOCK(current, flags);
+
+        THREAD_NAME(cfs_curproc_comm(), CFS_CURPROC_COMM_MAX, "%s",
+                    "quotacheck");
+        unlock_kernel();
+
+        exp = qta->qta_exp;
+        obd = exp->exp_obd;
+        oqctl = &qta->qta_oqctl;
+
+        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+        rc = fsfilt_quotacheck(obd, qta->qta_sb, oqctl);
+        if (rc)
+                CERROR("%s: fsfilt_quotacheck: %d\n", obd->obd_name, rc);
+
+        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+        rc = target_quotacheck_callback(exp, oqctl);
+
+        atomic_inc(qta->qta_sem);
+
+        OBD_FREE_PTR(qta);
+        return rc;
+}
+
+int target_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+        struct obd_device *obd = exp->exp_obd;
+        struct obd_device_target *obt = &obd->u.obt;
+        struct quotacheck_thread_args *qta;
+        int rc = 0;
+        ENTRY;
+
+        if (!atomic_dec_and_test(&obt->obt_quotachecking)) {
+                CDEBUG(D_INFO, "other people are doing quotacheck\n");
+                GOTO(out, rc = -EBUSY);
+        }
+
+        OBD_ALLOC_PTR(qta);
+        if (!qta)
+                GOTO(out, rc = -ENOMEM);
+
+        qta->qta_exp = exp;
+        qta->qta_oqctl = *oqctl;
+        qta->qta_sb = obt->obt_sb;
+        qta->qta_sem = &obt->obt_quotachecking;
+
+        if (!strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME)) {
+                /* quota master */
+                rc = init_admin_quotafiles(obd, &qta->qta_oqctl);
+                if (rc) {
+                        CERROR("init_admin_quotafiles failed: %d\n", rc);
+                        OBD_FREE_PTR(qta);
+                        GOTO(out, rc);
+                }
+        }
+
+        rc = kernel_thread(target_quotacheck_thread, qta, CLONE_VM|CLONE_FILES);
+        if (rc >= 0) {
+                CDEBUG(D_INFO, "%s: target_quotacheck_thread: %d\n",
+                       obd->obd_name, rc);
+                RETURN(0);
+        }
+
+        CERROR("%s: error starting quotacheck_thread: %d\n",
+               obd->obd_name, rc);
+        OBD_FREE_PTR(qta);
+out:
+        atomic_inc(&obt->obt_quotachecking);
+        RETURN(rc);
+}
+
+#endif /* __KERNEL__ */
+
+int client_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+        struct client_obd *cli = &exp->exp_obd->u.cli;
+        struct ptlrpc_request *req;
+        struct obd_quotactl *body;
+        int size = sizeof(*body), opc;
+        int rc;
+        ENTRY;
+
+        if (!strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_MDC_NAME))
+                opc = MDS_QUOTACHECK;
+        else if (!strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME))
+                opc = OST_QUOTACHECK;
+        else
+                RETURN(-EINVAL);
+
+        req = ptlrpc_prep_req(class_exp2cliimp(exp), opc, 1, &size,
+                              NULL);
+        if (!req)
+                GOTO(out, rc = -ENOMEM);
+
+        body = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*body));
+        *body = *oqctl;
+
+        req->rq_replen = lustre_msg_size(0, NULL);
+
+        /* the next poll will find -ENODATA, that means quotacheck is
+         * going on */
+        cli->cl_qchk_stat = -ENODATA;
+        rc = ptlrpc_queue_wait(req);
+        if (rc)
+                cli->cl_qchk_stat = rc;
+out:
+        ptlrpc_req_finished(req);
+        RETURN(rc);
+}
+
+int client_quota_poll_check(struct obd_export *exp, struct if_quotacheck *qchk)
+{
+        struct client_obd *cli = &exp->exp_obd->u.cli;
+        int rc;
+        ENTRY;
+
+        rc = cli->cl_qchk_stat;
+
+        /* the client is not the previous one */
+        if (rc == CL_NOT_QUOTACHECKED)
+                rc = -EINTR;
+
+        qchk->obd_uuid = cli->cl_import->imp_target_uuid;
+        if (strncmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME,
+            strlen(LUSTRE_OSC_NAME)))
+                memcpy(qchk->obd_type, LUSTRE_FILTER_NAME,
+                       strlen(LUSTRE_FILTER_NAME));
+        else if (strncmp(exp->exp_obd->obd_type->typ_name, LUSTRE_MDC_NAME,
+                 strlen(LUSTRE_MDC_NAME)))
+                memcpy(qchk->obd_type, LUSTRE_MDS_NAME,
+                       strlen(LUSTRE_MDS_NAME));
+
+        RETURN(rc);
+}
+
+int lov_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+        struct obd_device *obd = class_exp2obd(exp);
+        struct lov_obd *lov = &obd->u.lov;
+        int i, rc = 0;
+        ENTRY;
+
+        for (i = 0; i < lov->desc.ld_tgt_count; i++) {
+                int err;
+
+                if (!lov->tgts[i].active) {
+                        CERROR("lov idx %d inactive\n", i);
+                        RETURN(-EIO);
+                }
+
+                err = obd_quotacheck(lov->tgts[i].ltd_exp, oqctl);
+                if (err && lov->tgts[i].active && !rc)
+                        rc = err;
+        }
+
+        RETURN(rc);
+}
diff --git a/lustre/quota/quota_context.c b/lustre/quota/quota_context.c
new file mode 100644 (file)
index 0000000..ed1ff48
--- /dev/null
@@ -0,0 +1,797 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  lustre/quota/quota_context.c
+ *  Lustre Quota Context
+ *
+ *  Copyright (c) 2001-2005 Cluster File Systems, Inc.
+ *   Author: Niu YaWei <niu@clusterfs.com>
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
+ *
+ */
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+
+#define DEBUG_SUBSYSTEM S_MDS
+
+#include <linux/version.h>
+#include <linux/fs.h>
+#include <asm/unistd.h>
+#include <linux/slab.h>
+#include <linux/quotaops.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <linux/obd_class.h>
+#include <linux/lustre_quota.h>
+#include <linux/lustre_fsfilt.h>
+#include "quota_internal.h"
+
+unsigned long default_bunit_sz = 100 * 1024 * 1024;       /* 100M bytes */
+unsigned long default_btune_ratio = 50;                   /* 50 percentage */
+unsigned long default_iunit_sz = 5000;       /* 5000 inodes */
+unsigned long default_itune_ratio = 50;      /* 50 percentage */
+
+kmem_cache_t *qunit_cachep = NULL;
+struct list_head qunit_hash[NR_DQHASH];
+spinlock_t qunit_hash_lock = SPIN_LOCK_UNLOCKED;
+
+struct lustre_qunit {
+        struct list_head lq_hash;               /* Hash list in memory */
+        atomic_t lq_refcnt;                     /* Use count */
+        struct lustre_quota_ctxt *lq_ctxt;      /* Quota context this applies to */
+        struct qunit_data lq_data;              /* See qunit_data */
+        unsigned int lq_opc;                    /* QUOTA_DQACQ, QUOTA_DQREL */
+        struct list_head lq_waiters;            /* All write threads waiting for this qunit */
+};
+
+void qunit_cache_cleanup(void)
+{
+        int i;
+        ENTRY;
+
+        spin_lock(&qunit_hash_lock);
+        for (i = 0; i < NR_DQHASH; i++)
+                LASSERT(list_empty(qunit_hash + i));
+        spin_unlock(&qunit_hash_lock);
+
+        if (qunit_cachep) {
+                int rc;
+                rc = kmem_cache_destroy(qunit_cachep);
+                LASSERT(rc == 0);
+                qunit_cachep = NULL;
+        }
+        EXIT;
+}
+
+int qunit_cache_init(void)
+{
+        int i;
+        ENTRY;
+
+        LASSERT(qunit_cachep == NULL);
+        qunit_cachep = kmem_cache_create("ll_qunit_cache",
+                                         sizeof(struct lustre_qunit),
+                                         0, 0, NULL, NULL);
+        if (!qunit_cachep)
+                RETURN(-ENOMEM);
+
+        spin_lock(&qunit_hash_lock);
+        for (i = 0; i < NR_DQHASH; i++)
+                INIT_LIST_HEAD(qunit_hash + i);
+        spin_unlock(&qunit_hash_lock);
+        RETURN(0);
+}
+
+static inline int const
+qunit_hashfn(struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata)
+{
+        unsigned int id = qdata->qd_id;
+        unsigned int type = qdata->qd_type;
+
+        unsigned long tmp = ((unsigned long)qctxt >> L1_CACHE_SHIFT) ^ id;
+        tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
+        return tmp;
+}
+
+/* caller must hold qunit_hash_lock */
+static inline struct lustre_qunit *find_qunit(unsigned int hashent,
+                                              struct lustre_quota_ctxt *qctxt,
+                                              struct qunit_data *qdata)
+{
+        struct lustre_qunit *qunit = NULL;
+        struct qunit_data *tmp;
+
+        LASSERT_SPIN_LOCKED(&qunit_hash_lock);
+        list_for_each_entry(qunit, qunit_hash + hashent, lq_hash) {
+                tmp = &qunit->lq_data;
+                if (qunit->lq_ctxt == qctxt &&
+                    qdata->qd_id == tmp->qd_id && qdata->qd_type == tmp->qd_type
+                    && qdata->qd_isblk == tmp->qd_isblk)
+                        return qunit;
+        }
+        return NULL;
+}
+
+/* check_cur_qunit - check the current usage of qunit.
+ * @qctxt: quota context
+ * @qdata: the type of quota unit to be checked
+ *
+ * return: 1 - need acquire qunit;
+ *        2 - need release qunit;
+ *        0 - need do nothing.
+ *      < 0 - error.
+ */
+static int
+check_cur_qunit(struct obd_device *obd,
+                struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata)
+{
+        struct super_block *sb = qctxt->lqc_sb;
+        unsigned long qunit_sz, tune_sz;
+        __u64 usage, limit;
+        struct obd_quotactl *qctl;
+        int ret = 0;
+        ENTRY;
+
+        if (!sb_any_quota_enabled(sb))
+                RETURN(0);
+
+        /* ignore root user */
+        if (qdata->qd_id == 0 && qdata->qd_type == USRQUOTA)
+                RETURN(0);
+
+        OBD_ALLOC_PTR(qctl);
+        if (qctl == NULL)
+                RETURN(-ENOMEM);
+
+        /* get fs quota usage & limit */
+        qctl->qc_cmd = Q_GETQUOTA;
+        qctl->qc_id = qdata->qd_id;
+        qctl->qc_type = qdata->qd_type;
+        ret = fsfilt_quotactl(obd, sb, qctl);
+        if (ret) {
+                if (ret == -ESRCH)      /* no limit */
+                        ret = 0;
+                else
+                        CERROR("can't get fs quota usage! (rc:%d)\n", ret);
+                GOTO(out, ret);
+        }
+
+        if (qdata->qd_isblk) {
+                usage = qctl->qc_dqblk.dqb_curspace;
+                limit = qctl->qc_dqblk.dqb_bhardlimit << QUOTABLOCK_BITS;
+                qunit_sz = qctxt->lqc_bunit_sz;
+                tune_sz = qctxt->lqc_btune_sz;
+
+                LASSERT(!(qunit_sz % QUOTABLOCK_SIZE));
+        } else {
+                usage = qctl->qc_dqblk.dqb_curinodes;
+                limit = qctl->qc_dqblk.dqb_ihardlimit;
+                qunit_sz = qctxt->lqc_iunit_sz;
+                tune_sz = qctxt->lqc_itune_sz;
+        }
+
+        /* ignore the no quota limit case */
+        if (!limit)
+                GOTO(out, ret = 0);
+
+        /* we don't count the MIN_QLIMIT */
+        if ((limit == MIN_QLIMIT && !qdata->qd_isblk) ||
+            (toqb(limit) == MIN_QLIMIT && qdata->qd_isblk))
+                limit = 0;
+
+        LASSERT(qdata->qd_count == 0);
+        if (limit <= usage + tune_sz) {
+                while (qdata->qd_count + limit <= usage + tune_sz)
+                        qdata->qd_count += qunit_sz;
+                ret = 1;
+        } else if (limit > usage + qunit_sz + tune_sz) {
+                while (limit - qdata->qd_count > usage + qunit_sz + tune_sz)
+                        qdata->qd_count += qunit_sz;
+                ret = 2;
+        }
+        LASSERT(ret == 0 || qdata->qd_count);
+        EXIT;
+out:
+        OBD_FREE_PTR(qctl);
+        return ret;
+}
+
+/* caller must hold qunit_hash_lock */
+static struct lustre_qunit *dqacq_in_flight(struct lustre_quota_ctxt *qctxt,
+                                            struct qunit_data *qdata)
+{
+        unsigned int hashent = qunit_hashfn(qctxt, qdata);
+        struct lustre_qunit *qunit;
+        ENTRY;
+
+        LASSERT_SPIN_LOCKED(&qunit_hash_lock);
+        qunit = find_qunit(hashent, qctxt, qdata);
+        RETURN(qunit);
+}
+
+static struct lustre_qunit *alloc_qunit(struct lustre_quota_ctxt *qctxt,
+                                        struct qunit_data *qdata, int opc)
+{
+        struct lustre_qunit *qunit = NULL;
+        ENTRY;
+
+        OBD_SLAB_ALLOC(qunit, qunit_cachep, SLAB_NOFS, sizeof(*qunit));
+        if (qunit == NULL)
+                RETURN(NULL);
+
+        INIT_LIST_HEAD(&qunit->lq_hash);
+        INIT_LIST_HEAD(&qunit->lq_waiters);
+        atomic_set(&qunit->lq_refcnt, 1);
+        qunit->lq_ctxt = qctxt;
+        memcpy(&qunit->lq_data, qdata, sizeof(*qdata));
+        qunit->lq_opc = opc;
+
+        RETURN(qunit);
+}
+
+static inline void free_qunit(struct lustre_qunit *qunit)
+{
+        OBD_SLAB_FREE(qunit, qunit_cachep, sizeof(*qunit));
+}
+
+static inline void qunit_get(struct lustre_qunit *qunit)
+{
+        atomic_inc(&qunit->lq_refcnt);
+}
+
+static void qunit_put(struct lustre_qunit *qunit)
+{
+        LASSERT(atomic_read(&qunit->lq_refcnt));
+        if (atomic_dec_and_test(&qunit->lq_refcnt))
+                free_qunit(qunit);
+}
+
+static void
+insert_qunit_nolock(struct lustre_quota_ctxt *qctxt, struct lustre_qunit *qunit)
+{
+        struct list_head *head;
+
+        LASSERT(list_empty(&qunit->lq_hash));
+        head = qunit_hash + qunit_hashfn(qctxt, &qunit->lq_data);
+        list_add(&qunit->lq_hash, head);
+}
+
+static void remove_qunit_nolock(struct lustre_qunit *qunit)
+{
+        LASSERT(!list_empty(&qunit->lq_hash));
+        list_del_init(&qunit->lq_hash);
+}
+
+struct qunit_waiter {
+        struct list_head qw_entry;
+        wait_queue_head_t qw_waitq;
+        int qw_rc;
+};
+
+#define QDATA_DEBUG(qd, fmt, arg...)                                    \
+        CDEBUG(D_QUOTA, "id(%u) type(%u) count(%u) isblk(%u):"          \
+               fmt, qd->qd_id, qd->qd_type, qd->qd_count, qd->qd_isblk, \
+               ## arg);                                                 \
+
+#define INC_QLIMIT(limit, count) (limit == MIN_QLIMIT) ? \
+                                 (limit = count) : (limit += count)
+
+
+/* FIXME check if this mds is the master of specified id */
+static int 
+is_master(struct obd_device *obd, struct lustre_quota_ctxt *qctxt, 
+          unsigned int id, int type)
+{
+        return qctxt->lqc_handler ? 1 : 0;
+}
+
+static int 
+schedule_dqacq(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
+               struct qunit_data *qdata, int opc, int wait);
+
+static int
+dqacq_completion(struct obd_device *obd,
+                 struct lustre_quota_ctxt *qctxt,
+                 struct qunit_data *qdata, int rc, int opc)
+{
+        struct lustre_qunit *qunit = NULL;
+        struct super_block *sb = qctxt->lqc_sb;
+        unsigned long qunit_sz;
+        struct qunit_waiter *qw, *tmp;
+        int err = 0;
+        ENTRY;
+
+        LASSERT(qdata);
+        qunit_sz = qdata->qd_isblk ? qctxt->lqc_bunit_sz : qctxt->lqc_iunit_sz;
+        LASSERT(!(qdata->qd_count % qunit_sz));
+
+        /* update local operational quota file */
+        if (rc == 0) {
+                __u32 count = QUSG(qdata->qd_count, qdata->qd_isblk);
+                struct obd_quotactl *qctl;
+                __u64 *hardlimit;
+
+                OBD_ALLOC_PTR(qctl);
+                if (qctl == NULL)
+                        GOTO(out, err = -ENOMEM);
+
+                /* acq/rel qunit for specified uid/gid is serialized,
+                 * so there is no race between get fs quota limit and
+                 * set fs quota limit */
+                qctl->qc_cmd = Q_GETQUOTA;
+                qctl->qc_id = qdata->qd_id;
+                qctl->qc_type = qdata->qd_type;
+                err = fsfilt_quotactl(obd, sb, qctl);
+                if (err) {
+                        CERROR("error get quota fs limit! (rc:%d)\n", err);
+                        GOTO(out_mem, err);
+                }
+
+                if (qdata->qd_isblk) {
+                        qctl->qc_dqblk.dqb_valid = QIF_BLIMITS;
+                        hardlimit = &qctl->qc_dqblk.dqb_bhardlimit;
+                } else {
+                        qctl->qc_dqblk.dqb_valid = QIF_ILIMITS;
+                        hardlimit = &qctl->qc_dqblk.dqb_ihardlimit;
+                }
+
+                switch (opc) {
+                case QUOTA_DQACQ:
+                        INC_QLIMIT(*hardlimit, count);
+                        break;
+                case QUOTA_DQREL:
+                        LASSERT(count < *hardlimit);
+                        *hardlimit -= count;
+                        break;
+                default:
+                        LBUG();
+                }
+
+                /* clear quota limit */
+                if (count == 0)
+                        *hardlimit = 0;
+
+                qctl->qc_cmd = Q_SETQUOTA;
+                err = fsfilt_quotactl(obd, sb, qctl);
+                if (err)
+                        CERROR("error set quota fs limit! (rc:%d)\n", err);
+
+                QDATA_DEBUG(qdata, "%s completion\n",
+                            opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
+out_mem:
+                OBD_FREE_PTR(qctl);
+        } else if (rc == -EDQUOT) {
+                QDATA_DEBUG(qdata, "acquire qunit got EDQUOT.\n");
+        } else if (rc == -EBUSY) {
+                QDATA_DEBUG(qdata, "it's is recovering, got EBUSY.\n");
+        } else {
+                CERROR("acquire qunit got error! (rc:%d)\n", rc);
+        }
+out:
+        /* remove the qunit from hash */
+        spin_lock(&qunit_hash_lock);
+
+        qunit = dqacq_in_flight(qctxt, qdata);
+        /* this qunit has been removed by qctxt_cleanup() */
+        if (!qunit) {
+                spin_unlock(&qunit_hash_lock);
+                RETURN(err);
+        }
+
+        LASSERT(opc == qunit->lq_opc);
+        remove_qunit_nolock(qunit);
+
+        /* wake up all waiters */
+        list_for_each_entry_safe(qw, tmp, &qunit->lq_waiters, qw_entry) {
+                list_del_init(&qw->qw_entry);
+                qw->qw_rc = rc;
+                wake_up(&qw->qw_waitq);
+        }
+
+        spin_unlock(&qunit_hash_lock);
+
+        qunit_put(qunit);
+
+        /* don't reschedule in such cases:
+         *   - acq/rel failure, but not for quota recovery.
+         *   - local dqacq/dqrel.
+         *   - local disk io failure.
+         */
+        if (err || (rc && rc != -EBUSY) || 
+            is_master(obd, qctxt, qdata->qd_id, qdata->qd_type))
+                RETURN(err);
+
+        /* reschedule another dqacq/dqrel if needed */
+        qdata->qd_count = 0;
+        rc = check_cur_qunit(obd, qctxt, qdata);
+        if (rc > 0) {
+                int opc;
+                opc = rc == 1 ? QUOTA_DQACQ : QUOTA_DQREL;
+                rc = schedule_dqacq(obd, qctxt, qdata, opc, 0);
+                QDATA_DEBUG(qdata, "reschedudle opc(%d) rc(%d)\n", opc, rc);
+        }
+        RETURN(err);
+}
+
+struct dqacq_async_args {
+        struct lustre_quota_ctxt *aa_ctxt;
+        struct lustre_qunit *aa_qunit;
+};
+
+static int dqacq_interpret(struct ptlrpc_request *req, void *data, int rc)
+{
+        struct dqacq_async_args *aa = (struct dqacq_async_args *)data;
+        struct lustre_quota_ctxt *qctxt = aa->aa_ctxt;
+        struct lustre_qunit *qunit = aa->aa_qunit;
+        struct obd_device *obd = req->rq_import->imp_obd;
+        struct qunit_data *qdata = NULL;
+        ENTRY;
+
+        qdata = lustre_swab_repbuf(req, 0, sizeof(*qdata), lustre_swab_qdata);
+        if (rc == 0 && qdata == NULL)
+                RETURN(-EPROTO);
+
+        LASSERT(qdata->qd_id == qunit->lq_data.qd_id &&
+                qdata->qd_type == qunit->lq_data.qd_type &&
+                (qdata->qd_count == qunit->lq_data.qd_count ||
+                 qdata->qd_count == 0));
+
+        QDATA_DEBUG(qdata, "%s interpret rc(%d).\n",
+                    req->rq_reqmsg->opc == QUOTA_DQACQ ? "DQACQ" : "DQREL", rc);
+
+        rc = dqacq_completion(obd, qctxt, qdata, rc, req->rq_reqmsg->opc);
+
+        RETURN(rc);
+}
+
+static int got_qunit(struct qunit_waiter *waiter)
+{
+        int rc = 0;
+        ENTRY;
+        spin_lock(&qunit_hash_lock);
+        rc = list_empty(&waiter->qw_entry);
+        spin_unlock(&qunit_hash_lock);
+        RETURN(rc);
+}
+
+static int
+schedule_dqacq(struct obd_device *obd,
+               struct lustre_quota_ctxt *qctxt,
+               struct qunit_data *qdata, int opc, int wait)
+{
+        struct lustre_qunit *qunit, *empty;
+        struct qunit_waiter qw;
+        struct l_wait_info lwi = { 0 };
+        struct ptlrpc_request *req;
+        struct qunit_data *reqdata;
+        struct dqacq_async_args *aa;
+        int size = sizeof(*reqdata);
+        int rc = 0;
+        ENTRY;
+
+        INIT_LIST_HEAD(&qw.qw_entry);
+        init_waitqueue_head(&qw.qw_waitq);
+        qw.qw_rc = 0;
+
+        if ((empty = alloc_qunit(qctxt, qdata, opc)) == NULL)
+                RETURN(-ENOMEM);
+        
+        spin_lock(&qunit_hash_lock);
+
+        qunit = dqacq_in_flight(qctxt, qdata);
+        if (qunit) {
+                if (wait) 
+                        list_add_tail(&qw.qw_entry, &qunit->lq_waiters);
+                spin_unlock(&qunit_hash_lock);
+                
+                free_qunit(empty);
+                goto wait_completion;
+        } 
+        qunit = empty;
+        insert_qunit_nolock(qctxt, qunit);
+        if (wait)
+                list_add_tail(&qw.qw_entry, &qunit->lq_waiters);
+        spin_unlock(&qunit_hash_lock);
+
+        LASSERT(qunit);
+
+        /* master is going to dqacq/dqrel from itself */
+        if (is_master(obd, qctxt, qdata->qd_id, qdata->qd_type)) {
+                int rc2;
+                QDATA_DEBUG(qdata, "local %s.\n",
+                            opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
+                rc = qctxt->lqc_handler(obd, qdata, opc);
+                rc2 = dqacq_completion(obd, qctxt, qdata, rc, opc);
+                RETURN((rc && rc != -EDQUOT) ? rc : rc2);
+        }
+
+        /* build dqacq/dqrel request */
+        LASSERT(qctxt->lqc_import);
+        req = ptlrpc_prep_req(qctxt->lqc_import, opc, 1, &size, NULL);
+        if (!req) {
+                dqacq_completion(obd, qctxt, qdata, -ENOMEM, opc);
+                RETURN(-ENOMEM);
+        }
+
+        reqdata = lustre_msg_buf(req->rq_reqmsg, 0, sizeof(*reqdata));
+        *reqdata = *qdata;
+        size = sizeof(*reqdata);
+        req->rq_replen = lustre_msg_size(1, &size);
+
+        CLASSERT(sizeof(*aa) <= sizeof(req->rq_async_args));
+        aa = (struct dqacq_async_args *)&req->rq_async_args;
+        aa->aa_ctxt = qctxt;
+        aa->aa_qunit = qunit;
+
+        req->rq_interpret_reply = dqacq_interpret;
+        ptlrpcd_add_req(req);
+
+        QDATA_DEBUG(qdata, "%s scheduled.\n", 
+                    opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
+wait_completion:
+        if (wait && qunit) {
+                struct qunit_data *p = &qunit->lq_data;
+                QDATA_DEBUG(p, "wait for dqacq.\n");
+
+                l_wait_event(qw.qw_waitq, got_qunit(&qw), &lwi);
+                if (qw.qw_rc == 0)
+                        rc = -EAGAIN;
+
+                CDEBUG(D_QUOTA, "wait dqacq done. (rc:%d)\n", qw.qw_rc);
+        }
+        RETURN(rc);
+}
+
+int
+qctxt_adjust_qunit(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
+                   uid_t uid, gid_t gid, __u32 isblk, int wait)
+{
+        int ret, rc = 0, i = USRQUOTA;
+        __u32 id[MAXQUOTAS] = { uid, gid };
+        struct qunit_data qdata[MAXQUOTAS];
+        ENTRY;
+
+        CLASSERT(MAXQUOTAS < 4);
+        if (!sb_any_quota_enabled(qctxt->lqc_sb))
+                RETURN(0);
+
+        for (i = 0; i < MAXQUOTAS; i++) {
+                qdata[i].qd_id = id[i];
+                qdata[i].qd_type = i;
+                qdata[i].qd_isblk = isblk;
+                qdata[i].qd_count = 0;
+
+                ret = check_cur_qunit(obd, qctxt, &qdata[i]);
+                if (ret > 0) {
+                        int opc;
+                        /* need acquire or release */
+                        opc = ret == 1 ? QUOTA_DQACQ : QUOTA_DQREL;
+                        ret = schedule_dqacq(obd, qctxt, &qdata[i], opc, wait);
+                        if (!rc)
+                                rc = ret;
+                }
+        }
+
+        RETURN(rc);
+}
+
+int 
+qctxt_wait_pending_dqacq(struct lustre_quota_ctxt *qctxt, unsigned int id,
+                         unsigned short type, int isblk)
+{
+        struct lustre_qunit *qunit = NULL;
+        struct qunit_waiter qw;
+        struct qunit_data qdata;
+        struct l_wait_info lwi = { 0 };
+        ENTRY;
+
+        INIT_LIST_HEAD(&qw.qw_entry);
+        init_waitqueue_head(&qw.qw_waitq);
+        qw.qw_rc = 0;
+
+        qdata.qd_id = id;
+        qdata.qd_type = type;
+        qdata.qd_isblk = isblk;
+        qdata.qd_count = 0;
+
+        spin_lock(&qunit_hash_lock);
+
+        qunit = dqacq_in_flight(qctxt, &qdata);
+        if (qunit)
+                list_add_tail(&qw.qw_entry, &qunit->lq_waiters);
+
+        spin_unlock(&qunit_hash_lock);
+
+        if (qunit) {
+                struct qunit_data *p = &qdata;
+                QDATA_DEBUG(p, "wait for dqacq completion.\n");
+                l_wait_event(qw.qw_waitq, got_qunit(&qw), &lwi);
+                QDATA_DEBUG(p, "wait dqacq done. (rc:%d)\n", qw.qw_rc);
+        }
+        RETURN(0);
+}
+
+int
+qctxt_init(struct lustre_quota_ctxt *qctxt, struct super_block *sb,
+           dqacq_handler_t handler)
+{
+        int rc = 0;
+        ENTRY;
+
+        rc = ptlrpcd_addref();
+        if (rc)
+                RETURN(rc);
+
+        qctxt->lqc_handler = handler;
+        qctxt->lqc_sb = sb;
+        qctxt->lqc_import = NULL;
+        qctxt->lqc_recovery = 0;
+        qctxt->lqc_bunit_sz = default_bunit_sz;
+        qctxt->lqc_btune_sz = default_bunit_sz / 100 * default_btune_ratio;
+        qctxt->lqc_iunit_sz = default_iunit_sz;
+        qctxt->lqc_itune_sz = default_iunit_sz * default_itune_ratio / 100;
+
+        RETURN(0);
+}
+
+void qctxt_cleanup(struct lustre_quota_ctxt *qctxt, int force)
+{
+        struct lustre_qunit *qunit, *tmp;
+        struct qunit_waiter *qw, *tmp2;
+        int i;
+        ENTRY;
+
+        spin_lock(&qunit_hash_lock);
+
+        for (i = 0; i < NR_DQHASH; i++) {
+                list_for_each_entry_safe(qunit, tmp, &qunit_hash[i], lq_hash) {
+                        if (qunit->lq_ctxt != qctxt)
+                                continue;
+
+                        remove_qunit_nolock(qunit);
+                        /* wake up all waiters */
+                        list_for_each_entry_safe(qw, tmp2, &qunit->lq_waiters, 
+                                                 qw_entry) {
+                                list_del_init(&qw->qw_entry);
+                                qw->qw_rc = 0;
+                                wake_up(&qw->qw_waitq);
+                        }
+                        qunit_put(qunit);
+                }
+        }
+
+        spin_unlock(&qunit_hash_lock);
+
+        ptlrpcd_decref();
+
+        EXIT;
+}
+
+struct qslave_recov_thread_data {
+        struct obd_device *obd;
+        struct lustre_quota_ctxt *qctxt;
+        struct completion comp;
+};
+
+/* FIXME only recovery block quota by now */
+static int qslave_recovery_main(void *arg)
+{
+        struct qslave_recov_thread_data *data = arg;
+        struct obd_device *obd = data->obd;
+        struct lustre_quota_ctxt *qctxt = data->qctxt;
+        unsigned long flags;
+        unsigned int type; 
+        int rc = 0;
+        ENTRY;
+
+        lock_kernel();
+        ptlrpc_daemonize();
+
+        SIGNAL_MASK_LOCK(current, flags);
+        sigfillset(&current->blocked);
+        RECALC_SIGPENDING;
+        SIGNAL_MASK_UNLOCK(current, flags);
+        THREAD_NAME(cfs_curproc_comm(), CFS_CURPROC_COMM_MAX - 1, "%s", "qslave_recovd");
+        unlock_kernel();
+
+        complete(&data->comp);
+
+        if (qctxt->lqc_recovery)
+                RETURN(0);
+        qctxt->lqc_recovery = 1;
+
+        for (type = USRQUOTA; type < MAXQUOTAS; type++) {
+                struct qunit_data qdata;
+                struct quota_info *dqopt = sb_dqopt(qctxt->lqc_sb);
+                struct lustre_quota_info *dummy;
+                struct list_head id_list;
+                struct dquot_id *dqid, *tmp;
+                int ret;
+
+                OBD_ALLOC_PTR(dummy);
+                if (!dummy) {
+                        CERROR("Not enough memory\n");
+                        rc = -ENOMEM;
+                        break;
+                }
+
+                down(&dqopt->dqonoff_sem);
+                if (!sb_has_quota_enabled(qctxt->lqc_sb, type)) {
+                        up(&dqopt->dqonoff_sem);
+                        OBD_FREE_PTR(dummy);
+                        break;
+                }
+                dummy->qi_files[type] = dqopt->files[type];
+                LASSERT(dummy->qi_files[type] != NULL);
+                INIT_LIST_HEAD(&id_list);
+
+                rc = fsfilt_quotainfo(obd, dummy, type, QFILE_GET_QIDS, &id_list);
+                up(&dqopt->dqonoff_sem);
+
+                OBD_FREE_PTR(dummy);
+                if (rc)
+                        CERROR("Get ids from quota file failed. (rc:%d)\n", rc);
+
+                list_for_each_entry_safe(dqid, tmp, &id_list, di_link) {
+                        list_del_init(&dqid->di_link);
+                        /* skip slave recovery on itself */
+                        if (is_master(obd, qctxt, dqid->di_id, type))
+                                goto free;
+                        if (rc && rc != -EBUSY)
+                                goto free;
+
+                        qdata.qd_id = dqid->di_id;
+                        qdata.qd_type = type;
+                        qdata.qd_isblk = 1;
+                        qdata.qd_count = 0;
+
+                        ret = check_cur_qunit(obd, qctxt, &qdata);
+                        if (ret > 0) {
+                                int opc;
+                                opc = ret == 1 ? QUOTA_DQACQ : QUOTA_DQREL;
+                                rc = schedule_dqacq(obd, qctxt, &qdata, opc, 0);
+                        } else
+                                rc = 0;
+
+                        if (rc)
+                                CDEBUG(rc == -EBUSY ? D_QUOTA : D_ERROR, 
+                                       "qslave recovery failed! (id:%d type:%d "
+                                       " rc:%d)\n", dqid->di_id, type, rc);
+free:
+                        kfree(dqid);
+                }
+        }
+
+        qctxt->lqc_recovery = 0;
+        RETURN(rc);
+}
+
+void 
+qslave_start_recovery(struct obd_device *obd, struct lustre_quota_ctxt *qctxt)
+{
+        struct qslave_recov_thread_data data;
+        int rc;
+        ENTRY;
+
+        if (!sb_any_quota_enabled(qctxt->lqc_sb))
+                goto exit;
+
+        data.obd = obd;
+        data.qctxt = qctxt;
+        init_completion(&data.comp);
+
+        rc = kernel_thread(qslave_recovery_main, &data, CLONE_VM|CLONE_FILES);
+        if (rc < 0) {
+                CERROR("Cannot start quota recovery thread: rc %d\n", rc);
+                goto exit;
+        }
+        wait_for_completion(&data.comp);
+exit:
+        EXIT;
+}
+
diff --git a/lustre/quota/quota_ctl.c b/lustre/quota/quota_ctl.c
new file mode 100644 (file)
index 0000000..3414763
--- /dev/null
@@ -0,0 +1,255 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  lustre/quota/quota_ctl.c
+ *
+ *  Copyright (c) 2005 Cluster File Systems, Inc.
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
+ *
+ */
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+#define DEBUG_SUBSYSTEM S_MDS
+
+#ifdef __KERNEL__
+# include <linux/version.h>
+# include <linux/module.h>
+# include <linux/init.h>
+# include <linux/fs.h>
+# include <linux/jbd.h>
+# include <linux/ext3_fs.h>
+# include <linux/quota.h>
+# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+#  include <linux/smp_lock.h>
+#  include <linux/buffer_head.h>
+#  include <linux/workqueue.h>
+#  include <linux/mount.h>
+# else
+#  include <linux/locks.h>
+# endif
+#else /* __KERNEL__ */
+# include <liblustre.h>
+#endif
+
+#include <linux/obd_class.h>
+#include <linux/lustre_mds.h>
+#include <linux/lustre_dlm.h>
+#include <linux/lustre_cfg.h>
+#include <linux/obd_ost.h>
+#include <linux/lustre_fsfilt.h>
+#include <linux/lustre_quota.h>
+#include "quota_internal.h"
+
+#ifdef __KERNEL__
+int mds_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+        struct obd_device *obd = exp->exp_obd;
+        int rc = 0;
+        ENTRY;
+
+        switch (oqctl->qc_cmd) {
+        case Q_QUOTAON:
+                rc = mds_quota_on(obd, oqctl);
+                break;
+        case Q_QUOTAOFF:
+                mds_quota_off(obd, oqctl);
+                break;
+        case Q_SETINFO:
+                rc = mds_set_dqinfo(obd, oqctl);
+                break;
+        case Q_GETINFO:
+                rc = mds_get_dqinfo(obd, oqctl);
+                break;
+        case Q_SETQUOTA:
+                rc = mds_set_dqblk(obd, oqctl);
+                break;
+        case Q_GETQUOTA:
+                rc = mds_get_dqblk(obd, oqctl);
+                break;
+        case Q_GETOINFO:
+        case Q_GETOQUOTA:
+                rc = mds_get_obd_quota(obd, oqctl);
+                break;
+        default:
+                CERROR("%s: unsupported mds_quotactl command: %d\n",
+                       obd->obd_name, oqctl->qc_cmd);
+                RETURN(-EFAULT);
+        }
+
+        if (rc)
+                CDEBUG(D_INFO, "mds_quotactl admin quota command %d, id %u, "
+                               "type %d, failed: rc = %d\n",
+                       oqctl->qc_cmd, oqctl->qc_id, oqctl->qc_type, rc);
+
+        RETURN(rc);
+}
+
+int filter_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+        struct obd_device *obd = exp->exp_obd;
+        struct lvfs_run_ctxt saved;
+        int rc = 0;
+        ENTRY;
+
+        switch (oqctl->qc_cmd) {
+        case Q_QUOTAON:
+        case Q_QUOTAOFF:
+        case Q_GETOINFO:
+        case Q_GETOQUOTA:
+        case Q_GETQUOTA:
+                /* In recovery scenario, this pending dqacq/dqrel might have
+                 * been processed by master successfully before it's dquot
+                 * on master enter recovery mode. We must wait for this 
+                 * dqacq/dqrel done then return the correct limits to master */
+                if (oqctl->qc_stat == QUOTA_RECOVERING)
+                        qctxt_wait_pending_dqacq(&obd->u.obt.obt_qctxt,
+                                                 oqctl->qc_id, oqctl->qc_type, 
+                                                 1);
+
+                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+                rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+                break;
+        case Q_INITQUOTA:
+                {
+                unsigned int uid = 0, gid = 0;
+
+                /* Initialize quota limit to MIN_QLIMIT */
+                LASSERT(oqctl->qc_dqblk.dqb_valid == QIF_BLIMITS);
+                LASSERT(oqctl->qc_dqblk.dqb_bhardlimit == MIN_QLIMIT);
+                LASSERT(oqctl->qc_dqblk.dqb_bsoftlimit == 0);
+
+                /* There might be a pending dqacq/dqrel (which is going to
+                 * clear stale limits on slave). we should wait for it's 
+                 * completion then initialize limits */
+                qctxt_wait_pending_dqacq(&obd->u.obt.obt_qctxt, 
+                                         oqctl->qc_id, oqctl->qc_type, 1);
+
+                push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+                rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+
+                /* Update on-disk quota, in case of lose the changed limits
+                 * (MIN_QLIMIT) on crash, which cannot be recovered.*/
+                if (!rc) {
+                        oqctl->qc_cmd = Q_SYNC;
+                        fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+                        oqctl->qc_cmd = Q_INITQUOTA;
+                }
+                pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+                if (rc)
+                        RETURN(rc);
+
+                /* Trigger qunit pre-acquire */
+                if (oqctl->qc_type == USRQUOTA)
+                        uid = oqctl->qc_id;
+                else
+                        gid = oqctl->qc_id;
+
+                rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt, 
+                                        uid, gid, 1, 0);
+                break;
+                }
+        default:
+                CERROR("%s: unsupported filter_quotactl command: %d\n",
+                       obd->obd_name, oqctl->qc_cmd);
+                RETURN(-EFAULT);
+        }
+
+        RETURN(rc);
+}
+#endif /* __KERNEL__ */
+
+int client_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+        struct ptlrpc_request *req;
+        struct obd_quotactl *oqc;
+        int size = sizeof(*oqctl), opc;
+        int rc;
+        ENTRY;
+
+        if (!strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_MDC_NAME))
+                opc = MDS_QUOTACTL;
+        else if (!strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME))
+                opc = OST_QUOTACTL;
+        else
+                RETURN(-EINVAL);
+
+        req = ptlrpc_prep_req(class_exp2cliimp(exp), opc, 1, &size, NULL);
+        if (!req)
+                GOTO(out, rc = -ENOMEM);
+
+        oqc = lustre_msg_buf(req->rq_reqmsg, 0, sizeof (*oqctl));
+        *oqc = *oqctl;
+
+        req->rq_replen = lustre_msg_size(1, &size);
+
+        rc = ptlrpc_queue_wait(req);
+        if (!rc) {
+                oqc = lustre_swab_repbuf(req, 0, sizeof (*oqc),
+                                         lustre_swab_obd_quotactl);
+                if (oqc == NULL) {
+                        CERROR ("Can't unpack obd_quotactl\n");
+                        GOTO(out, rc = -EPROTO);
+                }
+
+                *oqctl = *oqc;
+        }
+out:
+        ptlrpc_req_finished(req);
+        RETURN (rc);
+}
+
+int lov_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl)
+{
+        struct obd_device *obd = class_exp2obd(exp);
+        struct lov_obd *lov = &obd->u.lov;
+        __u64 curspace = 0;
+        __u32 bhardlimit = 0;
+        int i, rc = 0;
+        ENTRY;
+
+        if (oqctl->qc_cmd != Q_QUOTAON && oqctl->qc_cmd != Q_QUOTAOFF &&
+            oqctl->qc_cmd != Q_GETOQUOTA && oqctl->qc_cmd != Q_INITQUOTA) {
+                CERROR("bad quota opc %x for lov obd", oqctl->qc_cmd);
+                RETURN(-EFAULT);
+        }
+
+        for (i = 0; i < lov->desc.ld_tgt_count; i++) {
+                int err;
+
+                if (!lov->tgts[i].active) {
+                        if (oqctl->qc_cmd == Q_GETOQUOTA) {
+                                CERROR("ost %d is inactive\n", i);
+                                rc = -EIO;
+                                break;
+                        } else {
+                                CDEBUG(D_HA, "ost %d is inactive\n", i);
+                                continue;
+                        }
+                }
+
+                err = obd_quotactl(lov->tgts[i].ltd_exp, oqctl);
+                if (err) {
+                        if (lov->tgts[i].active && !rc)
+                                rc = err;
+                        continue;
+                }
+
+                if (oqctl->qc_cmd == Q_GETOQUOTA) {
+                        curspace += oqctl->qc_dqblk.dqb_curspace;
+                        bhardlimit += oqctl->qc_dqblk.dqb_bhardlimit;
+                }
+        }
+
+        if (oqctl->qc_cmd == Q_GETOQUOTA) {
+                oqctl->qc_dqblk.dqb_curspace = curspace;
+                oqctl->qc_dqblk.dqb_bhardlimit = bhardlimit;
+        }
+        RETURN(rc);
+}
+
diff --git a/lustre/quota/quota_interface.c b/lustre/quota/quota_interface.c
new file mode 100644 (file)
index 0000000..6085ff3
--- /dev/null
@@ -0,0 +1,693 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  lustre/quota/quota_interface.c
+ *
+ *  Copyright (c) 2001-2005 Cluster File Systems, Inc.
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
+ *
+ */
+#ifndef EXPORT_SYMTAB
+# define EXPORT_SYMTAB
+#endif
+#define DEBUG_SUBSYSTEM S_MDS
+
+#ifdef __KERNEL__
+# include <linux/version.h>
+# include <linux/module.h>
+# include <linux/init.h>
+# include <linux/fs.h>
+# include <linux/jbd.h>
+# include <linux/ext3_fs.h>
+# include <linux/parser.h>
+# if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0))
+#  include <linux/smp_lock.h>
+#  include <linux/buffer_head.h>
+#  include <linux/workqueue.h>
+#  include <linux/mount.h>
+# else
+#  include <linux/locks.h>
+# endif
+#else /* __KERNEL__ */
+# include <liblustre.h>
+#endif
+
+#include <linux/obd_class.h>
+#include <linux/lustre_mds.h>
+#include <linux/lustre_dlm.h>
+#include <linux/lustre_cfg.h>
+#include <linux/obd_ost.h>
+#include <linux/lustre_fsfilt.h>
+#include <linux/lustre_quota.h>
+#include "quota_internal.h"
+
+
+#ifdef __KERNEL__
+extern unsigned long default_bunit_sz;
+extern unsigned long default_btune_ratio;
+extern unsigned long default_iunit_sz;
+extern unsigned long default_itune_ratio;
+
+enum {
+        Opt_quotaon, Opt_iunit_sz, Opt_bunit_sz,
+        Opt_itune_ratio, Opt_btune_ratio, Opt_err,
+};
+
+static match_table_t tokens = {
+        {Opt_quotaon, "quotaon=%10s"},
+        {Opt_iunit_sz, "iunit=%u"},
+        {Opt_bunit_sz, "bunit=%u"},
+        {Opt_itune_ratio, "itune=%u"},
+        {Opt_btune_ratio, "btune=%u"},
+        {Opt_err, NULL}
+};
+
+static int
+quota_parse_config_args(char *options, int *quotaon, int *type,
+                        struct lustre_quota_ctxt *qctxt)
+{
+        char *opt;
+        substring_t args[MAX_OPT_ARGS];
+        int option;
+        int rc = 0;
+        unsigned long iunit = 0, bunit = 0, itune = 0, btune = 0;
+        ENTRY;
+
+        while ((opt = strsep (&options, ",")) != NULL) {
+                int token;
+                if (!*opt)
+                        continue;
+
+                token = match_token(opt, tokens, args);
+                switch(token) {
+                case Opt_quotaon: {
+                        char *quota_type = match_strdup(&args[0]);
+                        if (!quota_type)
+                                GOTO(out, rc = -EINVAL);
+
+                        *quotaon = 1;
+                        if (strchr(quota_type, 'u') && strchr(quota_type, 'g'))
+                                *type = UGQUOTA;
+                        else if (strchr(quota_type, 'u'))
+                                *type = USRQUOTA;
+                        else if (strchr(quota_type, 'g'))
+                                *type = GRPQUOTA;
+                        else {
+                                *quotaon = 0;
+                                rc = -EINVAL;
+                        }
+                        break;
+                }
+                case Opt_iunit_sz:
+                        if (match_int(&args[0], &option))
+                                rc = -EINVAL;
+                        iunit = option;
+                        break;
+                case Opt_bunit_sz:
+                        if (match_int(&args[0], &option))
+                                rc = -EINVAL;
+                        bunit = option;
+                        break;
+                case Opt_itune_ratio:
+                        if (match_int(&args[0], &option) || 
+                            option <= 0 || option >= 100)
+                                rc = -EINVAL;
+                        itune = option;
+                        break;
+                case Opt_btune_ratio:
+                        if (match_int(&args[0], &option) ||
+                            option <= 0 || option >= 100)
+                                rc = -EINVAL;
+                        btune = option;
+                        break;
+                default:
+                        rc = -EINVAL;
+                }
+
+                if (rc)
+                        GOTO(out, rc);
+        }
+
+        /* adjust the tunables of qunits based on quota config args */
+        if (iunit)
+                qctxt->lqc_iunit_sz = iunit;
+        if (itune)
+                qctxt->lqc_itune_sz = qctxt->lqc_iunit_sz *
+                                      itune / 100;
+        else
+                qctxt->lqc_itune_sz = qctxt->lqc_iunit_sz *
+                                      default_itune_ratio / 100;
+        if (bunit)
+                qctxt->lqc_bunit_sz = bunit << 20;
+        if (btune)
+                qctxt->lqc_btune_sz = ((qctxt->lqc_bunit_sz >> 20) *
+                                        btune / 100) << 20;
+        else
+                qctxt->lqc_btune_sz = ((qctxt->lqc_bunit_sz >> 20) *
+                                        default_btune_ratio / 100) << 20;
+
+        CDEBUG(D_INFO, "iunit=%lu bunit=%lu itune=%lu btune=%lu\n",
+               qctxt->lqc_iunit_sz, qctxt->lqc_bunit_sz,
+               qctxt->lqc_itune_sz, qctxt->lqc_btune_sz);
+        EXIT;
+
+ out:
+        if (rc)
+                CERROR("quota config args parse error!(rc = %d) usage: "
+                "--quota quotaon=u|g|ug,iunit=100,bunit=100,itune=50,btune=50\n",
+                 rc);
+
+        return rc;
+}
+
+static int auto_quota_on(struct obd_device *obd, int type, 
+                         struct super_block *sb, int is_master)
+{
+        struct obd_quotactl *oqctl;
+        struct lvfs_run_ctxt saved;
+        int rc;
+        ENTRY;
+
+        LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
+
+        OBD_ALLOC_PTR(oqctl);
+        if (!oqctl)
+                RETURN(-ENOMEM);
+
+        oqctl->qc_type = type;
+        oqctl->qc_cmd = Q_QUOTAON;
+        oqctl->qc_id = QFMT_LDISKFS;
+
+        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+        if (!is_master)
+                goto local_quota;
+
+        /* turn on cluster wide quota */
+        rc = mds_admin_quota_on(obd, oqctl);
+        if (rc) {
+                CERROR("auto enable admin quota error! err = %d\n", rc);
+                GOTO(out_pop, rc);
+        }
+local_quota:
+        /* turn on local quota */
+        rc = fsfilt_quotactl(obd, sb, oqctl);
+        CDEBUG(rc ? D_ERROR : D_INFO, "auto-enable quota. rc=%d\n", rc);
+        if (rc && is_master)
+                mds_quota_off(obd, oqctl);
+out_pop:
+        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+        OBD_FREE_PTR(oqctl);
+        RETURN(rc);
+}
+
+static int mds_auto_quota_on(struct obd_device *obd, int type)
+{
+        int rc;
+        ENTRY;
+        rc = auto_quota_on(obd, type, obd->u.obt.obt_sb, 1);
+        RETURN(rc);
+}
+
+static int filter_auto_quota_on(struct obd_device *obd, int type)
+{
+        int rc = 0;
+        ENTRY;
+        rc = auto_quota_on(obd, type, obd->u.obt.obt_sb, 0);
+        RETURN(rc);
+}
+
+static int filter_quota_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
+{
+        int rc = 0;
+        struct obd_device_target *obt = &obd->u.obt;
+        ENTRY;
+
+        atomic_set(&obt->obt_quotachecking, 1);
+        rc = qctxt_init(&obt->obt_qctxt, obt->obt_sb, NULL);
+        if (rc) {
+                CERROR("initialize quota context failed! (rc:%d)\n", rc);
+                RETURN(rc);
+        }
+
+        /* Based on quota config args, set qunit sizes and enable quota */
+        if (LUSTRE_CFG_BUFLEN(lcfg, 5) > 0 && lustre_cfg_buf(lcfg, 5)) {
+                char *args = lustre_cfg_string(lcfg, 5);
+                int quotaon = 0, type;
+                int err = 0;
+
+                err = quota_parse_config_args(args, &quotaon, &type,
+                                              &obd->u.obt.obt_qctxt);
+                if (!err && quotaon)
+                        filter_auto_quota_on(obd, type);
+        }
+
+        RETURN(rc);
+}
+
+static int filter_quota_cleanup(struct obd_device *obd)
+{
+        qctxt_cleanup(&obd->u.obt.obt_qctxt, 0);
+        return 0;
+}
+
+static int filter_quota_setinfo(struct obd_export *exp, struct obd_device *obd)
+{
+        /* setup the quota context import */
+        obd->u.obt.obt_qctxt.lqc_import = exp->exp_imp_reverse;
+        /* start quota slave recovery thread. (release high limits) */
+        qslave_start_recovery(obd, &obd->u.obt.obt_qctxt);
+        return 0;
+}
+static int filter_quota_enforce(struct obd_device *obd, unsigned int ignore)
+{
+        ENTRY;
+
+        if (!sb_any_quota_enabled(obd->u.obt.obt_sb))
+                RETURN(0);
+
+        if (ignore)
+                cap_raise(current->cap_effective, CAP_SYS_RESOURCE);
+        else
+                cap_lower(current->cap_effective, CAP_SYS_RESOURCE);
+
+        RETURN(0);
+}
+
+static int filter_quota_getflag(struct obd_device *obd, struct obdo *oa)
+{
+        struct obd_device_target *obt = &obd->u.obt;
+        int err, cnt, rc = 0;
+        struct obd_quotactl *oqctl;
+        ENTRY;
+
+        if (!sb_any_quota_enabled(obt->obt_sb))
+                RETURN(0);
+
+        oa->o_flags &= ~(OBD_FL_NO_USRQUOTA | OBD_FL_NO_GRPQUOTA);
+
+        OBD_ALLOC_PTR(oqctl);
+        if (!oqctl) {
+                CERROR("Not enough memory!");
+                RETURN(-ENOMEM);
+        }
+
+        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+                memset(oqctl, 0, sizeof(*oqctl));
+
+                oqctl->qc_cmd = Q_GETQUOTA;
+                oqctl->qc_type = cnt;
+                oqctl->qc_id = (cnt == USRQUOTA) ? oa->o_uid : oa->o_gid;
+                err = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
+                if (err) {
+                        if (!rc)
+                                rc = err;
+                        continue;
+                }
+
+                /* set over quota flags for a uid/gid */
+                oa->o_valid |= (cnt == USRQUOTA) ?
+                               OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA;
+                if (oqctl->qc_dqblk.dqb_bhardlimit &&
+                   (toqb(oqctl->qc_dqblk.dqb_curspace) > 
+                    oqctl->qc_dqblk.dqb_bhardlimit))
+                        oa->o_flags |= (cnt == USRQUOTA) ? 
+                                OBD_FL_NO_USRQUOTA : OBD_FL_NO_GRPQUOTA;
+        }
+        OBD_FREE_PTR(oqctl);
+        RETURN(rc);
+}
+
+static int filter_quota_acquire(struct obd_device *obd, unsigned int uid, 
+                                unsigned int gid)
+{
+        struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
+        int rc;
+        ENTRY;
+
+        rc = qctxt_adjust_qunit(obd, qctxt, uid, gid, 1, 1);
+        RETURN(rc == -EAGAIN);
+}
+
+static int mds_quota_init(void)
+{
+        return lustre_dquot_init();
+}
+
+static int mds_quota_exit(void)
+{
+        lustre_dquot_exit();
+        return 0;
+}
+
+static int mds_quota_setup(struct obd_device *obd, struct lustre_cfg *lcfg)
+{
+        struct obd_device_target *obt = &obd->u.obt;
+        struct mds_obd *mds = &obd->u.mds;
+        int rc;
+        ENTRY;
+
+        atomic_set(&obt->obt_quotachecking, 1);
+        /* initialize quota master and quota context */
+        sema_init(&mds->mds_qonoff_sem, 1);
+        rc = qctxt_init(&obt->obt_qctxt, obt->obt_sb, dqacq_handler);
+        if (rc) {
+                CERROR("initialize quota context failed! (rc:%d)\n", rc);
+                RETURN(rc);
+        }
+
+        /* Based on quota config args, set qunit sizes and enable quota */
+        if (LUSTRE_CFG_BUFLEN(lcfg, 5) > 0 && lustre_cfg_buf(lcfg, 5)) {
+                char *args = lustre_cfg_string(lcfg, 5);
+                int quotaon = 0, type;
+                int err;
+
+                err = quota_parse_config_args(args, &quotaon, &type,
+                                              &obt->obt_qctxt);
+                if (!err && quotaon)
+                        mds_auto_quota_on(obd, type);
+        }
+        RETURN(rc);
+}
+
+static int mds_quota_cleanup(struct obd_device *obd)
+{
+        qctxt_cleanup(&obd->u.obt.obt_qctxt, 0);
+        RETURN(0);
+}
+
+static int mds_quota_fs_cleanup(struct obd_device *obd)
+{
+        struct mds_obd *mds = &obd->u.mds;
+        int i;
+        ENTRY;
+
+        /* close admin quota files */
+        down(&mds->mds_qonoff_sem);
+        for (i = 0; i < MAXQUOTAS; i++) {
+                if (mds->mds_quota_info.qi_files[i]) {
+                        filp_close(mds->mds_quota_info.qi_files[i], 0);
+                        mds->mds_quota_info.qi_files[i] = NULL;
+                }
+        }
+        up(&mds->mds_qonoff_sem);
+        RETURN(0);
+}
+#endif /* __KERNEL__ */
+
+struct osc_quota_info {
+        struct list_head        oqi_hash;       /* hash list */
+        struct client_obd      *oqi_cli;        /* osc obd */
+        unsigned int            oqi_id;         /* uid/gid of a file */
+        short                   oqi_type;       /* quota type */
+};
+
+spinlock_t qinfo_list_lock = SPIN_LOCK_UNLOCKED;
+
+static struct list_head qinfo_hash[NR_DQHASH];
+/* SLAB cache for client quota context */
+kmem_cache_t *qinfo_cachep = NULL;
+
+static inline int const hashfn(struct client_obd *cli, 
+                               unsigned long id, 
+                               int type)
+{
+        unsigned long tmp = ((unsigned long)cli>>6) ^ id;
+        tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
+        return tmp;
+}
+
+/* caller must hold qinfo_list_lock */
+static inline void insert_qinfo_hash(struct osc_quota_info *oqi)
+{
+        struct list_head *head = qinfo_hash + 
+                hashfn(oqi->oqi_cli, oqi->oqi_id, oqi->oqi_type);
+
+        LASSERT_SPIN_LOCKED(&qinfo_list_lock);
+        list_add(&oqi->oqi_hash, head);
+}
+
+/* caller must hold qinfo_list_lock */
+static inline void remove_qinfo_hash(struct osc_quota_info *oqi)
+{
+        LASSERT_SPIN_LOCKED(&qinfo_list_lock);
+        list_del_init(&oqi->oqi_hash);
+}
+
+/* caller must hold qinfo_list_lock */
+static inline struct osc_quota_info *find_qinfo(struct client_obd *cli,
+                                                unsigned int id, int type)
+{
+        unsigned int hashent = hashfn(cli, id, type);
+        struct osc_quota_info *oqi;
+
+        LASSERT_SPIN_LOCKED(&qinfo_list_lock);
+        list_for_each_entry(oqi, &qinfo_hash[hashent], oqi_hash) {
+                if (oqi->oqi_cli == cli &&
+                    oqi->oqi_id == id && oqi->oqi_type == type)
+                        return oqi;
+        }
+        return NULL;
+}
+
+static struct osc_quota_info *alloc_qinfo(struct client_obd *cli,
+                                          unsigned int id, int type)
+{
+        struct osc_quota_info *oqi;
+        ENTRY;
+
+        OBD_SLAB_ALLOC(oqi, qinfo_cachep, SLAB_KERNEL, sizeof(*oqi));
+        if(!oqi)
+                RETURN(NULL);
+
+        INIT_LIST_HEAD(&oqi->oqi_hash);
+        oqi->oqi_cli = cli;
+        oqi->oqi_id = id;
+        oqi->oqi_type = type;
+
+        RETURN(oqi);
+}
+
+static void free_qinfo(struct osc_quota_info *oqi)
+{
+        OBD_SLAB_FREE(oqi, qinfo_cachep, sizeof(*oqi));
+}
+
+int osc_quota_chkdq(struct client_obd *cli, 
+                    unsigned int uid, unsigned int gid)
+{
+        unsigned int id;
+        int cnt, rc = QUOTA_OK;
+        ENTRY;
+
+        spin_lock(&qinfo_list_lock);
+        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+                struct osc_quota_info *oqi = NULL;
+
+                id = (cnt == USRQUOTA) ? uid : gid;
+                oqi = find_qinfo(cli, id, cnt);
+                if (oqi) {
+                        rc = NO_QUOTA;
+                        break;
+                }
+        }
+        spin_unlock(&qinfo_list_lock);
+
+        RETURN(rc);
+}
+
+int osc_quota_setdq(struct client_obd *cli, 
+                    unsigned int uid, unsigned int gid,
+                    obd_flag valid, obd_flag flags)
+{
+        unsigned int id;
+        obd_flag noquota;
+        int cnt, rc = 0;
+        ENTRY;
+
+
+        for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
+                struct osc_quota_info *oqi, *old;
+
+                if (!(valid & ((cnt == USRQUOTA) ? 
+                    OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA)))
+                        continue;
+
+                id = (cnt == USRQUOTA) ? uid : gid;
+                noquota = (cnt == USRQUOTA) ? 
+                    (flags & OBD_FL_NO_USRQUOTA) : (flags & OBD_FL_NO_GRPQUOTA);
+
+                oqi = alloc_qinfo(cli, id, cnt);
+                if (oqi) {
+                        spin_lock(&qinfo_list_lock);
+
+                        old = find_qinfo(cli, id, cnt);
+                        if (old && !noquota)
+                                remove_qinfo_hash(old);
+                        else if (!old && noquota)
+                                insert_qinfo_hash(oqi);
+
+                        spin_unlock(&qinfo_list_lock);
+
+                        if (old || !noquota)
+                                free_qinfo(oqi);
+                        if (old && !noquota)
+                                free_qinfo(old);
+                } else {
+                        CERROR("not enough mem!\n");
+                        rc = -ENOMEM;
+                        break;
+                }
+        }
+
+        RETURN(rc);
+}
+
+int osc_quota_cleanup(struct obd_device *obd)
+{
+        struct client_obd *cli = &obd->u.cli;
+        struct osc_quota_info *oqi, *n;
+        int i;
+        ENTRY;
+
+        spin_lock(&qinfo_list_lock);
+        for (i = 0; i < NR_DQHASH; i++) {
+                list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
+                        if (oqi->oqi_cli != cli)
+                                continue;
+                        remove_qinfo_hash(oqi);
+                        free_qinfo(oqi);
+                }
+        }
+        spin_unlock(&qinfo_list_lock);
+
+        RETURN(0);
+}
+
+int osc_quota_init(void)
+{
+        int i;
+        ENTRY;
+
+        LASSERT(qinfo_cachep == NULL);
+        qinfo_cachep = kmem_cache_create("osc_quota_info",
+                                         sizeof(struct osc_quota_info),
+                                         0, 0, NULL, NULL);
+        if (!qinfo_cachep)
+                RETURN(-ENOMEM);
+
+        for (i = 0; i < NR_DQHASH; i++)
+                INIT_LIST_HEAD(qinfo_hash + i);
+
+        RETURN(0);
+}
+
+int osc_quota_exit(void)
+{
+        struct osc_quota_info *oqi, *n;
+        int i, rc;
+        ENTRY;
+
+        spin_lock(&qinfo_list_lock);
+        for (i = 0; i < NR_DQHASH; i++) {
+                list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) {
+                        remove_qinfo_hash(oqi);
+                        free_qinfo(oqi);
+                }
+        }
+        spin_unlock(&qinfo_list_lock);
+
+        rc = kmem_cache_destroy(qinfo_cachep);
+        LASSERT(rc == 0);
+        RETURN(0);
+}
+
+#ifdef __KERNEL__
+quota_interface_t mds_quota_interface = {
+        .quota_init     = mds_quota_init,
+        .quota_exit     = mds_quota_exit,
+        .quota_setup    = mds_quota_setup,
+        .quota_cleanup  = mds_quota_cleanup,
+        .quota_check    = target_quota_check,
+        .quota_ctl      = mds_quota_ctl,
+        .quota_fs_cleanup       =mds_quota_fs_cleanup,
+        .quota_recovery = mds_quota_recovery,
+        .quota_adjust   = mds_quota_adjust,
+};
+
+quota_interface_t filter_quota_interface = {
+        .quota_setup    = filter_quota_setup,
+        .quota_cleanup  = filter_quota_cleanup,
+        .quota_check    = target_quota_check,
+        .quota_ctl      = filter_quota_ctl,
+        .quota_setinfo  = filter_quota_setinfo,
+        .quota_enforce  = filter_quota_enforce,
+        .quota_getflag  = filter_quota_getflag,
+        .quota_acquire  = filter_quota_acquire,
+        .quota_adjust   = filter_quota_adjust,
+};
+#endif /* __KERNEL__ */
+
+quota_interface_t mdc_quota_interface = {
+        .quota_ctl      = client_quota_ctl,
+        .quota_check    = client_quota_check,
+        .quota_poll_check = client_quota_poll_check,
+};
+
+quota_interface_t osc_quota_interface = {
+        .quota_ctl      = client_quota_ctl,
+        .quota_check    = client_quota_check,
+        .quota_poll_check = client_quota_poll_check,
+        .quota_init     = osc_quota_init,
+        .quota_exit     = osc_quota_exit,
+        .quota_chkdq    = osc_quota_chkdq,
+        .quota_setdq    = osc_quota_setdq,
+        .quota_cleanup  = osc_quota_cleanup,
+};
+
+quota_interface_t lov_quota_interface = {
+        .quota_check    = lov_quota_check,
+        .quota_ctl      = lov_quota_ctl,
+};
+
+#ifdef __KERNEL__
+static int __init init_lustre_quota(void)
+{
+        int rc = qunit_cache_init();
+        if (rc)
+                return rc;
+        PORTAL_SYMBOL_REGISTER(filter_quota_interface);
+        PORTAL_SYMBOL_REGISTER(mds_quota_interface);
+        PORTAL_SYMBOL_REGISTER(mdc_quota_interface);
+        PORTAL_SYMBOL_REGISTER(osc_quota_interface);
+        PORTAL_SYMBOL_REGISTER(lov_quota_interface);
+        return 0;
+}
+
+static void /*__exit*/ exit_lustre_quota(void)
+{
+        PORTAL_SYMBOL_UNREGISTER(filter_quota_interface);
+        PORTAL_SYMBOL_UNREGISTER(mds_quota_interface);
+        PORTAL_SYMBOL_UNREGISTER(mdc_quota_interface);
+        PORTAL_SYMBOL_UNREGISTER(osc_quota_interface);
+        PORTAL_SYMBOL_UNREGISTER(lov_quota_interface);
+
+        qunit_cache_cleanup();
+}
+
+MODULE_AUTHOR("Cluster File Systems, Inc. <info@clusterfs.com>");
+MODULE_DESCRIPTION("Lustre Quota");
+MODULE_LICENSE("GPL");
+
+cfs_module(lquota, "1.0.0", init_lustre_quota, exit_lustre_quota);
+
+EXPORT_SYMBOL(mds_quota_interface);
+EXPORT_SYMBOL(filter_quota_interface);
+EXPORT_SYMBOL(mdc_quota_interface);
+EXPORT_SYMBOL(osc_quota_interface);
+EXPORT_SYMBOL(lov_quota_interface);
+#endif /* __KERNEL */
diff --git a/lustre/quota/quota_internal.h b/lustre/quota/quota_internal.h
new file mode 100644 (file)
index 0000000..0389734
--- /dev/null
@@ -0,0 +1,91 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ *
+ *  lustre/quota/quota_internal.h
+ *
+ *  Copyright (c) 2001-2005 Cluster File Systems, Inc.
+ *
+ *   This file is part of Lustre, http://www.lustre.org.
+ *
+ *   No redistribution or use is permitted outside of Cluster File Systems, Inc.
+ *
+ */
+
+#ifndef __QUOTA_INTERNAL_H
+#define __QUOTA_INTERNAL_H
+
+#include <linux/lustre_quota.h>
+
+/* QUSG covnert bytes to blocks when counting block quota */
+#define QUSG(count, isblk)      (isblk ? toqb(count) : count)
+
+/* This flag is set in qc_stat to distinguish if the current getquota 
+ * operation is for quota recovery */
+#define QUOTA_RECOVERING    0x01
+
+#ifdef __KERNEL__
+
+#define DQUOT_DEBUG(dquot, fmt, arg...)                                       \
+        CDEBUG(D_QUOTA, "refcnt(%u) id(%u) type(%u) off(%llu) flags(%lu) "    \
+               "bhardlimit(%u) curspace("LPX64") ihardlimit(%u) "             \
+               "curinodes(%u): " fmt, dquot->dq_refcnt,                       \
+               dquot->dq_id, dquot->dq_type, dquot->dq_off,  dquot->dq_flags, \
+               dquot->dq_dqb.dqb_bhardlimit, dquot->dq_dqb.dqb_curspace,      \
+               dquot->dq_dqb.dqb_ihardlimit, dquot->dq_dqb.dqb_curinodes,     \
+               ## arg);                                                       \
+
+#define QINFO_DEBUG(qinfo, fmt, arg...)                                       \
+        CDEBUG(D_QUOTA, "files (%p/%p) flags(%lu/%lu) blocks(%u/%u) "         \
+               "free_blk(/%u/%u) free_entry(%u/%u): " fmt,                    \
+               qinfo->qi_files[0], qinfo->qi_files[1],                        \
+               qinfo->qi_info[0].dqi_flags, qinfo->qi_info[1].dqi_flags,      \
+               qinfo->qi_info[0].dqi_blocks, qinfo->qi_info[1].dqi_blocks,    \
+               qinfo->qi_info[0].dqi_free_blk, qinfo->qi_info[1].dqi_free_blk,\
+               qinfo->qi_info[0].dqi_free_entry,                              \
+               qinfo->qi_info[1].dqi_free_entry, ## arg);
+
+/* quota_context.c */
+void qunit_cache_cleanup(void);
+int qunit_cache_init(void);
+int qctxt_adjust_qunit(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
+                       uid_t uid, gid_t gid, __u32 isblk, int wait);
+int qctxt_wait_pending_dqacq(struct lustre_quota_ctxt *qctxt, unsigned int id,
+                             unsigned short type, int isblk);
+int qctxt_init(struct lustre_quota_ctxt *qctxt, struct super_block *sb,
+               dqacq_handler_t handler);
+void qctxt_cleanup(struct lustre_quota_ctxt *qctxt, int force);
+void qslave_start_recovery(struct obd_device *obd, 
+                           struct lustre_quota_ctxt *qctxt);
+/* quota_master.c */
+int lustre_dquot_init(void);
+void lustre_dquot_exit(void);
+int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc);
+int mds_quota_adjust(struct obd_device *obd, unsigned int qcids[],
+                     unsigned int qpids[], int rc, int opc);
+int filter_quota_adjust(struct obd_device *obd, unsigned int qcids[],
+                        unsigned int qpids[], int rc, int opc);
+int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_admin_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_set_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_get_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_get_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl);
+int mds_quota_recovery(struct obd_device *obd);
+int mds_get_obd_quota(struct obd_device *obd, struct obd_quotactl *oqctl);
+#endif
+
+/* quota_ctl.c */
+int mds_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl);
+int filter_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl);
+int client_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl);
+int lov_quota_ctl(struct obd_export *exp, struct obd_quotactl *oqctl);
+
+/* quota_chk.c */
+int target_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl);
+int client_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl);
+int lov_quota_check(struct obd_export *exp, struct obd_quotactl *oqctl);
+int client_quota_poll_check(struct obd_export *exp, struct if_quotacheck *qchk);
+
+#endif
similarity index 56%
rename from lustre/mds/quota_master.c
rename to lustre/quota/quota_master.c
index 36c27e0..1a72640 100644 (file)
@@ -1,10 +1,10 @@
 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- *  lustre/mds/quota_master.c
+ *  lustre/quota/quota_master.c
  *  Lustre Quota Master request handler
  *
- *  Copyright (c) 2001-2003 Cluster File Systems, Inc.
+ *  Copyright (c) 2001-2005 Cluster File Systems, Inc.
  *   Author: Niu YaWei <niu@clusterfs.com>
  *
  *   This file is part of Lustre, http://www.lustre.org.
 #include <linux/lustre_fsfilt.h>
 #include <linux/lustre_mds.h>
 
-#include "mds_internal.h"
+#include "quota_internal.h"
 
+/* lock ordering: 
+ * mds->mds_qonoff_sem > dquot->dq_sem */
 static struct list_head lustre_dquot_hash[NR_DQHASH];
 static spinlock_t dquot_hash_lock = SPIN_LOCK_UNLOCKED;
 
@@ -67,8 +69,9 @@ void lustre_dquot_exit(void)
                 LASSERT(list_empty(lustre_dquot_hash + i));
         }
         if (lustre_dquot_cachep) {
-                LASSERTF(kmem_cache_destroy(lustre_dquot_cachep) == 0,
-                         "Cannot destroy lustre_dquot_cache\n");
+                int rc;
+                rc = kmem_cache_destroy(lustre_dquot_cachep);
+                LASSERT(rc == 0);
                 lustre_dquot_cachep = NULL;
         }
         EXIT;
@@ -82,17 +85,16 @@ static inline int const dquot_hashfn(struct lustre_quota_info *info,
         return tmp;
 }
 
+/* caller must hold dquot_hash_lock */
 static struct lustre_dquot *find_dquot(int hashent,
                                        struct lustre_quota_info *lqi, qid_t id,
                                        int type)
 {
-        struct list_head *head;
         struct lustre_dquot *dquot;
         ENTRY;
 
-        for (head = lustre_dquot_hash[hashent].next;
-             head != lustre_dquot_hash + hashent; head = head->next) {
-                dquot = list_entry(head, struct lustre_dquot, dq_hash);
+        LASSERT_SPIN_LOCKED(&dquot_hash_lock);
+        list_for_each_entry(dquot, &lustre_dquot_hash[hashent], dq_hash) {
                 if (dquot->dq_info == lqi &&
                     dquot->dq_id == id && dquot->dq_type == type)
                         RETURN(dquot);
@@ -111,12 +113,12 @@ static struct lustre_dquot *alloc_dquot(struct lustre_quota_info *lqi,
                 RETURN(NULL);
 
         INIT_LIST_HEAD(&dquot->dq_hash);
-        INIT_LIST_HEAD(&dquot->dq_unused);
-        sema_init(&dquot->dq_sem, 1);
-        atomic_set(&dquot->dq_refcnt, 1);
+        init_mutex_locked(&dquot->dq_sem);
+        dquot->dq_refcnt = 1;
         dquot->dq_info = lqi;
         dquot->dq_id = id;
         dquot->dq_type = type;
+        dquot->dq_status = DQ_STATUS_AVAIL;
 
         RETURN(dquot);
 }
@@ -130,6 +132,7 @@ static void insert_dquot_nolock(struct lustre_dquot *dquot)
 {
         struct list_head *head = lustre_dquot_hash +
             dquot_hashfn(dquot->dq_info, dquot->dq_id, dquot->dq_type);
+        LASSERT(list_empty(&dquot->dq_hash));
         list_add(&dquot->dq_hash, head);
 }
 
@@ -143,8 +146,9 @@ static void lustre_dqput(struct lustre_dquot *dquot)
 {
         ENTRY;
         spin_lock(&dquot_hash_lock);
-        LASSERT(atomic_read(&dquot->dq_refcnt));
-        if (atomic_dec_and_test(&dquot->dq_refcnt)) {
+        LASSERT(dquot->dq_refcnt);
+        dquot->dq_refcnt--;
+        if (!dquot->dq_refcnt) {
                 remove_dquot_nolock(dquot);
                 free_dquot(dquot);
         }
@@ -152,64 +156,41 @@ static void lustre_dqput(struct lustre_dquot *dquot)
         EXIT;
 }
 
-#define DQUOT_DEBUG(dquot, fmt, arg...)                                       \
-        CDEBUG(D_QUOTA, "refcnt(%u) id(%u) type(%u) off(%llu) flags(%lu) " \
-               "bhardlimit(%u) curspace("LPX64") ihardlimit(%u) "             \
-               "curinodes(%u): " fmt, atomic_read(&dquot->dq_refcnt),         \
-               dquot->dq_id, dquot->dq_type, dquot->dq_off,  dquot->dq_flags, \
-               dquot->dq_dqb.dqb_bhardlimit, dquot->dq_dqb.dqb_curspace,      \
-               dquot->dq_dqb.dqb_ihardlimit, dquot->dq_dqb.dqb_curinodes,     \
-               ## arg);                                                       \
-
-#define QINFO_DEBUG(qinfo, fmt, arg...)                                       \
-        CDEBUG(D_QUOTA, "files (%p/%p) flags(%lu/%lu) blocks(%u/%u) "         \
-               "free_blk(/%u/%u) free_entry(%u/%u): " fmt,                    \
-               qinfo->qi_files[0], qinfo->qi_files[1],                        \
-               qinfo->qi_info[0].dqi_flags, qinfo->qi_info[1].dqi_flags,      \
-               qinfo->qi_info[0].dqi_blocks, qinfo->qi_info[1].dqi_blocks,    \
-               qinfo->qi_info[0].dqi_free_blk, qinfo->qi_info[1].dqi_free_blk,\
-               qinfo->qi_info[0].dqi_free_entry,                              \
-               qinfo->qi_info[1].dqi_free_entry, ## arg);
-
 static struct lustre_dquot *lustre_dqget(struct obd_device *obd,
                                          struct lustre_quota_info *lqi,
                                          qid_t id, int type)
 {
         unsigned int hashent = dquot_hashfn(lqi, id, type);
-        struct lustre_dquot *dquot = NULL;
-        int read = 0;
+        struct lustre_dquot *dquot, *empty;
         ENTRY;
 
+        if ((empty = alloc_dquot(lqi, id, type)) == NULL)
+                RETURN(ERR_PTR(-ENOMEM));
+        
         spin_lock(&dquot_hash_lock);
         if ((dquot = find_dquot(hashent, lqi, id, type)) != NULL) {
-                atomic_inc(&dquot->dq_refcnt);
+                dquot->dq_refcnt++;
+                spin_unlock(&dquot_hash_lock);
+                free_dquot(empty);
         } else {
-                dquot = alloc_dquot(lqi, id, type);
-                if (dquot) {
-                        insert_dquot_nolock(dquot);
-                        read = 1;
-                }
-        }
-        spin_unlock(&dquot_hash_lock);
-
-        if (dquot == NULL)
-                RETURN(ERR_PTR(-ENOMEM));
+                int rc;
 
-        if (read) {
-                int rc = 0;
+                dquot = empty;
+                insert_dquot_nolock(dquot);
+                spin_unlock(&dquot_hash_lock);
 
-                down(&dquot->dq_info->qi_sem);
-                down(&dquot->dq_sem);
                 rc = fsfilt_dquot(obd, dquot, QFILE_RD_DQUOT);
                 up(&dquot->dq_sem);
-                up(&dquot->dq_info->qi_sem);
                 if (rc) {
-                        CERROR("can't read dquot from admin qutoafile! "
+                        CERROR("can't read dquot from admin quotafile! "
                                "(rc:%d)\n", rc);
                         lustre_dqput(dquot);
                         RETURN(ERR_PTR(rc));
                 }
+
         }
+
+        LASSERT(dquot);
         RETURN(dquot);
 }
 
@@ -225,6 +206,8 @@ int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc)
         int rc = 0;
         ENTRY;
 
+        OBD_FAIL_RETURN(OBD_FAIL_OBD_DQACQ, -EIO);
+
         /* slaves never acquires qunit for user root */
         LASSERT(qdata->qd_id || qdata->qd_type == GRPQUOTA);
 
@@ -235,9 +218,14 @@ int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc)
         DQUOT_DEBUG(dquot, "get dquot in dqacq_handler\n");
         QINFO_DEBUG(dquot->dq_info, "get dquot in dqadq_handler\n");
 
-        down(&dquot->dq_info->qi_sem);
+        down(&mds->mds_qonoff_sem);
         down(&dquot->dq_sem);
 
+        if (dquot->dq_status & DQ_STATUS_RECOVERY) {
+                DQUOT_DEBUG(dquot, "this dquot is under recovering.\n");
+                GOTO(out, rc = -EBUSY);
+        }
+
         if (qdata->qd_isblk) {
                 grace = info->qi_info[qdata->qd_type].dqi_bgrace;
                 usage = &dquot->dq_dqb.dqb_curspace;
@@ -250,7 +238,7 @@ int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc)
                 hlimit = dquot->dq_dqb.dqb_ihardlimit;
                 slimit = dquot->dq_dqb.dqb_isoftlimit;
                 time = &dquot->dq_dqb.dqb_itime;
-        } 
+        }
 
         /* if the quota limit in admin quotafile is zero, we just inform
          * slave to clear quota limit with zero qd_count */
@@ -258,63 +246,126 @@ int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc)
                 qdata->qd_count = 0;
                 GOTO(out, rc);
         }
-        
-        if (opc == QUOTA_DQACQ) {
+
+        switch (opc) {
+        case QUOTA_DQACQ:
                 if (hlimit && 
                     QUSG(*usage + qdata->qd_count, qdata->qd_isblk) > hlimit)
                         GOTO(out, rc = -EDQUOT);
 
                 if (slimit &&
                     QUSG(*usage + qdata->qd_count, qdata->qd_isblk) > slimit) {
-                        if (*time && CURRENT_SECONDS >= *time)
+                        if (*time && cfs_time_current_sec() >= *time)
                                 GOTO(out, rc = -EDQUOT);
                         else if (!*time)
-                                *time = CURRENT_SECONDS + grace;
+                                *time = cfs_time_current_sec() + grace;
                 }
 
                 *usage += qdata->qd_count;
-                
-        } else if (opc == QUOTA_DQREL) {
-                LASSERT(*usage - qdata->qd_count >= 0);
-                *usage -= qdata->qd_count;
+                break;
+        case QUOTA_DQREL:
+                /* The usage in administrative file might be incorrect before
+                 * recovery done */
+                if (*usage - qdata->qd_count < 0)
+                        *usage = 0;
+                else
+                        *usage -= qdata->qd_count;
 
                 /* (usage <= soft limit) but not (usage < soft limit) */
                 if (!slimit || QUSG(*usage, qdata->qd_isblk) <= slimit)
                         *time = 0;
-        } else {
+                break;
+        default:
                 LBUG();
         }
 
         rc = fsfilt_dquot(obd, dquot, QFILE_WR_DQUOT);
+        EXIT;
 out:
         up(&dquot->dq_sem);
-        up(&dquot->dq_info->qi_sem);
+        up(&mds->mds_qonoff_sem);
         lustre_dqput(dquot);
-        RETURN(rc);
+        return rc;
 }
 
-void mds_adjust_qunit(struct obd_device *obd, uid_t cuid, gid_t cgid,
-                      uid_t puid, gid_t pgid, int rc)
+int mds_quota_adjust(struct obd_device *obd, unsigned int qcids[],
+                     unsigned int qpids[], int rc, int opc)
 {
-        struct mds_obd *mds = &obd->u.mds;
-        struct lustre_quota_ctxt *qctxt = &mds->mds_quota_ctxt;
+        struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
+        int rc2 = 0;
         ENTRY;
 
-        if (rc && rc != -EDQUOT) {
-                EXIT;
-                return;
+        if (rc && rc != -EDQUOT)
+                RETURN(0);
+
+        switch (opc) {
+        case FSFILT_OP_RENAME:
+                /* acquire/release block quota on owner of original parent */
+                rc = qctxt_adjust_qunit(obd, qctxt, qpids[2], qpids[3], 1, 0);
+                /* fall-through */
+        case FSFILT_OP_CREATE:
+        case FSFILT_OP_UNLINK:
+                /* acquire/release file quota on owner of child, acquire/release
+                 * block quota on owner of parent */
+                rc = qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 0, 0);
+                rc2 = qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 1, 0);
+                break;
+        case FSFILT_OP_SETATTR:
+                /* acquire/release file quota on original & current owner 
+                 * of child*/
+                rc = qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 0, 0);
+                rc2 = qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 0, 0);
+                break;
+        default:
+                LBUG();
+                break;
         }
-        /* dqacq/dqrel file quota on owner of child */
-        rc = qctxt_adjust_qunit(obd, qctxt, cuid, cgid, 0);
-        if (rc)
-                CERROR("error mds adjust child qunit! (rc:%d)\n", rc);
-        /* dqacq/dqrel block quota on owner of parent directory */
-        rc = qctxt_adjust_qunit(obd, qctxt, puid, pgid, 1);
-        if (rc)
-                CERROR("error mds adjust parent qunit! (rc:%d)\n", rc);
-        EXIT;
+
+        if (rc || rc2)
+                CERROR("mds adjust qunit failed! (opc:%d rc:%d)\n", 
+                       opc, rc ?: rc2);
+        RETURN(0);
 }
 
+int filter_quota_adjust(struct obd_device *obd, unsigned int qcids[],
+                        unsigned int qpids[], int rc, int opc)
+{
+        struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
+        int rc2 = 0;
+        ENTRY;
+
+        if (rc && rc != -EDQUOT)
+                RETURN(0);
+
+        switch (opc) {
+        case FSFILT_OP_SETATTR:
+                /* acquire/release block quota on original & current owner */
+                rc = qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 1, 0);
+                rc2 = qctxt_adjust_qunit(obd, qctxt, qpids[0], qpids[1], 1, 0);
+                break;
+        case FSFILT_OP_UNLINK:
+                /* release block quota on this owner */
+        case FSFILT_OP_CREATE: /* XXX for write operation on obdfilter */
+                /* acquire block quota on this owner */
+                rc = qctxt_adjust_qunit(obd, qctxt, qcids[0], qcids[1], 1, 0);
+                break;
+        default:
+                LBUG();
+                break;
+        }
+
+        if (rc || rc2)
+                CERROR("filter adjust qunit failed! (opc:%d rc%d)\n",
+                       opc, rc ?: rc2);
+        RETURN(0);
+}
+
+#define LUSTRE_ADMIN_QUOTAFILES {\
+       "admin_quotafile.usr",  /* user admin quotafile */\
+       "admin_quotafile.grp"   /* group admin quotafile */\
+}
+static const char prefix[] = "OBJECTS/";
+
 int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl)
 {
         struct mds_obd *mds = &obd->u.mds;
@@ -330,10 +381,10 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl)
         LASSERT(iparent);
         push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
 
-        down(&qinfo->qi_sem);
+        down(&mds->mds_qonoff_sem);
         for (i = 0; i < MAXQUOTAS; i++) {
-                struct dentry *de = NULL;
-                struct file *fp = NULL;
+                struct dentry *de;
+                struct file *fp;
 
                 if (!Q_TYPESET(oqctl, i))
                         continue;
@@ -348,14 +399,14 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl)
                 /* lookup quota file */
                 rc = 0;
                 down(&iparent->i_sem);
-
                 de = lookup_one_len(quotafiles[i], dparent,
                                     strlen(quotafiles[i]));
-                if (IS_ERR(de) || de->d_inode == NULL)
+                up(&iparent->i_sem);
+                if (IS_ERR(de) || de->d_inode == NULL || 
+                    !S_ISREG(de->d_inode->i_mode))
                         rc = IS_ERR(de) ? PTR_ERR(de) : -ENOENT;
                 if (!IS_ERR(de))
                         dput(de);
-                up(&iparent->i_sem);
 
                 if (rc && rc != -ENOENT) {
                         CERROR("error lookup quotafile %s! (rc:%d)\n",
@@ -365,12 +416,13 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl)
                         continue;
                 }
 
-                sprintf(name, "OBJECTS/%s", quotafiles[i]);
+                LASSERT(strlen(quotafiles[i]) + sizeof(prefix) <= sizeof(name));
+                sprintf(name, "%s%s", prefix, quotafiles[i]);
 
                 LASSERT(rc == -ENOENT);
                 /* create quota file */
                 fp = filp_open(name, O_CREAT | O_EXCL, 0644);
-                if (IS_ERR(fp)) {
+                if (IS_ERR(fp) || !S_ISREG(fp->f_dentry->d_inode->i_mode)) {
                         rc = PTR_ERR(fp);
                         CERROR("error creating admin quotafile %s (rc:%d)\n",
                                name, rc);
@@ -378,7 +430,7 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl)
                 }
 
                 qinfo->qi_files[i] = fp;
-                rc = fsfilt_quotainfo(obd, qinfo, i, QFILE_INIT_INFO);
+                rc = fsfilt_quotainfo(obd, qinfo, i, QFILE_INIT_INFO, NULL);
                 filp_close(fp, 0);
                 qinfo->qi_files[i] = NULL;
 
@@ -388,35 +440,52 @@ int init_admin_quotafiles(struct obd_device *obd, struct obd_quotactl *oqctl)
                         break;
                 }
         }
-        up(&qinfo->qi_sem);
+        up(&mds->mds_qonoff_sem);
 
         pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
         RETURN(rc);
 }
 
-int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl)
+static int close_quota_files(struct obd_quotactl *oqctl, 
+                             struct lustre_quota_info *qinfo)
+{
+        int i, rc = 0;
+        ENTRY;
+
+        for (i = 0; i < MAXQUOTAS; i++) {
+                if (!Q_TYPESET(oqctl, i))
+                        continue;
+                if (qinfo->qi_files[i] == NULL) {
+                        rc = -ESRCH;
+                        continue;
+                }
+                filp_close(qinfo->qi_files[i], 0);
+                qinfo->qi_files[i] = NULL;
+        }
+        RETURN(rc);
+}
+
+int mds_admin_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl)
 {
         struct mds_obd *mds = &obd->u.mds;
         struct lustre_quota_info *qinfo = &mds->mds_quota_info;
         const char *quotafiles[] = LUSTRE_ADMIN_QUOTAFILES;
-        struct lvfs_run_ctxt saved;
         char name[64];
         int i, rc = 0;
         struct inode *iparent = mds->mds_objects_dir->d_inode;
         ENTRY;
 
         LASSERT(iparent);
-        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
 
-        down(&qinfo->qi_sem);
         /* open admin quota files and read quotafile info */
         for (i = 0; i < MAXQUOTAS; i++) {
-                struct file *fp = NULL;
+                struct file *fp;
 
                 if (!Q_TYPESET(oqctl, i))
                         continue;
 
-                sprintf(name, "OBJECTS/%s", quotafiles[i]);
+                LASSERT(strlen(quotafiles[i]) + sizeof(prefix) <= sizeof(name));
+                sprintf(name, "%s%s", prefix, quotafiles[i]);
 
                 if (qinfo->qi_files[i] != NULL) {
                         rc = -EBUSY;
@@ -424,82 +493,106 @@ int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl)
                 }
 
                 fp = filp_open(name, O_RDWR | O_EXCL, 0644);
-                if (IS_ERR(fp)) {
+                if (IS_ERR(fp) || !S_ISREG(fp->f_dentry->d_inode->i_mode)) {
                         rc = PTR_ERR(fp);
                         CERROR("error open %s! (rc:%d)\n", name, rc);
                         break;
                 }
                 qinfo->qi_files[i] = fp;
 
-                rc = fsfilt_quotainfo(obd, qinfo, i, QFILE_RD_INFO);
+                rc = fsfilt_quotainfo(obd, qinfo, i, QFILE_RD_INFO, NULL);
                 if (rc) {
                         CERROR("error read quotainfo of %s! (rc:%d)\n",
                                name, rc);
                         break;
                 }
         }
-        up(&qinfo->qi_sem);
 
-        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+        if (rc && rc != -EBUSY)
+                close_quota_files(oqctl, qinfo);
 
-        if (rc && rc != -EBUSY) {
-                down(&qinfo->qi_sem);
-                for (i = 0; i < MAXQUOTAS; i++) {
-                        if (!Q_TYPESET(oqctl, i))
-                                continue;
-                        if (qinfo->qi_files[i])
-                                filp_close(qinfo->qi_files[i], 0);
-                        qinfo->qi_files[i] = NULL;
-                }
-                up(&qinfo->qi_sem);
-        }
         RETURN(rc);
 }
 
-int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl)
+static int mds_admin_quota_off(struct obd_device *obd, 
+                               struct obd_quotactl *oqctl)
 {
         struct mds_obd *mds = &obd->u.mds;
         struct lustre_quota_info *qinfo = &mds->mds_quota_info;
-        int i, rc = 0;
+        int rc;
         ENTRY;
 
-        down(&qinfo->qi_sem);
         /* close admin quota files */
-        for (i = 0; i < MAXQUOTAS; i++) {
-                if (!Q_TYPESET(oqctl, i))
-                        continue;
+        rc = close_quota_files(oqctl, qinfo);
+        RETURN(rc);
+}
 
-                if (qinfo->qi_files[i] == NULL) {
-                        rc = -ESRCH;
-                        continue;
-                }
-                filp_close(qinfo->qi_files[i], 0);
-                qinfo->qi_files[i] = NULL;
-        }
-        up(&qinfo->qi_sem);
+int mds_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl)
+{
+        struct mds_obd *mds = &obd->u.mds;
+        struct lvfs_run_ctxt saved;
+        int rc;
+        ENTRY;
+
+        down(&mds->mds_qonoff_sem);
+        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+        rc = mds_admin_quota_on(obd, oqctl);
+        if (rc)
+                goto out;
 
+        rc = obd_quotactl(mds->mds_osc_exp, oqctl);
+        if (rc)
+                goto out;
+
+        rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+out:
+        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+        up(&mds->mds_qonoff_sem);
         RETURN(rc);
 }
 
+int mds_quota_off(struct obd_device *obd, struct obd_quotactl *oqctl)
+{
+        struct mds_obd *mds = &obd->u.mds;
+        struct lvfs_run_ctxt saved;
+        int rc, rc2;
+        ENTRY;
+
+        down(&mds->mds_qonoff_sem);
+        /* close admin quota files */
+        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+        mds_admin_quota_off(obd, oqctl);
+
+        rc = obd_quotactl(mds->mds_osc_exp, oqctl);
+        rc2 = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+
+        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+        up(&mds->mds_qonoff_sem);
+        RETURN(rc ?: rc2);
+}
+
 int mds_set_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl)
 {
         struct mds_obd *mds = &obd->u.mds;
         struct lustre_quota_info *qinfo = &mds->mds_quota_info;
         struct obd_dqinfo *dqinfo = &oqctl->qc_dqinfo;
-        int rc = 0;
+        int rc;
         ENTRY;
 
-        if (qinfo->qi_files[oqctl->qc_type] == NULL)
-                RETURN(-ESRCH);
+        down(&mds->mds_qonoff_sem);
+        if (qinfo->qi_files[oqctl->qc_type] == NULL) {
+                rc = -ESRCH;
+                goto out;
+        }
 
-        down(&qinfo->qi_sem);
         qinfo->qi_info[oqctl->qc_type].dqi_bgrace = dqinfo->dqi_bgrace;
         qinfo->qi_info[oqctl->qc_type].dqi_igrace = dqinfo->dqi_igrace;
         qinfo->qi_info[oqctl->qc_type].dqi_flags = dqinfo->dqi_flags;
 
-        rc = fsfilt_quotainfo(obd, qinfo, oqctl->qc_type, QFILE_WR_INFO);
-        up(&qinfo->qi_sem);
+        rc = fsfilt_quotainfo(obd, qinfo, oqctl->qc_type, QFILE_WR_INFO, NULL);
 
+out:
+        up(&mds->mds_qonoff_sem);
         RETURN(rc);
 }
 
@@ -508,25 +601,28 @@ int mds_get_dqinfo(struct obd_device *obd, struct obd_quotactl *oqctl)
         struct mds_obd *mds = &obd->u.mds;
         struct lustre_quota_info *qinfo = &mds->mds_quota_info;
         struct obd_dqinfo *dqinfo = &oqctl->qc_dqinfo;
+        int rc = 0;
         ENTRY;
 
-        if (qinfo->qi_files[oqctl->qc_type] == NULL)
-                RETURN(-ESRCH);
+        down(&mds->mds_qonoff_sem);
+        if (qinfo->qi_files[oqctl->qc_type] == NULL) {
+                rc = -ESRCH;
+                goto out;
+        }
 
-        down(&qinfo->qi_sem);
         dqinfo->dqi_bgrace = qinfo->qi_info[oqctl->qc_type].dqi_bgrace;
         dqinfo->dqi_igrace = qinfo->qi_info[oqctl->qc_type].dqi_igrace;
         dqinfo->dqi_flags = qinfo->qi_info[oqctl->qc_type].dqi_flags;
-        up(&qinfo->qi_sem);
 
-        RETURN(0);
+out:
+        up(&mds->mds_qonoff_sem);
+        RETURN(rc);
 }
 
 static int mds_init_slave_ilimits(struct obd_device *obd,
                                   struct obd_quotactl *oqctl)
 {
         /* XXX: for file limits only adjust local now */
-        struct mds_obd *mds = &obd->u.mds;
         unsigned int uid = 0, gid = 0;
         struct obd_quotactl *ioqc;
         int rc;
@@ -536,18 +632,18 @@ static int mds_init_slave_ilimits(struct obd_device *obd,
         if (!oqctl->qc_dqblk.dqb_ihardlimit && !oqctl->qc_dqblk.dqb_isoftlimit)
                 RETURN(0);
 
-        OBD_ALLOC(ioqc, sizeof(*ioqc));
+        OBD_ALLOC_PTR(ioqc);
         if (!ioqc)
                 RETURN(-ENOMEM);
 
-        ioqc->qc_cmd = Q_SETQUOTA;
+        ioqc->qc_cmd = Q_INITQUOTA;
         ioqc->qc_id = oqctl->qc_id;
         ioqc->qc_type = oqctl->qc_type;
         ioqc->qc_dqblk.dqb_valid = QIF_ILIMITS;
         ioqc->qc_dqblk.dqb_ihardlimit = MIN_QLIMIT;
 
         /* set local limit to MIN_QLIMIT */
-        rc = fsfilt_quotactl(obd, mds->mds_sb, ioqc);
+        rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, ioqc);
         if (rc)
                 GOTO(out, rc);
 
@@ -557,15 +653,16 @@ static int mds_init_slave_ilimits(struct obd_device *obd,
         else
                 gid = oqctl->qc_id;
 
-        rc = qctxt_adjust_qunit(obd, &mds->mds_quota_ctxt, uid, gid, 0);
+        rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt, uid, gid, 0, 0);
         if (rc) {
                 CERROR("error mds adjust local file quota! (rc:%d)\n", rc);
                 GOTO(out, rc);
         }
         /* FIXME initialize all slaves in CMD */
+        EXIT;
 out:
-        OBD_FREE(ioqc, sizeof(*ioqc));
-        RETURN(rc);
+        OBD_FREE_PTR(ioqc);
+        return rc;
 }
 
 static int mds_init_slave_blimits(struct obd_device *obd,
@@ -581,18 +678,18 @@ static int mds_init_slave_blimits(struct obd_device *obd,
         if (!oqctl->qc_dqblk.dqb_bhardlimit && !oqctl->qc_dqblk.dqb_bsoftlimit)
                 RETURN(0);
 
-        OBD_ALLOC(ioqc, sizeof(*ioqc));
+        OBD_ALLOC_PTR(ioqc);
         if (!ioqc)
                 RETURN(-ENOMEM);
 
-        ioqc->qc_cmd = Q_SETQUOTA;
+        ioqc->qc_cmd = Q_INITQUOTA;
         ioqc->qc_id = oqctl->qc_id;
         ioqc->qc_type = oqctl->qc_type;
         ioqc->qc_dqblk.dqb_valid = QIF_BLIMITS;
         ioqc->qc_dqblk.dqb_bhardlimit = MIN_QLIMIT;
 
         /* set local limit to MIN_QLIMIT */
-        rc = fsfilt_quotactl(obd, mds->mds_sb, ioqc);
+        rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, ioqc);
         if (rc)
                 GOTO(out, rc);
 
@@ -602,18 +699,18 @@ static int mds_init_slave_blimits(struct obd_device *obd,
         else
                 gid = oqctl->qc_id;
 
-        rc = qctxt_adjust_qunit(obd, &mds->mds_quota_ctxt, uid, gid, 1);
+        rc = qctxt_adjust_qunit(obd, &obd->u.obt.obt_qctxt, uid, gid, 1, 0);
         if (rc) {
                 CERROR("error mds adjust local block quota! (rc:%d)\n", rc);
                 GOTO(out, rc);
         }
 
         /* initialize all slave's limit */
-        ioqc->qc_cmd = Q_INITQUOTA;
         rc = obd_quotactl(mds->mds_osc_exp, ioqc);
+        EXIT;
 out:
-        OBD_FREE(ioqc, sizeof(*ioqc));
-        RETURN(rc);
+        OBD_FREE_PTR(ioqc);
+        return rc;
 }
 
 int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
@@ -624,21 +721,28 @@ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
         time_t btime, itime;
         struct lustre_dquot *dquot;
         struct obd_dqblk *dqblk = &oqctl->qc_dqblk;
-        int rc = 0;
+        int rc;
         ENTRY;
 
+        down(&mds->mds_qonoff_sem);
         if (qinfo->qi_files[oqctl->qc_type] == NULL)
-                RETURN(-ESRCH);
+                GOTO(out_sem, rc = -ESRCH);
 
         dquot = lustre_dqget(obd, qinfo, oqctl->qc_id, oqctl->qc_type);
         if (IS_ERR(dquot))
-                RETURN(PTR_ERR(dquot));
+                GOTO(out_sem, rc = PTR_ERR(dquot));
         DQUOT_DEBUG(dquot, "get dquot in mds_set_blk\n");
         QINFO_DEBUG(dquot->dq_info, "get dquot in mds_set_blk\n");
 
-        down(&dquot->dq_info->qi_sem);
         down(&dquot->dq_sem);
 
+        if (dquot->dq_status) {
+                up(&dquot->dq_sem);
+                lustre_dqput(dquot);
+                GOTO(out_sem, rc = -EBUSY);
+        }
+        dquot->dq_status |= DQ_STATUS_SET;
+
         ihardlimit = dquot->dq_dqb.dqb_ihardlimit;
         isoftlimit = dquot->dq_dqb.dqb_isoftlimit;
         bhardlimit = dquot->dq_dqb.dqb_bhardlimit;
@@ -646,6 +750,11 @@ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
         btime = dquot->dq_dqb.dqb_btime;
         itime = dquot->dq_dqb.dqb_itime;
 
+        if (dqblk->dqb_valid & QIF_BTIME)
+                dquot->dq_dqb.dqb_btime = dqblk->dqb_btime;
+        if (dqblk->dqb_valid & QIF_ITIME)
+                dquot->dq_dqb.dqb_itime = dqblk->dqb_itime;
+
         if (dqblk->dqb_valid & QIF_BLIMITS) {
                 dquot->dq_dqb.dqb_bhardlimit = dqblk->dqb_bhardlimit;
                 dquot->dq_dqb.dqb_bsoftlimit = dqblk->dqb_bsoftlimit;
@@ -653,6 +762,15 @@ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
                 if (!dquot->dq_dqb.dqb_bhardlimit && 
                     !dquot->dq_dqb.dqb_bsoftlimit)
                         dquot->dq_dqb.dqb_curspace = 0;
+
+                /* clear grace time */
+                if (!dqblk->dqb_bsoftlimit || 
+                    toqb(dquot->dq_dqb.dqb_curspace) <= dqblk->dqb_bsoftlimit)
+                        dquot->dq_dqb.dqb_btime = 0;
+                /* set grace only if user hasn't provided his own */
+                else if (!(dqblk->dqb_valid & QIF_BTIME))
+                        dquot->dq_dqb.dqb_btime = cfs_time_current_sec() + 
+                                qinfo->qi_info[dquot->dq_type].dqi_bgrace;
         }
 
         if (dqblk->dqb_valid & QIF_ILIMITS) {
@@ -662,27 +780,30 @@ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
                 if (!dquot->dq_dqb.dqb_ihardlimit &&
                     !dquot->dq_dqb.dqb_isoftlimit)
                         dquot->dq_dqb.dqb_curinodes = 0;
-        }
 
-        if (dqblk->dqb_valid & QIF_BTIME)
-                dquot->dq_dqb.dqb_btime = dqblk->dqb_btime;
-
-        if (dqblk->dqb_valid & QIF_ITIME)
-                dquot->dq_dqb.dqb_itime = dqblk->dqb_itime;
+                if (!dqblk->dqb_isoftlimit ||
+                    dquot->dq_dqb.dqb_curinodes <= dqblk->dqb_isoftlimit)
+                        dquot->dq_dqb.dqb_itime = 0;
+                else if (!(dqblk->dqb_valid & QIF_ITIME))
+                        dquot->dq_dqb.dqb_itime = cfs_time_current_sec() +
+                                qinfo->qi_info[dquot->dq_type].dqi_igrace;
+        }
 
         rc = fsfilt_dquot(obd, dquot, QFILE_WR_DQUOT);
 
         up(&dquot->dq_sem);
-        up(&dquot->dq_info->qi_sem);
 
-        if (rc)
-                GOTO(out, rc);
+        if (rc) {
+                CERROR("set limit failed! (rc:%d)\n", rc);
+                goto out;
+        }
 
+        up(&mds->mds_qonoff_sem);
         if (dqblk->dqb_valid & QIF_ILIMITS && !(ihardlimit || isoftlimit)) {
                 rc = mds_init_slave_ilimits(obd, oqctl);
                 if (rc) {
                         CERROR("init slave ilimits failed! (rc:%d)\n", rc);
-                        GOTO(revoke_out, rc);
+                        goto revoke_out;
                 }
         }
 
@@ -690,14 +811,14 @@ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
                 rc = mds_init_slave_blimits(obd, oqctl);
                 if (rc) {
                         CERROR("init slave blimits failed! (rc:%d)\n", rc);
-                        GOTO(revoke_out, rc);
+                        goto revoke_out;
                 }
         }
+        down(&mds->mds_qonoff_sem);
 
 revoke_out:
         if (rc) {
                 /* cancel previous setting */
-                down(&dquot->dq_info->qi_sem);
                 down(&dquot->dq_sem);
                 dquot->dq_dqb.dqb_ihardlimit = ihardlimit;
                 dquot->dq_dqb.dqb_isoftlimit = isoftlimit;
@@ -707,31 +828,52 @@ revoke_out:
                 dquot->dq_dqb.dqb_itime = itime;
                 fsfilt_dquot(obd, dquot, QFILE_WR_DQUOT);
                 up(&dquot->dq_sem);
-                up(&dquot->dq_info->qi_sem);
         }
 out:
+        down(&dquot->dq_sem);
+        dquot->dq_status &= ~DQ_STATUS_SET;
+        up(&dquot->dq_sem);
         lustre_dqput(dquot);
-        RETURN(rc);
+        EXIT;
+out_sem:
+        up(&mds->mds_qonoff_sem);
+        return rc;
 }
 
 static int mds_get_space(struct obd_device *obd, struct obd_quotactl *oqctl)
 {
         struct obd_quotactl *soqc;
+        struct lvfs_run_ctxt saved;
         int rc;
+        ENTRY;
 
-        OBD_ALLOC(soqc, sizeof(*soqc));
+        OBD_ALLOC_PTR(soqc);
         if (!soqc)
                 RETURN(-ENOMEM);
 
-        soqc->qc_cmd = oqctl->qc_cmd;
+        soqc->qc_cmd = Q_GETOQUOTA;
         soqc->qc_id = oqctl->qc_id;
         soqc->qc_type = oqctl->qc_type;
 
         rc = obd_quotactl(obd->u.mds.mds_osc_exp, soqc);
+        if (rc)
+               GOTO(out, rc);
 
         oqctl->qc_dqblk.dqb_curspace = soqc->qc_dqblk.dqb_curspace;
 
-        OBD_FREE(soqc, sizeof(*soqc));
+        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+        soqc->qc_dqblk.dqb_curspace = 0;
+        rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, soqc);
+        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+        if (rc)
+                GOTO(out, rc);
+
+        oqctl->qc_dqblk.dqb_curinodes += soqc->qc_dqblk.dqb_curinodes;
+        oqctl->qc_dqblk.dqb_curspace += soqc->qc_dqblk.dqb_curspace;
+        EXIT;
+out:
+        OBD_FREE_PTR(soqc);
         return rc;
 }
 
@@ -744,12 +886,13 @@ int mds_get_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
         int rc;
         ENTRY;
 
+        down(&mds->mds_qonoff_sem);
         if (qinfo->qi_files[oqctl->qc_type] == NULL)
-                RETURN(-ESRCH);
+                GOTO(out, rc = -ESRCH);
 
         dquot = lustre_dqget(obd, qinfo, oqctl->qc_id, oqctl->qc_type);
         if (IS_ERR(dquot))
-                RETURN(PTR_ERR(dquot));
+                GOTO(out, rc = PTR_ERR(dquot));
 
         down(&dquot->dq_sem);
         dqblk->dqb_ihardlimit = dquot->dq_dqb.dqb_ihardlimit;
@@ -760,11 +903,190 @@ int mds_get_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
         dqblk->dqb_itime = dquot->dq_dqb.dqb_itime;
         up(&dquot->dq_sem);
 
+        lustre_dqput(dquot);
+
         /* the usages in admin quota file is inaccurate */
         dqblk->dqb_curinodes = 0;
         dqblk->dqb_curspace = 0;
         rc = mds_get_space(obd, oqctl);
+        EXIT;
+out:
+        up(&mds->mds_qonoff_sem);
+        return rc;
+}
+
+int mds_get_obd_quota(struct obd_device *obd, struct obd_quotactl *oqctl)
+{
+        struct lvfs_run_ctxt saved;
+        int rc;
+        ENTRY;
+
+        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+        rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+
+        RETURN(rc);
+}
+
+
+/* FIXME we only recovery block limit by now, need recovery inode
+ * limits also after CMD involved in */
+static int 
+dquot_recovery(struct obd_device *obd, unsigned int id, unsigned short type)
+{
+        struct mds_obd *mds = &obd->u.mds;
+        struct lustre_quota_info *qinfo= &obd->u.mds.mds_quota_info;
+        struct lustre_dquot *dquot;
+        struct obd_quotactl *qctl;
+        __u64 total_limits = 0;
+        int rc;
+        ENTRY;
+
+        OBD_ALLOC_PTR(qctl);
+        if (qctl == NULL)
+                RETURN(-ENOMEM);
+
+        dquot = lustre_dqget(obd, qinfo, id, type);
+        if (IS_ERR(dquot)) {
+                CERROR("Get dquot failed. (rc:%ld)\n", PTR_ERR(dquot));
+                OBD_FREE_PTR(qctl);
+                RETURN(PTR_ERR(dquot));
+        }
+
+        down(&dquot->dq_sem);
+
+        /* don't recovery the dquot without limits or under setting */
+        if (!(dquot->dq_dqb.dqb_bhardlimit || dquot->dq_dqb.dqb_bsoftlimit) ||
+            dquot->dq_status)
+                GOTO(skip, rc = 0);
+        dquot->dq_status |= DQ_STATUS_RECOVERY;
+
+        up(&dquot->dq_sem);
+
+        /* get real bhardlimit from all slaves. */
+        qctl->qc_cmd = Q_GETOQUOTA;
+        qctl->qc_type = type;
+        qctl->qc_id = id;
+        qctl->qc_stat = QUOTA_RECOVERING;
+        rc = obd_quotactl(obd->u.mds.mds_osc_exp, qctl);
+        if (rc)
+                GOTO(out, rc);
+        total_limits = qctl->qc_dqblk.dqb_bhardlimit;
+
+        /* get real bhardlimit from master */
+        rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, qctl);
+        if (rc)
+                GOTO(out, rc);
+        total_limits += qctl->qc_dqblk.dqb_bhardlimit;
+
+        /* amend the usage of the administrative quotafile */
+        down(&mds->mds_qonoff_sem);
+        down(&dquot->dq_sem);
+
+        dquot->dq_dqb.dqb_curspace = total_limits << QUOTABLOCK_BITS;
+
+        rc = fsfilt_dquot(obd, dquot, QFILE_WR_DQUOT);
+        if (rc)
+                CERROR("write dquot failed! (rc:%d)\n", rc);
+
+        up(&dquot->dq_sem);
+        up(&mds->mds_qonoff_sem);
+        EXIT;
+out:
+        down(&dquot->dq_sem);
+        dquot->dq_status &= ~DQ_STATUS_RECOVERY;
+skip:
+        up(&dquot->dq_sem);
 
         lustre_dqput(dquot);
+        OBD_FREE_PTR(qctl);
+        return rc;
+}
+
+struct qmaster_recov_thread_data {
+        struct obd_device *obd;
+        struct completion comp;
+};
+
+static int qmaster_recovery_main(void *arg)
+{
+        struct qmaster_recov_thread_data *data = arg;
+        struct obd_device *obd = data->obd;
+        unsigned long flags;
+        int rc = 0;
+        unsigned short type;
+        ENTRY;
+
+        lock_kernel();
+        ptlrpc_daemonize();
+
+        SIGNAL_MASK_LOCK(current, flags);
+        sigfillset(&current->blocked);
+        RECALC_SIGPENDING;
+        SIGNAL_MASK_UNLOCK(current, flags);
+        THREAD_NAME(cfs_curproc_comm(), CFS_CURPROC_COMM_MAX - 1, "%s", 
+                    "qmaster_recovd");
+        unlock_kernel();
+
+        complete(&data->comp);
+
+        for (type = USRQUOTA; type < MAXQUOTAS; type++) {
+                struct mds_obd *mds = &obd->u.mds;
+                struct lustre_quota_info *qinfo = &mds->mds_quota_info;
+                struct list_head id_list;
+                struct dquot_id *dqid, *tmp;
+
+                down(&mds->mds_qonoff_sem);
+                if (qinfo->qi_files[type] == NULL) {
+                        up(&mds->mds_qonoff_sem);
+                        continue;
+                }
+                INIT_LIST_HEAD(&id_list);
+                rc = fsfilt_quotainfo(obd, qinfo, type, QFILE_GET_QIDS, 
+                                      &id_list);
+                up(&mds->mds_qonoff_sem);
+
+                if (rc)
+                        CERROR("error get ids from admin quotafile.(%d)\n", rc);
+
+                list_for_each_entry_safe(dqid, tmp, &id_list, di_link) {
+                        list_del_init(&dqid->di_link);
+                        if (rc)
+                                goto free;
+
+                        rc = dquot_recovery(obd, dqid->di_id, type);
+                        if (rc)
+                                CERROR("qmaster recovery failed! (id:%d type:%d"
+                                       " rc:%d)\n", dqid->di_id, type, rc);
+free:
+                        kfree(dqid);
+                }
+        }
+        RETURN(rc);
+}
+
+int mds_quota_recovery(struct obd_device *obd)
+{
+        struct lov_obd *lov = &obd->u.mds.mds_osc_obd->u.lov;
+        struct qmaster_recov_thread_data data;
+        int rc = 0;
+        ENTRY;
+
+        spin_lock(&lov->lov_lock);
+        if (lov->desc.ld_tgt_count != lov->desc.ld_active_tgt_count) {
+                CWARN("Not all osts are active, abort quota recovery\n");
+                spin_unlock(&lov->lov_lock);
+                RETURN(rc);
+        }
+        spin_unlock(&lov->lov_lock);
+
+        data.obd = obd;
+        init_completion(&data.comp);
+
+        rc = kernel_thread(qmaster_recovery_main, &data, CLONE_VM|CLONE_FILES);
+        if (rc < 0)
+                CERROR("Cannot start quota recovery thread: rc %d\n", rc);
+
+        wait_for_completion(&data.comp);
         RETURN(rc);
 }
similarity index 85%
rename from lustre/lvfs/quotacheck_test.c
rename to lustre/quota/quotacheck_test.c
index 87c9b7b..0c88030 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- *  Copyright (C) 2003 Cluster File Systems, Inc.
+ *  Copyright (C) 2005 Cluster File Systems, Inc.
  *   Author: Lai Siyao <lsy@clusterfs.com>
  *
  *   This file is part of Lustre, http://www.lustre.org/
@@ -40,12 +40,12 @@ get_group_desc(struct super_block *sb, int group)
 {
         unsigned long desc_block, desc;
         struct ext3_group_desc *gdp;
-                                                                                                                 
+
         desc_block = group / EXT3_DESC_PER_BLOCK(sb);
         desc = group % EXT3_DESC_PER_BLOCK(sb);
         gdp = (struct ext3_group_desc *)
               EXT3_SB(sb)->s_group_desc[desc_block]->b_data;
-                                                                                                                 
+
         return gdp + desc;
 }
 
@@ -54,10 +54,10 @@ read_inode_bitmap(struct super_block *sb, unsigned long group)
 {
         struct ext3_group_desc *desc;
         struct buffer_head *bh;
-                                                                                                                 
+
         desc = get_group_desc(sb, group);
         bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
-                                                                                                                 
+
         return bh;
 }
 
@@ -66,13 +66,13 @@ static inline struct inode *ext3_iget_inuse(struct super_block *sb,
                                      int index, unsigned long ino)
 {
         struct inode *inode = NULL;
-                                                                                                                 
+
         if (ext3_test_bit(index, bitmap_bh->b_data)) {
                 CERROR("i: %d, ino: %lu\n", index, ino);
                 ll_sleep(1);
                 inode = iget(sb, ino);
         }
-                                                                                                                 
+
         return inode;
 }
 
@@ -104,7 +104,7 @@ static int quotacheck_test_1(struct obd_device *obd, struct super_block *sb)
                 brelse(bitmap_bh);
                 bitmap_bh = read_inode_bitmap(sb, group);
 
-                if (group == 0) 
+                if (group == 0)
                         CERROR("groups_count: %lu, inodes_per_group: %lu, first_ino: %u, inodes_count: %u\n",
                                sbi->s_groups_count, sbi->s_inodes_per_group,
                                sbi->s_first_ino, le32_to_cpu(sbi->s_es->s_inodes_count));
@@ -133,20 +133,16 @@ static int quotacheck_test_1(struct obd_device *obd, struct super_block *sb)
  * ------------------------------------------------------------------------- */
 static int quotacheck_run_tests(struct obd_device *obd, struct obd_device *tgt)
 {
-        struct super_block *sb;
         int rc;
         ENTRY;
 
-        if (!strcmp(tgt->obd_type->typ_name, LUSTRE_MDS_NAME))
-                sb = tgt->u.mds.mds_sb;
-        else if (!strcmp(tgt->obd_type->typ_name, "obdfilter"))
-                sb = tgt->u.filter.fo_sb;
-        else {
+        if (strcmp(tgt->obd_type->typ_name, LUSTRE_MDS_NAME) &&
+            !strcmp(tgt->obd_type->typ_name, "obdfilter")) {
                 CERROR("TARGET OBD should be mds or ost\n");
                 RETURN(-EINVAL);
         }
 
-        rc = quotacheck_test_1(tgt, sb);
+        rc = quotacheck_test_1(tgt, tgt->u.obt.obt_sb);
 
         return rc;
 }
similarity index 94%
rename from lustre/lvfs/quotactl_test.c
rename to lustre/quota/quotactl_test.c
index 1e03388..0ac332c 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
  * vim:expandtab:shiftwidth=8:tabstop=8:
  *
- *  Copyright (C) 2003 Cluster File Systems, Inc.
+ *  Copyright (C) 2005 Cluster File Systems, Inc.
  *   Author: Lai Siyao <lsy@clusterfs.com>
  *
  *   This file is part of Lustre, http://www.lustre.org/
 #include <linux/lustre_mds.h>
 #include <linux/obd_ost.h>
 
-char *test_quotafile[] = {"aquotactl.user", "aquotactl.group"};
+static struct obd_quotactl oqctl;
 
 /* Test quotaon */
 static int quotactl_test_1(struct obd_device *obd, struct super_block *sb)
 {
-        struct obd_quotactl oqctl;
         int rc;
         ENTRY;
 
@@ -37,12 +36,9 @@ static int quotactl_test_1(struct obd_device *obd, struct super_block *sb)
         oqctl.qc_id = QFMT_LDISKFS;
         oqctl.qc_type = UGQUOTA;
         rc = fsfilt_quotactl(obd, sb, &oqctl);
-        if (rc) {
+        if (rc)
                 CERROR("1a: quotactl Q_QUOTAON failed: %d\n", rc);
-                RETURN(rc);
-        }
-
-        RETURN(0);
+        RETURN(rc);
 }
 
 #if 0 /* set/getinfo not supported, this is for cluster-wide quotas */
@@ -88,7 +84,6 @@ static int quotactl_test_2(struct obd_device *obd, struct super_block *sb)
 /* Test set/getquota */
 static int quotactl_test_3(struct obd_device *obd, struct super_block *sb)
 {
-        struct obd_quotactl oqctl;
         int rc;
         ENTRY;
 
@@ -236,7 +231,6 @@ static int quotactl_test_3(struct obd_device *obd, struct super_block *sb)
 /* Test quotaoff */
 static int quotactl_test_4(struct obd_device *obd, struct super_block *sb)
 {
-        struct obd_quotactl oqctl;
         int rc;
         ENTRY;
 
@@ -262,15 +256,14 @@ static int quotactl_run_tests(struct obd_device *obd, struct obd_device *tgt)
         int rc;
         ENTRY;
 
-        if (!strcmp(tgt->obd_type->typ_name, LUSTRE_MDS_NAME))
-                sb = tgt->u.mds.mds_sb;
-        else if (!strcmp(tgt->obd_type->typ_name, "obdfilter"))
-                sb = tgt->u.filter.fo_sb;
-        else {
-                CERROR("TARGET OBD should be mds or obdfilter\n");
+        if (strcmp(tgt->obd_type->typ_name, LUSTRE_MDS_NAME) &&
+            !strcmp(tgt->obd_type->typ_name, "obdfilter")) {
+                CERROR("TARGET OBD should be mds or ost\n");
                 RETURN(-EINVAL);
         }
 
+        sb = tgt->u.obt.obt_sb;
+
         push_ctxt(&saved, &tgt->obd_lvfs_ctxt, NULL);
 
         rc = quotactl_test_1(tgt, sb);
index 9c33b51..f124768 100644 (file)
@@ -18,7 +18,7 @@ if TESTS
 pkgexample_SCRIPTS = $(pkgexample_scripts)
 noinst_PROGRAMS = openunlink testreq truncate directio openme writeme
 noinst_PROGRAMS += tchmod toexcl fsx test_brw openclose createdestroy
-noinst_PROGRAMS += stat createmany statmany multifstat createtest mlink utime
+noinst_PROGRAMS += stat createmany chownmany statmany multifstat createtest mlink utime
 noinst_PROGRAMS += opendirunlink opendevunlink unlinkmany fchdir_test checkstat
 noinst_PROGRAMS += wantedi statone runas openfile getdents o_directory
 noinst_PROGRAMS += small_write multiop sleeptest ll_sparseness_verify cmknod
diff --git a/lustre/tests/chownmany.c b/lustre/tests/chownmany.c
new file mode 100644 (file)
index 0000000..64512ef
--- /dev/null
@@ -0,0 +1,79 @@
+/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
+ * vim:expandtab:shiftwidth=8:tabstop=8:
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+void usage(char *prog)
+{
+       printf("usage: %s owner filenamefmt count\n", prog);
+       printf("       %s owner filenamefmt start count\n", prog);
+}
+
+int main(int argc, char ** argv)
+{
+        int i, rc = 0, mask = 0;
+        char format[4096], *fmt;
+        char filename[4096];
+        long start, last;
+       long begin = 0, count;
+
+        if (argc < 4 || argc > 5) {
+               usage(argv[0]);
+                return 1;
+        }
+
+        mask = strtol(argv[1], NULL, 0);
+
+        if (strlen(argv[2]) > 4080) {
+                printf("name too long\n");
+                return 1;
+        }
+
+        start = last = time(0);
+
+       if (argc == 4) {
+               count = strtol(argv[3], NULL, 0);
+               if (count < 1) {
+                        printf("count must be at least one\n");
+                        return 1;
+                }
+       } else {
+               begin = strtol(argv[3], NULL, 0);
+               count = strtol(argv[4], NULL, 0);
+       }
+
+       if (strchr(argv[2], '%')) {
+               fmt = argv[2];
+        } else {
+               sprintf(format, "%s%%d", argv[2]);
+               fmt = format;
+       }
+        for (i = 0; i < count; i++, begin++) {
+                sprintf(filename, fmt, begin);
+               rc = chown(filename, mask, -1);
+                if (rc) {
+                        printf("chown (%s) error: %s\n",
+                               filename, strerror(errno));
+                        rc = errno;
+                        break;
+                }
+                if ((i % 10000) == 0) {
+                        printf(" - chowned %d (time %ld ; total %ld ; last "
+                               "%ld)\n", i, time(0), time(0) - start,
+                               time(0) - last);
+                        last = time(0);
+                }
+        }
+        printf("total: %d chowns in %ld seconds: %f chowns/second\n", i,
+               time(0) - start, ((float)i / (time(0) - start)));
+
+        return rc;
+}
diff --git a/lustre/tests/llog-test.sh b/lustre/tests/llog-test.sh
new file mode 100644 (file)
index 0000000..4044610
--- /dev/null
@@ -0,0 +1,102 @@
+#!/bin/sh
+
+set -e
+
+LUSTRE=${LUSTRE:-`dirname $0`/..}
+. $LUSTRE/tests/test-framework.sh
+
+init_test_env $@
+
+. ${CONFIG:=$LUSTRE/tests/cfg/local.sh}
+
+ostfailover_HOST=${ostfailover_HOST:-$ost_HOST}
+
+gen_config() {
+    rm -f "$XMLCONFIG"
+    add_mds mds --dev "$MDSDEV" --size "$MDSSIZE"
+    add_lov lov1 mds --stripe_sz $STRIPE_BYTES \
+       --stripe_cnt $STRIPES_PER_OBJ --stripe_pattern 0
+    add_ost ost --lov lov1 --dev $OSTDEV --size $OSTSIZE --failover
+    if [ ! -z "$ostfailover_HOST" ]; then
+        add_ostfailover ost --dev $OSTDEV --size $OSTSIZE
+    fi
+    add_client client mds --lov lov1 --path $MOUNT
+}
+
+cleanup() {
+    # make sure we are using the primary MDS, so the config log will
+    # be able to clean up properly.
+    activeost=`facet_active ost`
+    if [ $activeost != "ost" ]; then
+        fail ost
+    fi
+    zconf_umount `hostname` $MOUNT
+    stop mds ${FORCE} $MDSLCONFARGS
+    stop ost ${FORCE} --dump $TMP/replay-ost-single-`hostname`.log
+}
+
+if [ "$ONLY" == "cleanup" ]; then
+    sysctl -w portals.debug=0
+    FORCE=--force cleanup
+    exit
+fi
+
+build_test_filter
+
+SETUP=${SETUP:-"setup"}
+CLEANUP=${CLEANUP:-"cleanup"}
+
+setup() {
+    gen_config
+
+    start ost --reformat $OSTLCONFARGS
+    [ "$DAEMONFILE" ] && $LCTL debug_daemon start $DAEMONFILE $DAEMONSIZE
+    start mds --reformat $MDSLCONFARGS
+
+    if [ -z "`grep " $MOUNT " /proc/mounts`" ]; then
+       # test "-1" needed during initial client->OST connection
+       log "== test 00: target handle mismatch (bug 5317) === `date +%H:%M:%S`"
+
+       #define OBD_FAIL_OST_ALL_REPLY_NET       0x211
+       do_facet ost "sysctl -w lustre.fail_loc=0x80000211"
+
+       zconf_mount `hostname` $MOUNT && df $MOUNT && pass || error "mount fail"
+    fi
+}
+
+mkdir -p $DIR
+
+$SETUP
+
+LCOUNT=${LCOUNT:-10000}
+
+test_0() {
+    ./createmany -o $DIR/llog-%d $LCOUNT
+    #replay_barrier ost
+}
+run_test 0 "Prepare fileset"
+
+test_1() {
+    ./chownmany 1000 $DIR/llog-%d $LCOUNT
+    sleep 5
+}
+run_test 1 "Do chowns"
+
+test_2() {
+    HALFCOUNT=${HALFCOUNT:-17}
+    ./chownmany 500 $DIR/llog-%d 0 $HALFCOUNT
+    fail ost
+    ./chownmany 500 $DIR/llog-%d $HALFCOUNT $LCOUNT
+    sleep 5
+}
+#run_test 2 "Fail OST during chown"
+
+test_3() {
+    ./unlinkmany $DIR/llog-%d $LCOUNT
+    sleep 2
+    $CHECKSTAT -t file $DIR/llog-* && return 1 || true
+}
+run_test 3 "Remove testset"
+
+equals_msg test complete, cleaning up
+FORCE=--force $CLEANUP
index 3207c18..ced41d2 100755 (executable)
@@ -66,8 +66,12 @@ ${LMC} --add net --node client --nid '*' --nettype $NETTYPE || exit 12
 [ "x$MDS_MOUNT_OPTS" != "x" ] &&
     MDS_MOUNT_OPTS="--mountfsoptions $MDS_MOUNT_OPTS"
 
+[ "x$QUOTA_OPTS" != "x" ] &&
+    QUOTA_OPTS="--quota $QUOTA_OPTS"
+    
+# configure mds server
 ${LMC} --add mds --node $HOSTNAME --mds mds1 --fstype $FSTYPE \
-       --dev $MDSDEV $MDS_MOUNT_OPTS \
+       --dev $MDSDEV $MDS_MOUNT_OPTS $QUOTA_OPTS\
        --size $MDSSIZE $JARG $IARG $MDSOPT || exit 20
 
 [ "x$OST_MOUNT_OPTS" != "x" ] &&
@@ -78,7 +82,7 @@ ${LMC} --add lov --lov lov1 --mds mds1 --stripe_sz $STRIPE_BYTES \
        --stripe_cnt $STRIPES_PER_OBJ --stripe_pattern 0 $LOVOPT || exit 20
 
 ${LMC} --add ost --node $HOSTNAME --lov lov1 --fstype $FSTYPE \
-       --dev $OSTDEV \
+       --dev $OSTDEV $QUOTA_OPTS\
        $OST_MOUNT_OPTS --size $OSTSIZE $JARG $OSTOPT || exit 30
 
 # create client config
index fbf563f..7130ad0 100755 (executable)
@@ -42,12 +42,15 @@ ${LMC} --add node --node $HOSTNAME || exit 10
 ${LMC} --add net --node $HOSTNAME --nid $HOSTNAME --nettype $NETTYPE || exit 11
 ${LMC} --add net --node client --nid '*' --nettype $NETTYPE || exit 12
 
+[ "x$QUOTA_OPTS" != "x" ] &&
+    QUOTA_OPTS="--quota $QUOTA_OPTS"
+
 # configure mds server
 [ "x$MDS_MOUNT_OPTS" != "x" ] &&
     MDS_MOUNT_OPTS="--mountfsoptions $MDS_MOUNT_OPTS"
 
 ${LMC} --format --add mds --node $HOSTNAME --mds mds1 --fstype $FSTYPE \
-       --dev $MDSDEV $MDS_MOUNT_OPTS --size $MDSSIZE $MDSOPT || exit 20
+       --dev $MDSDEV $MDS_MOUNT_OPTS $QUOTA_OPTS --size $MDSSIZE $MDSOPT || exit 20
 
 # configure ost
 ${LMC} --add lov --lov lov1 --mds mds1 --stripe_sz $STRIPE_BYTES \
@@ -58,7 +61,7 @@ for num in `seq $OSTCOUNT`; do
     DEVPTR=OSTDEV$num
     eval $DEVPTR=${!DEVPTR:=$TMP/$OST-`hostname`}
     ${LMC} --add ost --node $HOSTNAME --lov lov1 --ost $OST --fstype $FSTYPE \
-       --dev ${!DEVPTR} --size $OSTSIZE $JARG $OSTOPT || exit 30
+       --dev ${!DEVPTR} --size $OSTSIZE $JARG $OSTOPT $QUOTA_OPTS|| exit 30
 done
 
 
diff --git a/lustre/tests/quota_sanity.sh b/lustre/tests/quota_sanity.sh
deleted file mode 100644 (file)
index 59f1b72..0000000
+++ /dev/null
@@ -1,446 +0,0 @@
-#!/bin/bash
-
-set -e
-#set -vx
-
-SRCDIR=`dirname $0`
-export PATH=$PWD/$SRCDIR:$SRCDIR:$SRCDIR/../utils:$PATH:/sbin
-. $SRCDIR/test-framework.sh
-
-LFS=${LFS:-lfs}
-LCTL=${LCTL:-lctl}
-USER="quota_usr"
-TSTID=${TSTID:-60000}
-RUNAS=${RUNAS:-"runas -u $TSTID"}
-BLK_SZ=1024
-BUNIT_SZ=1000 # 1000 quota blocks
-BTUNE_SZ=500  # 500 quota blocks
-IUNIT_SZ=10 # 10 files
-ITUNE_SZ=5  # 5 files
-MAX_DQ_TIME=604800
-MAX_IQ_TIME=604800
-
-MOUNT="`cat /proc/mounts | grep "lustre" | awk '{print $2}'`"
-if [ -z "$MOUNT" ]; then
-       echo "ERROR: lustre not mounted, quit test!"
-       exit 1;
-fi
-OSTCOUNT=`cat /proc/fs/lustre/lov/*/activeobd | head -n 1`
-TSTDIR="$MOUNT/quota_dir"
-
-# set_blk_tunables(btune_sz)
-set_blk_tunesz() {
-       # set btune size on all obdfilters
-       for i in `ls /proc/fs/lustre/obdfilter/*/quota_btune_sz`; do
-               echo $(($1 * $BLK_SZ)) > $i
-       done
-       # set btune size on mds
-       for i in `ls /proc/fs/lustre/mds/mds*/quota_btune_sz`; do
-               echo $(($1 * $BLK_SZ)) > $i
-       done
-}
-
-# se_blk_unitsz(bunit_sz)
-set_blk_unitsz() {
-       for i in `ls /proc/fs/lustre/obdfilter/*/quota_bunit_sz`; do
-               echo $(($1 * $BLK_SZ)) > $i
-       done
-       for i in `ls /proc/fs/lustre/mds/mds*/quota_bunit_sz`; do
-               echo $(($1 * $BLK_SZ)) > $i
-       done
-}
-
-# set_file_tunesz(itune_sz)
-set_file_tunesz() {
-       # set iunit and itune size on all obdfilters
-       for i in `ls /proc/fs/lustre/obdfilter/*/quota_itune_sz`; do
-               echo $1 > $i
-       done
-       # set iunit and itune size on mds
-       for i in `ls /proc/fs/lustre/mds/mds*/quota_itune_sz`; do
-               echo $1 > $i
-       done
-
-
-}
-# set_file_unitsz(iunit_sz)
-set_file_unitsz() {
-       for i in `ls /proc/fs/lustre/obdfilter/*/quota_iunit_sz`; do
-               echo $1 > $i
-       done;
-       for i in `ls /proc/fs/lustre/mds/mds*/quota_iunit_sz`; do
-               echo $1 > $i
-       done
-}
-
-prepare_test() {
-       # create test group
-       GRP="`cat /etc/group | grep "$USER" | awk -F: '{print $1}'`"
-       if [ -z "$GRP" ]; then
-               groupadd -g $TSTID "$USER"
-       fi
-       TSTID="`cat /etc/group | grep "$USER" | awk -F: '{print $3}'`"
-
-       # create test user
-       USR="`cat /etc/passwd | grep "$USER" | awk -F: '{print $1}'`"
-       if [ -z "$USR" ]; then
-               useradd -u $TSTID -g $TSTID -d /tmp "$USER"
-       fi
-       
-       RUNAS="runas -u $TSTID"
-       
-       # set block tunables
-       set_blk_tunesz $BTUNE_SZ
-       set_blk_unitsz $BUNIT_SZ
-       # set file tunaables
-       set_file_tunesz $ITUNE_SZ
-       set_file_unitsz $IUNIT_SZ
-
-       [ -d $TSTDIR ] || mkdir $TSTDIR 
-       chmod 777 $TSTDIR
-}
-
-cleanup_test() {       
-       # restore block tunables to default size
-       set_blk_unitsz $((1024 * 100))
-       set_blk_tunesz $((1024 * 50))
-       # restore file tunables to default size
-       set_file_unitsz 5000
-       set_file_tunesz 2500
-
-       rm -fr $TSTDIR
-       # delete test user and group
-       userdel "$USER"
-}
-
-# set quota
-test_1() {
-       echo "== Enable quota"
-       $LFS quotaoff -ug $MOUNT
-       $LFS quotacheck -ug $MOUNT
-
-       $LFS setquota -u $USER 0 0 0 0 $MOUNT
-       $LFS setquota -g $USER 0 0 0 0 $MOUNT
-       return 0
-}
-
-# block hard limit (normal use and out of quota)
-test_2() {
-       echo "== Block hard limit"
-       LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits each sever
-       TESTFILE="$TSTDIR/quota_tst20"
-       
-       echo "  User quota (limit: $LIMIT bytes)"
-       $LFS setquota -u $USER 0 $LIMIT 0 0 $MOUNT
-
-       $RUNAS touch $TESTFILE >/dev/null 2>&1
-       
-       echo "    Write ..."
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) > /dev/null 2>&1 || error "(usr) write failure, but expect success"
-       echo "    Done"
-       echo "    Write out of block quota ..."
-       # this time maybe cache write,  ignore it's failure
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) seek=$(($LIMIT/2)) > /dev/null 2>&1 || echo " " > /dev/null
-       # flush cache, ensure noquota flag is setted on client
-       sync; sleep 1; sync;
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT > /dev/null 2>&1 && error "(usr) write success, but expect EDQUOT"
-       echo "    EDQUOT"
-
-       rm -f $TESTFILE
-       
-       echo "  Group quota (limit: $LIMIT bytes)"
-       $LFS setquota -u $USER 0 0 0 0 $MOUNT           # clear user limit
-       $LFS setquota -g $USER 0 $LIMIT 0 0 $MOUNT
-       TESTFILE="$TSTDIR/quota_tst21"
-
-       $RUNAS touch $TESTFILE >/dev/null 2>&1
-
-       echo "    Write ..."
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) > /dev/null 2>&1 || error "(grp) write failure, but expect success"
-       echo "    Done"
-       echo "    Write out of block quota ..."
-       # this time maybe cache write, ignore it's failure
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) seek=$(($LIMIT/2)) > /dev/null 2>&1 || echo " " > /dev/null
-       sync; sleep 1; sync;
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT > /dev/null 2>&1 && error "(grp) write success, but expect EDQUOT"
-       echo "    EDQUOT"
-
-       # cleanup
-       rm -f $TESTFILE
-       $LFS setquota -g $USER 0 0 0 0 $MOUNT
-       return 0
-}
-
-# file hard limit (normal use and out of quota)
-test_3() {
-       echo "== File hard limit"
-       LIMIT=$(($IUNIT_SZ * 10)) # 10 iunits on mds
-       TESTFILE="$TSTDIR/quota_tst30"
-
-       echo "  User quota (limit: $LIMIT files)"
-       $LFS setquota -u $USER 0 0 0 $LIMIT $MOUNT
-
-       echo "    Create $LIMIT files ..."
-       for i in `seq ${LIMIT}`; do
-               $RUNAS touch ${TESTFILE}_$i > /dev/null 2>&1 || error "(usr) touch failure, but except success"
-       done
-       echo "    Done"
-       echo "    Create out of file quota ..."
-       $RUNAS touch ${TESTFILE}_xxx > /dev/null 2>&1 && error "(usr) touch success, but expect EDQUOT"
-       echo "    EDQUOT"
-
-       for i in `seq ${LIMIT}`; do
-               rm -f ${TESTFILE}_$i
-       done
-
-       echo "  Group quota (limit: $LIMIT files)"
-       $LFS setquota -u $USER 0 0 0 0 $MOUNT           # clear user limit
-       $LFS setquota -g $USER 0 0 0 $LIMIT $MOUNT
-       TESTFILE="$TSTDIR/quota_tst31"
-
-       echo "    Create $LIMIT files ..."
-       for i in `seq ${LIMIT}`; do
-               $RUNAS touch ${TESTFILE}_$i > /dev/null 2>&1 || error "(grp) touch failure, but expect success"
-       done
-       echo "    Done"
-       echo "    Create out of file quota ..."
-       $RUNAS touch ${TESTFILE}_xxx > /dev/null 2>&1 && error "(grp) touch success, but expect EDQUOT"
-       echo "    EDQUOT"
-
-       # cleanup
-       for i in `seq ${LIMIT}`; do
-               rm -f ${TESTFILE}_$i
-       done
-       $LFS setquota -g $USER 0 0 0 0 $MOUNT
-       return 0
-}
-
-test_block_soft() {
-       TESTFILE=$1
-       GRACE=$2
-       BS=$(($BUNIT_SZ * $BLK_SZ))
-
-       echo "    Write to exceed soft limit"
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
-       sync; sleep 1; sync;
-
-       echo "    Write before timer goes off"
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
-       sync; sleep 1; sync;
-       echo "    Done"
-       
-       echo "    Sleep $GRACE seconds ..."
-       sleep $GRACE
-
-       echo "    Write after timer goes off"
-       # maybe cache write, ignore.
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$(($BUNIT_SZ * 2)) >/dev/null 2>&1 || echo " " > /dev/null
-       sync; sleep 1; sync;
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=1 seek=$(($BUNIT_SZ * 3)) >/dev/null 2>&1 && error "write success, but expect EDQUOT"
-       echo "    EDQUOT"
-
-       echo "    Unlink file to stop timer"
-       rm -f $TESTFILE
-       echo "    Done"
-
-       echo "    Write ..."
-       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
-       echo "    Done"
-
-       # cleanup
-       rm -f $TESTFILE
-}
-
-# block soft limit (start timer, timer goes off, stop timer)
-test_4() {
-       echo "== Block soft limit"
-       LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) )) # 1 bunits each sever
-       TESTFILE="$TSTDIR/quota_tst40"
-       GRACE=10
-
-       echo "  User quota (soft limit: $LIMIT bytes  grace: $GRACE seconds)"
-       $LFS setquota -t -u $GRACE $MAX_IQ_TIME $MOUNT
-       $LFS setquota -u $USER $LIMIT 0 0 0 $MOUNT
-
-       test_block_soft $TESTFILE $GRACE
-       $LFS setquota -u $USER 0 0 0 0 $MOUNT
-
-       echo "  Group quota (soft limit: $LIMIT bytes  grace: $GRACE seconds)"
-       $LFS setquota -t -g $GRACE $MAX_IQ_TIME $MOUNT
-       $LFS setquota -g $USER $LIMIT 0 0 0 $MOUNT
-       TESTFILE="$TSTDIR/quota_tst41"
-
-       test_block_soft $TESTFILE $GRACE
-       $LFS setquota -g $USER 0 0 0 0 $MOUNT
-       
-       return 0
-}
-
-test_file_soft() {
-       TESTFILE=$1
-       LIMIT=$2
-       GRACE=$3
-
-       echo "    Create files to exceed soft limit"
-       for i in `seq $LIMIT`; do
-               $RUNAS touch ${TESTFILE}_$i >/dev/null 2>&1 || error "touch failure, but expect success"
-       done
-       echo "    Done"
-
-       echo "    Create file before timer goes off"
-       $RUNAS touch ${TESTFILE}_before >/dev/null 2>&1 || error "touch before timer goes off failure, but expect success"
-       echo "    Done"
-
-       echo "    Sleep $GRACE seconds ..."
-       sleep $GRACE
-       
-       echo "    Create file after timer goes off"
-       for i in `seq $(($IUNIT_SZ - 1))`; do
-               $RUNAS touch ${TESTFILE}_after_$i >/dev/null 2>&1 || error "touch ${TESTFILE}_after_$i failure, but expect success"
-       done
-       $RUNAS touch ${TESTFILE}_after >/dev/null 2>&1 && error "touch after timer goes off success, but expect EDQUOT"
-       echo "    EDQUOT"
-
-       echo "    Unlink files to stop timer"
-       for i in `seq $LIMIT`; do
-               rm -f ${TESTFILE}_$i >/dev/null 2>&1 || error "rm ${TESTFILE}_$i failure"
-       done
-       rm -f ${TESTFILE}_before
-       for i in `seq $(($IUNIT_SZ - 1))`; do
-               rm -f ${TESTFILE}_after_$i >/dev/null 2>&1 || error "rm ${TESTFILE}_after_$i failure"
-       done
-       echo "    Done"
-
-       echo "    Create file"
-       $RUNAS touch ${TESTFILE}_xxx >/dev/null 2>&1 || error "touch after timer stop failure, but expect success"
-       echo "    Done"
-
-       # cleanup
-       rm -f ${TESTFILE}_xxx
-}
-
-# file soft limit (start timer, timer goes off, stop timer)
-test_5() {
-       echo "== File soft limit"
-       LIMIT=$(($IUNIT_SZ * 10))       # 10 iunits on mds
-       TESTFILE="$TSTDIR/quota_tst50"
-       GRACE=5
-
-       echo "  User quota (soft limit: $LIMIT files  grace: $GRACE seconds)"
-       $LFS setquota -t -u $MAX_DQ_TIME $GRACE $MOUNT
-       $LFS setquota -u $USER 0 0 $LIMIT 0 $MOUNT
-
-       test_file_soft $TESTFILE $LIMIT $GRACE
-       $LFS setquota -u $USER 0 0 0 0 $MOUNT
-
-       echo "  Group quota (soft limit: $LIMIT files  grace: $GRACE seconds)"
-       $LFS setquota -t -g $MAX_DQ_TIME $GRACE $MOUNT
-       $LFS setquota -g $USER 0 0 $LIMIT 0 $MOUNT
-       TESTFILE="$TSTDIR/quota_tst51"
-
-       test_file_soft $TESTFILE $LIMIT $GRACE
-       $LFS setquota -g $USER 0 0 0 0 $MOUNT
-       
-       # cleanup
-       $LFS setquota -t -u $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
-       $LFS setquota -t -g $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
-       return 0
-}
-
-# chown & chgrp (chown & chgrp successfully even out of block/file quota)
-test_6() {
-       echo "== Chown/Chgrp ignore quota"
-       BLIMIT=$(( $BUNIT_SZ * $((OSTCOUNT + 1)) * 10)) # 10 bunits on each server
-       ILIMIT=$(( $IUNIT_SZ * 10 )) # 10 iunits on mds
-       
-       echo "  Set quota limit (0 $BLIMIT 0 $ILIMIT) for $USER.$USER"
-       $LFS setquota -u $USER 0 $BLIMIT 0 $ILIMIT $MOUNT
-       $LFS setquota -g $USER 0 $BLIMIT 0 $ILIMIT $MOUNT
-       
-       echo "  Create more than $ILIMIT files and alloc more than $BLIMIT blocks ..."
-       for i in `seq $(($ILIMIT + 1))`; do
-               touch $TSTDIR/quota_tst60_$i > /dev/null 2>&1 || error "touch failure, expect success"
-       done
-       dd if=/dev/zero of=$TSTDIR/quota_tst60_1 bs=$BLK_SZ count=$(($BLIMIT+1)) > /dev/null 2>&1 || error "write failure, expect success"
-
-       echo "  Chown files to $USER.$USER ..."
-       for i in `seq $(($ILIMIT + 1))`; do
-               chown $USER.$USER $TSTDIR/quota_tst60_$i > /dev/null 2>&1 || error "chown failure, but expect success"
-       done
-
-       # cleanup
-       for i in `seq $(($ILIMIT + 1))`; do
-               rm -f $TSTDIR/quota_tst60_$i
-       done
-       $LFS setquota -u $USER 0 0 0 0 $MOUNT
-       $LFS setquota -g $USER 0 0 0 0 $MOUNT
-       return 0
-}
-
-# block quota acquire & release
-test_7() {
-       echo "== Block quota acqurie / release"
-
-       if [ $OSTCOUNT -lt 2 ]; then
-               echo "WARN: too few osts, skip this test."
-               return 0;
-       fi
-
-       LIMIT=$(($BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits per server
-       FILEA="$TSTDIR/quota_tst70_a"
-       FILEB="$TSTDIR/quota_tst70_b"
-       
-       echo "  Set block limit $LIMIT bytes to $USER.$USER"
-       $LFS setquota -u $USER 0 $LIMIT 0 0 $MOUNT
-       $LFS setquota -g $USER 0 $LIMIT 0 0 $MOUNT
-
-       echo "  Create filea on OST0 and fileb on OST1"
-       $LFS setstripe $FILEA 65536 0 1
-       $LFS setstripe $FILEB 65536 1 1
-       chown $USER.$USER $FILEA
-       chown $USER.$USER $FILEB
-
-       echo "  Exceed quota limit ..."
-       $RUNAS dd if=/dev/zero of=$FILEB bs=$BLK_SZ count=$(($LIMIT - $BUNIT_SZ * $OSTCOUNT)) >/dev/null 2>&1 || error "write fileb failure, but expect success"
-       sync; sleep 1; sync;
-       $RUNAS dd if=/dev/zero of=$FILEB bs=$BLK_SZ seek=$LIMIT count=$BUNIT_SZ >/dev/null 2>&1 && error "write fileb success, but expect EDQUOT"
-       sync; sleep 1; sync;
-       echo "  Write to OST0 return EDQUOT"
-       # this write maybe cache write, ignore it's failure
-       $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($BUNIT_SZ * 2)) >/dev/null 2>&1 || echo " " > /dev/null
-       sync; sleep 1; sync;
-       $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($BUNIT_SZ * 2)) seek=$(($BUNIT_SZ *2)) >/dev/null 2>&1 && error "write filea success, but expect EDQUOT"
-       echo "  EDQUOT"
-
-       echo "  Remove fileb to let OST1 release quota"
-       rm -f $FILEB
-
-       echo "  Write to OST0"
-       $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($LIMIT - $BUNIT_SZ * $OSTCOUNT)) >/dev/null 2>&1 || error "write filea failure, expect success"
-       echo "  Done"
-
-       # cleanup
-       rm -f $FILEA
-       $LFS setquota -u $USER 0 0 0 0 $MOUNT
-       $LFS setquota -g $USER 0 0 0 0 $MOUNT
-       return 0
-}
-
-# turn off quota
-test_8()
-{
-       echo "=== Turn off quota"
-       $LFS quotaoff $MOUNT
-       return 0
-}
-       
-prepare_test
-
-# run all tests
-for j in `seq 8`; do
-       test_$j
-       echo "== Done"
-       echo " "
-done
-
-cleanup_test
diff --git a/lustre/tests/sanity-quota.sh b/lustre/tests/sanity-quota.sh
new file mode 100644 (file)
index 0000000..f3911c8
--- /dev/null
@@ -0,0 +1,666 @@
+#!/bin/bash
+#
+# Run select tests by setting ONLY, or as arguments to the script.
+# Skip specific tests by setting EXCEPT.
+#
+# Run test by setting NOSETUP=true when ltest has setup env for us
+set -e
+
+SRCDIR=`dirname $0`
+export PATH=$PWD/$SRCDIR:$SRCDIR:$PWD/$SRCDIR/../utils:$PATH:/sbin
+
+ONLY=${ONLY:-"$*"}
+ALWAYS_EXCEPT=${ALWAYS_EXCEPT:-""}
+# UPDATE THE COMMENT ABOVE WITH BUG NUMBERS WHEN CHANGING ALWAYS_EXCEPT!
+
+case `uname -r` in
+2.6*) FSTYPE=${FSTYPE:-ldiskfs};;
+*) error "unsupported kernel" ;;
+esac
+
+[ "$ALWAYS_EXCEPT$EXCEPT" ] && \
+       echo "Skipping tests: `echo $ALWAYS_EXCEPT $EXCEPT`"
+
+TMP=${TMP:-/tmp}
+
+LFS=${LFS:-lfs}
+LCTL=${LCTL:-lctl}
+LSTRIPE=${LSTRIPE:-"$LFS setstripe"}
+TSTID=${TSTID:-60000}
+RUNAS=${RUNAS:-"runas -u $TSTID"}
+TSTUSR=${TSTUSR:-"quota_usr"}
+BLK_SZ=1024
+BUNIT_SZ=${BUNIT_SZ:-1000}     # default 1000 quota blocks
+BTUNE_SZ=${BTUNE_SZ:-500}      # default 50% of BUNIT_SZ
+IUNIT_SZ=${IUNIT_SZ:-10}       # default 10 files
+ITUNE_SZ=${ITUNE_SZ:-5}                # default 50% of IUNIT_SZ
+MAX_DQ_TIME=604800
+MAX_IQ_TIME=604800
+
+log() {
+       echo "$*"
+       $LCTL mark "$*" 2> /dev/null || true
+}
+
+trace() {
+       log "STARTING: $*"
+       strace -o $TMP/$1.strace -ttt $*
+       RC=$?
+       log "FINISHED: $*: rc $RC"
+       return 1
+}
+TRACE=${TRACE:-""}
+
+run_one() {
+       BEFORE=`date +%s`
+       log "== test $1: $2= `date +%H:%M:%S` ($BEFORE)"
+       export TESTNAME=test_$1
+       test_$1 || error "exit with rc=$?"
+       unset TESTNAME
+       pass "($((`date +%s` - $BEFORE))s)"
+       cd $SAVE_PWD
+}
+
+build_test_filter() {
+        for O in $ONLY; do
+            eval ONLY_${O}=true
+        done
+        for E in $EXCEPT $ALWAYS_EXCEPT; do
+            eval EXCEPT_${E}=true
+        done
+       # turn on/off quota tests must be included
+       eval ONLY_0=true
+       eval ONLY_9=true
+}
+
+_basetest() {
+       echo $*
+}
+
+basetest() {
+       IFS=abcdefghijklmnopqrstuvwxyz _basetest $1
+}
+
+run_test() {
+         base=`basetest $1`
+         if [ "$ONLY" ]; then
+                 testname=ONLY_$1
+                 if [ ${!testname}x != x ]; then
+                       run_one $1 "$2"
+                       return $?
+                 fi
+                 testname=ONLY_$base
+                 if [ ${!testname}x != x ]; then
+                         run_one $1 "$2"
+                         return $?
+                 fi
+                 echo -n "."
+                 return 0
+       fi
+        testname=EXCEPT_$1
+        if [ ${!testname}x != x ]; then
+                 echo "skipping excluded test $1"
+                 return 0
+        fi
+        testname=EXCEPT_$base
+        if [ ${!testname}x != x ]; then
+                 echo "skipping excluded test $1 (base $base)"
+                 return 0
+        fi
+        run_one $1 "$2"
+       return $?
+}
+
+[ "$SANITYLOG" ] && rm -f $SANITYLOG || true
+
+error() { 
+       sysctl -w lustre.fail_loc=0
+       log "FAIL: $TESTNAME $@"
+       if [ "$SANITYLOG" ]; then
+               echo "FAIL: $TESTNAME $@" >> $SANITYLOG
+       else
+               exit 1
+       fi
+}
+
+pass() { 
+       echo PASS $@
+}
+
+mounted_lustre_filesystems() {
+       awk '($3 ~ "lustre") { print $2 }' /proc/mounts
+}
+MOUNT="`mounted_lustre_filesystems`"
+if [ -z "$MOUNT" ]; then
+       export QUOTA_OPTS="quotaon=ug"
+       sh llmount.sh
+       MOUNT="`mounted_lustre_filesystems`"
+       [ -z "$MOUNT" ] && error "NAME=$NAME not mounted"
+       I_MOUNTED=yes
+fi
+
+[ `echo $MOUNT | wc -w` -gt 1 ] && error "NAME=$NAME mounted more than once"
+
+DIR=${DIR:-$MOUNT}
+[ -z "`echo $DIR | grep $MOUNT`" ] && echo "$DIR not in $MOUNT" && exit 99
+
+LPROC=/proc/fs/lustre
+LOVNAME=`cat $LPROC/llite/*/lov/common_name | tail -n 1`
+OSTCOUNT=`cat $LPROC/lov/$LOVNAME/numobd`
+STRIPECOUNT=`cat $LPROC/lov/$LOVNAME/stripecount`
+STRIPESIZE=`cat $LPROC/lov/$LOVNAME/stripesize`
+ORIGFREE=`cat $LPROC/lov/$LOVNAME/kbytesavail`
+MAXFREE=${MAXFREE:-$((200000 * $OSTCOUNT))}
+MDS=$(\ls $LPROC/mds 2> /dev/null | grep -v num_refs | tail -n 1)
+TSTDIR="$MOUNT/quota_dir"
+
+build_test_filter
+
+
+# set_blk_tunables(btune_sz)
+set_blk_tunesz() {
+       # set btune size on all obdfilters
+       for i in `ls /proc/fs/lustre/obdfilter/*/quota_btune_sz`; do
+               echo $(($1 * $BLK_SZ)) > $i
+       done
+       # set btune size on mds
+       for i in `ls /proc/fs/lustre/mds/mds*/quota_btune_sz`; do
+               echo $(($1 * $BLK_SZ)) > $i
+       done
+}
+# se_blk_unitsz(bunit_sz)
+set_blk_unitsz() {
+       for i in `ls /proc/fs/lustre/obdfilter/*/quota_bunit_sz`; do
+               echo $(($1 * $BLK_SZ)) > $i
+       done
+       for i in `ls /proc/fs/lustre/mds/mds*/quota_bunit_sz`; do
+               echo $(($1 * $BLK_SZ)) > $i
+       done
+}
+# set_file_tunesz(itune_sz)
+set_file_tunesz() {
+       # set iunit and itune size on all obdfilters
+       for i in `ls /proc/fs/lustre/obdfilter/*/quota_itune_sz`; do
+               echo $1 > $i
+       done
+       # set iunit and itune size on mds
+       for i in `ls /proc/fs/lustre/mds/mds*/quota_itune_sz`; do
+               echo $1 > $i
+       done
+
+
+}
+# set_file_unitsz(iunit_sz)
+set_file_unitsz() {
+       for i in `ls /proc/fs/lustre/obdfilter/*/quota_iunit_sz`; do
+               echo $1 > $i
+       done;
+       for i in `ls /proc/fs/lustre/mds/mds*/quota_iunit_sz`; do
+               echo $1 > $i
+       done
+}
+
+# These are for test on local machine,if run sanity-quota.sh on 
+# real cluster, ltest should have setup the test environment: 
+#
+# - create test user/group on all servers with same id.
+# - set unit size/tune on all servers size to reasonable value.
+pre_test() {
+       if [ -z "$NOSETUP" ]; then
+               # set block tunables
+               set_blk_tunesz $BTUNE_SZ
+               set_blk_unitsz $BUNIT_SZ
+               # set file tunaables
+               set_file_tunesz $ITUNE_SZ
+               set_file_unitsz $IUNIT_SZ
+       fi
+}
+pre_test
+
+post_test() {
+       if [ -z "$NOSETUP" ]; then
+               # restore block tunables to default size
+               set_blk_unitsz $((1024 * 100))
+               set_blk_tunesz $((1024 * 50))
+               # restore file tunables to default size
+               set_file_unitsz 5000
+               set_file_tunesz 2500
+       fi
+}
+
+setup() {
+       # create local test group
+       GRP="`cat /etc/group | grep "$TSTUSR" | awk -F: '{print $1}'`"
+       if [ -z "$GRP" ]; then
+               groupadd -g $TSTID "$TSTUSR"
+       fi
+       TSTID="`cat /etc/group | grep "$TSTUSR" | awk -F: '{print $3}'`"
+
+       # create test user
+       USR="`cat /etc/passwd | grep "$TSTUSR" | awk -F: '{print $1}'`"
+       if [ -z "$USR" ]; then
+               useradd -u $TSTID -g $TSTID -d /tmp "$TSTUSR"
+       fi
+       
+       RUNAS="runas -u $TSTID"
+       
+       # create test directory
+       [ -d $TSTDIR ] || mkdir $TSTDIR 
+       chmod 777 $TSTDIR
+}
+setup
+
+# set quota
+test_0() {
+       $LFS quotaoff -ug $MOUNT
+       $LFS quotacheck -ug $MOUNT
+
+       $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+       $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 0 "Set quota ============================="
+
+# block hard limit (normal use and out of quota)
+test_1() {
+       LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits each sever
+       TESTFILE="$TSTDIR/quota_tst10"
+       
+       echo "  User quota (limit: $LIMIT bytes)"
+       $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $MOUNT
+       
+       $LFS setstripe $TESTFILE 65536 0 1
+       chown $TSTUSR.$TSTUSR $TESTFILE
+
+       echo "    Write ..."
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) > /dev/null 2>&1 || error "(usr) write failure, but expect success"
+       echo "    Done"
+       echo "    Write out of block quota ..."
+       # this time maybe cache write,  ignore it's failure
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) seek=$(($LIMIT/2)) > /dev/null 2>&1 || echo " " > /dev/null
+       # flush cache, ensure noquota flag is setted on client
+       sync; sleep 1; sync;
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT > /dev/null 2>&1 && error "(usr) write success, but expect EDQUOT"
+       echo "    EDQUOT"
+
+       rm -f $TESTFILE
+       
+       echo "  Group quota (limit: $LIMIT bytes)"
+       $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT         # clear user limit
+       $LFS setquota -g $TSTUSR 0 $LIMIT 0 0 $MOUNT
+       TESTFILE="$TSTDIR/quota_tst11"
+
+       $LFS setstripe $TESTFILE 65536 0 1
+       chown $TSTUSR.$TSTUSR $TESTFILE
+
+       echo "    Write ..."
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) > /dev/null 2>&1 || error "(grp) write failure, but expect success"
+       echo "    Done"
+       echo "    Write out of block quota ..."
+       # this time maybe cache write, ignore it's failure
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) seek=$(($LIMIT/2)) > /dev/null 2>&1 || echo " " > /dev/null
+       sync; sleep 1; sync;
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT > /dev/null 2>&1 && error "(grp) write success, but expect EDQUOT"
+       echo "    EDQUOT"
+
+       # cleanup
+       rm -f $TESTFILE
+       $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 1 "Block hard limit (normal use and out of quota) ==="
+
+# file hard limit (normal use and out of quota)
+test_2() {
+       LIMIT=$(($IUNIT_SZ * 10)) # 10 iunits on mds
+       TESTFILE="$TSTDIR/quota_tstr20"
+
+       echo "  User quota (limit: $LIMIT files)"
+       $LFS setquota -u $TSTUSR 0 0 0 $LIMIT $MOUNT
+
+       echo "    Create $LIMIT files ..."
+       for i in `seq ${LIMIT}`; do
+               $RUNAS touch ${TESTFILE}_$i > /dev/null 2>&1 || error "(usr) touch failure, but except success"
+       done
+       echo "    Done"
+       echo "    Create out of file quota ..."
+       $RUNAS touch ${TESTFILE}_xxx > /dev/null 2>&1 && error "(usr) touch success, but expect EDQUOT"
+       echo "    EDQUOT"
+
+       for i in `seq ${LIMIT}`; do
+               rm -f ${TESTFILE}_$i
+       done
+
+       echo "  Group quota (limit: $LIMIT files)"
+       $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT         # clear user limit
+       $LFS setquota -g $TSTUSR 0 0 0 $LIMIT $MOUNT
+       TESTFILE="$TSTDIR/quota_tst21"
+
+       echo "    Create $LIMIT files ..."
+       for i in `seq ${LIMIT}`; do
+               $RUNAS touch ${TESTFILE}_$i > /dev/null 2>&1 || error "(grp) touch failure, but expect success"
+       done
+       echo "    Done"
+       echo "    Create out of file quota ..."
+       $RUNAS touch ${TESTFILE}_xxx > /dev/null 2>&1 && error "(grp) touch success, but expect EDQUOT"
+       echo "    EDQUOT"
+
+       # cleanup
+       for i in `seq ${LIMIT}`; do
+               rm -f ${TESTFILE}_$i
+       done
+       $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 2 "File hard limit (normal use and out of quota) ==="
+
+test_block_soft() {
+       TESTFILE=$1
+       GRACE=$2
+
+       echo "    Write to exceed soft limit"
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
+       sync; sleep 1; sync;
+
+       echo "    Write before timer goes off"
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
+       sync; sleep 1; sync;
+       echo "    Done"
+       
+       echo "    Sleep $GRACE seconds ..."
+       sleep $GRACE
+
+       echo "    Write after timer goes off"
+       # maybe cache write, ignore.
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$(($BUNIT_SZ * 2)) >/dev/null 2>&1 || echo " " > /dev/null
+       sync; sleep 1; sync;
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=1 seek=$(($BUNIT_SZ * 3)) >/dev/null 2>&1 && error "write success, but expect EDQUOT"
+       echo "    EDQUOT"
+
+       echo "    Unlink file to stop timer"
+       rm -f $TESTFILE
+       echo "    Done"
+
+       echo "    Write ..."
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
+       echo "    Done"
+
+       # cleanup
+       rm -f $TESTFILE
+}
+
+# block soft limit (start timer, timer goes off, stop timer)
+test_3() {
+       LIMIT=$(( $BUNIT_SZ * 2 )) # 1 bunit on mds and 1 bunit on the ost
+       GRACE=10
+
+       echo "  User quota (soft limit: $LIMIT bytes  grace: $GRACE seconds)"
+       TESTFILE="$TSTDIR/quota_tst30"
+       $LFS setstripe $TESTFILE 65536 0 1
+       chown $TSTUSR.$TSTUSR $TESTFILE
+
+       $LFS setquota -t -u $GRACE $MAX_IQ_TIME $MOUNT
+       $LFS setquota -u $TSTUSR $LIMIT 0 0 0 $MOUNT
+
+       test_block_soft $TESTFILE $GRACE
+       $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+
+       echo "  Group quota (soft limit: $LIMIT bytes  grace: $GRACE seconds)"
+       TESTFILE="$TSTDIR/quota_tst31"
+       $LFS setstripe $TESTFILE 65536 0 1
+       chown $TSTUSR.$TSTUSR $TESTFILE
+
+       $LFS setquota -t -g $GRACE $MAX_IQ_TIME $MOUNT
+       $LFS setquota -g $TSTUSR $LIMIT 0 0 0 $MOUNT
+       TESTFILE="$TSTDIR/quota_tst31"
+
+       test_block_soft $TESTFILE $GRACE
+       $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 3 "Block soft limit (start timer, timer goes off, stop timer) ==="
+
+test_file_soft() {
+       TESTFILE=$1
+       LIMIT=$2
+       GRACE=$3
+
+       echo "    Create files to exceed soft limit"
+       for i in `seq $LIMIT`; do
+               $RUNAS touch ${TESTFILE}_$i >/dev/null 2>&1 || error "touch failure, but expect success"
+       done
+       echo "    Done"
+
+       echo "    Create file before timer goes off"
+       $RUNAS touch ${TESTFILE}_before >/dev/null 2>&1 || error "touch before timer goes off failure, but expect success"
+       echo "    Done"
+
+       echo "    Sleep $GRACE seconds ..."
+       sleep $GRACE
+       
+       echo "    Create file after timer goes off"
+       for i in `seq $(($IUNIT_SZ - 1))`; do
+               $RUNAS touch ${TESTFILE}_after_$i >/dev/null 2>&1 || error "touch ${TESTFILE}_after_$i failure, but expect success"
+       done
+       $RUNAS touch ${TESTFILE}_after >/dev/null 2>&1 && error "touch after timer goes off success, but expect EDQUOT"
+       echo "    EDQUOT"
+
+       echo "    Unlink files to stop timer"
+       for i in `seq $LIMIT`; do
+               rm -f ${TESTFILE}_$i >/dev/null 2>&1 || error "rm ${TESTFILE}_$i failure"
+       done
+       rm -f ${TESTFILE}_before
+       for i in `seq $(($IUNIT_SZ - 1))`; do
+               rm -f ${TESTFILE}_after_$i >/dev/null 2>&1 || error "rm ${TESTFILE}_after_$i failure"
+       done
+       echo "    Done"
+
+       echo "    Create file"
+       $RUNAS touch ${TESTFILE}_xxx >/dev/null 2>&1 || error "touch after timer stop failure, but expect success"
+       echo "    Done"
+
+       # cleanup
+       rm -f ${TESTFILE}_xxx
+}
+
+# file soft limit (start timer, timer goes off, stop timer)
+test_4() {
+       LIMIT=$(($IUNIT_SZ * 10))       # 10 iunits on mds
+       TESTFILE="$TSTDIR/quota_tst40"
+       GRACE=5
+
+       echo "  User quota (soft limit: $LIMIT files  grace: $GRACE seconds)"
+       $LFS setquota -t -u $MAX_DQ_TIME $GRACE $MOUNT
+       $LFS setquota -u $TSTUSR 0 0 $LIMIT 0 $MOUNT
+
+       test_file_soft $TESTFILE $LIMIT $GRACE
+       $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+
+       echo "  Group quota (soft limit: $LIMIT files  grace: $GRACE seconds)"
+       $LFS setquota -t -g $MAX_DQ_TIME $GRACE $MOUNT
+       $LFS setquota -g $TSTUSR 0 0 $LIMIT 0 $MOUNT
+       TESTFILE="$TSTDIR/quota_tst41"
+
+       test_file_soft $TESTFILE $LIMIT $GRACE
+       $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+       
+       # cleanup
+       $LFS setquota -t -u $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
+       $LFS setquota -t -g $MAX_DQ_TIME $MAX_IQ_TIME $MOUNT
+}
+run_test 4 "File soft limit (start timer, timer goes off, stop timer) ==="
+
+# chown & chgrp (chown & chgrp successfully even out of block/file quota)
+test_5() {
+       BLIMIT=$(( $BUNIT_SZ * $((OSTCOUNT + 1)) * 10)) # 10 bunits on each server
+       ILIMIT=$(( $IUNIT_SZ * 10 )) # 10 iunits on mds
+       
+       echo "  Set quota limit (0 $BLIMIT 0 $ILIMIT) for $TSTUSR.$TSTUSR"
+       $LFS setquota -u $TSTUSR 0 $BLIMIT 0 $ILIMIT $MOUNT
+       $LFS setquota -g $TSTUSR 0 $BLIMIT 0 $ILIMIT $MOUNT
+       
+       echo "  Create more than $ILIMIT files and alloc more than $BLIMIT blocks ..."
+       for i in `seq $(($ILIMIT + 1))`; do
+               touch $TSTDIR/quota_tst50_$i > /dev/null 2>&1 || error "touch failure, expect success"
+       done
+       dd if=/dev/zero of=$TSTDIR/quota_tst50_1 bs=$BLK_SZ count=$(($BLIMIT+1)) > /dev/null 2>&1 || error "write failure, expect success"
+
+       echo "  Chown files to $TSTUSR.$TSTUSR ..."
+       for i in `seq $(($ILIMIT + 1))`; do
+               chown $TSTUSR.$TSTUSR $TSTDIR/quota_tst50_$i > /dev/null 2>&1 || error "chown failure, but expect success"
+       done
+
+       # cleanup
+       for i in `seq $(($ILIMIT + 1))`; do
+               rm -f $TSTDIR/quota_tst50_$i
+       done
+       $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+       $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 5 "Chown & chgrp (chown & chgrp successfully even out of block/file quota) ==="
+
+# block quota acquire & release
+test_6() {
+       if [ $OSTCOUNT -lt 2 ]; then
+               echo "WARN: too few osts, skip this test."
+               return 0;
+       fi
+
+       LIMIT=$(($BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits per server
+       FILEA="$TSTDIR/quota_tst60_a"
+       FILEB="$TSTDIR/quota_tst60_b"
+       
+       echo "  Set block limit $LIMIT bytes to $TSTUSR.$TSTUSR"
+       $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $MOUNT
+       $LFS setquota -g $TSTUSR 0 $LIMIT 0 0 $MOUNT
+
+       echo "  Create filea on OST0 and fileb on OST1"
+       $LFS setstripe $FILEA 65536 0 1
+       $LFS setstripe $FILEB 65536 1 1
+       chown $TSTUSR.$TSTUSR $FILEA
+       chown $TSTUSR.$TSTUSR $FILEB
+
+       echo "  Exceed quota limit ..."
+       $RUNAS dd if=/dev/zero of=$FILEB bs=$BLK_SZ count=$(($LIMIT - $BUNIT_SZ * $OSTCOUNT)) >/dev/null 2>&1 || error "write fileb failure, but expect success"
+       sync; sleep 1; sync;
+       $RUNAS dd if=/dev/zero of=$FILEB bs=$BLK_SZ seek=$LIMIT count=$BUNIT_SZ >/dev/null 2>&1 && error "write fileb success, but expect EDQUOT"
+       sync; sleep 1; sync;
+       echo "  Write to OST0 return EDQUOT"
+       # this write maybe cache write, ignore it's failure
+       $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($BUNIT_SZ * 2)) >/dev/null 2>&1 || echo " " > /dev/null
+       sync; sleep 1; sync;
+       $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($BUNIT_SZ * 2)) seek=$(($BUNIT_SZ *2)) >/dev/null 2>&1 && error "write filea success, but expect EDQUOT"
+       echo "  EDQUOT"
+
+       echo "  Remove fileb to let OST1 release quota"
+       rm -f $FILEB
+
+       echo "  Write to OST0"
+       $RUNAS dd if=/dev/zero of=$FILEA bs=$BLK_SZ count=$(($LIMIT - $BUNIT_SZ * $OSTCOUNT)) >/dev/null 2>&1 || error "write filea failure, expect success"
+       echo "  Done"
+
+       # cleanup
+       rm -f $FILEA
+       $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+       $LFS setquota -g $TSTUSR 0 0 0 0 $MOUNT
+       return 0
+}
+run_test 6 "Block quota acquire & release ========="
+
+# quota recovery (block quota only by now)
+test_7()
+{
+       if [ -z "`lsmod|grep mds`" ]; then 
+               echo "WARN: no local mds, skip this test"
+               return 0
+       fi
+
+       LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits each sever
+       TESTFILE="$TSTDIR/quota_tst70"
+       
+       $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $MOUNT
+       
+       $LFS setstripe $TESTFILE 65536 0 1
+       chown $TSTUSR.$TSTUSR $TESTFILE
+
+       echo "  Write to OST0..."
+       $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ >/dev/null 2>&1 || error "write failure, but expect success"
+       
+       #define OBD_FAIL_OBD_DQACQ               0x604
+       echo 0x604 > /proc/sys/lustre/fail_loc
+       echo "  Remove files on OST0"
+       rm -f $TESTFILE
+       echo 0 > /proc/sys/lustre/fail_loc
+
+       echo "  Trigger recovery..."
+       OSC0_UUID="`$LCTL dl | awk '/.* OSC_[^ ]+_OST.* / { print $1 }'`"
+       [ -z "$OSC0_UUID" ] && OSC0_UUID="`$LCTL dl | awk '/.* OSC_[^ ]+_ost1.* / { print $1 }'`"
+       for i in $OSC0_UUID; do
+               $LCTL --device $i activate > /dev/null 2>&1 || error "activate osc failed!"
+       done
+
+       # sleep a while to wait for recovery done
+       sleep 20
+
+       # check limits
+       PATTERN="`echo $MOUNT | sed 's/\//\\\\\//g'`"
+       TOTAL_LIMIT="`$LFS quota -u $TSTUSR $MOUNT | awk '/^.*'$PATTERN'.*[[:digit:]+][[:space:]+]/ { print $4 }'`"
+       [ $TOTAL_LIMIT -eq $LIMIT ] || error "total limits not recovery!"
+       echo "  total limits = $TOTAL_LIMIT"
+       
+       OST0_UUID=`$LCTL dl | awk '/.*OST_[^ ]+_UUID.* / { print $5 }'`
+       [ -z "$OST0_UUID" ] && OST0_UUID=`$LCTL dl | awk '/.*ost1_[^ ]*UUID.* / { print $5 }'`
+       OST0_LIMIT="`$LFS quota -o $OST0_UUID -u $TSTUSR $MOUNT | awk '/^.*[[:digit:]+][[:space:]+]/ { print $3 }'`"
+       [ $OST0_LIMIT -eq $BUNIT_SZ ] || error "high limits not released!"
+       echo "  limits on $OST0_UUID = $OST0_LIMIT"
+
+       # cleanup
+       $LFS setquota -u $TSTUSR 0 0 0 0 $MOUNT
+}
+run_test 7 "Quota recovery (only block limit) ======"
+
+# run dbench with quota enabled
+test_8() {
+       BLK_LIMIT=$((100 * 1024 * 1024)) # 100G
+       FILE_LIMIT=1000000
+       
+       echo "  Set enough high limit for user: $TSTUSR"
+       $LFS setquota -u $TSTUSR 0 $BLK_LIMIT 0 $FILE_LIMIT $MOUNT
+       echo "  Set enough high limit for group: $TSTUSR"
+       $LFS setquota -g $USER 0 $BLK_LIMIT 0 $FILE_LIMIT $MOUNT
+       
+       TGT=$TSTDIR/client.txt
+       SRC=${SRC:-/usr/lib/dbench/client.txt}
+       [ ! -e $TGT -a -e $SRC ] && echo "  copying $SRC to $TGT" && cp $SRC $TGT
+       SRC=/usr/lib/dbench/client_plain.txt
+       [ ! -e $TGT -a -e $SRC ] && echo "  copying $SRC to $TGT" && cp $SRC $TGT
+       
+       SAVE_PWD=$PWD
+       cd $TSTDIR
+       $RUNAS dbench -c client.txt 3
+       RC=$?
+       
+       cd $SAVE_PWD
+       return $RC
+}
+run_test 8 "Run dbench with quota enabled ==========="
+
+# turn off quota
+test_9()
+{
+       $LFS quotaoff $MOUNT
+       return 0
+}
+run_test 9 "Quota off ==============================="
+
+
+log "cleanup: ======================================================"
+if [ "`mount | grep ^$NAME`" ]; then
+       rm -fr $TSTDIR
+       post_test
+       # delete test user and group
+       userdel "$TSTUSR"
+       if [ "$I_MOUNTED" = "yes" ]; then
+               sh llmountcleanup.sh || error "llmountcleanup failed"
+       fi
+fi
+
+echo '=========================== finished ==============================='
+[ -f "$SANITYLOG" ] && cat $SANITYLOG && exit 1 || true
+
index 7fc574d..398d463 100755 (executable)
@@ -1134,6 +1134,7 @@ class MDSDEV(Module):
         self.nspath = self.db.get_val('nspath', '')
         self.mkfsoptions = '-i 4096 ' + self.db.get_val('mkfsoptions', '')
         self.mountfsoptions = self.db.get_val('mountfsoptions', '')
+        self.quota = self.db.get_val('quota', '')
         # overwrite the orignal MDSDEV name and uuid with the MDS name and uuid
         target_uuid = self.db.get_first_ref('target')
         mds = self.db.lookup(target_uuid)
@@ -1189,6 +1190,8 @@ class MDSDEV(Module):
         self.uuid = target_uuid
 
         # loading modules
+        if self.quota:
+            self.add_lustre_module('quota', 'lquota')
         self.add_lustre_module('mdc', 'mdc')
         self.add_lustre_module('osc', 'osc')
         self.add_lustre_module('lov', 'lov')
@@ -1238,7 +1241,8 @@ class MDSDEV(Module):
             print 'MDS mount options: ' + mountfsoptions
 
             lctl.newdev("mds", self.name, self.uuid,
-                        setup ="%s %s %s %s" %(blkdev, self.fstype, self.name, mountfsoptions))
+                        setup ="%s %s %s %s %s" %(blkdev, self.fstype, self.name, 
+                                                  mountfsoptions, self.quota))
             self.group_upcall = self.db.get_val('group_upcall','')
             sys_set_group_upcall(self.name, self.group_upcall)
 
@@ -1391,6 +1395,7 @@ class OSD(Module):
         if self.size > 1000000:
                 self.mkfsoptions = '-i 16384 ' + self.mkfsoptions
         self.mountfsoptions = self.db.get_val('mountfsoptions', '')
+        self.quota = self.db.get_val('quota', '')
 
         self.fstype = self.db.get_val('fstype', '')
         if sys_get_branch() == '2.4' and self.fstype == 'ldiskfs':
@@ -1421,6 +1426,8 @@ class OSD(Module):
         self.target_dev_uuid = self.uuid
         self.uuid = target_uuid
         # modules
+        if self.quota:
+            self.add_lustre_module('quota', 'lquota')
         self.add_lustre_module('ost', 'ost')
         # FIXME: should we default to ext3 here?
         if self.fstype == 'ldiskfs':
@@ -1470,8 +1477,9 @@ class OSD(Module):
         print 'OST mount options: ' + mountfsoptions
 
         lctl.newdev(self.osdtype, self.name, self.uuid,
-                    setup ="%s %s %s %s" %(blkdev, self.fstype,
-                                           self.failover_ost, mountfsoptions))
+                    setup ="%s %s %s %s %s" %(blkdev, self.fstype,
+                                           self.failover_ost, mountfsoptions,
+                                           self.quota))
         if not is_prepared('OSS'):
             lctl.newdev("ost", 'OSS', 'OSS_UUID', setup ="")
 
@@ -1749,6 +1757,10 @@ class Mountpoint(Module):
         self.vosc = VOSC(obd, client_uuid, self.name)
         self.mdc = get_mdc(db, client_uuid, self.name, self.mds_uuid)
 
+        mds_db = self.db.lookup(self.mds_uuid)
+        quota = mds_db.get_val('quota', '')
+        if quota:
+                self.add_lustre_module('quota', 'lquota')
         self.add_lustre_module('mdc', 'mdc')
         self.add_lustre_module('llite', 'llite')
 
index ae1332c..79a3c58 100644 (file)
 #include <errno.h>
 #include <pwd.h>
 #include <grp.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <dirent.h>
 
 #include <lnet/api-support.h>
 #include <lnet/lnetctl.h>
 
 unsigned int libcfs_subsystem_debug = 0;
 
-#ifdef HAVE_QUOTA_SUPPORT
-
-/* FIXME: Q_SYNC ... commands defined in linux/quota.h seems broken,
- *        so define new commands with the value in kernel */
-#define LUSTRE_Q_QUOTAON  0x800002     /* turn quotas on */
-#define LUSTRE_Q_QUOTAOFF 0x800003     /* turn quotas off */
-#define LUSTRE_Q_GETINFO  0x800005     /* get information about quota files */
-#define LUSTRE_Q_SETINFO  0x800006     /* set information about quota files */
-#define LUSTRE_Q_GETQUOTA 0x800007     /* get user quota structure */
-#define LUSTRE_Q_SETQUOTA 0x800008     /* set user quota structure */
-
-/* Where is this stupid thing supposed to be defined? */
-#ifndef USRQUOTA
-# define USRQUOTA 0
-# define GRPQUOTA 1
-#endif
-
-#endif /* HAVE_QUOTA_SUPPORT */
-
 /* all functions */
 static int lfs_setstripe(int argc, char **argv);
 static int lfs_find(int argc, char **argv);
@@ -73,7 +58,7 @@ static int lfs_osts(int argc, char **argv);
 static int lfs_check(int argc, char **argv);
 static int lfs_catinfo(int argc, char **argv);
 #ifdef HAVE_QUOTA_SUPPORT
-static int lfs_quotachog(int argc, char **argv);
+static int lfs_quotachown(int argc, char **argv);
 static int lfs_quotacheck(int argc, char **argv);
 static int lfs_quotaon(int argc, char **argv);
 static int lfs_quotaoff(int argc, char **argv);
@@ -111,9 +96,9 @@ command_t cmdlist[] = {
          "\tnode name must be provided when use keyword config."},
         {"osts", lfs_osts, 0, "osts"},
 #ifdef HAVE_QUOTA_SUPPORT
-        {"quotachog",lfs_quotachog, 0,
-         "Change all files owner or group in specified filesystem.\n"
-         "usage: quotachog [-i] <filesystem>\n"
+        {"quotachown",lfs_quotachown, 0,
+         "Change files' owner or group on the specified filesystem.\n"
+         "usage: quotachown [-i] <filesystem>\n"
          "\t-i: ignore error if file is not exist\n"},
         {"quotacheck", lfs_quotacheck, 0,
          "Scan the specified filesystem for disk usage, and create,\n"
@@ -127,8 +112,7 @@ command_t cmdlist[] = {
          "usage: setquota [ -u | -g ] <name> <block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> <filesystem>\n"
          "       setquota -t [ -u | -g ] <block-grace> <inode-grace> <filesystem>"},
         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
-         "usage: quota -t [ -u |-g ] <filesystem>\n"
-         "       quota [ -o obd_uuid ] [ -u | -g ] [name] <filesystem>"},
+         "usage: quota [ -o obd_uuid ] [ -u | -g ] [name] <filesystem>"},
 #endif
         {"help", Parser_help, 0, "help"},
         {"exit", Parser_quit, 0, "quit"},
@@ -438,7 +422,7 @@ static int lfs_catinfo(int argc, char **argv)
 }
 
 #ifdef HAVE_QUOTA_SUPPORT
-static int lfs_quotachog(int argc, char **argv)
+static int lfs_quotachown(int argc, char **argv)
 {
 
         int c,rc;
@@ -450,13 +434,14 @@ static int lfs_quotachog(int argc, char **argv)
                         flag++;
                         break;
                 default:
-                        fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+                        fprintf(stderr, "error: %s: option '-%c' "
+                                        "unrecognized\n", argv[0], c);
                         return CMD_HELP;
                 }
         }
         if (optind == argc)
                 return CMD_HELP;
-        rc = llapi_quotachog(argv[optind], flag);
+        rc = llapi_quotachown(argv[optind], flag);
         if(rc)
                 fprintf(stderr,"error: change file owner/group failed.\n");
         return rc;
@@ -485,7 +470,8 @@ static int lfs_quotacheck(int argc, char **argv)
                         check_type |= 0x02;
                         break;
                 default:
-                        fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+                        fprintf(stderr, "error: %s: option '-%c' "
+                                        "unrecognized\n", argv[0], c);
                         return CMD_HELP;
                 }
         }
@@ -561,7 +547,8 @@ static int lfs_quotaon(int argc, char **argv)
                         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
                         break;
                 default:
-                        fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+                        fprintf(stderr, "error: %s: option '-%c' "
+                                        "unrecognized\n", argv[0], c);
                         return CMD_HELP;
                 }
         }
@@ -607,7 +594,8 @@ static int lfs_quotaoff(int argc, char **argv)
                         qctl.qc_type |= 0x02;
                         break;
                 default:
-                        fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+                        fprintf(stderr, "error: %s: option '-%c' "
+                                        "unrecognized\n", argv[0], c);
                         return CMD_HELP;
                 }
         }
@@ -720,7 +708,8 @@ int lfs_setquota(int argc, char **argv)
                         qctl.qc_cmd = LUSTRE_Q_SETINFO;
                         break;
                 default:
-                        fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+                        fprintf(stderr, "error: %s: option '-%c' "
+                                        "unrecognized\n", argv[0], c);
                         return CMD_HELP;
                 }
         }
@@ -729,12 +718,13 @@ int lfs_setquota(int argc, char **argv)
                 qctl.qc_type--;
 
         if (qctl.qc_type == UGQUOTA) {
-                fprintf(stderr, "error: user and group quotas can't be set together\n");
+                fprintf(stderr, "error: user and group quotas can't be set "
+                                "both\n");
                 return CMD_HELP;
         }
 
         if (qctl.qc_cmd == LUSTRE_Q_SETQUOTA) {
-                struct if_dqblk *dqb = &qctl.qc_dqblk;
+                struct obd_dqblk *dqb = &qctl.qc_dqblk;
 
                 if (optind + 6 != argc)
                         return CMD_HELP;
@@ -750,8 +740,10 @@ int lfs_setquota(int argc, char **argv)
                 ARG2INT(dqb->dqb_bhardlimit, argv[optind++], "block-hardlimit");
                 ARG2INT(dqb->dqb_isoftlimit, argv[optind++], "inode-softlimit");
                 ARG2INT(dqb->dqb_ihardlimit, argv[optind++], "inode-hardlimit");
+
+                dqb->dqb_valid = QIF_LIMITS;
         } else {
-                struct if_dqinfo *dqi = &qctl.qc_dqinfo;
+                struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
 
                 if (optind + 3 != argc)
                         return CMD_HELP;
@@ -813,8 +805,18 @@ static void diff2str(time_t seconds, char *buf, time_t now)
         grace2str(seconds - now, buf);
 }
 
+static void print_quota_title(char *name, struct if_quotactl *qctl)
+{
+        printf("Disk quotas for %s %s (%cid %u):\n",
+               type2name(qctl->qc_type), name,
+               *type2name(qctl->qc_type), qctl->qc_id);
+        printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
+               "Filesystem",
+               "blocks", "quota", "limit", "grace",
+               "files", "quota", "limit", "grace");
+}
 
-static void print_quota(char *mnt, char *name, struct if_quotactl *qctl)
+static void print_quota(char *mnt, struct if_quotactl *qctl, int ost_only)
 {
         time_t now;
 
@@ -822,7 +824,7 @@ static void print_quota(char *mnt, char *name, struct if_quotactl *qctl)
 
         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
                 int bover = 0, iover = 0;
-                struct if_dqblk *dqb = &qctl->qc_dqblk;
+                struct obd_dqblk *dqb = &qctl->qc_dqblk;
 
                 if (dqb->dqb_bhardlimit &&
                     toqb(dqb->dqb_curspace) > dqb->dqb_bhardlimit) {
@@ -848,14 +850,6 @@ static void print_quota(char *mnt, char *name, struct if_quotactl *qctl)
                         }
                 }
 
-                printf("Disk quotas for %s %s (%cid %u):\n",
-                        type2name(qctl->qc_type), name,
-                        *type2name(qctl->qc_type), qctl->qc_id);
-                printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
-                        "Filesystem",
-                        "blocks", "quota", "limit", "grace",
-                        "files", "quota", "limit", "grace");
-
 #if 0           /* XXX: always print quotas even when no usages */
                 if (dqb->dqb_curspace || dqb->dqb_curinodes)
 #endif
@@ -867,29 +861,92 @@ static void print_quota(char *mnt, char *name, struct if_quotactl *qctl)
                                 printf("%s\n%15s", mnt, "");
                         else
                                 printf("%15s", mnt);
+                        
                         if (bover)
                                 diff2str(dqb->dqb_btime, timebuf, now);
-                        sprintf(numbuf[0], LPU64, toqb(dqb->dqb_curspace));
-                        sprintf(numbuf[1], LPU64, dqb->dqb_bsoftlimit);
-                        sprintf(numbuf[2], LPU64, dqb->dqb_bhardlimit);
-                        printf(" %7s%c %6s %7s %7s", numbuf[0], bover ? '*' : ' ', numbuf[1],
+                        
+                        sprintf(numbuf[0], "%llu", toqb(dqb->dqb_curspace));
+                        sprintf(numbuf[1], "%llu", dqb->dqb_bsoftlimit);
+                        sprintf(numbuf[2], "%llu", dqb->dqb_bhardlimit);
+                        printf(" %7s%c %6s %7s %7s",
+                               numbuf[0], bover ? '*' : ' ', numbuf[1],
                                numbuf[2], bover > 1 ? timebuf : "");
+                        
                         if (iover)
                                 diff2str(dqb->dqb_itime, timebuf, now);
-                        sprintf(numbuf[0], LPU64, dqb->dqb_curinodes);
-                        sprintf(numbuf[1], LPU64, dqb->dqb_isoftlimit);
-                        sprintf(numbuf[2], LPU64, dqb->dqb_ihardlimit);
-                        printf(" %7s%c %6s %7s %7s\n", numbuf[0], iover ? '*' : ' ', numbuf[1],
-                               numbuf[2], iover > 1 ? timebuf : "");
+                        
+                        sprintf(numbuf[0], "%llu", dqb->dqb_curinodes);
+                        sprintf(numbuf[1], "%llu", dqb->dqb_isoftlimit);
+                        sprintf(numbuf[2], "%llu", dqb->dqb_ihardlimit);
+                        if (!ost_only)
+                                printf(" %7s%c %6s %7s %7s",
+                                       numbuf[0], iover ? '*' : ' ', numbuf[1],
+                                       numbuf[2], iover > 1 ? timebuf : "");
+                        printf("\n");
                 }
-        } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO || qctl->qc_cmd == Q_GETOINFO) {
+        } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
+                   qctl->qc_cmd == Q_GETOINFO) {
                 char bgtimebuf[40];
                 char igtimebuf[40];
 
                 grace2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf);
                 grace2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf);
-                printf("Block grace time: %s; Inode grace time: %s\n", bgtimebuf, igtimebuf);
+                printf("Block grace time: %s; Inode grace time: %s\n",
+                       bgtimebuf, igtimebuf);
+        }
+}
+
+static void print_mds_quota(char *mnt, struct if_quotactl *qctl)
+{
+        int rc;
+
+        /* XXX: this is a flag to mark that only mds quota is wanted */
+        qctl->qc_dqblk.dqb_valid = 1;
+        rc = llapi_quotactl(mnt, qctl);
+        if (rc) {
+                fprintf(stderr, "quotactl failed: %s\n", strerror(errno));
+                return;
+        }
+        qctl->qc_dqblk.dqb_valid = 0;
+
+        print_quota(qctl->obd_uuid.uuid, qctl, 0);
+}
+
+static void print_lov_quota(char *mnt, struct if_quotactl *qctl)
+{
+        DIR *dir;
+        struct obd_uuid uuids[1024], *uuidp;
+        int obdcount = 1024;
+        int i, rc;
+
+        dir = opendir(mnt);
+        if (!dir) {
+                fprintf(stderr, "open %s failed: %s\n", mnt, strerror(errno));
+                return;
+        }
+
+        rc = llapi_lov_get_uuids(dirfd(dir), uuids, &obdcount);
+        if (rc != 0) {
+                fprintf(stderr, "get ost uuid failed: %s\n", strerror(errno));
+                goto out;
+        }
+
+        for (i = 0, uuidp = uuids; i < obdcount; i++, uuidp++) {
+                memcpy(&qctl->obd_uuid, uuidp, sizeof(*uuidp));
+
+                rc = llapi_quotactl(mnt, qctl);
+                if (rc) {
+                        fprintf(stderr, "%s quotactl failed: %s\n",
+                                uuidp->uuid, strerror(errno));
+                        continue;
+                }
+
+                print_quota(uuidp->uuid, qctl, 1);
         }
+
+out:
+        closedir(dir);
+        return;
 }
 
 static int lfs_quota(int argc, char **argv)
@@ -920,7 +977,8 @@ static int lfs_quota(int argc, char **argv)
                         strncpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
                         break;
                 default:
-                        fprintf(stderr, "error: %s: option '-%c' unrecognized\n", argv[0], c);
+                        fprintf(stderr, "error: %s: option '-%c' "
+                                        "unrecognized\n", argv[0], c);
                         return CMD_HELP;
                 }
         }
@@ -929,11 +987,15 @@ static int lfs_quota(int argc, char **argv)
                 qctl.qc_type--;
 
         if (qctl.qc_type == UGQUOTA) {
-                fprintf(stderr, "error: user or group can't be specified together\n");
+                fprintf(stderr, "error: user or group can't be specified"
+                                "both\n");
                 return CMD_HELP;
         }
 
-        if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && optind + 2 == argc) {
+        if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
+                if (optind + 2 != argc)
+                        return CMD_HELP;
+
                 name = argv[optind++];
                 rc = name2id(&qctl.qc_id, name, qctl.qc_type);
                 if (rc) {
@@ -941,6 +1003,7 @@ static int lfs_quota(int argc, char **argv)
                                 name, strerror(errno));
                         return CMD_HELP;
                 }
+                print_quota_title(name, &qctl);
         } else if (optind + 1 != argc) {
                 return CMD_HELP;
         }
@@ -958,7 +1021,18 @@ static int lfs_quota(int argc, char **argv)
         if (!name)
                 rc = id2name(&name, getuid(), qctl.qc_type);
 
-        print_quota(mnt, name, &qctl);
+        if (*obd_uuid) {
+                mnt = "";
+                name = obd_uuid;
+        }
+
+        print_quota(mnt, &qctl, 0);
+
+        if (!*obd_uuid) {
+                print_mds_quota(mnt, &qctl);
+                print_lov_quota(mnt, &qctl);
+        }
+
         return 0;
 }
 #endif /* HAVE_QUOTA_SUPPORT */
index 67fc615..f40162b 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/lustre_lib.h>
 #include <lustre/liblustreapi.h>
 #include <linux/obd_lov.h>
+#include <lustre/liblustreapi.h>
 
 static void err_msg(char *fmt, ...)
 {
@@ -654,7 +655,7 @@ int llapi_ping(char *obd_type, char *obd_name)
         return rc;
 }
 
-int llapi_target_check(int type_num, char **obd_type, char *dir)
+int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb)
 {
         char buf[MAX_STRING_SIZE];
         FILE *fp = fopen(DEVICES_LIST, "r");
@@ -669,6 +670,7 @@ int llapi_target_check(int type_num, char **obd_type, char *dir)
         while (fgets(buf, sizeof(buf), fp) != NULL) {
                 char *obd_type_name = NULL;
                 char *obd_name = NULL;
+                char *obd_uuid = NULL;
                 char rawbuf[OBD_MAX_IOCTL_BUFFER];
                 char *bufl = rawbuf;
                 char *bufp = buf;
@@ -682,6 +684,7 @@ int llapi_target_check(int type_num, char **obd_type, char *dir)
                         obd_type_name = strsep(&bufp, " ");
                 }
                 obd_name = strsep(&bufp, " ");
+                obd_uuid = strsep(&bufp, " ");
 
                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
 
@@ -693,19 +696,32 @@ int llapi_target_check(int type_num, char **obd_type, char *dir)
                         if (strcmp(obd_type_name, obd_type[i]) != 0)
                                 continue;
 
-                        rc = llapi_ping(obd_type_name, obd_name);
-                        if (rc) {
-                                fprintf(stderr, "error: check %s: %s\n",
-                                        obd_name, strerror(rc = errno));
-                        } else {
-                                printf("%s active.\n", obd_name);
-                        }
+                        cb(obd_type_name, obd_name, obd_uuid, args);
                 }
         }
         fclose(fp);
         return rc;
 }
 
+static void do_target_check(char *obd_type_name, char *obd_name,
+                            char *obd_uuid, void *args)
+{
+        int rc;
+
+        rc = llapi_ping(obd_type_name, obd_name);
+        if (rc) {
+                fprintf(stderr, "error: check %s: %s\n",
+                        obd_name, strerror(rc = errno));
+        } else {
+                printf("%s active.\n", obd_name);
+        }
+}
+
+int llapi_target_check(int type_num, char **obd_type, char *dir)
+{
+        return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
+}
+
 #undef MAX_STRING_SIZE
 
 int llapi_catinfo(char *dir, char *keyword, char *node_name)
@@ -785,7 +801,7 @@ int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk)
 
         while (1) {
                 rc = ioctl(dirfd(root), LL_IOC_POLL_QUOTACHECK, qchk);
-                if (!rc || errno != ENODATA)
+                if (!rc)
                         break;
                 sleep(poll_intvl);
                 if (poll_intvl < 30)
@@ -813,7 +829,7 @@ int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
         return rc;
 }
 
-static int quotachog_process_file(DIR *dir, char *dname, char *fname,
+static int quotachown_process_file(DIR *dir, char *dname, char *fname,
                         struct find_param *param)
 {
         lstat_t *st;
@@ -839,6 +855,10 @@ static int quotachog_process_file(DIR *dir, char *dname, char *fname,
 
         st = &param->lmd->lmd_st;
         snprintf(pathname, sizeof(pathname), "%s/%s", dname, fname);
+
+        /* libc chown() will do extra check, and if the real owner is
+         * the same as the ones to set, it won't fall into kernel, so
+         * invoke syscall directly. */
         rc = syscall(SYS_chown, pathname, st->st_uid, st->st_gid);
         if (rc)
                 fprintf(stderr, "chown %s (%u,%u) fail: %s\n",
@@ -846,7 +866,7 @@ static int quotachog_process_file(DIR *dir, char *dname, char *fname,
         return rc;
 }
 
-int llapi_quotachog(char *path, int flag)
+int llapi_quotachown(char *path, int flag)
 {
         struct find_param param;
         int ret = 0;
@@ -855,7 +875,7 @@ int llapi_quotachog(char *path, int flag)
         param.recursive = 1;
         param.verbose = 0;
         param.quiet = 1;
-        param.process_file = quotachog_process_file;
+        param.process_file = quotachown_process_file;
 
         ret = prepare_find(&param);
         if (ret)
index d0c19db..d584d29 100755 (executable)
@@ -95,6 +95,7 @@ Object creation command summary:
   --mdsuuid uuid
   --mkfsoptions options
   --mountfsoptions options
+  --quota quotaon=u|g|ug,iunit=,bunit=,itune=,btune= 
 
 --add lov
   --lov lov_name
@@ -118,6 +119,7 @@ Object creation command summary:
   --ostuuid uuid
   --mkfsoptions options
   --mountfsoptions options
+  --quota quotaon=u|g|ug,iunit=,bunit=,itune=,btune=
  
 --add mtpt  - Mountpoint
   --node node_name
@@ -199,7 +201,19 @@ lmc_options = [
     ('mdsuuid', "Optional argument to specify MDS UUID", PARAM,""),
     ('nspath', "Local mount point of server namespace.", PARAM,""),
     ('format', ""),
-
+    ('quota', "quotaon:enable quota, only u|g|ug is supported now. \
+               iunit: the unit for slave to acquire/release inode quota from/to masteri.\
+                      Int type (>0), default value in Lustre is 5000 inodes.\
+               bunit: the unit for slave to acquire/release block quota from/to master.\
+                      Mbytes (>0), default value in Lustre is 100(Mbytes).\
+               itune: used to tune the threthold. When inode quota usage reach the threthold,\
+                      slave should acquire/release inode quota from/to master.\
+                      Int type (100 > btune > 0), default value in Lustre is 50 (percentge).\
+                      inode threthold = iunit * itune / 100.\
+               btune: used to tune the threthold. When block quota usage reach the threthold,\
+                      slave should acquire/release block quota from/to master.\
+                      Int type (100 > btune > 0), default value in Lustre is 50 (percentage).\
+                      block threthold = bunit * btune / 100.", PARAM,""),
     # clients: mountpoint and echo
     ('echo_client', "", PARAM),
     ('path', "Specify the mountpoint for Lustre.", PARAM),
@@ -383,7 +397,7 @@ class GenConfig:
 
     def osd(self, name, uuid, fstype, osdtype, devname, format, ost_uuid,
             node_uuid, dev_size=0, journal_size=0, inode_size=0, nspath="", 
-            mkfsoptions="", mountfsoptions=""):
+            mkfsoptions="", mountfsoptions="", quota=""):
         osd = self.newService("osd", name, uuid)
         osd.setAttribute('osdtype', osdtype)
         osd.appendChild(self.ref("target", ost_uuid))
@@ -403,6 +417,8 @@ class GenConfig:
                 self.addElement(osd, "mkfsoptions", mkfsoptions)
             if mountfsoptions:
                 self.addElement(osd, "mountfsoptions", mountfsoptions)
+            if quota:
+                self.addElement(osd, "quota", quota)
         if nspath:
             self.addElement(osd, "nspath", nspath)
         return osd
@@ -446,7 +462,7 @@ class GenConfig:
 
     def mdsdev(self, name, uuid, fstype, devname, format, node_uuid,
                mds_uuid, dev_size=0, journal_size=0, inode_size=256,
-               nspath="", mkfsoptions="", mountfsoptions="", group_upcall=""):
+               nspath="", mkfsoptions="", mountfsoptions="", quota="", group_upcall=""):
         mdd = self.newService("mdsdev", name, uuid)
         self.addElement(mdd, "fstype", fstype)
         dev = self.addElement(mdd, "devpath", devname)
@@ -463,6 +479,8 @@ class GenConfig:
             self.addElement(mdd, "mkfsoptions", mkfsoptions)
         if mountfsoptions:
             self.addElement(mdd, "mountfsoptions", mountfsoptions)
+        if quota:
+            self.addElement(mdd, "quota", quota)
        if group_upcall:
             self.addElement(mdd, "group_upcall", group_upcall)
 
@@ -760,6 +778,7 @@ def add_mds(gen, lustre, options):
     nspath = get_option(options, 'nspath')
     mkfsoptions = get_option(options, 'mkfsoptions')
     mountfsoptions = get_option(options, 'mountfsoptions')
+    quota = get_option(options, 'quota')
     group_upcall = get_option(options, 'group_upcall')
 
     node_uuid = name2uuid(lustre, node_name, 'node')
@@ -773,7 +792,7 @@ def add_mds(gen, lustre, options):
     mdd = gen.mdsdev(mdd_name, mdd_uuid, fstype, devname,
                      get_format_flag(options), node_uuid, mds_uuid,
                      size, journal_size, inode_size, nspath, mkfsoptions,
-                     mountfsoptions, group_upcall)
+                     mountfsoptions, quota, group_upcall)
     lustre.appendChild(mdd)
                    
 
@@ -792,7 +811,8 @@ def add_ost(gen, lustre, options):
         journal_size = ''
         inode_size = ''
         mkfsoptions = ''
-        mountfsoptions = ''
+       mountfsoptions = ''
+        quota = ''
     else:
         devname = get_option(options, 'dev') # can be unset for bluearcs
         size = get_option(options, 'size')
@@ -800,7 +820,8 @@ def add_ost(gen, lustre, options):
         journal_size = get_option(options, 'journal_size')
         inode_size = get_option(options, 'inode_size')
         mkfsoptions = get_option(options, 'mkfsoptions')
-        mountfsoptions = get_option(options, 'mountfsoptions')
+       mountfsoptions = get_option(options, 'mountfsoptions')
+        quota = get_option(options, 'quota')
         
     nspath = get_option(options, 'nspath')
 
@@ -839,7 +860,7 @@ def add_ost(gen, lustre, options):
     osd = gen.osd(osdname, osd_uuid, fstype, osdtype, devname,
                   get_format_flag(options), ost_uuid, node_uuid, size,
                   journal_size, inode_size, nspath, mkfsoptions,
-                  mountfsoptions)
+                  mountfsoptions, quota)
 
     node = findByName(lustre, node_name, "node")
 
index 755973c..eea50e4 100644 (file)
@@ -157,7 +157,7 @@ int jt_lcfg_setup(int argc, char **argv)
 
         lustre_cfg_bufs_reset(&bufs, lcfg_devname);
 
-        if (argc > 5)
+        if (argc > 6)
                 return CMD_HELP;
 
         for (i = 1; i < argc; i++) {