struct page_removal_cb_element {
struct list_head prce_list;
obd_page_removal_cb_t prce_callback;
+ atomic_t prce_refcnt;
};
typedef int (*cache_iterate_extents_cb_t)(struct lustre_cache *,
struct list_head lc_locks_list;
spinlock_t lc_locks_list_lock;
struct list_head lc_page_removal_callback_list;
+ rwlock_t lc_page_removal_cb_lock; /* iterate vs modify list */
struct obd_device *lc_obd;
obd_pin_extent_cb lc_pin_extent_cb;
};
RETURN(0);
}
+static void cache_extent_removal_get(struct page_removal_cb_element *element)
+{
+ atomic_inc(&element->prce_refcnt);
+}
+
+static void cache_extent_removal_put(struct page_removal_cb_element *element)
+{
+ if(atomic_dec_and_test(&element->prce_refcnt))
+ OBD_FREE_PTR(element);
+}
+
static int cache_extent_removal_event(struct lustre_cache *cache,
void *data, int discard)
{
struct page *page = data;
+ struct list_head *iter;
struct page_removal_cb_element *element;
- list_for_each_entry(element, &cache->lc_page_removal_callback_list,
- prce_list) {
+ read_lock(&cache->lc_page_removal_cb_lock);
+ iter = cache->lc_page_removal_callback_list.next;
+ while(iter != &cache->lc_page_removal_callback_list) {
+ element = list_entry(iter, struct page_removal_cb_element, prce_list);
+ cache_extent_removal_get(element);
+ read_unlock(&cache->lc_page_removal_cb_lock);
+
element->prce_callback(page, discard);
+
+ read_lock(&cache->lc_page_removal_cb_lock);
+ iter = iter->next;
+ cache_extent_removal_put(element);
}
+ read_unlock(&cache->lc_page_removal_cb_lock);
+
return 0;
}
if (!func_cb)
return 0;
- OBD_ALLOC(element, sizeof(*element));
+
+ OBD_ALLOC_PTR(element);
if (!element)
return -ENOMEM;
element->prce_callback = func_cb;
+ atomic_set(&element->prce_refcnt, 1);
+
+ write_lock(&cache->lc_page_removal_cb_lock);
list_add_tail(&element->prce_list,
&cache->lc_page_removal_callback_list);
+ write_unlock(&cache->lc_page_removal_cb_lock);
cache->lc_pin_extent_cb = pin_cb;
return 0;
int found = 0;
struct page_removal_cb_element *element, *t;
+ write_lock(&cache->lc_page_removal_cb_lock);
list_for_each_entry_safe(element, t,
&cache->lc_page_removal_callback_list,
prce_list) {
if (element->prce_callback == func_cb) {
list_del(&element->prce_list);
- OBD_FREE(element, sizeof(*element));
+ write_unlock(&cache->lc_page_removal_cb_lock);
found = 1;
+ cache_extent_removal_put(element);
+ write_lock(&cache->lc_page_removal_cb_lock);
/* We continue iterating the list in case this function
was registered more than once */
}
}
+ write_unlock(&cache->lc_page_removal_cb_lock);
if (list_empty(&cache->lc_page_removal_callback_list))
cache->lc_pin_extent_cb = NULL;
spin_lock_init(&cache->lc_locks_list_lock);
CFS_INIT_LIST_HEAD(&cache->lc_locks_list);
CFS_INIT_LIST_HEAD(&cache->lc_page_removal_callback_list);
+ rwlock_init(&cache->lc_page_removal_cb_lock);
cache->lc_obd = obd;
out: