diff -urN 2.3.18ac2/fs/buffer.c ramdisk/fs/buffer.c --- 2.3.18ac2/fs/buffer.c Mon Sep 13 03:38:46 1999 +++ ramdisk/fs/buffer.c Mon Sep 13 18:04:29 1999 @@ -1200,6 +1200,59 @@ return 0; } +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 @@ -1227,12 +1280,13 @@ * is this block fully flushed? */ if (offset <= curr_off) { - if (buffer_mapped(bh)) { + if (buffer_mapped(bh) && + MAJOR(bh->b_dev) != RAMDISK_MAJOR) + { mark_buffer_clean(bh); wait_on_buffer(bh); clear_bit(BH_Uptodate, &bh->b_state); clear_bit(BH_Req, &bh->b_state); - bh->b_blocknr = 0; } } curr_off = next_off; @@ -1252,6 +1306,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; } } @@ -1420,11 +1476,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); + } } } @@ -1582,11 +1664,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); + } } } @@ -1999,8 +2107,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;