xfs: use struct list_head for the buf cancel table

Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Alex Elder <aelder@sgi.com>
This commit is contained in:
Christoph Hellwig 2010-12-01 22:06:22 +00:00 committed by Alex Elder
parent e2714bf8d5
commit d5689eaa0a
3 changed files with 65 additions and 111 deletions

View File

@ -105,17 +105,6 @@ typedef struct xfs_buf_log_item {
xfs_buf_log_format_t bli_format; /* in-log header */ xfs_buf_log_format_t bli_format; /* in-log header */
} xfs_buf_log_item_t; } xfs_buf_log_item_t;
/*
* This structure is used during recovery to record the buf log
* items which have been canceled and should not be replayed.
*/
typedef struct xfs_buf_cancel {
xfs_daddr_t bc_blkno;
uint bc_len;
int bc_refcount;
struct xfs_buf_cancel *bc_next;
} xfs_buf_cancel_t;
void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *); void xfs_buf_item_init(struct xfs_buf *, struct xfs_mount *);
void xfs_buf_item_relse(struct xfs_buf *); void xfs_buf_item_relse(struct xfs_buf *);
void xfs_buf_item_log(xfs_buf_log_item_t *, uint, uint); void xfs_buf_item_log(xfs_buf_log_item_t *, uint, uint);

View File

@ -21,7 +21,6 @@
struct xfs_buf; struct xfs_buf;
struct log; struct log;
struct xlog_ticket; struct xlog_ticket;
struct xfs_buf_cancel;
struct xfs_mount; struct xfs_mount;
/* /*
@ -491,7 +490,7 @@ typedef struct log {
struct xfs_buftarg *l_targ; /* buftarg of log */ struct xfs_buftarg *l_targ; /* buftarg of log */
uint l_flags; uint l_flags;
uint l_quotaoffs_flag; /* XFS_DQ_*, for QUOTAOFFs */ uint l_quotaoffs_flag; /* XFS_DQ_*, for QUOTAOFFs */
struct xfs_buf_cancel **l_buf_cancel_table; struct list_head *l_buf_cancel_table;
int l_iclog_hsize; /* size of iclog header */ int l_iclog_hsize; /* size of iclog header */
int l_iclog_heads; /* # of iclog header sectors */ int l_iclog_heads; /* # of iclog header sectors */
uint l_sectBBsize; /* sector size in BBs (2^n) */ uint l_sectBBsize; /* sector size in BBs (2^n) */
@ -534,6 +533,9 @@ typedef struct log {
} xlog_t; } xlog_t;
#define XLOG_BUF_CANCEL_BUCKET(log, blkno) \
((log)->l_buf_cancel_table + ((__uint64_t)blkno % XLOG_BC_TABLE_SIZE))
#define XLOG_FORCED_SHUTDOWN(log) ((log)->l_flags & XLOG_IO_ERROR) #define XLOG_FORCED_SHUTDOWN(log) ((log)->l_flags & XLOG_IO_ERROR)
/* common routines */ /* common routines */

View File

@ -52,6 +52,17 @@ STATIC void xlog_recover_check_summary(xlog_t *);
#define xlog_recover_check_summary(log) #define xlog_recover_check_summary(log)
#endif #endif
/*
* This structure is used during recovery to record the buf log items which
* have been canceled and should not be replayed.
*/
struct xfs_buf_cancel {
xfs_daddr_t bc_blkno;
uint bc_len;
int bc_refcount;
struct list_head bc_list;
};
/* /*
* Sector aligned buffer routines for buffer create/read/write/access * Sector aligned buffer routines for buffer create/read/write/access
*/ */
@ -1607,15 +1618,11 @@ xlog_recover_reorder_trans(
*/ */
STATIC void STATIC void
xlog_recover_do_buffer_pass1( xlog_recover_do_buffer_pass1(
xlog_t *log, struct log *log,
xfs_buf_log_format_t *buf_f) xfs_buf_log_format_t *buf_f)
{ {
xfs_buf_cancel_t *bcp; struct list_head *bucket;
xfs_buf_cancel_t *nextp; struct xfs_buf_cancel *bcp;
xfs_buf_cancel_t *prevp;
xfs_buf_cancel_t **bucket;
xfs_daddr_t blkno = buf_f->blf_blkno;
uint len = buf_f->blf_len;
/* /*
* If this isn't a cancel buffer item, then just return. * If this isn't a cancel buffer item, then just return.
@ -1626,51 +1633,25 @@ xlog_recover_do_buffer_pass1(
} }
/* /*
* Insert an xfs_buf_cancel record into the hash table of * Insert an xfs_buf_cancel record into the hash table of them.
* them. If there is already an identical record, bump * If there is already an identical record, bump its reference count.
* its reference count.
*/ */
bucket = &log->l_buf_cancel_table[(__uint64_t)blkno % bucket = XLOG_BUF_CANCEL_BUCKET(log, buf_f->blf_blkno);
XLOG_BC_TABLE_SIZE]; list_for_each_entry(bcp, bucket, bc_list) {
/* if (bcp->bc_blkno == buf_f->blf_blkno &&
* If the hash bucket is empty then just insert a new record into bcp->bc_len == buf_f->blf_len) {
* the bucket. bcp->bc_refcount++;
*/
if (*bucket == NULL) {
bcp = (xfs_buf_cancel_t *)kmem_alloc(sizeof(xfs_buf_cancel_t),
KM_SLEEP);
bcp->bc_blkno = blkno;
bcp->bc_len = len;
bcp->bc_refcount = 1;
bcp->bc_next = NULL;
*bucket = bcp;
return;
}
/*
* The hash bucket is not empty, so search for duplicates of our
* record. If we find one them just bump its refcount. If not
* then add us at the end of the list.
*/
prevp = NULL;
nextp = *bucket;
while (nextp != NULL) {
if (nextp->bc_blkno == blkno && nextp->bc_len == len) {
nextp->bc_refcount++;
trace_xfs_log_recover_buf_cancel_ref_inc(log, buf_f); trace_xfs_log_recover_buf_cancel_ref_inc(log, buf_f);
return; return;
} }
prevp = nextp;
nextp = nextp->bc_next;
} }
ASSERT(prevp != NULL);
bcp = (xfs_buf_cancel_t *)kmem_alloc(sizeof(xfs_buf_cancel_t), bcp = kmem_alloc(sizeof(struct xfs_buf_cancel), KM_SLEEP);
KM_SLEEP); bcp->bc_blkno = buf_f->blf_blkno;
bcp->bc_blkno = blkno; bcp->bc_len = buf_f->blf_len;
bcp->bc_len = len;
bcp->bc_refcount = 1; bcp->bc_refcount = 1;
bcp->bc_next = NULL; list_add_tail(&bcp->bc_list, bucket);
prevp->bc_next = bcp;
trace_xfs_log_recover_buf_cancel_add(log, buf_f); trace_xfs_log_recover_buf_cancel_add(log, buf_f);
} }
@ -1689,14 +1670,13 @@ xlog_recover_do_buffer_pass1(
*/ */
STATIC int STATIC int
xlog_check_buffer_cancelled( xlog_check_buffer_cancelled(
xlog_t *log, struct log *log,
xfs_daddr_t blkno, xfs_daddr_t blkno,
uint len, uint len,
ushort flags) ushort flags)
{ {
xfs_buf_cancel_t *bcp; struct list_head *bucket;
xfs_buf_cancel_t *prevp; struct xfs_buf_cancel *bcp;
xfs_buf_cancel_t **bucket;
if (log->l_buf_cancel_table == NULL) { if (log->l_buf_cancel_table == NULL) {
/* /*
@ -1707,55 +1687,36 @@ xlog_check_buffer_cancelled(
return 0; return 0;
} }
bucket = &log->l_buf_cancel_table[(__uint64_t)blkno % /*
XLOG_BC_TABLE_SIZE]; * Search for an entry in the cancel table that matches our buffer.
bcp = *bucket; */
if (bcp == NULL) { bucket = XLOG_BUF_CANCEL_BUCKET(log, blkno);
/* list_for_each_entry(bcp, bucket, bc_list) {
* There is no corresponding entry in the table built if (bcp->bc_blkno == blkno && bcp->bc_len == len)
* in pass one, so this buffer has not been cancelled. goto found;
*/
ASSERT(!(flags & XFS_BLF_CANCEL));
return 0;
} }
/* /*
* Search for an entry in the buffer cancel table that * We didn't find a corresponding entry in the table, so return 0 so
* matches our buffer. * that the buffer is NOT cancelled.
*/
prevp = NULL;
while (bcp != NULL) {
if (bcp->bc_blkno == blkno && bcp->bc_len == len) {
/*
* We've go a match, so return 1 so that the
* recovery of this buffer is cancelled.
* If this buffer is actually a buffer cancel
* log item, then decrement the refcount on the
* one in the table and remove it if this is the
* last reference.
*/
if (flags & XFS_BLF_CANCEL) {
bcp->bc_refcount--;
if (bcp->bc_refcount == 0) {
if (prevp == NULL) {
*bucket = bcp->bc_next;
} else {
prevp->bc_next = bcp->bc_next;
}
kmem_free(bcp);
}
}
return 1;
}
prevp = bcp;
bcp = bcp->bc_next;
}
/*
* We didn't find a corresponding entry in the table, so
* return 0 so that the buffer is NOT cancelled.
*/ */
ASSERT(!(flags & XFS_BLF_CANCEL)); ASSERT(!(flags & XFS_BLF_CANCEL));
return 0; return 0;
found:
/*
* We've go a match, so return 1 so that the recovery of this buffer
* is cancelled. If this buffer is actually a buffer cancel log
* item, then decrement the refcount on the one in the table and
* remove it if this is the last reference.
*/
if (flags & XFS_BLF_CANCEL) {
if (--bcp->bc_refcount == 0) {
list_del(&bcp->bc_list);
kmem_free(bcp);
}
}
return 1;
} }
/* /*
@ -3649,7 +3610,7 @@ xlog_do_log_recovery(
xfs_daddr_t head_blk, xfs_daddr_t head_blk,
xfs_daddr_t tail_blk) xfs_daddr_t tail_blk)
{ {
int error; int error, i;
ASSERT(head_blk != tail_blk); ASSERT(head_blk != tail_blk);
@ -3657,10 +3618,12 @@ xlog_do_log_recovery(
* First do a pass to find all of the cancelled buf log items. * First do a pass to find all of the cancelled buf log items.
* Store them in the buf_cancel_table for use in the second pass. * Store them in the buf_cancel_table for use in the second pass.
*/ */
log->l_buf_cancel_table = log->l_buf_cancel_table = kmem_zalloc(XLOG_BC_TABLE_SIZE *
(xfs_buf_cancel_t **)kmem_zalloc(XLOG_BC_TABLE_SIZE * sizeof(struct list_head),
sizeof(xfs_buf_cancel_t*),
KM_SLEEP); KM_SLEEP);
for (i = 0; i < XLOG_BC_TABLE_SIZE; i++)
INIT_LIST_HEAD(&log->l_buf_cancel_table[i]);
error = xlog_do_recovery_pass(log, head_blk, tail_blk, error = xlog_do_recovery_pass(log, head_blk, tail_blk,
XLOG_RECOVER_PASS1); XLOG_RECOVER_PASS1);
if (error != 0) { if (error != 0) {
@ -3679,7 +3642,7 @@ xlog_do_log_recovery(
int i; int i;
for (i = 0; i < XLOG_BC_TABLE_SIZE; i++) for (i = 0; i < XLOG_BC_TABLE_SIZE; i++)
ASSERT(log->l_buf_cancel_table[i] == NULL); ASSERT(list_empty(&log->l_buf_cancel_table[i]));
} }
#endif /* DEBUG */ #endif /* DEBUG */