[Pkg-lustre-svn-commit] r427 - in /trunk/debian: changelog patches/00list patches/bug10600-smaller-qunit-quota.dpatch patches/bug14619-broken-qunit-allock.dpatch
winnie at users.alioth.debian.org
winnie at users.alioth.debian.org
Thu Jan 24 13:12:06 UTC 2008
Author: winnie
Date: Thu Jan 24 13:12:06 2008
New Revision: 427
URL: http://svn.debian.org/wsvn/pkg-lustre/?sc=1&rev=427
Log:
Add two new patches... but 10600 doesn't apply cleanly yet
Added:
trunk/debian/patches/bug10600-smaller-qunit-quota.dpatch
trunk/debian/patches/bug14619-broken-qunit-allock.dpatch
Modified:
trunk/debian/changelog
trunk/debian/patches/00list
Modified: trunk/debian/changelog
URL: http://svn.debian.org/wsvn/pkg-lustre/trunk/debian/changelog?rev=427&op=diff
==============================================================================
--- trunk/debian/changelog (original)
+++ trunk/debian/changelog Thu Jan 24 13:12:06 2008
@@ -4,6 +4,7 @@
* install own lfs.1 manpage which has more informations
* Removed some old and obsolete programms
* Rediff autogen-run dpatch
+ * Added two quota related patches from the upstream bts
-- Patrick Winnertz <winnie at debian.org> Wed, 02 Jan 2008 14:50:43 +0100
Modified: trunk/debian/patches/00list
URL: http://svn.debian.org/wsvn/pkg-lustre/trunk/debian/patches/00list?rev=427&op=diff
==============================================================================
--- trunk/debian/patches/00list (original)
+++ trunk/debian/patches/00list Thu Jan 24 13:12:06 2008
@@ -11,6 +11,8 @@
remove-set_tunables.dpatch
libsysio.dpatch
remove-fiemaph.dpatch
+#bug10600-smaller-qunit-quota.dpatch
+bug14619-broken-qunit-allock.dpatch
# Debian patches
bash_completion.dpatch
Added: trunk/debian/patches/bug10600-smaller-qunit-quota.dpatch
URL: http://svn.debian.org/wsvn/pkg-lustre/trunk/debian/patches/bug10600-smaller-qunit-quota.dpatch?rev=427&op=file
==============================================================================
--- trunk/debian/patches/bug10600-smaller-qunit-quota.dpatch (added)
+++ trunk/debian/patches/bug10600-smaller-qunit-quota.dpatch Thu Jan 24 13:12:06 2008
@@ -1,0 +1,5889 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## bug10600-smaller-qunit-quota.dpatch by Patrick Winnertz <winnie at debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Patch from upstream bugzilla (bug 10600)
+
+ at DPATCH@
+Index: lustre/ChangeLog
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/ChangeLog,v
+retrieving revision 1.176.2.253
+diff -p -u -r1.176.2.253 ChangeLog
+--- lustre/ChangeLog 17 Jan 2008 21:50:03 -0000 1.176.2.253
++++ lustre/ChangeLog 18 Jan 2008 05:51:44 -0000
+@@ -226,6 +226,17 @@ Details : Before packing join_file re
+ checked carefully in case some malformed flags cause fake
+ join_file req on client.
+
++Severity : normal
++Frequency : always
++Bugzilla : 10600
++Description: shrink/enlarge qunit size when needed; fix the problem of coarse
++ grain of quota doing harm to quota's accuracy
++Details : qunit size will be changed when quota limitation is too low/high;
++ record the pending quota write in order to get more accureate
++ quota; delete the patch for bug12588, which is unnecessary when
++ this patch is landed. This bug also contains 14526, 14299, 14601
++ and 13794, which are found and landed during v1_4_12.
++
+ --------------------------------------------------------------------------------
+
+ 2007-12-07 Cluster File Systems, Inc. <info at clusterfs.com>
+Index: lustre/include/class_hash.h
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/include/class_hash.h,v
+retrieving revision 1.3.6.3
+diff -p -u -r1.3.6.3 class_hash.h
+--- lustre/include/class_hash.h 27 Nov 2007 23:01:03 -0000 1.3.6.3
++++ lustre/include/class_hash.h 18 Jan 2008 05:51:44 -0000
+@@ -135,4 +135,12 @@ void* nidstats_refcount_get(struct hlist
+ void nidstats_refcount_put(struct hlist_node * actual_hnode);
+ extern struct lustre_hash_operations nid_stat_hash_operations;
+
++#ifdef __KERNEL__
++/* ( lqs <-> qctxt ) hash operations define b=10600 */
++__u32 lqs_hashfn(struct lustre_class_hash_body *hash_body, void * key);
++int lqs_hash_key_compare(void *key, struct hlist_node * compared_hnode);
++void * lqs_refcount_get(struct hlist_node * actual_hnode);
++void lqs_refcount_put(struct hlist_node * actual_hnode);
++#endif
++
+ #endif /* __CLASS_HASH_H */
+Index: lustre/include/lustre_quota.h
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/include/lustre_quota.h,v
+retrieving revision 1.3.12.3
+diff -p -u -r1.3.12.3 lustre_quota.h
+--- lustre/include/lustre_quota.h 25 Dec 2007 19:15:08 -0000 1.3.12.3
++++ lustre/include/lustre_quota.h 18 Jan 2008 05:51:44 -0000
+@@ -17,6 +17,7 @@
+ #include <lustre/lustre_idl.h>
+ #include <lustre_net.h>
+ #include <lvfs.h>
++#include <obd_support.h>
+
+ struct obd_device;
+ struct client_obd;
+@@ -69,7 +70,7 @@ struct lustre_dquot {
+ 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) */
+@@ -99,7 +100,7 @@ int lustre_write_quota_info(struct lustr
+ 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 file *file, struct inode *inode, int type,
++int lustre_get_qids(struct file *file, struct inode *inode, int type,
+ struct list_head *list);
+ int lustre_quota_convert(struct lustre_quota_info *lqi, int type);
+ #else
+@@ -150,23 +151,97 @@ typedef int (*dqacq_handler_t) (struct o
+ 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 */
++ dqacq_handler_t lqc_handler; /* dqacq/dqrel RPC handler, only for quota master */
++ unsigned long lqc_recovery:1, /* Doing recovery */
+ lqc_atype:2, /* Turn on user/group quota at setup automatically,
+ * 0: none, 1: user quota, 2: group quota, 3: both */
+- lqc_status:1; /* Quota status. 0:Off, 1:On */
+- spinlock_t lqc_lock; /* guard lqc_imp_valid now */
+- 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
++ lqc_status:1, /* Quota status. 0:Off, 1:On */
++ lqc_switch_qs:1; /* the function of change qunit size
++ * 0:Off, 1:On */
++ unsigned long lqc_iunit_sz; /* original unit size of file quota and
++ * upper limitation for adjust file
++ * qunit */
++ 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_bunit_sz; /* original unit size of block quota and
++ * upper limitation for adjust block
++ * qunit */
+ unsigned long lqc_btune_sz; /* See comment of lqc_itune_sz */
+- unsigned long lqc_limit_sz; /* When remaining quota on ost is less
+- * than this value, ost will request
+- * quota from mds */
++ struct lustre_class_hash_body *lqc_lqs_hash_body;
++ /* all lustre_qunit_size structure in
++ * it */
++ /* the values below are relative to how master change its qunit sizes */
++ unsigned long lqc_cqs_boundary_factor; /* this affects the boundary of
++ * shrinking and enlarging qunit
++ * size. default=4 */
++ unsigned long lqc_cqs_least_bunit; /* the least value of block qunit */
++ unsigned long lqc_cqs_least_iunit; /* the least value of inode qunit */
++ unsigned long lqc_cqs_qs_factor; /* when enlarging, qunit size will
++ * mutilple it; when shrinking,
++ * qunit size will divide it */
++ int lqc_switch_seconds; /* avoid ping-pong effect of
++ * adjusting qunit size. How many
++ * seconds must be waited between
++ * enlarging and shinking qunit */
++ spinlock_t lqc_lock; /* guard lqc_imp_valid now */
+ };
+
++#define LQC_HASH_BODY(qctxt) (qctxt->lqc_lqs_hash_body)
++
++struct lustre_qunit_size {
++ struct hlist_node lqs_hash; /* the hash entry */
++ unsigned int lqs_id; /* id of user/group */
++ unsigned long lqs_flags; /* is user/group; FULLBUF or LESSBUF */
++ unsigned long lqs_iunit_sz; /* Unit size of file quota currently */
++ unsigned long lqs_itune_sz; /* Trigger dqacq when available file quota
++ * less than this value, trigger dqrel
++ * when more than this value + 1 iunit */
++ unsigned long lqs_bunit_sz; /* Unit size of block quota currently */
++ unsigned long lqs_btune_sz; /* See comment of lqs itune sz */
++ unsigned long lqs_bwrite_pending; /* the blocks reached ost and don't
++ * finish */
++ unsigned long lqs_iwrite_pending; /* the inodes reached mds and don't
++ * finish */
++ long long lqs_ino_rec; /* when inodes are allocated/released,
++ * this value will record it */
++ long long lqs_blk_rec; /* when blocks are allocated/released,
++ * this value will record it */
++ atomic_t lqs_refcount;
++ cfs_time_t lqs_last_bshrink; /* time of last block shrink */
++ cfs_time_t lqs_last_ishrink; /* time of last inode shrink */
++ spinlock_t lqs_lock;
++};
++
++#define LQS_IS_GRP(lqs) ((lqs)->lqs_flags & LQUOTA_FLAGS_GRP)
++#define LQS_IS_ADJBLK(lqs) ((lqs)->lqs_flags & LQUOTA_FLAGS_ADJBLK)
++#define LQS_IS_ADJINO(lqs) ((lqs)->lqs_flags & LQUOTA_FLAGS_ADJINO)
++
++#define LQS_SET_GRP(lqs) ((lqs)->lqs_flags |= LQUOTA_FLAGS_GRP)
++#define LQS_SET_ADJBLK(lqs) ((lqs)->lqs_flags |= LQUOTA_FLAGS_ADJBLK)
++#define LQS_SET_ADJINO(lqs) ((lqs)->lqs_flags |= LQUOTA_FLAGS_ADJINO)
++
++static inline void lqs_getref(struct lustre_qunit_size *lqs)
++{
++ atomic_inc(&lqs->lqs_refcount);
++}
++
++static inline void lqs_putref(struct lustre_qunit_size *lqs)
++{
++ if (atomic_dec_and_test(&lqs->lqs_refcount)) {
++ spin_lock(&lqs->lqs_lock);
++ hlist_del_init(&lqs->lqs_hash);
++ spin_unlock(&lqs->lqs_lock);
++ OBD_FREE_PTR(lqs);
++ }
++}
++
++static inline void lqs_initref(struct lustre_qunit_size *lqs)
++{
++ atomic_set(&lqs->lqs_refcount, 0);
++}
++
+ #else
+
+ struct lustre_quota_info {
+@@ -200,6 +275,9 @@ struct quotacheck_thread_args {
+ atomic_t *qta_sem; /* obt_quotachecking */
+ };
+
++typedef int (*quota_acquire)(struct obd_device *obd,
++ unsigned int uid, unsigned int gid);
++
+ typedef struct {
+ int (*quota_init) (void);
+ int (*quota_exit) (void);
+@@ -210,45 +288,55 @@ typedef struct {
+ 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);
+-
++ 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, clear import when relative import is invalid */
+ int (*quota_clearinfo) (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 slave, check whether specified uid/gid's remaining quota
+- * can finish a write rpc */
++ * can finish a block_write or inode_create rpc. It updates the pending
++ * record of block and inode, acquires quota if necessary */
+ int (*quota_chkquota) (struct obd_device *, unsigned int, unsigned int,
+- int);
+-
++ int, int *, quota_acquire);
++
+ /* 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, the actions after the pending write is committed */
++ int (*quota_pending_commit) (struct obd_device *, unsigned int,
++ unsigned int, 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);
++
++ /* For adjusting qunit size b=10600 */
++ int (*quota_adjust_qunit) (struct obd_export *exp, struct
++ quota_adjust_qunit *oqaq);
++
+ } quota_interface_t;
+
+ #define Q_COPY(out, in, member) (out)->member = (in)->member
+
+-#define QUOTA_OP(interface, op) interface->quota_ ## op
++#define QUOTA_OP(interface, op) interface->quota_ ## op
+
+ #define QUOTA_CHECK_OP(interface, op) \
+ do { \
+@@ -264,17 +352,17 @@ static inline int lquota_init(quota_inte
+ {
+ int rc;
+ ENTRY;
+-
++
+ QUOTA_CHECK_OP(interface, init);
+ rc = QUOTA_OP(interface, init)();
+ RETURN(rc);
+ }
+
+-static inline int lquota_exit(quota_interface_t *interface)
++static inline int lquota_exit(quota_interface_t *interface)
+ {
+ int rc;
+ ENTRY;
+-
++
+ QUOTA_CHECK_OP(interface, exit);
+ rc = QUOTA_OP(interface, exit)();
+ RETURN(rc);
+@@ -285,18 +373,18 @@ static inline int lquota_setup(quota_int
+ {
+ int rc;
+ ENTRY;
+-
++
+ QUOTA_CHECK_OP(interface, setup);
+ rc = QUOTA_OP(interface, setup)(obd);
+ RETURN(rc);
+ }
+
+ static inline int lquota_cleanup(quota_interface_t *interface,
+- struct obd_device *obd)
++ struct obd_device *obd)
+ {
+ int rc;
+ ENTRY;
+-
++
+ QUOTA_CHECK_OP(interface, cleanup);
+ rc = QUOTA_OP(interface, cleanup)(obd);
+ RETURN(rc);
+@@ -307,32 +395,32 @@ static inline int lquota_fs_cleanup(quot
+ {
+ int rc;
+ ENTRY;
+-
++
+ QUOTA_CHECK_OP(interface, fs_cleanup);
+ rc = QUOTA_OP(interface, fs_cleanup)(obd);
+ RETURN(rc);
+ }
+
+ static inline int lquota_recovery(quota_interface_t *interface,
+- struct obd_device *obd)
+-{
++ 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)
++ 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);
+@@ -344,7 +432,7 @@ static inline int lquota_chkdq(quota_int
+ {
+ int rc;
+ ENTRY;
+-
++
+ QUOTA_CHECK_OP(interface, chkdq);
+ rc = QUOTA_OP(interface, chkdq)(cli, uid, gid);
+ RETURN(rc);
+@@ -357,7 +445,7 @@ static inline int lquota_setdq(quota_int
+ {
+ int rc;
+ ENTRY;
+-
++
+ QUOTA_CHECK_OP(interface, setdq);
+ rc = QUOTA_OP(interface, setdq)(cli, uid, gid, valid, flags);
+ RETURN(rc);
+@@ -369,16 +457,15 @@ static inline int lquota_poll_check(quot
+ {
+ 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)
++ struct obd_export *exp,
++ struct obd_device *obd)
+ {
+ int rc;
+ ENTRY;
+@@ -389,8 +476,8 @@ static inline int lquota_setinfo(quota_i
+ }
+
+ static inline int lquota_clearinfo(quota_interface_t *interface,
+- struct obd_export *exp,
+- struct obd_device *obd)
++ struct obd_export *exp,
++ struct obd_device *obd)
+ {
+ int rc;
+ ENTRY;
+@@ -400,7 +487,7 @@ static inline int lquota_clearinfo(quota
+ RETURN(rc);
+ }
+
+-static inline int lquota_enforce(quota_interface_t *interface,
++static inline int lquota_enforce(quota_interface_t *interface,
+ struct obd_device *obd,
+ unsigned int ignore)
+ {
+@@ -422,9 +509,9 @@ static inline int lquota_getflag(quota_i
+ rc = QUOTA_OP(interface, getflag)(obd, oa);
+ RETURN(rc);
+ }
+-
++
+ static inline int lquota_acquire(quota_interface_t *interface,
+- struct obd_device *obd,
++ struct obd_device *obd,
+ unsigned int uid, unsigned int gid)
+ {
+ int rc;
+@@ -438,41 +525,55 @@ static inline int lquota_acquire(quota_i
+ static inline int lquota_chkquota(quota_interface_t *interface,
+ struct obd_device *obd,
+ unsigned int uid, unsigned int gid,
+- int npage)
++ int count, int *flag)
+ {
+ int rc;
+ ENTRY;
+-
++
+ QUOTA_CHECK_OP(interface, chkquota);
+- rc = QUOTA_OP(interface, chkquota)(obd, uid, gid, npage);
++ QUOTA_CHECK_OP(interface, acquire);
++ rc = QUOTA_OP(interface, chkquota)(obd, uid, gid, count, flag,
++ QUOTA_OP(interface, acquire));
+ RETURN(rc);
+ }
+
+-int lprocfs_rd_bunit(char *page, char **start, off_t off, int count,
+- int *eof, void *data);
+-int lprocfs_rd_iunit(char *page, char **start, off_t off, int count,
+- int *eof, void *data);
+-int lprocfs_wr_bunit(struct file *file, const char *buffer,
+- unsigned long count, void *data);
+-int lprocfs_wr_iunit(struct file *file, const char *buffer,
+- unsigned long count, void *data);
+-int lprocfs_rd_btune(char *page, char **start, off_t off, int count,
+- int *eof, void *data);
+-int lprocfs_rd_itune(char *page, char **start, off_t off, int count,
+- int *eof, void *data);
+-int lprocfs_wr_btune(struct file *file, const char *buffer,
+- unsigned long count, void *data);
+-int lprocfs_wr_itune(struct file *file, const char *buffer,
+- unsigned long count, void *data);
+-int lprocfs_rd_type(char *page, char **start, off_t off, int count,
+- int *eof, void *data);
+-int lprocfs_wr_type(struct file *file, const char *buffer,
+- unsigned long count, void *data);
+-int lprocfs_filter_rd_limit(char *page, char **start, off_t off, int count,
+- int *eof, void *data);
+-int lprocfs_filter_wr_limit(struct file *file, const char *buffer,
+- unsigned long count, void *data);
++static inline int lquota_pending_commit(quota_interface_t *interface,
++ struct obd_device *obd,
++ unsigned int uid, unsigned int gid,
++ int npage)
++{
++ int rc;
++ ENTRY;
++
++ QUOTA_CHECK_OP(interface, pending_commit);
++ rc = QUOTA_OP(interface, pending_commit)(obd, uid, gid, npage);
++ RETURN(rc);
++}
+
++int lprocfs_quota_rd_bunit(char *page, char **start, off_t off, int count,
++ int *eof, void *data);
++int lprocfs_quota_wr_bunit(struct file *file, const char *buffer,
++ unsigned long count, void *data);
++int lprocfs_quota_rd_btune(char *page, char **start, off_t off, int count,
++ int *eof, void *data);
++int lprocfs_quota_wr_btune(struct file *file, const char *buffer,
++ unsigned long count, void *data);
++int lprocfs_quota_rd_iunit(char *page, char **start, off_t off, int count,
++ int *eof, void *data);
++int lprocfs_quota_wr_iunit(struct file *file, const char *buffer,
++ unsigned long count, void *data);
++int lprocfs_quota_rd_itune(char *page, char **start, off_t off, int count,
++ int *eof, void *data);
++int lprocfs_quota_wr_itune(struct file *file, const char *buffer,
++ unsigned long count, void *data);
++int lprocfs_quota_rd_type(char *page, char **start, off_t off, int count,
++ int *eof, void *data);
++int lprocfs_quota_wr_type(struct file *file, const char *buffer,
++ unsigned long count, void *data);
++int lprocfs_quota_rd_switch_seconds(char *page, char **start, off_t off,
++ int count, int *eof, void *data);
++int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer,
++ unsigned long count, void *data);
+
+ #ifndef __KERNEL__
+ extern quota_interface_t osc_quota_interface;
+Index: lustre/include/obd.h
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/include/obd.h,v
+retrieving revision 1.8.6.17
+diff -p -u -r1.8.6.17 obd.h
+--- lustre/include/obd.h 24 Dec 2007 03:19:57 -0000 1.8.6.17
++++ lustre/include/obd.h 18 Jan 2008 05:51:45 -0000
+@@ -1034,6 +1034,9 @@ struct obd_ops {
+ /* quota methods */
+ int (*o_quotacheck)(struct obd_export *, struct obd_quotactl *);
+ int (*o_quotactl)(struct obd_export *, struct obd_quotactl *);
++ int (*o_quota_adjust_qunit)(struct obd_export *exp,
++ struct quota_adjust_qunit *oqaq);
++
+
+ int (*o_ping)(struct obd_export *exp);
+
+@@ -1117,6 +1120,7 @@ static inline void init_obd_quota_ops(qu
+ LASSERT(obd_ops);
+ obd_ops->o_quotacheck = QUOTA_OP(interface, check);
+ obd_ops->o_quotactl = QUOTA_OP(interface, ctl);
++ obd_ops->o_quota_adjust_qunit = QUOTA_OP(interface, adjust_qunit);
+ }
+
+ #endif /* __OBD_H */
+Index: lustre/include/obd_class.h
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/include/obd_class.h,v
+retrieving revision 1.6.4.13
+diff -p -u -r1.6.4.13 obd_class.h
+--- lustre/include/obd_class.h 3 Jan 2008 06:30:44 -0000 1.6.4.13
++++ lustre/include/obd_class.h 18 Jan 2008 05:51:45 -0000
+@@ -1359,6 +1359,19 @@ static inline int obd_quotactl(struct ob
+ RETURN(rc);
+ }
+
++static inline int obd_quota_adjust_qunit(struct obd_export *exp,
++ struct quota_adjust_qunit *oqaq)
++{
++ int rc;
++ ENTRY;
++
++ EXP_CHECK_OP(exp, quota_adjust_qunit);
++ EXP_COUNTER_INCREMENT(exp, quota_adjust_qunit);
++
++ rc = OBP(exp->exp_obd, quota_adjust_qunit)(exp, oqaq);
++ RETURN(rc);
++}
++
+ static inline int obd_health_check(struct obd_device *obd)
+ {
+ /* returns: 0 on healthy
+Index: lustre/include/obd_support.h
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/include/obd_support.h,v
+retrieving revision 1.6.2.32
+diff -p -u -r1.6.2.32 obd_support.h
+--- lustre/include/obd_support.h 24 Dec 2007 03:19:58 -0000 1.6.2.32
++++ lustre/include/obd_support.h 18 Jan 2008 05:51:45 -0000
+@@ -26,6 +26,7 @@
+ #include <libcfs/kp30.h>
+ #include <lvfs.h>
+ #include <lprocfs_status.h>
++#include <lustre/lustre_idl.h>
+
+ /* global variables */
+ extern struct lprocfs_stats *obd_memory;
+@@ -254,7 +255,18 @@ extern unsigned int obd_alloc_fail_rate;
+ #define OBD_FAIL_MGS_PAUSE_REQ 0x904
+ #define OBD_FAIL_MGS_PAUSE_TARGET_REG 0x905
+
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
+ #define OBD_FAIL_QUOTA_QD_COUNT_32BIT 0xA00
++#else
++#warning "remove quota code above for format obsolete in new release"
++#endif
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 9, 0, 0)
++#define OBD_FAIL_QUOTA_WITHOUT_CHANGE_QS 0xA01
++#else
++#warning "remove quota code above for format obsolete in new release"
++#endif
++
++#define OBD_FAIL_QUOTA_RET_QDATA 0xA02
+
+ #define OBD_FAIL_LPROC_REMOVE 0xB00
+
+Index: lustre/include/lustre/lustre_idl.h
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/include/lustre/lustre_idl.h,v
+retrieving revision 1.3.12.19
+diff -p -u -r1.3.12.19 lustre_idl.h
+--- lustre/include/lustre/lustre_idl.h 9 Jan 2008 20:01:05 -0000 1.3.12.19
++++ lustre/include/lustre/lustre_idl.h 18 Jan 2008 05:51:46 -0000
+@@ -64,6 +64,7 @@
+
+ /* Defn's shared with user-space. */
+ #include <lustre/lustre_user.h>
++#include <lustre_ver.h>
+
+ /*
+ * this file contains all data structures used in Lustre interfaces:
+@@ -292,6 +293,8 @@ extern void lustre_swab_ptlrpc_body(stru
+ #define OBD_CONNECT_LRU_RESIZE 0x02000000ULL /*Lru resize feature. */
+ #define OBD_CONNECT_MDS_MDS 0x04000000ULL /*MDS-MDS connection */
+ #define OBD_CONNECT_REAL 0x08000000ULL /*real connection */
++#define OBD_CONNECT_CHANGE_QS 0x10000000ULL /*shrink/enlarge qunit size
++ *b=10600 */
+ #define OBD_CONNECT_CKSUM 0x20000000ULL /*support several cksum algos */
+ /* also update obd_connect_names[] for lprocfs_rd_connect_flags()
+ * and lustre/utils/wirecheck.c */
+@@ -313,7 +316,7 @@ extern void lustre_swab_ptlrpc_body(stru
+ OBD_CONNECT_TRUNCLOCK | OBD_CONNECT_INDEX | \
+ OBD_CONNECT_BRW_SIZE | OBD_CONNECT_QUOTA64 | \
+ OBD_CONNECT_CANCELSET | OBD_CONNECT_AT | \
+- LRU_RESIZE_CONNECT_FLAG)
++ LRU_RESIZE_CONNECT_FLAG | OBD_CONNECT_CHANGE_QS)
+ #define ECHO_CONNECT_SUPPORTED (0)
+ #define MGS_CONNECT_SUPPORTED (OBD_CONNECT_VERSION | OBD_CONNECT_AT)
+
+@@ -373,6 +376,7 @@ typedef enum {
+ OST_SET_INFO = 17,
+ OST_QUOTACHECK = 18,
+ OST_QUOTACTL = 19,
++ OST_QUOTA_ADJUST_QUNIT = 20,
+ OST_LAST_OPC
+ } ost_cmd_t;
+ #define OST_FIRST_OPC OST_REPLY
+@@ -819,6 +823,34 @@ struct obd_quotactl {
+
+ extern void lustre_swab_obd_quotactl(struct obd_quotactl *q);
+
++struct quota_adjust_qunit {
++ __u32 qaq_flags;
++ __u32 qaq_id;
++ __u64 qaq_bunit_sz;
++ __u64 qaq_iunit_sz;
++ __u64 padding1;
++};
++extern void lustre_swab_quota_adjust_qunit(struct quota_adjust_qunit *q);
++
++/* flags in qunit_data and quota_adjust_qunit will use macroes below */
++#define LQUOTA_FLAGS_GRP 1UL /* 0 is user, 1 is group */
++#define LQUOTA_FLAGS_BLK 2UL /* 0 is inode, 1 is block */
++#define LQUOTA_FLAGS_ADJBLK 4UL /* adjust the block qunit size */
++#define LQUOTA_FLAGS_ADJINO 8UL /* adjust the inode qunit size */
++#define LQUOTA_FLAGS_CHG_QS 16UL /* indicate whether it has capability of
++ * OBD_CONNECT_CHANGE_QS */
++
++/* the status of lqs_flags in struct lustre_qunit_size */
++#define LQUOTA_QUNIT_FLAGS (LQUOTA_FLAGS_GRP | LQUOTA_FLAGS_BLK)
++
++#define QAQ_IS_GRP(qaq) ((qaq)->qaq_flags & LQUOTA_FLAGS_GRP)
++#define QAQ_IS_ADJBLK(qaq) ((qaq)->qaq_flags & LQUOTA_FLAGS_ADJBLK)
++#define QAQ_IS_ADJINO(qaq) ((qaq)->qaq_flags & LQUOTA_FLAGS_ADJINO)
++
++#define QAQ_SET_GRP(qaq) ((qaq)->qaq_flags |= LQUOTA_FLAGS_GRP)
++#define QAQ_SET_ADJBLK(qaq) ((qaq)->qaq_flags |= LQUOTA_FLAGS_ADJBLK)
++#define QAQ_SET_ADJINO(qaq) ((qaq)->qaq_flags |= LQUOTA_FLAGS_ADJINO)
++
+ struct mds_rec_setattr {
+ __u32 sa_opcode;
+ __u32 sa_fsuid;
+@@ -1462,28 +1494,69 @@ extern void lustre_swab_llog_rec(struct
+ struct lustre_cfg;
+ extern void lustre_swab_lustre_cfg(struct lustre_cfg *lcfg);
+
+-/* quota. fixed by tianzy for bug10707 */
+-#define QUOTA_IS_GRP 0X1UL /* 0 is user, 1 is group. Used by qd_flags*/
+-#define QUOTA_IS_BLOCK 0x2UL /* 0 is inode, 1 is block. Used by qd_flags*/
+-
++/* this will be used when OBD_CONNECT_CHANGE_QS is set */
+ struct qunit_data {
++ __u32 qd_id; /* ID appiles to (uid, gid) */
++ __u32 qd_flags; /* LQUOTA_FLAGS_* affect the responding bits */
++ __u64 qd_count; /* acquire/release count (bytes for block quota) */
++ __u64 qd_qunit; /* when a master returns the reply to a slave, it will
++ * contain the current corresponding qunit size */
++ __u64 padding;
++};
++
++#define QDATA_IS_GRP(qdata) ((qdata)->qd_flags & LQUOTA_FLAGS_GRP)
++#define QDATA_IS_BLK(qdata) ((qdata)->qd_flags & LQUOTA_FLAGS_BLK)
++#define QDATA_IS_ADJBLK(qdata) ((qdata)->qd_flags & LQUOTA_FLAGS_ADJBLK)
++#define QDATA_IS_ADJINO(qdata) ((qdata)->qd_flags & LQUOTA_FLAGS_ADJINO)
++#define QDATA_IS_CHANGE_QS(qdata) ((qdata)->qd_flags & LQUOTA_FLAGS_CHG_QS)
++
++#define QDATA_SET_GRP(qdata) ((qdata)->qd_flags |= LQUOTA_FLAGS_GRP)
++#define QDATA_SET_BLK(qdata) ((qdata)->qd_flags |= LQUOTA_FLAGS_BLK)
++#define QDATA_SET_ADJBLK(qdata) ((qdata)->qd_flags |= LQUOTA_FLAGS_ADJBLK)
++#define QDATA_SET_ADJINO(qdata) ((qdata)->qd_flags |= LQUOTA_FLAGS_ADJINO)
++#define QDATA_SET_CHANGE_QS(qdata) ((qdata)->qd_flags |= LQUOTA_FLAGS_CHG_QS)
++
++#define QDATA_CLR_GRP(qdata) ((qdata)->qd_flags &= ~LQUOTA_FLAGS_GRP)
++#define QDATA_CLR_CHANGE_QS(qdata) ((qdata)->qd_flags &= ~LQUOTA_FLAGS_CHG_QS)
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 9, 0, 0)
++/* this will be used when OBD_CONNECT_QUOTA64 is set */
++struct qunit_data_old2 {
+ __u32 qd_id; /* ID appiles to (uid, gid) */
+ __u32 qd_flags; /* Quota type (USRQUOTA, GRPQUOTA) occupy one bit;
+ * Block quota or file quota occupy one bit */
+ __u64 qd_count; /* acquire/release count (bytes for block quota) */
+ };
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
+
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
+ struct qunit_data_old {
+ __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 */
+ };
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
+
+ extern void lustre_swab_qdata(struct qunit_data *d);
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
+ extern void lustre_swab_qdata_old(struct qunit_data_old *d);
+-extern struct qunit_data *lustre_quota_old_to_new(struct qunit_data_old *d);
+-extern struct qunit_data_old *lustre_quota_new_to_old(struct qunit_data *d);
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 9, 0, 0)
++extern void lustre_swab_qdata_old2(struct qunit_data_old2 *d);
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++extern int quota_get_qdata(void*req, struct qunit_data *qdata,
++ int is_req, int is_exp);
++extern int quota_copy_qdata(void *request, struct qunit_data *qdata,
++ int is_req, int is_exp);
+
+ typedef enum {
+ QUOTA_DQACQ = 601,
+@@ -1492,10 +1565,17 @@ typedef enum {
+
+ #define JOIN_FILE_ALIGN 4096
+
++#define QUOTA_REQUEST 1
++#define QUOTA_REPLY 0
++#define QUOTA_EXPORT 1
++#define QUOTA_IMPORT 0
++
+ /* quota check function */
+ #define QUOTA_RET_OK 0 /* return successfully */
+ #define QUOTA_RET_NOQUOTA 1 /* not support quota */
+ #define QUOTA_RET_NOLIMIT 2 /* quota limit isn't set */
+-#define QUOTA_RET_ACQUOTA 3 /* need to acquire extra quota */
++#define QUOTA_RET_ACQUOTA 4 /* need to acquire extra quota */
++#define QUOTA_RET_INC_PENDING 8 /* pending value is increased */
+
++extern int quota_get_qunit_data_size(__u64 flag);
+ #endif
+Index: lustre/ldlm/ldlm_lib.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/ldlm/ldlm_lib.c,v
+retrieving revision 1.96.6.24
+diff -p -u -r1.96.6.24 ldlm_lib.c
+--- lustre/ldlm/ldlm_lib.c 9 Jan 2008 20:01:08 -0000 1.96.6.24
++++ lustre/ldlm/ldlm_lib.c 18 Jan 2008 05:51:46 -0000
+@@ -1606,68 +1606,56 @@ int target_handle_dqacq_callback(struct
+ struct obd_device *obd = req->rq_export->exp_obd;
+ struct obd_device *master_obd;
+ struct lustre_quota_ctxt *qctxt;
+- struct qunit_data *qdata;
+- void* rep;
+- struct qunit_data_old *qdata_old;
++ struct qunit_data *qdata = NULL;
+ int rc = 0;
+- int repsize[2] = { sizeof(struct ptlrpc_body),
+- sizeof(struct qunit_data) };
++ int repsize[2] = { sizeof(struct ptlrpc_body), 0 };
+ ENTRY;
+-
++
++ repsize[1] = quota_get_qunit_data_size(req->rq_export->
++ exp_connect_flags);
++
+ rc = lustre_pack_reply(req, 2, repsize, NULL);
+ if (rc)
+ RETURN(rc);
+
+ LASSERT(req->rq_export);
+
+- /* fixed for bug10707 */
+- if ((req->rq_export->exp_connect_flags & OBD_CONNECT_QUOTA64) &&
+- !OBD_FAIL_CHECK(OBD_FAIL_QUOTA_QD_COUNT_32BIT)) {
+- CDEBUG(D_QUOTA, "qd_count is 64bit!\n");
+- rep = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF,
+- sizeof(struct qunit_data));
+- LASSERT(rep);
+- qdata = lustre_swab_reqbuf(req, REQ_REC_OFF, sizeof(*qdata),
+- lustre_swab_qdata);
+- } else {
+- CDEBUG(D_QUOTA, "qd_count is 32bit!\n");
+- rep = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF,
+- sizeof(struct qunit_data_old));
+- LASSERT(rep);
+- qdata_old = lustre_swab_reqbuf(req, REQ_REC_OFF, sizeof(*qdata_old),
+- lustre_swab_qdata_old);
+- qdata = lustre_quota_old_to_new(qdata_old);
+- }
+-
+- if (qdata == NULL) {
+- CERROR("Can't unpack qunit_data\n");
+- RETURN(-EPROTO);
++ /* there are three forms of qunit(historic causes), so we need to
++ * adjust qunits from slaves to the same form here */
++ OBD_ALLOC(qdata, sizeof(struct qunit_data));
++ if (!qdata)
++ RETURN(-ENOMEM);
++ rc = quota_get_qdata(req, qdata, QUOTA_REQUEST, QUOTA_EXPORT);
++ if (rc < 0) {
++ CDEBUG(D_ERROR, "Can't unpack qunit_data\n");
++ GOTO(out, rc = -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,
+ lustre_msg_get_opc(req->rq_reqmsg));
+ if (rc && rc != -EDQUOT)
+- CDEBUG(rc == -EBUSY ? D_QUOTA : D_ERROR,
++ CDEBUG(rc == -EBUSY ? D_QUOTA : D_ERROR,
+ "dqacq failed! (rc:%d)\n", rc);
+-
+- /* the qd_count might be changed in lqc_handler */
+- if ((req->rq_export->exp_connect_flags & OBD_CONNECT_QUOTA64) &&
+- !OBD_FAIL_CHECK(OBD_FAIL_QUOTA_QD_COUNT_32BIT)) {
+- memcpy(rep,qdata,sizeof(*qdata));
+- } else {
+- qdata_old = lustre_quota_new_to_old(qdata);
+- memcpy(rep,qdata_old,sizeof(*qdata_old));
+- }
+ req->rq_status = rc;
++
++ /* there are three forms of qunit(historic causes), so we need to
++ * adjust the same form to different forms slaves needed */
++ rc = quota_copy_qdata(req, qdata, QUOTA_REPLY, QUOTA_EXPORT);
++ if (rc < 0) {
++ CDEBUG(D_ERROR, "Can't pack qunit_data\n");
++ GOTO(out, rc = -EPROTO);
++ }
++
+ rc = ptlrpc_reply(req);
+-
+- RETURN(rc);
++out:
++ OBD_FREE(qdata, sizeof(struct qunit_data));
++ RETURN(rc);
+ #else
+ return 0;
+ #endif /* !__KERNEL__ */
+Index: lustre/mds/lproc_mds.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/mds/lproc_mds.c,v
+retrieving revision 1.37.34.4
+diff -p -u -r1.37.34.4 lproc_mds.c
+--- lustre/mds/lproc_mds.c 3 Jan 2008 06:30:57 -0000 1.37.34.4
++++ lustre/mds/lproc_mds.c 18 Jan 2008 05:51:46 -0000
+@@ -99,7 +99,7 @@ static int lprocfs_mds_wr_evict_client(s
+ ptlrpc_check_set(set);
+ }
+
+- /* See the comments in function lprocfs_wr_evict_client()
++ /* See the comments in function lprocfs_wr_evict_client()
+ * in ptlrpc/lproc_ptlrpc.c for details. - jay */
+ class_incref(obd);
+ LPROCFS_EXIT();
+@@ -392,6 +392,155 @@ static int lprocfs_rd_nosquash_nid(char
+ libcfs_nid2str(mds->mds_nosquash_nid));
+ }
+
++#ifdef HAVE_QUOTA_SUPPORT
++static int lprocfs_mds_rd_switch_qs(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, "changing qunit size is %s\n",
++ obd->u.obt.obt_qctxt.lqc_switch_qs ?
++ "enabled" : "disabled");
++}
++
++static int lprocfs_mds_rd_boundary_factor(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_cqs_boundary_factor);
++}
++
++static int lprocfs_mds_rd_least_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_cqs_least_bunit);
++}
++
++static int lprocfs_mds_rd_least_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_cqs_least_iunit);
++}
++
++static int lprocfs_mds_rd_qs_factor(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_cqs_qs_factor);
++}
++
++static int lprocfs_mds_wr_switch_qs(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_switch_qs = 1;
++ else
++ obd->u.obt.obt_qctxt.lqc_switch_qs = 0;
++
++ return count;
++}
++
++static int lprocfs_mds_wr_boundary_factor(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 < 2)
++ return -EINVAL;
++
++ obd->u.obt.obt_qctxt.lqc_cqs_boundary_factor = val;
++ return count;
++}
++
++static int lprocfs_mds_wr_least_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 < PTLRPC_MAX_BRW_SIZE ||
++ val >= obd->u.obt.obt_qctxt.lqc_bunit_sz)
++ return -EINVAL;
++
++ obd->u.obt.obt_qctxt.lqc_cqs_least_bunit = val;
++ return count;
++}
++
++static int lprocfs_mds_wr_least_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 < 1 || val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
++ return -EINVAL;
++
++ obd->u.obt.obt_qctxt.lqc_cqs_least_iunit = val;
++ return count;
++}
++
++static int lprocfs_mds_wr_qs_factor(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 < 2)
++ return -EINVAL;
++
++ obd->u.obt.obt_qctxt.lqc_cqs_qs_factor = val;
++ return count;
++}
++#endif
++
+ struct lprocfs_vars lprocfs_mds_obd_vars[] = {
+ { "uuid", lprocfs_rd_uuid, 0, 0 },
+ { "blocksize", lprocfs_rd_blksize, 0, 0 },
+@@ -408,11 +557,23 @@ struct lprocfs_vars lprocfs_mds_obd_vars
+ lprocfs_mds_wr_evictostnids, 0 },
+ { "num_exports", lprocfs_rd_num_exports, 0, 0 },
+ #ifdef HAVE_QUOTA_SUPPORT
+- { "quota_bunit_sz", lprocfs_rd_bunit, lprocfs_wr_bunit, 0 },
+- { "quota_btune_sz", lprocfs_rd_btune, lprocfs_wr_btune, 0 },
+- { "quota_iunit_sz", lprocfs_rd_iunit, lprocfs_wr_iunit, 0 },
+- { "quota_itune_sz", lprocfs_rd_itune, lprocfs_wr_itune, 0 },
+- { "quota_type", lprocfs_rd_type, lprocfs_wr_type, 0 },
++ { "quota_bunit_sz", lprocfs_quota_rd_bunit, lprocfs_quota_wr_bunit, 0 },
++ { "quota_btune_sz", lprocfs_quota_rd_btune, lprocfs_quota_wr_btune, 0 },
++ { "quota_iunit_sz", lprocfs_quota_rd_iunit, lprocfs_quota_wr_iunit, 0 },
++ { "quota_itune_sz", lprocfs_quota_rd_itune, lprocfs_quota_wr_itune, 0 },
++ { "quota_type", lprocfs_quota_rd_type, lprocfs_quota_wr_type, 0 },
++ { "quota_switch_qs", lprocfs_mds_rd_switch_qs,
++ lprocfs_mds_wr_switch_qs, 0 },
++ { "quota_boundary_factor", lprocfs_mds_rd_boundary_factor,
++ lprocfs_mds_wr_boundary_factor, 0 },
++ { "quota_least_bunit", lprocfs_mds_rd_least_bunit,
++ lprocfs_mds_wr_least_bunit, 0 },
++ { "quota_least_iunit", lprocfs_mds_rd_least_iunit,
++ lprocfs_mds_wr_least_iunit, 0 },
++ { "quota_qs_factor", lprocfs_mds_rd_qs_factor,
++ lprocfs_mds_wr_qs_factor, 0 },
++ { "quota_switch_seconds", lprocfs_quota_rd_switch_seconds,
++ lprocfs_quota_wr_switch_seconds, 0 },
+ #endif
+ { "group_expire_interval", lprocfs_rd_group_expire,
+ lprocfs_wr_group_expire, 0},
+Index: lustre/mds/mds_lov.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/mds/mds_lov.c,v
+retrieving revision 1.90.18.15
+diff -p -u -r1.90.18.15 mds_lov.c
+--- lustre/mds/mds_lov.c 21 Dec 2007 09:32:47 -0000 1.90.18.15
++++ lustre/mds/mds_lov.c 18 Jan 2008 05:51:47 -0000
+@@ -507,7 +507,8 @@ int mds_lov_connect(struct obd_device *o
+ if (data == NULL)
+ RETURN(-ENOMEM);
+ data->ocd_connect_flags = OBD_CONNECT_VERSION | OBD_CONNECT_INDEX |
+- OBD_CONNECT_REQPORTAL | OBD_CONNECT_QUOTA64 | OBD_CONNECT_AT;
++ OBD_CONNECT_REQPORTAL | OBD_CONNECT_QUOTA64 | OBD_CONNECT_AT |
++ OBD_CONNECT_CHANGE_QS;
+ #ifdef HAVE_LRU_RESIZE_SUPPORT
+ data->ocd_connect_flags |= OBD_CONNECT_LRU_RESIZE;
+ #endif
+Index: lustre/mds/mds_open.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/mds/mds_open.c,v
+retrieving revision 1.150.32.13
+diff -p -u -r1.150.32.13 mds_open.c
+--- lustre/mds/mds_open.c 20 Dec 2007 09:13:07 -0000 1.150.32.13
++++ lustre/mds/mds_open.c 18 Jan 2008 05:51:47 -0000
+@@ -872,6 +872,8 @@ int mds_open(struct mds_update_record *r
+ ldlm_policy_data_t policy = {.l_inodebits={MDS_INODELOCK_LOOKUP}};
+ struct ldlm_res_id child_res_id = { .name = {0}};
+ int lock_flags = 0;
++ int rec_pending = 0;
++ unsigned int gid = current->fsgid;
+ ENTRY;
+
+ mds_counter_incr(req->rq_export, LPROC_MDS_OPEN);
+@@ -1018,6 +1020,16 @@ int mds_open(struct mds_update_record *r
+ if (req->rq_export->exp_connect_flags & OBD_CONNECT_RDONLY)
+ GOTO(cleanup, rc = -EROFS);
+
++ if (dparent->d_inode->i_mode & S_ISGID)
++ gid = dparent->d_inode->i_gid;
++ else
++ gid = current->fsgid;
++ rc = lquota_chkquota(mds_quota_interface_ref, obd,
++ current->fsuid, gid, 1, &rec_pending);
++
++ if (rc < 0)
++ GOTO(cleanup, rc);
++
+ intent_set_disposition(rep, DISP_OPEN_CREATE);
+ handle = fsfilt_start(obd, dparent->d_inode, FSFILT_OP_CREATE,
+ NULL);
+@@ -1053,10 +1065,7 @@ int mds_open(struct mds_update_record *r
+ LTIME_S(iattr.ia_mtime) = rec->ur_time;
+
+ iattr.ia_uid = current->fsuid; /* set by push_ctxt already */
+- if (dparent->d_inode->i_mode & S_ISGID)
+- iattr.ia_gid = dparent->d_inode->i_gid;
+- else
+- iattr.ia_gid = current->fsgid;
++ iattr.ia_gid = gid;
+
+ iattr.ia_valid = ATTR_UID | ATTR_GID | ATTR_ATIME |
+ ATTR_MTIME | ATTR_CTIME;
+@@ -1189,6 +1198,9 @@ found_child:
+ req, rc, rep ? rep->lock_policy_res1 : 0, 0);
+
+ cleanup_no_trans:
++ if (rec_pending)
++ lquota_pending_commit(mds_quota_interface_ref, obd,
++ current->fsuid, gid, 1);
+ switch (cleanup_phase) {
+ case 3:
+ if (rc)
+Index: lustre/mds/mds_reint.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/mds/mds_reint.c,v
+retrieving revision 1.264.32.11
+diff -p -u -r1.264.32.11 mds_reint.c
+--- lustre/mds/mds_reint.c 13 Dec 2007 03:44:02 -0000 1.264.32.11
++++ lustre/mds/mds_reint.c 18 Jan 2008 05:51:48 -0000
+@@ -776,6 +776,8 @@ static int mds_reint_create(struct mds_u
+ unsigned int qcids[MAXQUOTAS] = { current->fsuid, current->fsgid };
+ unsigned int qpids[MAXQUOTAS] = { 0, 0 };
+ struct lvfs_dentry_params dp = LVFS_DENTRY_PARAMS_INIT;
++ int rec_pending = 0;
++ unsigned int gid = current->fsgid;
+ ENTRY;
+
+ LASSERT(offset == REQ_REC_OFF);
+@@ -835,6 +837,17 @@ static int mds_reint_create(struct mds_u
+ dp.ldp_inum = (unsigned long)rec->ur_fid2->id;
+ dp.ldp_ptr = req;
+
++ if (dir->i_mode & S_ISGID)
++ gid = dir->i_gid;
++ else
++ gid = current->fsgid;
++
++ rc = lquota_chkquota(mds_quota_interface_ref, obd,
++ current->fsuid, gid, 1, &rec_pending);
++
++ if (rc < 0)
++ GOTO(cleanup, rc);
++
+ switch (type) {
+ case S_IFREG:{
+ handle = fsfilt_start(obd, dir, FSFILT_OP_CREATE, NULL);
+@@ -902,10 +915,7 @@ static int mds_reint_create(struct mds_u
+ LTIME_S(iattr.ia_ctime) = rec->ur_time;
+ LTIME_S(iattr.ia_mtime) = rec->ur_time;
+ iattr.ia_uid = current->fsuid; /* set by push_ctxt already */
+- if (dir->i_mode & S_ISGID)
+- iattr.ia_gid = dir->i_gid;
+- else
+- iattr.ia_gid = current->fsgid;
++ iattr.ia_gid = gid;
+ iattr.ia_valid = ATTR_UID | ATTR_GID | ATTR_ATIME |
+ ATTR_MTIME | ATTR_CTIME;
+
+@@ -952,6 +962,9 @@ static int mds_reint_create(struct mds_u
+
+ cleanup:
+ err = mds_finish_transno(mds, dir, handle, req, rc, 0, 0);
++ if (rec_pending)
++ lquota_pending_commit(mds_quota_interface_ref, obd,
++ current->fsuid, gid, 1);
+
+ if (rc && created) {
+ /* Destroy the file we just created. This should not need
+Index: lustre/obdclass/class_hash.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/obdclass/class_hash.c,v
+retrieving revision 1.3.6.3
+diff -p -u -r1.3.6.3 class_hash.c
+--- lustre/obdclass/class_hash.c 27 Nov 2007 23:01:05 -0000 1.3.6.3
++++ lustre/obdclass/class_hash.c 18 Jan 2008 05:51:48 -0000
+@@ -21,9 +21,10 @@
+ #include <lustre_export.h>
+ #include <obd_support.h>
+ #include <lustre_net.h>
++#include <lustre_quota.h>
+
+-int lustre_hash_init(struct lustre_class_hash_body **hash_body_new,
+- char *hashname, __u32 hashsize,
++int lustre_hash_init(struct lustre_class_hash_body **hash_body_new,
++ char *hashname, __u32 hashsize,
+ struct lustre_hash_operations *hash_operations)
+ {
+ int i, n = 0;
+@@ -42,28 +43,28 @@ int lustre_hash_init(struct lustre_class
+
+ LASSERTF(n == 1, "hashsize %u isn't 2^n\n", hashsize);
+
+- /* alloc space for hash_body */
+- OBD_ALLOC(hash_body, sizeof(*hash_body));
++ /* alloc space for hash_body */
++ OBD_ALLOC(hash_body, sizeof(*hash_body));
+
+ if (hash_body == NULL) {
+- CERROR("Cannot alloc space for hash body, hashname = %s \n",
++ CERROR("Cannot alloc space for hash body, hashname = %s \n",
+ hashname);
+ RETURN(-ENOMEM);
+ }
+
+- LASSERT(hashname != NULL &&
++ LASSERT(hashname != NULL &&
+ strlen(hashname) <= sizeof(hash_body->hashname));
+ strcpy(hash_body->hashname, hashname);
+- hash_body->lchb_hash_max_size = hashsize;
+- hash_body->lchb_hash_operations = hash_operations;
++ hash_body->lchb_hash_max_size = hashsize;
++ hash_body->lchb_hash_operations = hash_operations;
+
+ /* alloc space for the hash tables */
+- OBD_ALLOC(hash_body->lchb_hash_tables,
++ OBD_ALLOC(hash_body->lchb_hash_tables,
+ sizeof(*hash_body->lchb_hash_tables) * hash_body->lchb_hash_max_size);
+
+ if (hash_body->lchb_hash_tables == NULL) {
+- OBD_FREE(hash_body, sizeof(*hash_body));
+- CERROR("Cannot alloc space for hashtables, hashname = %s \n",
++ OBD_FREE(hash_body, sizeof(*hash_body));
++ CERROR("Cannot alloc space for hashtables, hashname = %s \n",
+ hash_body->hashname);
+ RETURN(-ENOMEM);
+ }
+@@ -99,7 +100,7 @@ void lustre_hash_exit(struct lustre_clas
+ if (hash_body->lchb_hash_tables == NULL ) {
+ spin_unlock(&hash_body->lchb_lock);
+ CWARN("hash tables has been deleted\n");
+- goto out_hash;
++ goto out_hash;
+ }
+
+ for( i = 0; i < hash_body->lchb_hash_max_size; i++ ) {
+@@ -111,12 +112,13 @@ void lustre_hash_exit(struct lustre_clas
+ hlist_for_each_safe(actual_hnode, pos, &(bucket->lhb_head)) {
+ lustre_hash_delitem_nolock(hash_body, i, actual_hnode);
+ }
+- spin_unlock(&bucket->lhb_lock);
++ spin_unlock(&bucket->lhb_lock);
+ }
+
+ /* free the hash_tables's memory space */
+ OBD_FREE(hash_body->lchb_hash_tables,
+- sizeof(*hash_body->lchb_hash_tables) * hash_body->lchb_hash_max_size);
++ sizeof(*hash_body->lchb_hash_tables) *
++ hash_body->lchb_hash_max_size);
+
+ hash_body->lchb_hash_tables = NULL;
+
+@@ -671,3 +673,84 @@ void nidstats_refcount_put(struct hlist_
+ }
+
+ /*******************************************************************************/
++
++#ifdef __KERNEL__
++/*
++ * define ( lqs <-> qctxt ) hash operations and function define
++ */
++
++/* define the conn hash operations */
++struct lustre_hash_operations lqs_hash_operations = {
++ .lustre_hashfn = lqs_hashfn,
++ .lustre_hash_key_compare = lqs_hash_key_compare,
++ .lustre_hash_object_refcount_get = lqs_refcount_get,
++ .lustre_hash_object_refcount_put = lqs_refcount_put,
++};
++EXPORT_SYMBOL(lqs_hash_operations);
++
++/* string hashing using djb2 hash algorithm */
++__u32 lqs_hashfn(struct lustre_class_hash_body *hash_body, void * key)
++{
++ struct quota_adjust_qunit *lqs_key = NULL;
++ __u32 hash;
++
++ LASSERT(key != NULL);
++
++ lqs_key = (struct quota_adjust_qunit *)key;
++
++ hash = QAQ_IS_GRP(lqs_key) ? 5381 : 5387;
++ hash *= lqs_key->qaq_id;
++
++ hash &= (hash_body->lchb_hash_max_size - 1);
++
++ RETURN(hash);
++}
++
++int lqs_hash_key_compare(void *key, struct hlist_node *compared_hnode)
++{
++ struct quota_adjust_qunit *lqs_key = NULL;
++ struct lustre_qunit_size *q = NULL;
++ int retval = 0;
++
++ LASSERT( key != NULL);
++
++ lqs_key = (struct quota_adjust_qunit *)key;
++
++ q = hlist_entry(compared_hnode, struct lustre_qunit_size, lqs_hash);
++
++ spin_lock(&q->lqs_lock);
++ if (lqs_key->qaq_id == q->lqs_id && QAQ_IS_GRP(lqs_key) == LQS_IS_GRP(q))
++ retval = 1;
++ spin_unlock(&q->lqs_lock);
++
++ return retval;
++}
++
++void * lqs_refcount_get(struct hlist_node * actual_hnode)
++{
++ struct lustre_qunit_size *q = NULL;
++
++ LASSERT(actual_hnode != NULL);
++
++ q = hlist_entry(actual_hnode, struct lustre_qunit_size, lqs_hash);
++
++ LASSERT(q != NULL);
++
++ lqs_getref(q);
++
++ RETURN(q);
++}
++
++void lqs_refcount_put(struct hlist_node * actual_hnode)
++{
++ struct lustre_qunit_size *q = NULL;
++
++ LASSERT(actual_hnode != NULL);
++
++ q = hlist_entry(actual_hnode, struct lustre_qunit_size, lqs_hash);
++
++ LASSERT(q != NULL);
++
++ lqs_putref(q);
++}
++#endif
+Index: lustre/obdclass/lprocfs_status.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/obdclass/lprocfs_status.c,v
+retrieving revision 1.43.34.17
+diff -p -u -r1.43.34.17 lprocfs_status.c
+--- lustre/obdclass/lprocfs_status.c 26 Dec 2007 08:27:09 -0000 1.43.34.17
++++ lustre/obdclass/lprocfs_status.c 18 Jan 2008 05:51:48 -0000
+@@ -1121,6 +1121,7 @@ void lprocfs_init_ops_stats(int num_priv
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, health_check);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotacheck);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, quotactl);
++ LPROCFS_OBD_OP_INIT(num_private_stats, stats, quota_adjust_qunit);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, ping);
+ LPROCFS_OBD_OP_INIT(num_private_stats, stats, register_page_removal_cb);
+ LPROCFS_OBD_OP_INIT(num_private_stats,stats,unregister_page_removal_cb);
+@@ -1708,6 +1709,163 @@ int lprocfs_obd_wr_recovery_maxtime(stru
+ EXPORT_SYMBOL(lprocfs_obd_wr_recovery_maxtime);
+ #endif /* CRAY_XT3 */
+
++#ifdef HAVE_QUOTA_SUPPORT
++int lprocfs_quota_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);
++}
++EXPORT_SYMBOL(lprocfs_quota_rd_bunit);
++
++int lprocfs_quota_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;
++}
++EXPORT_SYMBOL(lprocfs_quota_wr_bunit);
++
++int lprocfs_quota_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);
++}
++EXPORT_SYMBOL(lprocfs_quota_rd_btune);
++
++int lprocfs_quota_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;
++}
++EXPORT_SYMBOL(lprocfs_quota_wr_btune);
++
++int lprocfs_quota_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);
++}
++EXPORT_SYMBOL(lprocfs_quota_rd_iunit);
++
++int lprocfs_quota_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;
++}
++EXPORT_SYMBOL(lprocfs_quota_wr_iunit);
++
++int lprocfs_quota_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);
++}
++EXPORT_SYMBOL(lprocfs_quota_rd_itune);
++
++int lprocfs_quota_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;
++}
++EXPORT_SYMBOL(lprocfs_quota_wr_itune);
++
++int lprocfs_quota_rd_switch_seconds(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, "%d\n",
++ obd->u.obt.obt_qctxt.lqc_switch_seconds);
++}
++EXPORT_SYMBOL(lprocfs_quota_rd_switch_seconds);
++
++int lprocfs_quota_wr_switch_seconds(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 <= 10)
++ return -EINVAL;
++
++ obd->u.obt.obt_qctxt.lqc_switch_seconds = val;
++ return count;
++}
++EXPORT_SYMBOL(lprocfs_quota_wr_switch_seconds);
++
++#endif
++
++
+ EXPORT_SYMBOL(lprocfs_register);
+ EXPORT_SYMBOL(lprocfs_srch);
+ EXPORT_SYMBOL(lprocfs_remove);
+Index: lustre/obdfilter/filter_io_26.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/obdfilter/filter_io_26.c,v
+retrieving revision 1.41.12.11
+diff -p -u -r1.41.12.11 filter_io_26.c
+--- lustre/obdfilter/filter_io_26.c 26 Oct 2007 11:00:35 -0000 1.41.12.11
++++ lustre/obdfilter/filter_io_26.c 18 Jan 2008 05:51:49 -0000
+@@ -633,7 +633,8 @@ int filter_commitrw_write(struct obd_exp
+ int i, err, cleanup_phase = 0;
+ struct obd_device *obd = exp->exp_obd;
+ void *wait_handle;
+- int total_size = 0, rc2;
++ int total_size = 0, rc2 = 0;
++ int rec_pending = 0;
+ unsigned int qcids[MAXQUOTAS] = {0, 0};
+ ENTRY;
+
+@@ -647,18 +648,12 @@ int filter_commitrw_write(struct obd_exp
+ /* Unfortunately, if quota master is too busy to handle the
+ * pre-dqacq in time and quota hash on ost is used up, we
+ * have to wait for the completion of in flight dqacq/dqrel,
+- * then try again */
+- if ((rc2 = lquota_chkquota(filter_quota_interface_ref, obd, oa->o_uid,
+- oa->o_gid, niocount)) == QUOTA_RET_ACQUOTA) {
+- OBD_FAIL_TIMEOUT(OBD_FAIL_OST_HOLD_WRITE_RPC, 90);
+- lquota_acquire(filter_quota_interface_ref, obd, oa->o_uid,
+- oa->o_gid);
+- }
++ * in order not to get enough quota for write b=12588 */
++ rc2 = lquota_chkquota(filter_quota_interface_ref, obd, oa->o_uid,
++ oa->o_gid, niocount, &rec_pending);
+
+- if (rc2 < 0) {
+- rc = rc2;
+- GOTO(cleanup, rc);
+- }
++ if (rc2 < 0)
++ GOTO(cleanup, rc = rc2);
+
+ iobuf = filter_iobuf_get(&obd->u.filter, oti);
+ if (IS_ERR(iobuf))
+@@ -788,6 +783,10 @@ int filter_commitrw_write(struct obd_exp
+ fsfilt_check_slow(obd, now, "commitrw commit");
+
+ cleanup:
++ if (rec_pending)
++ lquota_pending_commit(filter_quota_interface_ref, obd, oa->o_uid,
++ oa->o_gid, niocount);
++
+ filter_grant_commit(exp, niocount, res);
+
+ switch (cleanup_phase) {
+Index: lustre/obdfilter/lproc_obdfilter.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/obdfilter/lproc_obdfilter.c,v
+retrieving revision 1.23.34.7
+diff -p -u -r1.23.34.7 lproc_obdfilter.c
+--- lustre/obdfilter/lproc_obdfilter.c 3 Jan 2008 06:31:08 -0000 1.23.34.7
++++ lustre/obdfilter/lproc_obdfilter.c 18 Jan 2008 05:51:49 -0000
+@@ -203,13 +203,19 @@ static struct lprocfs_vars lprocfs_filte
+ lprocfs_filter_rd_readcache,
+ lprocfs_filter_wr_readcache, 0 },
+ #ifdef HAVE_QUOTA_SUPPORT
+- { "quota_bunit_sz", lprocfs_rd_bunit, lprocfs_wr_bunit, 0},
+- { "quota_btune_sz", lprocfs_rd_btune, lprocfs_wr_btune, 0},
+- { "quota_iunit_sz", lprocfs_rd_iunit, lprocfs_wr_iunit, 0},
+- { "quota_itune_sz", lprocfs_rd_itune, lprocfs_wr_itune, 0},
+- { "quota_type", lprocfs_rd_type, lprocfs_wr_type, 0},
+- { "quota_limit_sz", lprocfs_filter_rd_limit,
+- lprocfs_filter_wr_limit, 0},
++ { "quota_bunit_sz", lprocfs_quota_rd_bunit,
++ lprocfs_quota_wr_bunit, 0},
++ { "quota_btune_sz", lprocfs_quota_rd_btune,
++ lprocfs_quota_wr_btune, 0},
++ { "quota_iunit_sz", lprocfs_quota_rd_iunit,
++ lprocfs_quota_wr_iunit, 0},
++ { "quota_itune_sz", lprocfs_quota_rd_itune,
++ lprocfs_quota_wr_itune, 0},
++ { "quota_type", lprocfs_quota_rd_type,
++ lprocfs_quota_wr_type, 0},
++ { "quota_switch_seconds", lprocfs_quota_rd_switch_seconds,
++ lprocfs_quota_wr_switch_seconds, 0 },
++
+ #endif
+ { "client_cache_count", lprocfs_filter_rd_fmd_max_num,
+ lprocfs_filter_wr_fmd_max_num, 0 },
+Index: lustre/osc/osc_request.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/osc/osc_request.c,v
+retrieving revision 1.284.6.37
+diff -p -u -r1.284.6.37 osc_request.c
+--- lustre/osc/osc_request.c 3 Jan 2008 06:31:11 -0000 1.284.6.37
++++ lustre/osc/osc_request.c 18 Jan 2008 05:51:50 -0000
+@@ -673,7 +673,8 @@ static void osc_consume_write_grant(stru
+ pga->flag |= OBD_BRW_FROM_GRANT;
+ CDEBUG(D_CACHE, "using %lu grant credits for brw %p page %p\n",
+ CFS_PAGE_SIZE, pga, pga->pg);
+- LASSERT(cli->cl_avail_grant >= 0);
++ LASSERTF(cli->cl_avail_grant >= 0, "invalid avail grant is %ld \n",
++ cli->cl_avail_grant);
+ }
+
+ /* the companion to osc_consume_write_grant, called when a brw has completed.
+Index: lustre/ost/ost_handler.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/ost/ost_handler.c,v
+retrieving revision 1.184.6.28
+diff -p -u -r1.184.6.28 ost_handler.c
+--- lustre/ost/ost_handler.c 3 Jan 2008 06:31:14 -0000 1.184.6.28
++++ lustre/ost/ost_handler.c 18 Jan 2008 05:51:50 -0000
+@@ -1344,6 +1344,28 @@ static int ost_handle_quotacheck(struct
+ RETURN(0);
+ }
+
++static int ost_handle_quota_adjust_qunit(struct ptlrpc_request *req)
++{
++ struct quota_adjust_qunit *oqaq, *repoqa;
++ int size[2] = { sizeof(struct ptlrpc_body), sizeof(*repoqa) };
++ int rc;
++ ENTRY;
++
++ oqaq = lustre_swab_reqbuf(req, REQ_REC_OFF, sizeof(*oqaq),
++ lustre_swab_quota_adjust_qunit);
++
++ if (oqaq == NULL)
++ GOTO(out, rc = -EPROTO);
++ rc = lustre_pack_reply(req, 2, size, NULL);
++ if (rc)
++ GOTO(out, rc);
++ repoqa = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF, sizeof(*repoqa));
++ req->rq_status = obd_quota_adjust_qunit(req->rq_export, oqaq);
++ *repoqa = *oqaq;
++ out:
++ RETURN(rc);
++}
++
+ static int ost_filter_recovery_request(struct ptlrpc_request *req,
+ struct obd_device *obd, int *process)
+ {
+@@ -1402,6 +1424,7 @@ int ost_msg_check_version(struct lustre_
+ case OST_GET_INFO:
+ case OST_QUOTACHECK:
+ case OST_QUOTACTL:
++ case OST_QUOTA_ADJUST_QUNIT:
+ rc = lustre_msg_check_version(msg, LUSTRE_OST_VERSION);
+ if (rc)
+ CERROR("bad opc %u version %08x, expecting %08x\n",
+@@ -1594,6 +1617,10 @@ static int ost_handle(struct ptlrpc_requ
+ OBD_FAIL_RETURN(OBD_FAIL_OST_QUOTACTL_NET, 0);
+ rc = ost_handle_quotactl(req);
+ break;
++ case OST_QUOTA_ADJUST_QUNIT:
++ CDEBUG(D_INODE, "quota_adjust_qunit\n");
++ rc = ost_handle_quota_adjust_qunit(req);
++ break;
+ case OBD_PING:
+ DEBUG_REQ(D_INODE, req, "ping");
+ rc = target_handle_ping(req);
+Index: lustre/ptlrpc/lproc_ptlrpc.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/ptlrpc/lproc_ptlrpc.c,v
+retrieving revision 1.18.34.11
+diff -p -u -r1.18.34.11 lproc_ptlrpc.c
+--- lustre/ptlrpc/lproc_ptlrpc.c 28 Oct 2007 02:14:14 -0000 1.18.34.11
++++ lustre/ptlrpc/lproc_ptlrpc.c 18 Jan 2008 05:51:50 -0000
+@@ -61,6 +61,7 @@ struct ll_rpc_opcode {
+ { OST_SET_INFO, "ost_set_info" },
+ { OST_QUOTACHECK, "ost_quotacheck" },
+ { OST_QUOTACTL, "ost_quotactl" },
++ { OST_QUOTA_ADJUST_QUNIT, "ost_quota_adjust_qunit" },
+ { MDS_GETATTR, "mds_getattr" },
+ { MDS_GETATTR_NAME, "mds_getattr_lock" },
+ { MDS_CLOSE, "mds_close" },
+Index: lustre/ptlrpc/pack_generic.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/ptlrpc/pack_generic.c,v
+retrieving revision 1.71.30.12
+diff -p -u -r1.71.30.12 pack_generic.c
+--- lustre/ptlrpc/pack_generic.c 11 Jan 2008 10:29:09 -0000 1.71.30.12
++++ lustre/ptlrpc/pack_generic.c 18 Jan 2008 05:51:51 -0000
+@@ -2091,6 +2091,14 @@ void lustre_swab_obd_quotactl (struct ob
+ lustre_swab_obd_dqblk (&q->qc_dqblk);
+ }
+
++void lustre_swab_quota_adjust_qunit (struct quota_adjust_qunit *q)
++{
++ __swab32s (&q->qaq_flags);
++ __swab32s (&q->qaq_id);
++ __swab64s (&q->qaq_bunit_sz);
++ __swab64s (&q->qaq_iunit_sz);
++}
++
+ void lustre_swab_mds_rec_setattr (struct mds_rec_setattr *sa)
+ {
+ __swab32s (&sa->sa_opcode);
+@@ -2360,8 +2368,10 @@ void lustre_swab_qdata(struct qunit_data
+ __swab32s (&d->qd_id);
+ __swab32s (&d->qd_flags);
+ __swab64s (&d->qd_count);
++ __swab64s (&d->qd_qunit);
+ }
+
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
+ void lustre_swab_qdata_old(struct qunit_data_old *d)
+ {
+ __swab32s (&d->qd_id);
+@@ -2369,45 +2379,283 @@ void lustre_swab_qdata_old(struct qunit_
+ __swab32s (&d->qd_count);
+ __swab32s (&d->qd_isblk);
+ }
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 9, 0, 0)
++void lustre_swab_qdata_old2(struct qunit_data_old2 *d)
++{
++ __swab32s (&d->qd_id);
++ __swab32s (&d->qd_flags);
++ __swab64s (&d->qd_count);
++}
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
+
+ #ifdef __KERNEL__
+-struct qunit_data *lustre_quota_old_to_new(struct qunit_data_old *d)
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
++void qdata_v1_v3(struct qunit_data_old *d,
++ struct qunit_data *qdata)
++{
++ LASSERT(d);
++ LASSERT(qdata);
++
++ qdata->qd_id = d->qd_id;
++ if (d->qd_type)
++ QDATA_SET_GRP(qdata);
++ if (d->qd_isblk)
++ QDATA_SET_BLK(qdata);
++ qdata->qd_count = d->qd_count;
++}
++
++struct qunit_data_old *qdata_v3_to_v1(struct qunit_data *d)
+ {
+- struct qunit_data_old tmp;
+- struct qunit_data *ret;
++ struct qunit_data tmp;
++ struct qunit_data_old *ret;
+ ENTRY;
+
+ if (!d)
+ return NULL;
+
+ tmp = *d;
+- ret = (struct qunit_data *)d;
++ ret = (struct qunit_data_old *)d;
+ ret->qd_id = tmp.qd_id;
+- ret->qd_flags = (tmp.qd_type ? QUOTA_IS_GRP : 0) | (tmp.qd_isblk ? QUOTA_IS_BLOCK : 0);
+- ret->qd_count = tmp.qd_count;
++ ret->qd_type = (QDATA_IS_GRP(&tmp) ? GRPQUOTA : USRQUOTA);
++ ret->qd_count = (__u32)tmp.qd_count;
++ ret->qd_isblk = (QDATA_IS_BLK(&tmp) ? 1 : 0);
+ RETURN(ret);
++}
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
+
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 9, 0, 0)
++void qdata_v2_to_v3(struct qunit_data_old2 *d,
++ struct qunit_data *qdata)
++{
++ LASSERT(d);
++ LASSERT(qdata);
++
++ qdata->qd_id = d->qd_id;
++ qdata->qd_flags = d->qd_flags;
++ qdata->qd_count = d->qd_count;
+ }
+-EXPORT_SYMBOL(lustre_quota_old_to_new);
+
+-struct qunit_data_old *lustre_quota_new_to_old(struct qunit_data *d)
++struct qunit_data_old2 *qdata_v3_to_v2(struct qunit_data *d)
+ {
+ struct qunit_data tmp;
+- struct qunit_data_old *ret;
++ struct qunit_data_old2 *ret;
+ ENTRY;
+
+ if (!d)
+ return NULL;
+
+ tmp = *d;
+- ret = (struct qunit_data_old *)d;
++ ret = (struct qunit_data_old2 *)d;
+ ret->qd_id = tmp.qd_id;
+- ret->qd_type = ((tmp.qd_flags & QUOTA_IS_GRP) ? GRPQUOTA : USRQUOTA);
+- ret->qd_count = (__u32)tmp.qd_count;
+- ret->qd_isblk = ((tmp.qd_flags & QUOTA_IS_BLOCK) ? 1 : 0);
++ ret->qd_flags = tmp.qd_flags & LQUOTA_QUNIT_FLAGS;
++ ret->qd_count = tmp.qd_count;
+ RETURN(ret);
+ }
+-EXPORT_SYMBOL(lustre_quota_new_to_old);
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++
++/* got qdata from request(req/rep) */
++int quota_get_qdata(void *request, struct qunit_data *qdata,
++ int is_req, int is_exp)
++{
++ struct ptlrpc_request *req = (struct ptlrpc_request *)request;
++ struct qunit_data *new;
++ struct qunit_data_old *old;
++ struct qunit_data_old2 *old2;
++ int size = sizeof(struct qunit_data_old);
++ int size2 = sizeof(struct qunit_data_old2);
++ __u64 flags = is_exp ? req->rq_export->exp_connect_flags :
++ req->rq_import->imp_connect_data.ocd_connect_flags;
++
++ LASSERT(req);
++ LASSERT(qdata);
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
++ if (OBD_FAIL_CHECK(OBD_FAIL_QUOTA_QD_COUNT_32BIT))
++ goto quota32;
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 9, 0, 0)
++ if (OBD_FAIL_CHECK(OBD_FAIL_QUOTA_WITHOUT_CHANGE_QS))
++ goto without_change_qs;
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++
++ /* support for quota64 and change_qs */
++ if (flags & OBD_CONNECT_CHANGE_QS) {
++ if (!(flags & OBD_CONNECT_QUOTA64)) {
++ CDEBUG(D_ERROR, "Wire protocol for qunit is broken!\n");
++ return -EINVAL;
++ }
++ if (is_req == QUOTA_REQUEST)
++ new = lustre_swab_reqbuf(req, REQ_REC_OFF,
++ sizeof(struct qunit_data),
++ lustre_swab_qdata);
++ else
++ new = lustre_swab_repbuf(req, REPLY_REC_OFF,
++ sizeof(struct qunit_data),
++ lustre_swab_qdata);
++ *qdata = *new;
++ QDATA_SET_CHANGE_QS(qdata);
++ return 0;
++ } else {
++ QDATA_CLR_CHANGE_QS(qdata);
++ }
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 9, 0, 0)
++without_change_qs:
++ /* only support for quota64 */
++ if (flags & OBD_CONNECT_QUOTA64) {
++
++ if (is_req == QUOTA_REQUEST)
++ old2 = lustre_swab_reqbuf(req, REQ_REC_OFF, size2,
++ lustre_swab_qdata_old2);
++ else
++ old2 = lustre_swab_repbuf(req, REPLY_REC_OFF, size2,
++ lustre_swab_qdata_old2);
++ qdata_v2_to_v3(old2, qdata);
++
++ return 0;
++ }
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
++quota32:
++ /* not support for quota64 and change_qs */
++ if (is_req == QUOTA_REQUEST)
++ old = lustre_swab_reqbuf(req, REQ_REC_OFF, size,
++ lustre_swab_qdata_old);
++ else
++ old = lustre_swab_repbuf(req, REPLY_REC_OFF, size,
++ lustre_swab_qdata_old);
++ qdata_v1_v3(old, qdata);
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++
++ return 0;
++}
++EXPORT_SYMBOL(quota_get_qdata);
++
++/* copy qdata to request(req/rep) */
++int quota_copy_qdata(void *request, struct qunit_data *qdata,
++ int is_req, int is_exp)
++{
++ struct ptlrpc_request *req = (struct ptlrpc_request *)request;
++ void *target;
++ struct qunit_data_old *old;
++ struct qunit_data_old2 *old2;
++ __u64 flags = is_exp ? req->rq_export->exp_connect_flags :
++ req->rq_import->imp_connect_data.ocd_connect_flags;
++
++ LASSERT(req);
++ LASSERT(qdata);
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
++ if (OBD_FAIL_CHECK(OBD_FAIL_QUOTA_QD_COUNT_32BIT))
++ goto quota32;
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 9, 0, 0)
++ if (OBD_FAIL_CHECK(OBD_FAIL_QUOTA_WITHOUT_CHANGE_QS))
++ goto without_change_qs;
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++
++ /* support for quota64 and change_qs */
++ if (flags & OBD_CONNECT_CHANGE_QS) {
++ if (!(flags & OBD_CONNECT_QUOTA64)) {
++ CERROR("Wire protocol for qunit is broken!\n");
++ return -EINVAL;
++ }
++ if (is_req == QUOTA_REQUEST)
++ target = lustre_msg_buf(req->rq_reqmsg, REQ_REC_OFF,
++ sizeof(struct qunit_data));
++ else
++ target = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF,
++ sizeof(struct qunit_data));
++ if (!target)
++ return -EINVAL;
++ memcpy(target, qdata, sizeof(*qdata));
++ return 0;
++ }
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 9, 0, 0)
++without_change_qs:
++ /* only support for quota64 */
++ if (flags & OBD_CONNECT_QUOTA64) {
++ if (is_req == QUOTA_REQUEST)
++ target = lustre_msg_buf(req->rq_reqmsg, REQ_REC_OFF,
++ sizeof(struct qunit_data_old2));
++ else
++ target = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF,
++ sizeof(struct qunit_data_old2));
++ if (!target)
++ return -EINVAL;
++ old2 = qdata_v3_to_v2(qdata);
++ memcpy(target, old2, sizeof(*old2));
++ return 0;
++ }
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
++quota32:
++ /* not support for quota64 and change_qs */
++ if (is_req == QUOTA_REQUEST)
++ target = lustre_msg_buf(req->rq_reqmsg, REQ_REC_OFF,
++ sizeof(struct qunit_data_old));
++ else
++ target = lustre_msg_buf(req->rq_repmsg, REPLY_REC_OFF,
++ sizeof(struct qunit_data_old));
++ if (!target)
++ return -EINVAL;
++ old = qdata_v3_to_v1(qdata);
++ memcpy(target, old, sizeof(*old));
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++
++ return 0;
++}
++EXPORT_SYMBOL(quota_copy_qdata);
++
++int quota_get_qunit_data_size(__u64 flag)
++{
++ int size;
++
++ if (flag & OBD_CONNECT_CHANGE_QS) {
++ size = sizeof(struct qunit_data);
++ } else {
++ /* write in this way because sizes of qunit_data_old and
++ * qunit_data_old2 are same */
++ LASSERT(sizeof(struct qunit_data_old) ==
++ sizeof(struct qunit_data_old2));
++ size = sizeof(struct qunit_data_old);
++ }
++
++ return(size);
++}
++EXPORT_SYMBOL(quota_get_qunit_data_size);
+ #endif /* __KERNEL__ */
+
+ static inline int req_ptlrpc_body_swabbed(struct ptlrpc_request *req)
+Index: lustre/ptlrpc/ptlrpc_module.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/ptlrpc/ptlrpc_module.c,v
+retrieving revision 1.38.6.10
+diff -p -u -r1.38.6.10 ptlrpc_module.c
+--- lustre/ptlrpc/ptlrpc_module.c 11 Jan 2008 10:29:10 -0000 1.38.6.10
++++ lustre/ptlrpc/ptlrpc_module.c 18 Jan 2008 05:51:51 -0000
+@@ -228,7 +228,17 @@ EXPORT_SYMBOL(lustre_swab_ldlm_lock_desc
+ EXPORT_SYMBOL(lustre_swab_ldlm_request);
+ EXPORT_SYMBOL(lustre_swab_ldlm_reply);
+ EXPORT_SYMBOL(lustre_swab_qdata);
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
+ EXPORT_SYMBOL(lustre_swab_qdata_old);
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 9, 0, 0)
++EXPORT_SYMBOL(lustre_swab_qdata_old2);
++#else
++#warning "remove quota code above for format absolete in new release"
++#endif
++EXPORT_SYMBOL(lustre_swab_quota_adjust_qunit);
+ EXPORT_SYMBOL(lustre_msg_get_flags);
+ EXPORT_SYMBOL(lustre_msg_add_flags);
+ EXPORT_SYMBOL(lustre_msg_set_flags);
+Index: lustre/ptlrpc/wiretest.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/ptlrpc/wiretest.c,v
+retrieving revision 1.2.34.8
+diff -p -u -r1.2.34.8 wiretest.c
+--- lustre/ptlrpc/wiretest.c 9 Jan 2008 20:01:14 -0000 1.2.34.8
++++ lustre/ptlrpc/wiretest.c 18 Jan 2008 05:51:52 -0000
+@@ -77,7 +77,9 @@ void lustre_assert_wire_constants(void)
+ (long long)OST_QUOTACHECK);
+ LASSERTF(OST_QUOTACTL == 19, " found %lld\n",
+ (long long)OST_QUOTACTL);
+- LASSERTF(OST_LAST_OPC == 20, " found %lld\n",
++ LASSERTF(OST_QUOTA_ADJUST_QUNIT == 20, " found %lld\n",
++ (long long)OST_QUOTA_ADJUST_QUNIT);
++ LASSERTF(OST_LAST_OPC == 21, " found %lld\n",
+ (long long)OST_LAST_OPC);
+ LASSERTF(OBD_OBJECT_EOF == 0xffffffffffffffffULL," found %lld\n",
+ (long long)OBD_OBJECT_EOF);
+@@ -1987,7 +1989,7 @@ void lustre_assert_wire_constants(void)
+ (long long)(int)sizeof(((struct mds_extent_desc *)0)->med_lmm));
+
+ /* Checks for struct qunit_data */
+- LASSERTF((int)sizeof(struct qunit_data) == 16, " found %lld\n",
++ LASSERTF((int)sizeof(struct qunit_data) == 32, " found %lld\n",
+ (long long)(int)sizeof(struct qunit_data));
+ LASSERTF((int)offsetof(struct qunit_data, qd_id) == 0, " found %lld\n",
+ (long long)(int)offsetof(struct qunit_data, qd_id));
+@@ -2001,6 +2003,30 @@ void lustre_assert_wire_constants(void)
+ (long long)(int)offsetof(struct qunit_data, qd_count));
+ LASSERTF((int)sizeof(((struct qunit_data *)0)->qd_count) == 8, " found %lld\n",
+ (long long)(int)sizeof(((struct qunit_data *)0)->qd_count));
++ LASSERTF((int)offsetof(struct qunit_data, qd_qunit) == 16, " found %lld\n",
++ (long long)(int)offsetof(struct qunit_data, qd_qunit));
++ LASSERTF((int)sizeof(((struct qunit_data *)0)->qd_qunit) == 8, " found %lld\n",
++ (long long)(int)sizeof(((struct qunit_data *)0)->qd_qunit));
++ LASSERTF((int)offsetof(struct qunit_data, padding) == 24, " found %lld\n",
++ (long long)(int)offsetof(struct qunit_data, padding));
++ LASSERTF((int)sizeof(((struct qunit_data *)0)->padding) == 8, " found %lld\n",
++ (long long)(int)sizeof(((struct qunit_data *)0)->padding));
++
++ /* Checks for struct qunit_data_old2 */
++ LASSERTF((int)sizeof(struct qunit_data_old2) == 16, " found %lld\n",
++ (long long)(int)sizeof(struct qunit_data_old2));
++ LASSERTF((int)offsetof(struct qunit_data_old2, qd_id) == 0, " found %lld\n",
++ (long long)(int)offsetof(struct qunit_data_old2, qd_id));
++ LASSERTF((int)sizeof(((struct qunit_data_old2 *)0)->qd_id) == 4, " found %lld\n",
++ (long long)(int)sizeof(((struct qunit_data_old2 *)0)->qd_id));
++ LASSERTF((int)offsetof(struct qunit_data_old2, qd_flags) == 4, " found %lld\n",
++ (long long)(int)offsetof(struct qunit_data_old2, qd_flags));
++ LASSERTF((int)sizeof(((struct qunit_data_old2 *)0)->qd_flags) == 4, " found %lld\n",
++ (long long)(int)sizeof(((struct qunit_data_old2 *)0)->qd_flags));
++ LASSERTF((int)offsetof(struct qunit_data_old2, qd_count) == 8, " found %lld\n",
++ (long long)(int)offsetof(struct qunit_data_old2, qd_count));
++ LASSERTF((int)sizeof(((struct qunit_data_old2 *)0)->qd_count) == 8, " found %lld\n",
++ (long long)(int)sizeof(((struct qunit_data_old2 *)0)->qd_count));
+
+ /* Checks for struct qunit_data_old */
+ LASSERTF((int)sizeof(struct qunit_data_old) == 16, " found %lld\n",
+@@ -2022,6 +2048,26 @@ void lustre_assert_wire_constants(void)
+ LASSERTF((int)sizeof(((struct qunit_data_old *)0)->qd_isblk) == 4, " found %lld\n",
+ (long long)(int)sizeof(((struct qunit_data_old *)0)->qd_isblk));
+
++ /* Checks for struct quota_adjust_qunit */
++ LASSERTF((int)sizeof(struct quota_adjust_qunit) == 32, " found %lld\n",
++ (long long)(int)sizeof(struct quota_adjust_qunit));
++ LASSERTF((int)offsetof(struct quota_adjust_qunit, qaq_flags) == 0, " found %lld\n",
++ (long long)(int)offsetof(struct quota_adjust_qunit, qaq_flags));
++ LASSERTF((int)sizeof(((struct quota_adjust_qunit *)0)->qaq_flags) == 4, " found %lld\n",
++ (long long)(int)sizeof(((struct quota_adjust_qunit *)0)->qaq_flags));
++ LASSERTF((int)offsetof(struct quota_adjust_qunit, qaq_id) == 4, " found %lld\n",
++ (long long)(int)offsetof(struct quota_adjust_qunit, qaq_id));
++ LASSERTF((int)sizeof(((struct quota_adjust_qunit *)0)->qaq_id) == 4, " found %lld\n",
++ (long long)(int)sizeof(((struct quota_adjust_qunit *)0)->qaq_id));
++ LASSERTF((int)offsetof(struct quota_adjust_qunit, qaq_bunit_sz) == 8, " found %lld\n",
++ (long long)(int)offsetof(struct quota_adjust_qunit, qaq_bunit_sz));
++ LASSERTF((int)sizeof(((struct quota_adjust_qunit *)0)->qaq_bunit_sz) == 8, " found %lld\n",
++ (long long)(int)sizeof(((struct quota_adjust_qunit *)0)->qaq_bunit_sz));
++ LASSERTF((int)offsetof(struct quota_adjust_qunit, qaq_iunit_sz) == 16, " found %lld\n",
++ (long long)(int)offsetof(struct quota_adjust_qunit, qaq_iunit_sz));
++ LASSERTF((int)sizeof(((struct quota_adjust_qunit *)0)->qaq_iunit_sz) == 8, " found %lld\n",
++ (long long)(int)sizeof(((struct quota_adjust_qunit *)0)->qaq_iunit_sz));
++
+ /* Checks for struct mgs_target_info */
+ LASSERTF((int)sizeof(struct mgs_target_info) == 4544, " found %lld\n",
+ (long long)(int)sizeof(struct mgs_target_info));
+Index: lustre/quota/Makefile.in
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/quota/Makefile.in,v
+retrieving revision 1.2
+diff -p -u -r1.2 Makefile.in
+--- lustre/quota/Makefile.in 10 Feb 2007 06:33:01 -0000 1.2
++++ lustre/quota/Makefile.in 18 Jan 2008 05:51:52 -0000
+@@ -2,7 +2,7 @@ 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
++lquota-objs += quota_master.o quota_adjust_qunit.o
+ quotactl-objs := quotactl_test.o
+ quotaccheck-objs := quotacheck_test.o
+
+Index: lustre/quota/autoMakefile.am
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/quota/autoMakefile.am,v
+retrieving revision 1.2
+diff -p -u -r1.2 autoMakefile.am
+--- lustre/quota/autoMakefile.am 10 Feb 2007 06:33:01 -0000 1.2
++++ lustre/quota/autoMakefile.am 18 Jan 2008 05:51:52 -0000
+@@ -5,7 +5,7 @@
+
+ if LIBLUSTRE
+ noinst_LIBRARIES = libquota.a
+-libquota_a_SOURCES = quota_check.c quota_ctl.c quota_interface.c
++libquota_a_SOURCES = quota_check.c quota_ctl.c quota_interface.c quota_adjust_qunit.c
+ libquota_a_CPPFLAGS = $(LLCPPFLAGS)
+ libquota_a_CFLAGS = $(LLCFLAGS)
+ endif
+Index: lustre/quota/quota_adjust_qunit.c
+===================================================================
+RCS file: lustre/quota/quota_adjust_qunit.c
+diff -N lustre/quota/quota_adjust_qunit.c
+--- /dev/null 1 Jan 1970 00:00:00 -0000
++++ lustre/quota/quota_adjust_qunit.c 18 Jan 2008 05:51:52 -0000
+@@ -0,0 +1,402 @@
++/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
++ * vim:expandtab:shiftwidth=8:tabstop=8:
++ *
++ * lustre/quota/quota_adjust_qunit.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 <obd_class.h>
++#include <lustre_mds.h>
++#include <lustre_dlm.h>
++#include <lustre_cfg.h>
++#include <obd_ost.h>
++#include <lustre_fsfilt.h>
++#include <linux/lustre_quota.h>
++#include <class_hash.h>
++#include "quota_internal.h"
++
++#ifdef __KERNEL__
++/* this function is charge of recording lqs_ino_rec and
++ * lqs_blk_rec. when a lquota slave checks a quota
++ * request(check_cur_qunit) and finishes a quota
++ * request(dqacq_completion), it will be called.
++ * is_chk: whether it is checking quota; otherwise, it is finishing
++ * is_acq: whether it is acquiring; otherwise, it is releasing
++ */
++void quota_compute_lqs(struct qunit_data *qdata, struct lustre_qunit_size *lqs,
++ int is_chk, int is_acq)
++{
++ int is_blk;
++
++ LASSERT(qdata && lqs);
++ LASSERT_SPIN_LOCKED(&lqs->lqs_lock);
++ is_blk = QDATA_IS_BLK(qdata);
++
++ if (is_chk) {
++ if (is_acq) {
++ if (is_blk)
++ lqs->lqs_blk_rec += qdata->qd_count;
++ else
++ lqs->lqs_ino_rec += qdata->qd_count;
++ } else {
++ if (is_blk)
++ lqs->lqs_blk_rec -= qdata->qd_count;
++ else
++ lqs->lqs_ino_rec -= qdata->qd_count;
++ }
++ } else {
++ if (is_acq) {
++ if (is_blk)
++ lqs->lqs_blk_rec -= qdata->qd_count;
++ else
++ lqs->lqs_ino_rec -= qdata->qd_count;
++ } else {
++ if (is_blk)
++ lqs->lqs_blk_rec += qdata->qd_count;
++ else
++ lqs->lqs_ino_rec += qdata->qd_count;
++ }
++ }
++}
++
++void qdata_to_oqaq(struct qunit_data *qdata,
++ struct quota_adjust_qunit *oqaq)
++{
++ LASSERT(qdata);
++ LASSERT(oqaq);
++
++ oqaq->qaq_flags = qdata->qd_flags;
++ oqaq->qaq_id = qdata->qd_id;
++ if (QDATA_IS_ADJBLK(qdata))
++ oqaq->qaq_bunit_sz = qdata->qd_qunit;
++ if (QDATA_IS_ADJINO(qdata))
++ oqaq->qaq_iunit_sz = qdata->qd_qunit;
++}
++
++int quota_search_lqs(struct qunit_data *qdata,
++ struct quota_adjust_qunit *oqaq,
++ struct lustre_quota_ctxt *qctxt,
++ struct lustre_qunit_size **lqs_return)
++{
++ struct quota_adjust_qunit *oqaq_tmp = NULL;
++ ENTRY;
++
++ LASSERT(*lqs_return == NULL);
++ LASSERT(oqaq || qdata);
++
++ if (!oqaq) {
++ OBD_ALLOC_PTR(oqaq_tmp);
++ if (!oqaq_tmp)
++ RETURN(-ENOMEM);
++ qdata_to_oqaq(qdata, oqaq_tmp);
++ } else {
++ oqaq_tmp = oqaq;
++ }
++
++ *lqs_return = lustre_hash_get_object_by_key(LQC_HASH_BODY(qctxt),
++ oqaq_tmp);
++ if (*lqs_return)
++ LQS_DEBUG((*lqs_return), "show lqs\n");
++
++ if (!oqaq)
++ OBD_FREE_PTR(oqaq_tmp);
++ RETURN(0);
++}
++
++int quota_create_lqs(struct qunit_data *qdata,
++ struct quota_adjust_qunit *oqaq,
++ struct lustre_quota_ctxt *qctxt,
++ struct lustre_qunit_size **lqs_return)
++{
++ int rc = 0;
++ struct quota_adjust_qunit *oqaq_tmp = NULL;
++ struct lustre_qunit_size *lqs = NULL;
++ ENTRY;
++
++ LASSERT(*lqs_return == NULL);
++ LASSERT(oqaq || qdata);
++
++ if (!oqaq) {
++ OBD_ALLOC_PTR(oqaq_tmp);
++ if (!oqaq_tmp)
++ RETURN(-ENOMEM);
++ qdata_to_oqaq(qdata, oqaq_tmp);
++ } else {
++ oqaq_tmp = oqaq;
++ }
++
++ OBD_ALLOC_PTR(lqs);
++ if (!lqs)
++ GOTO(out, rc = -ENOMEM);
++
++ spin_lock_init(&lqs->lqs_lock);
++ lqs->lqs_bwrite_pending = 0;
++ lqs->lqs_iwrite_pending = 0;
++ lqs->lqs_ino_rec = 0;
++ lqs->lqs_blk_rec = 0;
++ lqs->lqs_id = oqaq_tmp->qaq_id;
++ lqs->lqs_flags = QAQ_IS_GRP(oqaq_tmp);
++ lqs->lqs_bunit_sz = qctxt->lqc_bunit_sz;
++ lqs->lqs_iunit_sz = qctxt->lqc_iunit_sz;
++ lqs->lqs_btune_sz = qctxt->lqc_btune_sz;
++ lqs->lqs_itune_sz = qctxt->lqc_itune_sz;
++ if (qctxt->lqc_handler) {
++ lqs->lqs_last_bshrink = 0;
++ lqs->lqs_last_ishrink = 0;
++ }
++ lqs_initref(lqs);
++ rc = lustre_hash_additem_unique(LQC_HASH_BODY(qctxt),
++ oqaq_tmp, &lqs->lqs_hash);
++ LQS_DEBUG(lqs, "create lqs\n");
++ if (!rc) {
++ lqs_getref(lqs);
++ *lqs_return = lqs;
++ }
++ out:
++ if (rc && lqs)
++ OBD_FREE_PTR(lqs);
++ if (!oqaq)
++ OBD_FREE_PTR(oqaq_tmp);
++ RETURN(rc);
++}
++
++int quota_adjust_slave_lqs(struct quota_adjust_qunit *oqaq, struct
++ lustre_quota_ctxt *qctxt)
++{
++ struct lustre_qunit_size *lqs = NULL;
++ unsigned long *lbunit, *liunit, *lbtune, *litune;
++ signed long b_tmp = 0, i_tmp = 0;
++ static cfs_time_t time_limit = 0;
++ int rc = 0;
++ ENTRY;
++
++ if (OBD_FAIL_CHECK(OBD_FAIL_QUOTA_WITHOUT_CHANGE_QS))
++ RETURN(0);
++
++ LASSERT(qctxt);
++ search_lqs:
++ rc = quota_search_lqs(NULL, oqaq, qctxt, &lqs);
++
++ /* deleting the lqs, because a user sets lfs quota 0 0 0 0 */
++ if (!oqaq->qaq_bunit_sz && !oqaq->qaq_iunit_sz && QAQ_IS_ADJBLK(oqaq) &&
++ QAQ_IS_ADJINO(oqaq)) {
++ if (lqs) {
++ LQS_DEBUG(lqs, "release lqs\n");
++ /* this is for quota_search_lqs */
++ lqs_putref(lqs);
++ /* this is for deleting this lqs */
++ lqs_putref(lqs);
++ }
++ RETURN(rc);
++ }
++
++ if (!lqs) {
++ rc = quota_create_lqs(NULL, oqaq, qctxt, &lqs);
++ if (rc == -EALREADY)
++ goto search_lqs;
++ if (rc < 0)
++ RETURN(rc);
++ }
++
++ lbunit = &lqs->lqs_bunit_sz;
++ liunit = &lqs->lqs_iunit_sz;
++ lbtune = &lqs->lqs_btune_sz;
++ litune = &lqs->lqs_itune_sz;
++
++ spin_lock(&lqs->lqs_lock);
++ CDEBUG(D_QUOTA, "before: bunit: %lu, iunit: %lu.\n", *lbunit, *liunit);
++ /* adjust the slave's block qunit size */
++ if (QAQ_IS_ADJBLK(oqaq)) {
++ cfs_duration_t sec = cfs_time_seconds(qctxt->lqc_switch_seconds);
++
++ b_tmp = *lbunit - oqaq->qaq_bunit_sz;
++
++ if (qctxt->lqc_handler && b_tmp > 0)
++ lqs->lqs_last_bshrink = cfs_time_current();
++
++ if (qctxt->lqc_handler && b_tmp < 0) {
++ time_limit = cfs_time_add(lqs->lqs_last_bshrink, sec);
++ if (!lqs->lqs_last_bshrink ||
++ cfs_time_after(cfs_time_current(), time_limit)) {
++ *lbunit = oqaq->qaq_bunit_sz;
++ *lbtune = (*lbunit) / 2;
++ } else {
++ b_tmp = 0;
++ }
++ } else {
++ *lbunit = oqaq->qaq_bunit_sz;
++ *lbtune = (*lbunit) / 2;
++ }
++ }
++
++ /* adjust the slave's file qunit size */
++ if (QAQ_IS_ADJINO(oqaq)) {
++ i_tmp = *liunit - oqaq->qaq_iunit_sz;
++
++ if (qctxt->lqc_handler && i_tmp > 0)
++ lqs->lqs_last_ishrink = cfs_time_current();
++
++ if (qctxt->lqc_handler && i_tmp < 0) {
++ time_limit = cfs_time_add(lqs->lqs_last_ishrink,
++ cfs_time_seconds(qctxt->
++ lqc_switch_seconds));
++ if (!lqs->lqs_last_ishrink ||
++ cfs_time_after(cfs_time_current(), time_limit)) {
++ *liunit = oqaq->qaq_iunit_sz;
++ *litune = (*liunit) / 2;
++ } else {
++ i_tmp = 0;
++ }
++ } else {
++ *liunit = oqaq->qaq_iunit_sz;
++ *litune = (*liunit) / 2;
++ }
++ }
++ CDEBUG(D_QUOTA, "after: bunit: %lu, iunit: %lu.\n", *lbunit, *liunit);
++ spin_unlock(&lqs->lqs_lock);
++
++ lqs_putref(lqs);
++
++ if (b_tmp > 0)
++ rc |= LQS_BLK_DECREASE;
++ else if (b_tmp < 0)
++ rc |= LQS_BLK_INCREASE;
++
++ if (i_tmp > 0)
++ rc |= LQS_INO_DECREASE;
++ else if (i_tmp < 0)
++ rc |= LQS_INO_INCREASE;
++
++ RETURN(rc);
++}
++
++int filter_quota_adjust_qunit(struct obd_export *exp, struct
++ quota_adjust_qunit *oqaq)
++{
++ struct obd_device *obd = exp->exp_obd;
++ struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
++ unsigned int uid = 0, gid = 0;
++ int rc = 0;
++ ENTRY;
++
++ LASSERT(oqaq);
++ LASSERT(QAQ_IS_ADJBLK(oqaq));
++ rc = quota_adjust_slave_lqs(oqaq, qctxt);
++ if (rc < 0) {
++ CERROR("adjust mds slave's qunit size failed!(rc:%d)\n", rc);
++ RETURN(rc);
++ }
++ if (QAQ_IS_GRP(oqaq))
++ gid = oqaq->qaq_id;
++ else
++ uid = oqaq->qaq_id;
++
++ if (rc > 0) {
++ rc = qctxt_adjust_qunit(obd, qctxt, uid, gid, 1, 0);
++ if (rc)
++ CERROR("slave adjust block quota failed!(rc:%d)\n", rc);
++ }
++ RETURN(rc);
++}
++#endif /* __KERNEL__ */
++
++int client_quota_adjust_qunit(struct obd_export *exp, struct
++ quota_adjust_qunit *oqaq)
++{
++ struct ptlrpc_request *req;
++ struct quota_adjust_qunit *oqa;
++ int size[2] = { sizeof(struct ptlrpc_body), sizeof(*oqaq) };
++ int rc = 0;
++ ENTRY;
++
++ /* client don't support this kind of operation, abort it */
++ if (!(exp->exp_connect_flags & OBD_CONNECT_CHANGE_QS)||
++ OBD_FAIL_CHECK(OBD_FAIL_QUOTA_WITHOUT_CHANGE_QS)) {
++ CDEBUG(D_QUOTA, "osc: %s don't support change qunit size\n",
++ exp->exp_obd->obd_name);
++ RETURN(rc);
++ }
++ if (strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME))
++ RETURN(-EINVAL);
++
++ req = ptlrpc_prep_req(class_exp2cliimp(exp), LUSTRE_OST_VERSION,
++ OST_QUOTA_ADJUST_QUNIT, 2, size, NULL);
++ if (!req)
++ GOTO(out, rc = -ENOMEM);
++
++ oqa = lustre_msg_buf(req->rq_reqmsg, REQ_REC_OFF, sizeof(*oqaq));
++ *oqa = *oqaq;
++
++ ptlrpc_req_set_repsize(req, 2, size);
++
++ rc = ptlrpc_queue_wait(req);
++ if (rc) {
++ CERROR("%s: %s failed: rc = %d\n", exp->exp_obd->obd_name,
++ __FUNCTION__, rc);
++ GOTO(out, rc);
++ }
++ ptlrpc_req_finished(req);
++out:
++ RETURN (rc);
++}
++
++int lov_quota_adjust_qunit(struct obd_export *exp, struct
++ quota_adjust_qunit *oqaq)
++{
++ struct obd_device *obd = class_exp2obd(exp);
++ struct lov_obd *lov = &obd->u.lov;
++ int i, rc = 0;
++ ENTRY;
++
++ if (!QAQ_IS_ADJBLK(oqaq)) {
++ CERROR("bad qaq_flags %x for lov obd.\n", oqaq->qaq_flags);
++ RETURN(-EFAULT);
++ }
++
++ for (i = 0; i < lov->desc.ld_tgt_count; i++) {
++ int err;
++
++ if (!lov->lov_tgts[i]->ltd_active) {
++ CDEBUG(D_HA, "ost %d is inactive\n", i);
++ continue;
++ }
++
++ err = obd_quota_adjust_qunit(lov->lov_tgts[i]->ltd_exp, oqaq);
++ if (err) {
++ if (lov->lov_tgts[i]->ltd_active && !rc)
++ rc = err;
++ continue;
++ }
++ }
++ RETURN(rc);
++}
+Index: lustre/quota/quota_check.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/quota/quota_check.c,v
+retrieving revision 1.2
+diff -p -u -r1.2 quota_check.c
+--- lustre/quota/quota_check.c 10 Feb 2007 06:33:01 -0000 1.2
++++ lustre/quota/quota_check.c 18 Jan 2008 05:51:52 -0000
+@@ -202,11 +202,11 @@ int client_quota_poll_check(struct obd_e
+ qchk->obd_uuid = cli->cl_target_uuid;
+ /* FIXME change strncmp to strcmp and save the strlen op */
+ if (strncmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME,
+- strlen(LUSTRE_OSC_NAME)))
++ strlen(LUSTRE_OSC_NAME)) == 0)
+ memcpy(qchk->obd_type, LUSTRE_OST_NAME,
+ strlen(LUSTRE_OST_NAME));
+ else if (strncmp(exp->exp_obd->obd_type->typ_name, LUSTRE_MDC_NAME,
+- strlen(LUSTRE_MDC_NAME)))
++ strlen(LUSTRE_MDC_NAME)) == 0)
+ memcpy(qchk->obd_type, LUSTRE_MDS_NAME,
+ strlen(LUSTRE_MDS_NAME));
+
+Index: lustre/quota/quota_context.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/quota/quota_context.c,v
+retrieving revision 1.3.12.9
+diff -p -u -r1.3.12.9 quota_context.c
+--- lustre/quota/quota_context.c 5 Sep 2007 09:50:17 -0000 1.3.12.9
++++ lustre/quota/quota_context.c 18 Jan 2008 05:51:52 -0000
+@@ -29,13 +29,15 @@
+ #include <obd_class.h>
+ #include <lustre_quota.h>
+ #include <lustre_fsfilt.h>
++#include <class_hash.h>
+ #include "quota_internal.h"
+
+-unsigned long default_bunit_sz = 100 * 1024 * 1024; /* 100M bytes */
++extern struct lustre_hash_operations lqs_hash_operations;
++
++unsigned long default_bunit_sz = 128 * 1024 * 1024; /* 128M bytes */
+ unsigned long default_btune_ratio = 50; /* 50 percentage */
+-unsigned long default_iunit_sz = 5000; /* 5000 inodes */
++unsigned long default_iunit_sz = 5120; /* 5120 inodes */
+ unsigned long default_itune_ratio = 50; /* 50 percentage */
+-unsigned long default_limit_sz = 20 * 1024 * 1024;
+
+ cfs_mem_cache_t *qunit_cachep = NULL;
+ struct list_head qunit_hash[NR_DQHASH];
+@@ -55,8 +57,12 @@ int should_translate_quota (struct obd_i
+ ENTRY;
+
+ LASSERT(imp);
+- if ((imp->imp_connect_data.ocd_connect_flags & OBD_CONNECT_QUOTA64) &&
++#if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(1, 7, 0, 0)
++ if (imp->imp_connect_data.ocd_connect_flags & OBD_CONNECT_QUOTA64 &&
+ !OBD_FAIL_CHECK(OBD_FAIL_QUOTA_QD_COUNT_32BIT))
++#else
++ if (imp->imp_connect_data.ocd_connect_flags & OBD_CONNECT_QUOTA64)
++#endif
+ RETURN(0);
+ else
+ RETURN(1);
+@@ -108,7 +114,7 @@ static inline int
+ qunit_hashfn(struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata)
+ {
+ unsigned int id = qdata->qd_id;
+- unsigned int type = qdata->qd_flags & QUOTA_IS_GRP;
++ unsigned int type = QDATA_IS_GRP(qdata);
+
+ unsigned long tmp = ((unsigned long)qctxt >> L1_CACHE_SHIFT) ^ id;
+ tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH;
+@@ -127,7 +133,9 @@ static inline struct lustre_qunit *find_
+ 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_flags == tmp->qd_flags)
++ qdata->qd_id == tmp->qd_id &&
++ (qdata->qd_flags & LQUOTA_QUNIT_FLAGS) ==
++ (tmp->qd_flags & LQUOTA_QUNIT_FLAGS))
+ return qunit;
+ }
+ return NULL;
+@@ -148,11 +156,11 @@ check_cur_qunit(struct obd_device *obd,
+ {
+ struct super_block *sb = qctxt->lqc_sb;
+ unsigned long qunit_sz, tune_sz;
+- __u64 usage, limit;
++ __u64 usage, limit, limit_org, pending_write = 0;
++ long long record = 0;
+ struct obd_quotactl *qctl;
++ struct lustre_qunit_size *lqs = NULL;
+ int ret = 0;
+- __u32 qdata_type = qdata->qd_flags & QUOTA_IS_GRP;
+- __u32 is_blk = (qdata->qd_flags & QUOTA_IS_BLOCK) >> 1;
+ ENTRY;
+
+ if (!sb_any_quota_enabled(sb))
+@@ -165,7 +173,7 @@ check_cur_qunit(struct obd_device *obd,
+ /* get fs quota usage & limit */
+ qctl->qc_cmd = Q_GETQUOTA;
+ qctl->qc_id = qdata->qd_id;
+- qctl->qc_type = qdata_type;
++ qctl->qc_type = QDATA_IS_GRP(qdata);
+ ret = fsfilt_quotactl(obd, sb, qctl);
+ if (ret) {
+ if (ret == -ESRCH) /* no limit */
+@@ -175,84 +183,133 @@ check_cur_qunit(struct obd_device *obd,
+ GOTO(out, ret);
+ }
+
+- if (is_blk) {
++ if (QDATA_IS_BLK(qdata)) {
+ 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 */
++ /* ignore the no quota limit case; and it can avoid creating
++ * unnecessary lqs for uid/gid */
+ if (!limit)
+ GOTO(out, ret = 0);
+
++ search_lqs:
++ quota_search_lqs(qdata, NULL, qctxt, &lqs);
++ if (!lqs) {
++ CDEBUG(D_QUOTA, "Can't find the lustre qunit size!\n");
++ ret = quota_create_lqs(qdata, NULL, qctxt, &lqs);
++ if (ret == -EALREADY)
++ goto search_lqs;
++ if (ret < 0)
++ GOTO (out, ret);
++ }
++ spin_lock(&lqs->lqs_lock);
++
++ if (QDATA_IS_BLK(qdata)) {
++ qunit_sz = lqs->lqs_bunit_sz;
++ tune_sz = lqs->lqs_btune_sz;
++ pending_write = lqs->lqs_bwrite_pending * CFS_PAGE_SIZE;
++ record = lqs->lqs_blk_rec;
++ LASSERT(!(qunit_sz % QUOTABLOCK_SIZE));
++ } else {
++ /* we didn't need change inode qunit size now */
++ qunit_sz = lqs->lqs_iunit_sz;
++ tune_sz = lqs->lqs_itune_sz;
++ pending_write = lqs->lqs_iwrite_pending;
++ record = lqs->lqs_ino_rec;
++ }
++
+ /* we don't count the MIN_QLIMIT */
+- if ((limit == MIN_QLIMIT && !is_blk) ||
+- (toqb(limit) == MIN_QLIMIT && is_blk))
++ if ((limit == MIN_QLIMIT && !QDATA_IS_BLK(qdata)) ||
++ (toqb(limit) == MIN_QLIMIT && QDATA_IS_BLK(qdata)))
+ limit = 0;
+
++ usage += pending_write;
++ limit_org = limit;
++ /* when a releasing quota req is sent, before it returned
++ limit is assigned a small value. limit will overflow */
++ if (limit + record < 0)
++ usage -= record;
++ else
++ limit += record;
++
+ LASSERT(qdata->qd_count == 0);
+ if (limit <= usage + tune_sz) {
+- while (qdata->qd_count + 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)
++ } else if (limit > usage + qunit_sz + tune_sz &&
++ limit_org > qdata->qd_count + qunit_sz) {
++ while (limit - qdata->qd_count > usage + qunit_sz + tune_sz &&
++ limit_org > qdata->qd_count + qunit_sz)
+ qdata->qd_count += qunit_sz;
+ ret = 2;
+ }
++ CDEBUG(D_QUOTA, "type: %c, limit: "LPU64", usage: "LPU64
++ ", pending_write: "LPU64", record: "LPD64
++ ", qunit_sz: %lu, tune_sz: %lu, ret: %d.\n",
++ QDATA_IS_BLK(qdata) ? 'b' : 'i', limit, usage, pending_write,
++ record, qunit_sz, tune_sz, ret);
+ LASSERT(ret == 0 || qdata->qd_count);
++
++ if (ret > 0) {
++ quota_compute_lqs(qdata, lqs, 1, (ret == 1) ? 1 : 0);
++ /* when this qdata returned from mds, it will call lqs_putref */
++ lqs_getref(lqs);
++ }
++
++ spin_unlock(&lqs->lqs_lock);
++ lqs_putref(lqs);
+ EXIT;
+-out:
++ out:
+ OBD_FREE_PTR(qctl);
+ return ret;
+ }
+
+ /* compute the remaining quota for certain gid or uid b=11693 */
+ int compute_remquota(struct obd_device *obd,
+- struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata)
++ struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata,
++ int isblk)
+ {
+ struct super_block *sb = qctxt->lqc_sb;
+ __u64 usage, limit;
+ struct obd_quotactl *qctl;
+ int ret = QUOTA_RET_OK;
+- __u32 qdata_type = qdata->qd_flags & QUOTA_IS_GRP;
+ ENTRY;
+
+ if (!sb_any_quota_enabled(sb))
+ RETURN(QUOTA_RET_NOQUOTA);
+
+ /* ignore root user */
+- if (qdata->qd_id == 0 && qdata_type == USRQUOTA)
++ if (qdata->qd_id == 0 && QDATA_IS_GRP(qdata) == USRQUOTA)
+ RETURN(QUOTA_RET_NOLIMIT);
+
+ OBD_ALLOC_PTR(qctl);
+- if (qctl == NULL)
++ 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_type;
++ qctl->qc_type = QDATA_IS_GRP(qdata);
+ ret = fsfilt_quotactl(obd, sb, qctl);
+ if (ret) {
+ if (ret == -ESRCH) /* no limit */
+ ret = QUOTA_RET_NOLIMIT;
+ else
+- CDEBUG(D_QUOTA, "can't get fs quota usage! (rc:%d)",
++ CDEBUG(D_QUOTA, "can't get fs quota usage! (rc:%d)",
+ ret);
+ GOTO(out, ret);
+ }
+
+- usage = qctl->qc_dqblk.dqb_curspace;
+- limit = qctl->qc_dqblk.dqb_bhardlimit << QUOTABLOCK_BITS;
++ usage = isblk ? qctl->qc_dqblk.dqb_curspace :
++ qctl->qc_dqblk.dqb_curinodes;
++ limit = isblk ? qctl->qc_dqblk.dqb_bhardlimit << QUOTABLOCK_BITS :
++ qctl->qc_dqblk.dqb_ihardlimit;
+ if (!limit){ /* no limit */
+ ret = QUOTA_RET_NOLIMIT;
+ GOTO(out, ret);
+@@ -328,9 +385,31 @@ insert_qunit_nolock(struct lustre_quota_
+ list_add(&qunit->lq_hash, head);
+ }
+
++static void compute_lqs_after_removing_qunit(struct lustre_qunit *qunit)
++{
++ struct lustre_qunit_size *lqs = NULL;
++
++ quota_search_lqs(&qunit->lq_data, NULL, qunit->lq_ctxt, &lqs);
++ if (lqs) {
++ spin_lock(&lqs->lqs_lock);
++ if (qunit->lq_opc == QUOTA_DQACQ)
++ quota_compute_lqs(&qunit->lq_data, lqs, 0, 1);
++ if (qunit->lq_opc == QUOTA_DQREL)
++ quota_compute_lqs(&qunit->lq_data, lqs, 0, 0);
++ spin_unlock(&lqs->lqs_lock);
++ /* this is for quota_search_lqs */
++ lqs_putref(lqs);
++ /* this is for check_cur_qunit */
++ lqs_putref(lqs);
++ }
++
++}
++
+ static void remove_qunit_nolock(struct lustre_qunit *qunit)
+ {
+ LASSERT(!list_empty(&qunit->lq_hash));
++ LASSERT_SPIN_LOCKED(&qunit_hash_lock);
++
+ list_del_init(&qunit->lq_hash);
+ }
+
+@@ -345,18 +424,19 @@ struct qunit_waiter {
+
+
+ /* FIXME check if this mds is the master of specified id */
+-static int
+-is_master(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
++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
++static int
+ schedule_dqacq(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
+ struct qunit_data *qdata, int opc, int wait);
+
+-static int split_before_schedule_dqacq(struct obd_device *obd, struct lustre_quota_ctxt *qctxt,
++static int split_before_schedule_dqacq(struct obd_device *obd,
++ struct lustre_quota_ctxt *qctxt,
+ struct qunit_data *qdata, int opc, int wait)
+ {
+ int rc = 0;
+@@ -366,17 +446,17 @@ static int split_before_schedule_dqacq(s
+
+ LASSERT(qdata && qdata->qd_count);
+ QDATA_DEBUG(qdata, "%s quota split.\n",
+- (qdata->qd_flags & QUOTA_IS_BLOCK) ? "block" : "inode");
+- if (qdata->qd_flags & QUOTA_IS_BLOCK)
+- factor = MAX_QUOTA_COUNT32 / qctxt->lqc_bunit_sz *
++ QDATA_IS_BLK(qdata) ? "block" : "inode");
++ if (QDATA_IS_BLK(qdata))
++ factor = MAX_QUOTA_COUNT32 / qctxt->lqc_bunit_sz *
+ qctxt->lqc_bunit_sz;
+ else
+- factor = MAX_QUOTA_COUNT32 / qctxt->lqc_iunit_sz *
++ factor = MAX_QUOTA_COUNT32 / qctxt->lqc_iunit_sz *
+ qctxt->lqc_iunit_sz;
+
+ if (qctxt->lqc_import && should_translate_quota(qctxt->lqc_import) &&
+ qdata->qd_count > factor) {
+- tmp_qdata = *qdata;
++ tmp_qdata = *qdata;
+ tmp_qdata.qd_count = factor;
+ qdata->qd_count -= tmp_qdata.qd_count;
+ QDATA_DEBUG((&tmp_qdata), "be split.\n");
+@@ -396,24 +476,19 @@ dqacq_completion(struct obd_device *obd,
+ {
+ struct lustre_qunit *qunit = NULL;
+ struct super_block *sb = qctxt->lqc_sb;
+- unsigned long qunit_sz;
+ struct qunit_waiter *qw, *tmp;
+ int err = 0;
+- __u32 qdata_type = qdata->qd_flags & QUOTA_IS_GRP;
+- __u32 is_blk = (qdata->qd_flags & QUOTA_IS_BLOCK) >> 1;
+- __u64 qd_tmp = qdata->qd_count;
+- unsigned long div_r;
++ struct quota_adjust_qunit *oqaq = NULL;
++ int rc1 = 0;
+ ENTRY;
+
+ LASSERT(qdata);
+- qunit_sz = is_blk ? qctxt->lqc_bunit_sz : qctxt->lqc_iunit_sz;
+- div_r = do_div(qd_tmp, qunit_sz);
+- LASSERTF(!div_r, "qunit_sz: %lu, return qunit_sz: "LPU64"\n",
+- qunit_sz, qd_tmp);
++ QDATA_DEBUG(qdata, "obd(%s): complete %s quota req\n",
++ obd->obd_name, (opc == QUOTA_DQACQ) ? "acq" : "rel");
+
+ /* update local operational quota file */
+ if (rc == 0) {
+- __u32 count = QUSG(qdata->qd_count, is_blk);
++ __u32 count = QUSG(qdata->qd_count, QDATA_IS_BLK(qdata));
+ struct obd_quotactl *qctl;
+ __u64 *hardlimit;
+
+@@ -426,14 +501,14 @@ dqacq_completion(struct obd_device *obd,
+ * set fs quota limit */
+ qctl->qc_cmd = Q_GETQUOTA;
+ qctl->qc_id = qdata->qd_id;
+- qctl->qc_type = qdata_type;
++ qctl->qc_type = QDATA_IS_GRP(qdata);
+ err = fsfilt_quotactl(obd, sb, qctl);
+ if (err) {
+ CERROR("error get quota fs limit! (rc:%d)\n", err);
+ GOTO(out_mem, err);
+ }
+
+- if (is_blk) {
++ if (QDATA_IS_BLK(qdata)) {
+ qctl->qc_dqblk.dqb_valid = QIF_BLIMITS;
+ hardlimit = &qctl->qc_dqblk.dqb_bhardlimit;
+ } else {
+@@ -441,19 +516,14 @@ dqacq_completion(struct obd_device *obd,
+ hardlimit = &qctl->qc_dqblk.dqb_ihardlimit;
+ }
+
++ CDEBUG(D_QUOTA, "hardlimt: "LPU64"\n", *hardlimit);
+ switch (opc) {
+ case QUOTA_DQACQ:
+- CDEBUG(D_QUOTA, "%s(acq):count: %d, hardlimt: "LPU64
+- ",type: %s.\n", obd->obd_name, count, *hardlimit,
+- qdata_type ? "grp": "usr");
+ INC_QLIMIT(*hardlimit, count);
+ break;
+ case QUOTA_DQREL:
+- CDEBUG(D_QUOTA, "%s(rel):count: %d, hardlimt: "LPU64
+- ",type: %s.\n", obd->obd_name, count, *hardlimit,
+- qdata_type ? "grp": "usr");
+- LASSERTF(count < *hardlimit,
+- "count: %d, hardlimit: "LPU64".\n",
++ LASSERTF(count < *hardlimit,
++ "count: %d, hardlimit: "LPU64".\n",
+ count, *hardlimit);
+ *hardlimit -= count;
+ break;
+@@ -494,6 +564,9 @@ out:
+
+ LASSERT(opc == qunit->lq_opc);
+ remove_qunit_nolock(qunit);
++ spin_unlock(&qunit_hash_lock);
++
++ compute_lqs_after_removing_qunit(qunit);
+
+ /* wake up all waiters */
+ list_for_each_entry_safe(qw, tmp, &qunit->lq_waiters, qw_entry) {
+@@ -502,27 +575,38 @@ out:
+ 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.
++ * - acq/rel failure and qunit isn't changed,
++ * 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_type))
++ OBD_ALLOC_PTR(oqaq);
++ if (!oqaq)
++ RETURN(-ENOMEM);
++ qdata_to_oqaq(qdata, oqaq);
++ /* adjust the qunit size in slaves */
++ rc1 = quota_adjust_slave_lqs(oqaq, qctxt);
++ OBD_FREE_PTR(oqaq);
++ if (rc1 < 0) {
++ CERROR("adjust slave's qunit size failed!(rc:%d)\n", rc1);
++ RETURN(rc1);
++ }
++ if (err || (rc && rc != -EBUSY && rc1 == 0) ||
++ is_master(obd, qctxt, qdata->qd_id, QDATA_IS_GRP(qdata)))
+ RETURN(err);
+
+ /* reschedule another dqacq/dqrel if needed */
+ qdata->qd_count = 0;
+- rc = check_cur_qunit(obd, qctxt, qdata);
+- if (rc > 0) {
++ qdata->qd_flags &= LQUOTA_QUNIT_FLAGS;
++ rc1 = check_cur_qunit(obd, qctxt, qdata);
++ if (rc1 > 0) {
+ int opc;
+- opc = rc == 1 ? QUOTA_DQACQ : QUOTA_DQREL;
+- rc = split_before_schedule_dqacq(obd, qctxt, qdata, opc, 0);
+- QDATA_DEBUG(qdata, "reschedudle opc(%d) rc(%d)\n", opc, rc);
++ opc = rc1 == 1 ? QUOTA_DQACQ : QUOTA_DQREL;
++ rc1 = split_before_schedule_dqacq(obd, qctxt, qdata, opc, 0);
++ QDATA_DEBUG(qdata, "reschedudle opc(%d) rc(%d)\n", opc, rc1);
+ }
+ RETURN(err);
+ }
+@@ -539,38 +623,57 @@ static int dqacq_interpret(struct ptlrpc
+ struct lustre_qunit *qunit = aa->aa_qunit;
+ struct obd_device *obd = req->rq_import->imp_obd;
+ struct qunit_data *qdata = NULL;
+- struct qunit_data_old *qdata_old = NULL;
++ int rc1 = 0;
+ ENTRY;
+
+ LASSERT(req);
+ LASSERT(req->rq_import);
+- if ((req->rq_import->imp_connect_data.ocd_connect_flags & OBD_CONNECT_QUOTA64) &&
+- !OBD_FAIL_CHECK(OBD_FAIL_QUOTA_QD_COUNT_32BIT)) {
+- CDEBUG(D_QUOTA, "qd_count is 64bit!\n");
+- qdata = lustre_swab_reqbuf(req, REPLY_REC_OFF, sizeof(*qdata), lustre_swab_qdata);
+- } else {
+- CDEBUG(D_QUOTA, "qd_count is 32bit!\n");
+- qdata_old = lustre_swab_reqbuf(req, REPLY_REC_OFF, sizeof(struct qunit_data_old),
+- lustre_swab_qdata_old);
+- qdata = lustre_quota_old_to_new(qdata_old);
++
++ /* there are several forms of qunit(historic causes), so we need to
++ * adjust qunit from slaves to the same form here */
++ OBD_ALLOC(qdata, sizeof(struct qunit_data));
++ if (!qdata)
++ RETURN(-ENOMEM);
++ rc1 = quota_get_qdata(req, qdata, QUOTA_REPLY, QUOTA_IMPORT);
++ if (rc1 < 0) {
++ DEBUG_REQ(D_ERROR, req, "error unpacking qunit_data\n");
++ GOTO(exit, rc = -EPROTO);
++ }
++
++ QDATA_DEBUG(qdata, "qdata: interpret rc(%d).\n", rc);
++ QDATA_DEBUG((&qunit->lq_data), "lq_data: \n");
++
++ if (qdata->qd_id != qunit->lq_data.qd_id ||
++ OBD_FAIL_CHECK_ONCE(OBD_FAIL_QUOTA_RET_QDATA)) {
++ CDEBUG(D_ERROR, "the returned qd_id isn't expected!"
++ "(qdata: %u, lq_data: %u)\n", qdata->qd_id,
++ qunit->lq_data.qd_id);
++ qdata->qd_id = qunit->lq_data.qd_id;
++ rc = -EPROTO;
++ }
++ if (QDATA_IS_GRP(qdata) != QDATA_IS_GRP(&qunit->lq_data)) {
++ CDEBUG(D_ERROR, "the returned grp/usr isn't expected!"
++ "(qdata: %u, lq_data: %u)\n", qdata->qd_flags,
++ qunit->lq_data.qd_flags);
++ if (QDATA_IS_GRP(&qunit->lq_data))
++ QDATA_SET_GRP(qdata);
++ else
++ QDATA_CLR_GRP(qdata);
++ rc = -EPROTO;
+ }
+- if (qdata == NULL) {
+- DEBUG_REQ(D_ERROR, req, "error unpacking qunit_data");
+- RETURN(-EPROTO);
++ if (qdata->qd_count > qunit->lq_data.qd_count) {
++ CDEBUG(D_ERROR, "the returned qd_count isn't expected!"
++ "(qdata: "LPU64", lq_data: "LPU64")\n", qdata->qd_count,
++ qunit->lq_data.qd_count);
++ rc = -EPROTO;
+ }
+
+- LASSERT(qdata->qd_id == qunit->lq_data.qd_id &&
+- (qdata->qd_flags & QUOTA_IS_GRP) == (qunit->lq_data.qd_flags & QUOTA_IS_GRP) &&
+- (qdata->qd_count == qunit->lq_data.qd_count ||
+- qdata->qd_count == 0));
+-
+- QDATA_DEBUG(qdata, "%s interpret rc(%d).\n",
+- lustre_msg_get_opc(req->rq_reqmsg) == QUOTA_DQACQ ?
+- "DQACQ" : "DQREL", rc);
+-
+ rc = dqacq_completion(obd, qctxt, qdata, rc,
+ lustre_msg_get_opc(req->rq_reqmsg));
+
++exit:
++ OBD_FREE(qdata, sizeof(struct qunit_data));
++
+ RETURN(rc);
+ }
+
+@@ -593,9 +696,8 @@ schedule_dqacq(struct obd_device *obd,
+ 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[2] = { sizeof(struct ptlrpc_body), sizeof(*reqdata) };
++ int size[2] = { sizeof(struct ptlrpc_body), 0 };
+ struct obd_import *imp = NULL;
+ unsigned long factor;
+ int rc = 0;
+@@ -607,18 +709,34 @@ schedule_dqacq(struct obd_device *obd,
+
+ 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)
++ struct lustre_qunit_size *lqs = NULL;
++
++ if (wait)
+ list_add_tail(&qw.qw_entry, &qunit->lq_waiters);
+ spin_unlock(&qunit_hash_lock);
+-
+ free_qunit(empty);
++
++ quota_search_lqs(qdata, NULL, qctxt, &lqs);
++ if (lqs) {
++ spin_lock(&lqs->lqs_lock);
++ quota_compute_lqs(qdata, lqs, 0,
++ (opc == QUOTA_DQACQ) ? 1 : 0);
++ spin_unlock(&lqs->lqs_lock);
++ /* this is for quota_search_lqs */
++ lqs_putref(lqs);
++ /* this is for check_cur_qunit */
++ lqs_putref(lqs);
++ } else {
++ CDEBUG(D_ERROR, "Can't find the lustre qunit size!\n");
++ }
++
+ goto wait_completion;
+- }
++ }
+ qunit = empty;
+ insert_qunit_nolock(qctxt, qunit);
+ if (wait)
+@@ -627,8 +745,10 @@ schedule_dqacq(struct obd_device *obd,
+
+ LASSERT(qunit);
+
++ QDATA_DEBUG(qdata, "obd(%s): send %s quota req\n",
++ obd->obd_name, (opc == QUOTA_DQACQ) ? "acq" : "rel");
+ /* master is going to dqacq/dqrel from itself */
+- if (is_master(obd, qctxt, qdata->qd_id, qdata->qd_flags & QUOTA_IS_GRP)) {
++ if (is_master(obd, qctxt, qdata->qd_id, QDATA_IS_GRP(qdata))) {
+ int rc2;
+ QDATA_DEBUG(qdata, "local %s.\n",
+ opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
+@@ -645,9 +765,10 @@ schedule_dqacq(struct obd_device *obd,
+ if (wait)
+ list_del_init(&qw.qw_entry);
+ remove_qunit_nolock(qunit);
+- free_qunit(empty);
+ qunit = NULL;
+ spin_unlock(&qunit_hash_lock);
++ compute_lqs_after_removing_qunit(qunit);
++ free_qunit(empty);
+ RETURN(-EAGAIN);
+ } else {
+ imp = class_import_get(qctxt->lqc_import);
+@@ -656,6 +777,9 @@ schedule_dqacq(struct obd_device *obd,
+
+ /* build dqacq/dqrel request */
+ LASSERT(imp);
++ size[1] = quota_get_qunit_data_size(imp->
++ imp_connect_data.ocd_connect_flags);
++
+ req = ptlrpc_prep_req(imp, LUSTRE_MDS_VERSION, opc, 2,
+ size, NULL);
+ if (!req) {
+@@ -664,33 +788,21 @@ schedule_dqacq(struct obd_device *obd,
+ RETURN(-ENOMEM);
+ }
+
+- if (qdata->qd_flags & QUOTA_IS_BLOCK)
+- factor = MAX_QUOTA_COUNT32 / qctxt->lqc_bunit_sz *
++ if (QDATA_IS_BLK(qdata))
++ factor = MAX_QUOTA_COUNT32 / qctxt->lqc_bunit_sz *
+ qctxt->lqc_bunit_sz;
+ else
+- factor = MAX_QUOTA_COUNT32 / qctxt->lqc_iunit_sz *
++ factor = MAX_QUOTA_COUNT32 / qctxt->lqc_iunit_sz *
+ qctxt->lqc_iunit_sz;
+
+ LASSERTF(!should_translate_quota(imp) ||
+ qdata->qd_count <= factor,
+ "qd_count: "LPU64"; should_translate_quota: %d.\n",
+ qdata->qd_count, should_translate_quota(imp));
+- if (should_translate_quota(imp))
+- {
+- struct qunit_data_old *reqdata_old, *tmp;
+-
+- reqdata_old = lustre_msg_buf(req->rq_reqmsg, REPLY_REC_OFF,
+- sizeof(*reqdata_old));
+- tmp = lustre_quota_new_to_old(qdata);
+- *reqdata_old = *tmp;
+- size[1] = sizeof(*reqdata_old);
+- CDEBUG(D_QUOTA, "qd_count is 32bit!\n");
+- } else {
+- reqdata = lustre_msg_buf(req->rq_reqmsg, REPLY_REC_OFF,
+- sizeof(*reqdata));
+- *reqdata = *qdata;
+- size[1] = sizeof(*reqdata);
+- CDEBUG(D_QUOTA, "qd_count is 64bit!\n");
++ rc = quota_copy_qdata(req, qdata, QUOTA_REQUEST, QUOTA_IMPORT);
++ if (rc < 0) {
++ CDEBUG(D_ERROR, "Can't pack qunit_data\n");
++ RETURN(-EPROTO);
+ }
+ ptlrpc_req_set_repsize(req, 2, size);
+ class_import_put(imp);
+@@ -703,7 +815,7 @@ schedule_dqacq(struct obd_device *obd,
+ req->rq_interpret_reply = dqacq_interpret;
+ ptlrpcd_add_req(req);
+
+- QDATA_DEBUG(qdata, "%s scheduled.\n",
++ QDATA_DEBUG(qdata, "%s scheduled.\n",
+ opc == QUOTA_DQACQ ? "DQACQ" : "DQREL");
+ wait_completion:
+ if (wait && qunit) {
+@@ -734,9 +846,9 @@ qctxt_adjust_qunit(struct obd_device *ob
+
+ for (i = 0; i < MAXQUOTAS; i++) {
+ qdata[i].qd_id = id[i];
+- qdata[i].qd_flags = 0;
+- qdata[i].qd_flags |= i;
+- qdata[i].qd_flags |= isblk ? QUOTA_IS_BLOCK : 0;
++ qdata[i].qd_flags = i;
++ if (isblk)
++ QDATA_SET_BLK(&qdata[i]);
+ qdata[i].qd_count = 0;
+
+ ret = check_cur_qunit(obd, qctxt, &qdata[i]);
+@@ -754,7 +866,7 @@ qctxt_adjust_qunit(struct obd_device *ob
+ RETURN(rc);
+ }
+
+-int
++int
+ qctxt_wait_pending_dqacq(struct lustre_quota_ctxt *qctxt, unsigned int id,
+ unsigned short type, int isblk)
+ {
+@@ -769,9 +881,9 @@ qctxt_wait_pending_dqacq(struct lustre_q
+ qw.qw_rc = 0;
+
+ qdata.qd_id = id;
+- qdata.qd_flags = 0;
+- qdata.qd_flags |= type;
+- qdata.qd_flags |= isblk ? QUOTA_IS_BLOCK : 0;
++ qdata.qd_flags = type;
++ if (isblk)
++ QDATA_SET_BLK(&qdata);
+ qdata.qd_count = 0;
+
+ spin_lock(&qunit_hash_lock);
+@@ -798,6 +910,8 @@ qctxt_init(struct lustre_quota_ctxt *qct
+ int rc = 0;
+ ENTRY;
+
++ LASSERT(qctxt);
++
+ rc = ptlrpcd_addref();
+ if (rc)
+ RETURN(rc);
+@@ -808,46 +922,65 @@ qctxt_init(struct lustre_quota_ctxt *qct
+ qctxt->lqc_sb = sb;
+ qctxt->lqc_import = NULL;
+ qctxt->lqc_recovery = 0;
++ qctxt->lqc_switch_qs = 1; /* Change qunit size in default setting */
++ qctxt->lqc_cqs_boundary_factor = 4;
++ qctxt->lqc_cqs_least_bunit = PTLRPC_MAX_BRW_SIZE;
++ qctxt->lqc_cqs_least_iunit = 1;
++ qctxt->lqc_cqs_qs_factor = 2;
+ qctxt->lqc_atype = 0;
+ qctxt->lqc_status= 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;
+- qctxt->lqc_limit_sz = default_limit_sz;
++ qctxt->lqc_switch_seconds = 300; /* enlarging will wait 5 minutes
++ * after the last shrinking */
++ rc = lustre_hash_init(&LQC_HASH_BODY(qctxt), "LQS_HASH",128,
++ &lqs_hash_operations);
++ if (rc) {
++ CDEBUG(D_ERROR, "initialize hash lqs on ost error!\n");
++ lustre_hash_exit(&LQC_HASH_BODY(qctxt));
++ }
+ spin_unlock(&qctxt->lqc_lock);
+
+- RETURN(0);
++ RETURN(rc);
+ }
+
+ void qctxt_cleanup(struct lustre_quota_ctxt *qctxt, int force)
+ {
+ struct lustre_qunit *qunit, *tmp;
+ struct qunit_waiter *qw, *tmp2;
++ struct list_head tmp_list;
+ int i;
+ ENTRY;
+
+- spin_lock(&qunit_hash_lock);
++ INIT_LIST_HEAD(&tmp_list);
+
++ 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);
++ list_add(&qunit->lq_hash, &tmp_list);
+ }
+ }
+-
+ spin_unlock(&qunit_hash_lock);
+
++ list_for_each_entry_safe(qunit, tmp, &tmp_list, lq_hash) {
++ list_del_init(&qunit->lq_hash);
++ compute_lqs_after_removing_qunit(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);
++ }
++
++ lustre_hash_exit(&LQC_HASH_BODY(qctxt));
+ ptlrpcd_decref();
+
+ EXIT;
+@@ -865,7 +998,7 @@ static int qslave_recovery_main(void *ar
+ struct qslave_recov_thread_data *data = arg;
+ struct obd_device *obd = data->obd;
+ struct lustre_quota_ctxt *qctxt = data->qctxt;
+- unsigned int type;
++ unsigned int type;
+ int rc = 0;
+ ENTRY;
+
+@@ -892,7 +1025,7 @@ static int qslave_recovery_main(void *ar
+
+ LASSERT(dqopt->files[type] != NULL);
+ INIT_LIST_HEAD(&id_list);
+-#ifndef KERNEL_SUPPORTS_QUOTA_READ
++#ifndef KERNEL_SUPPORTS_QUOTA_READ
+ rc = fsfilt_qids(obd, dqopt->files[type], NULL, type, &id_list);
+ #else
+ rc = fsfilt_qids(obd, NULL, dqopt->files[type], type, &id_list);
+@@ -910,9 +1043,8 @@ static int qslave_recovery_main(void *ar
+ goto free;
+
+ qdata.qd_id = dqid->di_id;
+- qdata.qd_flags = 0;
+- qdata.qd_flags |= type;
+- qdata.qd_flags |= QUOTA_IS_BLOCK;
++ qdata.qd_flags = type;
++ QDATA_SET_BLK(&qdata);
+ qdata.qd_count = 0;
+
+ ret = check_cur_qunit(obd, qctxt, &qdata);
+@@ -924,7 +1056,7 @@ static int qslave_recovery_main(void *ar
+ rc = 0;
+
+ if (rc)
+- CDEBUG(rc == -EBUSY ? D_QUOTA : D_ERROR,
++ CDEBUG(rc == -EBUSY ? D_QUOTA : D_ERROR,
+ "qslave recovery failed! (id:%d type:%d "
+ " rc:%d)\n", dqid->di_id, type, rc);
+ free:
+@@ -936,7 +1068,7 @@ free:
+ RETURN(rc);
+ }
+
+-void
++void
+ qslave_start_recovery(struct obd_device *obd, struct lustre_quota_ctxt *qctxt)
+ {
+ struct qslave_recov_thread_data data;
+Index: lustre/quota/quota_ctl.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/quota/quota_ctl.c,v
+retrieving revision 1.2.34.3
+diff -p -u -r1.2.34.3 quota_ctl.c
+--- lustre/quota/quota_ctl.c 25 Dec 2007 19:15:21 -0000 1.2.34.3
++++ lustre/quota/quota_ctl.c 18 Jan 2008 05:51:52 -0000
+@@ -132,7 +132,8 @@ int filter_quota_ctl(struct obd_export *
+ }
+ break;
+ case Q_SETQUOTA:
+- qctxt_wait_pending_dqacq(&obd->u.obt.obt_qctxt,
++ /* currently, it is only used for nullifying the quota */
++ qctxt_wait_pending_dqacq(&obd->u.obt.obt_qctxt,
+ oqctl->qc_id, oqctl->qc_type, 1);
+
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+@@ -154,14 +155,14 @@ int filter_quota_ctl(struct obd_export *
+ 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
++ * clear stale limits on slave). we should wait for it's
+ * completion then initialize limits */
+- qctxt_wait_pending_dqacq(&obd->u.obt.obt_qctxt,
++ qctxt_wait_pending_dqacq(&obd->u.obt.obt_qctxt,
+ oqctl->qc_id, oqctl->qc_type, 1);
+
+ if (!oqctl->qc_dqblk.dqb_bhardlimit)
+ goto adjust;
+-
++
+ LASSERT(oqctl->qc_dqblk.dqb_bhardlimit == MIN_QLIMIT);
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, oqctl);
+Index: lustre/quota/quota_interface.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/quota/quota_interface.c,v
+retrieving revision 1.3.12.4
+diff -p -u -r1.3.12.4 quota_interface.c
+--- lustre/quota/quota_interface.c 25 Dec 2007 19:15:22 -0000 1.3.12.4
++++ lustre/quota/quota_interface.c 18 Jan 2008 05:51:53 -0000
+@@ -49,30 +49,20 @@
+
+ /* quota proc file handling functions */
+ #ifdef LPROCFS
+-int lprocfs_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);
+-}
+-EXPORT_SYMBOL(lprocfs_rd_bunit);
+
+-int lprocfs_rd_iunit(char *page, char **start, off_t off, int count,
+- int *eof, void *data)
++int lprocfs_quota_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_iunit_sz);
++ return snprintf(page, count, "%lu\n",
++ obd->u.obt.obt_qctxt.lqc_bunit_sz);
+ }
+-EXPORT_SYMBOL(lprocfs_rd_iunit);
++EXPORT_SYMBOL(lprocfs_quota_rd_bunit);
+
+-int lprocfs_wr_bunit(struct file *file, const char *buffer,
+- unsigned long count, void *data)
++int lprocfs_quota_wr_bunit(struct file *file, const char *buffer,
++ unsigned long count, void *data)
+ {
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+@@ -89,10 +79,21 @@ int lprocfs_wr_bunit(struct file *file,
+ obd->u.obt.obt_qctxt.lqc_bunit_sz = val;
+ return count;
+ }
+-EXPORT_SYMBOL(lprocfs_wr_bunit);
++EXPORT_SYMBOL(lprocfs_quota_wr_bunit);
+
+-int lprocfs_wr_iunit(struct file *file, const char *buffer,
+- unsigned long count, void *data)
++int lprocfs_quota_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);
++}
++EXPORT_SYMBOL(lprocfs_quota_rd_btune);
++
++int lprocfs_quota_wr_btune(struct file *file, const char *buffer,
++ unsigned long count, void *data)
+ {
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+@@ -102,38 +103,58 @@ int lprocfs_wr_iunit(struct file *file,
+ if (rc)
+ return rc;
+
+- if (val <= obd->u.obt.obt_qctxt.lqc_itune_sz)
++ 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_iunit_sz = val;
++ obd->u.obt.obt_qctxt.lqc_btune_sz = val;
+ return count;
+ }
+-EXPORT_SYMBOL(lprocfs_wr_iunit);
++EXPORT_SYMBOL(lprocfs_quota_wr_btune);
+
+-int lprocfs_rd_btune(char *page, char **start, off_t off, int count,
+- int *eof, void *data)
++int lprocfs_quota_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_btune_sz);
++ return snprintf(page, count, "%lu\n",
++ obd->u.obt.obt_qctxt.lqc_iunit_sz);
++}
++EXPORT_SYMBOL(lprocfs_quota_rd_iunit);
++
++int lprocfs_quota_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;
+ }
+-EXPORT_SYMBOL(lprocfs_rd_btune);
++EXPORT_SYMBOL(lprocfs_quota_wr_iunit);
+
+-int lprocfs_rd_itune(char *page, char **start, off_t off, int count,
+- int *eof, void *data)
++int lprocfs_quota_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",
++ return snprintf(page, count, "%lu\n",
+ obd->u.obt.obt_qctxt.lqc_itune_sz);
+ }
+-EXPORT_SYMBOL(lprocfs_rd_itune);
++EXPORT_SYMBOL(lprocfs_quota_rd_itune);
+
+-int lprocfs_wr_btune(struct file *file, const char *buffer,
+- unsigned long count, void *data)
++int lprocfs_quota_wr_itune(struct file *file, const char *buffer,
++ unsigned long count, void *data)
+ {
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+@@ -142,18 +163,29 @@ int lprocfs_wr_btune(struct file *file,
+ 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)
++
++ if (val <= MIN_QLIMIT ||
++ val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
+ return -EINVAL;
+
+- obd->u.obt.obt_qctxt.lqc_btune_sz = val;
++ obd->u.obt.obt_qctxt.lqc_itune_sz = val;
+ return count;
+ }
+-EXPORT_SYMBOL(lprocfs_wr_btune);
++EXPORT_SYMBOL(lprocfs_quota_wr_itune);
+
+-int lprocfs_wr_itune(struct file *file, const char *buffer,
+- unsigned long count, void *data)
++int lprocfs_quota_rd_switch_seconds(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, "%d\n",
++ obd->u.obt.obt_qctxt.lqc_switch_seconds);
++}
++EXPORT_SYMBOL(lprocfs_quota_rd_switch_seconds);
++
++int lprocfs_quota_wr_switch_seconds(struct file *file, const char *buffer,
++ unsigned long count, void *data)
+ {
+ struct obd_device *obd = (struct obd_device *)data;
+ int val, rc;
+@@ -162,22 +194,21 @@ int lprocfs_wr_itune(struct file *file,
+ rc = lprocfs_write_helper(buffer, count, &val);
+ if (rc)
+ return rc;
+-
+- if (val <= MIN_QLIMIT ||
+- val >= obd->u.obt.obt_qctxt.lqc_iunit_sz)
++
++ if (val <= 10)
+ return -EINVAL;
+
+- obd->u.obt.obt_qctxt.lqc_itune_sz = val;
++ obd->u.obt.obt_qctxt.lqc_switch_seconds = val;
+ return count;
+ }
+-EXPORT_SYMBOL(lprocfs_wr_itune);
++EXPORT_SYMBOL(lprocfs_quota_wr_switch_seconds);
+
+ #define USER_QUOTA 1
+ #define GROUP_QUOTA 2
+
+ #define MAX_STYPE_SIZE 5
+-int lprocfs_rd_type(char *page, char **start, off_t off, int count,
+- int *eof, void *data)
++int lprocfs_quota_rd_type(char *page, char **start, off_t off, int count,
++ int *eof, void *data)
+ {
+ struct obd_device *obd = (struct obd_device *)data;
+ char stype[MAX_STYPE_SIZE + 1] = "";
+@@ -216,9 +247,9 @@ int lprocfs_rd_type(char *page, char **s
+
+ return snprintf(page, count, "%s\n", stype);
+ }
+-EXPORT_SYMBOL(lprocfs_rd_type);
++EXPORT_SYMBOL(lprocfs_quota_rd_type);
+
+-static int auto_quota_on(struct obd_device *obd, int type,
++static int auto_quota_on(struct obd_device *obd, int type,
+ struct super_block *sb, int is_master)
+ {
+ struct obd_quotactl *oqctl;
+@@ -248,7 +279,7 @@ static int auto_quota_on(struct obd_devi
+ /* turn on cluster wide quota */
+ rc = mds_admin_quota_on(obd, oqctl);
+ if (rc) {
+- CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR,
++ CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR,
+ "auto-enable admin quota failed. rc=%d\n", rc);
+ GOTO(out_pop, rc);
+ }
+@@ -256,7 +287,7 @@ local_quota:
+ /* turn on local quota */
+ rc = fsfilt_quotactl(obd, sb, oqctl);
+ if (rc) {
+- CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR,
++ CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR,
+ "auto-enable local quota failed. rc=%d\n", rc);
+ if (is_master)
+ mds_quota_off(obd, oqctl);
+@@ -270,8 +301,8 @@ out_pop:
+ RETURN(rc);
+ }
+
+-int lprocfs_wr_type(struct file *file, const char *buffer,
+- unsigned long count, void *data)
++int lprocfs_quota_wr_type(struct file *file, const char *buffer,
++ unsigned long count, void *data)
+ {
+ struct obd_device *obd = (struct obd_device *)data;
+ struct obd_device_target *obt = &obd->u.obt;
+@@ -290,14 +321,14 @@ int lprocfs_wr_type(struct file *file, c
+ int rc;
+
+ switch (stype[i]) {
+- case 'u' :
++ case 'u' :
+ type |= USER_QUOTA;
+ break;
+- case 'g' :
++ case 'g' :
+ type |= GROUP_QUOTA;
+ break;
+ /* quota version specifiers */
+- case '1' :
++ case '1' :
+ if (strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME))
+ break;
+
+@@ -307,7 +338,7 @@ int lprocfs_wr_type(struct file *file, c
+ return rc;
+ }
+ break;
+- case '2' :
++ case '2' :
+ if (strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME))
+ break;
+
+@@ -331,42 +362,13 @@ int lprocfs_wr_type(struct file *file, c
+ auto_quota_on(obd, type - 1, obt->obt_sb, 1);
+ else if (!strcmp(obd->obd_type->typ_name, LUSTRE_OST_NAME))
+ auto_quota_on(obd, type - 1, obt->obt_sb, 0);
+- else
++ else
+ return -EFAULT;
+
+ return count;
+ }
+-EXPORT_SYMBOL(lprocfs_wr_type);
++EXPORT_SYMBOL(lprocfs_quota_wr_type);
+
+-int lprocfs_filter_rd_limit(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_limit_sz);
+-}
+-EXPORT_SYMBOL(lprocfs_filter_rd_limit);
+-
+-int lprocfs_filter_wr_limit(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 <= 1 << 20)
+- return -EINVAL;
+-
+- obd->u.obt.obt_qctxt.lqc_limit_sz = val;
+- return count;
+-}
+-EXPORT_SYMBOL(lprocfs_filter_wr_limit);
+
+ #endif /* LPROCFS */
+
+@@ -406,7 +408,8 @@ static int filter_quota_setinfo(struct o
+ imp = exp->exp_imp_reverse;
+ if (imp)
+ imp->imp_connect_data.ocd_connect_flags |=
+- (exp->exp_connect_flags & OBD_CONNECT_QUOTA64);
++ (exp->exp_connect_flags &
++ (OBD_CONNECT_QUOTA64 | OBD_CONNECT_CHANGE_QS));
+
+ /* start quota slave recovery thread. (release high limits) */
+ qslave_start_recovery(obd, &obd->u.obt.obt_qctxt);
+@@ -487,53 +490,202 @@ static int filter_quota_getflag(struct o
+ RETURN(rc);
+ }
+
+-static int filter_quota_acquire(struct obd_device *obd, unsigned int uid,
++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);
++ rc = qctxt_adjust_qunit(obd, qctxt, uid, gid, LQUOTA_FLAGS_BLK, 1);
++ RETURN(rc);
+ }
+
+-/* check whether the left quota of certain uid and uid can satisfy a write rpc
+- * when need to acquire quota, return QUOTA_RET_ACQUOTA */
+-static int filter_quota_check(struct obd_device *obd, unsigned int uid,
+- unsigned int gid, int npage)
++/* check whether the left quota of certain uid and gid can satisfy a block_write
++ * or inode_create rpc. When need to acquire quota, return QUOTA_RET_ACQUOTA */
++static int quota_check_common(struct obd_device *obd, unsigned int uid,
++ unsigned int gid, int count, int cycle, int isblk)
+ {
+ struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
+ int i;
+ __u32 id[MAXQUOTAS] = { uid, gid };
+- __u64 limit;
+ struct qunit_data qdata[MAXQUOTAS];
+- int rc;
++ int rc = 0, rc2[2] = { 0, 0 };
+ ENTRY;
+
+ CLASSERT(MAXQUOTAS < 4);
+ if (!sb_any_quota_enabled(qctxt->lqc_sb))
+- RETURN(0);
++ RETURN(rc);
+
+ for (i = 0; i < MAXQUOTAS; i++) {
++ struct lustre_qunit_size *lqs = NULL;
++
+ qdata[i].qd_id = id[i];
+ qdata[i].qd_flags = i;
+- qdata[i].qd_flags |= QUOTA_IS_BLOCK;
++ if (isblk)
++ QDATA_SET_BLK(&qdata[i]);
+ qdata[i].qd_count = 0;
+
+- qctxt_wait_pending_dqacq(qctxt, id[i], i, 1);
+- rc = compute_remquota(obd, qctxt, &qdata[i]);
+- limit = npage * CFS_PAGE_SIZE;
+- if (limit < qctxt->lqc_limit_sz )
+- limit = qctxt->lqc_limit_sz;
+- if (rc == QUOTA_RET_OK &&
+- qdata[i].qd_count < limit)
+- RETURN(QUOTA_RET_ACQUOTA);
++ /* ignore root user */
++ if (qdata[i].qd_id == 0 && !QDATA_IS_GRP(&qdata[i]))
++ continue;
++
++ quota_search_lqs(&qdata[i], NULL, qctxt, &lqs);
++ if (!lqs)
++ continue;
++
++ qctxt_wait_pending_dqacq(qctxt, id[i], i, isblk);
++ rc2[i] = compute_remquota(obd, qctxt, &qdata[i], isblk);
++ spin_lock(&lqs->lqs_lock);
++ if (!cycle) {
++ rc = QUOTA_RET_INC_PENDING;
++ if (isblk)
++ lqs->lqs_bwrite_pending += count;
++ else
++ lqs->lqs_iwrite_pending += count;
++ }
++
++ CDEBUG(D_QUOTA, "write pending: %lu, qd_count: "LPU64".\n",
++ isblk ? lqs->lqs_bwrite_pending : lqs->lqs_iwrite_pending,
++ qdata[i].qd_count);
++ if (rc2[i] == QUOTA_RET_OK) {
++ if (isblk && qdata[i].qd_count <
++ lqs->lqs_bwrite_pending * CFS_PAGE_SIZE)
++ rc2[i] = QUOTA_RET_ACQUOTA;
++ if (!isblk && qdata[i].qd_count <
++ lqs->lqs_iwrite_pending)
++ rc2[i] = QUOTA_RET_ACQUOTA;
++ }
++
++ spin_unlock(&lqs->lqs_lock);
++ lqs_putref(lqs);
+ }
+
++ if (rc2[0] == QUOTA_RET_ACQUOTA || rc2[1] == QUOTA_RET_ACQUOTA)
++ RETURN(rc | QUOTA_RET_ACQUOTA);
++ else
++ RETURN(rc);
++}
++
++static int quota_chk_acq_common(struct obd_device *obd, unsigned int uid,
++ unsigned int gid, int count, int *pending,
++ int isblk, quota_acquire acquire)
++{
++ int rc = 0, cycle = 0;
++ ENTRY;
++
++ while ((rc = quota_check_common(obd, uid, gid, count, cycle, isblk)) &
++ QUOTA_RET_ACQUOTA) {
++
++ if (rc & QUOTA_RET_INC_PENDING)
++ *pending = 1;
++
++ cycle++;
++ if (isblk)
++ OBD_FAIL_TIMEOUT(OBD_FAIL_OST_HOLD_WRITE_RPC, 90);
++ rc = acquire(obd, uid, gid);
++
++ /* please reference to dqacq_completion for the below */
++ /* a new request is finished, try again */
++ if (rc == -EAGAIN) {
++ CDEBUG(D_QUOTA, "finish a quota req, try again\n");
++ continue;
++ }
++
++ /* it is out of quota already */
++ if (rc == -EDQUOT) {
++ CDEBUG(D_QUOTA, "out of quota, return -EDQUOT\n");
++ break;
++ }
++
++ /* -EBUSY and others, try 10 times */
++ if (rc < 0 && cycle < 10) {
++ CDEBUG(D_QUOTA, "rc: %d, cycle: %d\n", rc, cycle);
++ cfs_schedule_timeout(CFS_TASK_INTERRUPTIBLE, HZ);
++ continue;
++ }
++
++ CDEBUG(D_QUOTA, "exit with rc: %d\n", rc);
++ break;
++ }
++
++ if (!cycle && rc & QUOTA_RET_INC_PENDING)
++ *pending = 1;
++
+ RETURN(rc);
+ }
+
++
++static int filter_quota_check(struct obd_device *obd, unsigned int uid,
++ unsigned int gid, int npage, int *flag,
++ quota_acquire acquire)
++{
++ return quota_chk_acq_common(obd, uid, gid, npage, flag, LQUOTA_FLAGS_BLK,
++ acquire);
++}
++
++/* when a block_write or inode_create rpc is finished, adjust the record for
++ * pending blocks and inodes*/
++static int quota_pending_commit(struct obd_device *obd, unsigned int uid,
++ unsigned int gid, int count, int isblk)
++{
++ struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
++ int i;
++ __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++) {
++ struct lustre_qunit_size *lqs = NULL;
++
++ qdata[i].qd_id = id[i];
++ qdata[i].qd_flags = i;
++ if (isblk)
++ QDATA_SET_BLK(&qdata[i]);
++ qdata[i].qd_count = 0;
++
++ if (qdata[i].qd_id == 0 && !QDATA_IS_GRP(&qdata[i]))
++ continue;
++
++ quota_search_lqs(&qdata[i], NULL, qctxt, &lqs);
++ if (lqs) {
++ spin_lock(&lqs->lqs_lock);
++ CDEBUG(D_QUOTA, "pending: %lu, count: %d.\n",
++ isblk ? lqs->lqs_bwrite_pending :
++ lqs->lqs_iwrite_pending, count);
++
++ if (isblk) {
++ if (lqs->lqs_bwrite_pending >= count)
++ lqs->lqs_bwrite_pending -= count;
++ else
++ CDEBUG(D_ERROR,
++ "there are too many blocks!\n");
++ } else {
++ if (lqs->lqs_iwrite_pending >= count)
++ lqs->lqs_iwrite_pending -= count;
++ else
++ CDEBUG(D_ERROR,
++ "there are too many files!\n");
++ }
++
++ spin_unlock(&lqs->lqs_lock);
++ lqs_putref(lqs);
++ }
++ }
++
++ RETURN(0);
++}
++
++static int filter_quota_pending_commit(struct obd_device *obd, unsigned int uid,
++ unsigned int gid, int npage)
++{
++ return quota_pending_commit(obd, uid, gid, npage, LQUOTA_FLAGS_BLK);
++}
++
+ static int mds_quota_init(void)
+ {
+ return lustre_dquot_init();
+@@ -587,6 +739,30 @@ static int mds_quota_fs_cleanup(struct o
+ up(&mds->mds_qonoff_sem);
+ RETURN(0);
+ }
++
++static int mds_quota_check(struct obd_device *obd, unsigned int uid,
++ unsigned int gid, int inodes, int *flag,
++ quota_acquire acquire)
++{
++ return quota_chk_acq_common(obd, uid, gid, inodes, flag, 0, acquire);
++}
++
++static int mds_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, 0, 1);
++ RETURN(rc);
++}
++
++static int mds_quota_pending_commit(struct obd_device *obd, unsigned int uid,
++ unsigned int gid, int inodes)
++{
++ return quota_pending_commit(obd, uid, gid, inodes, 0);
++}
+ #endif /* __KERNEL__ */
+
+ struct osc_quota_info {
+@@ -810,6 +986,9 @@ quota_interface_t mds_quota_interface =
+ .quota_fs_cleanup =mds_quota_fs_cleanup,
+ .quota_recovery = mds_quota_recovery,
+ .quota_adjust = mds_quota_adjust,
++ .quota_chkquota = mds_quota_check,
++ .quota_acquire = mds_quota_acquire,
++ .quota_pending_commit = mds_quota_pending_commit,
+ };
+
+ quota_interface_t filter_quota_interface = {
+@@ -824,6 +1003,8 @@ quota_interface_t filter_quota_interface
+ .quota_acquire = filter_quota_acquire,
+ .quota_adjust = filter_quota_adjust,
+ .quota_chkquota = filter_quota_check,
++ .quota_adjust_qunit = filter_quota_adjust_qunit,
++ .quota_pending_commit = filter_quota_pending_commit,
+ };
+ #endif /* __KERNEL__ */
+
+@@ -842,11 +1023,13 @@ quota_interface_t osc_quota_interface =
+ .quota_chkdq = osc_quota_chkdq,
+ .quota_setdq = osc_quota_setdq,
+ .quota_cleanup = osc_quota_cleanup,
++ .quota_adjust_qunit = client_quota_adjust_qunit,
+ };
+
+ quota_interface_t lov_quota_interface = {
+ .quota_check = lov_quota_check,
+ .quota_ctl = lov_quota_ctl,
++ .quota_adjust_qunit = lov_quota_adjust_qunit,
+ };
+
+ #ifdef __KERNEL__
+Index: lustre/quota/quota_internal.h
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/quota/quota_internal.h,v
+retrieving revision 1.3.12.3
+diff -p -u -r1.3.12.3 quota_internal.h
+--- lustre/quota/quota_internal.h 3 Jan 2008 06:31:15 -0000 1.3.12.3
++++ lustre/quota/quota_internal.h 18 Jan 2008 05:51:53 -0000
+@@ -19,7 +19,7 @@
+ /* 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
++/* This flag is set in qc_stat to distinguish if the current getquota
+ * operation is for quota recovery */
+ #define QUOTA_RECOVERING 0x01
+
+@@ -45,10 +45,28 @@
+ qinfo->qi_info[1].dqi_free_entry, ## arg);
+
+ #define QDATA_DEBUG(qd, fmt, arg...) \
+- CDEBUG(D_QUOTA, "id(%u) type(%lu) count("LPU64") isblk(%lu):" \
+- fmt, qd->qd_id, qd->qd_flags & QUOTA_IS_GRP, qd->qd_count, \
+- (qd->qd_flags & QUOTA_IS_BLOCK) >> 1, \
+- ## arg);
++ CDEBUG(D_QUOTA, "id(%u) flag(%u) type(%c) isblk(%c) count("LPU64") " \
++ "qd_qunit("LPU64"): " fmt, qd->qd_id, qd->qd_flags, \
++ QDATA_IS_GRP(qd) ? 'g' : 'u', QDATA_IS_BLK(qd) ? 'b': 'i', \
++ qd->qd_count, qd->qd_qunit, ## arg);
++
++#define QAQ_DEBUG(qaq, fmt, arg...) \
++ CDEBUG(D_QUOTA, "id(%u) flag(%u) type(%c) bunit("LPU64") " \
++ "iunit("LPU64"): " fmt, qaq->qaq_id, qaq->qaq_flags, \
++ QAQ_IS_GRP(qaq) ? 'g': 'u', qaq->qaq_bunit_sz, \
++ qaq->qaq_iunit_sz, ## arg);
++
++#define LQS_DEBUG(lqs, fmt, arg...) \
++ CDEBUG(D_QUOTA, "lqs(%p) id(%u) flag(%lu) type(%c) bunit(%lu) " \
++ "btune(%lu) iunit(%lu) itune(%lu) lqs_bwrite_pending(%lu) " \
++ "lqs_iwrite_pending(%lu) ino_rec("LPD64") blk_rec("LPD64" )" \
++ "refcount(%d): " \
++ fmt, lqs, lqs->lqs_id, lqs->lqs_flags, \
++ LQS_IS_GRP(lqs) ? 'g' : 'u', \
++ lqs->lqs_bunit_sz, lqs->lqs_btune_sz, lqs->lqs_iunit_sz, \
++ lqs->lqs_itune_sz, lqs->lqs_bwrite_pending, \
++ lqs->lqs_iwrite_pending, lqs->lqs_ino_rec, \
++ lqs->lqs_blk_rec, atomic_read(&lqs->lqs_refcount), ## arg);
+
+
+ /* quota_context.c */
+@@ -61,10 +79,11 @@ int qctxt_wait_pending_dqacq(struct lust
+ 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,
++void qslave_start_recovery(struct obd_device *obd,
+ struct lustre_quota_ctxt *qctxt);
+ int compute_remquota(struct obd_device *obd,
+- struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata);
++ struct lustre_quota_ctxt *qctxt, struct qunit_data *qdata,
++ int isblk);
+ /* quota_master.c */
+ int lustre_dquot_init(void);
+ void lustre_dquot_exit(void);
+@@ -87,6 +106,9 @@ int mds_set_dqblk(struct obd_device *obd
+ 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);
++int dquot_create_oqaq(struct lustre_quota_ctxt *qctxt, struct lustre_dquot
++ *dquot, __u32 ost_num, __u32 mdt_num, int type,
++ struct quota_adjust_qunit *oqaq);
+ #endif
+
+ /* quota_ctl.c */
+@@ -117,4 +139,40 @@ static inline void lprocfs_quotacheck_te
+ }
+ #endif
+
++/* quota_adjust_qunit.c */
++int client_quota_adjust_qunit(struct obd_export *exp, struct
++ quota_adjust_qunit *oqaq);
++int lov_quota_adjust_qunit(struct obd_export *exp, struct
++ quota_adjust_qunit *oqaq);
++int quota_adjust_slave_lqs(struct quota_adjust_qunit *oqaq, struct
++ lustre_quota_ctxt *qctxt);
++void qdata_to_oqaq(struct qunit_data *qdata,
++ struct quota_adjust_qunit *oqaq);
++#ifdef __KERNEL__
++int quota_search_lqs(struct qunit_data *qdata,
++ struct quota_adjust_qunit *oqaq,
++ struct lustre_quota_ctxt *qctxt,
++ struct lustre_qunit_size **lqs_return);
++int quota_create_lqs(struct qunit_data *qdata,
++ struct quota_adjust_qunit *oqaq,
++ struct lustre_quota_ctxt *qctxt,
++ struct lustre_qunit_size **lqs_return);
++void quota_compute_lqs(struct qunit_data *qdata, struct lustre_qunit_size *lqs,
++ int is_chk, int is_acq);
++
++
++extern int quote_get_qdata(struct ptlrpc_request *req, struct qunit_data *qdata,
++ int is_req, int is_exp);
++extern int quote_copy_qdata(struct ptlrpc_request *req, struct qunit_data *qdata,
++ int is_req, int is_exp);
++int filter_quota_adjust_qunit(struct obd_export *exp, struct
++ quota_adjust_qunit *oqaq);
++#endif
++
++#define LQS_BLK_DECREASE 1
++#define LQS_BLK_INCREASE 2
++#define LQS_INO_DECREASE 4
++#define LQS_INO_INCREASE 8
++
++
+ #endif
+Index: lustre/quota/quota_master.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/quota/quota_master.c,v
+retrieving revision 1.2.34.6
+diff -p -u -r1.2.34.6 quota_master.c
+--- lustre/quota/quota_master.c 25 Dec 2007 19:15:24 -0000 1.2.34.6
++++ lustre/quota/quota_master.c 18 Jan 2008 05:51:53 -0000
+@@ -198,23 +198,129 @@ static struct lustre_dquot *lustre_dqget
+ RETURN(dquot);
+ }
+
++static void init_oqaq(struct quota_adjust_qunit *oqaq,
++ struct lustre_quota_ctxt *qctxt,
++ qid_t id, int type)
++{
++ struct lustre_qunit_size *lqs = NULL;
++
++ oqaq->qaq_id = id;
++ oqaq->qaq_flags = type;
++ quota_search_lqs(NULL, oqaq, qctxt, &lqs);
++ if (lqs) {
++ spin_lock(&lqs->lqs_lock);
++ oqaq->qaq_bunit_sz = lqs->lqs_bunit_sz;
++ oqaq->qaq_iunit_sz = lqs->lqs_iunit_sz;
++ oqaq->qaq_flags = lqs->lqs_flags;
++ spin_unlock(&lqs->lqs_lock);
++ lqs_putref(lqs);
++ } else {
++ CDEBUG(D_QUOTA, "Can't find the lustre qunit size!\n");
++ oqaq->qaq_bunit_sz = qctxt->lqc_bunit_sz;
++ oqaq->qaq_iunit_sz = qctxt->lqc_iunit_sz;
++ }
++}
++
++int dqacq_adjust_qunit_sz(struct obd_device *obd, qid_t id, int type,
++ __u32 is_blk)
++{
++ struct mds_obd *mds = &obd->u.mds;
++ struct lustre_quota_ctxt *qctxt = &mds->mds_obt.obt_qctxt;
++ struct obd_device *lov_mds_obd = class_exp2obd(mds->mds_osc_exp);
++ struct lov_obd *lov = &lov_mds_obd->u.lov;
++ __u32 ost_num = lov->desc.ld_tgt_count, mdt_num = 1;
++ struct quota_adjust_qunit *oqaq = NULL;
++ unsigned int uid = 0, gid = 0;
++ struct lustre_quota_info *info = &mds->mds_quota_info;
++ struct lustre_dquot *dquot = NULL;
++ int adjust_res = 0;
++ int rc = 0;
++ ENTRY;
++
++ LASSERT(mds);
++ dquot = lustre_dqget(obd, info, id, type);
++ if (IS_ERR(dquot))
++ RETURN(PTR_ERR(dquot));
++
++ OBD_ALLOC_PTR(oqaq);
++ if (!oqaq)
++ GOTO(out, rc = -ENOMEM);
++
++ down(&dquot->dq_sem);
++ init_oqaq(oqaq, qctxt, id, type);
++
++ rc = dquot_create_oqaq(qctxt, dquot, ost_num, mdt_num,
++ is_blk ? LQUOTA_FLAGS_ADJBLK :
++ LQUOTA_FLAGS_ADJINO, oqaq);
++
++ if (rc < 0) {
++ CDEBUG(D_ERROR, "create oqaq failed! (rc:%d)\n", rc);
++ GOTO(out_sem, rc);
++ }
++ QAQ_DEBUG(oqaq, "show oqaq.\n")
++
++ if (!QAQ_IS_ADJBLK(oqaq) && !QAQ_IS_ADJINO(oqaq))
++ GOTO(out_sem, rc);
++
++ /* adjust the mds slave qunit size */
++ adjust_res = quota_adjust_slave_lqs(oqaq, qctxt);
++ if (adjust_res <= 0) {
++ if (adjust_res < 0) {
++ rc = adjust_res;
++ CDEBUG(D_ERROR, "adjust mds slave's qunit size failed! \
++ (rc:%d)\n", rc);
++ } else {
++ CDEBUG(D_QUOTA, "qunit doesn't need to be adjusted.\n");
++ }
++ GOTO(out_sem, rc);
++ }
++
++ if (type)
++ gid = dquot->dq_id;
++ else
++ uid = dquot->dq_id;
++
++ up(&dquot->dq_sem);
++
++ rc = qctxt_adjust_qunit(obd, qctxt, uid, gid, is_blk, 0);
++ if (rc) {
++ CDEBUG(D_ERROR, "mds fail to adjust file quota! \
++ (rc:%d)\n", rc);
++ GOTO(out, rc);
++ }
++
++ /* only when block qunit is reduced, boardcast to osts */
++ if ((adjust_res & LQS_BLK_DECREASE) && QAQ_IS_ADJBLK(oqaq))
++ rc = obd_quota_adjust_qunit(mds->mds_osc_exp, oqaq);
++
++out:
++ lustre_dqput(dquot);
++ if (oqaq)
++ OBD_FREE_PTR(oqaq);
++
++ RETURN(rc);
++out_sem:
++ up(&dquot->dq_sem);
++ goto out;
++}
++
+ int dqacq_handler(struct obd_device *obd, struct qunit_data *qdata, int opc)
+ {
+ struct mds_obd *mds = &obd->u.mds;
++ struct lustre_quota_ctxt *qctxt = &mds->mds_obt.obt_qctxt;
+ struct lustre_quota_info *info = &mds->mds_quota_info;
+ struct lustre_dquot *dquot = NULL;
+ __u64 *usage = NULL;
+ __u32 hlimit = 0, slimit = 0;
+- __u32 qdata_type = qdata->qd_flags & QUOTA_IS_GRP;
+- __u32 is_blk = (qdata->qd_flags & QUOTA_IS_BLOCK) >> 1;
+ time_t *time = NULL;
+ unsigned int grace = 0;
++ struct lustre_qunit_size *lqs = NULL;
+ int rc = 0;
+ ENTRY;
+
+ OBD_FAIL_RETURN(OBD_FAIL_OBD_DQACQ, -EIO);
+
+- dquot = lustre_dqget(obd, info, qdata->qd_id, qdata_type);
++ dquot = lustre_dqget(obd, info, qdata->qd_id, QDATA_IS_GRP(qdata));
+ if (IS_ERR(dquot))
+ RETURN(PTR_ERR(dquot));
+
+@@ -229,14 +335,14 @@ int dqacq_handler(struct obd_device *obd
+ GOTO(out, rc = -EBUSY);
+ }
+
+- if (is_blk) {
+- grace = info->qi_info[qdata_type].dqi_bgrace;
++ if (QDATA_IS_BLK(qdata)) {
++ grace = info->qi_info[QDATA_IS_GRP(qdata)].dqi_bgrace;
+ usage = &dquot->dq_dqb.dqb_curspace;
+ hlimit = dquot->dq_dqb.dqb_bhardlimit;
+ slimit = dquot->dq_dqb.dqb_bsoftlimit;
+ time = &dquot->dq_dqb.dqb_btime;
+ } else {
+- grace = info->qi_info[qdata_type].dqi_igrace;
++ grace = info->qi_info[QDATA_IS_GRP(qdata)].dqi_igrace;
+ usage = (__u64 *) & dquot->dq_dqb.dqb_curinodes;
+ hlimit = dquot->dq_dqb.dqb_ihardlimit;
+ slimit = dquot->dq_dqb.dqb_isoftlimit;
+@@ -252,12 +358,20 @@ int dqacq_handler(struct obd_device *obd
+
+ switch (opc) {
+ case QUOTA_DQACQ:
+- if (hlimit &&
+- QUSG(*usage + qdata->qd_count, is_blk) > hlimit)
+- GOTO(out, rc = -EDQUOT);
++ if (hlimit &&
++ QUSG(*usage + qdata->qd_count, QDATA_IS_BLK(qdata)) > hlimit)
++ {
++ if (QDATA_IS_CHANGE_QS(qdata) &&
++ QUSG(*usage, QDATA_IS_BLK(qdata)) < hlimit)
++ qdata->qd_count = (hlimit -
++ QUSG(*usage, QDATA_IS_BLK(qdata)))
++ * QUOTABLOCK_SIZE;
++ else
++ GOTO(out, rc = -EDQUOT);
++ }
+
+ if (slimit &&
+- QUSG(*usage + qdata->qd_count, is_blk) > slimit) {
++ QUSG(*usage + qdata->qd_count, QDATA_IS_BLK(qdata)) > slimit) {
+ if (*time && cfs_time_current_sec() >= *time)
+ GOTO(out, rc = -EDQUOT);
+ else if (!*time)
+@@ -275,7 +389,7 @@ int dqacq_handler(struct obd_device *obd
+ *usage -= qdata->qd_count;
+
+ /* (usage <= soft limit) but not (usage < soft limit) */
+- if (!slimit || QUSG(*usage, is_blk) <= slimit)
++ if (!slimit || QUSG(*usage, QDATA_IS_BLK(qdata)) <= slimit)
+ *time = 0;
+ break;
+ default:
+@@ -288,6 +402,36 @@ out:
+ up(&dquot->dq_sem);
+ up(&mds->mds_qonoff_sem);
+ lustre_dqput(dquot);
++ if (rc != -EDQUOT)
++ dqacq_adjust_qunit_sz(obd, qdata->qd_id, QDATA_IS_GRP(qdata), QDATA_IS_BLK(qdata));
++
++ quota_search_lqs(qdata, NULL, qctxt, &lqs);
++ if (QDATA_IS_BLK(qdata)) {
++ if (!lqs) {
++ CDEBUG(D_INFO, "Can't find the lustre qunit size!\n");
++ qdata->qd_qunit = qctxt->lqc_bunit_sz;
++ } else {
++ spin_lock(&lqs->lqs_lock);
++ qdata->qd_qunit = lqs->lqs_bunit_sz;
++ spin_unlock(&lqs->lqs_lock);
++ }
++ QDATA_SET_ADJBLK(qdata);
++ } else {
++ if (!lqs) {
++ CDEBUG(D_INFO, "Can't find the lustre qunit size!\n");
++ qdata->qd_qunit = qctxt->lqc_iunit_sz;
++ } else {
++ spin_lock(&lqs->lqs_lock);
++ qdata->qd_qunit = lqs->lqs_iunit_sz;
++ spin_unlock(&lqs->lqs_lock);
++ }
++ QDATA_SET_ADJINO(qdata);
++ }
++
++ QDATA_DEBUG(qdata, "alloc/release qunit in dqacq_handler\n");
++ if (lqs)
++ lqs_putref(lqs);
++
+ return rc;
+ }
+
+@@ -778,10 +922,125 @@ out:
+ RETURN(rc);
+ }
+
++int dquot_create_oqaq(struct lustre_quota_ctxt *qctxt,
++ struct lustre_dquot *dquot, __u32 ost_num,
++ __u32 mdt_num, int type,
++ struct quota_adjust_qunit *oqaq)
++{
++ __u64 bunit_curr_o, iunit_curr_o;
++ unsigned long shrink_qunit_limit = qctxt->lqc_cqs_boundary_factor;
++ unsigned long cqs_factor = qctxt->lqc_cqs_qs_factor;
++ __u64 blimit = dquot->dq_dqb.dqb_bhardlimit ?
++ dquot->dq_dqb.dqb_bhardlimit : dquot->dq_dqb.dqb_bsoftlimit;
++ __u64 ilimit = dquot->dq_dqb.dqb_ihardlimit ?
++ dquot->dq_dqb.dqb_ihardlimit : dquot->dq_dqb.dqb_isoftlimit;
++ int rc = 0;
++ ENTRY;
++
++ if (!dquot || !oqaq)
++ RETURN(-EINVAL);
++ LASSERT_SEM_LOCKED(&dquot->dq_sem);
++ LASSERT(oqaq->qaq_iunit_sz);
++ LASSERT(oqaq->qaq_bunit_sz);
++
++ /* don't change qunit size */
++ if (!qctxt->lqc_switch_qs)
++ RETURN(rc);
++
++ bunit_curr_o = oqaq->qaq_bunit_sz;
++ iunit_curr_o = oqaq->qaq_iunit_sz;
++
++ if (dquot->dq_type == GRPQUOTA)
++ QAQ_SET_GRP(oqaq);
++
++ if ((type & LQUOTA_FLAGS_ADJBLK) && blimit) {
++ __u64 b_limitation =
++ oqaq->qaq_bunit_sz * ost_num * shrink_qunit_limit;
++ /* enlarge block qunit size */
++ while (blimit >
++ QUSG(dquot->dq_dqb.dqb_curspace + 2 * b_limitation, 1)) {
++ oqaq->qaq_bunit_sz =
++ QUSG(oqaq->qaq_bunit_sz * cqs_factor, 1)
++ << QUOTABLOCK_BITS;
++ b_limitation = oqaq->qaq_bunit_sz * ost_num *
++ shrink_qunit_limit;
++ }
++
++ if (oqaq->qaq_bunit_sz > qctxt->lqc_bunit_sz)
++ oqaq->qaq_bunit_sz = qctxt->lqc_bunit_sz;
++
++ /* shrink block qunit size */
++ while (blimit <
++ QUSG(dquot->dq_dqb.dqb_curspace + b_limitation, 1)) {
++ do_div(oqaq->qaq_bunit_sz , cqs_factor);
++ oqaq->qaq_bunit_sz = QUSG(oqaq->qaq_bunit_sz, 1) <<
++ QUOTABLOCK_BITS;
++ b_limitation = oqaq->qaq_bunit_sz * ost_num *
++ shrink_qunit_limit;
++ if (oqaq->qaq_bunit_sz < qctxt->lqc_cqs_least_bunit)
++ break;
++ }
++
++ if (oqaq->qaq_bunit_sz < qctxt->lqc_cqs_least_bunit)
++ oqaq->qaq_bunit_sz = qctxt->lqc_cqs_least_bunit;
++
++ if (bunit_curr_o != oqaq->qaq_bunit_sz)
++ QAQ_SET_ADJBLK(oqaq);
++
++ }
++
++ if ((type & LQUOTA_FLAGS_ADJINO) && ilimit) {
++ __u64 i_limitation =
++ oqaq->qaq_iunit_sz * mdt_num * shrink_qunit_limit;
++ /* enlarge file qunit size */
++ while (ilimit > dquot->dq_dqb.dqb_curinodes
++ + 2 * i_limitation) {
++ oqaq->qaq_iunit_sz = oqaq->qaq_iunit_sz * cqs_factor;
++ i_limitation = oqaq->qaq_iunit_sz * mdt_num *
++ shrink_qunit_limit;
++ }
++
++ if (oqaq->qaq_iunit_sz > qctxt->lqc_iunit_sz)
++ oqaq->qaq_iunit_sz = qctxt->lqc_iunit_sz;
++
++ /* shrink file qunit size */
++ while (ilimit < dquot->dq_dqb.dqb_curinodes
++ + i_limitation) {
++ do_div(oqaq->qaq_iunit_sz, cqs_factor);
++ i_limitation = oqaq->qaq_iunit_sz * mdt_num *
++ shrink_qunit_limit;
++ if (oqaq->qaq_iunit_sz < qctxt->lqc_cqs_least_iunit)
++ break;
++ }
++
++ if (oqaq->qaq_iunit_sz < qctxt->lqc_cqs_least_iunit)
++ oqaq->qaq_iunit_sz = qctxt->lqc_cqs_least_iunit;
++
++ if (iunit_curr_o != oqaq->qaq_iunit_sz)
++ QAQ_SET_ADJINO(oqaq);
++
++ }
++
++ if (!dquot->dq_dqb.dqb_bhardlimit && !dquot->dq_dqb.dqb_bsoftlimit &&
++ !dquot->dq_dqb.dqb_ihardlimit && !dquot->dq_dqb.dqb_isoftlimit) {
++ oqaq->qaq_bunit_sz = 0;
++ oqaq->qaq_iunit_sz = 0;
++ QAQ_SET_ADJBLK(oqaq);
++ QAQ_SET_ADJINO(oqaq);
++ }
++
++ QAQ_DEBUG(oqaq, "the oqaq computed\n");
++
++ RETURN(rc);
++}
++
+ static int mds_init_slave_ilimits(struct obd_device *obd,
+- struct obd_quotactl *oqctl, int set)
++ struct obd_quotactl *oqctl, int set,
++ struct quota_adjust_qunit *oqaq)
+ {
+ /* XXX: for file limits only adjust local now */
++ struct obd_device_target *obt = &obd->u.obt;
++ struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt;
+ unsigned int uid = 0, gid = 0;
+ struct obd_quotactl *ioqc = NULL;
+ int flag;
+@@ -796,8 +1055,8 @@ static int mds_init_slave_ilimits(struct
+ OBD_ALLOC_PTR(ioqc);
+ if (!ioqc)
+ RETURN(-ENOMEM);
+-
+- flag = oqctl->qc_dqblk.dqb_ihardlimit ||
++
++ flag = oqctl->qc_dqblk.dqb_ihardlimit ||
+ oqctl->qc_dqblk.dqb_isoftlimit || set;
+ ioqc->qc_cmd = flag ? Q_INITQUOTA : Q_SETQUOTA;
+ ioqc->qc_id = oqctl->qc_id;
+@@ -805,6 +1064,14 @@ static int mds_init_slave_ilimits(struct
+ ioqc->qc_dqblk.dqb_valid = QIF_ILIMITS;
+ ioqc->qc_dqblk.dqb_ihardlimit = flag ? MIN_QLIMIT : 0;
+
++ if (QAQ_IS_ADJINO(oqaq)) {
++ /* adjust the mds slave's inode qunit size */
++ rc = quota_adjust_slave_lqs(oqaq, qctxt);
++ if (rc < 0)
++ CDEBUG(D_ERROR, "adjust mds slave's inode qunit size \
++ failed! (rc:%d)\n", rc);
++ }
++
+ /* set local limit to MIN_QLIMIT */
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, ioqc);
+ if (rc)
+@@ -818,7 +1085,8 @@ static int mds_init_slave_ilimits(struct
+
+ 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);
++ CDEBUG(D_QUOTA,"error mds adjust local file quota! (rc:%d)\n",
++ rc);
+ GOTO(out, rc);
+ }
+ /* FIXME initialize all slaves in CMD */
+@@ -830,13 +1098,16 @@ out:
+ }
+
+ static int mds_init_slave_blimits(struct obd_device *obd,
+- struct obd_quotactl *oqctl, int set)
++ struct obd_quotactl *oqctl, int set,
++ struct quota_adjust_qunit *oqaq)
+ {
++ struct obd_device_target *obt = &obd->u.obt;
++ struct lustre_quota_ctxt *qctxt = &obt->obt_qctxt;
+ struct mds_obd *mds = &obd->u.mds;
+ struct obd_quotactl *ioqc;
+ unsigned int uid = 0, gid = 0;
++ int rc, rc1 = 0;
+ int flag;
+- int rc;
+ ENTRY;
+
+ /* if we are going to set zero limit, needn't init slaves */
+@@ -855,6 +1126,13 @@ static int mds_init_slave_blimits(struct
+ ioqc->qc_type = oqctl->qc_type;
+ ioqc->qc_dqblk.dqb_valid = QIF_BLIMITS;
+ ioqc->qc_dqblk.dqb_bhardlimit = flag ? MIN_QLIMIT : 0;
++ if (QAQ_IS_ADJBLK(oqaq)) {
++ /* adjust the mds slave's block qunit size */
++ rc1 = quota_adjust_slave_lqs(oqaq, qctxt);
++ if (rc1 < 0)
++ CERROR("adjust mds slave's block qunit size failed!"
++ "(rc:%d)\n", rc1);
++ }
+
+ rc = fsfilt_quotactl(obd, obd->u.obt.obt_sb, ioqc);
+ if (rc)
+@@ -866,14 +1144,21 @@ static int mds_init_slave_blimits(struct
+ else
+ gid = oqctl->qc_id;
+
++ /* initialize all slave's limit */
++ rc = obd_quotactl(mds->mds_osc_exp, ioqc);
++
+ 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 */
+- rc = obd_quotactl(mds->mds_osc_exp, ioqc);
++ /* adjust all slave's qunit size when setting quota
++ * this is will create a lqs for every ost, which will present
++ * certain uid/gid is set quota or not */
++ QAQ_SET_ADJBLK(oqaq);
++ rc = obd_quota_adjust_qunit(mds->mds_osc_exp, oqaq);
++
+ EXIT;
+ out:
+ OBD_FREE_PTR(ioqc);
+@@ -883,15 +1168,24 @@ out:
+ int mds_set_dqblk(struct obd_device *obd, struct obd_quotactl *oqctl)
+ {
+ struct mds_obd *mds = &obd->u.mds;
++ struct lustre_quota_ctxt *qctxt = &mds->mds_obt.obt_qctxt;
++ struct obd_device *lov_obd = class_exp2obd(mds->mds_osc_exp);
++ struct lov_obd *lov = &lov_obd->u.lov;
++ struct quota_adjust_qunit *oqaq = NULL;
+ struct lustre_quota_info *qinfo = &mds->mds_quota_info;
+ __u64 ihardlimit, isoftlimit, bhardlimit, bsoftlimit;
+ time_t btime, itime;
+ struct lustre_dquot *dquot;
+ struct obd_dqblk *dqblk = &oqctl->qc_dqblk;
+- int set, rc;
++ int set, rc, flag = 0;
+ ENTRY;
+
++ OBD_ALLOC_PTR(oqaq);
++ if (!oqaq)
++ RETURN(-ENOMEM);
+ down(&mds->mds_qonoff_sem);
++ init_oqaq(oqaq, qctxt, oqctl->qc_id, oqctl->qc_type);
++
+ if (qinfo->qi_files[oqctl->qc_type] == NULL)
+ GOTO(out_sem, rc = -ESRCH);
+
+@@ -926,18 +1220,20 @@ int mds_set_dqblk(struct obd_device *obd
+ dquot->dq_dqb.dqb_bhardlimit = dqblk->dqb_bhardlimit;
+ dquot->dq_dqb.dqb_bsoftlimit = dqblk->dqb_bsoftlimit;
+ /* clear usage (limit pool) */
+- if (!dquot->dq_dqb.dqb_bhardlimit &&
++ if (!dquot->dq_dqb.dqb_bhardlimit &&
+ !dquot->dq_dqb.dqb_bsoftlimit)
+ dquot->dq_dqb.dqb_curspace = 0;
+
+ /* clear grace time */
+- if (!dqblk->dqb_bsoftlimit ||
++ 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() +
++ dquot->dq_dqb.dqb_btime = cfs_time_current_sec() +
+ qinfo->qi_info[dquot->dq_type].dqi_bgrace;
++
++ flag |= LQUOTA_FLAGS_ADJBLK;
+ }
+
+ if (dqblk->dqb_valid & QIF_ILIMITS) {
+@@ -954,7 +1250,16 @@ int mds_set_dqblk(struct obd_device *obd
+ else if (!(dqblk->dqb_valid & QIF_ITIME))
+ dquot->dq_dqb.dqb_itime = cfs_time_current_sec() +
+ qinfo->qi_info[dquot->dq_type].dqi_igrace;
++
++ flag |= LQUOTA_FLAGS_ADJINO;
+ }
++ QAQ_DEBUG(oqaq, "before dquot_create_oqaq\n");
++ rc = dquot_create_oqaq(qctxt, dquot, lov->desc.ld_tgt_count, 1,
++ flag, oqaq);
++ QAQ_DEBUG(oqaq, "after dquot_create_oqaq\n");
++ if (rc < 0)
++ CDEBUG(D_QUOTA, "adjust qunit size failed! (rc:%d)\n", rc);
++
+
+ rc = fsfilt_dquot(obd, dquot, QFILE_WR_DQUOT);
+
+@@ -968,7 +1273,10 @@ int mds_set_dqblk(struct obd_device *obd
+ up(&mds->mds_qonoff_sem);
+ if (dqblk->dqb_valid & QIF_ILIMITS) {
+ set = !(ihardlimit || isoftlimit);
+- rc = mds_init_slave_ilimits(obd, oqctl, set);
++ down(&dquot->dq_sem);
++ dquot->dq_dqb.dqb_curinodes = 0;
++ up(&dquot->dq_sem);
++ rc = mds_init_slave_ilimits(obd, oqctl, set, oqaq);
+ if (rc) {
+ CERROR("init slave ilimits failed! (rc:%d)\n", rc);
+ goto revoke_out;
+@@ -977,7 +1285,10 @@ int mds_set_dqblk(struct obd_device *obd
+
+ if (dqblk->dqb_valid & QIF_BLIMITS) {
+ set = !(bhardlimit || bsoftlimit);
+- rc = mds_init_slave_blimits(obd, oqctl, set);
++ down(&dquot->dq_sem);
++ dquot->dq_dqb.dqb_curspace = 0;
++ up(&dquot->dq_sem);
++ rc = mds_init_slave_blimits(obd, oqctl, set, oqaq);
+ if (rc) {
+ CERROR("init slave blimits failed! (rc:%d)\n", rc);
+ goto revoke_out;
+@@ -1006,6 +1317,10 @@ out:
+ EXIT;
+ out_sem:
+ up(&mds->mds_qonoff_sem);
++
++ if (oqaq)
++ OBD_FREE_PTR(oqaq);
++
+ return rc;
+ }
+
+Index: lustre/tests/sanity-quota.sh
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/tests/sanity-quota.sh,v
+retrieving revision 1.7.10.23
+diff -p -u -r1.7.10.23 sanity-quota.sh
+--- lustre/tests/sanity-quota.sh 4 Jan 2008 08:33:41 -0000 1.7.10.23
++++ lustre/tests/sanity-quota.sh 18 Jan 2008 05:51:53 -0000
+@@ -37,10 +37,8 @@ TSTID2=${TSTID2:-60001}
+ TSTUSR=${TSTUSR:-"quota_usr"}
+ TSTUSR2=${TSTUSR2:-"quota_2usr"}
+ 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
++BUNIT_SZ=${BUNIT_SZ:-1024} # min block quota unit(kB)
++IUNIT_SZ=${IUNIT_SZ:-10} # min inode quota unit
+ MAX_DQ_TIME=604800
+ MAX_IQ_TIME=604800
+
+@@ -66,6 +64,9 @@ SHOW_QUOTA_USER="$LFS quota -u $TSTUSR $
+ SHOW_QUOTA_GROUP="$LFS quota -g $TSTUSR $DIR"
+ SHOW_QUOTA_INFO="$LFS quota -t $DIR"
+
++# control the time of tests
++cycle=30
++
+ build_test_filter
+
+ eval ONLY_0=true
+@@ -73,6 +74,7 @@ eval ONLY_99=true
+
+ # set_blk_tunables(btune_sz)
+ set_blk_tunesz() {
++ local i
+ # set btune size on all obdfilters
+ do_facet ost1 "set -x; for i in /proc/fs/lustre/obdfilter/*/quota_btune_sz; do
+ echo $(($1 * BLK_SZ)) >> \\\$i;
+@@ -85,6 +87,7 @@ set_blk_tunesz() {
+
+ # set_blk_unitsz(bunit_sz)
+ set_blk_unitsz() {
++ local i
+ do_facet ost1 "for i in /proc/fs/lustre/obdfilter/*/quota_bunit_sz; do
+ echo $(($1 * BLK_SZ)) >> \\\$i;
+ done"
+@@ -95,6 +98,7 @@ set_blk_unitsz() {
+
+ # set_file_tunesz(itune_sz)
+ set_file_tunesz() {
++ local i
+ # set iunit and itune size on all obdfilters
+ do_facet ost1 "for i in /proc/fs/lustre/obdfilter/*/quota_itune_sz; do
+ echo $1 >> \\\$i;
+@@ -107,6 +111,7 @@ set_file_tunesz() {
+
+ # set_file_unitsz(iunit_sz)
+ set_file_unitsz() {
++ local i
+ do_facet ost1 "for i in /proc/fs/lustre/obdfilter/*/quota_iunit_sz; do
+ echo $1 >> \\\$i;
+ done"
+@@ -115,34 +120,6 @@ set_file_unitsz() {
+ 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 tunables
+- 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
+-}
+-
+ RUNAS="runas -u $TSTID"
+ RUNAS2="runas -u $TSTID2"
+ FAIL_ON_ERROR=true check_runas_id $TSTID $RUNAS
+@@ -157,103 +134,173 @@ test_0() {
+
+ $LFS setquota -u $TSTUSR 0 0 0 0 $DIR
+ $LFS setquota -g $TSTUSR 0 0 0 0 $DIR
++ sysctl -w lnet.debug="+quota"
+ }
+ run_test 0 "Set quota ============================="
+
+-# block hard limit (normal use and out of quota)
+-test_1() {
++# test for specific quota limitation, qunit, qtune $1=block_quota_limit
++test_1_sub() {
++ LIMIT=$1
+ chmod 0777 $DIR/$tdir
++ TESTFILE="$DIR/$tdir/$tfile-0"
+
+- LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) * 5)) # 5 bunits each sever
+- TESTFILE=$DIR/$tdir/$tfile-0
+-
+- echo " User quota (limit: $LIMIT kbytes)"
+- $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $DIR
+- $SHOW_QUOTA_USER
+-
+- $LFS setstripe $TESTFILE -c 1
+- chown $TSTUSR.$TSTUSR $TESTFILE
++ # test for user
++ log " User quota (limit: $LIMIT kbytes)"
++ $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $DIR
++ sleep 3
++ $SHOW_QUOTA_USER
+
+- echo " Write ..."
+- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) || error "(usr) write failure, but expect success"
+- echo " Done"
+- echo " Write out of block quota ..."
++ $LFS setstripe $TESTFILE -c 1
++ chown $TSTUSR.$TSTUSR $TESTFILE
++
++ log " Write ..."
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) || error "(usr) write failure, but expect success"
++ log " Done"
++ log " 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)) || true
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) seek=$(($LIMIT/2)) || true
+ # 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 && error "(usr) write success, but expect EDQUOT"
++
++ rm -f $TESTFILE
+ sync; sleep 1; sync;
+- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT && error "(usr) write success, but expect EDQUOT"
++ OST0_UUID=`$LCTL dl | grep -m1 obdfilter | awk '{print $((NF-1))}'`
++ OST0_QUOTA_USED="`$LFS quota -o $OST0_UUID -u $TSTUSR $DIR | awk '/^.*[[:digit:]+][[:space:]+]/ { print $1 }'`"
++ echo $OST0_QUOTA_USED
++ [ $OST0_QUOTA_USED -ne 0 ] && \
++ ($SHOW_QUOTA_USER; error "quota deleted isn't released")
++ $SHOW_QUOTA_USER
++ $LFS setquota -u $TSTUSR 0 0 0 0 $DIR # clear user limit
+
+- rm -f $TESTFILE
+-
+- echo " Group quota (limit: $LIMIT kbytes)"
+- $LFS setquota -u $TSTUSR 0 0 0 0 $DIR # clear user limit
+- $LFS setquota -g $TSTUSR 0 $LIMIT 0 0 $DIR
+- $SHOW_QUOTA_GROUP
+- TESTFILE=$DIR/$tdir/$tfile-1
++ # test for group
++ log "--------------------------------------"
++ log " Group quota (limit: $LIMIT kbytes)"
++ $LFS setquota -g $TSTUSR 0 $LIMIT 0 0 $DIR
++ sleep 3
++ $SHOW_QUOTA_GROUP
++ TESTFILE="$DIR/$tdir/$tfile-1"
+
+- $LFS setstripe $TESTFILE -c 1
+- chown $TSTUSR.$TSTUSR $TESTFILE
++ $LFS setstripe $TESTFILE -c 1
++ chown $TSTUSR.$TSTUSR $TESTFILE
+
+- echo " Write ..."
+- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) || error "(grp) write failure, but expect success"
+- echo " Done"
+- echo " Write out of block quota ..."
++ log " Write ..."
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) || error "(grp) write failure, but expect success"
++ log " Done"
++ log " 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)) || true
+- sync; sleep 1; sync;
+- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT && error "(grp) write success, but expect EDQUOT"
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT/2)) seek=$(($LIMIT/2)) || true
++ sync; sleep 1; sync;
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$LIMIT && error "(grp) write success, but expect EDQUOT"
+
+ # cleanup
+- rm -f $TESTFILE
+- $LFS setquota -g $TSTUSR 0 0 0 0 $DIR
++ rm -f $TESTFILE
++ sync; sleep 1; sync;
++ OST0_UUID=`$LCTL dl | grep -m1 obdfilter | awk '{print $((NF-1))}'`
++ OST0_QUOTA_USED="`$LFS quota -o $OST0_UUID -g $TSTUSR $DIR | awk '/^.*[[:digit:]+][[:space:]+]/ { print $1 }'`"
++ echo $OST0_QUOTA_USED
++ [ $OST0_QUOTA_USED -ne 0 ] && \
++ ($SHOW_QUOTA_USER; error "quota deleted isn't released")
++ $SHOW_QUOTA_GROUP
++ $LFS setquota -g $TSTUSR 0 0 0 0 $DIR # clear group limit
++}
++
++# block hard limit (normal use and out of quota)
++test_1() {
++ for i in `seq 1 $cycle`; do
++ # define blk_qunit is between 1M and 4M
++ blk_qunit=$(( $RANDOM % 3072 + 1024 ))
++ blk_qtune=$(( $RANDOM % $blk_qunit ))
++ # other osts and mds will occupy at 1M blk quota
++ b_limit=$(( ($RANDOM - 16384) / 8 + $OSTCOUNT * $blk_qunit * 4 ))
++ set_blk_tunesz $blk_qtune
++ set_blk_unitsz $blk_qunit
++ echo "cycle: $i(total $cycle) bunit:$blk_qunit, btune:$blk_qtune, blimit:$b_limit"
++ test_1_sub $b_limit
++ echo "=================================================="
++ set_blk_unitsz $((128 * 1024))
++ set_blk_tunesz $((128 * 1024 / 2))
++ done
+ }
+ run_test 1 "Block hard limit (normal use and out of quota) ==="
+
+-# file hard limit (normal use and out of quota)
+-test_2() {
++# test for specific quota limitation, qunit, qtune $1=block_quota_limit
++test_2_sub() {
++ LIMIT=$1
+ chmod 0777 $DIR/$tdir
++ TESTFILE="$DIR/$tdir/$tfile-0"
+
+- LIMIT=$(($IUNIT_SZ * 10)) # 10 iunits on mds
+- TESTFILE=$DIR/$tdir/$tfile-0
+-
+- echo " User quota (limit: $LIMIT files)"
+- $LFS setquota -u $TSTUSR 0 0 0 $LIMIT $DIR
+- $SHOW_QUOTA_USER
++ # test for user
++ log " User quota (limit: $LIMIT files)"
++ $LFS setquota -u $TSTUSR 0 0 0 $LIMIT $DIR
++ sleep 3
++ $SHOW_QUOTA_USER
+
+- echo " Create $LIMIT files ..."
++ log " Create $LIMIT files ..."
+ $RUNAS createmany -m ${TESTFILE} $LIMIT || \
+- error "(usr) create failure, but except success"
+- echo " Done"
+- echo " Create out of file quota ..."
++ error "(usr) create failure, but except success"
++ log " Done"
++ log " Create out of file quota ..."
+ $RUNAS touch ${TESTFILE}_xxx && \
+- error "(usr) touch success, but expect EDQUOT"
++ error "(usr) touch success, but expect EDQUOT"
+
+ unlinkmany ${TESTFILE} $LIMIT
+- rm ${TESTFILE}_xxx
+-
+- echo " Group quota (limit: $LIMIT files)"
+- $LFS setquota -u $TSTUSR 0 0 0 0 $DIR # clear user limit
+- $LFS setquota -g $TSTUSR 0 0 0 $LIMIT $DIR
+- $SHOW_QUOTA_GROUP
+- TESTFILE=$DIR/$tdir/$tfile-1
++ rm -f ${TESTFILE}_xxx
++ sync; sleep 1; sync;
+
+- echo " Create $LIMIT files ..."
+- $RUNAS createmany -m ${TESTFILE} $LIMIT || \
+- error "(grp) create failure, but expect success"
++ MDS_UUID=`$LCTL dl | grep -m1 mds | awk '{print $((NF-1))}'`
++ MDS_QUOTA_USED="`$LFS quota -o $MDS_UUID -u $TSTUSR $DIR | awk '/^.*[[:digit:]+][[:space:]+]/ { print $4 }'`"
++ echo $MDS_QUOTA_USED
++ [ $MDS_QUOTA_USED -ne 0 ] && \
++ ($SHOW_QUOTA_USER; error "quota deleted isn't released")
++ $SHOW_QUOTA_USER
++ $LFS setquota -u $TSTUSR 0 0 0 0 $DIR # clear user limit
+
+- echo " Done"
+- echo " Create out of file quota ..."
+- $RUNAS touch ${TESTFILE}_xxx && \
+- error "(grp) touch success, but expect EDQUOT"
++ # test for group
++ log "--------------------------------------"
++ log " Group quota (limit: $LIMIT FILE)"
++ $LFS setquota -g $TSTUSR 0 0 0 $LIMIT $DIR
++ sleep 3
++ $SHOW_QUOTA_GROUP
++ TESTFILE=$DIR/$tdir/$tfile-1
+
+- $RUNAS touch ${TESTFILE}_xxx > /dev/null 2>&1 && error "(grp) touch success, but expect EDQUOT"
++ log " Create $LIMIT files ..."
++ $RUNAS createmany -m ${TESTFILE} $LIMIT || \
++ error "(usr) create failure, but except success"
++ log " Done"
++ log " Create out of file quota ..."
++ $RUNAS touch ${TESTFILE}_xxx && \
++ error "(usr) touch success, but expect EDQUOT"
+
+- # cleanup
+ unlinkmany ${TESTFILE} $LIMIT
+- rm ${TESTFILE}_xxx
++ rm -f ${TESTFILE}_xxx
++ sync; sleep 1; sync;
+
+- $LFS setquota -g $TSTUSR 0 0 0 0 $DIR
++ MDS_UUID=`$LCTL dl | grep -m1 mds | awk '{print $((NF-1))}'`
++ MDS_QUOTA_USED="`$LFS quota -o $MDS_UUID -g $TSTUSR $DIR | awk '/^.*[[:digit:]+][[:space:]+]/ { print $4 }'`"
++ echo $MDS_QUOTA_USED
++ [ $MDS_QUOTA_USED -ne 0 ] && \
++ ($SHOW_QUOTA_USER; error "quota deleted isn't released")
++ $SHOW_QUOTA_GROUP
++ $LFS setquota -g $TSTUSR 0 0 0 0 $DIR # clear user limit
++}
++
++# file hard limit (normal use and out of quota)
++test_2() {
++ for i in `seq 1 $cycle`; do
++ # define ino_qunit is between 10 and 100
++ ino_qunit=$(( $RANDOM % 90 + 10 ))
++ ino_qtune=$(( $RANDOM % $ino_qunit ))
++ # RANDOM's maxium is 32767
++ i_limit=$(( $RANDOM % 990 + 10 ))
++ set_file_tunesz $ino_qtune
++ set_file_unitsz $ino_qunit
++ echo "cycle: $i(total $cycle) iunit:$ino_qunit, itune:$ino_qtune, ilimit:$i_limit"
++ test_2_sub $i_limit
++ echo "=================================================="
++ set_file_unitsz 5120
++ set_file_tunesz 2560
++ done
+ }
+ run_test 2 "File hard limit (normal use and out of quota) ==="
+
+@@ -279,7 +326,7 @@ test_block_soft() {
+ OFFSET=$((OFFSET + BUNIT_SZ))
+ sync; sleep 1; sync;
+ echo " Done"
+-
++
+ echo " Sleep $TIMER seconds ..."
+ sleep $TIMER
+
+@@ -302,6 +349,7 @@ test_block_soft() {
+
+ echo " Unlink file to stop timer"
+ rm -f $TESTFILE
++ sync; sleep 1; sync
+ echo " Done"
+
+ $SHOW_QUOTA_USER
+@@ -320,7 +368,8 @@ test_block_soft() {
+ test_3() {
+ chmod 0777 $DIR/$tdir
+
+- LIMIT=$(( $BUNIT_SZ * 2 )) # 1 bunit on mds and 1 bunit on the ost
++ # 1 bunit on mds and 1 bunit on every ost
++ LIMIT=$(( $BUNIT_SZ * ($OSTCOUNT + 1) ))
+ GRACE=10
+
+ echo " User quota (soft limit: $LIMIT kbytes grace: $GRACE seconds)"
+@@ -368,23 +417,20 @@ test_file_soft() {
+
+ echo " Sleep $TIMER seconds ..."
+ sleep $TIMER
+-
++
+ $SHOW_QUOTA_USER
+ $SHOW_QUOTA_GROUP
+ $SHOW_QUOTA_INFO
+-
++
+ echo " Create file after timer goes off"
+- $RUNAS createmany -m ${TESTFILE}_after_ $((IUNIT_SZ - 2)) || \
+- error "create ${TESTFILE}_after failure, but expect success"
+- sync; sleep 1; sync
+- $RUNAS touch ${TESTFILE}_after && \
++ $RUNAS touch ${TESTFILE}_after ${TESTFILE}_after1 && \
+ error "create after timer expired, but expect EDQUOT"
+ sync; sleep 1; sync
+
+ $SHOW_QUOTA_USER
+ $SHOW_QUOTA_GROUP
+ $SHOW_QUOTA_INFO
+-
++
+ echo " Unlink files to stop timer"
+ find `dirname $TESTFILE` -name "`basename ${TESTFILE}`*" | xargs rm -f
+ echo " Done"
+@@ -423,7 +469,7 @@ test_4() {
+
+ test_file_soft $TESTFILE $LIMIT $GRACE
+ $LFS setquota -g $TSTUSR 0 0 0 0 $DIR
+-
++
+ # cleanup
+ $LFS setquota -t -u $MAX_DQ_TIME $MAX_IQ_TIME $DIR
+ $LFS setquota -t -g $MAX_DQ_TIME $MAX_IQ_TIME $DIR
+@@ -460,13 +506,13 @@ run_test 4a "Grace time strings handling
+ 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 $DIR
+ $LFS setquota -g $TSTUSR 0 $BLIMIT 0 $ILIMIT $DIR
+ $SHOW_QUOTA_USER
+ $SHOW_QUOTA_GROUP
+-
++
+ echo " Create more than $ILIMIT files and more than $BLIMIT kbytes ..."
+ createmany -m $DIR/$tdir/$tfile-0_ $((ILIMIT + 1)) || \
+ error "touch failure, expect success"
+@@ -498,7 +544,7 @@ test_6() {
+ LIMIT=$((BUNIT_SZ * (OSTCOUNT + 1) * 5)) # 5 bunits per server
+ FILEA="$DIR/$tdir/$tfile-0_a"
+ FILEB="$DIR/$tdir/$tfile-0_b"
+-
++
+ echo " Set block limit $LIMIT kbytes to $TSTUSR.$TSTUSR"
+ $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $DIR
+ $LFS setquota -g $TSTUSR 0 $LIMIT 0 0 $DIR
+@@ -555,18 +601,18 @@ test_7()
+ chmod 0777 $DIR/$tdir
+ remote_mds && skip "remote mds" && return 0
+
+- LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits each sever
++ LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) ))
+ TESTFILE="$DIR/$tdir/$tfile-0"
+-
++
+ $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $DIR
+-
++
+ $LFS setstripe $TESTFILE -c 1
+ chown $TSTUSR.$TSTUSR $TESTFILE
+
+ echo " Write to OST0..."
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ || \
+ error "write failure, but expect success"
+-
++
+ #define OBD_FAIL_OBD_DQACQ 0x604
+ echo 0x604 > /proc/sys/lustre/fail_loc
+ echo " Remove files on OST0"
+@@ -587,7 +633,7 @@ test_7()
+ TOTAL_LIMIT="`$LFS quota -u $TSTUSR $DIR | awk '/^.*'$PATTERN'.*[[:digit:]+][[:space:]+]/ { print $4 }'`"
+ [ $TOTAL_LIMIT -eq $LIMIT ] || error "total limits not recovery!"
+ echo " total limits = $TOTAL_LIMIT"
+-
++
+ OST0_UUID=`do_facet ost1 "$LCTL dl | grep -m1 obdfilter" | awk '{print $((NF-1))}'`
+ [ -z "$OST0_UUID" ] && OST0_UUID=`do_facet ost1 "$LCTL dl | grep -m1 obdfilter" | awk '{print $((NF-1))}'`
+ OST0_LIMIT="`$LFS quota -o $OST0_UUID -u $TSTUSR $DIR | awk '/^.*[[:digit:]+][[:space:]+]/ { print $3 }'`"
+@@ -604,14 +650,13 @@ test_8() {
+ BLK_LIMIT=$((100 * 1024 * 1024)) # 100G
+ FILE_LIMIT=1000000
+ DBENCH_LIB=${DBENCH_LIB:-/usr/lib/dbench}
+-
++
+ [ ! -d $DBENCH_LIB ] && skip "dbench not installed" && return 0
+-
++
+ echo " Set enough high limit for user: $TSTUSR"
+ $LFS setquota -u $TSTUSR 0 $BLK_LIMIT 0 $FILE_LIMIT $DIR
+ echo " Set enough high limit for group: $TSTUSR"
+ $LFS setquota -g $USER 0 $BLK_LIMIT 0 $FILE_LIMIT $DIR
+-
+
+ TGT=$DIR/$tdir/client.txt
+ SRC=${SRC:-$DBENCH_LIB/client.txt}
+@@ -624,7 +669,7 @@ test_8() {
+ cd $DIR/$tdir
+ $RUNAS dbench -c client.txt 3
+ RC=$?
+-
++
+ rm -f client.txt
+ cd $SAVE_PWD
+ return $RC
+@@ -634,71 +679,67 @@ run_test 8 "Run dbench with quota enable
+ # run for fixing bug10707, it needs a big room. test for 64bit
+ KB=1024
+ GB=$((KB * 1024 * 1024))
+-FSIZE=$((OSTCOUNT * 9 / 2))
+ # Use this as dd bs to decrease time
+ # inode->i_blkbits = min(PTLRPC_MAX_BRW_BITS+1, LL_MAX_BLKSIZE_BITS);
+ blksize=$((1 << 21)) # 2Mb
++size_file=$((GB * 9 / 2))
++# this check is just for test9 and test10
++OST0_MIN=4900000 #4.67G
++check_whether_skip () {
++ OST0_SIZE=`$LFS df $DIR | awk '/\[OST:0\]/ {print $4}'`
++ log "OST0_SIZE: $OST0_SIZE required: $OST0_MIN"
++ if [ $OST0_SIZE -lt $OST0_MIN ]; then
++ echo "WARN: OST0 has less than $OST0_MIN free, skip this test."
++ return 0
++ else
++ return 1
++ fi
++}
+
+ test_9() {
+- chmod 0777 $DIR/$tdir
+- lustrefs_size=`(echo 0; df -t lustre -P | awk '{print $4}') | tail -n 1`
+- size_file=$((FSIZE * GB))
+- echo "lustrefs_size:$lustrefs_size size_file:$((size_file / KB))"
+- if [ $((lustrefs_size * KB)) -lt $size_file ]; then
+- skip "less than $size_file bytes free"
+- return 0;
+- fi
++ check_whether_skip && return 0
+
+- set_blk_unitsz $((1024 * 100))
+- set_blk_tunesz $((1024 * 50))
+-
+- # set the D_QUOTA flag
+- debugsave
+- sysctl -w lnet.debug="+quota"
++ set_blk_tunesz 512
++ set_blk_unitsz 1024
+
++ chmod 0777 $DIR/$tdir
+ TESTFILE="$DIR/$tdir/$tfile-0"
+
+ BLK_LIMIT=$((100 * KB * KB)) # 100G
+ FILE_LIMIT=1000000
+
+- echo " Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT) for user: $TSTUSR"
++ log " Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT) for user: $TSTUSR"
+ $LFS setquota -u $TSTUSR 0 $BLK_LIMIT 0 $FILE_LIMIT $DIR
+- echo " Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT) for group: $TSTUSR"
++ log " Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT) for group: $TSTUSR"
+ $LFS setquota -g $TSTUSR 0 $BLK_LIMIT 0 $FILE_LIMIT $DIR
+
+ echo " Set stripe"
+- [ $OSTCOUNT -ge 2 ] && $LFS setstripe $TESTFILE -c $OSTCOUNT
++ $LFS setstripe $TESTFILE -c 1
+ touch $TESTFILE
+ chown $TSTUSR.$TSTUSR $TESTFILE
+
+ $SHOW_QUOTA_USER
+ $SHOW_QUOTA_GROUP
+
+- echo " Write the big file of $FSIZE G ..."
++ log " Write the big file of 4.5G ..."
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$blksize count=$((size_file / blksize)) || \
+- error "(usr) write $FSIZE G file failure, but expect success"
++ error "(usr) write 4.5G file failure, but expect success"
+
+ $SHOW_QUOTA_USER
+ $SHOW_QUOTA_GROUP
+
+- echo " delete the big file of $FSIZE G..."
++ log " delete the big file of 4.5G..."
+ $RUNAS rm -f $TESTFILE
++ sync; sleep 3; sync;
+
+ $SHOW_QUOTA_USER
+ $SHOW_QUOTA_GROUP
+
+- echo " write the big file of 2 G..."
+- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$blksize count=$((2 * GB / blksize)) || \
+- error "(usr) write 2 G file failure, but expect seccess"
+-
+- echo " delete the big file of 2 G..."
+- $RUNAS rm -f $TESTFILE
+ RC=$?
+
+- set_blk_tunesz $BTUNE_SZ
+- set_blk_unitsz $BUNIT_SZ
++ set_blk_unitsz $((128 * 1024))
++ set_blk_tunesz $((128 * 1024 / 2))
+
+- debugrestore
+ wait_delete_completed
+
+ return $RC
+@@ -708,23 +749,13 @@ run_test 9 "run for fixing bug10707(64bi
+ # run for fixing bug10707, it need a big room. test for 32bit
+ test_10() {
+ chmod 0777 $DIR/$tdir
+- lustrefs_size=`(echo 0; df -t lustre -P | awk '{print $4}') | tail -n 1`
+- size_file=$((FSIZE * GB))
+- echo "lustrefs_size:$lustrefs_size size_file:$((size_file / KB))"
+- if [ $((lustrefs_size * KB)) -lt $size_file ]; then
+- skip "less than $size_file bytes free"
+- return 0;
+- fi
++ check_whether_skip && return 0
+
+ sync; sleep 10; sync;
+
+- set_blk_unitsz $((1024 * 100))
+- set_blk_tunesz $((1024 * 50))
++ set_blk_tunesz 512
++ set_blk_unitsz 1024
+
+- # set the D_QUOTA flag
+- debugsave
+- sysctl -w lnet.debug="+quota"
+-
+ # make qd_count 32 bit
+ sysctl -w lustre.fail_loc=0xA00
+
+@@ -733,49 +764,40 @@ test_10() {
+ BLK_LIMIT=$((100 * KB * KB)) # 100G
+ FILE_LIMIT=1000000
+
+- echo " Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT) for user: $TSTUSR"
++ log " Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT) for user: $TSTUSR"
+ $LFS setquota -u $TSTUSR 0 $BLK_LIMIT 0 $FILE_LIMIT $DIR
+- echo " Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT) for group: $TSTUSR"
++ log " Set enough high limit(block:$BLK_LIMIT; file: $FILE_LIMIT) for group: $TSTUSR"
+ $LFS setquota -g $TSTUSR 0 $BLK_LIMIT 0 $FILE_LIMIT $DIR
+-
++
+ echo " Set stripe"
+- [ $OSTCOUNT -ge 2 ] && $LFS setstripe $TESTFILE -c $OSTCOUNT
++ $LFS setstripe $TESTFILE -c 1
+ touch $TESTFILE
+ chown $TSTUSR.$TSTUSR $TESTFILE
+
+ $SHOW_QUOTA_USER
+ $SHOW_QUOTA_GROUP
+
+- echo " Write the big file of $FSIZE G ..."
++ log " Write the big file of 4.5 G ..."
+ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$blksize count=$((size_file / blksize)) || \
+- error "(usr) write $FSIZE G file failure, but expect success"
+-
++ error "(usr) write 4.5 G file failure, but expect success"
++
+ $SHOW_QUOTA_USER
+ $SHOW_QUOTA_GROUP
+
+- echo " delete the big file of $FSIZE G..."
+- $RUNAS rm -f $TESTFILE
++ log " delete the big file of 4.5 G..."
++ $RUNAS rm -f $TESTFILE
++ sync; sleep 3; sync;
+
+ $SHOW_QUOTA_USER
+ $SHOW_QUOTA_GROUP
+
+- echo " write the big file of 2 G..."
+- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$blksize count=$((2 * GB / blksize)) || \
+- error "(usr) write 2 G file failure, but expect success"
+-
+- echo " delete the big file of 2 G..."
+- $RUNAS rm -f $TESTFILE
+-
+ RC=$?
+
+- # clear the flage
+- debugrestore
+-
+ # make qd_count 64 bit
+ sysctl -w lustre.fail_loc=0
+
+- set_blk_tunesz $BTUNE_SZ
+- set_blk_unitsz $BUNIT_SZ
++ set_blk_unitsz $((128 * 1024))
++ set_blk_tunesz $((128 * 1024 / 2))
+
+ wait_delete_completed
+
+@@ -859,24 +881,23 @@ test_12() {
+ LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) * 10)) # 10 bunits each sever
+ TESTFILE="$DIR/$tdir/$tfile-0"
+ TESTFILE2="$DIR2/$tdir/$tfile-1"
+-
++
+ echo " User quota (limit: $LIMIT kbytes)"
+ $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $DIR
+
+- $LFS setstripe $TESTFILE -i 0 -c 1
++ $LFS setstripe $TESTFILE -i 0 -c 1
+ chown $TSTUSR.$TSTUSR $TESTFILE
+ $LFS setstripe $TESTFILE2 -i 0 -c 1
+ chown $TSTUSR2.$TSTUSR2 $TESTFILE2
+
+ #define OBD_FAIL_OST_HOLD_WRITE_RPC 0x21f
+- sysctl -w lustre.fail_loc=0x0000021f
++ sysctl -w lustre.fail_loc=0x0000021f
+
+ echo " step1: write out of block quota ..."
+- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT*2)) &
+- DDPID=$!
+- sleep 5
+- $RUNAS2 dd if=/dev/zero of=$TESTFILE2 bs=$BLK_SZ count=102400 &
++ $RUNAS2 dd if=/dev/zero of=$TESTFILE2 bs=$BLK_SZ count=102400 &
+ DDPID1=$!
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(($LIMIT*2)) &
++ DDPID=$!
+
+ echo " step2: testing ......"
+ count=0
+@@ -888,7 +909,7 @@ test_12() {
+ error "dd should be finished!"
+ fi
+ sleep 1
+- done
++ done
+ echo "(dd_pid=$DDPID1, time=$count)successful"
+
+ #Recover fail_loc and dd will finish soon
+@@ -903,25 +924,28 @@ test_12() {
+ error "dd should be finished!"
+ fi
+ sleep 1
+- done
++ done
+ echo "(dd_pid=$DDPID, time=$count)successful"
+
+ rm -f $TESTFILE $TESTFILE2
+-
++ sync; sleep 3; sync;
++
+ $LFS setquota -u $TSTUSR 0 0 0 0 $DIR # clear user limit
+ }
+ run_test 12 "test a deadlock between quota and journal ==="
+
+ # test multiple clients write block quota b=11693
+ test_13() {
++ wait_delete_completed
++
+ # one OST * 10 + (mds + other OSTs)
+ LIMIT=$((BUNIT_SZ * 10 + (BUNIT_SZ * OSTCOUNT)))
+ TESTFILE="$DIR/$tdir/$tfile"
+-
++
+ echo " User quota (limit: $LIMIT kbytes)"
+ $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $DIR
+ $SHOW_QUOTA_USER
+-
++
+ $LFS setstripe $TESTFILE -i 0 -c 1
+ chown $TSTUSR.$TSTUSR $TESTFILE
+ $LFS setstripe $TESTFILE.2 -i 0 -c 1
+@@ -929,9 +953,9 @@ test_13() {
+
+ echo " step1: write out of block quota ..."
+ # one bunit will give mds
+- $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$[($LIMIT - $BUNIT_SZ) / 2] &
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$[($LIMIT - $BUNIT_SZ) / 2] &
+ DDPID=$!
+- $RUNAS dd if=/dev/zero of=$TESTFILE.2 bs=$BLK_SZ count=$[($LIMIT - $BUNIT_SZ) / 2] &
++ $RUNAS dd if=/dev/zero of=$TESTFILE.2 bs=$BLK_SZ count=$[($LIMIT - $BUNIT_SZ) / 2] &
+ DDPID1=$!
+
+ echo " step2: testing ......"
+@@ -943,7 +967,7 @@ test_13() {
+ error "dd should be finished!"
+ fi
+ sleep 1
+- done
++ done
+ echo "(dd_pid=$DDPID, time=$count)successful"
+
+ count=0
+@@ -954,7 +978,7 @@ test_13() {
+ error "dd should be finished!"
+ fi
+ sleep 1
+- done
++ done
+ echo "(dd_pid=$DDPID1, time=$count)successful"
+
+ sync; sleep 5; sync;
+@@ -967,7 +991,7 @@ test_13() {
+ error "files too small $fz + $fz2 < $((BUNIT_SZ * BLK_SZ * 10))"
+
+ rm -f $TESTFILE $TESTFILE.2
+-
++
+ $LFS setquota -u $TSTUSR 0 0 0 0 $DIR # clear user limit
+ }
+ run_test 13 "test multiple clients write block quota ==="
+@@ -981,7 +1005,7 @@ check_if_quota_zero(){
+ field="3 5"
+ fi
+ for j in $field; do
+- tmp=`$LFS quota -$1 $2 $DIR | sed -n ${i}p |
++ tmp=`$LFS quota -$1 $2 $DIR | sed -n ${i}p |
+ awk '{print $'"$j"'}'`
+ [ -n "$tmp" ] && [ $tmp -ne 0 ] && $LFS quota -$1 $2 $DIR && \
+ error "quota on $2 isn't clean"
+@@ -992,13 +1016,12 @@ check_if_quota_zero(){
+
+ pre_test_14 () {
+ # reboot the lustre
++ sync; sleep 5; sync
+ cd $T_PWD; sh llmountcleanup.sh || error "llmountcleanup failed"
+ sh llmount.sh
+- pre_test
+ run_test 0 "reboot lustre"
+ }
+-
+-pre_test_14
++pre_test_14
+
+ test_14(){ # b=12223 -- setting quota on root
+ TESTFILE="$DIR/$tdir/$tfile"
+@@ -1011,19 +1034,19 @@ test_14(){ # b=12223 -- setting quota on
+ error "unexpected: user(root) write files failly!"
+ chmod 666 $TESTFILE
+ $RUNAS dd if=/dev/zero of=${TESTFILE} seek=4096 bs=4k count=4096 && \
+- error "unexpected: user(quota_usr) write a file successfully!"
++ error "unexpected: user(quota_usr) write a file successfully!"
+
+ # trigger the llog
+ chmod 777 $DIR
+- for i in `seq 1 10`; do $RUNAS touch ${TESTFILE}a_$i; done
+- for i in `seq 1 10`; do $RUNAS rm -f ${TESTFILE}a_$i; done
++ for i in `seq 1 10`; do $RUNAS touch ${TESTFILE}a_$i; done
++ for i in `seq 1 10`; do $RUNAS rm -f ${TESTFILE}a_$i; done
+
+ # do the check
+- dmesg | tail | grep "\-122" |grep llog_obd_origin_add && error "err -122 not found in dmesg"
++ dmesg | tail | grep "\-122" |grep llog_obd_origin_add && error "err -122 not found in dmesg"
+ $LFS setquota -u root 0 0 0 0 $DIR
+ #check_if_quota_zero u root
+
+- # clean
++ # clean
+ unlinkmany ${TESTFILE} 15
+ rm -f $TESTFILE
+ }
+@@ -1102,10 +1125,123 @@ test_15(){
+ }
+ run_test 15 "set block quota more than 4T ==="
+
++# $1=u/g $2=with qunit adjust or not
++test_16_tub() {
++ LIMIT=$(( $BUNIT_SZ * $(($OSTCOUNT + 1)) * 4))
++ TESTFILE="$DIR/$tdir/$tfile"
++
++ echo " User quota (limit: $LIMIT kbytes)"
++ if [ $1 == "u" ]; then
++ $LFS setquota -u $TSTUSR 0 $LIMIT 0 0 $DIR
++ $SHOW_QUOTA_USER
++ else
++ $LFS setquota -g $TSTUSR 0 $LIMIT 0 0 $DIR
++ $SHOW_QUOTA_GROUP
++ fi
++
++ $LFS setstripe $TESTFILE -c 1
++ chown $TSTUSR.$TSTUSR $TESTFILE
++
++ echo " Write ..."
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$((BUNIT_SZ * 4)) || \
++ 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=$BUNIT_SZ seek=$((BUNIT_SZ * 4)) || true
++ # flush cache, ensure noquota flag is setted on client
++ sync; sleep 1; sync;
++ if [ $2 -eq 1 ]; then
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$((BUNIT_SZ * 4)) || \
++ error "(write failure, but expect success"
++ else
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$BUNIT_SZ seek=$((BUNIT_SZ * 4)) && \
++ error "(write success, but expect EDQUOT"
++ fi
++
++ rm -f $TESTFILE
++ $LFS setquota -$1 $TSTUSR 0 0 0 0 $DIR
++}
++
++# test without adjusting qunit
++test_16 () {
++ set_blk_tunesz $((BUNIT_SZ * 2))
++ set_blk_unitsz $((BUNIT_SZ * 4))
++ for i in u g; do
++ for j in 0 1; do
++ # define OBD_FAIL_QUOTA_WITHOUT_CHANGE_QS 0xA01
++ echo " grp/usr: $i, adjust qunit: $j"
++ echo "-------------------------------"
++ [ $j -eq 1 ] && sysctl -w lustre.fail_loc=0
++ [ $j -eq 0 ] && sysctl -w lustre.fail_loc=0xA01
++ test_16_tub $i $j
++ done
++ done
++ set_blk_unitsz $((128 * 1024))
++ set_blk_tunesz $((128 * 1024 / 2))
++}
++run_test 16 "test without adjusting qunit"
++
++# run for fixing bug14526, failed returned quota reqs shouldn't ruin lustre.
++test_17() {
++ set_blk_tunesz 512
++ set_blk_unitsz 1024
++
++ #define OBD_FAIL_QUOTA_RET_QDATA | OBD_FAIL_ONCE
++ sysctl -w lustre.fail_loc=0x80000A02
++
++ TESTFILE="$DIR/$tdir/$tfile-a"
++ TESTFILE2="$DIR/$tdir/$tfile-b"
++
++ BLK_LIMIT=$((100 * 1024)) # 100M
++
++ log " Set enough high limit(block:$BLK_LIMIT) for user: $TSTUSR"
++ $LFS setquota -u $TSTUSR 0 $BLK_LIMIT 0 0 $DIR
++ log " Set enough high limit(block:$BLK_LIMIT) for group: $TSTUSR"
++ $LFS setquota -g $TSTUSR 0 $BLK_LIMIT 0 0 $DIR
++
++ touch $TESTFILE
++ chown $TSTUSR.$TSTUSR $TESTFILE
++ touch $TESTFILE2
++ chown $TSTUSR.$TSTUSR $TESTFILE2
++
++ $SHOW_QUOTA_USER
++ $SHOW_QUOTA_GROUP
++
++ log " Write the test file1 ..."
++ $RUNAS dd if=/dev/zero of=$TESTFILE bs=$BLK_SZ count=$(( 10 * 1024 )) \
++ || echo "write 10M file failure"
++
++ $SHOW_QUOTA_USER
++ $SHOW_QUOTA_GROUP
++
++ log " write the test file2 ..."
++ $RUNAS dd if=/dev/zero of=$TESTFILE2 bs=$BLK_SZ count=$(( 10 * 1024 )) \
++ || error "write 10M file failure"
++
++ $SHOW_QUOTA_USER
++ $SHOW_QUOTA_GROUP
++
++ rm -f $TESTFILE $TESTFILE2
++ RC=$?
++ sync; sleep 3; sync;
++
++ # make qd_count 64 bit
++ sysctl -w lustre.fail_loc=0
++
++ set_blk_unitsz $((128 * 1024))
++ set_blk_tunesz $((128 * 1024 / 2))
++
++ return $RC
++}
++run_test 17 "run for fixing bug14526 ==========="
++
+ # turn off quota
+ test_99()
+ {
+ $LFS quotaoff $DIR
++ sysctl -w lnet.debug="-quota"
++
+ return 0
+ }
+ run_test 99 "Quota off ==============================="
+@@ -1113,7 +1249,6 @@ run_test 99 "Quota off =================
+
+ log "cleanup: ======================================================"
+ cd $ORIG_PWD
+-post_test
+ check_and_cleanup_lustre
+ echo '=========================== finished ==============================='
+ [ -f "$QUOTALOG" ] && cat $QUOTALOG && grep -q FAIL $QUOTALOG && exit 1 || true
+Index: lustre/utils/wirecheck.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/utils/wirecheck.c,v
+retrieving revision 1.30.34.11
+diff -p -u -r1.30.34.11 wirecheck.c
+--- lustre/utils/wirecheck.c 9 Jan 2008 20:01:16 -0000 1.30.34.11
++++ lustre/utils/wirecheck.c 18 Jan 2008 05:51:54 -0000
+@@ -975,6 +975,18 @@ check_qunit_data(void)
+ CHECK_MEMBER(qunit_data, qd_id);
+ CHECK_MEMBER(qunit_data, qd_flags);
+ CHECK_MEMBER(qunit_data, qd_count);
++ CHECK_MEMBER(qunit_data, qd_qunit);
++ CHECK_MEMBER(qunit_data, padding );
++}
++
++static void
++check_qunit_data_old2(void)
++{
++ BLANK_LINE();
++ CHECK_STRUCT(qunit_data_old2);
++ CHECK_MEMBER(qunit_data_old2, qd_id);
++ CHECK_MEMBER(qunit_data_old2, qd_flags);
++ CHECK_MEMBER(qunit_data_old2, qd_count);
+ }
+
+ static void
+@@ -1048,6 +1060,17 @@ check_posix_acl_xattr_header(void)
+ #endif
+
+ static void
++check_quota_adjust_qunit(void)
++{
++ BLANK_LINE();
++ CHECK_STRUCT(quota_adjust_qunit);
++ CHECK_MEMBER(quota_adjust_qunit, qaq_flags);
++ CHECK_MEMBER(quota_adjust_qunit, qaq_id);
++ CHECK_MEMBER(quota_adjust_qunit, qaq_bunit_sz);
++ CHECK_MEMBER(quota_adjust_qunit, qaq_iunit_sz);
++}
++
++static void
+ system_string (char *cmdline, char *str, int len)
+ {
+ int fds[2];
+@@ -1152,6 +1175,7 @@ main(int argc, char **argv)
+ CHECK_VALUE(OST_SYNC);
+ CHECK_VALUE(OST_QUOTACHECK);
+ CHECK_VALUE(OST_QUOTACTL);
++ CHECK_VALUE(OST_QUOTA_ADJUST_QUNIT);
+ CHECK_VALUE(OST_LAST_OPC);
+
+ CHECK_DEFINE(OBD_OBJECT_EOF);
+@@ -1293,7 +1317,9 @@ main(int argc, char **argv)
+ check_llog_array_rec();
+ check_mds_extent_desc();
+ check_qunit_data();
++ check_qunit_data_old2();
+ check_qunit_data_old();
++ check_quota_adjust_qunit();
+ check_mgs_target_info();
+ check_lustre_disk_data();
+ #ifdef LIBLUSTRE_POSIX_ACL
+Index: lustre/utils/wiretest.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/utils/wiretest.c,v
+retrieving revision 1.31.34.10
+diff -p -u -r1.31.34.10 wiretest.c
+--- lustre/utils/wiretest.c 9 Jan 2008 20:01:18 -0000 1.31.34.10
++++ lustre/utils/wiretest.c 18 Jan 2008 05:51:55 -0000
+@@ -93,7 +93,9 @@ void lustre_assert_wire_constants(void)
+ (long long)OST_QUOTACHECK);
+ LASSERTF(OST_QUOTACTL == 19, " found %lld\n",
+ (long long)OST_QUOTACTL);
+- LASSERTF(OST_LAST_OPC == 20, " found %lld\n",
++ LASSERTF(OST_QUOTA_ADJUST_QUNIT == 20, " found %lld\n",
++ (long long)OST_QUOTA_ADJUST_QUNIT);
++ LASSERTF(OST_LAST_OPC == 21, " found %lld\n",
+ (long long)OST_LAST_OPC);
+ LASSERTF(OBD_OBJECT_EOF == 0xffffffffffffffffULL," found %lld\n",
+ (long long)OBD_OBJECT_EOF);
+@@ -2003,7 +2005,7 @@ void lustre_assert_wire_constants(void)
+ (long long)(int)sizeof(((struct mds_extent_desc *)0)->med_lmm));
+
+ /* Checks for struct qunit_data */
+- LASSERTF((int)sizeof(struct qunit_data) == 16, " found %lld\n",
++ LASSERTF((int)sizeof(struct qunit_data) == 32, " found %lld\n",
+ (long long)(int)sizeof(struct qunit_data));
+ LASSERTF((int)offsetof(struct qunit_data, qd_id) == 0, " found %lld\n",
+ (long long)(int)offsetof(struct qunit_data, qd_id));
+@@ -2017,6 +2019,30 @@ void lustre_assert_wire_constants(void)
+ (long long)(int)offsetof(struct qunit_data, qd_count));
+ LASSERTF((int)sizeof(((struct qunit_data *)0)->qd_count) == 8, " found %lld\n",
+ (long long)(int)sizeof(((struct qunit_data *)0)->qd_count));
++ LASSERTF((int)offsetof(struct qunit_data, qd_qunit) == 16, " found %lld\n",
++ (long long)(int)offsetof(struct qunit_data, qd_qunit));
++ LASSERTF((int)sizeof(((struct qunit_data *)0)->qd_qunit) == 8, " found %lld\n",
++ (long long)(int)sizeof(((struct qunit_data *)0)->qd_qunit));
++ LASSERTF((int)offsetof(struct qunit_data, padding) == 24, " found %lld\n",
++ (long long)(int)offsetof(struct qunit_data, padding));
++ LASSERTF((int)sizeof(((struct qunit_data *)0)->padding) == 8, " found %lld\n",
++ (long long)(int)sizeof(((struct qunit_data *)0)->padding));
++
++ /* Checks for struct qunit_data_old2 */
++ LASSERTF((int)sizeof(struct qunit_data_old2) == 16, " found %lld\n",
++ (long long)(int)sizeof(struct qunit_data_old2));
++ LASSERTF((int)offsetof(struct qunit_data_old2, qd_id) == 0, " found %lld\n",
++ (long long)(int)offsetof(struct qunit_data_old2, qd_id));
++ LASSERTF((int)sizeof(((struct qunit_data_old2 *)0)->qd_id) == 4, " found %lld\n",
++ (long long)(int)sizeof(((struct qunit_data_old2 *)0)->qd_id));
++ LASSERTF((int)offsetof(struct qunit_data_old2, qd_flags) == 4, " found %lld\n",
++ (long long)(int)offsetof(struct qunit_data_old2, qd_flags));
++ LASSERTF((int)sizeof(((struct qunit_data_old2 *)0)->qd_flags) == 4, " found %lld\n",
++ (long long)(int)sizeof(((struct qunit_data_old2 *)0)->qd_flags));
++ LASSERTF((int)offsetof(struct qunit_data_old2, qd_count) == 8, " found %lld\n",
++ (long long)(int)offsetof(struct qunit_data_old2, qd_count));
++ LASSERTF((int)sizeof(((struct qunit_data_old2 *)0)->qd_count) == 8, " found %lld\n",
++ (long long)(int)sizeof(((struct qunit_data_old2 *)0)->qd_count));
+
+ /* Checks for struct qunit_data_old */
+ LASSERTF((int)sizeof(struct qunit_data_old) == 16, " found %lld\n",
+@@ -2038,6 +2064,26 @@ void lustre_assert_wire_constants(void)
+ LASSERTF((int)sizeof(((struct qunit_data_old *)0)->qd_isblk) == 4, " found %lld\n",
+ (long long)(int)sizeof(((struct qunit_data_old *)0)->qd_isblk));
+
++ /* Checks for struct quota_adjust_qunit */
++ LASSERTF((int)sizeof(struct quota_adjust_qunit) == 32, " found %lld\n",
++ (long long)(int)sizeof(struct quota_adjust_qunit));
++ LASSERTF((int)offsetof(struct quota_adjust_qunit, qaq_flags) == 0, " found %lld\n",
++ (long long)(int)offsetof(struct quota_adjust_qunit, qaq_flags));
++ LASSERTF((int)sizeof(((struct quota_adjust_qunit *)0)->qaq_flags) == 4, " found %lld\n",
++ (long long)(int)sizeof(((struct quota_adjust_qunit *)0)->qaq_flags));
++ LASSERTF((int)offsetof(struct quota_adjust_qunit, qaq_id) == 4, " found %lld\n",
++ (long long)(int)offsetof(struct quota_adjust_qunit, qaq_id));
++ LASSERTF((int)sizeof(((struct quota_adjust_qunit *)0)->qaq_id) == 4, " found %lld\n",
++ (long long)(int)sizeof(((struct quota_adjust_qunit *)0)->qaq_id));
++ LASSERTF((int)offsetof(struct quota_adjust_qunit, qaq_bunit_sz) == 8, " found %lld\n",
++ (long long)(int)offsetof(struct quota_adjust_qunit, qaq_bunit_sz));
++ LASSERTF((int)sizeof(((struct quota_adjust_qunit *)0)->qaq_bunit_sz) == 8, " found %lld\n",
++ (long long)(int)sizeof(((struct quota_adjust_qunit *)0)->qaq_bunit_sz));
++ LASSERTF((int)offsetof(struct quota_adjust_qunit, qaq_iunit_sz) == 16, " found %lld\n",
++ (long long)(int)offsetof(struct quota_adjust_qunit, qaq_iunit_sz));
++ LASSERTF((int)sizeof(((struct quota_adjust_qunit *)0)->qaq_iunit_sz) == 8, " found %lld\n",
++ (long long)(int)sizeof(((struct quota_adjust_qunit *)0)->qaq_iunit_sz));
++
+ /* Checks for struct mgs_target_info */
+ LASSERTF((int)sizeof(struct mgs_target_info) == 4544, " found %lld\n",
+ (long long)(int)sizeof(struct mgs_target_info));
Added: trunk/debian/patches/bug14619-broken-qunit-allock.dpatch
URL: http://svn.debian.org/wsvn/pkg-lustre/trunk/debian/patches/bug14619-broken-qunit-allock.dpatch?rev=427&op=file
==============================================================================
--- trunk/debian/patches/bug14619-broken-qunit-allock.dpatch (added)
+++ trunk/debian/patches/bug14619-broken-qunit-allock.dpatch Thu Jan 24 13:12:06 2008
@@ -1,0 +1,34 @@
+#! /bin/sh /usr/share/dpatch/dpatch-run
+## bug14619-broken-qunit-allock.dpatch by Patrick Winnertz <winnie at debian.org>
+##
+## All lines beginning with `## DP:' are a description of the patch.
+## DP: Patch from upstream bugzilla (bug 14619)
+
+ at DPATCH@
+Index: quota_master.c
+===================================================================
+RCS file: /cvsroot/cfs/lustre-core/quota/quota_master.c,v
+retrieving revision 1.2.34.6
+diff -p -u -r1.2.34.6 quota_master.c
+--- quota_master.c 25 Dec 2007 19:15:24 -0000 1.2.34.6
++++ quota_master.c 21 Jan 2008 18:40:39 -0000
+@@ -968,6 +968,9 @@ int mds_set_dqblk(struct obd_device *obd
+ up(&mds->mds_qonoff_sem);
+ if (dqblk->dqb_valid & QIF_ILIMITS) {
+ set = !(ihardlimit || isoftlimit);
++ down(&dquot->dq_sem);
++ dquot->dq_dqb.dqb_curinodes = 0;
++ up(&dquot->dq_sem);
+ rc = mds_init_slave_ilimits(obd, oqctl, set);
+ if (rc) {
+ CERROR("init slave ilimits failed! (rc:%d)\n", rc);
+@@ -977,6 +980,9 @@ int mds_set_dqblk(struct obd_device *obd
+
+ if (dqblk->dqb_valid & QIF_BLIMITS) {
+ set = !(bhardlimit || bsoftlimit);
++ down(&dquot->dq_sem);
++ dquot->dq_dqb.dqb_curspace = 0;
++ up(&dquot->dq_sem);
+ rc = mds_init_slave_blimits(obd, oqctl, set);
+ if (rc) {
+ CERROR("init slave blimits failed! (rc:%d)\n", rc);
More information about the Pkg-lustre-svn-commit
mailing list