X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fosc%2Fosc_quota.c;h=3325cf952ba2c315a079c83e76d4f0e8b181bc5a;hb=2c126c5a73edea434456c6c335772daaac717f2f;hp=3d2b45b8e12009ff6d8f41c80b9f4d6b1c9acacf;hpb=3a92c850b094019e556577ec6cab5907538dcbf5;p=fs%2Flustre-release.git diff --git a/lustre/osc/osc_quota.c b/lustre/osc/osc_quota.c index 3d2b45b..3325cf9 100644 --- a/lustre/osc/osc_quota.c +++ b/lustre/osc/osc_quota.c @@ -23,237 +23,248 @@ /* * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved. * - * Copyright (c) 2012, Whamcloud, Inc. + * Copyright (c) 2012, 2017, Intel Corporation. * * Code originally extracted from quota directory */ -#ifndef __KERNEL__ -# include -#endif -#include -#include "osc_internal.h" +#include +#include -struct osc_quota_info { - cfs_list_t oqi_hash; /* hash list */ - struct client_obd *oqi_cli; /* osc obd */ - unsigned int oqi_id; /* uid/gid of a file */ - short oqi_type; /* quota type */ -}; +#include "osc_internal.h" -cfs_spinlock_t qinfo_list_lock = CFS_SPIN_LOCK_UNLOCKED; +static inline struct osc_quota_info *osc_oqi_alloc(u32 id) +{ + struct osc_quota_info *oqi; -static cfs_list_t qinfo_hash[NR_DQHASH]; -/* SLAB cache for client quota context */ -cfs_mem_cache_t *qinfo_cachep = NULL; + OBD_SLAB_ALLOC_PTR(oqi, osc_quota_kmem); + if (oqi != NULL) + oqi->oqi_id = id; -static inline int hashfn(struct client_obd *cli, unsigned long id, int type) - __attribute__((__const__)); + return oqi; +} -static inline int hashfn(struct client_obd *cli, unsigned long id, int type) +int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[]) { - unsigned long tmp = ((unsigned long)cli>>6) ^ id; - tmp = (tmp * (MAXQUOTAS - type)) % NR_DQHASH; - return tmp; + int type; + ENTRY; + + for (type = 0; type < LL_MAXQUOTAS; type++) { + struct osc_quota_info *oqi; + + oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]); + if (oqi) { + /* do not try to access oqi here, it could have been + * freed by osc_quota_setdq() */ + + /* the slot is busy, the user is about to run out of + * quota space on this OST */ + CDEBUG(D_QUOTA, "chkdq found noquota for %s %d\n", + type == USRQUOTA ? "user" : "grout", qid[type]); + RETURN(NO_QUOTA); + } + } + + RETURN(QUOTA_OK); } -/* caller must hold qinfo_list_lock */ -static inline void insert_qinfo_hash(struct osc_quota_info *oqi) +static inline u32 md_quota_flag(int qtype) { - cfs_list_t *head = qinfo_hash + - hashfn(oqi->oqi_cli, oqi->oqi_id, oqi->oqi_type); - - LASSERT_SPIN_LOCKED(&qinfo_list_lock); - cfs_list_add(&oqi->oqi_hash, head); + switch (qtype) { + case USRQUOTA: + return OBD_MD_FLUSRQUOTA; + case GRPQUOTA: + return OBD_MD_FLGRPQUOTA; + case PRJQUOTA: + return OBD_MD_FLPRJQUOTA; + default: + return 0; + } } -/* caller must hold qinfo_list_lock */ -static inline void remove_qinfo_hash(struct osc_quota_info *oqi) +static inline u32 fl_quota_flag(int qtype) { - LASSERT_SPIN_LOCKED(&qinfo_list_lock); - cfs_list_del_init(&oqi->oqi_hash); + switch (qtype) { + case USRQUOTA: + return OBD_FL_NO_USRQUOTA; + case GRPQUOTA: + return OBD_FL_NO_GRPQUOTA; + case PRJQUOTA: + return OBD_FL_NO_PRJQUOTA; + default: + return 0; + } } -/* caller must hold qinfo_list_lock */ -static inline struct osc_quota_info *find_qinfo(struct client_obd *cli, - unsigned int id, int type) +int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[], + u64 valid, u32 flags) { - struct osc_quota_info *oqi; - unsigned int hashent = hashfn(cli, id, type); + int type; + int rc = 0; + ENTRY; - LASSERT_SPIN_LOCKED(&qinfo_list_lock); - cfs_list_for_each_entry(oqi, &qinfo_hash[hashent], oqi_hash) { - if (oqi->oqi_cli == cli && - oqi->oqi_id == id && oqi->oqi_type == type) - RETURN(oqi); - } - RETURN(NULL); + if ((valid & (OBD_MD_FLALLQUOTA)) == 0) + RETURN(0); + + for (type = 0; type < LL_MAXQUOTAS; type++) { + struct osc_quota_info *oqi; + + if ((valid & md_quota_flag(type)) == 0) + continue; + + /* lookup the ID in the per-type hash table */ + oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]); + if ((flags & fl_quota_flag(type)) != 0) { + /* This ID is getting close to its quota limit, let's + * switch to sync I/O */ + if (oqi != NULL) + continue; + + oqi = osc_oqi_alloc(qid[type]); + if (oqi == NULL) { + rc = -ENOMEM; + break; + } + + rc = cfs_hash_add_unique(cli->cl_quota_hash[type], + &qid[type], &oqi->oqi_hash); + /* race with others? */ + if (rc == -EALREADY) { + rc = 0; + OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem); + } + + CDEBUG(D_QUOTA, "%s: setdq to insert for %s %d (%d)\n", + cli_name(cli), qtype_name(type), qid[type], rc); + } else { + /* This ID is now off the hook, let's remove it from + * the hash table */ + if (oqi == NULL) + continue; + + oqi = cfs_hash_del_key(cli->cl_quota_hash[type], + &qid[type]); + if (oqi) + OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem); + + CDEBUG(D_QUOTA, "%s: setdq to remove for %s %d (%p)\n", + cli_name(cli), qtype_name(type), qid[type], oqi); + } + } + + RETURN(rc); } -static struct osc_quota_info *alloc_qinfo(struct client_obd *cli, - unsigned int id, int type) +/* + * Hash operations for uid/gid <-> osc_quota_info + */ +static unsigned +oqi_hashfn(struct cfs_hash *hs, const void *key, unsigned mask) { - struct osc_quota_info *oqi; - ENTRY; + return cfs_hash_u32_hash(*((__u32*)key), mask); +} - OBD_SLAB_ALLOC_PTR(oqi, qinfo_cachep); - if(!oqi) - RETURN(NULL); +static int +oqi_keycmp(const void *key, struct hlist_node *hnode) +{ + struct osc_quota_info *oqi; + u32 uid; - CFS_INIT_LIST_HEAD(&oqi->oqi_hash); - oqi->oqi_cli = cli; - oqi->oqi_id = id; - oqi->oqi_type = type; + LASSERT(key != NULL); + uid = *((u32 *)key); + oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash); - RETURN(oqi); + return uid == oqi->oqi_id; } -static void free_qinfo(struct osc_quota_info *oqi) +static void * +oqi_key(struct hlist_node *hnode) { - OBD_SLAB_FREE(oqi, qinfo_cachep, sizeof(*oqi)); + struct osc_quota_info *oqi; + oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash); + return &oqi->oqi_id; } -int osc_quota_chkdq(struct client_obd *cli, const unsigned int qid[]) +static void * +oqi_object(struct hlist_node *hnode) { - unsigned int id; - int cnt, rc = QUOTA_OK; - ENTRY; - - cfs_spin_lock(&qinfo_list_lock); - for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - struct osc_quota_info *oqi = NULL; - - id = (cnt == USRQUOTA) ? qid[USRQUOTA] : qid[GRPQUOTA]; - oqi = find_qinfo(cli, id, cnt); - if (oqi) { - rc = NO_QUOTA; - break; - } - } - cfs_spin_unlock(&qinfo_list_lock); - - if (rc == NO_QUOTA) - CDEBUG(D_QUOTA, "chkdq found noquota for %s %d\n", - cnt == USRQUOTA ? "user" : "group", id); - RETURN(rc); + return hlist_entry(hnode, struct osc_quota_info, oqi_hash); } -int osc_quota_setdq(struct client_obd *cli, const unsigned int qid[], - obd_flag valid, obd_flag flags) +static void +oqi_get(struct cfs_hash *hs, struct hlist_node *hnode) { - unsigned int id; - obd_flag noquota; - int cnt, rc = 0; - ENTRY; - - for (cnt = 0; cnt < MAXQUOTAS; cnt++) { - struct osc_quota_info *oqi = NULL, *old; - - if (!(valid & ((cnt == USRQUOTA) ? - OBD_MD_FLUSRQUOTA : OBD_MD_FLGRPQUOTA))) - continue; - - id = (cnt == USRQUOTA) ? qid[USRQUOTA] : qid[GRPQUOTA]; - noquota = (cnt == USRQUOTA) ? - (flags & OBD_FL_NO_USRQUOTA) : (flags & OBD_FL_NO_GRPQUOTA); - - if (noquota) { - oqi = alloc_qinfo(cli, id, cnt); - if (!oqi) { - rc = -ENOMEM; - CDEBUG(D_QUOTA, "setdq for %s %d failed, " - "(rc = %d)\n", - cnt == USRQUOTA ? "user" : "group", - id, rc); - break; - } - } - - cfs_spin_lock(&qinfo_list_lock); - old = find_qinfo(cli, id, cnt); - if (old && !noquota) - remove_qinfo_hash(old); - else if (!old && noquota) - insert_qinfo_hash(oqi); - cfs_spin_unlock(&qinfo_list_lock); - - if (old && !noquota) - CDEBUG(D_QUOTA, "setdq to remove for %s %d\n", - cnt == USRQUOTA ? "user" : "group", id); - else if (!old && noquota) - CDEBUG(D_QUOTA, "setdq to insert for %s %d\n", - cnt == USRQUOTA ? "user" : "group", id); - - if (old) { - if (noquota) - free_qinfo(oqi); - else - free_qinfo(old); - } - } - RETURN(rc); } -int osc_quota_cleanup(struct obd_device *obd) +static void +oqi_put_locked(struct cfs_hash *hs, struct hlist_node *hnode) { - struct client_obd *cli = &obd->u.cli; - struct osc_quota_info *oqi, *n; - int i; - ENTRY; - - cfs_spin_lock(&qinfo_list_lock); - for (i = 0; i < NR_DQHASH; i++) { - cfs_list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) { - if (oqi->oqi_cli != cli) - continue; - remove_qinfo_hash(oqi); - free_qinfo(oqi); - } - } - cfs_spin_unlock(&qinfo_list_lock); - - RETURN(0); } -int osc_quota_init() +static void +oqi_exit(struct cfs_hash *hs, struct hlist_node *hnode) { - int i; - ENTRY; + struct osc_quota_info *oqi; - LASSERT(qinfo_cachep == NULL); - qinfo_cachep = cfs_mem_cache_create("osc_quota_info", - sizeof(struct osc_quota_info), - 0, 0); - if (!qinfo_cachep) - RETURN(-ENOMEM); + oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash); - for (i = 0; i < NR_DQHASH; i++) - CFS_INIT_LIST_HEAD(qinfo_hash + i); - - RETURN(0); + OBD_SLAB_FREE_PTR(oqi, osc_quota_kmem); } -int osc_quota_exit() +#define HASH_QUOTA_BKT_BITS 5 +#define HASH_QUOTA_CUR_BITS 5 +#define HASH_QUOTA_MAX_BITS 15 + +static struct cfs_hash_ops quota_hash_ops = { + .hs_hash = oqi_hashfn, + .hs_keycmp = oqi_keycmp, + .hs_key = oqi_key, + .hs_object = oqi_object, + .hs_get = oqi_get, + .hs_put_locked = oqi_put_locked, + .hs_exit = oqi_exit, +}; + +int osc_quota_setup(struct obd_device *obd) { - struct osc_quota_info *oqi, *n; - int i, rc; - ENTRY; + struct client_obd *cli = &obd->u.cli; + int i, type; + ENTRY; + + for (type = 0; type < LL_MAXQUOTAS; type++) { + cli->cl_quota_hash[type] = cfs_hash_create("QUOTA_HASH", + HASH_QUOTA_CUR_BITS, + HASH_QUOTA_MAX_BITS, + HASH_QUOTA_BKT_BITS, + 0, + CFS_HASH_MIN_THETA, + CFS_HASH_MAX_THETA, + "a_hash_ops, + CFS_HASH_DEFAULT); + if (cli->cl_quota_hash[type] == NULL) + break; + } + + if (type == LL_MAXQUOTAS) + RETURN(0); + + for (i = 0; i < type; i++) + cfs_hash_putref(cli->cl_quota_hash[i]); + + RETURN(-ENOMEM); +} - cfs_spin_lock(&qinfo_list_lock); - for (i = 0; i < NR_DQHASH; i++) { - cfs_list_for_each_entry_safe(oqi, n, &qinfo_hash[i], oqi_hash) { - remove_qinfo_hash(oqi); - free_qinfo(oqi); - } - } - cfs_spin_unlock(&qinfo_list_lock); +int osc_quota_cleanup(struct obd_device *obd) +{ + struct client_obd *cli = &obd->u.cli; + int type; + ENTRY; - rc = cfs_mem_cache_destroy(qinfo_cachep); - LASSERTF(rc == 0, "couldn't destory qinfo_cachep slab\n"); - qinfo_cachep = NULL; + for (type = 0; type < LL_MAXQUOTAS; type++) + cfs_hash_putref(cli->cl_quota_hash[type]); - RETURN(0); + RETURN(0); } int osc_quotactl(struct obd_device *unused, struct obd_export *exp, @@ -292,86 +303,3 @@ int osc_quotactl(struct obd_device *unused, struct obd_export *exp, RETURN(rc); } - -int osc_quotacheck(struct obd_device *unused, struct obd_export *exp, - struct obd_quotactl *oqctl) -{ - struct client_obd *cli = &exp->exp_obd->u.cli; - struct ptlrpc_request *req; - struct obd_quotactl *body; - int rc; - ENTRY; - - req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp), - &RQF_OST_QUOTACHECK, LUSTRE_OST_VERSION, - OST_QUOTACHECK); - if (req == NULL) - RETURN(-ENOMEM); - - body = req_capsule_client_get(&req->rq_pill, &RMF_OBD_QUOTACTL); - *body = *oqctl; - - ptlrpc_request_set_replen(req); - - /* the next poll will find -ENODATA, that means quotacheck is - * going on */ - cli->cl_qchk_stat = -ENODATA; - rc = ptlrpc_queue_wait(req); - if (rc) - cli->cl_qchk_stat = rc; - ptlrpc_req_finished(req); - RETURN(rc); -} - -int osc_quota_poll_check(struct obd_export *exp, struct if_quotacheck *qchk) -{ - struct client_obd *cli = &exp->exp_obd->u.cli; - int rc; - ENTRY; - - qchk->obd_uuid = cli->cl_target_uuid; - memcpy(qchk->obd_type, LUSTRE_OST_NAME, strlen(LUSTRE_OST_NAME)); - - rc = cli->cl_qchk_stat; - /* the client is not the previous one */ - if (rc == CL_NOT_QUOTACHECKED) - rc = -EINTR; - RETURN(rc); -} - -int osc_quota_adjust_qunit(struct obd_export *exp, - struct quota_adjust_qunit *oqaq, - struct lustre_quota_ctxt *qctxt, - struct ptlrpc_request_set *rqset) -{ - struct ptlrpc_request *req; - struct quota_adjust_qunit *oqa; - int rc = 0; - ENTRY; - - /* client don't support this kind of operation, abort it */ - if (!(exp->exp_connect_flags & OBD_CONNECT_CHANGE_QS)) { - CDEBUG(D_QUOTA, "osc: %s don't support change qunit size\n", - exp->exp_obd->obd_name); - RETURN(rc); - } - if (strcmp(exp->exp_obd->obd_type->typ_name, LUSTRE_OSC_NAME)) - RETURN(-EINVAL); - - LASSERT(rqset); - - req = ptlrpc_request_alloc_pack(class_exp2cliimp(exp), - &RQF_OST_QUOTA_ADJUST_QUNIT, - LUSTRE_OST_VERSION, - OST_QUOTA_ADJUST_QUNIT); - if (req == NULL) - RETURN(-ENOMEM); - - oqa = req_capsule_client_get(&req->rq_pill, &RMF_QUOTA_ADJUST_QUNIT); - *oqa = *oqaq; - - ptlrpc_request_set_replen(req); - - ptlrpc_set_add_req(rqset, req); - RETURN(rc); -}