diff -urN 2.3.21/fs/buffer.c 2.3.21-ramdisk/fs/buffer.c --- 2.3.21/fs/buffer.c Tue Oct 12 18:13:37 1999 +++ 2.3.21-ramdisk/fs/buffer.c Wed Oct 13 19:50:23 1999 @@ -1207,7 +1207,8 @@ static void unmap_buffer(struct buffer_head * bh) { - if (buffer_mapped(bh)) + if (buffer_mapped(bh) && + MAJOR(bh->b_dev) != RAMDISK_MAJOR) { mark_buffer_clean(bh); wait_on_buffer(bh); @@ -1217,6 +1218,59 @@ } } +static void hash_ramdisk_buffers(struct page * page) +{ + struct buffer_head * bh = page->buffers, * first = bh, ** head; + + do { + if (MAJOR(bh->b_dev) != RAMDISK_MAJOR) + BUG(); + if (buffer_mapped(bh) && buffer_uptodate(bh)) + { + struct buffer_head * oldbh; + + /* the buffer hash doesn't like duplicates */ + oldbh = get_hash_table(bh->b_dev, bh->b_blocknr, + bh->b_size); + if (oldbh) + { + mark_buffer_clean(oldbh); + wait_on_buffer(oldbh); + clear_bit(BH_Protected, &oldbh->b_state); + + /* an anonymous buffer is not update */ + clear_bit(BH_Uptodate, &oldbh->b_state); + + /* make sure the old buffer will be anonymous, + bforget may fail to forget the buffer + if there's some other user */ + write_lock(&hash_table_lock); + if (oldbh->b_pprev) + __hash_unlink(oldbh); + write_unlock(&hash_table_lock); + + bforget(oldbh); + } + + /* stop the I/O before changing the end-io + completation callback */ + if (buffer_dirty(bh) || buffer_locked(bh)) + { + mark_buffer_clean(bh); + wait_on_buffer(bh); + } + /* need a mb() here?? It seems no. */ + bh->b_end_io = end_buffer_io_sync; + + head = &hash(bh->b_dev, bh->b_blocknr); + write_lock(&hash_table_lock); + __hash_link(bh, head); + write_unlock(&hash_table_lock); + } + bh = bh->b_this_page; + } while (bh != first); +} + /* * We don't have to release all buffers here, but * we have to be sure that no dirty buffer is left @@ -1262,6 +1316,8 @@ if (!offset) { if (!try_to_free_buffers(page)) { atomic_add(PAGE_CACHE_SIZE, &buffermem); + if (MAJOR(inode->i_dev) == RAMDISK_MAJOR) + hash_ramdisk_buffers(page); return 0; } } @@ -1445,11 +1501,37 @@ if (buffer_new(bh)) { memset(bh->b_data, 0, bh->b_size); } else { - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - err = -EIO; - if (!buffer_uptodate(bh)) - goto out; + if (MAJOR(bh->b_dev) != RAMDISK_MAJOR) + { + do_IO: + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + err = -EIO; + if (!buffer_uptodate(bh)) + goto out; + } else { + struct buffer_head * oldbh; + + oldbh = get_hash_table(bh->b_dev, + bh->b_blocknr, + bh->b_size); + if (!oldbh) + goto do_IO; + mark_buffer_clean(oldbh); + wait_on_buffer(oldbh); + clear_bit(BH_Protected, + &oldbh->b_state); + if (!buffer_uptodate(oldbh)) + { + bforget(oldbh); + goto do_IO; + } + + memcpy(bh->b_data, oldbh->b_data, + bh->b_size); + set_bit(BH_Protected, &bh->b_state); + bforget(oldbh); + } } } @@ -1608,11 +1690,37 @@ if (buffer_new(bh)) { memset(bh->b_data, 0, bh->b_size); } else { - ll_rw_block(READ, 1, &bh); - wait_on_buffer(bh); - err = -EIO; - if (!buffer_uptodate(bh)) - goto out; + if (MAJOR(bh->b_dev) != RAMDISK_MAJOR) + { + do_IO: + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + err = -EIO; + if (!buffer_uptodate(bh)) + goto out; + } else { + struct buffer_head * oldbh; + + oldbh = get_hash_table(bh->b_dev, + bh->b_blocknr, + bh->b_size); + if (!oldbh) + goto do_IO; + mark_buffer_clean(oldbh); + wait_on_buffer(oldbh); + clear_bit(BH_Protected, + &oldbh->b_state); + if (!buffer_uptodate(oldbh)) + { + bforget(oldbh); + goto do_IO; + } + + memcpy(bh->b_data, oldbh->b_data, + bh->b_size); + set_bit(BH_Protected, &bh->b_state); + bforget(oldbh); + } } } @@ -2032,8 +2140,33 @@ set_bit(BH_Uptodate, &bh->b_state); continue; } + else if (MAJOR(bh->b_dev) == RAMDISK_MAJOR) + { + struct buffer_head * oldbh; + + oldbh = get_hash_table(bh->b_dev, + bh->b_blocknr, + bh->b_size); + if (!oldbh) + goto do_IO; + mark_buffer_clean(oldbh); + wait_on_buffer(oldbh); + clear_bit(BH_Protected, &oldbh->b_state); + if (!buffer_uptodate(oldbh)) + { + bforget(oldbh); + goto do_IO; + } + + memcpy(bh->b_data, oldbh->b_data, bh->b_size); + set_bit(BH_Uptodate, &bh->b_state); + set_bit(BH_Protected, &bh->b_state); + bforget(oldbh); + continue; + } } + do_IO: init_buffer(bh, end_buffer_io_async, NULL); atomic_inc(&bh->b_count); arr[nr] = bh;