MFS: reimplement block clean marking fix

MFS' get_block() must never return a newly acquired block buffer that
is marked dirty from previous use. This patch replaces git-dd59d50,
which assumed a working model where blocks for device NO_DEV would
never be dirty. For at least one scenario, that assumption does not
hold, triggering superblock overwrite warnings. In this patch, blocks
are explicitly marked as clean upon being repurposed. The working
model is now restored to be: the dirty state of a block is relevant
only when its associated device is not set to NO_DEV.
This commit is contained in:
David van Moolenbroek 2012-04-20 17:23:09 +02:00
parent 26f817243b
commit 0c11190cdc
2 changed files with 9 additions and 12 deletions

View file

@ -145,12 +145,12 @@ struct buf *get_block(
*/ */
yieldid = make64(bp->b_dev, bp->b_blocknr); yieldid = make64(bp->b_dev, bp->b_blocknr);
assert(bp->b_bytes == fs_block_size); assert(bp->b_bytes == fs_block_size);
BP_CLEARDEV(bp); bp->b_dev = NO_DEV;
} }
/* Fill in block's parameters and add it to the hash chain where it goes. */ /* Fill in block's parameters and add it to the hash chain where it goes. */
if(dev == NO_DEV) BP_CLEARDEV(bp); MARKCLEAN(bp); /* NO_DEV blocks may be marked dirty */
else BP_SETDEV(bp, dev); bp->b_dev = dev; /* fill in device number */
bp->b_blocknr = block; /* fill in block number */ bp->b_blocknr = block; /* fill in block number */
bp->b_count++; /* record that block is being used */ bp->b_count++; /* record that block is being used */
b = BUFHASH(bp->b_blocknr); b = BUFHASH(bp->b_blocknr);
@ -184,7 +184,7 @@ struct buf *get_block(
if(only_search == PREFETCH) { if(only_search == PREFETCH) {
/* PREFETCH: don't do i/o. */ /* PREFETCH: don't do i/o. */
BP_CLEARDEV(bp); bp->b_dev = NO_DEV;
} else if (only_search == NORMAL) { } else if (only_search == NORMAL) {
read_block(bp); read_block(bp);
} else if(only_search == NO_READ) { } else if(only_search == NO_READ) {
@ -351,7 +351,7 @@ register struct buf *bp; /* buffer pointer */
} }
if (op_failed) { if (op_failed) {
BP_CLEARDEV(bp); /* invalidate block */ bp->b_dev = NO_DEV; /* invalidate block */
/* Report read errors to interested parties. */ /* Report read errors to interested parties. */
rdwt_err = r; rdwt_err = r;
@ -371,7 +371,7 @@ void invalidate(
register struct buf *bp; register struct buf *bp;
for (bp = &buf[0]; bp < &buf[nr_bufs]; bp++) for (bp = &buf[0]; bp < &buf[nr_bufs]; bp++)
if (bp->b_dev == device) BP_CLEARDEV(bp); if (bp->b_dev == device) bp->b_dev = NO_DEV;
vm_forgetblocks(); vm_forgetblocks();
} }
@ -502,13 +502,13 @@ void rw_scattered(
if (r < (ssize_t) fs_block_size) { if (r < (ssize_t) fs_block_size) {
/* Transfer failed. */ /* Transfer failed. */
if (i == 0) { if (i == 0) {
BP_CLEARDEV(bp); /* Invalidate block */ bp->b_dev = NO_DEV; /* Invalidate block */
vm_forgetblocks(); vm_forgetblocks();
} }
break; break;
} }
if (rw_flag == READING) { if (rw_flag == READING) {
BP_SETDEV(bp, dev); /* validate block */ bp->b_dev = dev; /* validate block */
put_block(bp, PARTIAL_DATA_BLOCK); put_block(bp, PARTIAL_DATA_BLOCK);
} else { } else {
MARKCLEAN(bp); MARKCLEAN(bp);
@ -663,7 +663,7 @@ void buf_pool(int new_nr_bufs)
for (bp = &buf[0]; bp < &buf[nr_bufs]; bp++) { for (bp = &buf[0]; bp < &buf[nr_bufs]; bp++) {
bp->b_blocknr = NO_BLOCK; bp->b_blocknr = NO_BLOCK;
BP_CLEARDEV(bp); bp->b_dev = NO_DEV;
bp->b_next = bp + 1; bp->b_next = bp + 1;
bp->b_prev = bp - 1; bp->b_prev = bp - 1;
bp->bp = NULL; bp->bp = NULL;

View file

@ -8,7 +8,4 @@
#define ISDIRTY(b) ((b)->b_dirt == BP_DIRTY) #define ISDIRTY(b) ((b)->b_dirt == BP_DIRTY)
#define ISCLEAN(b) ((b)->b_dirt == BP_CLEAN) #define ISCLEAN(b) ((b)->b_dirt == BP_CLEAN)
#define BP_SETDEV(b, dev) do { assert((dev) != NO_DEV); (b)->b_dev = (dev); } while(0)
#define BP_CLEARDEV(b) do { (b)->b_dev = NO_DEV; MARKCLEAN(b); } while(0)
#endif #endif