Commit d434869e authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Nathan Scott

[XFS] plug race in pagebuf freeing

SGI Modid: xfs-linux:xfs-kern:167222a
parent 07bb44f3
...@@ -320,25 +320,13 @@ _pagebuf_freepages( ...@@ -320,25 +320,13 @@ _pagebuf_freepages(
* pagebuf_free releases the specified buffer. The modification * pagebuf_free releases the specified buffer. The modification
* state of any associated pages is left unchanged. * state of any associated pages is left unchanged.
*/ */
STATIC void void
__pagebuf_free( pagebuf_free(
page_buf_t *pb) page_buf_t *pb)
{ {
pb_hash_t *hash = pb_hash(pb);
PB_TRACE(pb, "free", 0); PB_TRACE(pb, "free", 0);
spin_lock(&hash->pb_hash_lock); ASSERT(list_empty(&pb->pb_hash_list));
/*
* 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);
/* release any virtual mapping */ ; /* release any virtual mapping */ ;
if (pb->pb_flags & _PBF_ADDR_ALLOCATED) { if (pb->pb_flags & _PBF_ADDR_ALLOCATED) {
...@@ -367,17 +355,6 @@ __pagebuf_free( ...@@ -367,17 +355,6 @@ __pagebuf_free(
pagebuf_deallocate(pb); 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 * _pagebuf_lookup_pages
* *
...@@ -588,8 +565,7 @@ _pagebuf_find( /* find buffer for block */ ...@@ -588,8 +565,7 @@ _pagebuf_find( /* find buffer for block */
if (pb->pb_target == target && if (pb->pb_target == target &&
pb->pb_file_offset == range_base && pb->pb_file_offset == range_base &&
pb->pb_buffer_length == range_length && pb->pb_buffer_length == range_length) {
atomic_read(&pb->pb_hold)) {
/* If we look at something bring it to the /* If we look at something bring it to the
* front of the list for next time * front of the list for next time
*/ */
...@@ -946,16 +922,21 @@ void ...@@ -946,16 +922,21 @@ void
pagebuf_rele( pagebuf_rele(
page_buf_t *pb) page_buf_t *pb)
{ {
pb_hash_t *hash = pb_hash(pb);
PB_TRACE(pb, "rele", pb->pb_relse); 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; int do_free = 1;
if (pb->pb_relse) { if (pb->pb_relse) {
atomic_inc(&pb->pb_hold); atomic_inc(&pb->pb_hold);
spin_unlock(&hash->pb_hash_lock);
(*(pb->pb_relse)) (pb); (*(pb->pb_relse)) (pb);
spin_lock(&hash->pb_hash_lock);
do_free = 0; do_free = 0;
} }
if (pb->pb_flags & PBF_DELWRI) { if (pb->pb_flags & PBF_DELWRI) {
pb->pb_flags |= PBF_ASYNC; pb->pb_flags |= PBF_ASYNC;
atomic_inc(&pb->pb_hold); atomic_inc(&pb->pb_hold);
...@@ -966,7 +947,11 @@ pagebuf_rele( ...@@ -966,7 +947,11 @@ pagebuf_rele(
} }
if (do_free) { 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);
} }
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment