/* * 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 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 = offsetof(struct xfs_buf_log_format, blf_data_map) + (blfp->blf_map_size * sizeof(blfp->blf_data_map[0])); 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; /* * You would think we need to bump the nvecs here too, but we do not * this number is used by recovery, and it gets confused by the boundary * split here * nvecs++; */ vecp++; first_bit = next_bit; last_bit = next_bit; nbits = 1; } else { last_bit++; nbits++; } } out: blfp->blf_size = nvecs; return vecp; }
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++; } } }
/* * This is called to fill in the vector of log iovecs for the * given log buf item. It fills the first entry with a buf log * format structure, and the rest point to contiguous chunks * within the buffer. */ STATIC void xfs_buf_item_format( xfs_buf_log_item_t *bip, xfs_log_iovec_t *log_vector) { uint base_size; uint nvecs; xfs_log_iovec_t *vecp; xfs_buf_t *bp; int first_bit; int last_bit; int next_bit; uint nbits; uint buffer_offset; ASSERT(atomic_read(&bip->bli_refcount) > 0); ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || (bip->bli_flags & XFS_BLI_STALE)); bp = bip->bli_buf; vecp = log_vector; /* * The size of the base structure is the size of the * declared structure plus the space for the extra words * of the bitmap. We subtract one from the map size, because * the first element of the bitmap is accounted for in the * size of the base structure. */ base_size = (uint)(sizeof(xfs_buf_log_format_t) + ((bip->bli_format.blf_map_size - 1) * sizeof(uint))); vecp->i_addr = (xfs_caddr_t)&bip->bli_format; vecp->i_len = base_size; XLOG_VEC_SET_TYPE(vecp, 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. */ xfs_buf_item_trace("FORMAT STALE", bip); ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); bip->bli_format.blf_size = nvecs; return; } /* * Fill in an iovec for each set of contiguous chunks. */ first_bit = xfs_next_bit(bip->bli_format.blf_data_map, bip->bli_format.blf_map_size, 0); ASSERT(first_bit != -1); 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(bip->bli_format.blf_data_map, bip->bli_format.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 = first_bit * XFS_BLI_CHUNK; vecp->i_addr = xfs_buf_offset(bp, buffer_offset); vecp->i_len = nbits * XFS_BLI_CHUNK; XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK); nvecs++; break; } else if (next_bit != last_bit + 1) { buffer_offset = first_bit * XFS_BLI_CHUNK; vecp->i_addr = xfs_buf_offset(bp, buffer_offset); vecp->i_len = nbits * XFS_BLI_CHUNK; XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK); nvecs++; vecp++; first_bit = next_bit; last_bit = next_bit; nbits = 1; } else if (xfs_buf_offset(bp, next_bit << XFS_BLI_SHIFT) != (xfs_buf_offset(bp, last_bit << XFS_BLI_SHIFT) + XFS_BLI_CHUNK)) { buffer_offset = first_bit * XFS_BLI_CHUNK; vecp->i_addr = xfs_buf_offset(bp, buffer_offset); vecp->i_len = nbits * XFS_BLI_CHUNK; XLOG_VEC_SET_TYPE(vecp, XLOG_REG_TYPE_BCHUNK); /* You would think we need to bump the nvecs here too, but we do not * this number is used by recovery, and it gets confused by the boundary * split here * nvecs++; */ vecp++; first_bit = next_bit; last_bit = next_bit; nbits = 1; } else { last_bit++; nbits++; } } bip->bli_format.blf_size = nvecs; /* * Check to make sure everything is consistent. */ xfs_buf_item_trace("FORMAT NORM", bip); xfs_buf_item_log_check(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 uint xfs_buf_item_size( xfs_buf_log_item_t *bip) { uint nvecs; int next_bit; int last_bit; xfs_buf_t *bp; 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. */ xfs_buf_item_trace("SIZE STALE", bip); ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); return 1; } bp = bip->bli_buf; ASSERT(bip->bli_flags & XFS_BLI_LOGGED); nvecs = 1; last_bit = xfs_next_bit(bip->bli_format.blf_data_map, bip->bli_format.blf_map_size, 0); ASSERT(last_bit != -1); nvecs++; 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(bip->bli_format.blf_data_map, bip->bli_format.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) { last_bit = -1; } else if (next_bit != last_bit + 1) { last_bit = next_bit; nvecs++; } else if (xfs_buf_offset(bp, next_bit * XFS_BLI_CHUNK) != (xfs_buf_offset(bp, last_bit * XFS_BLI_CHUNK) + XFS_BLI_CHUNK)) { last_bit = next_bit; nvecs++; } else { last_bit++; } } xfs_buf_item_trace("SIZE NORM", bip); return nvecs; }
/* * This is called to fill in the vector of log iovecs for the * given log buf item. It fills the first entry with a buf log * format structure, and the rest point to contiguous chunks * within the buffer. */ STATIC void xfs_buf_item_format( struct xfs_log_item *lip, struct xfs_log_iovec *vecp) { struct xfs_buf_log_item *bip = BUF_ITEM(lip); 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; ASSERT(atomic_read(&bip->bli_refcount) > 0); ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || (bip->bli_flags & XFS_BLI_STALE)); /* * The size of the base structure is the size of the * declared structure plus the space for the extra words * of the bitmap. We subtract one from the map size, because * the first element of the bitmap is accounted for in the * size of the base structure. */ base_size = (uint)(sizeof(xfs_buf_log_format_t) + ((bip->bli_format.blf_map_size - 1) * sizeof(uint))); vecp->i_addr = &bip->bli_format; vecp->i_len = base_size; vecp->i_type = XLOG_REG_TYPE_BFORMAT; vecp++; nvecs = 1; /* * If it is an inode buffer, transfer the in-memory state to the * format flags and clear the in-memory state. We do not transfer * this state if the inode buffer allocation has not yet been committed * to the log as setting the XFS_BLI_INODE_BUF flag will prevent * correct replay of the inode allocation. */ if (bip->bli_flags & XFS_BLI_INODE_BUF) { if (!((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && xfs_log_item_in_current_chkpt(lip))) bip->bli_format.blf_flags |= XFS_BLF_INODE_BUF; bip->bli_flags &= ~XFS_BLI_INODE_BUF; } 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(bip->bli_format.blf_flags & XFS_BLF_CANCEL); bip->bli_format.blf_size = nvecs; return; } /* * Fill in an iovec for each set of contiguous chunks. */ first_bit = xfs_next_bit(bip->bli_format.blf_data_map, bip->bli_format.blf_map_size, 0); ASSERT(first_bit != -1); 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(bip->bli_format.blf_data_map, bip->bli_format.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 = 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 = 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, next_bit << XFS_BLF_SHIFT) != (xfs_buf_offset(bp, last_bit << XFS_BLF_SHIFT) + XFS_BLF_CHUNK)) { buffer_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; /* You would think we need to bump the nvecs here too, but we do not * this number is used by recovery, and it gets confused by the boundary * split here * nvecs++; */ vecp++; first_bit = next_bit; last_bit = next_bit; nbits = 1; } else { last_bit++; nbits++; } } bip->bli_format.blf_size = nvecs; /* * Check to make sure everything is consistent. */ trace_xfs_buf_item_format(bip); xfs_buf_item_log_check(bip); }