your fix for SMP race in getblk()

From: Tigran Aivazian (tigran@veritas.com)
Date: Wed May 03 2000 - 11:14:31 EST


Hi Steve,

This is just to say that I looked at, understood and tested your fix to
getblk() under 2.3.99-pre7-3. Looks like a valid bugfix - why not resend
it to Linus?

Regards,
Tigran

PS. I attached a version that applies cleanly to 2.3.99-pre7-3 for those
who wish to test it a bit more.

--- linux/fs/buffer.c Wed May 3 14:17:28 2000
+++ work/fs/buffer.c Wed May 3 17:07:40 2000
@@ -537,12 +537,11 @@
  * will force it bad). This shouldn't really happen currently, but
  * the code is ready.
  */
-struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
+static struct buffer_head * __get_hash_table(kdev_t dev, int block, int size,
+ struct buffer_head **head)
 {
- struct buffer_head **head = &hash(dev, block);
         struct buffer_head *bh;
 
- read_lock(&hash_table_lock);
         for(bh = *head; bh; bh = bh->b_next)
                 if (bh->b_blocknr == block &&
                     bh->b_size == size &&
@@ -550,11 +549,42 @@
                         break;
         if (bh)
                 atomic_inc(&bh->b_count);
+
+ return bh;
+}
+
+struct buffer_head * get_hash_table(kdev_t dev, int block, int size)
+{
+ struct buffer_head **head = &hash(dev, block);
+ struct buffer_head *bh;
+
+ read_lock(&hash_table_lock);
+ bh = __get_hash_table(dev, block, size, head);
         read_unlock(&hash_table_lock);
 
         return bh;
 }
 
+static int insert_into_queues_unique(struct buffer_head *bh)
+{
+ struct buffer_head **head = &hash(bh->b_dev, bh->b_blocknr);
+ struct buffer_head *alias;
+ int err = 0;
+
+ spin_lock(&lru_list_lock);
+ write_lock(&hash_table_lock);
+ alias = __get_hash_table(bh->b_dev, bh->b_blocknr, bh->b_size, head);
+ if (!alias) {
+ __hash_link(bh, head);
+ __insert_into_lru_list(bh, bh->b_list);
+ } else
+ err = 1;
+ write_unlock(&hash_table_lock);
+ spin_unlock(&lru_list_lock);
+
+ return err;
+}
+
 unsigned int get_hardblocksize(kdev_t dev)
 {
         /*
@@ -841,8 +871,15 @@
                 bh->b_blocknr = block;
                 bh->b_state = 1 << BH_Mapped;
 
- /* Insert the buffer into the regular lists */
- insert_into_queues(bh);
+ /* Insert the buffer into the regular lists; check noone
+ else added it first */
+ if (!insert_into_queues_unique(bh))
+ goto out;
+
+ /* someone added it after we last check the hash table */
+ put_last_free(bh);
+ goto repeat;
+
         out:
                 touch_buffer(bh);
                 return bh;

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sun May 07 2000 - 21:00:12 EST