CDEBUG|CERROR|CNETERR|CEMERG|CL_LOCK_DEBUG|CWARN|DEBUG_REQ|LCONSOLE_[A-Z]*|
panic|
MODULE_[A-Z_]+|
- seq_vprintf|seq_printf|seq_puts
+ seq_vprintf|seq_printf|seq_puts|
+ printf|fprintf
)};
our $signature_tags = qr{(?xi:
.B lfs quota -t \fR<\fB-u\fR|\fB-g\fR|\fB-p\fR> <\fIfilesystem\fR>
.br
+.br
+.B lfs quota -a \fR<\fB-u\fR|\fB-g\fR|\fB-p\fR> <\fIfilesystem\fR>
+.br
+
.TP
.SH DESCRIPTION
.PP
.B --pool <\fIpname\fR>
Display user, group or project grace times per OST pool \fIpname\fR.
.TP
+.B lfs quota -a \fR<\fB-u\fR|\fB-g\fR|\fB-p\fR> <\fIfilesystem\fR>
+.TP
+Display all quota setting for all users, groups, or projects.
+.TP
.SH EXAMPLES
.TP
.B $ lfs quota /mnt/lustre
OSD_QID_FORCE = BIT(2),
};
+/* the length of the buffer to contain the quotas gotten from QMT/QSD,
+ * the maximum is 128 quota IDs (each struct lquota_glb_rec for MD or DT),
+ * it can contain about 420 quota IDs for theirs quota usage.
+ */
+#define LQUOTA_ITER_BUFLEN \
+ (128 * 2 * (sizeof(__u64) + sizeof(struct lquota_glb_rec)))
+
+struct lquota_iter {
+ struct list_head li_link;
+ __u32 li_md_size;
+ __u32 li_dt_size;
+ char li_buffer[0];
+};
+
+struct if_quotactl_iter {
+ struct list_head qci_link;
+ struct if_quotactl qci_qc;
+};
+
/* Index features supported by the global index objects
* Only used for migration purpose and should be removed once on-disk migration
* is no longer needed
struct qmt_handlers {
/* Handle quotactl request from client. */
int (*qmth_quotactl)(const struct lu_env *env, struct lu_device *d,
- struct obd_quotactl *);
+ struct obd_quotactl *, char *buf, int len);
/* Handle dqacq/dqrel request from slave. */
int (*qmth_dqacq)(const struct lu_env *env, struct lu_device *d,
* on slave
*/
int lquotactl_slv(const struct lu_env *env, struct dt_device *dt,
- struct obd_quotactl *obdq);
+ struct obd_quotactl *obdq, char *buf, int len);
/** @} quota */
#endif /* _LUSTRE_QUOTA_H */
extern struct req_msg_field RMF_CAPA2;
extern struct req_msg_field RMF_OBD_QUOTACHECK;
extern struct req_msg_field RMF_OBD_QUOTACTL;
+extern struct req_msg_field RMF_OBD_QUOTA_ITER;
extern struct req_msg_field RMF_OBD_QUOTACTL_POOL;
extern struct req_msg_field RMF_QUOTA_BODY;
extern struct req_msg_field RMF_STRING;
RETURN(rc);
}
+static inline int obd_quota_iter(struct obd_export *exp,
+ struct obd_quotactl *oqctl,
+ struct list_head *list)
+{
+ int rc = 0;
+
+ do {
+ oqctl->qc_iter_list = (__u64)list;
+ rc = obd_quotactl(exp, oqctl);
+ if (rc)
+ break;
+
+ } while (oqctl->qc_iter_md_offset || oqctl->qc_iter_dt_offset);
+
+ return rc;
+}
+
static inline int obd_health_check(const struct lu_env *env,
struct obd_device *obd)
{
#define OBD_FAIL_QUOTA_PREACQ 0xA06
#define OBD_FAIL_QUOTA_RECALC 0xA07
#define OBD_FAIL_QUOTA_GRANT 0xA08
+#define OBD_FAIL_QUOTA_NOSYNC 0xA09
#define OBD_FAIL_LPROC_REMOVE 0xB00
char qc_poolname[];
};
+#define qc_iter_md_offset qc_dqblk.dqb_bhardlimit
+#define qc_iter_dt_offset qc_dqblk.dqb_ihardlimit
+#define qc_iter_md_buflen qc_dqblk.dqb_bsoftlimit
+#define qc_iter_dt_buflen qc_dqblk.dqb_isoftlimit
+#define qc_iter_list qc_dqblk.dqb_curspace
+#define qc_iter_qid_start qc_dqblk.dqb_curinodes
+#define qc_iter_qid_end qc_dqblk.dqb_btime
+
#define Q_COPY(out, in, member) (out)->member = (in)->member
#define QCTL_COPY_NO_PNAME(out, in) \
#define LUSTRE_Q_SETDEFAULT_POOL 0x800014 /* set default pool quota */
#define LUSTRE_Q_DELETEQID 0x800015 /* delete quota ID */
#define LUSTRE_Q_RESETQID 0x800016 /* reset quota ID */
+#define LUSTRE_Q_ITERQUOTA 0x800017 /* iterate quota information */
+#define LUSTRE_Q_ITEROQUOTA 0x800018 /* iterate obd quota information */
+#define LUSTRE_Q_GETALLQUOTA 0x800019 /* get all quota information */
/* In the current Lustre implementation, the grace time is either the time
* or the timestamp to be used after some quota ID exceeds the soft limt,
* 48 bits should be enough, its high 16 bits can be used as quota flags.
char qc_poolname[];
};
+#define qc_allquota_count qc_dqblk.dqb_bhardlimit
+#define qc_allquota_buffer qc_dqblk.dqb_bsoftlimit
+#define qc_allquota_buflen qc_dqblk.dqb_curspace
+#define qc_allquota_qid_start qc_dqblk.dqb_curinodes
+#define qc_allquota_qid_end qc_dqblk.dqb_btime
+#define qc_allquota_mark qc_dqblk.dqb_itime
+
/* swap layout flags */
#define SWAP_LAYOUTS_CHECK_DV1 (1 << 0)
#define SWAP_LAYOUTS_CHECK_DV2 (1 << 1)
#include <lustre_fid.h>
#include <lustre_kernelcomm.h>
#include <lustre_swab.h>
+#include <lustre_quota.h>
#include <libcfs/libcfs_crypto.h>
#include "llite_internal.h"
return 0;
}
+struct kmem_cache *quota_iter_slab;
+static DEFINE_MUTEX(quotactl_iter_lock);
+
+struct ll_quotactl_iter_list {
+ __u64 lqil_mark; /* iter identifier */
+ __u32 lqil_flags; /* what has been done */
+ pid_t lqil_pid; /* debug calling task */
+ time64_t lqil_iter_time; /* the time to iter */
+ struct list_head lqil_sbi_list; /* list on ll_sb_info */
+ struct list_head lqil_quotactl_iter_list; /* list of quota iters */
+};
+
+void ll_quota_iter_check_and_cleanup(struct ll_sb_info *sbi, bool check)
+{
+ struct if_quotactl_iter *iter_rec = NULL;
+ struct ll_quotactl_iter_list *tmp, *ll_iter = NULL;
+
+ if (!check)
+ mutex_lock("actl_iter_lock);
+
+ list_for_each_entry_safe(ll_iter, tmp, &sbi->ll_all_quota_list,
+ lqil_sbi_list) {
+ if (check &&
+ ll_iter->lqil_iter_time > (ktime_get_seconds() - 86400))
+ continue;
+
+ while ((iter_rec = list_first_entry_or_null(
+ &ll_iter->lqil_quotactl_iter_list,
+ struct if_quotactl_iter,
+ qci_link)) != NULL) {
+ list_del_init(&iter_rec->qci_link);
+ OBD_SLAB_FREE_PTR(iter_rec, quota_iter_slab);
+ }
+
+ list_del_init(&ll_iter->lqil_sbi_list);
+ OBD_FREE_PTR(ll_iter);
+ }
+
+ if (!check)
+ mutex_unlock("actl_iter_lock);
+}
+
+/* iterate the quota usage from all QSDs */
+static int quotactl_iter_acct(struct list_head *quota_list, void *buffer,
+ __u64 size, __u64 *count, __u32 qtype, bool is_md)
+{
+ struct if_quotactl_iter *tmp, *iter = NULL;
+ struct lquota_acct_rec *acct;
+ __u64 qid, cur = 0;
+ int rc = 0;
+
+ ENTRY;
+
+ while (cur < size) {
+ if ((size - cur) <
+ (sizeof(qid) + sizeof(*acct))) {
+ rc = -EPROTO;
+ break;
+ }
+
+ qid = *((__u64 *)(buffer + cur));
+ cur += sizeof(qid);
+ acct = (struct lquota_acct_rec *)(buffer + cur);
+ cur += sizeof(*acct);
+
+ iter = NULL;
+ list_for_each_entry(tmp, quota_list, qci_link) {
+ if (tmp->qci_qc.qc_id == (__u32)qid) {
+ iter = tmp;
+ break;
+ }
+ }
+
+ if (iter == NULL) {
+ CDEBUG(D_QUOTA, "can't find the iter record for %llu\n",
+ qid);
+
+ if (qid != 0)
+ continue;
+
+ OBD_SLAB_ALLOC_PTR(iter, quota_iter_slab);
+ if (iter == NULL) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ INIT_LIST_HEAD(&iter->qci_link);
+ iter->qci_qc.qc_id = 0;
+ iter->qci_qc.qc_type = qtype;
+ (*count)++;
+
+ list_add(&iter->qci_link, quota_list);
+ }
+
+ if (is_md) {
+ iter->qci_qc.qc_dqblk.dqb_valid |= QIF_INODES;
+ iter->qci_qc.qc_dqblk.dqb_curinodes += acct->ispace;
+ iter->qci_qc.qc_dqblk.dqb_curspace += acct->bspace;
+ } else {
+ iter->qci_qc.qc_dqblk.dqb_valid |= QIF_SPACE;
+ iter->qci_qc.qc_dqblk.dqb_curspace += acct->bspace;
+ }
+ }
+
+ RETURN(rc);
+}
+
+/* iterate all quota settings from QMT */
+static int quotactl_iter_glb(struct list_head *quota_list, void *buffer,
+ __u64 size, __u64 *count, __u32 qtype, bool is_md)
+{
+ struct if_quotactl_iter *tmp, *iter = NULL;
+ struct lquota_glb_rec *glb;
+ __u64 qid, cur = 0;
+ bool inserted = false;
+ int rc = 0;
+
+ ENTRY;
+
+ while (cur < size) {
+ if ((size - cur) <
+ (sizeof(qid) + sizeof(*glb))) {
+ rc = -EPROTO;
+ break;
+ }
+
+ qid = *((__u64 *)(buffer + cur));
+ cur += sizeof(qid);
+ glb = (struct lquota_glb_rec *)(buffer + cur);
+ cur += sizeof(*glb);
+
+ iter = NULL;
+ list_for_each_entry(tmp, quota_list, qci_link) {
+ if (tmp->qci_qc.qc_id == (__u32)qid) {
+ iter = tmp;
+ break;
+ }
+ }
+
+ if (iter == NULL) {
+ OBD_SLAB_ALLOC_PTR(iter, quota_iter_slab);
+ if (iter == NULL) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ INIT_LIST_HEAD(&iter->qci_link);
+
+ inserted = false;
+ list_for_each_entry(tmp, quota_list, qci_link) {
+ if (tmp->qci_qc.qc_id < qid)
+ continue;
+
+ inserted = true;
+ list_add_tail(&iter->qci_link,
+ &tmp->qci_link);
+ break;
+ }
+
+ if (!inserted)
+ list_add_tail(&iter->qci_link, quota_list);
+
+ iter->qci_qc.qc_type = qtype;
+ iter->qci_qc.qc_id = (__u32)qid;
+ (*count)++;
+ }
+
+ if (is_md) {
+ iter->qci_qc.qc_dqblk.dqb_valid |= QIF_ILIMITS;
+ iter->qci_qc.qc_dqblk.dqb_ihardlimit =
+ glb->qbr_hardlimit;
+ iter->qci_qc.qc_dqblk.dqb_isoftlimit =
+ glb->qbr_softlimit;
+ iter->qci_qc.qc_dqblk.dqb_itime = glb->qbr_time;
+ } else {
+ iter->qci_qc.qc_dqblk.dqb_valid |= QIF_BLIMITS;
+ iter->qci_qc.qc_dqblk.dqb_bhardlimit =
+ glb->qbr_hardlimit;
+ iter->qci_qc.qc_dqblk.dqb_bsoftlimit =
+ glb->qbr_softlimit;
+ iter->qci_qc.qc_dqblk.dqb_btime = glb->qbr_time;
+ }
+ }
+
+ RETURN(rc);
+}
+
+/* iterate the quota setting from QMT and all QSDs to get the quota information
+ * for all users or groups
+ **/
+static int quotactl_iter(struct ll_sb_info *sbi, struct if_quotactl *qctl)
+{
+ struct list_head iter_quota_glb_list;
+ struct list_head iter_obd_quota_md_list;
+ struct list_head iter_obd_quota_dt_list;
+ struct ll_quotactl_iter_list *ll_iter;
+ struct lquota_iter *iter;
+ struct obd_quotactl *oqctl;
+ __u64 count;
+ int rc = 0;
+
+ ENTRY;
+
+ OBD_ALLOC_PTR(ll_iter);
+ if (ll_iter == NULL)
+ RETURN(-ENOMEM);
+
+ INIT_LIST_HEAD(&ll_iter->lqil_sbi_list);
+ INIT_LIST_HEAD(&ll_iter->lqil_quotactl_iter_list);
+
+ mutex_lock("actl_iter_lock);
+
+ if (!list_empty(&sbi->ll_all_quota_list))
+ ll_quota_iter_check_and_cleanup(sbi, true);
+
+ INIT_LIST_HEAD(&iter_quota_glb_list);
+ INIT_LIST_HEAD(&iter_obd_quota_md_list);
+ INIT_LIST_HEAD(&iter_obd_quota_dt_list);
+
+ OBD_ALLOC_PTR(oqctl);
+ if (oqctl == NULL)
+ GOTO(out, rc = -ENOMEM);
+
+ QCTL_COPY(oqctl, qctl);
+ oqctl->qc_iter_list = (__u64)&iter_quota_glb_list;
+ rc = obd_quotactl(sbi->ll_md_exp, oqctl);
+ if (rc)
+ GOTO(cleanup, rc);
+
+ QCTL_COPY(oqctl, qctl);
+ oqctl->qc_cmd = LUSTRE_Q_ITEROQUOTA;
+ oqctl->qc_iter_list = (__u64)&iter_obd_quota_md_list;
+ rc = obd_quotactl(sbi->ll_md_exp, oqctl);
+ if (rc)
+ GOTO(cleanup, rc);
+
+ QCTL_COPY(oqctl, qctl);
+ oqctl->qc_cmd = LUSTRE_Q_ITEROQUOTA;
+ oqctl->qc_iter_list = (__u64)&iter_obd_quota_dt_list;
+ rc = obd_quotactl(sbi->ll_dt_exp, oqctl);
+ if (rc)
+ GOTO(cleanup, rc);
+
+ count = 0;
+ while ((iter = list_first_entry_or_null(&iter_quota_glb_list,
+ struct lquota_iter, li_link))) {
+ void *buffer;
+
+ buffer = iter->li_buffer;
+ rc = quotactl_iter_glb(&ll_iter->lqil_quotactl_iter_list,
+ buffer, iter->li_md_size, &count,
+ oqctl->qc_type, true);
+ if (rc)
+ GOTO(cleanup, rc);
+
+ buffer = iter->li_buffer + LQUOTA_ITER_BUFLEN / 2;
+ rc = quotactl_iter_glb(&ll_iter->lqil_quotactl_iter_list,
+ buffer, iter->li_dt_size, &count,
+ oqctl->qc_type, false);
+
+ if (rc)
+ GOTO(cleanup, rc);
+
+ list_del_init(&iter->li_link);
+ OBD_FREE_LARGE(iter,
+ sizeof(struct lquota_iter) + LQUOTA_ITER_BUFLEN);
+ }
+
+ while ((iter = list_first_entry_or_null(&iter_obd_quota_md_list,
+ struct lquota_iter, li_link))) {
+ rc = quotactl_iter_acct(&ll_iter->lqil_quotactl_iter_list,
+ iter->li_buffer, iter->li_md_size,
+ &count, oqctl->qc_type, true);
+ if (rc)
+ GOTO(cleanup, rc);
+
+ list_del_init(&iter->li_link);
+ OBD_FREE_LARGE(iter,
+ sizeof(struct lquota_iter) + LQUOTA_ITER_BUFLEN);
+ }
+
+ while ((iter = list_first_entry_or_null(&iter_obd_quota_dt_list,
+ struct lquota_iter, li_link))) {
+ rc = quotactl_iter_acct(&ll_iter->lqil_quotactl_iter_list,
+ iter->li_buffer, iter->li_dt_size,
+ &count, oqctl->qc_type, false);
+ if (rc)
+ GOTO(cleanup, rc);
+
+ list_del_init(&iter->li_link);
+ OBD_FREE_LARGE(iter,
+ sizeof(struct lquota_iter) + LQUOTA_ITER_BUFLEN);
+ }
+
+ ll_iter->lqil_mark = ((__u64)current->pid << 32) |
+ ((__u32)qctl->qc_type << 8) |
+ (ktime_get_seconds() & 0xFFFFFF);
+ ll_iter->lqil_flags = qctl->qc_type;
+ ll_iter->lqil_pid = current->pid;
+ ll_iter->lqil_iter_time = ktime_get_seconds();
+
+ list_add(&ll_iter->lqil_sbi_list, &sbi->ll_all_quota_list);
+
+ qctl->qc_allquota_count = count;
+ qctl->qc_allquota_mark = ll_iter->lqil_mark;
+ GOTO(out, rc);
+
+cleanup:
+ ll_quota_iter_check_and_cleanup(sbi, true);
+
+ while ((iter = list_first_entry_or_null(&iter_quota_glb_list,
+ struct lquota_iter, li_link))) {
+ list_del_init(&iter->li_link);
+ OBD_FREE_LARGE(iter,
+ sizeof(struct lquota_iter) + LQUOTA_ITER_BUFLEN);
+ }
+
+ while ((iter = list_first_entry_or_null(&iter_obd_quota_md_list,
+ struct lquota_iter, li_link))) {
+ list_del_init(&iter->li_link);
+ OBD_FREE_LARGE(iter,
+ sizeof(struct lquota_iter) + LQUOTA_ITER_BUFLEN);
+ }
+
+ while ((iter = list_first_entry_or_null(&iter_obd_quota_dt_list,
+ struct lquota_iter, li_link))) {
+ list_del_init(&iter->li_link);
+ OBD_FREE_LARGE(iter,
+ sizeof(struct lquota_iter) + LQUOTA_ITER_BUFLEN);
+ }
+
+ OBD_FREE_PTR(ll_iter);
+
+out:
+ OBD_FREE_PTR(oqctl);
+
+ mutex_unlock("actl_iter_lock);
+ RETURN(rc);
+}
+
+static int quotactl_getallquota(struct ll_sb_info *sbi,
+ struct if_quotactl *qctl)
+{
+ struct ll_quotactl_iter_list *ll_iter = NULL;
+ struct if_quotactl_iter *iter = NULL;
+ void __user *buffer = (void __user *)qctl->qc_allquota_buffer;
+ __u64 cur = 0, count = qctl->qc_allquota_buflen;
+ int rc = 0;
+
+ ENTRY;
+
+ mutex_lock("actl_iter_lock);
+
+ while ((ll_iter = list_first_entry_or_null(&sbi->ll_all_quota_list,
+ struct ll_quotactl_iter_list,
+ lqil_sbi_list)) != NULL) {
+ if (qctl->qc_allquota_mark == ll_iter->lqil_mark)
+ break;
+ }
+
+ if (!ll_iter) {
+ mutex_unlock("actl_iter_lock);
+ RETURN(-EBUSY);
+ }
+
+ while ((iter = list_first_entry_or_null(
+ &ll_iter->lqil_quotactl_iter_list,
+ struct if_quotactl_iter, qci_link))) {
+ if (count - cur < sizeof(struct if_quotactl)) {
+ rc = -ERANGE;
+ break;
+ }
+
+ if (copy_to_user(buffer + cur, &iter->qci_qc,
+ sizeof(struct if_quotactl))) {
+ rc = -EFAULT;
+ break;
+ }
+
+ cur += sizeof(struct if_quotactl);
+
+ list_del_init(&iter->qci_link);
+ OBD_SLAB_FREE_PTR(iter, quota_iter_slab);
+ }
+
+ /* cleanup in case of error */
+ while ((iter = list_first_entry_or_null(
+ &ll_iter->lqil_quotactl_iter_list,
+ struct if_quotactl_iter, qci_link))) {
+ list_del_init(&iter->qci_link);
+ OBD_SLAB_FREE_PTR(iter, quota_iter_slab);
+ }
+
+ mutex_unlock("actl_iter_lock);
+
+ RETURN(rc);
+}
+
int quotactl_ioctl(struct super_block *sb, struct if_quotactl *qctl)
{
struct ll_sb_info *sbi = ll_s2sbi(sb);
case LUSTRE_Q_GETDEFAULT:
case LUSTRE_Q_GETQUOTAPOOL:
case LUSTRE_Q_GETDEFAULT_POOL:
+ case LUSTRE_Q_ITERQUOTA:
+ case LUSTRE_Q_GETALLQUOTA:
if (check_owner(type, id) &&
(!capable(CAP_SYS_ADMIN)))
RETURN(-EPERM);
RETURN(-EOPNOTSUPP);
}
- if (valid != QC_GENERAL) {
+ if (cmd == LUSTRE_Q_ITERQUOTA) {
+ rc = quotactl_iter(sbi, qctl);
+ } else if (cmd == LUSTRE_Q_GETALLQUOTA) {
+ rc = quotactl_getallquota(sbi, qctl);
+ } else if (valid != QC_GENERAL) {
if (cmd == Q_GETINFO)
qctl->qc_cmd = Q_GETOINFO;
else if (cmd == Q_GETQUOTA ||
/* cached file security context xattr name. e.g: security.selinux */
char *ll_secctx_name;
__u32 ll_secctx_name_size;
+
+ /* LU-14535: the list of "lfs quota -a" */
+ struct list_head ll_all_quota_list;
};
#define SBI_DEFAULT_HEAT_DECAY_WEIGHT ((80 * 256 + 50) / 100)
extern const struct file_operations ll_dir_operations;
extern const struct inode_operations ll_dir_inode_operations;
+extern struct kmem_cache *quota_iter_slab;
#ifdef HAVE_DIR_CONTEXT
int ll_dir_read(struct inode *inode, __u64 *pos, struct md_op_data *op_data,
struct dir_context *ctx, int *partial_readdir_rc);
__u64 offset, int *partial_readdir_rc);
void ll_release_page(struct inode *inode, struct page *page, bool remove);
int quotactl_ioctl(struct super_block *sb, struct if_quotactl *qctl);
+void ll_quota_iter_check_and_cleanup(struct ll_sb_info *sbi, bool check);
/* llite/namei.c */
extern const struct inode_operations ll_special_inode_operations;
sbi->ll_oc_thrsh_count = SBI_DEFAULT_OPENCACHE_THRESHOLD_COUNT;
sbi->ll_oc_max_ms = SBI_DEFAULT_OPENCACHE_THRESHOLD_MAX_MS;
sbi->ll_oc_thrsh_ms = SBI_DEFAULT_OPENCACHE_THRESHOLD_MS;
+
+ INIT_LIST_HEAD(&sbi->ll_all_quota_list);
RETURN(sbi);
out_destroy_ra:
if (sbi->ll_foreign_symlink_prefix)
CDEBUG(D_VFSTRACE, "VFS Op: cfg_instance %s-%016lx (sb %p)\n",
profilenm, cfg_instance, sb);
+ ll_quota_iter_check_and_cleanup(sbi, false);
+
cfg.cfg_instance = cfg_instance;
lustre_end_log(sb, profilenm, &cfg);
#include <linux/version.h>
#include <lustre_ha.h>
#include <lustre_dlm.h>
+#include <lustre_quota.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/random.h>
if (pcc_inode_slab == NULL)
GOTO(out_cache, rc = -ENOMEM);
+ quota_iter_slab = kmem_cache_create("ll_quota_iter",
+ sizeof(struct if_quotactl_iter), 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (quota_iter_slab == NULL)
+ GOTO(out_cache, rc = -ENOMEM);
+
rc = llite_tunables_register();
if (rc)
GOTO(out_cache, rc);
kmem_cache_destroy(ll_inode_cachep);
kmem_cache_destroy(ll_file_data_slab);
kmem_cache_destroy(pcc_inode_slab);
+ kmem_cache_destroy(quota_iter_slab);
return rc;
}
kmem_cache_destroy(ll_inode_cachep);
kmem_cache_destroy(ll_file_data_slab);
kmem_cache_destroy(pcc_inode_slab);
+ kmem_cache_destroy(quota_iter_slab);
}
MODULE_AUTHOR("OpenSFS, Inc. <http://www.lustre.org/>");
RETURN(-EIO);
}
+ if (oqctl->qc_cmd == LUSTRE_Q_ITERQUOTA ||
+ oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA) {
+ struct list_head *lst = (struct list_head *)oqctl->qc_iter_list;
+ int err;
+
+ if (oqctl->qc_cmd == LUSTRE_Q_ITERQUOTA)
+ RETURN(obd_quota_iter(tgt->ltd_exp, oqctl, lst));
+
+ lmv_foreach_connected_tgt(lmv, tgt) {
+ if (!tgt->ltd_active)
+ continue;
+
+ err = obd_quota_iter(tgt->ltd_exp, oqctl, lst);
+ if (err) {
+ CERROR("%s: getquota failed mdt %d: rc = %d\n",
+ obd->obd_name, tgt->ltd_index, err);
+ if (!rc)
+ rc = err;
+ }
+ }
+
+ RETURN(rc);
+ }
+
if (oqctl->qc_cmd != Q_GETOQUOTA) {
rc = obd_quotactl(tgt->ltd_exp, oqctl);
RETURN(rc);
struct lov_obd *lov = &obd->u.lov;
struct lov_tgt_desc *tgt;
struct lov_pool_desc *pool = NULL;
+ struct list_head *lst = NULL;
__u64 curspace = 0;
__u64 bhardlimit = 0;
int i, rc = 0;
ENTRY;
if (oqctl->qc_cmd != Q_GETOQUOTA &&
oqctl->qc_cmd != LUSTRE_Q_SETQUOTA &&
- oqctl->qc_cmd != LUSTRE_Q_GETQUOTAPOOL) {
+ oqctl->qc_cmd != LUSTRE_Q_GETQUOTAPOOL &&
+ oqctl->qc_cmd != LUSTRE_Q_ITEROQUOTA) {
rc = -EFAULT;
CERROR("%s: bad quota opc %x for lov obd: rc = %d\n",
obd->obd_name, oqctl->qc_cmd, rc);
oqctl->qc_cmd = Q_GETOQUOTA;
}
+ if (oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA)
+ lst = (struct list_head *)oqctl->qc_iter_list;
+
/* for lov tgt */
lov_tgts_getref(obd);
for (i = 0; i < lov->desc.ld_tgt_count; i++) {
continue;
}
- err = obd_quotactl(tgt->ltd_exp, oqctl);
+ if (oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA)
+ err = obd_quota_iter(tgt->ltd_exp, oqctl, lst);
+ else
+ err = obd_quotactl(tgt->ltd_exp, oqctl);
+
if (err) {
if (tgt->ltd_active && !rc)
rc = err;
oqctl->qc_dqblk.dqb_curspace = curspace;
oqctl->qc_dqblk.dqb_bhardlimit = bhardlimit;
}
+
RETURN(rc);
}
#include <lustre_log.h>
#include <lustre_osc.h>
#include <lustre_swab.h>
+#include <lustre_quota.h>
#include <obd_class.h>
#include "mdc_internal.h"
static int mdc_ioc_hsm_ct_start(struct obd_export *exp,
struct lustre_kernelcomm *lk);
-
static int mdc_quotactl(struct obd_device *unused, struct obd_export *exp,
struct obd_quotactl *oqctl)
{
RCL_CLIENT,
sizeof(*oqc) + LOV_MAXPOOLNAME + 1);
+ if (oqctl->qc_cmd == LUSTRE_Q_ITERQUOTA ||
+ oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA)
+ req_capsule_set_size(&req->rq_pill, &RMF_OBD_QUOTA_ITER,
+ RCL_SERVER, LQUOTA_ITER_BUFLEN);
+ else
+ req_capsule_set_size(&req->rq_pill, &RMF_OBD_QUOTA_ITER,
+ RCL_SERVER, 0);
+
rc = ptlrpc_request_pack(req, LUSTRE_MDS_VERSION,
MDS_QUOTACTL);
if (rc) {
if (req->rq_repmsg &&
(oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL))) {
+ struct list_head *lst = (struct list_head *)oqctl->qc_iter_list;
+
QCTL_COPY(oqctl, oqc);
+
+ if (oqctl->qc_cmd == LUSTRE_Q_ITERQUOTA ||
+ oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA) {
+ void *buffer;
+ struct lquota_iter *iter;
+
+ buffer = req_capsule_server_get(&req->rq_pill,
+ &RMF_OBD_QUOTA_ITER);
+
+ if (buffer == NULL) {
+ CDEBUG(D_QUOTA, "%s: no buffer in iter req\n",
+ exp->exp_obd->obd_name);
+
+ rc = -EPROTO;
+ GOTO(out, rc);
+ }
+
+ OBD_ALLOC_LARGE(iter,
+ sizeof(struct lquota_iter) + LQUOTA_ITER_BUFLEN);
+ if (iter == NULL)
+ GOTO(out, rc = -ENOMEM);
+
+ INIT_LIST_HEAD(&iter->li_link);
+ list_add(&iter->li_link, lst);
+
+ memcpy(iter->li_buffer, buffer, LQUOTA_ITER_BUFLEN);
+ iter->li_md_size = oqctl->qc_iter_md_buflen;
+ if (oqctl->qc_cmd == LUSTRE_Q_ITERQUOTA)
+ iter->li_dt_size = oqctl->qc_iter_dt_buflen;
+
+ oqctl->qc_iter_md_buflen = 0;
+ oqctl->qc_iter_dt_buflen = 0;
+ }
} else if (!rc) {
rc = -EPROTO;
CERROR("%s: cannot unpack obd_quotactl: rc = %d\n",
struct obd_export *exp = tsi->tsi_exp;
struct req_capsule *pill = tsi->tsi_pill;
struct obd_quotactl *oqctl, *repoqc;
- int id, rc;
struct mdt_device *mdt = mdt_exp2dev(exp);
struct lu_device *qmt = mdt->mdt_qmt_dev;
struct lu_nodemap *nodemap;
+ char *buffer = NULL;
+ int id, rc;
ENTRY;
if (!oqctl)
RETURN(err_serious(-EPROTO));
+ if (oqctl->qc_cmd == LUSTRE_Q_ITERQUOTA ||
+ oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA)
+ req_capsule_set_size(pill, &RMF_OBD_QUOTA_ITER, RCL_SERVER,
+ LQUOTA_ITER_BUFLEN);
+ else
+ req_capsule_set_size(pill, &RMF_OBD_QUOTA_ITER, RCL_SERVER, 0);
+
rc = req_capsule_server_pack(pill);
if (rc)
RETURN(err_serious(rc));
case LUSTRE_Q_GETQUOTAPOOL:
case LUSTRE_Q_GETINFOPOOL:
case LUSTRE_Q_GETDEFAULT_POOL:
+ case LUSTRE_Q_ITERQUOTA:
if (qmt == NULL)
GOTO(out_nodemap, rc = -EOPNOTSUPP);
/* slave quotactl */
fallthrough;
case Q_GETOINFO:
case Q_GETOQUOTA:
+ case LUSTRE_Q_ITEROQUOTA:
break;
default:
rc = -EFAULT;
if (repoqc == NULL)
GOTO(out_nodemap, rc = err_serious(-EFAULT));
+ if (oqctl->qc_cmd == LUSTRE_Q_ITERQUOTA ||
+ oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA) {
+ buffer = req_capsule_server_get(pill, &RMF_OBD_QUOTA_ITER);
+ if (buffer == NULL)
+ GOTO(out_nodemap, rc = err_serious(-EFAULT));
+ }
+
if (oqctl->qc_cmd == Q_SETINFO || oqctl->qc_cmd == Q_SETQUOTA)
barrier_exit(tsi->tsi_tgt->lut_bottom);
case LUSTRE_Q_GETDEFAULT_POOL:
case LUSTRE_Q_DELETEQID:
case LUSTRE_Q_RESETQID:
+ case LUSTRE_Q_ITERQUOTA:
/* forward quotactl request to QMT */
- rc = qmt_hdls.qmth_quotactl(tsi->tsi_env, qmt, oqctl);
+ rc = qmt_hdls.qmth_quotactl(tsi->tsi_env, qmt, oqctl, buffer,
+ buffer == NULL ? 0 :
+ LQUOTA_ITER_BUFLEN);
break;
case Q_GETOINFO:
case Q_GETOQUOTA:
+ case LUSTRE_Q_ITEROQUOTA:
/* slave quotactl */
rc = lquotactl_slv(tsi->tsi_env, tsi->tsi_tgt->lut_bottom,
- oqctl);
+ oqctl, buffer,
+ buffer == NULL ? 0 : LQUOTA_ITER_BUFLEN);
break;
default:
struct obd_quotactl *oqctl, *repoqc;
struct lu_nodemap *nodemap;
ktime_t kstart = ktime_get();
+ char *buffer = NULL;
int id;
int rc;
-
ENTRY;
oqctl = req_capsule_client_get(tsi->tsi_pill, &RMF_OBD_QUOTACTL);
if (oqctl == NULL)
RETURN(err_serious(-EPROTO));
+ if (oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA)
+ req_capsule_set_size(tsi->tsi_pill, &RMF_OBD_QUOTA_ITER,
+ RCL_SERVER, LQUOTA_ITER_BUFLEN);
+ else
+ req_capsule_set_size(tsi->tsi_pill, &RMF_OBD_QUOTA_ITER,
+ RCL_SERVER, 0);
+
+ rc = req_capsule_server_pack(tsi->tsi_pill);
+ if (rc)
+ RETURN(err_serious(rc));
+
repoqc = req_capsule_server_get(tsi->tsi_pill, &RMF_OBD_QUOTACTL);
if (repoqc == NULL)
RETURN(err_serious(-ENOMEM));
-
*repoqc = *oqctl;
+ if (oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA) {
+ buffer = req_capsule_server_get(tsi->tsi_pill,
+ &RMF_OBD_QUOTA_ITER);
+ if (buffer == NULL)
+ RETURN(err_serious(-ENOMEM));
+ }
+
nodemap = nodemap_get_from_exp(tsi->tsi_exp);
if (IS_ERR(nodemap))
RETURN(PTR_ERR(nodemap));
if (repoqc->qc_id != id)
swap(repoqc->qc_id, id);
- rc = lquotactl_slv(tsi->tsi_env, tsi->tsi_tgt->lut_bottom, repoqc);
+ rc = lquotactl_slv(tsi->tsi_env, tsi->tsi_tgt->lut_bottom, repoqc,
+ buffer, buffer == NULL ? 0 : LQUOTA_ITER_BUFLEN);
ofd_counter_incr(tsi->tsi_exp, LPROC_OFD_STATS_QUOTACTL,
tsi->tsi_jobid, ktime_us_delta(ktime_get(), kstart));
OST_PUNCH, ofd_punch_hdl,
ofd_hp_punch),
TGT_OST_HDL(HAS_BODY | HAS_REPLY, OST_SYNC, ofd_sync_hdl),
-TGT_OST_HDL(HAS_REPLY, OST_QUOTACTL, ofd_quotactl),
+TGT_OST_HDL(0, OST_QUOTACTL, ofd_quotactl),
TGT_OST_HDL(HAS_BODY | HAS_REPLY, OST_LADVISE, ofd_ladvise_hdl),
TGT_OST_HDL(HAS_BODY | HAS_REPLY | IS_MUTABLE, OST_FALLOCATE, ofd_fallocate_hdl),
TGT_OST_HDL(HAS_BODY | HAS_REPLY, OST_SEEK, tgt_lseek),
#include <obd_class.h>
#include <lustre_osc.h>
+#include <lustre_quota.h>
#include "osc_internal.h"
int osc_quotactl(struct obd_device *unused, struct obd_export *exp,
struct obd_quotactl *oqctl)
{
- struct ptlrpc_request *req;
- struct obd_quotactl *oqc;
- int rc;
- ENTRY;
+ struct ptlrpc_request *req;
+ struct obd_quotactl *oqc;
+ int rc;
+
+ ENTRY;
- req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
- &RQF_OST_QUOTACTL, LUSTRE_OST_VERSION,
- OST_QUOTACTL);
- if (req == NULL)
- RETURN(-ENOMEM);
+ req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp),
+ &RQF_OST_QUOTACTL, LUSTRE_OST_VERSION,
+ OST_QUOTACTL);
+ if (req == NULL)
+ RETURN(-ENOMEM);
+
+ if (oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA)
+ req_capsule_set_size(&req->rq_pill, &RMF_OBD_QUOTA_ITER,
+ RCL_SERVER, LQUOTA_ITER_BUFLEN);
+ else
+ req_capsule_set_size(&req->rq_pill, &RMF_OBD_QUOTA_ITER,
+ RCL_SERVER, 0);
oqc = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
*oqc = *oqctl;
if (rc)
CERROR("ptlrpc_queue_wait failed, rc: %d\n", rc);
- if (req->rq_repmsg &&
- (oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL))) {
- *oqctl = *oqc;
- } else if (!rc) {
- CERROR ("Can't unpack obd_quotactl\n");
- rc = -EPROTO;
- }
- ptlrpc_req_finished(req);
+ if (req->rq_repmsg) {
+ struct list_head *lst = (struct list_head *)oqctl->qc_iter_list;
+
+ oqc = req_capsule_server_get(&req->rq_pill, &RMF_OBD_QUOTACTL);
+ if (!oqc)
+ GOTO(out, rc = -EPROTO);
- RETURN(rc);
+ *oqctl = *oqc;
+
+ if (oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA) {
+ void *buffer;
+ struct lquota_iter *iter;
+
+ buffer = req_capsule_server_get(&req->rq_pill,
+ &RMF_OBD_QUOTA_ITER);
+
+ if (buffer == NULL) {
+ CDEBUG(D_QUOTA, "%s: no buffer in iter req\n",
+ exp->exp_obd->obd_name);
+
+ rc = -EPROTO;
+ GOTO(out, rc);
+ }
+
+ OBD_ALLOC_LARGE(iter,
+ sizeof(struct lquota_iter) + LQUOTA_ITER_BUFLEN);
+ if (iter == NULL)
+ GOTO(out, rc = -ENOMEM);
+
+ INIT_LIST_HEAD(&iter->li_link);
+ list_add(&iter->li_link, lst);
+
+ memcpy(iter->li_buffer, buffer, LQUOTA_ITER_BUFLEN);
+ iter->li_dt_size = oqctl->qc_iter_dt_buflen;
+ oqctl->qc_iter_md_buflen = 0;
+ oqctl->qc_iter_dt_buflen = 0;
+ }
+ } else if (!rc) {
+ CERROR("%s: cannot unpack obd_quotactl: rc = %d\n",
+ exp->exp_obd->obd_name, rc);
+
+ rc = -EPROTO;
+ }
+
+out:
+ ptlrpc_req_finished(req);
+
+ RETURN(rc);
}
&RMF_OBD_QUOTACTL
};
+static const struct req_msg_field *quotactl_server_only[] = {
+ &RMF_PTLRPC_BODY,
+ &RMF_OBD_QUOTACTL,
+ &RMF_OBD_QUOTA_ITER
+};
+
static const struct req_msg_field *quota_body_only[] = {
&RMF_PTLRPC_BODY,
&RMF_QUOTA_BODY
lustre_swab_obd_quotactl, NULL);
EXPORT_SYMBOL(RMF_OBD_QUOTACTL);
+struct req_msg_field RMF_OBD_QUOTA_ITER =
+ DEFINE_MSGFL("quota_iter_key", 0, -1, NULL, NULL);
+EXPORT_SYMBOL(RMF_OBD_QUOTA_ITER);
+
struct req_msg_field RMF_QUOTA_BODY =
DEFINE_MSGF("quota_body", 0,
sizeof(struct quota_body), lustre_swab_quota_body, NULL);
EXPORT_SYMBOL(RQF_FLD_READ);
struct req_format RQF_MDS_QUOTACTL =
- DEFINE_REQ_FMT0("MDS_QUOTACTL", quotactl_only, quotactl_only);
+ DEFINE_REQ_FMT0("MDS_QUOTACTL", quotactl_only, quotactl_server_only);
EXPORT_SYMBOL(RQF_MDS_QUOTACTL);
struct req_format RQF_OST_QUOTACTL =
- DEFINE_REQ_FMT0("OST_QUOTACTL", quotactl_only, quotactl_only);
+ DEFINE_REQ_FMT0("OST_QUOTACTL", quotactl_only, quotactl_server_only);
EXPORT_SYMBOL(RQF_OST_QUOTACTL);
struct req_format RQF_QUOTA_DQACQ =
void lquota_generate_fid(struct lu_fid *, int, int);
int lquota_extract_fid(const struct lu_fid *, int *, int *);
const struct dt_index_features *glb_idx_feature(struct lu_fid *);
+int lquota_obj_iter(const struct lu_env *env, struct dt_device *dev,
+ struct dt_object *obj, struct obd_quotactl *oqctl,
+ char *buffer, int size, bool is_glb, bool is_md);
/* lquota_entry.c */
/* site create/destroy */
}
/*
+ * Iterate quota settings managed by \a obj.
+ *
+ * \param env - is the environment passed by the caller
+ * \param dev - is the backend device holding the quota object
+ * \param obj - is the quota object to be iterated
+ * \param oqctl - is the quota ioctl object passed in by caller
+ * \param buf - is the buffer to save the retrieved quota settings
+ * \param size - is the size of the buffer
+ * \param is_glb - true to iterate the global quota settings
+ * \param is_md - true to iterate LQUOTA_MD quota settings
+ */
+int lquota_obj_iter(const struct lu_env *env, struct dt_device *dev,
+ struct dt_object *obj, struct obd_quotactl *oqctl,
+ char *buf, int size, bool is_glb, bool is_md)
+{
+ struct lquota_thread_info *qti = lquota_info(env);
+ const struct dt_it_ops *iops;
+ struct dt_it *it;
+ struct dt_key *key;
+ struct dt_rec *rec = (struct dt_rec *)&qti->qti_rec;
+ __u64 offset;
+ bool skip = true;
+ int cur = 0, rc;
+ int rec_size;
+
+ ENTRY;
+
+ iops = &obj->do_index_ops->dio_it;
+ it = iops->init(env, obj, 0);
+ if (IS_ERR(it)) {
+ rc = PTR_ERR(it);
+ CERROR("%s: failed to initialize iterator: rc = %ld\n",
+ obj->do_lu.lo_dev->ld_obd->obd_name, PTR_ERR(it));
+ RETURN(rc);
+ }
+
+ rc = iops->load(env, it, 0);
+ if (rc <= 0) {
+ if (is_md)
+ oqctl->qc_iter_md_offset = 0;
+ else
+ oqctl->qc_iter_dt_offset = 0;
+
+ GOTO(out_fini, rc);
+ }
+
+ if ((is_md && oqctl->qc_iter_md_offset == 0) ||
+ (!is_md && oqctl->qc_iter_dt_offset == 0))
+ skip = false;
+
+ if (is_glb)
+ rec_size = sizeof(struct lquota_glb_rec);
+ else
+ rec_size = sizeof(struct lquota_acct_rec);
+
+ if (is_md)
+ offset = oqctl->qc_iter_md_offset;
+ else
+ offset = oqctl->qc_iter_dt_offset;
+
+ while ((size - cur) > (sizeof(__u64) + rec_size)) {
+ if (!skip)
+ goto get_setting;
+
+ if (offset == iops->store(env, it))
+ skip = false;
+ else {
+ rc = iops->next(env, it);
+ if (rc < 0) {
+ CERROR("%s: next failed: rc = %d\n",
+ obj->do_lu.lo_dev->ld_obd->obd_name, rc);
+ break;
+ }
+
+ /* reach the end */
+ if (rc > 0) {
+ if (is_md)
+ oqctl->qc_iter_md_offset = 0;
+ else
+ oqctl->qc_iter_dt_offset = 0;
+
+ break;
+ }
+
+ continue;
+ }
+
+get_setting:
+ key = iops->key(env, it);
+ if (IS_ERR(key)) {
+ CERROR("%s: failed to get key: rc = %ld\n",
+ obj->do_lu.lo_dev->ld_obd->obd_name,
+ PTR_ERR(key));
+
+ GOTO(out_fini, rc = PTR_ERR(key));
+ }
+
+ rc = iops->rec(env, it, rec, 0);
+ if (rc) {
+ CERROR("%s: failed to get rec: rc = %d\n",
+ obj->do_lu.lo_dev->ld_obd->obd_name, rc);
+ GOTO(out_fini, rc);
+ }
+
+ if (oqctl->qc_iter_qid_end != 0 &&
+ (*((__u64 *)key) < oqctl->qc_iter_qid_start ||
+ *((__u64 *)key) > oqctl->qc_iter_qid_end))
+ goto next;
+
+ memcpy(buf + cur, key, sizeof(__u64));
+ cur += sizeof(__u64);
+
+ memcpy(buf + cur, rec, rec_size);
+ cur += rec_size;
+
+next:
+ rc = iops->next(env, it);
+ if (rc < 0) {
+ CERROR("%s: next failed: rc = %d\n",
+ obj->do_lu.lo_dev->ld_obd->obd_name, rc);
+
+ GOTO(out_fini, rc);
+ }
+
+ /* reach the end */
+ if (rc > 0) {
+ if (is_md)
+ oqctl->qc_iter_md_offset = 0;
+ else
+ oqctl->qc_iter_dt_offset = 0;
+
+ break;
+ }
+
+ if (is_md)
+ oqctl->qc_iter_md_offset = iops->store(env, it);
+ else
+ oqctl->qc_iter_dt_offset = iops->store(env, it);
+ }
+
+out_fini:
+ if (rc >= 0) {
+ if (is_md)
+ oqctl->qc_iter_md_buflen = cur;
+ else
+ oqctl->qc_iter_dt_buflen = cur;
+
+ rc = 0;
+ }
+
+ iops->put(env, it);
+ iops->fini(env, it);
+ return rc < 0 ? rc : 0;
+}
+
+/*
* Helper routine to retrieve slave information.
* This function converts a quotactl request into quota/accounting object
* operations. It is independant of the slave stack which is only accessible
* \param oqctl - is the quotactl request
*/
int lquotactl_slv(const struct lu_env *env, struct dt_device *dev,
- struct obd_quotactl *oqctl)
+ struct obd_quotactl *oqctl, char *buffer, int size)
{
- struct lquota_thread_info *qti = lquota_info(env);
+ struct lquota_thread_info *qti = lquota_info(env);
__u64 key;
struct dt_object *obj, *obj_aux = NULL;
struct obd_dqblk *dqblk = &oqctl->qc_dqblk;
int rc;
ENTRY;
- if (oqctl->qc_cmd != Q_GETOQUOTA) {
+ if (oqctl->qc_cmd != Q_GETOQUOTA &&
+ oqctl->qc_cmd != LUSTRE_Q_ITEROQUOTA) {
/* as in many other places, dev->dd_lu_dev.ld_obd->obd_name
* point to an invalid obd_name, to be fixed in LU-1574 */
CERROR("%s: Unsupported quotactl command: %x\n",
if (obj->do_index_ops == NULL)
GOTO(out, rc = -EINVAL);
+ if (oqctl->qc_cmd == LUSTRE_Q_ITEROQUOTA) {
+ if (lu_device_is_md(dev->dd_lu_dev.ld_site->ls_top_dev))
+ rc = lquota_obj_iter(env, dev, obj, oqctl, buffer, size,
+ false, true);
+ else
+ rc = lquota_obj_iter(env, dev, obj, oqctl, buffer, size,
+ false, false);
+
+ GOTO(out, rc);
+ }
+
/* lookup record storing space accounting information for this ID */
rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_acct_rec,
(struct dt_key *)&key);
struct lqe_glbl_data *lgd = lqe_gl->lqe_glbl_data;
if (reseed) {
- qmt_seed_glbe_all(env, lgd, qunit, edquot);
+ qmt_seed_glbe_all(env, lgd, qunit, edquot,
+ false);
} else if (idx >= 0) {
int lge_idx = qmt_map_lge_idx(lgd, idx);
mutex_lock(&lqe_gl->lqe_glbl_data_lock);
if (lqe_gl->lqe_glbl_data)
- qmt_seed_glbe(env, lqe_gl->lqe_glbl_data);
+ qmt_seed_glbe(env, lqe_gl->lqe_glbl_data, false);
mutex_unlock(&lqe_gl->lqe_glbl_data_lock);
qmt_id_lock_notify(qmt, lqe_gl);
}
void qmt_seed_glbe_all(const struct lu_env *env, struct lqe_glbl_data *lgd,
- bool qunit, bool edquot)
+ bool qunit, bool edquot, bool pool_locked)
{
struct qmt_pool_info *qpi;
int i, j;
CDEBUG(D_QUOTA, "lqes_cnt %d, i %d\n", qti_lqes_cnt(env), i);
qpi = lqe2qpi(lqe);
- qmt_sarr_read_down(qpi);
+ if (!pool_locked)
+ qmt_sarr_read_down(qpi);
+
slaves_cnt = qmt_sarr_count(qpi);
for (j = 0; j < slaves_cnt; j++) {
}
}
- qmt_sarr_read_up(qpi);
+ if (!pool_locked)
+ qmt_sarr_read_up(qpi);
}
/* TODO: only for debug purposes - remove it later */
for (i = 0; i < lgd->lqeg_num_used; i++)
qmt_pool_lqes_lookup_spec(env, qmt, pool_type,
lqe_qtype(lqe), &lqe->lqe_id);
- qmt_seed_glbe(env, lgd);
+ qmt_seed_glbe(env, lgd, false);
lqe->lqe_glbl_data = lgd;
qmt_id_lock_notify(qmt, lqe);
mutex_lock(&lqe_gl->lqe_glbl_data_lock);
if (lqe_gl->lqe_glbl_data)
- qmt_seed_glbe(env, lqe_gl->lqe_glbl_data);
+ qmt_seed_glbe(env, lqe_gl->lqe_glbl_data, false);
mutex_unlock(&lqe_gl->lqe_glbl_data_lock);
/* Even if slaves haven't enqueued quota lock yet,
th = qmt_trans_start(env, lqe);
if (IS_ERR(th))
GOTO(out_nolock, rc = PTR_ERR(th));
+
+ if (CFS_FAIL_CHECK(OBD_FAIL_QUOTA_NOSYNC))
+ th->th_sync = 0;
}
now = ktime_get_real_seconds();
if (IS_ERR(th))
GOTO(out, rc = PTR_ERR(th));
+ if (CFS_FAIL_CHECK(OBD_FAIL_QUOTA_NOSYNC))
+ th->th_sync = 0;
+
lqe_write_lock(lqe);
rc = lquota_disk_delete(env, th,
qpi->qpi_glb_obj[qtype], qid, &ver);
* \param oqctl - is the quotactl request
*/
static int qmt_quotactl(const struct lu_env *env, struct lu_device *ld,
- struct obd_quotactl *oqctl)
+ struct obd_quotactl *oqctl, char *buffer, int size)
{
struct qmt_thread_info *qti = qmt_info(env);
union lquota_id *id = &qti->qti_id;
struct qmt_device *qmt = lu2qmt_dev(ld);
+ struct dt_object *glb_obj;
struct obd_dqblk *dqb = &oqctl->qc_dqblk;
+ struct qmt_pool_info *pool;
char *poolname;
int rc = 0;
bool is_default = false;
+ bool is_first_iter = false;
ENTRY;
LASSERT(qmt != NULL);
poolname);
break;
+ case LUSTRE_Q_ITERQUOTA:
+ if (oqctl->qc_iter_md_offset == 0 &&
+ oqctl->qc_iter_dt_offset == 0)
+ is_first_iter = true;
+
+ if (is_first_iter || oqctl->qc_iter_md_offset != 0) {
+ pool = qmt_pool_lookup_name(env, qmt, LQUOTA_RES_MD,
+ NULL);
+ if (IS_ERR(pool))
+ RETURN(PTR_ERR(pool));
+
+ glb_obj = pool->qpi_glb_obj[oqctl->qc_type];
+ rc = lquota_obj_iter(env, lu2dt_dev(ld), glb_obj,
+ oqctl, buffer, size / 2, true, true);
+
+ qpi_putref(env, pool);
+
+ if (rc < 0 && rc != -ENOENT)
+ break;
+
+ rc = 0;
+ } else {
+ oqctl->qc_iter_md_buflen = 0;
+ }
+
+ if (is_first_iter || oqctl->qc_iter_dt_offset != 0) {
+ pool = qmt_pool_lookup_name(env, qmt, LQUOTA_RES_DT,
+ NULL);
+ if (IS_ERR(pool))
+ RETURN(PTR_ERR(pool));
+
+ glb_obj = pool->qpi_glb_obj[oqctl->qc_type];
+ rc = lquota_obj_iter(env, lu2dt_dev(ld), glb_obj,
+ oqctl, buffer + size / 2, size / 2,
+ true, false);
+ qpi_putref(env, pool);
+
+ if (rc < 0 && rc != -ENOENT)
+ break;
+
+ rc = 0;
+ } else {
+ oqctl->qc_iter_dt_buflen = 0;
+ }
+ break;
+
case LUSTRE_Q_GETDEFAULT:
case LUSTRE_Q_GETDEFAULT_POOL:
is_default = true;
void qmt_setup_lqe_gd(const struct lu_env *, struct qmt_device *,
struct lquota_entry *, struct lqe_glbl_data *, int);
#define qmt_seed_glbe_edquot(env, lqeg) \
- qmt_seed_glbe_all(env, lqeg, false, true)
+ qmt_seed_glbe_all(env, lqeg, false, true, false)
#define qmt_seed_glbe_qunit(env, lqeg) \
- qmt_seed_glbe_all(env, lqeg, true, false)
-#define qmt_seed_glbe(env, lqeg) \
- qmt_seed_glbe_all(env, lqeg, true, true)
+ qmt_seed_glbe_all(env, lqeg, true, false, false)
+#define qmt_seed_glbe(env, lqeg, pool_locked) \
+ qmt_seed_glbe_all(env, lqeg, true, true, pool_locked)
void qmt_seed_glbe_all(const struct lu_env *, struct lqe_glbl_data *,
- bool , bool);
+ bool, bool, bool);
/* qmt_handler.c */
int qmt_set_with_lqe(const struct lu_env *env, struct qmt_device *qmt,
struct lquota_entry *lqeg = qti_lqes_glbl(env);
mutex_lock(&lqeg->lqe_glbl_data_lock);
- if (lqeg->lqe_glbl_data)
- qmt_seed_glbe(env, lqeg->lqe_glbl_data);
+ if (lqeg->lqe_glbl_data &&
+ qti_lqes_cnt(env) > 0)
+ qmt_seed_glbe(env, lqeg->lqe_glbl_data,
+ true);
mutex_unlock(&lqeg->lqe_glbl_data_lock);
qmt_id_lock_notify(qmt, lqeg);
}
req_capsule_set_size(tsi->tsi_pill, &RMF_FILE_ENCCTX,
RCL_SERVER, 0);
+ if (req_capsule_has_field(tsi->tsi_pill, &RMF_OBD_QUOTA_ITER,
+ RCL_SERVER)) {
+ req_capsule_set_size(tsi->tsi_pill,
+ &RMF_OBD_QUOTA_ITER, RCL_SERVER, 0);
+ }
+
rc = req_capsule_server_pack(tsi->tsi_pill);
}
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
+#include <sys/ioctl.h>
#include <time.h>
#include <unistd.h>
+#include <lustre/lustreapi.h>
#include <linux/lustre/lustre_user.h>
#include <lustre/lustreapi.h>
"\t-u\tunlink file/dir (with optional <unlinkfmt>)\n");
printf("\t-d\tuse directories instead of regular files\n"
"\t-t\tstop creating files after <seconds> have elapsed\n");
+ printf("\t-S\tthe file size\n"
+ "\t-U\tthe start User ID of the file\n"
+ "\t-G\tthe start Group ID of the file\n"
+ "\t-P\tthe start Project ID of the file\n");
exit(EXIT_FAILURE);
}
{
bool do_open = false, do_keep = false, do_link = false;
bool do_unlink = false, do_mknod = false, do_mkdir = false;
+ bool do_setsize = false, do_chuid = false, do_chgid = false;
+ bool do_chprj = false;
bool do_rmdir = false;
int stripe_pattern = LMV_HASH_TYPE_FNV_1A_64;
int stripe_offset = -1, stripe_count = 1;
int has_fmt_spec = 0, unlink_has_fmt_spec = 0;
long i, total, last_i = 0;
int c, last_fd = -1, stderr_fd;
+ unsigned int uid = 0, gid = 0, pid = 0;
+ int size = 0;
int rc = 0;
/* Handle the deprecated positional last argument "-seconds" */
else
progname = argv[0];
- while ((c = getopt(argc, argv, "i:dl:kmor::t:u::")) != -1) {
+ while ((c = getopt(argc, argv, "i:dG:l:kmor::S:t:u::U:")) != -1) {
switch (c) {
case 'd':
do_mkdir = true;
break;
+ case 'G':
+ do_chgid = true;
+ gid = strtoul(optarg, NULL, 0);
+ break;
case 'i':
stripe_offset = strtoul(optarg, &endp, 0);
if (*endp != '\0') {
case 'o':
do_open = true;
break;
+ case 'P':
+ do_chprj = true;
+ pid = strtoul(optarg, NULL, 0);
+ break;
+ case 'S':
+ do_setsize = true;
+ size = atoi(optarg);
+ break;
case 't':
end = strtol(optarg, &endp, 0);
if (end <= 0.0 || *endp != '\0')
do_unlink = true;
fmt_unlink = optarg;
break;
+ case 'U':
+ do_chuid = true;
+ uid = strtoul(optarg, NULL, 0);
+ break;
case '?':
fprintf(stderr, "Unknown option '%c'\n", optopt);
usage(progname);
}
}
+ if (!do_open && (do_setsize || do_chuid || do_chgid || do_chprj)) {
+ fprintf(stderr, "error: -S, -U, -G, -P works only with -o\n");
+ usage(progname);
+ }
+
if (do_open + do_mkdir + do_link + do_mknod > 1 ||
do_open + do_mkdir + do_link + do_mknod + do_unlink == 0) {
fprintf(stderr, "error: only one of -o, -m, -l, -d\n");
rc = errno;
break;
}
+ if (do_setsize) {
+ rc = lseek(fd, (size - 6) < 0 ? 0 : size - 6,
+ SEEK_SET);
+ if (rc < 0) {
+ printf("lseek(%s, %d) error: %s\n",
+ filename, size, strerror(errno));
+ break;
+ }
+ rc = write(fd, "Lustre", 6);
+ if (rc < 0) {
+ printf("write(%s, %d) error: %s\n",
+ filename, 6, strerror(errno));
+ break;
+ }
+ }
+
+ if (do_chuid || do_chgid) {
+ rc = fchown(fd, do_chuid ? uid + i : -1,
+ do_chgid ? gid + i : -1);
+ if (rc < 0) {
+ printf("fchown(%s, %u, %u) error: %s\n",
+ filename, do_chuid ? uid : -1,
+ do_chgid ? gid : -1,
+ strerror(errno));
+ break;
+ }
+ }
+
+ if (do_chprj) {
+ struct fsxattr fsx;
+
+ rc = ioctl(fd, FS_IOC_FSGETXATTR, &fsx);
+ if (rc < 0) {
+ printf("ioctl(%s) error: %s\n",
+ "FS_IOC_GETXATTR",
+ strerror(errno));
+ break;
+ }
+
+ fsx.fsx_projid = pid + i;
+ rc = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
+ if (rc < 0) {
+ printf("ioctl(%s, %d) error: %s\n",
+ "FS_IOC_SETXATTR", pid,
+ strerror(errno));
+ break;
+ }
+ }
+
if (!do_keep)
close(fd);
else if (fd > last_fd)
}
run_test 48 "lfs quota --delete should delete quota project ID"
+test_get_allquota() {
+ local file_cnt=$1
+ local start_qid=$2
+ local end_qid=$3
+ local u_blimit=$4
+ local u_ilimit=$5
+ local g_blimit=$6
+ local g_ilimit=$7
+ local TFILE="$DIR/$tdir/$tfile-0"
+
+ local u_blimits
+ local u_ilimits
+ local g_blimits
+ local g_ilimits
+ local u_busage
+ local u_busage2
+ local g_busage
+ local g_busage2
+ local u_iusage
+ local u_iusage2
+ local g_iusage
+ local g_iusage2
+ local start
+ local total
+
+ local qid_cnt=$file_cnt
+
+ [ $end_qid -ne 0 ] && qid_cnt=$((end_qid - start_qid + 1))
+ [ $end_qid -ge $file_cnt ] &&
+ qid_cnt=$((qid_cnt - end_qid + file_cnt))
+ [ $qid_cnt -le 0 ] && error "quota ID count is wrong"
+
+ cnt=$($LFS quota -a -s $start_qid -e $end_qid -u $MOUNT | wc -l)
+ [ $cnt -ge $((qid_cnt + 2)) ] || error "failed to get all usr quota"
+ cnt=$($LFS quota -a -s $start_qid -e $end_qid -g $MOUNT | wc -l)
+ [ $cnt -ge $((qid_cnt + 2)) ] || error "failed to get all grp quota"
+
+ cancel_lru_locks osc
+ sync; sync_all_data || true
+ sleep 5
+
+ eval $($LFS quota -a -s $start_qid -e $end_qid -u $MOUNT |
+ awk 'NR > 2 {printf("u_blimits[%d]=%d;u_ilimits[%d]=%d; \
+ u_busage[%d]=%d;u_iusage[%d]=%d;", \
+ NR, $4, NR, $8, NR, $2, NR, $6)}')
+ eval $($LFS quota -a -s $start_qid -e $end_qid -g $MOUNT |
+ awk 'NR > 2 {printf("g_blimits[%d]=%d;g_ilimits[%d]=%d; \
+ g_busage[%d]=%d;g_iusage[%d]=%d;", \
+ NR, $4, NR, $8, NR, $2, NR, $6)}')
+
+ for i in $(seq $qid_cnt); do
+ [ $i -le 2 ] && continue
+
+ [ ${u_ilimits[$i]} -eq $u_ilimit ] ||
+ error "file limit for user ID $((start_qid + i - 3)) is wrong"
+ [ ${u_blimits[$i]} -eq $u_blimit ] ||
+ error "block limit for user ID $((start_qid + i - 3)) is wrong"
+ [ ${g_ilimits[$i]} -eq $g_ilimit ] ||
+ error "file limit for group ID $((start_qid + i - 3)) is wrong"
+ [ ${g_blimits[$i]} -eq $g_blimit ] ||
+ error "block limit for group ID $((start_qid + i - 3)) is wrong"
+ done
+
+ echo "Create $qid_cnt files..."
+ createmany -S 4k -U $start_qid -G $start_qid -o ${TFILE} $qid_cnt ||
+ error "failed to create many files"
+
+ cancel_lru_locks osc
+ sync; sync_all_data || true
+ sleep 5
+
+ start=$SECONDS
+ $LFS quota -a -s $start_qid -e $end_qid -u $MOUNT | tail -n 50
+ total=$((SECONDS - start))
+ (( end - start > 0 )) &&
+ echo "time=$total, rate=$((qid_cnt / total))/s" ||
+ echo "time=0, rate=$qid_cnt/0"
+
+ start=$SECONDS
+ $LFS quota -a -s $start_qid -e $end_qid -g $MOUNT | tail -n 50
+ total=$((SECONDS - start))
+ (( end - start > 0 )) &&
+ echo "time=$total, rate=$((qid_cnt / total))/s" ||
+ echo "time=0, rate=$qid_cnt/0"
+
+ cnt=$($LFS quota -a -s $start_qid -e $end_qid -u $MOUNT | wc -l)
+ [ $cnt -ge $((qid_cnt + 2)) ] || error "failed to get all usr quota"
+ cnt=$($LFS quota -a -s $start_qid -e $end_qid -g $MOUNT | wc -l)
+ [ $cnt -ge $((qid_cnt + 2)) ] || error "failed to get all grp quota"
+
+ eval $($LFS quota -a -s $start_qid -e $end_qid -u $MOUNT |
+ awk 'NR > 2 {printf("u_blimits[%d]=%d;u_ilimits[%d]=%d; \
+ u_busage2[%d]=%d;u_iusage2[%d]=%d;", \
+ NR, $4, NR, $8, NR, $2, NR, $6)}')
+ eval $($LFS quota -a -s $start_qid -e $end_qid -g $MOUNT |
+ awk 'NR > 2 {printf("g_blimits[%d]=%d;g_ilimits[%d]=%d; \
+ g_busage2[%d]=%d;g_iusage2[%d]=%d;", \
+ NR, $4, NR, $8, NR, $2, NR, $6)}')
+
+ sz=$((sz / 1024))
+ for i in $(seq $qid_cnt); do
+ [ $i -le 2 ] && continue
+
+ [ ${u_ilimits[$i]} -eq $u_ilimit ] ||
+ error "file limit for user ID $((start_qid + i - 3)) is wrong"
+ [ ${u_blimits[$i]} -eq $u_blimit ] ||
+ error "block limit for user ID $((start_qid + i - 3)) is wrong"
+ [ ${g_ilimits[$i]} -eq $g_ilimit ] ||
+ error "file limit for group ID $((start_qid + i - 3)) is wrong"
+ [ ${g_blimits[$i]} -eq $g_blimit ] ||
+ error "block limit for group ID $((start_qid + i - 3)) is wrong"
+ [ ${u_iusage2[$i]} -eq $((u_iusage[$i] + 1)) ] ||
+ error "file usage for user ID $((start_qid + i - 3)) is wrong ${u_iusage[$i]}, ${u_iusage2[$i]}"
+ [ ${u_busage2[$i]} -ge $((u_busage[$i] + 4)) ] ||
+ error "block usage for user ID $((start_qid + i - 3)) is wrong ${u_busage[$i]}, ${u_busage2[$i]}"
+ [ ${g_iusage2[$i]} -eq $((g_iusage[$i] + 1)) ] ||
+ error "file usage for group ID $((start_qid + i - 3)) is wrong ${g_iusage[$i]}, ${g_iusage2[$i]}"
+ [ ${g_busage2[$i]} -ge $((g_busage[$i] + 4)) ] ||
+ error "block usage for group ID $((start_qid + i - 3)) is wrong ${g_busage[$i]}, ${g_busage2[$i]}"
+ done
+
+ unlinkmany ${TFILE} $qid_cnt
+}
+
+test_49()
+{
+ (( MDS1_VERSION >= $(version_code 2.15.60) )) ||
+ skip "Need MDS version at least 2.15.60"
+
+ local u_blimit=102400
+ local u_ilimit=10240
+ local g_blimit=204800
+ local g_ilimit=20480
+ local count=10
+
+ setup_quota_test || error "setup quota failed with $?"
+ stack_trap cleanup_quota_test EXIT
+
+ [ "$SLOW" = "yes" ] && total_file_cnt=20000 || total_file_cnt=1000
+ total_file_cnt=${NUM_QIDS:-$total_file_cnt}
+
+ local start=$SECONDS
+
+ echo "setquota for users and groups"
+ #define OBD_FAIL_QUOTA_NOSYNC 0xA09
+ do_facet mds1 $LCTL set_param fail_loc=0xa09
+ for i in $(seq $total_file_cnt); do
+ $LFS setquota -u $i -B ${u_blimit} -I ${u_ilimit} $MOUNT ||
+ error "failed to setquota for usr $i"
+ $LFS setquota -g $i -B ${g_blimit} -I ${g_ilimit} $MOUNT ||
+ error "failed to setquota for grp $i"
+ (( i % 1000 == 0)) &&
+ echo "lfs setquota: $i / $((SECONDS - start)) seconds"
+ done
+ do_facet mds1 $LCTL set_param fail_loc=0
+
+ start=$SECONDS
+ $LFS quota -a -u $MOUNT | tail -n 100
+ echo "get all usr quota: $total_file_cnt / $((SECONDS - start)) seconds"
+
+ start=$SECONDS
+ $LFS quota -a -g $MOUNT | tail -n 100
+ echo "get all grp quota: $total_file_cnt / $((SECONDS - start)) seconds"
+
+ while true; do
+ test_get_allquota $total_file_cnt $count $((count + 5000)) \
+ $u_blimit $u_ilimit $g_blimit $g_ilimit
+ test_get_allquota $total_file_cnt $count $((count + 5000)) \
+ $u_blimit $u_ilimit $g_blimit $g_ilimit
+
+ count=$((count + 5000))
+ [ $count -gt $total_file_cnt ] && break
+ done;
+
+ do_facet mds1 $LCTL set_param fail_loc=0xa08
+ for i in $(seq $total_file_cnt); do
+ $LFS setquota -u $i --delete $MOUNT
+ $LFS setquota -g $i --delete $MOUNT
+ done
+ do_facet mds1 $LCTL set_param fail_loc=0
+
+ formatall
+ setupall
+}
+run_test 49 "lfs quota -a prints the quota usage for all quota IDs"
+
test_50() {
! is_project_quota_supported &&
skip "Project quota is not supported"
wait_update_facet "--quiet" mds1 \
"$LCTL get_param -n qmt.$FSNAME-QMT0000.dt-$pool.info \
>/dev/null 2>&1 || echo foo" "">/dev/null ||
- error "mds1: failed to create quota pool $pool"
+ error "mds1: failed to create quota pool $pool"
do_facet mds1 $LCTL get_param -n qmt.$FSNAME-QMT0000.dt-$pool.info |
awk '/usr/ {getline; print $2}'
" [{-u|-g|-p} UNAME|UID|GNAME|GID|PROJID]\n"
" [--pool <OST pool name>] <filesystem>\n"
" quota -t <-u|-g|-p> [--pool <OST pool name>] <filesystem>\n"
- " quota [-q] [-v] [h] {-U|-G|-P} [--pool <OST pool name>] <filesystem>"},
+ " quota [-q] [-v] [h] {-U|-G|-P} [--pool <OST pool name>] <filesystem>\n"
+ " quota -a {-u|-g|-p} [-s start_qid] [-e end_qid] <filesystem>"},
{"project", lfs_project, 0,
"Change or list project attribute for specified file or directory.\n"
"usage: project [-d|-r] <file|directory...>\n"
#define STRBUF_LEN 24
static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
- int rc, bool h, bool show_default)
+ int rc, bool h, bool show_default, bool show_qid)
{
+ char *name;
time_t now;
time(&now);
iover = 3;
}
- if (strlen(mnt) > 15)
- printf("%s\n%15s", mnt, "");
- else
- printf("%15s", mnt);
+ if (show_qid) {
+ if (qctl->qc_type == USRQUOTA) {
+ if (uid2name(&name, qctl->qc_id))
+ printf("%10u", qctl->qc_id);
+ else
+ printf("%10s", name);
+ } else if (qctl->qc_type == GRPQUOTA) {
+ if (gid2name(&name, qctl->qc_id))
+ printf("%10u", qctl->qc_id);
+ else
+ printf("%10s", name);
+ } else {
+ printf("%10u", qctl->qc_id);
+ }
+ } else {
+ if (strlen(mnt) > 15)
+ printf("%s\n%15s", mnt, "");
+ else
+ printf("%15s", mnt);
+ }
if (show_default)
snprintf(timebuf, sizeof(timebuf), "%llu",
memset(&qctl->qc_dqblk, 0,
sizeof(qctl->qc_dqblk));
print_quota(name, qctl, qctl->qc_valid, 0, h,
- false);
+ false, false);
rc = 0;
continue;
}
}
print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
- qctl->qc_valid, 0, h, false);
+ qctl->qc_valid, 0, h, false, false);
*total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
qctl->qc_dqblk.dqb_bhardlimit;
}
return rc ? : rc1;
}
-static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
+static int print_one_quota(char *mnt, char *name, struct if_quotactl *qctl,
int verbose, int quiet, bool human_readable,
- bool show_default)
+ bool show_default, bool show_qid, int rc)
{
- int rc1 = 0, rc2 = 0, rc3 = 0;
+ int rc1 = 0, rc2 = 0;
char *obd_type = (char *)qctl->obd_type;
char *obd_uuid = (char *)qctl->obd_uuid.uuid;
__u64 total_ialloc = 0, total_balloc = 0;
bool use_default_for_file = false;
int inacc;
- rc1 = llapi_quotactl(mnt, qctl);
- if (rc1 < 0) {
- switch (rc1) {
- case -ESRCH:
- fprintf(stderr, "%s quotas are not enabled.\n",
- qtype_name(qctl->qc_type));
- goto out;
- case -EPERM:
- fprintf(stderr, "Permission denied.\n");
- case -ENODEV:
- case -ENOENT:
- /* We already got error message. */
- goto out;
- default:
- fprintf(stderr, "Unexpected quotactl error: %s\n",
- strerror(-rc1));
- }
- }
-
if (!show_default && qctl->qc_id == 0) {
qctl->qc_dqblk.dqb_bhardlimit = 0;
qctl->qc_dqblk.dqb_bsoftlimit = 0;
qctl->qc_dqblk.dqb_itime &= LQUOTA_GRACE_MASK;
}
- if ((qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
+ if (!show_qid && (qctl->qc_cmd == LUSTRE_Q_GETQUOTA ||
qctl->qc_cmd == LUSTRE_Q_GETQUOTAPOOL ||
qctl->qc_cmd == LUSTRE_Q_GETDEFAULT_POOL ||
qctl->qc_cmd == LUSTRE_Q_GETDEFAULT) && !quiet)
print_quota_title(name, qctl, human_readable, show_default);
- if (rc1 && *obd_type)
+ if (rc && *obd_type)
fprintf(stderr, "%s %s ", obd_type, obd_uuid);
if (qctl->qc_valid != QC_GENERAL)
((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
(QIF_LIMITS|QIF_USAGE));
- print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable, show_default);
+ print_quota(mnt, qctl, QC_GENERAL, rc, human_readable, show_default,
+ show_qid);
- if (!show_default && verbose &&
+ if (!show_qid && !show_default && verbose &&
qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
qctl->qc_cmd != LUSTRE_Q_GETINFOPOOL) {
char strbuf[STRBUF_LEN];
- rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
+ rc1 = print_obd_quota(mnt, qctl, 1, human_readable,
&total_ialloc);
- rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
+ rc2 = print_obd_quota(mnt, qctl, 0, human_readable,
&total_balloc);
kbytes2str(total_balloc, strbuf, sizeof(strbuf),
human_readable);
printf("%cid %u is using default file quota setting\n",
*qtype_name(qctl->qc_type), qctl->qc_id);
- if (rc1 || rc2 || rc3 || inacc)
- printf("Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n");
-out:
+ if (!show_qid && (rc || rc1 || rc2 || inacc))
+ printf("%d Some errors happened when getting quota info. Some devices may be not working or deactivated. The data in \"[]\" is inaccurate.\n", inacc);
+
+ if (rc)
+ return rc;
if (rc1)
return rc1;
if (rc2)
return rc2;
- if (rc3)
- return rc3;
if (inacc)
return -EIO;
return 0;
}
+static int iter_all_quota(char *mnt, struct if_quotactl *qctl, int quiet,
+ bool human_readable)
+{
+ struct if_quotactl qctl_tmp, *qctl_iter;
+ void *buffer = NULL;
+ __u64 mark;
+ __u64 cur, buflen = 0;
+ int rc = 0;
+
+ memcpy(&qctl_tmp, qctl, sizeof(struct if_quotactl));
+ qctl_tmp.qc_cmd = LUSTRE_Q_ITERQUOTA;
+ rc = llapi_quotactl(mnt, &qctl_tmp);
+ if (rc)
+ goto out;
+
+ buflen = qctl_tmp.qc_allquota_count * sizeof(struct if_quotactl);
+ buffer = malloc(buflen);
+ if (buffer == NULL) {
+ rc = -ENOMEM;
+ goto out;
+ }
+
+ mark = qctl_tmp.qc_allquota_mark;
+ memcpy(&qctl_tmp, qctl, sizeof(struct if_quotactl));
+ qctl_tmp.qc_cmd = LUSTRE_Q_GETALLQUOTA;
+ qctl_tmp.qc_allquota_buffer = (__u64)buffer;
+ qctl_tmp.qc_allquota_buflen = buflen;
+ qctl_tmp.qc_allquota_mark = mark;
+ rc = llapi_quotactl(mnt, &qctl_tmp);
+ if (rc)
+ goto out;
+
+ printf("Filesystem %s, Disk %s quotas\n", mnt,
+ qtype_name(qctl->qc_type));
+ printf("%10s%8s %7s%8s%8s%8s %7s%8s%8s\n", "quota_id",
+ human_readable ? "used" : "kbytes", "quota", "limit", "grace",
+ "files", "quota", "limit", "grace");
+
+ cur = 0;
+ while (cur < buflen) {
+ if ((buflen - cur) < sizeof(struct if_quotactl)) {
+ rc = -EFAULT;
+ break;
+ }
+
+ qctl_iter = buffer + cur;
+ qctl_iter->qc_cmd = LUSTRE_Q_GETQUOTA;
+ cur += sizeof(struct if_quotactl);
+
+ /* Is no file created for this quota ID yet? */
+ if ((qctl_iter->qc_dqblk.dqb_valid & QIF_USAGE) != QIF_USAGE)
+ qctl_iter->qc_dqblk.dqb_valid |= QIF_USAGE;
+
+ print_one_quota(mnt, NULL, qctl_iter, 0, quiet,
+ human_readable, false, true, 0);
+ }
+
+out:
+ if (buffer != NULL)
+ free(buffer);
+
+ if (rc)
+ fprintf(stderr, "get all quota failed %d\n", rc);
+
+ return rc;
+}
+
+static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
+ int verbose, int quiet, bool human_readable,
+ bool show_default)
+{
+ int rc;
+
+ rc = llapi_quotactl(mnt, qctl);
+ if (rc < 0) {
+ switch (rc) {
+ case -ESRCH:
+ fprintf(stderr, "%s quotas are not enabled.\n",
+ qtype_name(qctl->qc_type));
+ break;
+ case -EPERM:
+ fprintf(stderr, "Permission denied.\n");
+ case -ENODEV:
+ case -ENOENT:
+ /* We already got error message. */
+ break;
+ default:
+ fprintf(stderr, "Unexpected quotactl error: %s\n",
+ strerror(-rc));
+ }
+
+ return rc;
+ }
+
+ return print_one_quota(mnt, name, qctl, verbose, quiet, human_readable,
+ show_default, false, rc);
+}
+
static int lfs_project(int argc, char **argv)
{
int ret = 0, err = 0, c, i;
char *obd_uuid;
int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
__u32 valid = QC_GENERAL, idx = 0;
+ __u32 start_qid = 0, end_qid = 0;
bool human_readable = false;
bool show_default = false;
int qtype;
qctl->qc_type = ALLQUOTA;
obd_uuid = (char *)qctl->obd_uuid.uuid;
- while ((c = getopt_long(argc, argv, "gGi:I:o:pPqtuUvh",
+ while ((c = getopt_long(argc, argv, "ae:gGi:I:o:pPqs:tuUvh",
long_opts, NULL)) != -1) {
switch (c) {
case 'U':
}
qctl->qc_type = qtype;
break;
+ case 'a':
+ qctl->qc_cmd = LUSTRE_Q_ITERQUOTA;
+ break;
case 't':
qctl->qc_cmd = LUSTRE_Q_GETINFO;
break;
goto out;
}
break;
+ case 's':
+ start_qid = strtoul(optarg, NULL, 0);
+ break;
+ case 'e':
+ end_qid = strtoul(optarg, NULL, 0);
+ break;
case 'v':
verbose = 1;
break;
goto out;
}
}
+ } else if (qctl->qc_cmd == LUSTRE_Q_ITERQUOTA) {
+ if (optind + 1 != argc) {
+ fprintf(stderr,
+ "%s quota: mount point must be specified\n",
+ progname);
+ rc = CMD_HELP;
+ goto out;
+ }
+
+ if (qctl->qc_type == ALLQUOTA) {
+ fprintf(stderr, "%s quota: no quota type to iterate\n",
+ progname);
+ rc = CMD_HELP;
+ goto out;
+ }
+
+ if (end_qid != 0 && start_qid > end_qid) {
+ fprintf(stderr,
+ "%s quota: end qid is smaller than start qid\n",
+ progname);
+ rc = CMD_HELP;
+ goto out;
+ }
+
+ qctl->qc_allquota_qid_start = start_qid;
+ qctl->qc_allquota_qid_end = end_qid;
+ rc = iter_all_quota(argv[optind], qctl, quiet, human_readable);
+ goto out;
} else if (optind + 1 != argc || qctl->qc_type == ALLQUOTA) {
fprintf(stderr, "%s quota: missing quota info argument(s)\n",
progname);