* pagebuf_free releases the specified buffer. The modification
* state of any associated pages is left unchanged.
*/
-STATIC void
-__pagebuf_free(
+void
+pagebuf_free(
page_buf_t *pb)
{
- pb_hash_t *hash = pb_hash(pb);
-
PB_TRACE(pb, "free", 0);
-
- spin_lock(&hash->pb_hash_lock);
- /*
- * Someone grabbed a reference while we weren't looking,
- * try again later.
- */
- if (unlikely(atomic_read(&pb->pb_hold))) {
- spin_unlock(&hash->pb_hash_lock);
- return;
- } else if (!list_empty(&pb->pb_hash_list))
- list_del_init(&pb->pb_hash_list);
- spin_unlock(&hash->pb_hash_lock);
+
+ ASSERT(list_empty(&pb->pb_hash_list));
/* release any virtual mapping */ ;
if (pb->pb_flags & _PBF_ADDR_ALLOCATED) {
pagebuf_deallocate(pb);
}
-void
-pagebuf_free(
- page_buf_t *pb)
-{
- if (unlikely(!atomic_dec_and_test(&pb->pb_hold))) {
- printk(KERN_ERR "XFS: freeing inuse buffer!\n");
- dump_stack();
- } else
- __pagebuf_free(pb);
-}
-
/*
* _pagebuf_lookup_pages
*
if (pb->pb_target == target &&
pb->pb_file_offset == range_base &&
- pb->pb_buffer_length == range_length &&
- atomic_read(&pb->pb_hold)) {
+ pb->pb_buffer_length == range_length) {
/* If we look at something bring it to the
* front of the list for next time
*/
pagebuf_rele(
page_buf_t *pb)
{
+ pb_hash_t *hash = pb_hash(pb);
+
PB_TRACE(pb, "rele", pb->pb_relse);
- if (atomic_dec_and_test(&pb->pb_hold)) {
+ if (atomic_dec_and_lock(&pb->pb_hold, &hash->pb_hash_lock)) {
int do_free = 1;
if (pb->pb_relse) {
atomic_inc(&pb->pb_hold);
+ spin_unlock(&hash->pb_hash_lock);
(*(pb->pb_relse)) (pb);
+ spin_lock(&hash->pb_hash_lock);
do_free = 0;
}
+
if (pb->pb_flags & PBF_DELWRI) {
pb->pb_flags |= PBF_ASYNC;
atomic_inc(&pb->pb_hold);
}
if (do_free) {
- __pagebuf_free(pb);
+ list_del_init(&pb->pb_hash_list);
+ spin_unlock(&hash->pb_hash_lock);
+ pagebuf_free(pb);
+ } else {
+ spin_unlock(&hash->pb_hash_lock);
}
}
}