int cmd);
int (* fs_qids)(struct file *file, struct inode *inode, int type,
struct list_head *list);
+ int (* fs_get_mblk)(struct super_block *sb, int *count,
+ struct inode *inode, int frags);
int (* fs_dquot)(struct lustre_dquot *dquot, int cmd);
lvfs_sbdev_type (* fs_journal_sbdev)(struct super_block *sb);
};
return -ENOTSUPP;
}
+static inline int fsfilt_get_mblk(struct obd_device *obd,
+ struct super_block *sb, int *count,
+ struct inode *inode, int frags)
+{
+ if (obd->obd_fsops->fs_get_mblk)
+ return obd->obd_fsops->fs_get_mblk(sb, count, inode, frags);
+ return -ENOTSUPP;
+}
+
static inline int fsfilt_map_inode_pages(struct obd_device *obd,
struct inode *inode,
struct page **page, int pages,
#define QUOTA_RET_NOQUOTA 1 /**< not support quota */
#define QUOTA_RET_NOLIMIT 2 /**< quota limit isn't set */
#define QUOTA_RET_ACQUOTA 4 /**< need to acquire extra quota */
-#define QUOTA_RET_INC_PENDING 8 /**< pending value is increased */
/* security opcodes */
typedef enum {
*/
int (*quota_getflag) (struct obd_device *, struct obdo *);
+#ifdef __KERNEL__
/**
* For quota slave, acquire/release quota from master if needed
*/
*/
int (*quota_chkquota) (struct obd_device *, unsigned int, unsigned int,
int, int *, quota_acquire,
- struct obd_trans_info *, int);
+ struct obd_trans_info *, int, struct inode *,
+ int);
+
+ /**
+ * For quota client, the actions after the pending write is committed
+ */
+ int (*quota_pending_commit) (struct obd_device *, unsigned int,
+ unsigned int, int, int);
+#endif
/**
* For quota client, poll if the quota check done
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, int);
-
- /**
* For quota client, set over quota flag for specifed uid/gid
*/
int (*quota_setdq) (struct client_obd *, unsigned int, unsigned int,
RETURN(rc);
}
+#ifdef __KERNEL__
static inline int lquota_chkquota(quota_interface_t *interface,
struct obd_device *obd,
unsigned int uid, unsigned int gid, int count,
int *flag, struct obd_trans_info *oti,
- int isblk)
+ int isblk, struct inode *inode, int frags)
{
int rc;
ENTRY;
QUOTA_CHECK_OP(interface, acquire);
rc = QUOTA_OP(interface, chkquota)(obd, uid, gid, count, flag,
QUOTA_OP(interface, acquire), oti,
- isblk);
+ isblk, inode, frags);
RETURN(rc);
}
static inline int lquota_pending_commit(quota_interface_t *interface,
struct obd_device *obd,
unsigned int uid, unsigned int gid,
- int npage, int isblk)
+ int pending, int isblk)
{
int rc;
ENTRY;
QUOTA_CHECK_OP(interface, pending_commit);
- rc = QUOTA_OP(interface, pending_commit)(obd, uid, gid, npage, isblk);
+ rc = QUOTA_OP(interface, pending_commit)(obd, uid, gid, pending, isblk);
RETURN(rc);
}
+#endif
#ifndef __KERNEL__
extern quota_interface_t osc_quota_interface;
}
RETURN(rc);
}
+
+static int fsfilt_ext3_get_mblk(struct super_block *sb, int *count,
+ struct inode *inode, int frags)
+{
+ /* for an ost_write request, it needs <#fragments> * <tree depth + 1>
+ * metablocks at maxium b=16542 */
+ *count = frags * (EXT_DEPTH(inode) + 1) * EXT3_BLOCK_SIZE(sb);
+ return 0;
+}
+
#endif
lvfs_sbdev_type fsfilt_ext3_journal_sbdev(struct super_block *sb)
.fs_quotainfo = fsfilt_ext3_quotainfo,
.fs_qids = fsfilt_ext3_qids,
.fs_dquot = fsfilt_ext3_dquot,
+ .fs_get_mblk = fsfilt_ext3_get_mblk,
#endif
.fs_journal_sbdev = fsfilt_ext3_journal_sbdev,
};
/* get block quota for parent */
lquota_chkquota(mds_quota_interface_ref, obd,
qids[USRQUOTA], qids[GRPQUOTA], 1,
- &rec_pending, NULL, LQUOTA_FLAGS_BLK);
+ &rec_pending, NULL, LQUOTA_FLAGS_BLK,
+ NULL, 0);
}
}
#endif
if (rec_pending)
lquota_pending_commit(mds_quota_interface_ref, obd,
qids[USRQUOTA], qids[GRPQUOTA],
- 1, 1);
+ rec_pending, 1);
/* Trigger dqacq for the parent owner. If failed,
* the next call for lquota_chkquota will process it. */
lquota_adjust(mds_quota_interface_ref, obd, 0, qids, rc,
lquota_chkquota(mds_quota_interface_ref, obd,
qids[USRQUOTA], qids[GRPQUOTA],
1, &rec_pending, NULL,
- LQUOTA_FLAGS_BLK);
+ LQUOTA_FLAGS_BLK, NULL, 0);
}
} else {
uc->mu_cap |= CFS_CAP_SYS_RESOURCE_MASK;
if (rec_pending)
lquota_pending_commit(mds_quota_interface_ref,
obd, qids[USRQUOTA],
- qids[GRPQUOTA], 1, 1);
+ qids[GRPQUOTA],
+ rec_pending, 1);
/* Trigger dqacq for the parent owner. If failed,
* the next call for lquota_chkquota will process it*/
lquota_adjust(mds_quota_interface_ref, obd, 0, qids,
/* get block quota for target parent */
lquota_chkquota(mds_quota_interface_ref, obd,
qpids[USRQUOTA], qpids[GRPQUOTA], 1,
- &rec_pending, NULL, LQUOTA_FLAGS_BLK);
+ &rec_pending, NULL, LQUOTA_FLAGS_BLK,
+ NULL, 0);
}
}
#endif
lquota_pending_commit(mds_quota_interface_ref, obd,
qpids[USRQUOTA],
qpids[GRPQUOTA],
- 1, 1);
+ rec_pending, 1);
if (quota_opc)
/* Trigger dqrel/dqacq on the target owner of child and
* parent. If failed, the next call for lquota_chkquota
/* get file quota for child */
lquota_chkquota(mds_quota_interface_ref, obd,
qcids[USRQUOTA], qcids[GRPQUOTA], 1,
- &inode_pending, NULL, 0);
+ &inode_pending, NULL, 0, NULL, 0);
switch (ma->ma_attr.la_mode & S_IFMT) {
case S_IFLNK:
case S_IFDIR:
qcids[USRQUOTA], qcids[GRPQUOTA],
block_count,
&block_pending, NULL,
- LQUOTA_FLAGS_BLK);
+ LQUOTA_FLAGS_BLK, NULL, 0);
if (!same)
lquota_chkquota(mds_quota_interface_ref, obd,
qpids[USRQUOTA], qpids[GRPQUOTA], 1,
&parent_pending, NULL,
- LQUOTA_FLAGS_BLK);
+ LQUOTA_FLAGS_BLK, NULL, 0);
}
}
#endif
if (inode_pending)
lquota_pending_commit(mds_quota_interface_ref, obd,
qcids[USRQUOTA], qcids[GRPQUOTA],
- 1, 0);
+ inode_pending, 0);
if (block_pending)
lquota_pending_commit(mds_quota_interface_ref, obd,
qcids[USRQUOTA], qcids[GRPQUOTA],
- block_count, 1);
+ block_pending, 1);
if (parent_pending)
lquota_pending_commit(mds_quota_interface_ref, obd,
qpids[USRQUOTA], qpids[GRPQUOTA],
- 1, 1);
+ parent_pending, 1);
/* Trigger dqacq on the owner of child and parent. If failed,
* the next call for lquota_chkquota will process it. */
lquota_adjust(mds_quota_interface_ref, obd, qcids, qpids, rc,
obd, qtpids[USRQUOTA],
qtpids[GRPQUOTA], 1,
&rec_pending, NULL,
- LQUOTA_FLAGS_BLK);
+ LQUOTA_FLAGS_BLK,
+ NULL, 0);
}
}
}
lquota_pending_commit(mds_quota_interface_ref, obd,
qtpids[USRQUOTA],
qtpids[GRPQUOTA],
- 1, 1);
+ rec_pending, 1);
/* Trigger dqrel on the source owner of parent.
* If failed, the next call for lquota_chkquota will
* process it. */
/* get file quota for new owner */
lquota_chkquota(mds_quota_interface_ref, obd,
qnids[USRQUOTA], qnids[GRPQUOTA], 1,
- &inode_pending, NULL, 0);
+ &inode_pending, NULL, 0, NULL, 0);
block_count = (la_tmp->la_blocks + 7) >> 3;
if (block_count)
/* get block quota for new owner */
qnids[USRQUOTA],
qnids[GRPQUOTA],
block_count, &block_pending,
- NULL, LQUOTA_FLAGS_BLK);
+ NULL, LQUOTA_FLAGS_BLK,
+ NULL, 0);
}
}
#endif
if (inode_pending)
lquota_pending_commit(mds_quota_interface_ref, obd,
qnids[USRQUOTA], qnids[GRPQUOTA],
- 1, 0);
+ inode_pending, 0);
if (block_pending)
lquota_pending_commit(mds_quota_interface_ref, obd,
qnids[USRQUOTA], qnids[GRPQUOTA],
- block_count, 1);
+ block_pending, 1);
/* Trigger dqrel/dqacq for original owner and new owner.
* If failed, the next call for lquota_chkquota will
* process it. */
mdd_quota_wrapper(&ma->ma_attr, qids);
/* get file quota for child */
lquota_chkquota(mds_quota_interface_ref, obd, qids[USRQUOTA],
- qids[GRPQUOTA], 1, &inode_pending, NULL, 0);
+ qids[GRPQUOTA], 1, &inode_pending, NULL, 0,
+ NULL, 0);
switch (ma->ma_attr.la_mode & S_IFMT) {
case S_IFLNK:
case S_IFDIR:
lquota_chkquota(mds_quota_interface_ref, obd,
qids[USRQUOTA], qids[GRPQUOTA],
block_count, &block_pending, NULL,
- LQUOTA_FLAGS_BLK);
+ LQUOTA_FLAGS_BLK, NULL, 0);
}
#endif
if (inode_pending)
lquota_pending_commit(mds_quota_interface_ref, obd,
qids[USRQUOTA], qids[GRPQUOTA],
- 1, 0);
+ inode_pending, 0);
if (block_pending)
lquota_pending_commit(mds_quota_interface_ref, obd,
qids[USRQUOTA], qids[GRPQUOTA],
- block_count, 1);
+ block_pending, 1);
/* Trigger dqacq on the owner of child. If failed,
* the next call for lquota_chkquota will process it. */
lquota_adjust(mds_quota_interface_ref, obd, qids, 0, rc,
struct lvfs_run_ctxt saved;
struct fsfilt_objinfo fso;
struct iattr iattr = { 0 };
- struct inode *inode = NULL;
+ struct inode *inode = res->dentry->d_inode;
unsigned long now = jiffies;
int i, err, cleanup_phase = 0;
struct obd_device *obd = exp->exp_obd;
* decide if it is out of quota or not b=14783 */
lquota_chkquota(filter_quota_interface_ref, obd, oa->o_uid,
oa->o_gid, niocount, &rec_pending, oti,
- LQUOTA_FLAGS_BLK);
+ LQUOTA_FLAGS_BLK, inode, obj->ioo_bufcnt);
iobuf = filter_iobuf_get(&obd->u.filter, oti);
if (IS_ERR(iobuf))
fso.fso_dentry = res->dentry;
fso.fso_bufcnt = obj->ioo_bufcnt;
- inode = res->dentry->d_inode;
iobuf->dr_ignore_quota = 0;
for (i = 0, lnb = res; i < niocount; i++, lnb++) {
cleanup:
if (rec_pending)
lquota_pending_commit(filter_quota_interface_ref, obd, oa->o_uid,
- oa->o_gid, niocount, 1);
+ oa->o_gid, rec_pending, 1);
filter_grant_commit(exp, niocount, res);
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;
+ pending_write = lqs->lqs_bwrite_pending;
record = lqs->lqs_blk_rec;
LASSERT(!(qunit_sz % QUOTABLOCK_SIZE));
} else {
* 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)
+ unsigned int gid, int count, int cycle, int isblk,
+ struct inode *inode, int frags, int *pending)
{
struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
int i;
__u32 id[MAXQUOTAS] = { uid, gid };
struct qunit_data qdata[MAXQUOTAS];
+ int mb = 0;
int rc = 0, rc2[2] = { 0, 0 };
ENTRY;
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;
+ if (isblk) {
+ *pending = count * CFS_PAGE_SIZE;
+ /* in order to complete this write, we need extra
+ * meta blocks. This function can get it through
+ * data needed to be written b=16542 */
+ mb = *pending;
+ LASSERT(inode && frags > 0);
+ if (fsfilt_get_mblk(obd, qctxt->lqc_sb, &mb,
+ inode, frags) < 0)
+ CDEBUG(D_ERROR,
+ "can't get extra meta blocks.\n");
+ else
+ *pending += mb;
+ lqs->lqs_bwrite_pending += *pending;
+ } else {
+ *pending = count;
+ lqs->lqs_iwrite_pending += *pending;
+ }
}
if (rc2[i] == QUOTA_RET_OK) {
- if (isblk && qdata[i].qd_count <
- lqs->lqs_bwrite_pending * CFS_PAGE_SIZE)
+ if (isblk && qdata[i].qd_count < lqs->lqs_bwrite_pending)
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);
- CDEBUG(D_QUOTA, "count: %d, write pending: %lu, qd_count: "LPU64
- ".\n", count,
+ CDEBUG(D_QUOTA, "count: %d, lqs pending: %lu, qd_count: "LPU64
+ ", metablocks: %d, isblk: %d, pending: %d.\n", count,
isblk ? lqs->lqs_bwrite_pending : lqs->lqs_iwrite_pending,
- qdata[i].qd_count);
+ qdata[i].qd_count, mb, isblk, *pending);
/* When cycle is zero, lqs_*_pending will be changed. We will
* get reference of the lqs here and put reference of lqs in
}
if (rc2[0] == QUOTA_RET_ACQUOTA || rc2[1] == QUOTA_RET_ACQUOTA)
- RETURN(rc | QUOTA_RET_ACQUOTA);
+ RETURN(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,
quota_acquire acquire,
- struct obd_trans_info *oti, int isblk)
+ struct obd_trans_info *oti, int isblk,
+ struct inode *inode, int frags)
{
struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
struct timeval work_start;
* have to wait for the completion of in flight dqacq/dqrel,
* in order to get enough quota for write b=12588 */
do_gettimeofday(&work_start);
- while ((rc = quota_check_common(obd, uid, gid, count, cycle, isblk)) &
+ while ((rc = quota_check_common(obd, uid, gid, count, cycle, isblk,
+ inode, frags, pending)) &
QUOTA_RET_ACQUOTA) {
spin_lock(&qctxt->lqc_lock);
spin_unlock(&qctxt->lqc_lock);
}
- if (rc & QUOTA_RET_INC_PENDING)
- *pending = 1;
-
cycle++;
if (isblk)
OBD_FAIL_TIMEOUT(OBD_FAIL_OST_HOLD_WRITE_RPC, 90);
CDEBUG(D_QUOTA, "recheck quota with rc: %d, cycle: %d\n", rc,
cycle);
}
-
- if (!cycle && rc & QUOTA_RET_INC_PENDING)
- *pending = 1;
-
do_gettimeofday(&work_end);
timediff = cfs_timeval_sub(&work_end, &work_start, NULL);
lprocfs_counter_add(qctxt->lqc_stats,
* pending blocks and inodes
*/
static int quota_pending_commit(struct obd_device *obd, unsigned int uid,
- unsigned int gid, int count, int isblk)
+ unsigned int gid, int pending, int isblk)
{
struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
struct timeval work_start;
quota_search_lqs(&qdata[i], NULL, qctxt, &lqs);
if (lqs) {
int flag = 0;
- CDEBUG(D_QUOTA, "pending: %lu, count: %d.\n",
- isblk ? lqs->lqs_bwrite_pending :
- lqs->lqs_iwrite_pending, count);
spin_lock(&lqs->lqs_lock);
if (isblk) {
- if (lqs->lqs_bwrite_pending >= count) {
- lqs->lqs_bwrite_pending -= count;
+ if (lqs->lqs_bwrite_pending >= pending) {
+ lqs->lqs_bwrite_pending -= pending;
spin_unlock(&lqs->lqs_lock);
flag = 1;
} else {
"there are too many blocks!\n");
}
} else {
- if (lqs->lqs_iwrite_pending >= count) {
- lqs->lqs_iwrite_pending -= count;
+ if (lqs->lqs_iwrite_pending >= pending) {
+ lqs->lqs_iwrite_pending -= pending;
spin_unlock(&lqs->lqs_lock);
flag = 1;
} else {
"there are too many files!\n");
}
}
+ CDEBUG(D_QUOTA, "lqs pending: %lu, pending: %d, "
+ "isblk: %d.\n",
+ isblk ? lqs->lqs_bwrite_pending :
+ lqs->lqs_iwrite_pending, pending, isblk);
lqs_putref(lqs);
/* When lqs_*_pening is changed back, we'll putref lqs