/** The ldlm_glimpse_work was slab allocated & must be freed accordingly.*/
#define LDLM_GL_WORK_SLAB_ALLOCATED 0x1
-/** Interval node data for each LDLM_EXTENT lock. */
-struct ldlm_interval {
- struct interval_node li_node; /* node for tree management */
- struct list_head li_group; /* locks having same policy */
-};
-#define to_ldlm_interval(n) container_of(n, struct ldlm_interval, li_node)
-
/**
* Interval tree for extent locks.
* The interval tree must be accessed under the resource lock.
* Internal structures per lock type..
*/
union {
- struct ldlm_interval *l_tree_node;
+ struct interval_node l_tree_node;
struct ldlm_ibits_node *l_ibits_node;
};
/**
static enum interval_iter ldlm_extent_compat_cb(struct interval_node *n,
void *data)
{
+ struct ldlm_lock *lock = container_of(n, struct ldlm_lock, l_tree_node);
struct ldlm_extent_compat_args *priv = data;
- struct ldlm_interval *node = to_ldlm_interval(n);
- struct ldlm_extent *extent;
struct list_head *work_list = priv->work_list;
- struct ldlm_lock *lock, *enq = priv->lock;
+ struct ldlm_lock *enq = priv->lock;
enum ldlm_mode mode = priv->mode;
- int count = 0;
ENTRY;
-
- LASSERT(!list_empty(&node->li_group));
-
- list_for_each_entry(lock, &node->li_group, l_sl_policy) {
- /* interval tree is for granted lock */
- LASSERTF(mode == lock->l_granted_mode,
- "mode = %s, lock->l_granted_mode = %s\n",
- ldlm_lockname[mode],
- ldlm_lockname[lock->l_granted_mode]);
- count++;
- if (lock->l_blocking_ast && lock->l_granted_mode != LCK_GROUP)
- ldlm_add_ast_work_item(lock, enq, work_list);
- }
+ /* interval tree is for granted lock */
+ LASSERTF(mode == lock->l_granted_mode,
+ "mode = %s, lock->l_granted_mode = %s\n",
+ ldlm_lockname[mode],
+ ldlm_lockname[lock->l_granted_mode]);
+ if (lock->l_blocking_ast && lock->l_granted_mode != LCK_GROUP)
+ ldlm_add_ast_work_item(lock, enq, work_list);
/* don't count conflicting glimpse locks */
- extent = ldlm_interval_extent(node);
- if (!(mode == LCK_PR && extent->start == 0 &&
- extent->end == OBD_OBJECT_EOF))
- *priv->locks += count;
+ if (!(mode == LCK_PR && lock->l_policy_data.l_extent.start == 0 &&
+ lock->l_policy_data.l_extent.end == OBD_OBJECT_EOF))
+ *priv->locks += 1;
if (priv->compat)
*priv->compat = 0;
data.mode = tree->lit_mode;
if (lockmode_compat(req_mode, tree->lit_mode)) {
- struct ldlm_interval *node;
- struct ldlm_extent *extent;
+ struct ldlm_lock *lock;
if (req_mode != LCK_GROUP)
continue;
- /* group lock,grant it immediately if
- * compatible */
- node = to_ldlm_interval(tree->lit_root);
- extent = ldlm_interval_extent(node);
+ /* group lock, grant it immediately if
+ * compatible
+ */
+ lock = container_of(tree->lit_root,
+ struct ldlm_lock,
+ l_tree_node);
if (req->l_policy_data.l_extent.gid ==
- extent->gid)
+ lock->l_policy_data.l_extent.gid)
RETURN(2);
}
static enum interval_iter ldlm_resource_prolong_cb(struct interval_node *n,
void *data)
{
+ struct ldlm_lock *lock = container_of(n, struct ldlm_lock, l_tree_node);
struct ldlm_prolong_args *arg = data;
- struct ldlm_interval *node = to_ldlm_interval(n);
- struct ldlm_lock *lock;
ENTRY;
-
- LASSERT(!list_empty(&node->li_group));
-
- list_for_each_entry(lock, &node->li_group, l_sl_policy) {
- ldlm_lock_prolong_one(lock, arg);
- }
-
+ ldlm_lock_prolong_one(lock, arg);
RETURN(INTERVAL_ITER_CONT);
}
static enum interval_iter ldlm_kms_shift_cb(struct interval_node *n,
void *args)
{
+ struct ldlm_lock *lock = container_of(n, struct ldlm_lock, l_tree_node);
struct ldlm_kms_shift_args *arg = args;
- struct ldlm_interval *node = to_ldlm_interval(n);
- struct ldlm_lock *tmplock;
- struct ldlm_lock *lock = NULL;
ENTRY;
-
/* Since all locks in an interval have the same extent, we can just
- * use the first lock without kms_ignore set. */
- list_for_each_entry(tmplock, &node->li_group, l_sl_policy) {
- if (ldlm_is_kms_ignore(tmplock))
- continue;
-
- lock = tmplock;
-
- break;
- }
-
- /* No locks in this interval without kms_ignore set */
- if (!lock)
+ * use the lock without kms_ignore set.
+ */
+ if (ldlm_is_kms_ignore(lock))
RETURN(INTERVAL_ITER_CONT);
/* If we find a lock with a greater or equal kms, we are not the
* highest lock (or we share that distinction with another lock), and
- * don't need to update KMS. Return old_kms and stop looking. */
+ * don't need to update KMS. Return old_kms and stop looking.
+ */
if (lock->l_policy_data.l_extent.end == OBD_OBJECT_EOF ||
lock->l_policy_data.l_extent.end + 1 >= arg->old_kms) {
arg->kms = arg->old_kms;
}
EXPORT_SYMBOL(ldlm_extent_shift_kms);
-struct kmem_cache *ldlm_interval_slab;
-static struct ldlm_interval *ldlm_interval_alloc(struct ldlm_lock *lock)
-{
- struct ldlm_interval *node;
-
- ENTRY;
-
- LASSERT(lock->l_resource->lr_type == LDLM_EXTENT ||
- lock->l_resource->lr_type == LDLM_FLOCK);
- OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, GFP_NOFS);
- if (node == NULL)
- RETURN(NULL);
-
- INIT_LIST_HEAD(&node->li_group);
- ldlm_interval_attach(node, lock);
- RETURN(node);
-}
-
-void ldlm_interval_free(struct ldlm_interval *node)
-{
- if (node) {
- LASSERT(list_empty(&node->li_group));
- LASSERT(!interval_is_intree(&node->li_node));
- OBD_SLAB_FREE(node, ldlm_interval_slab, sizeof(*node));
- }
-}
-
-/* interval tree, for LDLM_EXTENT. */
-void ldlm_interval_attach(struct ldlm_interval *n,
- struct ldlm_lock *l)
-{
- LASSERT(l->l_tree_node == NULL);
- LASSERT(l->l_resource->lr_type == LDLM_EXTENT ||
- l->l_resource->lr_type == LDLM_FLOCK);
-
- list_add_tail(&l->l_sl_policy, &n->li_group);
- l->l_tree_node = n;
-}
-
-struct ldlm_interval *ldlm_interval_detach(struct ldlm_lock *l)
-{
- struct ldlm_interval *n = l->l_tree_node;
-
- if (n == NULL)
- return NULL;
-
- LASSERT(!list_empty(&n->li_group));
- l->l_tree_node = NULL;
- list_del_init(&l->l_sl_policy);
-
- return list_empty(&n->li_group) ? n : NULL;
-}
-
static inline int ldlm_mode_to_index(enum ldlm_mode mode)
{
int index;
return index;
}
-int ldlm_extent_alloc_lock(struct ldlm_lock *lock)
-{
- lock->l_tree_node = NULL;
-
- if (ldlm_interval_alloc(lock) == NULL)
- return -ENOMEM;
- return 0;
-}
-
/** Add newly granted lock into interval tree for the resource. */
void ldlm_extent_add_lock(struct ldlm_resource *res,
struct ldlm_lock *lock)
{
- struct interval_node *found, **root;
- struct ldlm_interval *node;
+ struct interval_node **root;
struct ldlm_extent *extent;
int idx, rc;
LASSERT(ldlm_is_granted(lock));
- node = lock->l_tree_node;
- LASSERT(node != NULL);
- LASSERT(!interval_is_intree(&node->li_node));
+ LASSERT(!interval_is_intree(&lock->l_tree_node));
idx = ldlm_mode_to_index(lock->l_granted_mode);
LASSERT(lock->l_granted_mode == BIT(idx));
/* node extent initialize */
extent = &lock->l_policy_data.l_extent;
- rc = interval_set(&node->li_node, extent->start, extent->end);
+ rc = interval_set(&lock->l_tree_node, extent->start, extent->end);
LASSERT(!rc);
root = &res->lr_itree[idx].lit_root;
- found = interval_insert(&node->li_node, root);
- if (found) { /* The policy group found. */
- struct ldlm_interval *tmp = ldlm_interval_detach(lock);
-
- LASSERT(tmp != NULL);
- ldlm_interval_free(tmp);
- ldlm_interval_attach(to_ldlm_interval(found), lock);
- }
+ interval_insert(&lock->l_tree_node, root);
res->lr_itree[idx].lit_size++;
/* even though we use interval tree to manage the extent lock, we also
void ldlm_extent_unlink_lock(struct ldlm_lock *lock)
{
struct ldlm_resource *res = lock->l_resource;
- struct ldlm_interval *node = lock->l_tree_node;
struct ldlm_interval_tree *tree;
int idx;
- if (!node || !interval_is_intree(&node->li_node)) /* duplicate unlink */
+ if (!interval_is_intree(&lock->l_tree_node)) /* duplicate unlink */
return;
idx = ldlm_mode_to_index(lock->l_granted_mode);
LASSERT(tree->lit_root != NULL); /* assure the tree is not null */
tree->lit_size--;
- node = ldlm_interval_detach(lock);
- if (node) {
- interval_erase(&node->li_node, &tree->lit_root);
- ldlm_interval_free(node);
- }
+ interval_erase(&lock->l_tree_node, &tree->lit_root);
}
void ldlm_extent_policy_wire_to_local(const union ldlm_wire_policy_data *wpolicy,
void ldlm_flock_unlink_lock(struct ldlm_lock *lock)
{
struct ldlm_resource *res = lock->l_resource;
- struct ldlm_interval *node = lock->l_tree_node;
+ struct interval_node **root = &res->lr_flock_node.lfn_root;
- if (!node || !interval_is_intree(&node->li_node)) /* duplicate unlink */
+ if (!interval_is_intree(&lock->l_tree_node)) /* duplicate unlink */
return;
- node = ldlm_interval_detach(lock);
- if (node) {
- struct interval_node **root = &res->lr_flock_node.lfn_root;
-
- interval_erase(&node->li_node, root);
- ldlm_interval_free(node);
- }
+ interval_erase(&lock->l_tree_node, root);
}
static inline void
struct list_head *head,
struct ldlm_lock *lock)
{
- struct interval_node *found, **root;
- struct ldlm_interval *node = lock->l_tree_node;
+ struct interval_node **root;
struct ldlm_extent *extent = &lock->l_policy_data.l_extent;
int rc;
LASSERT(ldlm_is_granted(lock));
- LASSERT(node != NULL);
- LASSERT(!interval_is_intree(&node->li_node));
+ LASSERT(!interval_is_intree(&lock->l_tree_node));
- rc = interval_set(&node->li_node, extent->start, extent->end);
+ rc = interval_set(&lock->l_tree_node, extent->start, extent->end);
LASSERT(!rc);
root = &res->lr_flock_node.lfn_root;
- found = interval_insert(&node->li_node, root);
- if (found) { /* The same extent found. */
- struct ldlm_interval *tmp = ldlm_interval_detach(lock);
-
- LASSERT(tmp != NULL);
- ldlm_interval_free(tmp);
- ldlm_interval_attach(to_ldlm_interval(found), lock);
- }
+ interval_insert(&lock->l_tree_node, root);
/* Add the locks into list */
ldlm_resource_add_lock(res, head, lock);
ldlm_flock_range_update(struct ldlm_lock *lock, struct ldlm_lock *req)
{
struct ldlm_resource *res = lock->l_resource;
- struct interval_node *found, **root = &res->lr_flock_node.lfn_root;
- struct ldlm_interval *node;
+ struct interval_node **root = &res->lr_flock_node.lfn_root;
struct ldlm_extent *extent = &lock->l_policy_data.l_extent;
- node = ldlm_interval_detach(lock);
- if (!node) {
- node = ldlm_interval_detach(req);
- LASSERT(node);
- } else {
- interval_erase(&node->li_node, root);
- }
- interval_set(&node->li_node, extent->start, extent->end);
+ interval_erase(&lock->l_tree_node, root);
+ interval_set(&lock->l_tree_node, extent->start, extent->end);
+ interval_insert(&lock->l_tree_node, root);
- found = interval_insert(&node->li_node, root);
- if (found) { /* The policy group found. */
- ldlm_interval_free(node);
- node = to_ldlm_interval(found);
- }
- ldlm_interval_attach(node, lock);
EXIT;
}
enum ldlm_process_intention intention,
enum ldlm_error *err, struct list_head *work_list);
#endif
-int ldlm_extent_alloc_lock(struct ldlm_lock *lock);
void ldlm_extent_add_lock(struct ldlm_resource *res, struct ldlm_lock *lock);
void ldlm_extent_unlink_lock(struct ldlm_lock *lock);
struct ldlm_bl_pool *ldlm_bl_pool;
};
-/* interval tree, for LDLM_EXTENT. */
-extern struct kmem_cache *ldlm_interval_slab; /* slab cache for ldlm_interval */
-extern void ldlm_interval_attach(struct ldlm_interval *n, struct ldlm_lock *l);
-extern struct ldlm_interval *ldlm_interval_detach(struct ldlm_lock *l);
-extern void ldlm_interval_free(struct ldlm_interval *node);
-/* this function must be called with res lock held */
-static inline struct ldlm_extent *
-ldlm_interval_extent(struct ldlm_interval *node)
-{
- struct ldlm_lock *lock;
-
- LASSERT(!list_empty(&node->li_group));
-
- lock = list_first_entry(&node->li_group, struct ldlm_lock,
- l_sl_policy);
- return &lock->l_policy_data.l_extent;
-}
-
int ldlm_init(void);
void ldlm_exit(void);
if (lock->l_lvb_data != NULL)
OBD_FREE_LARGE(lock->l_lvb_data, lock->l_lvb_len);
- if (res->lr_type == LDLM_EXTENT || res->lr_type == LDLM_FLOCK) {
- ldlm_interval_free(ldlm_interval_detach(lock));
- } else if (res->lr_type == LDLM_IBITS) {
- if (lock->l_ibits_node != NULL)
- OBD_SLAB_FREE_PTR(lock->l_ibits_node,
- ldlm_inodebits_slab);
+ if (res->lr_type == LDLM_IBITS && lock->l_ibits_node) {
+ OBD_SLAB_FREE_PTR(lock->l_ibits_node,
+ ldlm_inodebits_slab);
}
ldlm_resource_putref(res);
lock->l_resource = NULL;
return NULL;
lock->l_flags |= BIT(63);
switch (resource->lr_type) {
- case LDLM_EXTENT:
- rc = ldlm_extent_alloc_lock(lock);
- break;
case LDLM_IBITS:
rc = ldlm_inodebits_alloc_lock(lock);
break;
static unsigned int itree_overlap_cb(struct interval_node *in, void *args)
{
- struct ldlm_interval *node = to_ldlm_interval(in);
+ struct ldlm_lock *lock = container_of(in, struct ldlm_lock,
+ l_tree_node);
struct ldlm_match_data *data = args;
- struct ldlm_lock *lock;
- list_for_each_entry(lock, &node->li_group, l_sl_policy) {
- if (lock_matches(lock, data))
- return INTERVAL_ITER_STOP;
- }
- return INTERVAL_ITER_CONT;
+ return lock_matches(lock, data) ?
+ INTERVAL_ITER_STOP : INTERVAL_ITER_CONT;
}
/**
{
struct ldlm_lock *lock;
struct ldlm_resource *res;
- int rc;
+ int rc = 0;
ENTRY;
lock->l_glimpse_ast = cbs->lcs_glimpse;
}
- switch (type) {
- case LDLM_EXTENT:
- case LDLM_FLOCK:
- rc = ldlm_extent_alloc_lock(lock);
- break;
- case LDLM_IBITS:
+ if (type == LDLM_IBITS) {
rc = ldlm_inodebits_alloc_lock(lock);
- break;
- default:
- rc = 0;
+ if (rc)
+ GOTO(out, rc);
}
- if (rc)
- GOTO(out, rc);
if (lvb_len) {
lock->l_lvb_len = lvb_len;
struct ldlm_resource *res;
int local = ns_is_client(ns);
enum ldlm_error rc = ELDLM_OK;
- struct ldlm_interval *node = NULL;
#ifdef HAVE_SERVER_SUPPORT
bool reconstruct = false;
#endif
}
#ifdef HAVE_SERVER_SUPPORT
- /* For a replaying lock, it might be already in granted list. So
- * unlinking the lock will cause the interval node to be freed, we
- * have to allocate the interval node early otherwise we can't regrant
- * this lock in the future. - jay
- *
- * The only time the ldlm_resource changes for the ldlm_lock is when
- * ldlm_lock_change_resource() is called and that only happens for
- * the Lustre client case.
- */
- if (!local && (*flags & LDLM_FL_REPLAY) &&
- lock->l_resource->lr_type == LDLM_EXTENT)
- OBD_SLAB_ALLOC_PTR_GFP(node, ldlm_interval_slab, GFP_NOFS);
-
reconstruct = !local && lock->l_resource->lr_type == LDLM_FLOCK &&
!(*flags & LDLM_FL_TEST_LOCK);
if (reconstruct) {
}
ldlm_resource_unlink_lock(lock);
- if (res->lr_type == LDLM_EXTENT && lock->l_tree_node == NULL) {
- if (node == NULL) {
- ldlm_lock_destroy_nolock(lock);
- GOTO(out, rc = -ENOMEM);
- }
-
- INIT_LIST_HEAD(&node->li_group);
- ldlm_interval_attach(node, lock);
- node = NULL;
- }
/* Some flags from the enqueue want to make it into the AST, via the
* lock's l_flags.
req, 0, NULL, false, 0);
}
#endif
- if (node)
- OBD_SLAB_FREE(node, ldlm_interval_slab, sizeof(*node));
return rc;
}
if (ldlm_lock_slab == NULL)
goto out_resource;
- ldlm_interval_slab = kmem_cache_create("interval_node",
- sizeof(struct ldlm_interval),
- 0, SLAB_HWCACHE_ALIGN, NULL);
- if (ldlm_interval_slab == NULL)
- goto out_lock;
-
ldlm_interval_tree_slab = kmem_cache_create("interval_tree",
sizeof(struct ldlm_interval_tree) * LCK_MODE_NUM,
0, SLAB_HWCACHE_ALIGN, NULL);
if (ldlm_interval_tree_slab == NULL)
- goto out_interval;
+ goto out_lock_slab;
#ifdef HAVE_SERVER_SUPPORT
ldlm_inodebits_slab = kmem_cache_create("ldlm_ibits_node",
out_interval_tree:
kmem_cache_destroy(ldlm_interval_tree_slab);
#endif
-out_interval:
- kmem_cache_destroy(ldlm_interval_slab);
-out_lock:
+out_lock_slab:
kmem_cache_destroy(ldlm_lock_slab);
out_resource:
kmem_cache_destroy(ldlm_resource_slab);
*/
rcu_barrier();
kmem_cache_destroy(ldlm_lock_slab);
- kmem_cache_destroy(ldlm_interval_slab);
kmem_cache_destroy(ldlm_interval_tree_slab);
#ifdef HAVE_SERVER_SUPPORT
kmem_cache_destroy(ldlm_inodebits_slab);
return extent_compare(&n1->in_extent, &n2->in_extent);
}
-int node_equal(struct interval_node *n1, struct interval_node *n2)
-{
- return extent_equal(&n1->in_extent, &n2->in_extent);
-}
-
#define interval_for_each(node, root) \
for (node = interval_first(root); node != NULL; \
node = interval_next(node))
p = root;
while (*p) {
parent = *p;
- if (node_equal(parent, node))
- RETURN(parent);
/* max_high field must be updated after each iteration */
if (parent->in_max_high < interval_high(node))
*/
static enum interval_iter ofd_intent_cb(struct interval_node *n, void *args)
{
- struct ldlm_interval *node = (struct ldlm_interval *)n;
- struct ofd_intent_args *arg = args;
- __u64 size = arg->size;
- struct ldlm_lock *victim_lock = NULL;
- struct ldlm_lock *lck;
+ struct ldlm_lock *lock = container_of(n, struct ldlm_lock, l_tree_node);
+ struct ofd_intent_args *arg = args;
+ __u64 size = arg->size;
struct ldlm_glimpse_work *gl_work = NULL;
int rc = 0;
if (interval_high(n) <= size)
GOTO(out, rc = INTERVAL_ITER_STOP);
- /* Find the 'victim' lock from this interval */
- list_for_each_entry(lck, &node->li_group, l_sl_policy) {
- victim_lock = LDLM_LOCK_GET(lck);
-
- /* the same policy group - every lock has the
- * same extent, so needn't do it any more */
- break;
- }
-
- /* l_export can be null in race with eviction - In that case, we will
- * not find any locks in this interval */
- if (!victim_lock)
- GOTO(out, rc = INTERVAL_ITER_CONT);
-
/*
* This check is for lock taken in ofd_destroy_by_fid() that does
* not have l_glimpse_ast set. So the logic is: if there is a lock
* Hence, if you are grabbing DLM locks on the server, always set
* non-NULL glimpse_ast (e.g., ldlm_request.c::ldlm_glimpse_ast()).
*/
- if (victim_lock->l_glimpse_ast == NULL) {
- LDLM_DEBUG(victim_lock, "no l_glimpse_ast");
+ if (lock->l_glimpse_ast == NULL) {
+ LDLM_DEBUG(lock, "no l_glimpse_ast");
arg->no_glimpse_ast = true;
- GOTO(out_release, rc = INTERVAL_ITER_STOP);
+ GOTO(out, rc = INTERVAL_ITER_STOP);
}
/* If NO_EXPANSION is not set, this is an active lock, and we don't need
* to glimpse any further once we've glimpsed the client holding this
- * lock. So set us up to stop. See comment above this function. */
- if (!(victim_lock->l_flags & LDLM_FL_NO_EXPANSION))
+ * lock. So set us up to stop. See comment above this function.
+ */
+ if (!(lock->l_flags & LDLM_FL_NO_EXPANSION))
rc = INTERVAL_ITER_STOP;
else
rc = INTERVAL_ITER_CONT;
* client; if so, don't add this lock to the glimpse list - We need
* only glimpse each client once. (And if we know that client holds
* an active lock, we can stop glimpsing. So keep the rc set in the
- * check above.) */
+ * check above.)
+ */
list_for_each_entry(gl_work, &arg->gl_list, gl_list) {
- if (gl_work->gl_lock->l_export == victim_lock->l_export)
- GOTO(out_release, rc);
+ if (gl_work->gl_lock->l_export == lock->l_export)
+ GOTO(out, rc);
}
if (!CFS_FAIL_CHECK(OBD_FAIL_OST_GL_WORK_ALLOC))
if (!gl_work) {
arg->error = -ENOMEM;
- GOTO(out_release, rc = INTERVAL_ITER_STOP);
+ GOTO(out, rc = INTERVAL_ITER_STOP);
}
/* Populate the gl_work structure. */
- gl_work->gl_lock = victim_lock;
+ gl_work->gl_lock = LDLM_LOCK_GET(lock);
list_add_tail(&gl_work->gl_list, &arg->gl_list);
/* There is actually no need for a glimpse descriptor when glimpsing
- * extent locks */
+ * extent locks
+ */
gl_work->gl_desc = NULL;
/* This tells ldlm_work_gl_ast_lock this was allocated from a slab and
- * must be freed in a slab-aware manner. */
+ * must be freed in a slab-aware manner.
+ */
gl_work->gl_flags = LDLM_GL_WORK_SLAB_ALLOCATED;
GOTO(out, rc);
-
-out_release:
- /* If the victim doesn't go on the glimpse list, we must release it */
- LDLM_LOCK_RELEASE(victim_lock);
-
out:
return rc;
}