/* * This is called to unpin the buffer associated with the buf log * item which was previously pinned with a call to xfs_buf_item_pin(). * Just call bunpin() on the buffer to do this. * * Also drop the reference to the buf item for the current transaction. * If the XFS_BLI_STALE flag is set and we are the last reference, * then free up the buf log item and unlock the buffer. */ void xfs_buf_item_unpin( xfs_buf_log_item_t *bip, int stale) { xfs_mount_t *mp; xfs_buf_t *bp; int freed; SPLDECL(s); bp = bip->bli_buf; ASSERT(bp != NULL); ASSERT(XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *) == bip); ASSERT(atomic_read(&bip->bli_refcount) > 0); xfs_buf_item_trace("UNPIN", bip); xfs_buftrace("XFS_UNPIN", bp); freed = atomic_dec_and_test(&bip->bli_refcount); mp = bip->bli_item.li_mountp; xfs_bunpin(bp); if (freed && stale) { ASSERT(bip->bli_flags & XFS_BLI_STALE); ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); ASSERT(!(XFS_BUF_ISDELAYWRITE(bp))); ASSERT(XFS_BUF_ISSTALE(bp)); ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); xfs_buf_item_trace("UNPIN STALE", bip); xfs_buftrace("XFS_UNPIN STALE", bp); /* * If we get called here because of an IO error, we may * or may not have the item on the AIL. xfs_trans_delete_ail() * will take care of that situation. * xfs_trans_delete_ail() drops the AIL lock. */ if (bip->bli_flags & XFS_BLI_STALE_INODE) { xfs_buf_do_callbacks(bp, (xfs_log_item_t *)bip); XFS_BUF_SET_FSPRIVATE(bp, NULL); XFS_BUF_CLR_IODONE_FUNC(bp); } else { AIL_LOCK(mp,s); xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s); xfs_buf_item_relse(bp); ASSERT(XFS_BUF_FSPRIVATE(bp, void *) == NULL); } xfs_buf_relse(bp); }
/* * Get and lock the buffer for the caller if it is not already * locked within the given transaction. If it is already locked * within the transaction, just increment its lock recursion count * and return a pointer to it. * * Use the fast path function xfs_trans_buf_item_match() or the buffer * cache routine incore_match() to find the buffer * if it is already owned by this transaction. * * If we don't already own the buffer, use get_buf() to get it. * If it doesn't yet have an associated xfs_buf_log_item structure, * then allocate one and add the item to this transaction. * * If the transaction pointer is NULL, make this just a normal * get_buf() call. */ xfs_buf_t * xfs_trans_get_buf(xfs_trans_t *tp, xfs_buftarg_t *target_dev, xfs_daddr_t blkno, int len, uint flags) { xfs_buf_t *bp; xfs_buf_log_item_t *bip; if (flags == 0) flags = XFS_BUF_LOCK | XFS_BUF_MAPPED; /* * Default to a normal get_buf() call if the tp is NULL. */ if (tp == NULL) { bp = xfs_buf_get_flags(target_dev, blkno, len, flags | BUF_BUSY); return(bp); } /* * If we find the buffer in the cache with this transaction * pointer in its b_fsprivate2 field, then we know we already * have it locked. In this case we just increment the lock * recursion count and return the buffer to the caller. */ if (tp->t_items.lic_next == NULL) { bp = xfs_trans_buf_item_match(tp, target_dev, blkno, len); } else { bp = xfs_trans_buf_item_match_all(tp, target_dev, blkno, len); } if (bp != NULL) { ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); if (XFS_FORCED_SHUTDOWN(tp->t_mountp)) { xfs_buftrace("TRANS GET RECUR SHUT", bp); XFS_BUF_SUPER_STALE(bp); } /* * If the buffer is stale then it was binval'ed * since last read. This doesn't matter since the * caller isn't allowed to use the data anyway. */ else if (XFS_BUF_ISSTALE(bp)) { xfs_buftrace("TRANS GET RECUR STALE", bp); ASSERT(!XFS_BUF_ISDELAYWRITE(bp)); } ASSERT(XFS_BUF_FSPRIVATE2(bp, xfs_trans_t *) == tp); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t *); ASSERT(bip != NULL); ASSERT(atomic_read(&bip->bli_refcount) > 0); bip->bli_recur++; xfs_buftrace("TRANS GET RECUR", bp); xfs_buf_item_trace("GET RECUR", bip); return (bp); }
/* * This is called to pin the buffer associated with the buf log * item in memory so it cannot be written out. Simply call bpin() * on the buffer to do this. */ void xfs_buf_item_pin( xfs_buf_log_item_t *bip) { xfs_buf_t *bp; bp = bip->bli_buf; ASSERT(XFS_BUF_ISBUSY(bp)); ASSERT(atomic_read(&bip->bli_refcount) > 0); ASSERT((bip->bli_flags & XFS_BLI_LOGGED) || (bip->bli_flags & XFS_BLI_STALE)); xfs_buf_item_trace("PIN", bip); xfs_buftrace("XFS_PIN", bp); xfs_bpin(bp); }
/* * 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. */ 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; ASSERT(XFS_BUF_BP_ISMAPPED(bp)); 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; 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_buf_item_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_buf_item_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; 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; nvecs++; vecp++; first_bit = next_bit; last_bit = next_bit; nbits = 1; } else if (xfs_buf_offset(bp, next_bit * XFS_BLI_CHUNK) != (xfs_buf_offset(bp, last_bit * XFS_BLI_CHUNK) + 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; nvecs++; vecp++; first_bit = next_bit; last_bit = next_bit; } 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. */ 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_buf_item_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_buf_item_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; }