On Fri, 9 Apr 1999, Alexander Viro wrote:

> set_blocksize() seems to do really odd thing:
> suppose you have clean buffer (b_count==0, all nice and dandy) with
> b_size==foo.
>       set_blocksize(dev, bar) will leave it on a clean list and will call
> remove_from_hash_queue() on it. 
>       set_blocksize(dev,foo) now. Nothing happens with our buffer.
>       set_blocksize(dev,bar) again and there we go -
> remove_from_hash_queue() is called again.
> 
> Repeat until the complete satisfaction (nr_hashed_buffers going negative ;-/)
> 
> Wouldn't remove_from_queues() be the right thing here?

yep, the RAID patch has been doing this for some time: 

--- linux/fs/buffer.c.orig      Tue Apr  6 16:35:10 1999
+++ linux/fs/buffer.c   Wed Apr  7 16:08:12 1999
@@ -663,9 +663,16 @@
                                 continue;
                        if (bh->b_size == size)
                                 continue;
-                       bhnext->b_count++;
+                       /*
+                        * We try to completely drop alien-size
+                        * buffers. subtle: we have to protect
+                        * bhnext across the wait and across the
+                        * try_to_free... call because we have
+                        * to keep the 'way forward' on the list.
+                        */
+                       if (bhnext)
+                               bhnext->b_count++;
                        wait_on_buffer(bh);
-                       bhnext->b_count--;
                        if (bh->b_dev == dev && bh->b_size != size) {
                                clear_bit(BH_Dirty, &bh->b_state);
                                clear_bit(BH_Uptodate, &bh->b_state);
@@ -673,11 +680,57 @@
                                bh->b_flushtime = 0;
                        }
                        remove_from_hash_queue(bh);
+
+                       /*
+                        * lets be mega-conservative about what to free:
+                        */
+                       if (    (bh->b_dev != dev) ||
+                               (bh->b_size == size) ||
+                               bh->b_count ||
+                               buffer_protected(bh) ||
+                               buffer_dirty(bh) ||
+                               buffer_locked(bh) ||
+                               waitqueue_active(&bh->b_wait)) {
+                                       if (bhnext)
+                                               bhnext->b_count--;
+                                       continue;
+                       }
+                       try_to_free_buffers(buffer_page(bh));
+                       if (bhnext)
+                               bhnext->b_count--;
                }
        }
 }

-- mingo

Reply via email to