Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d5689eaa authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Alex Elder
Browse files

xfs: use struct list_head for the buf cancel table



Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarAlex Elder <aelder@sgi.com>
parent e2714bf8
Loading
Loading
Loading
Loading
+0 −11
Original line number Diff line number Diff line
@@ -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);
+4 −2
Original line number Diff line number Diff line
@@ -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 */
+61 −98
Original line number Diff line number Diff line
@@ -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.
	 */
	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.
	 * Insert an xfs_buf_cancel record into the hash table of them.
	 * If there is already an identical record, bump its reference count.
	 */
	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,56 +1687,37 @@ 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.
	 * Search for an entry in the  cancel table that matches our buffer.
	 */
		ASSERT(!(flags & XFS_BLF_CANCEL));
		return 0;
	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.
	 * We didn't find a corresponding entry in the table, so return 0 so
	 * that the buffer is NOT cancelled.
	 */
	prevp = NULL;
	while (bcp != NULL) {
		if (bcp->bc_blkno == blkno && bcp->bc_len == len) {
	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.
	 * 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;
					}
		if (--bcp->bc_refcount == 0) {
			list_del(&bcp->bc_list);
			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));
	return 0;
}

/*
 * Perform recovery for a buffer full of inodes.  In these buffers, the only
@@ -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 */