/*
 * This returns the number of log iovecs needed to log the given buf log item.
 *
 * It calculates this as 1 iovec for the buf log format structure and 1 for each
 * stretch of non-contiguous chunks to be logged.  Contiguous chunks are logged
 * in a single iovec.
 *
 * Discontiguous buffers need a format structure per region that that is being
 * logged. This makes the changes in the buffer appear to log recovery as though
 * they came from separate buffers, just like would occur if multiple buffers
 * were used instead of a single discontiguous buffer. This enables
 * discontiguous buffers to be in-memory constructs, completely transparent to
 * what ends up on disk.
 *
 * If the XFS_BLI_STALE flag has been set, then log nothing but the buf log
 * format structures.
 */
STATIC void
xfs_buf_item_size(
	struct xfs_log_item	*lip,
	int			*nvecs,
	int			*nbytes)
{
	struct xfs_buf_log_item	*bip = BUF_ITEM(lip);
	int			i;

	ASSERT(atomic_read(&bip->bli_refcount) > 0);
	if (bip->bli_flags & XFS_BLI_STALE) {
		/*
		 * The buffer is stale, so all we need to log
		 * is the buf log format structure with the
		 * cancel flag in it.
		 */
		trace_xfs_buf_item_size_stale(bip);
		ASSERT(bip->__bli_format.blf_flags & XFS_BLF_CANCEL);
		*nvecs += bip->bli_format_count;
		for (i = 0; i < bip->bli_format_count; i++) {
			*nbytes += xfs_buf_log_format_size(&bip->bli_formats[i]);
		}
		return;
	}

	ASSERT(bip->bli_flags & XFS_BLI_LOGGED);

	if (bip->bli_flags & XFS_BLI_ORDERED) {
		/*
		 * The buffer has been logged just to order it.
		 * It is not being included in the transaction
		 * commit, so no vectors are used at all.
		 */
		trace_xfs_buf_item_size_ordered(bip);
		*nvecs = XFS_LOG_VEC_ORDERED;
		return;
	}

	/*
	 * the vector count is based on the number of buffer vectors we have
	 * dirty bits in. This will only be greater than one when we have a
	 * compound buffer with more than one segment dirty. Hence for compound
	 * buffers we need to track which segment the dirty bits correspond to,
	 * and when we move from one segment to the next increment the vector
	 * count for the extra buf log format structure that will need to be
	 * written.
	 */
	for (i = 0; i < bip->bli_format_count; i++) {
		xfs_buf_item_size_segment(bip, &bip->bli_formats[i],
					  nvecs, nbytes);
	}
	trace_xfs_buf_item_size(bip);
}
/*
 * This returns the number of log iovecs needed to log the
 * given buf log item.
 *
 * It calculates this as 1 iovec for the buf log format structure
 * and 1 for each stretch of non-contiguous chunks to be logged.
 * Contiguous chunks are logged in a single iovec.
 *
 * If the XFS_BLI_STALE flag has been set, then log nothing.
 */
STATIC void
xfs_buf_item_size_segment(
	struct xfs_buf_log_item	*bip,
	struct xfs_buf_log_format *blfp,
	int			*nvecs,
	int			*nbytes)
{
	struct xfs_buf		*bp = bip->bli_buf;
	int			next_bit;
	int			last_bit;

	last_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0);
	if (last_bit == -1)
		return;

	/*
	 * initial count for a dirty buffer is 2 vectors - the format structure
	 * and the first dirty region.
	 */
	*nvecs += 2;
	*nbytes += xfs_buf_log_format_size(blfp) + XFS_BLF_CHUNK;

	while (last_bit != -1) {
		/*
		 * This takes the bit number to start looking from and
		 * returns the next set bit from there.  It returns -1
		 * if there are no more bits set or the start bit is
		 * beyond the end of the bitmap.
		 */
		next_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size,
					last_bit + 1);
		/*
		 * If we run out of bits, leave the loop,
		 * else if we find a new set of bits bump the number of vecs,
		 * else keep scanning the current set of bits.
		 */
		if (next_bit == -1) {
			break;
		} else if (next_bit != last_bit + 1) {
			last_bit = next_bit;
			(*nvecs)++;
		} else if (xfs_buf_offset(bp, next_bit * XFS_BLF_CHUNK) !=
			   (xfs_buf_offset(bp, last_bit * XFS_BLF_CHUNK) +
			    XFS_BLF_CHUNK)) {
			last_bit = next_bit;
			(*nvecs)++;
		} else {
			last_bit++;
		}
		*nbytes += XFS_BLF_CHUNK;
	}
}
static void
xfs_buf_item_format_segment(
	struct xfs_buf_log_item	*bip,
	struct xfs_log_vec	*lv,
	struct xfs_log_iovec	**vecp,
	uint			offset,
	struct xfs_buf_log_format *blfp)
{
	struct xfs_buf	*bp = bip->bli_buf;
	uint		base_size;
	int		first_bit;
	int		last_bit;
	int		next_bit;
	uint		nbits;

	/* copy the flags across from the base format item */
	blfp->blf_flags = bip->__bli_format.blf_flags;

	/*
	 * Base size is the actual size of the ondisk structure - it reflects
	 * the actual size of the dirty bitmap rather than the size of the in
	 * memory structure.
	 */
	base_size = xfs_buf_log_format_size(blfp);

	first_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0);
	if (!(bip->bli_flags & XFS_BLI_STALE) && first_bit == -1) {
		/*
		 * If the map is not be dirty in the transaction, mark
		 * the size as zero and do not advance the vector pointer.
		 */
		return;
	}

	blfp = xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_BFORMAT, blfp, base_size);
	blfp->blf_size = 1;

	if (bip->bli_flags & XFS_BLI_STALE) {
		/*
		 * The buffer is stale, so all we need to log
		 * is the buf log format structure with the
		 * cancel flag in it.
		 */
		trace_xfs_buf_item_format_stale(bip);
		ASSERT(blfp->blf_flags & XFS_BLF_CANCEL);
		return;
	}


	/*
	 * Fill in an iovec for each set of contiguous chunks.
	 */
	last_bit = first_bit;
	nbits = 1;
	for (;;) {
		/*
		 * This takes the bit number to start looking from and
		 * returns the next set bit from there.  It returns -1
		 * if there are no more bits set or the start bit is
		 * beyond the end of the bitmap.
		 */
		next_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size,
					(uint)last_bit + 1);
		/*
		 * If we run out of bits fill in the last iovec and get out of
		 * the loop.  Else if we start a new set of bits then fill in
		 * the iovec for the series we were looking at and start
		 * counting the bits in the new one.  Else we're still in the
		 * same set of bits so just keep counting and scanning.
		 */
		if (next_bit == -1) {
			xfs_buf_item_copy_iovec(lv, vecp, bp, offset,
						first_bit, nbits);
			blfp->blf_size++;
			break;
		} else if (next_bit != last_bit + 1 ||
		           xfs_buf_item_straddle(bp, offset, next_bit, last_bit)) {
			xfs_buf_item_copy_iovec(lv, vecp, bp, offset,
						first_bit, nbits);
			blfp->blf_size++;
			first_bit = next_bit;
			last_bit = next_bit;
			nbits = 1;
		} else {
			last_bit++;
			nbits++;
		}
	}
}
Example #4
0
static struct xfs_log_iovec *
xfs_buf_item_format_segment(
    struct xfs_buf_log_item	*bip,
    struct xfs_log_iovec	*vecp,
    uint			offset,
    struct xfs_buf_log_format *blfp)
{
    struct xfs_buf	*bp = bip->bli_buf;
    uint		base_size;
    uint		nvecs;
    int		first_bit;
    int		last_bit;
    int		next_bit;
    uint		nbits;
    uint		buffer_offset;

    /* copy the flags across from the base format item */
    blfp->blf_flags = bip->__bli_format.blf_flags;

    /*
     * Base size is the actual size of the ondisk structure - it reflects
     * the actual size of the dirty bitmap rather than the size of the in
     * memory structure.
     */
    base_size = xfs_buf_log_format_size(blfp);

    nvecs = 0;
    first_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size, 0);
    if (!(bip->bli_flags & XFS_BLI_STALE) && first_bit == -1) {
        /*
         * If the map is not be dirty in the transaction, mark
         * the size as zero and do not advance the vector pointer.
         */
        goto out;
    }

    vecp->i_addr = blfp;
    vecp->i_len = base_size;
    vecp->i_type = XLOG_REG_TYPE_BFORMAT;
    vecp++;
    nvecs = 1;

    if (bip->bli_flags & XFS_BLI_STALE) {
        /*
         * The buffer is stale, so all we need to log
         * is the buf log format structure with the
         * cancel flag in it.
         */
        trace_xfs_buf_item_format_stale(bip);
        ASSERT(blfp->blf_flags & XFS_BLF_CANCEL);
        goto out;
    }


    /*
     * Fill in an iovec for each set of contiguous chunks.
     */

    last_bit = first_bit;
    nbits = 1;
    for (;;) {
        /*
         * This takes the bit number to start looking from and
         * returns the next set bit from there.  It returns -1
         * if there are no more bits set or the start bit is
         * beyond the end of the bitmap.
         */
        next_bit = xfs_next_bit(blfp->blf_data_map, blfp->blf_map_size,
                                (uint)last_bit + 1);
        /*
         * If we run out of bits fill in the last iovec and get
         * out of the loop.
         * Else if we start a new set of bits then fill in the
         * iovec for the series we were looking at and start
         * counting the bits in the new one.
         * Else we're still in the same set of bits so just
         * keep counting and scanning.
         */
        if (next_bit == -1) {
            buffer_offset = offset + first_bit * XFS_BLF_CHUNK;
            vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
            vecp->i_len = nbits * XFS_BLF_CHUNK;
            vecp->i_type = XLOG_REG_TYPE_BCHUNK;
            nvecs++;
            break;
        } else if (next_bit != last_bit + 1) {
            buffer_offset = offset + first_bit * XFS_BLF_CHUNK;
            vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
            vecp->i_len = nbits * XFS_BLF_CHUNK;
            vecp->i_type = XLOG_REG_TYPE_BCHUNK;
            nvecs++;
            vecp++;
            first_bit = next_bit;
            last_bit = next_bit;
            nbits = 1;
        } else if (xfs_buf_offset(bp, offset +
                                  (next_bit << XFS_BLF_SHIFT)) !=
                   (xfs_buf_offset(bp, offset +
                                   (last_bit << XFS_BLF_SHIFT)) +
                    XFS_BLF_CHUNK)) {
            buffer_offset = offset + first_bit * XFS_BLF_CHUNK;
            vecp->i_addr = xfs_buf_offset(bp, buffer_offset);
            vecp->i_len = nbits * XFS_BLF_CHUNK;
            vecp->i_type = XLOG_REG_TYPE_BCHUNK;
            nvecs++;
            vecp++;
            first_bit = next_bit;
            last_bit = next_bit;
            nbits = 1;
        } else {
            last_bit++;
            nbits++;
        }
    }
out:
    blfp->blf_size = nvecs;
    return vecp;
}