mirror of https://gitee.com/openkylin/linux.git
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:
parent
e2714bf8d5
commit
d5689eaa0a
|
@ -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);
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
|
@ -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 */
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue