struct kmem_cache *ldlm_resource_slab, *ldlm_lock_slab;
struct kmem_cache *ldlm_interval_tree_slab;
+struct kmem_cache *ldlm_inodebits_slab;
int ldlm_srv_namespace_nr = 0;
int ldlm_cli_namespace_nr = 0;
const char __user *buffer, size_t count,
loff_t *off)
{
- __s64 value;
+ struct seq_file *m = file->private_data;
+ u64 value;
__u64 watermark;
- __u64 *data = ((struct seq_file *)file->private_data)->private;
+ __u64 *data = m->private;
bool wm_low = (data == &ldlm_reclaim_threshold_mb) ? true : false;
+ char kernbuf[22] = "";
int rc;
- rc = lprocfs_str_with_units_to_s64(buffer, count, &value, 'M');
- if (rc) {
+ if (count >= sizeof(kernbuf))
+ return -EINVAL;
+
+ if (copy_from_user(kernbuf, buffer, count))
+ return -EFAULT;
+ kernbuf[count] = 0;
+
+ rc = sysfs_memparse(kernbuf, count, &value, "MiB");
+ if (rc < 0) {
CERROR("Failed to set %s, rc = %d.\n",
wm_low ? "lock_reclaim_threshold_mb" : "lock_limit_mb",
rc);
if (IS_ERR_OR_NULL(ldlm_debugfs_dir)) {
CERROR("LDebugFS failed in ldlm-init\n");
rc = ldlm_debugfs_dir ? PTR_ERR(ldlm_debugfs_dir) : -ENOMEM;
+ ldlm_debugfs_dir = NULL;
GOTO(err, rc);
}
CERROR("LProcFS failed in ldlm-init\n");
rc = ldlm_ns_debugfs_dir ? PTR_ERR(ldlm_ns_debugfs_dir)
: -ENOMEM;
- GOTO(err_type, rc);
+ GOTO(err, rc);
}
ldlm_svc_debugfs_dir = ldebugfs_register("services",
CERROR("LProcFS failed in ldlm-init\n");
rc = ldlm_svc_debugfs_dir ? PTR_ERR(ldlm_svc_debugfs_dir)
: -ENOMEM;
- GOTO(err_ns, rc);
+ GOTO(err, rc);
}
rc = ldebugfs_add_vars(ldlm_debugfs_dir, ldlm_debugfs_list, NULL);
if (rc != 0) {
CERROR("LProcFS failed in ldlm-init\n");
- GOTO(err_svc, rc);
+ GOTO(err, rc);
}
RETURN(0);
-err_svc:
- ldebugfs_remove(&ldlm_svc_debugfs_dir);
-err_ns:
- ldebugfs_remove(&ldlm_ns_debugfs_dir);
-err_type:
- ldebugfs_remove(&ldlm_debugfs_dir);
err:
+ debugfs_remove_recursive(ldlm_debugfs_dir);
ldlm_svc_debugfs_dir = NULL;
ldlm_ns_debugfs_dir = NULL;
ldlm_debugfs_dir = NULL;
void ldlm_debugfs_cleanup(void)
{
- if (!IS_ERR_OR_NULL(ldlm_svc_debugfs_dir))
- ldebugfs_remove(&ldlm_svc_debugfs_dir);
-
- if (!IS_ERR_OR_NULL(ldlm_ns_debugfs_dir))
- ldebugfs_remove(&ldlm_ns_debugfs_dir);
-
- if (!IS_ERR_OR_NULL(ldlm_debugfs_dir))
- ldebugfs_remove(&ldlm_debugfs_dir);
+ debugfs_remove_recursive(ldlm_debugfs_dir);
ldlm_svc_debugfs_dir = NULL;
ldlm_ns_debugfs_dir = NULL;
struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace,
ns_kobj);
__u64 res = 0;
- struct cfs_hash_bd bd;
int i;
/* result is not strictly consistant */
- cfs_hash_for_each_bucket(ns->ns_rs_hash, &bd, i)
- res += cfs_hash_bd_count_get(&bd);
+ for (i = 0; i < (1 << ns->ns_bucket_bits); i++)
+ res += atomic_read(&ns->ns_rs_buckets[i].nsb_count);
return sprintf(buf, "%lld\n", res);
}
LUSTRE_RO_ATTR(resource_count);
CERROR("dlm namespace %s has no procfs dir?\n",
ldlm_ns_name(ns));
else
- ldebugfs_remove(&ns->ns_debugfs_entry);
+ debugfs_remove_recursive(ns->ns_debugfs_entry);
if (ns->ns_stats != NULL)
lprocfs_free_stats(&ns->ns_stats);
return val & mask;
}
-static unsigned ldlm_res_hop_fid_hash(struct cfs_hash *hs,
- const void *key, unsigned mask)
+static unsigned int ldlm_res_hop_fid_hash(const struct ldlm_res_id *id, unsigned int bits)
{
- const struct ldlm_res_id *id = key;
struct lu_fid fid;
__u32 hash;
__u32 val;
hash += (hash >> 4) + (hash << 12); /* mixing oid and seq */
if (id->name[LUSTRE_RES_ID_HSH_OFF] != 0) {
val = id->name[LUSTRE_RES_ID_HSH_OFF];
- hash += (val >> 5) + (val << 11);
} else {
val = fid_oid(&fid);
}
- hash = hash_long(hash, hs->hs_bkt_bits);
- /* give me another random factor */
- hash -= hash_long((unsigned long)hs, val % 11 + 3);
-
- hash <<= hs->hs_cur_bits - hs->hs_bkt_bits;
- hash |= ldlm_res_hop_hash(hs, key, CFS_HASH_NBKT(hs) - 1);
-
- return hash & mask;
+ hash += (val >> 5) + (val << 11);
+ return cfs_hash_32(hash, bits);
}
static void *ldlm_res_hop_key(struct hlist_node *hnode)
.hs_put = ldlm_res_hop_put
};
-static struct cfs_hash_ops ldlm_ns_fid_hash_ops = {
- .hs_hash = ldlm_res_hop_fid_hash,
- .hs_key = ldlm_res_hop_key,
- .hs_keycmp = ldlm_res_hop_keycmp,
- .hs_keycpy = NULL,
- .hs_object = ldlm_res_hop_object,
- .hs_get = ldlm_res_hop_get_locked,
- .hs_put = ldlm_res_hop_put
-};
-
-typedef struct ldlm_ns_hash_def {
- enum ldlm_ns_type nsd_type;
+static struct {
/** hash bucket bits */
unsigned nsd_bkt_bits;
/** hash bits */
unsigned nsd_all_bits;
- /** hash operations */
- struct cfs_hash_ops *nsd_hops;
-} ldlm_ns_hash_def_t;
-
-static struct ldlm_ns_hash_def ldlm_ns_hash_defs[] =
-{
- {
- .nsd_type = LDLM_NS_TYPE_MDC,
+} ldlm_ns_hash_defs[] = {
+ [LDLM_NS_TYPE_MDC] = {
.nsd_bkt_bits = 11,
.nsd_all_bits = 16,
- .nsd_hops = &ldlm_ns_fid_hash_ops,
},
- {
- .nsd_type = LDLM_NS_TYPE_MDT,
+ [LDLM_NS_TYPE_MDT] = {
.nsd_bkt_bits = 14,
.nsd_all_bits = 21,
- .nsd_hops = &ldlm_ns_fid_hash_ops,
},
- {
- .nsd_type = LDLM_NS_TYPE_OSC,
+ [LDLM_NS_TYPE_OSC] = {
.nsd_bkt_bits = 8,
.nsd_all_bits = 12,
- .nsd_hops = &ldlm_ns_hash_ops,
},
- {
- .nsd_type = LDLM_NS_TYPE_OST,
+ [LDLM_NS_TYPE_OST] = {
.nsd_bkt_bits = 11,
.nsd_all_bits = 17,
- .nsd_hops = &ldlm_ns_hash_ops,
},
- {
- .nsd_type = LDLM_NS_TYPE_MGC,
- .nsd_bkt_bits = 4,
+ [LDLM_NS_TYPE_MGC] = {
+ .nsd_bkt_bits = 3,
.nsd_all_bits = 4,
- .nsd_hops = &ldlm_ns_hash_ops,
},
- {
- .nsd_type = LDLM_NS_TYPE_MGT,
- .nsd_bkt_bits = 4,
+ [LDLM_NS_TYPE_MGT] = {
+ .nsd_bkt_bits = 3,
.nsd_all_bits = 4,
- .nsd_hops = &ldlm_ns_hash_ops,
- },
- {
- .nsd_type = LDLM_NS_TYPE_UNKNOWN,
},
};
enum ldlm_ns_type ns_type)
{
struct ldlm_namespace *ns = NULL;
- struct ldlm_ns_bucket *nsb;
- struct ldlm_ns_hash_def *nsd;
- struct cfs_hash_bd bd;
int idx;
int rc;
RETURN(NULL);
}
- for (idx = 0; ; idx++) {
- nsd = &ldlm_ns_hash_defs[idx];
- if (nsd->nsd_type == LDLM_NS_TYPE_UNKNOWN) {
- CERROR("Unknown type %d for ns %s\n", ns_type, name);
- GOTO(out_ref, NULL);
- }
-
- if (nsd->nsd_type == ns_type)
- break;
+ if (ns_type >= ARRAY_SIZE(ldlm_ns_hash_defs) ||
+ ldlm_ns_hash_defs[ns_type].nsd_bkt_bits == 0) {
+ CERROR("Unknown type %d for ns %s\n", ns_type, name);
+ GOTO(out_ref, NULL);
}
OBD_ALLOC_PTR(ns);
GOTO(out_ref, NULL);
ns->ns_rs_hash = cfs_hash_create(name,
- nsd->nsd_all_bits, nsd->nsd_all_bits,
- nsd->nsd_bkt_bits, sizeof(*nsb),
+ ldlm_ns_hash_defs[ns_type].nsd_all_bits,
+ ldlm_ns_hash_defs[ns_type].nsd_all_bits,
+ ldlm_ns_hash_defs[ns_type].nsd_bkt_bits,
+ 0,
CFS_HASH_MIN_THETA,
CFS_HASH_MAX_THETA,
- nsd->nsd_hops,
+ &ldlm_ns_hash_ops,
CFS_HASH_DEPTH |
CFS_HASH_BIGNAME |
CFS_HASH_SPIN_BKTLOCK |
if (ns->ns_rs_hash == NULL)
GOTO(out_ns, NULL);
- cfs_hash_for_each_bucket(ns->ns_rs_hash, &bd, idx) {
- nsb = cfs_hash_bd_extra_get(ns->ns_rs_hash, &bd);
+ ns->ns_bucket_bits = ldlm_ns_hash_defs[ns_type].nsd_all_bits -
+ ldlm_ns_hash_defs[ns_type].nsd_bkt_bits;
+
+ OBD_ALLOC_LARGE(ns->ns_rs_buckets,
+ BIT(ns->ns_bucket_bits) * sizeof(ns->ns_rs_buckets[0]));
+ if (!ns->ns_rs_buckets)
+ goto out_hash;
+
+ for (idx = 0; idx < (1 << ns->ns_bucket_bits); idx++) {
+ struct ldlm_ns_bucket *nsb = &ns->ns_rs_buckets[idx];
+
at_init(&nsb->nsb_at_estimate, ldlm_enqueue_min, 0);
nsb->nsb_namespace = ns;
nsb->nsb_reclaim_start = 0;
+ atomic_set(&nsb->nsb_count, 0);
}
ns->ns_obd = obd;
ldlm_namespace_sysfs_unregister(ns);
ldlm_namespace_cleanup(ns, 0);
out_hash:
+ OBD_FREE_LARGE(ns->ns_rs_buckets,
+ BIT(ns->ns_bucket_bits) * sizeof(ns->ns_rs_buckets[0]));
kfree(ns->ns_name);
cfs_hash_putref(ns->ns_rs_hash);
out_ns:
ldlm_namespace_cleanup(ns, force ? LDLM_FL_LOCAL_ONLY : 0);
if (atomic_read(&ns->ns_bref) > 0) {
- struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL);
int rc;
CDEBUG(D_DLMTRACE,
"dlm namespace %s free waiting on refcount %d\n",
ldlm_ns_name(ns), atomic_read(&ns->ns_bref));
force_wait:
if (force)
- lwi = LWI_TIMEOUT(msecs_to_jiffies(obd_timeout *
- MSEC_PER_SEC) / 4, NULL, NULL);
-
- rc = l_wait_event(ns->ns_waitq,
- atomic_read(&ns->ns_bref) == 0, &lwi);
+ rc = wait_event_idle_timeout(
+ ns->ns_waitq,
+ atomic_read(&ns->ns_bref) == 0,
+ cfs_time_seconds(1) / 4);
+ else
+ rc = l_wait_event_abortable(
+ ns->ns_waitq, atomic_read(&ns->ns_bref) == 0);
/* Forced cleanups should be able to reclaim all references,
* so it's safe to wait forever... we can't leak locks... */
- if (force && rc == -ETIMEDOUT) {
+ if (force && rc == 0) {
+ rc = -ETIMEDOUT;
LCONSOLE_ERROR("Forced cleanup waiting for %s "
"namespace with %d resources in use, "
"(rc=%d)\n", ldlm_ns_name(ns),
ldlm_namespace_debugfs_unregister(ns);
ldlm_namespace_sysfs_unregister(ns);
cfs_hash_putref(ns->ns_rs_hash);
+ OBD_FREE_LARGE(ns->ns_rs_buckets,
+ BIT(ns->ns_bucket_bits) * sizeof(ns->ns_rs_buckets[0]));
kfree(ns->ns_name);
/* Namespace \a ns should be not on list at this time, otherwise
* this will cause issues related to using freed \a ns in poold
struct ldlm_namespace, ns_list_chain);
}
+static bool ldlm_resource_extent_new(struct ldlm_resource *res)
+{
+ int idx;
+
+ OBD_SLAB_ALLOC(res->lr_itree, ldlm_interval_tree_slab,
+ sizeof(*res->lr_itree) * LCK_MODE_NUM);
+ if (res->lr_itree == NULL)
+ return false;
+ /* Initialize interval trees for each lock mode. */
+ for (idx = 0; idx < LCK_MODE_NUM; idx++) {
+ res->lr_itree[idx].lit_size = 0;
+ res->lr_itree[idx].lit_mode = 1 << idx;
+ res->lr_itree[idx].lit_root = NULL;
+ }
+ return true;
+}
+
+static bool ldlm_resource_inodebits_new(struct ldlm_resource *res)
+{
+ int i;
+
+ OBD_ALLOC_PTR(res->lr_ibits_queues);
+ if (res->lr_ibits_queues == NULL)
+ return false;
+ for (i = 0; i < MDS_INODELOCK_NUMBITS; i++)
+ INIT_LIST_HEAD(&res->lr_ibits_queues->liq_waiting[i]);
+ return true;
+}
+
/** Create and initialize new resource. */
static struct ldlm_resource *ldlm_resource_new(enum ldlm_type ldlm_type)
{
struct ldlm_resource *res;
- int idx;
+ bool rc;
OBD_SLAB_ALLOC_PTR_GFP(res, ldlm_resource_slab, GFP_NOFS);
if (res == NULL)
return NULL;
- if (ldlm_type == LDLM_EXTENT) {
- OBD_SLAB_ALLOC(res->lr_itree, ldlm_interval_tree_slab,
- sizeof(*res->lr_itree) * LCK_MODE_NUM);
- if (res->lr_itree == NULL) {
- OBD_SLAB_FREE_PTR(res, ldlm_resource_slab);
- return NULL;
- }
- /* Initialize interval trees for each lock mode. */
- for (idx = 0; idx < LCK_MODE_NUM; idx++) {
- res->lr_itree[idx].lit_size = 0;
- res->lr_itree[idx].lit_mode = 1 << idx;
- res->lr_itree[idx].lit_root = NULL;
- }
+ switch (ldlm_type) {
+ case LDLM_EXTENT:
+ rc = ldlm_resource_extent_new(res);
+ break;
+ case LDLM_IBITS:
+ rc = ldlm_resource_inodebits_new(res);
+ break;
+ default:
+ rc = true;
+ break;
+ }
+ if (!rc) {
+ OBD_SLAB_FREE_PTR(res, ldlm_resource_slab);
+ return NULL;
}
INIT_LIST_HEAD(&res->lr_granted);
return res;
}
+static void ldlm_resource_free(struct ldlm_resource *res)
+{
+ if (res->lr_type == LDLM_EXTENT) {
+ if (res->lr_itree != NULL)
+ OBD_SLAB_FREE(res->lr_itree, ldlm_interval_tree_slab,
+ sizeof(*res->lr_itree) * LCK_MODE_NUM);
+ } else if (res->lr_type == LDLM_IBITS) {
+ if (res->lr_ibits_queues != NULL)
+ OBD_FREE_PTR(res->lr_ibits_queues);
+ }
+
+ OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof *res);
+}
+
/**
* Return a reference to resource with given name, creating it if necessary.
* Args: namespace with ns_lock unlocked
struct cfs_hash_bd bd;
__u64 version;
int ns_refcount = 0;
+ int hash;
LASSERT(ns != NULL);
LASSERT(parent == NULL);
if (res == NULL)
return ERR_PTR(-ENOMEM);
- res->lr_ns_bucket = cfs_hash_bd_extra_get(ns->ns_rs_hash, &bd);
+ hash = ldlm_res_hop_fid_hash(name, ns->ns_bucket_bits);
+ res->lr_ns_bucket = &ns->ns_rs_buckets[hash];
res->lr_name = *name;
res->lr_type = type;
cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1);
/* Clean lu_ref for failed resource. */
lu_ref_fini(&res->lr_reference);
- if (res->lr_itree != NULL)
- OBD_SLAB_FREE(res->lr_itree, ldlm_interval_tree_slab,
- sizeof(*res->lr_itree) * LCK_MODE_NUM);
- OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof *res);
+ ldlm_resource_free(res);
found:
res = hlist_entry(hnode, struct ldlm_resource, lr_hash);
return res;
}
/* We won! Let's add the resource. */
cfs_hash_bd_add_locked(ns->ns_rs_hash, &bd, &res->lr_hash);
- if (cfs_hash_bd_count_get(&bd) == 1)
+ if (atomic_inc_return(&res->lr_ns_bucket->nsb_count) == 1)
ns_refcount = ldlm_namespace_get_return(ns);
cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1);
cfs_hash_bd_del_locked(nsb->nsb_namespace->ns_rs_hash,
bd, &res->lr_hash);
lu_ref_fini(&res->lr_reference);
- if (cfs_hash_bd_count_get(bd) == 0)
+ if (atomic_dec_and_test(&nsb->nsb_count))
ldlm_namespace_put(nsb->nsb_namespace);
}
cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1);
if (ns->ns_lvbo && ns->ns_lvbo->lvbo_free)
ns->ns_lvbo->lvbo_free(res);
- if (res->lr_itree != NULL)
- OBD_SLAB_FREE(res->lr_itree, ldlm_interval_tree_slab,
- sizeof(*res->lr_itree) * LCK_MODE_NUM);
- OBD_SLAB_FREE(res, ldlm_resource_slab, sizeof *res);
+ ldlm_resource_free(res);
return 1;
}
return 0;
LASSERT(list_empty(&lock->l_res_link));
list_add_tail(&lock->l_res_link, head);
+
+ if (res->lr_type == LDLM_IBITS)
+ ldlm_inodebits_add_lock(res, head, lock);
}
/**
int type = lock->l_resource->lr_type;
check_res_locked(lock->l_resource);
- if (type == LDLM_IBITS || type == LDLM_PLAIN)
+ switch (type) {
+ case LDLM_PLAIN:
ldlm_unlink_lock_skiplist(lock);
- else if (type == LDLM_EXTENT)
+ break;
+ case LDLM_EXTENT:
ldlm_extent_unlink_lock(lock);
+ break;
+ case LDLM_IBITS:
+ ldlm_inodebits_unlink_lock(lock);
+ break;
+ }
list_del_init(&lock->l_res_link);
}
EXPORT_SYMBOL(ldlm_resource_unlink_lock);
struct ldlm_lock *lock;
unsigned int granted = 0;
- CLASSERT(RES_NAME_SIZE == 4);
+ BUILD_BUG_ON(RES_NAME_SIZE != 4);
if (!((libcfs_debug | D_ERROR) & level))
return;