#include <obd_class.h>
#include "osc_internal.h"
+static const struct rhashtable_params quota_hash_params = {
+ .key_len = sizeof(u32),
+ .key_offset = offsetof(struct osc_quota_info, oqi_id),
+ .head_offset = offsetof(struct osc_quota_info, oqi_hash),
+ .automatic_shrinking = true,
+};
+
static inline struct osc_quota_info *osc_oqi_alloc(u32 id)
{
struct osc_quota_info *oqi;
for (type = 0; type < MAXQUOTAS; type++) {
struct osc_quota_info *oqi;
- oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
+ oqi = rhashtable_lookup_fast(&cli->cl_quota_hash[type], &qid[type],
+ quota_hash_params);
if (oqi) {
- /* do not try to access oqi here, it could have been
+ /* Must not access oqi here, it could have been
* freed by osc_quota_setdq()
*/
return QUOTA_OK;
}
+static void osc_quota_free(struct rcu_head *head)
+{
+ struct osc_quota_info *oqi = container_of(head, struct osc_quota_info, rcu);
+
+ kmem_cache_free(osc_quota_kmem, oqi);
+}
+
+
#define MD_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_MD_FLUSRQUOTA \
: OBD_MD_FLGRPQUOTA)
#define FL_QUOTA_FLAG(type) ((type == USRQUOTA) ? OBD_FL_NO_USRQUOTA \
continue;
/* lookup the ID in the per-type hash table */
- oqi = cfs_hash_lookup(cli->cl_quota_hash[type], &qid[type]);
+ rcu_read_lock();
+ oqi = rhashtable_lookup_fast(&cli->cl_quota_hash[type], &qid[type],
+ quota_hash_params);
if ((flags & FL_QUOTA_FLAG(type)) != 0) {
/* This ID is getting close to its quota limit, let's
* switch to sync I/O
*/
+ rcu_read_unlock();
if (oqi)
continue;
break;
}
- rc = cfs_hash_add_unique(cli->cl_quota_hash[type],
- &qid[type], &oqi->oqi_hash);
+ rc = rhashtable_lookup_insert_fast(&cli->cl_quota_hash[type],
+ &oqi->oqi_hash, quota_hash_params);
/* race with others? */
- if (rc == -EALREADY) {
- rc = 0;
+ if (rc) {
kmem_cache_free(osc_quota_kmem, oqi);
+ if (rc != -EEXIST) {
+ rc = -ENOMEM;
+ break;
+ }
+ rc = 0;
}
CDEBUG(D_QUOTA, "%s: setdq to insert for %s %d (%d)\n",
/* This ID is now off the hook, let's remove it from
* the hash table
*/
- if (!oqi)
+ if (!oqi) {
+ rcu_read_unlock();
continue;
-
- oqi = cfs_hash_del_key(cli->cl_quota_hash[type],
- &qid[type]);
- if (oqi)
- kmem_cache_free(osc_quota_kmem, oqi);
-
+ }
+ if (rhashtable_remove_fast(&cli->cl_quota_hash[type],
+ &oqi->oqi_hash, quota_hash_params) == 0)
+ call_rcu(&oqi->rcu, osc_quota_free);
+ rcu_read_unlock();
CDEBUG(D_QUOTA, "%s: setdq to remove for %s %d (%p)\n",
cli_name(cli),
type == USRQUOTA ? "user" : "group",
return rc;
}
-/*
- * Hash operations for uid/gid <-> osc_quota_info
- */
-static unsigned int
-oqi_hashfn(struct cfs_hash *hs, const void *key, unsigned int mask)
-{
- return cfs_hash_u32_hash(*((__u32 *)key), mask);
-}
-
-static int
-oqi_keycmp(const void *key, struct hlist_node *hnode)
-{
- struct osc_quota_info *oqi;
- u32 uid;
-
- LASSERT(key);
- uid = *((u32 *)key);
- oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
-
- return uid == oqi->oqi_id;
-}
-
-static void *
-oqi_key(struct hlist_node *hnode)
-{
- struct osc_quota_info *oqi;
-
- oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
- return &oqi->oqi_id;
-}
-
-static void *
-oqi_object(struct hlist_node *hnode)
-{
- return hlist_entry(hnode, struct osc_quota_info, oqi_hash);
-}
-
-static void
-oqi_get(struct cfs_hash *hs, struct hlist_node *hnode)
-{
-}
-
-static void
-oqi_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
-{
-}
-
static void
-oqi_exit(struct cfs_hash *hs, struct hlist_node *hnode)
+oqi_exit(void *vquota, void *data)
{
- struct osc_quota_info *oqi;
-
- oqi = hlist_entry(hnode, struct osc_quota_info, oqi_hash);
+ struct osc_quota_info *oqi = vquota;
- kmem_cache_free(osc_quota_kmem, oqi);
+ osc_quota_free(&oqi->rcu);
}
-#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 client_obd *cli = &obd->u.cli;
int i, type;
for (type = 0; type < 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])
+ if (rhashtable_init(&cli->cl_quota_hash[type], "a_hash_params) != 0)
break;
}
return 0;
for (i = 0; i < type; i++)
- cfs_hash_putref(cli->cl_quota_hash[i]);
+ rhashtable_destroy(&cli->cl_quota_hash[i]);
return -ENOMEM;
}
int type;
for (type = 0; type < MAXQUOTAS; type++)
- cfs_hash_putref(cli->cl_quota_hash[type]);
+ rhashtable_free_and_destroy(&cli->cl_quota_hash[type],
+ oqi_exit, NULL);
return 0;
}