--- 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;