📄 xfs_buf_item.c
字号:
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); }}/* * this is called from uncommit in the forced-shutdown path. * we need to check to see if the reference count on the log item * is going to drop to zero. If so, unpin will free the log item * so we need to free the item's descriptor (that points to the item) * in the transaction. */STATIC voidxfs_buf_item_unpin_remove( xfs_buf_log_item_t *bip, xfs_trans_t *tp){ xfs_buf_t *bp; xfs_log_item_desc_t *lidp; int stale = 0; bp = bip->bli_buf; /* * will xfs_buf_item_unpin() call xfs_buf_item_relse()? */ if ((atomic_read(&bip->bli_refcount) == 1) && (bip->bli_flags & XFS_BLI_STALE)) { ASSERT(XFS_BUF_VALUSEMA(bip->bli_buf) <= 0); xfs_buf_item_trace("UNPIN REMOVE", bip); xfs_buftrace("XFS_UNPIN_REMOVE", bp); /* * yes -- clear the xaction descriptor in-use flag * and free the chunk if required. We can safely * do some work here and then call buf_item_unpin * to do the rest because if the if is true, then * we are holding the buffer locked so no one else * will be able to bump up the refcount. */ lidp = xfs_trans_find_item(tp, (xfs_log_item_t *) bip); stale = lidp->lid_flags & XFS_LID_BUF_STALE; xfs_trans_free_item(tp, lidp); /* * Since the transaction no longer refers to the buffer, * the buffer should no longer refer to the transaction. */ XFS_BUF_SET_FSPRIVATE2(bp, NULL); } xfs_buf_item_unpin(bip, stale); return;}/* * This is called to attempt to lock the buffer associated with this * buf log item. Don't sleep on the buffer lock. If we can't get * the lock right away, return 0. If we can get the lock, pull the * buffer from the free list, mark it busy, and return 1. */STATIC uintxfs_buf_item_trylock( xfs_buf_log_item_t *bip){ xfs_buf_t *bp; bp = bip->bli_buf; if (XFS_BUF_ISPINNED(bp)) { return XFS_ITEM_PINNED; } if (!XFS_BUF_CPSEMA(bp)) { return XFS_ITEM_LOCKED; } /* * Remove the buffer from the free list. Only do this * if it's on the free list. Private buffers like the * superblock buffer are not. */ XFS_BUF_HOLD(bp); ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); xfs_buf_item_trace("TRYLOCK SUCCESS", bip); return XFS_ITEM_SUCCESS;}/* * Release the buffer associated with the buf log item. * If there is no dirty logged data associated with the * buffer recorded in the buf log item, then free the * buf log item and remove the reference to it in the * buffer. * * This call ignores the recursion count. It is only called * when the buffer should REALLY be unlocked, regardless * of the recursion count. * * If the XFS_BLI_HOLD flag is set in the buf log item, then * free the log item if necessary but do not unlock the buffer. * This is for support of xfs_trans_bhold(). Make sure the * XFS_BLI_HOLD field is cleared if we don't free the item. */STATIC voidxfs_buf_item_unlock( xfs_buf_log_item_t *bip){ int aborted; xfs_buf_t *bp; uint hold; bp = bip->bli_buf; xfs_buftrace("XFS_UNLOCK", bp); /* * Clear the buffer's association with this transaction. */ XFS_BUF_SET_FSPRIVATE2(bp, NULL); /* * If this is a transaction abort, don't return early. * Instead, allow the brelse to happen. * Normally it would be done for stale (cancelled) buffers * at unpin time, but we'll never go through the pin/unpin * cycle if we abort inside commit. */ aborted = (bip->bli_item.li_flags & XFS_LI_ABORTED) != 0; /* * If the buf item is marked stale, then don't do anything. * We'll unlock the buffer and free the buf item when the * buffer is unpinned for the last time. */ if (bip->bli_flags & XFS_BLI_STALE) { bip->bli_flags &= ~XFS_BLI_LOGGED; xfs_buf_item_trace("UNLOCK STALE", bip); ASSERT(bip->bli_format.blf_flags & XFS_BLI_CANCEL); if (!aborted) return; } /* * Drop the transaction's reference to the log item if * it was not logged as part of the transaction. Otherwise * we'll drop the reference in xfs_buf_item_unpin() when * the transaction is really through with the buffer. */ if (!(bip->bli_flags & XFS_BLI_LOGGED)) { atomic_dec(&bip->bli_refcount); } else { /* * Clear the logged flag since this is per * transaction state. */ bip->bli_flags &= ~XFS_BLI_LOGGED; } /* * Before possibly freeing the buf item, determine if we should * release the buffer at the end of this routine. */ hold = bip->bli_flags & XFS_BLI_HOLD; xfs_buf_item_trace("UNLOCK", bip); /* * If the buf item isn't tracking any data, free it. * Otherwise, if XFS_BLI_HOLD is set clear it. */ if (xfs_bitmap_empty(bip->bli_format.blf_data_map, bip->bli_format.blf_map_size)) { xfs_buf_item_relse(bp); } else if (hold) { bip->bli_flags &= ~XFS_BLI_HOLD; } /* * Release the buffer if XFS_BLI_HOLD was not set. */ if (!hold) { xfs_buf_relse(bp); }}/* * This is called to find out where the oldest active copy of the * buf log item in the on disk log resides now that the last log * write of it completed at the given lsn. * We always re-log all the dirty data in a buffer, so usually the * latest copy in the on disk log is the only one that matters. For * those cases we simply return the given lsn. * * The one exception to this is for buffers full of newly allocated * inodes. These buffers are only relogged with the XFS_BLI_INODE_BUF * flag set, indicating that only the di_next_unlinked fields from the * inodes in the buffers will be replayed during recovery. If the * original newly allocated inode images have not yet been flushed * when the buffer is so relogged, then we need to make sure that we * keep the old images in the 'active' portion of the log. We do this * by returning the original lsn of that transaction here rather than * the current one. */STATIC xfs_lsn_txfs_buf_item_committed( xfs_buf_log_item_t *bip, xfs_lsn_t lsn){ xfs_buf_item_trace("COMMITTED", bip); if ((bip->bli_flags & XFS_BLI_INODE_ALLOC_BUF) && (bip->bli_item.li_lsn != 0)) { return bip->bli_item.li_lsn; } return (lsn);}/* * This is called to asynchronously write the buffer associated with this * buf log item out to disk. The buffer will already have been locked by * a successful call to xfs_buf_item_trylock(). If the buffer still has * B_DELWRI set, then get it going out to disk with a call to bawrite(). * If not, then just release the buffer. */STATIC voidxfs_buf_item_push( xfs_buf_log_item_t *bip){ xfs_buf_t *bp; ASSERT(!(bip->bli_flags & XFS_BLI_STALE)); xfs_buf_item_trace("PUSH", bip); bp = bip->bli_buf; if (XFS_BUF_ISDELAYWRITE(bp)) { xfs_bawrite(bip->bli_item.li_mountp, bp); } else { xfs_buf_relse(bp); }}/* ARGSUSED */STATIC voidxfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn){}/* * This is the ops vector shared by all buf log items. */static struct xfs_item_ops xfs_buf_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_buf_item_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_buf_item_format, .iop_pin = (void(*)(xfs_log_item_t*))xfs_buf_item_pin, .iop_unpin = (void(*)(xfs_log_item_t*, int))xfs_buf_item_unpin, .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t *)) xfs_buf_item_unpin_remove, .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_buf_item_trylock, .iop_unlock = (void(*)(xfs_log_item_t*))xfs_buf_item_unlock, .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) xfs_buf_item_committed, .iop_push = (void(*)(xfs_log_item_t*))xfs_buf_item_push, .iop_pushbuf = NULL, .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) xfs_buf_item_committing};/* * Allocate a new buf log item to go with the given buffer. * Set the buffer's b_fsprivate field to point to the new * buf log item. If there are other item's attached to the * buffer (see xfs_buf_attach_iodone() below), then put the * buf log item at the front. */voidxfs_buf_item_init( xfs_buf_t *bp, xfs_mount_t *mp){ xfs_log_item_t *lip; xfs_buf_log_item_t *bip; int chunks; int map_size; /* * Check to see if there is already a buf log item for * this buffer. If there is, it is guaranteed to be * the first. If we do already have one, there is * nothing to do here so return. */ if (XFS_BUF_FSPRIVATE3(bp, xfs_mount_t *) != mp) XFS_BUF_SET_FSPRIVATE3(bp, mp); XFS_BUF_SET_BDSTRAT_FUNC(bp, xfs_bdstrat_cb); if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); if (lip->li_type == XFS_LI_BUF) { return; } } /* * chunks is the number of XFS_BLI_CHUNK size pieces * the buffer can be divided into. Make sure not to * truncate any pieces. map_size is the size of the * bitmap needed to describe the chunks of the buffer. */ chunks = (int)((XFS_BUF_COUNT(bp) + (XFS_BLI_CHUNK - 1)) >> XFS_BLI_SHIFT); map_size = (int)((chunks + NBWORD) >> BIT_TO_WORD_SHIFT); bip = (xfs_buf_log_item_t*)kmem_zone_zalloc(xfs_buf_item_zone, KM_SLEEP); bip->bli_item.li_type = XFS_LI_BUF; bip->bli_item.li_ops = &xfs_buf_item_ops; bip->bli_item.li_mountp = mp; bip->bli_buf = bp; bip->bli_format.blf_type = XFS_LI_BUF; bip->bli_format.blf_blkno = (__int64_t)XFS_BUF_ADDR(bp); bip->bli_format.blf_len = (ushort)BTOBB(XFS_BUF_COUNT(bp)); bip->bli_format.blf_map_size = map_size;#ifdef XFS_BLI_TRACE bip->bli_trace = ktrace_alloc(XFS_BLI_TRACE_SIZE, KM_SLEEP);#endif#ifdef XFS_TRANS_DEBUG /* * Allocate the arrays for tracking what needs to be logged * and what our callers request to be logged. bli_orig * holds a copy of the original, clean buffer for comparison * against, and bli_logged keeps a 1 bit flag per byte in * the buffer to indicate which bytes the callers have asked * to have logged. */ bip->bli_orig = (char *)kmem_alloc(XFS_BUF_COUNT(bp), KM_SLEEP); memcpy(bip->bli_orig, XFS_BUF_PTR(bp), XFS_BUF_COUNT(bp)); bip->bli_logged = (char *)kmem_zalloc(XFS_BUF_COUNT(bp) / NBBY, KM_SLEEP);#endif /* * Put the buf item into the list of items attached to the * buffer at the front. */ if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { bip->bli_item.li_bio_list = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); } XFS_BUF_SET_FSPRIVATE(bp, bip);}/* * Mark bytes first through last inclusive as dirty in the buf * item's bitmap. */voidxfs_buf_item_log( xfs_buf_log_item_t *bip, uint first, uint last){ uint first_bit; uint last_bit; uint bits_to_set; uint bits_set; uint word_num; uint *wordp; uint bit; uint end_bit; uint mask; /* * Mark the item as having some dirty data for * quick reference in xfs_buf_item_dirty. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -