--- linux/drivers/block/rd.c	Fri Nov 19 09:00:38 1999
+++ 2329-p1-rd/drivers/block/rd.c	Fri Nov 19 09:14:26 1999
@@ -185,6 +185,7 @@
 {
 	unsigned int minor;
 	unsigned long offset, len;
+	struct buffer_head *rbh, *sbh;
 
 repeat:
 	INIT_REQUEST;
@@ -211,16 +212,63 @@
 	}
 
 	/*
-	 * If we're reading, fill the buffer with 0's.  This is okay since
-         * we're using protected buffers which should never get freed...
+	 * This has become somewhat more complicated with the addition of
+	 * the page cache. The problem is that in some cases the furnished
+	 * buffer is "real", i.e., part of the existing ramdisk, while in
+ 	 * others it is "unreal", e.g., part of a page. In the first case
+	 * not much needs to be done, while in the second, some kind of
+	 * transfer is needed.
+	 * The two cases are distinguished here by checking whether the
+	 * real buffer is already in the buffer cache, and whether it is
+	 * the same as the one supplied.
 	 *
-	 * If we're writing, we protect the buffer.
+	 * There are three cases with read/write to consider:
+	 *
+	 * 1. Supplied buffer matched one in the buffer cache:
+	 * Read - Clear the buffer, as it wasn't already valid.
+	 * Write - Mark the buffer as "Protected".
+	 *
+	 * 2. Supplied buffer mismatched one in the buffer cache:
+	 * Read - Copy the data from the buffer cache entry.
+	 * Write - Copy the data to the buffer cache entry.
+	 *
+	 * 3 No buffer cache entry existed:
+	 * Read - Clear the supplied buffer, but do not create a real
+	 * one.
+	 * Write - Create a real buffer, copy the data to it, and mark
+	 * it as "Protected".
+	 *
+	 * NOTE: There seems to be some schizophrenia here - the logic
+	 * using "len" seems to assume arbitrary request lengths, while
+	 * the "protect" logic assumes a single buffer cache entry.
+	 * This seems to be left over from the ancient contiguous ramdisk
+	 * logic.
   	 */
-
-	if (CURRENT->cmd == READ) 
-		memset(CURRENT->buffer, 0, len); 
-	else
+	sbh = CURRENT->bh;
+	rbh = get_hash_table(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
+	if (sbh == rbh) {
+		if (CURRENT->cmd == READ)
+			memset(CURRENT->buffer, 0, len);
+	} else if (rbh) {
+		if (CURRENT->cmd == READ)
+			memcpy(CURRENT->buffer, rbh->b_data, rbh->b_size);
+		else
+			memcpy(rbh->b_data, CURRENT->buffer, rbh->b_size);
+	} else { /* !rbh */
+		if (CURRENT->cmd == READ)
+			memset(sbh->b_data, 0, len);
+		else {
+			rbh = getblk(sbh->b_dev, sbh->b_blocknr, sbh->b_size);
+			if (rbh)
+				memcpy(rbh->b_data, CURRENT->buffer, rbh->b_size);
+			else
+				BUG(); /* No buffer, what to do here? */
+		}
+	}
+	if (rbh) {
 		set_bit(BH_Protected, &CURRENT->bh->b_state);
+		brelse(rbh);
+	}
 
 	end_request(1);
 	goto repeat;
