X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fquota%2Flquota_lib.c;h=8bbc58b3591979237561a860481c30265fdf895f;hb=b5d7edd5077829d87eef5a2863b6ca9649d17120;hp=0f5d984314705a83986adf3b362197bb4d4d2220;hpb=57df6353ca590f32a32c0f0dc4a1d10a86a027ec;p=fs%2Flustre-release.git diff --git a/lustre/quota/lquota_lib.c b/lustre/quota/lquota_lib.c index 0f5d984..8bbc58b 100644 --- a/lustre/quota/lquota_lib.c +++ b/lustre/quota/lquota_lib.c @@ -21,59 +21,146 @@ * GPL HEADER END */ /* - * Copyright (c) 2011, 2012, Whamcloud, Inc. + * Copyright (c) 2012, 2017, Intel Corporation. * Use is subject to license terms. * - * Author: Johann Lombardi - * Author: Niu Yawei + * Author: Johann Lombardi + * Author: Niu Yawei */ -#ifndef EXPORT_SYMTAB -# define EXPORT_SYMTAB -#endif - #define DEBUG_SUBSYSTEM S_LQUOTA +#include +#include +#include + #include "lquota_internal.h" -static struct dt_object_format dt_acct_format = { - .dof_type = DFT_INDEX, - .u.dof_idx.di_feat = &dt_acct_features +struct kmem_cache *lqe_kmem; + +struct lu_kmem_descr lquota_caches[] = { + { + .ckd_cache = &lqe_kmem, + .ckd_name = "lqe_kmem", + .ckd_size = sizeof(struct lquota_entry) + }, + { + .ckd_cache = NULL + } }; +/* register lquota key */ +LU_KEY_INIT_FINI(lquota, struct lquota_thread_info); +LU_CONTEXT_KEY_DEFINE(lquota, LCT_MD_THREAD | LCT_DT_THREAD | LCT_LOCAL); +LU_KEY_INIT_GENERIC(lquota); + +static inline __u32 qtype2acct_oid(int qtype) +{ + switch (qtype) { + case USRQUOTA: + return ACCT_USER_OID; + case GRPQUOTA: + return ACCT_GROUP_OID; + case PRJQUOTA: + return ACCT_PROJECT_OID; + } + + return ACCT_GROUP_OID; +} + /** * Look-up accounting object to collect space usage information for user * or group. * - * \param env - is the environment passed by the caller - * \param dev - is the dt_device storing the accounting object - * \param oid - is the object id of the accounting object to initialize, must be - * either ACCT_USER_OID or ACCT_GROUP_OID. + * \param env - is the environment passed by the caller + * \param dev - is the dt_device storing the accounting object + * \param type - is the quota type, either USRQUOTA or GRPQUOTA */ struct dt_object *acct_obj_lookup(const struct lu_env *env, - struct dt_device *dev, __u32 oid) + struct dt_device *dev, int type) { - struct dt_object *obj = NULL; - struct lu_fid fid; - struct lu_attr attr; - int rc; + struct lquota_thread_info *qti = lquota_info(env); + struct dt_object *obj = NULL; ENTRY; - memset(&attr, 0, sizeof(attr)); - attr.la_valid = LA_MODE; - attr.la_mode = S_IFREG | S_IRUGO | S_IWUSR; - lu_local_obj_fid(&fid, oid); + lu_local_obj_fid(&qti->qti_fid, qtype2acct_oid(type)); - /* lookup/create the accounting object */ - obj = dt_find_or_create(env, dev, &fid, &dt_acct_format, &attr); + /* lookup the accounting object */ + obj = dt_locate(env, dev, &qti->qti_fid); if (IS_ERR(obj)) RETURN(obj); + if (!dt_object_exists(obj)) { + dt_object_put(env, obj); + RETURN(ERR_PTR(-ENOENT)); + } + if (obj->do_index_ops == NULL) { + int rc; + /* set up indexing operations */ rc = obj->do_ops->do_index_try(env, obj, &dt_acct_features); if (rc) { - lu_object_put(env, &obj->do_lu); + CERROR("%s: failed to set up indexing operations for %s" + " acct object rc:%d\n", + dev->dd_lu_dev.ld_obd->obd_name, + qtype_name(type), rc); + dt_object_put(env, obj); + RETURN(ERR_PTR(rc)); + } + } + RETURN(obj); +} + +/** + * Initialize slave index object to collect local quota limit for user or group. + * + * \param env - is the environment passed by the caller + * \param dev - is the dt_device storing the slave index object + * \param pool - is the pool type, either LQUOTA_RES_MD or LQUOTA_RES_DT + * \param type - is the quota type, either USRQUOTA or GRPQUOTA + */ +static struct dt_object *quota_obj_lookup(const struct lu_env *env, + struct dt_device *dev, int pool, + int type) +{ + struct lquota_thread_info *qti = lquota_info(env); + struct dt_object *obj = NULL; + int is_md; + ENTRY; + + is_md = lu_device_is_md(dev->dd_lu_dev.ld_site->ls_top_dev); + if ((is_md && pool == LQUOTA_RES_MD) || + (!is_md && pool == LQUOTA_RES_DT)) + qti->qti_fid.f_oid = qtype2slv_oid(type); + else + qti->qti_fid.f_oid = pool << 16 | qtype2slv_oid(type); + + qti->qti_fid.f_seq = FID_SEQ_QUOTA; + qti->qti_fid.f_ver = 0; + + /* lookup the quota object */ + obj = dt_locate(env, dev, &qti->qti_fid); + if (IS_ERR(obj)) + RETURN(obj); + + if (!dt_object_exists(obj)) { + dt_object_put(env, obj); + RETURN(ERR_PTR(-ENOENT)); + } + + if (obj->do_index_ops == NULL) { + int rc; + + /* set up indexing operations */ + rc = obj->do_ops->do_index_try(env, obj, + &dt_quota_slv_features); + if (rc) { + CERROR("%s: failed to set up indexing operations for %s" + " slave index object rc:%d\n", + dev->dd_lu_dev.ld_obd->obd_name, + qtype_name(type), rc); + dt_object_put(env, obj); RETURN(ERR_PTR(rc)); } } @@ -93,51 +180,220 @@ struct dt_object *acct_obj_lookup(const struct lu_env *env, int lquotactl_slv(const struct lu_env *env, struct dt_device *dev, struct obd_quotactl *oqctl) { - struct acct_rec rec; - __u64 key; - struct dt_object *obj; - int rc = 0; + 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) { /* as in many other places, dev->dd_lu_dev.ld_obd->obd_name - * point to a valid obd_name, to be fixed in LU-1574 */ + * point to an invalid obd_name, to be fixed in LU-1574 */ CERROR("%s: Unsupported quotactl command: %x\n", dev->dd_lu_dev.ld_obd->obd_name, oqctl->qc_cmd); RETURN(-EOPNOTSUPP); } - if (oqctl->qc_type == USRQUOTA) - obj = acct_obj_lookup(env, dev, ACCT_USER_OID); - else if (oqctl->qc_type == GRPQUOTA) - obj = acct_obj_lookup(env, dev, ACCT_GROUP_OID); - else - /* no support for directory quota yet */ + if (oqctl->qc_type < 0 || oqctl->qc_type >= LL_MAXQUOTAS) RETURN(-EOPNOTSUPP); + /* qc_id is a 32-bit field while a key has 64 bits */ + key = oqctl->qc_id; + + /* Step 1: collect accounting information */ + + obj = acct_obj_lookup(env, dev, oqctl->qc_type); if (IS_ERR(obj)) RETURN(-EOPNOTSUPP); if (obj->do_index_ops == NULL) GOTO(out, rc = -EINVAL); - /* qc_id is a 32-bit field while a key has 64 bits */ - key = oqctl->qc_id; - /* lookup record storing space accounting information for this ID */ - rc = dt_lookup(env, obj, (struct dt_rec *)&rec, (struct dt_key *)&key, - BYPASS_CAPA); + rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_acct_rec, + (struct dt_key *)&key); if (rc < 0) GOTO(out, rc); memset(&oqctl->qc_dqblk, 0, sizeof(struct obd_dqblk)); - oqctl->qc_dqblk.dqb_curspace = rec.bspace; - oqctl->qc_dqblk.dqb_curinodes = rec.ispace; - oqctl->qc_dqblk.dqb_valid = QIF_USAGE; - /* TODO: must set {hard,soft}limit and grace time */ + dqblk->dqb_curspace = qti->qti_acct_rec.bspace; + dqblk->dqb_curinodes = qti->qti_acct_rec.ispace; + dqblk->dqb_valid = QIF_USAGE; + + dt_object_put(env, obj); + + /* Step 2: collect enforcement information */ + + if (lu_device_is_md(dev->dd_lu_dev.ld_site->ls_top_dev)) + obj = quota_obj_lookup(env, dev, LQUOTA_RES_MD, oqctl->qc_type); + else + obj = quota_obj_lookup(env, dev, LQUOTA_RES_DT, oqctl->qc_type); + + if (IS_ERR(obj)) + RETURN(0); + if (obj->do_index_ops == NULL) + GOTO(out, rc = 0); - EXIT; + memset(&qti->qti_slv_rec, 0, sizeof(qti->qti_slv_rec)); + /* lookup record storing enforcement information for this ID */ + rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_slv_rec, + (struct dt_key *)&key); + if (rc < 0 && rc != -ENOENT) + GOTO(out, rc = 0); + + if (lu_device_is_md(dev->dd_lu_dev.ld_site->ls_top_dev)) { + dqblk->dqb_ihardlimit = qti->qti_slv_rec.qsr_granted; + dqblk->dqb_bhardlimit = 0; + + obj_aux = quota_obj_lookup(env, dev, LQUOTA_RES_DT, + oqctl->qc_type); + if (IS_ERR(obj_aux)) { + obj_aux = NULL; + GOTO(out, rc = 0); + } + + if (obj_aux->do_index_ops == NULL) + GOTO(out, rc = 0); + + memset(&qti->qti_slv_rec, 0, sizeof(qti->qti_slv_rec)); + rc = dt_lookup(env, obj_aux, (struct dt_rec *)&qti->qti_slv_rec, + (struct dt_key *)&key); + if (rc < 0 && rc != -ENOENT) + GOTO(out, rc = 0); + + dqblk->dqb_bhardlimit = qti->qti_slv_rec.qsr_granted; + } else { + dqblk->dqb_ihardlimit = 0; + dqblk->dqb_bhardlimit = qti->qti_slv_rec.qsr_granted; + } + dqblk->dqb_valid |= QIF_LIMITS; + + GOTO(out, rc = 0); out: - lu_object_put(env, &obj->do_lu); - return rc; + dt_object_put(env, obj); + if (obj_aux != NULL) + dt_object_put(env, obj_aux); + return rc; } EXPORT_SYMBOL(lquotactl_slv); + +static inline __u8 qtype2lqtype(int qtype) +{ + switch (qtype) { + case USRQUOTA: + return LQUOTA_TYPE_USR; + case GRPQUOTA: + return LQUOTA_TYPE_GRP; + case PRJQUOTA: + return LQUOTA_TYPE_PRJ; + } + + return LQUOTA_TYPE_GRP; +} + +static inline int lqtype2qtype(int lqtype) +{ + switch (lqtype) { + case LQUOTA_TYPE_USR: + return USRQUOTA; + case LQUOTA_TYPE_GRP: + return GRPQUOTA; + case LQUOTA_TYPE_PRJ: + return PRJQUOTA; + } + + return GRPQUOTA; +} + +/** + * Helper routine returning the FID associated with the global index storing + * quota settings for default storage pool, resource type \pool_type and + * the quota type \quota_type. + */ +void lquota_generate_fid(struct lu_fid *fid, int pool_type, int quota_type) +{ + __u8 lqtype = qtype2lqtype(quota_type); + + fid->f_seq = FID_SEQ_QUOTA_GLB; + fid->f_oid = (lqtype << 24) | (pool_type << 16); + fid->f_ver = 0; +} + +/** + * Helper routine used to extract pool type and quota type from a + * given FID. + */ +int lquota_extract_fid(const struct lu_fid *fid, int *pool_type, + int *quota_type) +{ + unsigned int lqtype; + ENTRY; + + if (fid->f_seq != FID_SEQ_QUOTA_GLB) + RETURN(-EINVAL); + + if (pool_type != NULL) { + lqtype = (fid->f_oid >> 16) & 0xffU; + if (lqtype >= LQUOTA_LAST_RES) + RETURN(-ENOTSUPP); + + *pool_type = lqtype; + } + + if (quota_type != NULL) { + lqtype = fid->f_oid >> 24; + if (lqtype >= LQUOTA_TYPE_MAX) + RETURN(-ENOTSUPP); + + *quota_type = lqtype2qtype(lqtype); + } + + RETURN(0); +} + +static int __init lquota_init(void) +{ + int rc; + ENTRY; + + lquota_key_init_generic(&lquota_thread_key, NULL); + lu_context_key_register(&lquota_thread_key); + + rc = lu_kmem_init(lquota_caches); + if (rc) + GOTO(out_key, rc); + + rc = qmt_glb_init(); + if (rc) + GOTO(out_caches, rc); + + rc = qsd_glb_init(); + if (rc) + GOTO(out_qmt, rc); + + RETURN(0); + +out_qmt: + qmt_glb_fini(); +out_caches: + lu_kmem_fini(lquota_caches); +out_key: + lu_context_key_degister(&lquota_thread_key); + return rc; +} + +static void __exit lquota_exit(void) +{ + qsd_glb_fini(); + qmt_glb_fini(); + lu_kmem_fini(lquota_caches); + lu_context_key_degister(&lquota_thread_key); +} + +MODULE_AUTHOR("OpenSFS, Inc. "); +MODULE_DESCRIPTION("Lustre Quota"); +MODULE_VERSION(LUSTRE_VERSION_STRING); +MODULE_LICENSE("GPL"); + +module_init(lquota_init); +module_exit(lquota_exit);