kmem_cache_t *ldlm_resource_slab, *ldlm_lock_slab;
+spinlock_t ldlm_namespace_lock = SPIN_LOCK_UNLOCKED;
+struct list_head ldlm_namespace_list = LIST_HEAD_INIT(ldlm_namespace_list);
+static struct proc_dir_entry *ldlm_ns_proc_dir = NULL;
+
+int ldlm_proc_setup(struct obd_device *obd)
+{
+ ENTRY;
+
+ if (obd->obd_proc_entry == NULL)
+ RETURN(-EINVAL);
+
+ ldlm_ns_proc_dir = proc_mkdir("namespaces", obd->obd_proc_entry);
+ if (ldlm_ns_proc_dir == NULL) {
+ CERROR("Couldn't create /proc/lustre/ldlm/namespaces\n");
+ RETURN(-EPERM);
+ }
+ RETURN(0);
+}
+
+void ldlm_proc_cleanup(struct obd_device *obd)
+{
+ proc_lustre_remove_obd_entry("namespaces", obd);
+}
+
struct ldlm_namespace *ldlm_namespace_new(char *name, __u32 client)
{
struct ldlm_namespace *ns = NULL;
for (bucket = ns->ns_hash + RES_HASH_SIZE - 1; bucket >= ns->ns_hash;
bucket--)
INIT_LIST_HEAD(bucket);
+
+ spin_lock(&ldlm_namespace_lock);
+ list_add(&ns->ns_list_chain, &ldlm_namespace_list);
+ ns->ns_proc_dir = proc_mkdir(ns->ns_name, ldlm_ns_proc_dir);
+ if (ns->ns_proc_dir == NULL)
+ CERROR("Unable to create proc directory for namespace.\n");
+ spin_unlock(&ldlm_namespace_lock);
+
RETURN(ns);
out:
return NULL;
}
-static int cleanup_resource(struct ldlm_resource *res, struct list_head *q)
+extern struct ldlm_lock *ldlm_lock_get(struct ldlm_lock *lock);
+
+static void cleanup_resource(struct ldlm_resource *res, struct list_head *q)
{
struct list_head *tmp, *pos;
int rc = 0, client = res->lr_namespace->ns_client;
list_for_each_safe(tmp, pos, q) {
struct ldlm_lock *lock;
lock = list_entry(tmp, struct ldlm_lock, l_res_link);
+ LDLM_LOCK_GET(lock);
if (client) {
struct lustre_handle lockh;
ldlm_lock2handle(lock, &lockh);
+ /* can we get away without a connh here? */
rc = ldlm_cli_cancel(&lockh);
- if (rc < 0) {
+ if (rc != ELDLM_OK) {
+ /* It failed remotely, but we'll force it to
+ * cleanup locally. */
CERROR("ldlm_cli_cancel: %d\n", rc);
- LBUG();
+ ldlm_lock_cancel(lock);
}
- if (rc == ELDLM_RESOURCE_FREED)
- rc = 1;
} else {
- CERROR("Freeing a lock still held by a client node.\n");
+ CERROR("Freeing lock %p still held by client node.\n",
+ lock);
+ ldlm_lock_dump(lock);
ldlm_resource_unlink_lock(lock);
ldlm_lock_destroy(lock);
-
- rc = ldlm_resource_put(res);
}
+ LDLM_LOCK_PUT(lock);
}
-
- RETURN(rc);
}
int ldlm_namespace_free(struct ldlm_namespace *ns)
{
struct list_head *tmp, *pos;
- int i, rc;
+ int i;
if (!ns)
RETURN(ELDLM_OK);
+ spin_lock(&ldlm_namespace_lock);
+ list_del(&ns->ns_list_chain);
+ remove_proc_entry(ns->ns_name, ldlm_ns_proc_dir);
+ spin_unlock(&ldlm_namespace_lock);
+
l_lock(&ns->ns_lock);
for (i = 0; i < RES_HASH_SIZE; i++) {
list_for_each_safe(tmp, pos, &(ns->ns_hash[i])) {
struct ldlm_resource *res;
res = list_entry(tmp, struct ldlm_resource, lr_hash);
+ ldlm_resource_getref(res);
- rc = cleanup_resource(res, &res->lr_granted);
- if (!rc)
- rc = cleanup_resource(res, &res->lr_converting);
- if (!rc)
- rc = cleanup_resource(res, &res->lr_waiting);
+ cleanup_resource(res, &res->lr_granted);
+ cleanup_resource(res, &res->lr_converting);
+ cleanup_resource(res, &res->lr_waiting);
- if (rc == 0) {
+ if (!ldlm_resource_put(res)) {
CERROR("Resource refcount nonzero (%d) after "
"lock cleanup; forcing cleanup.\n",
atomic_read(&res->lr_refcount));
ldlm_resource_dump(res);
atomic_set(&res->lr_refcount, 1);
- rc = ldlm_resource_put(res);
+ ldlm_resource_put(res);
}
}
}
bucket = ns->ns_hash + ldlm_hash_fn(parent, name);
list_add(&res->lr_hash, bucket);
- if (parent == NULL) {
- res->lr_parent = res;
- list_add(&res->lr_rootlink, &ns->ns_root_list);
- } else {
+ if (parent == NULL)
+ list_add(&res->lr_childof, &ns->ns_root_list);
+ else {
res->lr_parent = parent;
list_add(&res->lr_childof, &parent->lr_children);
}
ns->ns_refcount--;
list_del(&res->lr_hash);
- list_del(&res->lr_rootlink);
list_del(&res->lr_childof);
kmem_cache_free(ldlm_resource_slab, res);
memcpy(desc->lr_version, res->lr_version, sizeof(desc->lr_version));
}
+void ldlm_dump_all_namespaces(void)
+{
+ struct list_head *tmp;
+
+ spin_lock(&ldlm_namespace_lock);
+
+ list_for_each(tmp, &ldlm_namespace_list) {
+ struct ldlm_namespace *ns;
+ ns = list_entry(tmp, struct ldlm_namespace, ns_list_chain);
+ ldlm_namespace_dump(ns);
+ }
+
+ spin_unlock(&ldlm_namespace_lock);
+}
+
+void ldlm_namespace_dump(struct ldlm_namespace *ns)
+{
+ struct list_head *tmp;
+
+ l_lock(&ns->ns_lock);
+ CDEBUG(D_OTHER, "--- Namespace: %s (rc: %d, client: %d)\n", ns->ns_name,
+ ns->ns_refcount, ns->ns_client);
+
+ list_for_each(tmp, &ns->ns_root_list) {
+ struct ldlm_resource *res;
+ res = list_entry(tmp, struct ldlm_resource, lr_childof);
+
+ /* Once we have resources with children, this should really dump
+ * them recursively. */
+ ldlm_resource_dump(res);
+ }
+ l_unlock(&ns->ns_lock);
+}
+
void ldlm_resource_dump(struct ldlm_resource *res)
{
struct list_head *tmp;