115 lines
3.2 KiB
C
115 lines
3.2 KiB
C
/* The file system maintains a buffer cache to reduce the number of disk
|
|
* accesses needed. Whenever a read or write to the disk is done, a check is
|
|
* first made to see if the block is in the cache. This file manages the
|
|
* cache.
|
|
*
|
|
* The entry points into this file are:
|
|
* get_block: request to fetch a block for reading or writing from cache
|
|
* put_block: return a block previously requested with get_block
|
|
*
|
|
* Private functions:
|
|
* read_block: read physically the block
|
|
*/
|
|
|
|
#include "inc.h"
|
|
#include <minix/com.h>
|
|
#include <minix/u64.h>
|
|
#include "buf.h"
|
|
|
|
FORWARD _PROTOTYPE(int read_block, (struct buf *));
|
|
|
|
PUBLIC struct buf *bp_to_pickup = buf; /* This is a pointer to the next node in the
|
|
* buffer cache to pick up*/
|
|
|
|
|
|
/*===========================================================================*
|
|
* get_block *
|
|
*===========================================================================*/
|
|
PUBLIC struct buf *get_block(block)
|
|
register block_t block; /* which block is wanted? */
|
|
{
|
|
register struct buf *bp, *free_bp;
|
|
|
|
free_bp = NULL;
|
|
|
|
/* Find if the block is already loaded */
|
|
for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
|
|
if (bp->b_blocknr == block) {
|
|
/* Block found. Increment count and return it */
|
|
bp->b_count++;
|
|
return bp;
|
|
} else
|
|
if (bp == bp_to_pickup) {
|
|
if (bp->b_count == 0)
|
|
free_bp = bp;
|
|
else /* Increment the node to pickup */
|
|
if (bp_to_pickup < &buf[NR_BUFS] - 1)
|
|
bp_to_pickup++;
|
|
else
|
|
bp_to_pickup = buf;
|
|
}
|
|
|
|
if (free_bp == NULL &&
|
|
bp_to_pickup == buf &&
|
|
bp_to_pickup->b_count == 0)
|
|
free_bp = bp_to_pickup;
|
|
|
|
if (free_bp != NULL) {
|
|
/* Set fields of data structure */
|
|
free_bp->b_blocknr = block;
|
|
if (read_block(free_bp) != OK) return NULL;
|
|
free_bp->b_count = 1;
|
|
|
|
if (bp_to_pickup < &buf[NR_BUFS] - 1)
|
|
bp_to_pickup++;
|
|
else
|
|
bp_to_pickup = buf;
|
|
|
|
return free_bp;
|
|
} else {
|
|
/* No free blocks. Return NULL */
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* put_block *
|
|
*===========================================================================*/
|
|
PUBLIC void put_block(bp)
|
|
register struct buf *bp; /* pointer to the buffer to be released */
|
|
{
|
|
if (bp == NULL) return; /* it is easier to check here than in caller */
|
|
|
|
bp->b_count--; /* there is one use fewer now */
|
|
}
|
|
|
|
/*===========================================================================*
|
|
* read_block *
|
|
*===========================================================================*/
|
|
PRIVATE int read_block(bp)
|
|
register struct buf *bp; /* buffer pointer */
|
|
{
|
|
int r, op;
|
|
u64_t pos;
|
|
int block_size;
|
|
|
|
block_size = v_pri.logical_block_size_l; /* The block size is indicated by
|
|
* the superblock */
|
|
|
|
|
|
pos = mul64u(bp->b_blocknr, block_size); /* get absolute position */
|
|
op = MFS_DEV_READ; /* flag to read */
|
|
r = block_dev_io(op, fs_dev, SELF_E, bp->b_data, pos, block_size, 0);
|
|
if (r != block_size) {
|
|
if (r >= 0) r = END_OF_FILE;
|
|
if (r != END_OF_FILE)
|
|
printf("ISOFS(%d) I/O error on device %d/%d, block %u\n",
|
|
SELF_E, (fs_dev>>MAJOR)&BYTE, (fs_dev>>MINOR)&BYTE,
|
|
bp->b_blocknr);
|
|
|
|
rdwt_err = r;
|
|
return EINVAL;
|
|
}
|
|
|
|
return OK;
|
|
}
|