📄 xfs_buf_item.c
字号:
bip->bli_flags |= XFS_BLI_DIRTY; /* * Convert byte offsets to bit numbers. */ first_bit = first >> XFS_BLI_SHIFT; last_bit = last >> XFS_BLI_SHIFT; /* * Calculate the total number of bits to be set. */ bits_to_set = last_bit - first_bit + 1; /* * Get a pointer to the first word in the bitmap * to set a bit in. */ word_num = first_bit >> BIT_TO_WORD_SHIFT; wordp = &(bip->bli_format.blf_data_map[word_num]); /* * Calculate the starting bit in the first word. */ bit = first_bit & (uint)(NBWORD - 1); /* * First set any bits in the first word of our range. * If it starts at bit 0 of the word, it will be * set below rather than here. That is what the variable * bit tells us. The variable bits_set tracks the number * of bits that have been set so far. End_bit is the number * of the last bit to be set in this word plus one. */ if (bit) { end_bit = MIN(bit + bits_to_set, (uint)NBWORD); mask = ((1 << (end_bit - bit)) - 1) << bit; *wordp |= mask; wordp++; bits_set = end_bit - bit; } else { bits_set = 0; } /* * Now set bits a whole word at a time that are between * first_bit and last_bit. */ while ((bits_to_set - bits_set) >= NBWORD) { *wordp |= 0xffffffff; bits_set += NBWORD; wordp++; } /* * Finally, set any bits left to be set in one last partial word. */ end_bit = bits_to_set - bits_set; if (end_bit) { mask = (1 << end_bit) - 1; *wordp |= mask; } xfs_buf_item_log_debug(bip, first, last);}/* * Return 1 if the buffer has some data that has been logged (at any * point, not just the current transaction) and 0 if not. */uintxfs_buf_item_dirty( xfs_buf_log_item_t *bip){ return (bip->bli_flags & XFS_BLI_DIRTY);}/* * This is called when the buf log item is no longer needed. It should * free the buf log item associated with the given buffer and clear * the buffer's pointer to the buf log item. If there are no more * items in the list, clear the b_iodone field of the buffer (see * xfs_buf_attach_iodone() below). */voidxfs_buf_item_relse( xfs_buf_t *bp){ xfs_buf_log_item_t *bip; xfs_buftrace("XFS_RELSE", bp); bip = XFS_BUF_FSPRIVATE(bp, xfs_buf_log_item_t*); XFS_BUF_SET_FSPRIVATE(bp, bip->bli_item.li_bio_list); if ((XFS_BUF_FSPRIVATE(bp, void *) == NULL) && (XFS_BUF_IODONE_FUNC(bp) != NULL)) { XFS_BUF_CLR_IODONE_FUNC(bp); }#ifdef XFS_TRANS_DEBUG kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); bip->bli_orig = NULL; kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY); bip->bli_logged = NULL;#endif /* XFS_TRANS_DEBUG */#ifdef XFS_BLI_TRACE ktrace_free(bip->bli_trace);#endif kmem_zone_free(xfs_buf_item_zone, bip);}/* * Add the given log item with its callback to the list of callbacks * to be called when the buffer's I/O completes. If it is not set * already, set the buffer's b_iodone() routine to be * xfs_buf_iodone_callbacks() and link the log item into the list of * items rooted at b_fsprivate. Items are always added as the second * entry in the list if there is a first, because the buf item code * assumes that the buf log item is first. */voidxfs_buf_attach_iodone( xfs_buf_t *bp, void (*cb)(xfs_buf_t *, xfs_log_item_t *), xfs_log_item_t *lip){ xfs_log_item_t *head_lip; ASSERT(XFS_BUF_ISBUSY(bp)); ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); lip->li_cb = cb; if (XFS_BUF_FSPRIVATE(bp, void *) != NULL) { head_lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); lip->li_bio_list = head_lip->li_bio_list; head_lip->li_bio_list = lip; } else { XFS_BUF_SET_FSPRIVATE(bp, lip); } ASSERT((XFS_BUF_IODONE_FUNC(bp) == xfs_buf_iodone_callbacks) || (XFS_BUF_IODONE_FUNC(bp) == NULL)); XFS_BUF_SET_IODONE_FUNC(bp, xfs_buf_iodone_callbacks);}STATIC voidxfs_buf_do_callbacks( xfs_buf_t *bp, xfs_log_item_t *lip){ xfs_log_item_t *nlip; while (lip != NULL) { nlip = lip->li_bio_list; ASSERT(lip->li_cb != NULL); /* * Clear the next pointer so we don't have any * confusion if the item is added to another buf. * Don't touch the log item after calling its * callback, because it could have freed itself. */ lip->li_bio_list = NULL; lip->li_cb(bp, lip); lip = nlip; }}/* * This is the iodone() function for buffers which have had callbacks * attached to them by xfs_buf_attach_iodone(). It should remove each * log item from the buffer's list and call the callback of each in turn. * When done, the buffer's fsprivate field is set to NULL and the buffer * is unlocked with a call to iodone(). */voidxfs_buf_iodone_callbacks( xfs_buf_t *bp){ xfs_log_item_t *lip; static ulong lasttime; static xfs_buftarg_t *lasttarg; xfs_mount_t *mp; ASSERT(XFS_BUF_FSPRIVATE(bp, void *) != NULL); lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); if (XFS_BUF_GETERROR(bp) != 0) { /* * If we've already decided to shutdown the filesystem * because of IO errors, there's no point in giving this * a retry. */ mp = lip->li_mountp; if (XFS_FORCED_SHUTDOWN(mp)) { ASSERT(XFS_BUF_TARGET(bp) == mp->m_ddev_targp); XFS_BUF_SUPER_STALE(bp); xfs_buftrace("BUF_IODONE_CB", bp); xfs_buf_do_callbacks(bp, lip); XFS_BUF_SET_FSPRIVATE(bp, NULL); XFS_BUF_CLR_IODONE_FUNC(bp); /* * XFS_SHUT flag gets set when we go thru the * entire buffer cache and deliberately start * throwing away delayed write buffers. * Since there's no biowait done on those, * we should just brelse them. */ if (XFS_BUF_ISSHUT(bp)) { XFS_BUF_UNSHUT(bp); xfs_buf_relse(bp); } else { xfs_biodone(bp); } return; } if ((XFS_BUF_TARGET(bp) != lasttarg) || (time_after(jiffies, (lasttime + 5*HZ)))) { lasttime = jiffies; cmn_err(CE_ALERT, "Device %s, XFS metadata write error" " block 0x%llx in %s", XFS_BUFTARG_NAME(XFS_BUF_TARGET(bp)), (__uint64_t)XFS_BUF_ADDR(bp), mp->m_fsname); } lasttarg = XFS_BUF_TARGET(bp); if (XFS_BUF_ISASYNC(bp)) { /* * If the write was asynchronous then noone will be * looking for the error. Clear the error state * and write the buffer out again delayed write. * * XXXsup This is OK, so long as we catch these * before we start the umount; we don't want these * DELWRI metadata bufs to be hanging around. */ XFS_BUF_ERROR(bp,0); /* errno of 0 unsets the flag */ if (!(XFS_BUF_ISSTALE(bp))) { XFS_BUF_DELAYWRITE(bp); XFS_BUF_DONE(bp); XFS_BUF_SET_START(bp); } ASSERT(XFS_BUF_IODONE_FUNC(bp)); xfs_buftrace("BUF_IODONE ASYNC", bp); xfs_buf_relse(bp); } else { /* * If the write of the buffer was not asynchronous, * then we want to make sure to return the error * to the caller of bwrite(). Because of this we * cannot clear the B_ERROR state at this point. * Instead we install a callback function that * will be called when the buffer is released, and * that routine will clear the error state and * set the buffer to be written out again after * some delay. */ /* We actually overwrite the existing b-relse function at times, but we're gonna be shutting down anyway. */ XFS_BUF_SET_BRELSE_FUNC(bp,xfs_buf_error_relse); XFS_BUF_DONE(bp); XFS_BUF_V_IODONESEMA(bp); } return; }#ifdef XFSERRORDEBUG xfs_buftrace("XFS BUFCB NOERR", bp);#endif xfs_buf_do_callbacks(bp, lip); XFS_BUF_SET_FSPRIVATE(bp, NULL); XFS_BUF_CLR_IODONE_FUNC(bp); xfs_biodone(bp);}/* * This is a callback routine attached to a buffer which gets an error * when being written out synchronously. */STATIC voidxfs_buf_error_relse( xfs_buf_t *bp){ xfs_log_item_t *lip; xfs_mount_t *mp; lip = XFS_BUF_FSPRIVATE(bp, xfs_log_item_t *); mp = (xfs_mount_t *)lip->li_mountp; ASSERT(XFS_BUF_TARGET(bp) == mp->m_ddev_targp); XFS_BUF_STALE(bp); XFS_BUF_DONE(bp); XFS_BUF_UNDELAYWRITE(bp); XFS_BUF_ERROR(bp,0); xfs_buftrace("BUF_ERROR_RELSE", bp); if (! XFS_FORCED_SHUTDOWN(mp)) xfs_force_shutdown(mp, SHUTDOWN_META_IO_ERROR); /* * We have to unpin the pinned buffers so do the * callbacks. */ xfs_buf_do_callbacks(bp, lip); XFS_BUF_SET_FSPRIVATE(bp, NULL); XFS_BUF_CLR_IODONE_FUNC(bp); XFS_BUF_SET_BRELSE_FUNC(bp,NULL); xfs_buf_relse(bp);}/* * This is the iodone() function for buffers which have been * logged. It is called when they are eventually flushed out. * It should remove the buf item from the AIL, and free the buf item. * It is called by xfs_buf_iodone_callbacks() above which will take * care of cleaning up the buffer itself. *//* ARGSUSED */voidxfs_buf_iodone( xfs_buf_t *bp, xfs_buf_log_item_t *bip){ struct xfs_mount *mp; SPLDECL(s); ASSERT(bip->bli_buf == bp); mp = bip->bli_item.li_mountp; /* * If we are forcibly shutting down, this may well be * off the AIL already. That's because we simulate the * log-committed callbacks to unpin these buffers. Or we may never * have put this item on AIL because of the transaction was * aborted forcibly. xfs_trans_delete_ail() takes care of these. * * Either way, AIL is useless if we're forcing a shutdown. */ AIL_LOCK(mp,s); /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)bip, s);#ifdef XFS_TRANS_DEBUG kmem_free(bip->bli_orig, XFS_BUF_COUNT(bp)); bip->bli_orig = NULL; kmem_free(bip->bli_logged, XFS_BUF_COUNT(bp) / NBBY); bip->bli_logged = NULL;#endif /* XFS_TRANS_DEBUG */#ifdef XFS_BLI_TRACE ktrace_free(bip->bli_trace);#endif kmem_zone_free(xfs_buf_item_zone, bip);}#if defined(XFS_BLI_TRACE)voidxfs_buf_item_trace( char *id, xfs_buf_log_item_t *bip){ xfs_buf_t *bp; ASSERT(bip->bli_trace != NULL); bp = bip->bli_buf; ktrace_enter(bip->bli_trace, (void *)id, (void *)bip->bli_buf, (void *)((unsigned long)bip->bli_flags), (void *)((unsigned long)bip->bli_recur), (void *)((unsigned long)atomic_read(&bip->bli_refcount)), (void *)((unsigned long) (0xFFFFFFFF & XFS_BUF_ADDR(bp) >> 32)), (void *)((unsigned long)(0xFFFFFFFF & XFS_BUF_ADDR(bp))), (void *)((unsigned long)XFS_BUF_COUNT(bp)), (void *)((unsigned long)XFS_BUF_BFLAGS(bp)), XFS_BUF_FSPRIVATE(bp, void *), XFS_BUF_FSPRIVATE2(bp, void *), (void *)(unsigned long)XFS_BUF_ISPINNED(bp), (void *)XFS_BUF_IODONE_FUNC(bp), (void *)((unsigned long)(XFS_BUF_VALUSEMA(bp))), (void *)bip->bli_item.li_desc, (void *)((unsigned long)bip->bli_item.li_flags));}#endif /* XFS_BLI_TRACE */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -