int (* fs_qids)(struct file *file, struct inode *inode, int type,
struct list_head *list);
int (* fs_dquot)(struct lustre_dquot *dquot, int cmd);
+ int (* fs_get_mblk)(struct super_block *sb, int *count,
+ struct inode *inode, int frags);
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 */
extern int quota_get_qunit_data_size(__u64 flag);
#endif
/* For quota slave, check whether specified uid/gid is over quota */
int (*quota_getflag) (struct obd_device *, struct obdo *);
-
+#ifdef __KERNEL__
/* For quota slave, acquire/release quota from master if needed */
int (*quota_acquire) (struct obd_device *, unsigned int, unsigned int,
struct obd_trans_info *);
* record of block and inode, acquires quota if necessary */
int (*quota_chkquota) (struct obd_device *, unsigned int, unsigned int,
int, int *, quota_acquire,
- struct obd_trans_info *);
+ struct obd_trans_info *, 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);
+#endif
/* 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);
RETURN(rc);
}
+#ifdef __KERNEL__
static inline int lquota_acquire(quota_interface_t *interface,
struct obd_device *obd,
unsigned int uid, unsigned int gid,
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 *flag, struct obd_trans_info *oti,
+ struct inode *inode, int frags)
{
int rc;
ENTRY;
QUOTA_CHECK_OP(interface, chkquota);
QUOTA_CHECK_OP(interface, acquire);
rc = QUOTA_OP(interface, chkquota)(obd, uid, gid, count, flag,
- QUOTA_OP(interface, acquire), oti);
+ QUOTA_OP(interface, acquire), oti,
+ 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 pending)
{
int rc;
ENTRY;
QUOTA_CHECK_OP(interface, pending_commit);
- rc = QUOTA_OP(interface, pending_commit)(obd, uid, gid, npage);
+ rc = QUOTA_OP(interface, pending_commit)(obd, uid, gid, pending);
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
static 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,
};
* FIXME: after CMD is used, pointer to obd_trans_info* couldn't
* be NULL, b=14840 */
lquota_chkquota(mds_quota_interface_ref, obd,
- current->fsuid, gid, 1, &rec_pending, NULL);
+ current->fsuid, gid, 1, &rec_pending,
+ NULL, NULL, 0);
intent_set_disposition(rep, DISP_OPEN_CREATE);
handle = fsfilt_start(obd, dparent->d_inode, FSFILT_OP_CREATE,
cleanup_no_trans:
if (rec_pending)
lquota_pending_commit(mds_quota_interface_ref, obd,
- current->fsuid, gid, 1);
+ current->fsuid, gid, rec_pending);
switch (cleanup_phase) {
case 2:
if (rc && created) {
* FIXME: after CMD is used, pointer to obd_trans_info* couldn't
* be NULL, b=14840 */
lquota_chkquota(mds_quota_interface_ref, obd,
- current->fsuid, gid, 1, &rec_pending, NULL);
+ current->fsuid, gid, 1, &rec_pending, NULL, NULL, 0);
switch (type) {
case S_IFREG:{
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);
+ current->fsuid, gid, rec_pending);
if (rc && created) {
/* Destroy the file we just created. This should not need
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;
/* we try to get enough quota to write here, and let ldiskfs
* 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_chkquota(filter_quota_interface_ref, obd, oa->o_uid, oa->o_gid,
+ niocount, &rec_pending, oti, 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 < obj->ioo_bufcnt; i++, lnb++) {
cleanup:
if (rec_pending)
lquota_pending_commit(filter_quota_interface_ref, obd, oa->o_uid,
- oa->o_gid, niocount);
+ oa->o_gid, rec_pending);
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 {
/* 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)
+ 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;
+ }
}
- 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);
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)
}
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,
int isblk, quota_acquire acquire,
- struct obd_trans_info *oti)
+ struct obd_trans_info *oti, 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)) &
- QUOTA_RET_ACQUOTA) {
+ while ((rc = quota_check_common(obd, uid, gid, count, cycle, isblk,
+ inode, frags, pending)) & QUOTA_RET_ACQUOTA) {
spin_lock(&qctxt->lqc_lock);
if (!qctxt->lqc_import && oti) {
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);
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,
}
static int filter_quota_check(struct obd_device *obd, unsigned int uid,
- unsigned int gid, int npage, int *flag,
- quota_acquire acquire, struct obd_trans_info *oti)
+ unsigned int gid, int npage, int *pending,
+ quota_acquire acquire, struct obd_trans_info *oti,
+ struct inode *inode, int frags)
{
- return quota_chk_acq_common(obd, uid, gid, npage, flag, LQUOTA_FLAGS_BLK,
- acquire, oti);
+ return quota_chk_acq_common(obd, uid, gid, npage, pending, LQUOTA_FLAGS_BLK,
+ acquire, oti, inode, frags);
}
/* 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)
+ unsigned int gid, int pending, int isblk)
{
struct lustre_quota_ctxt *qctxt = &obd->u.obt.obt_qctxt;
struct timeval work_start;
if (lqs) {
int flag = 0;
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;
+ if (lqs->lqs_bwrite_pending >= pending) {
+ lqs->lqs_bwrite_pending -= pending;
flag = 1;
} else {
CDEBUG(D_ERROR,
"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;
flag = 1;
} else {
CDEBUG(D_ERROR,
"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);
spin_unlock(&lqs->lqs_lock);
lqs_putref(lqs);
}
static int filter_quota_pending_commit(struct obd_device *obd, unsigned int uid,
- unsigned int gid, int npage)
+ unsigned int gid, int blocks)
{
- return quota_pending_commit(obd, uid, gid, npage, LQUOTA_FLAGS_BLK);
+ return quota_pending_commit(obd, uid, gid, blocks, LQUOTA_FLAGS_BLK);
}
static int mds_quota_init(void)
}
static int mds_quota_check(struct obd_device *obd, unsigned int uid,
- unsigned int gid, int inodes, int *flag,
- quota_acquire acquire, struct obd_trans_info *oti)
+ unsigned int gid, int inodes, int *pending,
+ quota_acquire acquire, struct obd_trans_info *oti,
+ struct inode *inode, int frags)
{
- return quota_chk_acq_common(obd, uid, gid, inodes, flag, 0,
- acquire, oti);
+ return quota_chk_acq_common(obd, uid, gid, inodes, pending, 0,
+ acquire, oti, inode, frags);
}
static int mds_quota_acquire(struct obd_device *obd, unsigned int uid,