#define MAX_STYPE_SIZE 5
+/* The following information about CURRENT quotas is expected on the output:
+ * MDS: u for user quotas (administrative+operational) turned on,
+ * g for group quotas (administrative+operational) turned on,
+ * 1 for 32-bit operational quotas and 32-bit administrative quotas,
+ * 2 for 32-bit operational quotas and 64-bit administrative quotas,
+ * 3 for 64-bit operational quotas and 64-bit administrative quotas
+ * OST: u for user quotas (operational) turned on,
+ * g for group quotas (operational) turned on,
+ * 1 for 32-bit local operational quotas,
+ * 3 for 64-bit local operational quotas,
+ * Permanent parameters can be read with lctl (?)
+ */
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] = "";
- int oq_type;
+ int oq_type, rc, is_mds;
+ lustre_quota_version_t aq_version, oq_version;
struct obd_device_target *obt;
LASSERT(obd != NULL);
obt = &obd->u.obt;
+ is_mds = !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
/* Collect the needed information */
oq_type = obd->u.obt.obt_qctxt.lqc_flags;
+ if (is_mds) {
+ rc = mds_quota_get_version(obd, &aq_version, &oq_version);
+ if (rc)
+ return -EPROTO;
+ } else {
+ oq_version = obt->obt_qfmt;
+ }
/* Transform the collected data into a user-readable string */
if (oq_type & LQC_USRQUOTA_FLAG)
if (oq_type & LQC_GRPQUOTA_FLAG)
strcat(stype, "g");
- strcat(stype, "3");
+ if ((!is_mds || aq_version == LUSTRE_QUOTA_V1) &&
+ oq_version == LUSTRE_QUOTA_V1)
+ strcat(stype, "1");
+#ifdef HAVE_QUOTA64
+ else if ((!is_mds || aq_version == LUSTRE_QUOTA_V2) &&
+ oq_version == LUSTRE_QUOTA_V2)
+ strcat(stype, "3");
+#endif
+ else if (is_mds && aq_version == LUSTRE_QUOTA_V2 &&
+ oq_version == LUSTRE_QUOTA_V1)
+ strcat(stype, "2");
+ else
+ return -EPROTO;
return snprintf(page, count, "%s\n", stype);
}
EXPORT_SYMBOL(lprocfs_quota_rd_type);
-static int auto_quota_on(struct obd_device *obd, int type,
- struct super_block *sb, int is_master)
+/*
+ * generic_quota_on is very lazy and tolerant about current quota settings
+ * @global means to turn on quotas on each OST additionally to local quotas;
+ * should not be called from filter_quota_ctl on MDS nodes (as it starts
+ * admin quotas on MDS nodes).
+ */
+int generic_quota_on(struct obd_device *obd, struct obd_quotactl *oqctl, int global)
{
- struct obd_quotactl *oqctl;
- struct lvfs_run_ctxt saved;
- int rc = 0, id;
struct obd_device_target *obt = &obd->u.obt;
+ struct lvfs_run_ctxt saved;
+ int id, is_master, rc = 0, local; /* means we need a local quotaon */
+
+ if (!atomic_dec_and_test(&obt->obt_quotachecking)) {
+ CDEBUG(D_INFO, "other people are doing quotacheck\n");
+ atomic_inc(&obt->obt_quotachecking);
+ RETURN(-EBUSY);
+ }
+
+ id = UGQUOTA2LQC(oqctl->qc_type);
+ local = (obt->obt_qctxt.lqc_flags & id) != id;
+
+ oqctl->qc_cmd = Q_QUOTAON;
+ oqctl->qc_id = obt->obt_qfmt;
+
+ is_master= !strcmp(obd->obd_type->typ_name, LUSTRE_MDS_NAME);
+ if (is_master && local) {
+ down(&obd->u.mds.mds_qonoff_sem);
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ /* turn on cluster wide quota */
+ rc = mds_admin_quota_on(obd, oqctl);
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ if (rc && rc != -ENOENT)
+ CERROR("%s: %s admin quotaon failed. rc=%d\n",
+ obd->obd_name, global ? "global" : "local", rc);
+ }
+
+ if (rc == 0) {
+ if (local) {
+ push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ /* turn on local quota */
+ rc = fsfilt_quotactl(obd, obt->obt_sb, oqctl);
+ pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
+ if (rc) {
+ if (rc != -ENOENT)
+ CERROR("%s: %s quotaon failed with"
+ " rc=%d\n", obd->obd_name,
+ global ? "global" : "local", rc);
+ } else {
+ obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(oqctl->qc_type);
+ }
+ }
+
+ if (rc == 0 && global && is_master)
+ rc = obd_quotactl(obd->u.mds.mds_lov_exp, oqctl);
+ }
+
+ if (is_master)
+ up(&obd->u.mds.mds_qonoff_sem);
+
+ atomic_inc(&obt->obt_quotachecking);
+
+ return rc;
+}
+
+static int auto_quota_on(struct obd_device *obd, int type)
+{
+ struct obd_quotactl *oqctl;
+ int rc;
ENTRY;
LASSERT(type == USRQUOTA || type == GRPQUOTA || type == UGQUOTA);
if (!oqctl)
RETURN(-ENOMEM);
- down(&obt->obt_quotachecking);
- id = UGQUOTA2LQC(type);
- /* quota already turned on */
- if ((obt->obt_qctxt.lqc_flags & id) == id)
- GOTO(out, rc);
+ oqctl->qc_type = type;
- if (obt->obt_qctxt.lqc_immutable) {
- LCONSOLE_ERROR("Failed to turn Quota on, immutable mode "
- "(is SOM enabled?)\n");
- GOTO(out, rc);
- }
+ rc = generic_quota_on(obd, oqctl, 0);
- oqctl->qc_type = type;
- oqctl->qc_cmd = Q_QUOTAON;
- oqctl->qc_id = obt->obt_qfmt;
+ OBD_FREE_PTR(oqctl);
+ RETURN(rc);
+}
- push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
- if (is_master) {
- struct mds_obd *mds = &obd->u.mds;
+static int filter_quota_set_version(struct obd_device *obd,
+ lustre_quota_version_t version)
+{
+ struct obd_device_target *obt = &obd->u.obt;
- down(&mds->mds_qonoff_sem);
- /* turn on cluster wide quota */
- rc = mds_admin_quota_on(obd, oqctl);
- if (rc)
- CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR,
- "auto-enable admin quota failed. rc=%d\n", rc);
- up(&mds->mds_qonoff_sem);
+ if (version != LUSTRE_QUOTA_V1) {
+#ifdef HAVE_QUOTA64
+ if (version != LUSTRE_QUOTA_V2)
+#endif
+ return -EINVAL;
+ }
+ if (!atomic_dec_and_test(&obt->obt_quotachecking)) {
+ CDEBUG(D_INFO, "other people are doing quotacheck\n");
+ atomic_inc(&obt->obt_quotachecking);
+ return -EBUSY;
}
- if (!rc) {
- /* turn on local quota */
- rc = fsfilt_quotactl(obd, sb, oqctl);
- if (rc)
- CDEBUG(rc == -ENOENT ? D_QUOTA : D_ERROR,
- "auto-enable local quota failed. rc=%d\n", rc);
- else
- obt->obt_qctxt.lqc_flags |= UGQUOTA2LQC(type);
+
+ /* do not complain of being busy if we actually have nothing to do */
+ if (obt->obt_qfmt != version) {
+ if (obt->obt_qctxt.lqc_flags&(LQC_USRQUOTA_FLAG|LQC_GRPQUOTA_FLAG)){
+ atomic_inc(&obt->obt_quotachecking);
+ return -EBUSY;
+ }
+ obt->obt_qfmt = version;
}
- pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);
- EXIT;
+ atomic_inc(&obt->obt_quotachecking);
-out:
- up(&obt->obt_quotachecking);
- OBD_FREE_PTR(oqctl);
- return rc;
+ return 0;
}
+/* The following settings of CURRENT quotas is expected on the input:
+ * MDS: u for user quotas (administrative+operational) turned on,
+ * g for group quotas (administrative+operational) turned on,
+ * 1 for 32-bit operational quotas and 32-bit administrative quotas,
+ * 2 for 32-bit operational quotas and 64-bit administrative quotas,
+ * 3 for 64-bit operational quotas and 64-bit administrative quotas
+ * OST: u for user quotas (operational) turned on,
+ * g for group quotas (operational) turned on,
+ * 1 for 32-bit local operational quotas,
+ * 2 for 32-bit local operational quotas,
+ * 3 for 64-bit local operational quotas,
+ * Permanent parameters can be set with lctl/tunefs
+ */
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;
- int type = 0, is_mds;
+ int type = 0, is_mds, idx;
unsigned long i;
char stype[MAX_STYPE_SIZE + 1] = "";
-
+ static const lustre_quota_version_t s2av[3] = {LUSTRE_QUOTA_V1,
+ LUSTRE_QUOTA_V2,
+ LUSTRE_QUOTA_V2},
+ s2ov[3] = {LUSTRE_QUOTA_V1,
+ LUSTRE_QUOTA_V1,
+ LUSTRE_QUOTA_V2};
LASSERT(obd != NULL);
obt = &obd->u.obt;
return -EFAULT;
for (i = 0 ; i < count ; i++) {
+ int rc;
+
switch (stype[i]) {
case 'u' :
type |= USER_QUOTA;
case 'g' :
type |= GROUP_QUOTA;
break;
+ /* quota version specifiers */
case '1' :
case '2' :
- CWARN("quota_type options 1 and 2 are obsolete, "
- "they will be ignored\n");
+ case '3' :
+ idx = stype[i] - '1';
+#ifndef HAVE_QUOTA64
+ if (s2ov[idx] == LUSTRE_QUOTA_V2)
+ return -EINVAL;
+#endif
+ if (is_mds) {
+ rc = mds_quota_set_version(obd, s2av[idx],
+ s2ov[idx]);
+ if (rc) {
+ CDEBUG(D_QUOTA, "failed to set admin "
+ "quota to spec %c! %d\n",
+ stype[i], rc);
+ return rc;
+ }
+ } else {
+ rc = filter_quota_set_version(obd, s2ov[idx]);
+ if (rc) {
+ CDEBUG(D_QUOTA, "failed to set op"
+ " quota to spec %c! %d\n",
+ stype[i], rc);
+ return rc;
+ }
+ }
break;
- case '3' : /* the only valid version spec, do nothing */
default : /* just skip stray symbols like \n */
break;
}
}
if (type != 0) {
- auto_quota_on(obd, type - 1, obt->obt_sb, is_mds);
- build_lqs(obd);
+ int rc = auto_quota_on(obd, type - 1);
+
+ if (rc == 0)
+ build_lqs(obd);
+ else if (rc == -ENOENT)
+ CWARN("%s: quotaon failed because quota files don't "
+ "exist, please run quotacheck firstly\n",
+ obd->obd_name);
+ else if (rc == -EALREADY)
+ CWARN("%s: quota is on already!\n", obd->obd_name);
+ else
+ return rc;
}
return count;
lprocfs_quota_common_vars, obd);
if (IS_ERR(qctxt->lqc_proc_dir)) {
rc = PTR_ERR(qctxt->lqc_proc_dir);
- CERROR("error %d setting up lprocfs for %s\n", rc,
- obd->obd_name);
+ CERROR("%s: error %d setting up lprocfs\n",
+ obd->obd_name, rc);
qctxt->lqc_proc_dir = NULL;
GOTO(out, rc);
}
rc = lprocfs_add_vars(qctxt->lqc_proc_dir,
lprocfs_quota_master_vars, obd);
if (rc) {
- CERROR("error %d setting up lprocfs for %s"
- "(quota master)\n", rc, obd->obd_name);
+ CERROR("%s: error %d setting up lprocfs for "
+ "quota master\n", obd->obd_name, rc);
GOTO(out_free_proc, rc);
}
}
return -EINVAL;
if (qctxt->lqc_stats != NULL)
- lprocfs_free_stats(&qctxt->lqc_stats);
+ lprocfs_free_stats(&qctxt->lqc_stats);
lprocfs_remove(&qctxt->lqc_proc_dir);
return 0;