int lprocfs_wr_nosquash_nids(const char __user *buffer, unsigned long count,
struct root_squash_info *squash, char *name);
-/* all quota proc functions */
-extern int lprocfs_quota_rd_bunit(char *page, char **start,
- off_t off, int count,
- int *eof, void *data);
-extern int lprocfs_quota_wr_bunit(struct file *file, const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_btune(char *page, char **start,
- off_t off, int count,
- int *eof, void *data);
-extern int lprocfs_quota_wr_btune(struct file *file, const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_iunit(char *page, char **start,
- off_t off, int count,
- int *eof, void *data);
-extern int lprocfs_quota_wr_iunit(struct file *file, const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_itune(char *page, char **start,
- off_t off, int count,
- int *eof, void *data);
-extern int lprocfs_quota_wr_itune(struct file *file, const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_type(char *page, char **start, off_t off, int count,
- int *eof, void *data);
-extern int lprocfs_quota_wr_type(struct file *file, const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_switch_seconds(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-extern int lprocfs_quota_wr_switch_seconds(struct file *file,
- const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_sync_blk(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-extern int lprocfs_quota_wr_sync_blk(struct file *file, const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_switch_qs(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-extern int lprocfs_quota_wr_switch_qs(struct file *file,
- const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_boundary_factor(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-extern int lprocfs_quota_wr_boundary_factor(struct file *file,
- const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_least_bunit(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-extern int lprocfs_quota_wr_least_bunit(struct file *file,
- const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_least_iunit(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-extern int lprocfs_quota_wr_least_iunit(struct file *file,
- const char *buffer,
- unsigned long count, void *data);
-extern int lprocfs_quota_rd_qs_factor(char *page, char **start, off_t off,
- int count, int *eof, void *data);
-extern int lprocfs_quota_wr_qs_factor(struct file *file,
- const char *buffer,
- unsigned long count, void *data);
#else /* !CONFIG_PROC_FS */
#define proc_lustre_root NULL
/* See comment in qmt_adjust_qunit(). LU-4139 */
if (qmt_hard_exhausted(lqe) ||
- pool->qpi_key >> 16 == LQUOTA_RES_MD) {
+ pool->qpi_key >> 16 != LQUOTA_RES_DT) {
/* we haven't reached the minimal qunit yet so there is
* still hope that the rebalancing process might free
* up some quota space */
lqe->lqe_revoke_time))
RETURN_EXIT;
} else {
- /* When exceeding softlimit, block qunit will be shrunk
- * to (4 * least_qunit) finally. */
- if (lqe->lqe_qunit > (pool->qpi_least_qunit << 2))
+ if (lqe->lqe_qunit > pool->qpi_soft_least_qunit)
RETURN_EXIT;
}
LASSERT(lqe->lqe_softlimit != 0);
*oversoft = false;
/* No need to do special tweaking for inode limit */
- if (pool->qpi_key >> 16 == LQUOTA_RES_MD)
+ if (pool->qpi_key >> 16 != LQUOTA_RES_DT)
return lqe->lqe_softlimit;
- /* Added (least_qunit * 4) as margin */
if (lqe->lqe_granted <= lqe->lqe_softlimit +
- (pool->qpi_least_qunit << 2)) {
+ pool->qpi_soft_least_qunit) {
return lqe->lqe_softlimit;
} else if (lqe->lqe_hardlimit != 0) {
*oversoft = true;
remaining = qmt_calc_softlimit(lqe, &oversoft);
if (remaining == 0)
remaining = lqe->lqe_granted +
- (pool->qpi_least_qunit << 2);
+ pool->qpi_soft_least_qunit;
} else {
remaining = lqe->lqe_hardlimit;
}
bool oversoft;
/* As a compromise of write performance and the grace time
* accuracy, the block qunit size will be shrunk to
- * (4 * least_qunit) when over softlimit. LU-4139. */
+ * qpi_soft_least_qunit when over softlimit. LU-4139. */
limit = qmt_calc_softlimit(lqe, &oversoft);
if (oversoft)
- qunit2 = pool->qpi_least_qunit << 2;
+ qunit2 = pool->qpi_soft_least_qunit;
if (limit == 0)
GOTO(done, qunit = qunit2);
} else if (lqe->lqe_hardlimit != 0) {
/* Global quota parameters which apply to all quota type */
/* the least value of qunit */
unsigned long qpi_least_qunit;
+
+ /* Least value of qunit when soft limit is exceeded.
+ *
+ * When soft limit is exceeded, qunit will be shrinked to least_qunit
+ * (1M for block limit), that results in significant write performance
+ * drop since the client will turn to sync write from now on.
+ *
+ * To retain the write performance in an acceptable level, we choose
+ * to sacrifice grace time accuracy a bit and use a larger least_qunit
+ * when soft limit is exceeded. It's (qpi_least_qunit * 4) by default,
+ * and user may enlarge it via procfs to get even better performance
+ * (with the cost of losing more grace time accuracy).
+ *
+ * See qmt_calc_softlimit().
+ */
+ unsigned long qpi_soft_least_qunit;
};
/*
}
LPROC_SEQ_FOPS_RO(qpi_state);
+static int qpi_soft_least_qunit_seq_show(struct seq_file *m, void *data)
+{
+ struct qmt_pool_info *pool = m->private;
+ LASSERT(pool != NULL);
+
+ return seq_printf(m, "%lu\n", pool->qpi_soft_least_qunit);
+}
+
+static ssize_t
+qpi_soft_least_qunit_seq_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *off)
+{
+ struct qmt_pool_info *pool;
+ int qunit, rc;
+ s64 least_qunit;
+
+ pool = ((struct seq_file *)file->private_data)->private;
+ LASSERT(pool != NULL);
+
+ /* Not tuneable for inode limit */
+ if (pool->qpi_key >> 16 != LQUOTA_RES_DT)
+ return -EINVAL;
+
+ rc = lprocfs_str_to_s64(buffer, count, &least_qunit);
+ if (rc)
+ return rc;
+
+ /* Miminal qpi_soft_least_qunit */
+ qunit = pool->qpi_least_qunit << 2;
+ /* The value must be power of miminal qpi_soft_least_qunit, see
+ * how the qunit is adjusted in qmt_adjust_qunit(). */
+ while (qunit > 0 && qunit < least_qunit)
+ qunit <<= 2;
+ if (qunit <= 0)
+ qunit = INT_MAX & ~3;
+
+ pool->qpi_soft_least_qunit = qunit;
+ return count;
+}
+LPROC_SEQ_FOPS(qpi_soft_least_qunit);
+
static struct lprocfs_vars lprocfs_quota_qpi_vars[] = {
{ .name = "info",
.fops = &qpi_state_fops },
+ { .name = "soft_least_qunit",
+ .fops = &qpi_soft_least_qunit_fops },
{ NULL }
};
/* set up least qunit size to use for this pool */
pool->qpi_least_qunit = LQUOTA_LEAST_QUNIT(pool_type);
+ if (pool_type == LQUOTA_RES_DT)
+ pool->qpi_soft_least_qunit = pool->qpi_least_qunit << 2;
+ else
+ pool->qpi_soft_least_qunit = pool->qpi_least_qunit;
/* create pool proc directory */
sprintf(qti->qti_buf, "%s-0x%x", RES_NAME(pool_type), pool_id);