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