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_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_relse(struct xfs_buf *);
void xfs_buf_item_log(xfs_buf_log_item_t *, uint, uint);

View file

@ -21,7 +21,6 @@
struct xfs_buf;
struct log;
struct xlog_ticket;
struct xfs_buf_cancel;
struct xfs_mount;
/*
@ -491,7 +490,7 @@ typedef struct log {
struct xfs_buftarg *l_targ; /* buftarg of log */
uint l_flags;
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_heads; /* # of iclog header sectors */
uint l_sectBBsize; /* sector size in BBs (2^n) */
@ -534,6 +533,9 @@ typedef struct log {
} 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)
/* common routines */

View file

@ -52,6 +52,17 @@ STATIC void xlog_recover_check_summary(xlog_t *);
#define xlog_recover_check_summary(log)
#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
*/
@ -1607,15 +1618,11 @@ xlog_recover_reorder_trans(
*/
STATIC void
xlog_recover_do_buffer_pass1(
xlog_t *log,
struct log *log,
xfs_buf_log_format_t *buf_f)
{
xfs_buf_cancel_t *bcp;
xfs_buf_cancel_t *nextp;
xfs_buf_cancel_t *prevp;
xfs_buf_cancel_t **bucket;
xfs_daddr_t blkno = buf_f->blf_blkno;
uint len = buf_f->blf_len;
struct list_head *bucket;
struct xfs_buf_cancel *bcp;
/*
* 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
* them. If there is already an identical record, bump
* its reference count.
* Insert an xfs_buf_cancel record into the hash table of them.
* If there is already an identical record, bump its reference count.
*/
bucket = &log->l_buf_cancel_table[(__uint64_t)blkno %
XLOG_BC_TABLE_SIZE];
/*
* If the hash bucket is empty then just insert a new record into
* the bucket.
*/
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++;
bucket = XLOG_BUF_CANCEL_BUCKET(log, buf_f->blf_blkno);
list_for_each_entry(bcp, bucket, bc_list) {
if (bcp->bc_blkno == buf_f->blf_blkno &&
bcp->bc_len == buf_f->blf_len) {
bcp->bc_refcount++;
trace_xfs_log_recover_buf_cancel_ref_inc(log, buf_f);
return;
}
prevp = nextp;
nextp = nextp->bc_next;
}
ASSERT(prevp != NULL);
bcp = (xfs_buf_cancel_t *)kmem_alloc(sizeof(xfs_buf_cancel_t),
KM_SLEEP);
bcp->bc_blkno = blkno;
bcp->bc_len = len;
bcp = kmem_alloc(sizeof(struct xfs_buf_cancel), KM_SLEEP);
bcp->bc_blkno = buf_f->blf_blkno;
bcp->bc_len = buf_f->blf_len;
bcp->bc_refcount = 1;
bcp->bc_next = NULL;
prevp->bc_next = bcp;
list_add_tail(&bcp->bc_list, bucket);
trace_xfs_log_recover_buf_cancel_add(log, buf_f);
}
@ -1689,14 +1670,13 @@ xlog_recover_do_buffer_pass1(
*/
STATIC int
xlog_check_buffer_cancelled(
xlog_t *log,
struct log *log,
xfs_daddr_t blkno,
uint len,
ushort flags)
{
xfs_buf_cancel_t *bcp;
xfs_buf_cancel_t *prevp;
xfs_buf_cancel_t **bucket;
struct list_head *bucket;
struct xfs_buf_cancel *bcp;
if (log->l_buf_cancel_table == NULL) {
/*
@ -1707,55 +1687,36 @@ xlog_check_buffer_cancelled(
return 0;
}
bucket = &log->l_buf_cancel_table[(__uint64_t)blkno %
XLOG_BC_TABLE_SIZE];
bcp = *bucket;
if (bcp == NULL) {
/*
* There is no corresponding entry in the table built
* in pass one, so this buffer has not been cancelled.
*/
ASSERT(!(flags & XFS_BLF_CANCEL));
return 0;
/*
* Search for an entry in the cancel table that matches our buffer.
*/
bucket = XLOG_BUF_CANCEL_BUCKET(log, blkno);
list_for_each_entry(bcp, bucket, bc_list) {
if (bcp->bc_blkno == blkno && bcp->bc_len == len)
goto found;
}
/*
* Search for an entry in the buffer cancel table that
* matches our buffer.
*/
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.
* 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));
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 tail_blk)
{
int error;
int error, i;
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.
* Store them in the buf_cancel_table for use in the second pass.
*/
log->l_buf_cancel_table =
(xfs_buf_cancel_t **)kmem_zalloc(XLOG_BC_TABLE_SIZE *
sizeof(xfs_buf_cancel_t*),
log->l_buf_cancel_table = kmem_zalloc(XLOG_BC_TABLE_SIZE *
sizeof(struct list_head),
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,
XLOG_RECOVER_PASS1);
if (error != 0) {
@ -3679,7 +3642,7 @@ xlog_do_log_recovery(
int 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 */