/* * Prior to finally logging the inode, we have to ensure that all the * per-modification inode state changes are applied. This includes VFS inode * state updates, format conversions, verifier state synchronisation and * ensuring the inode buffer remains in memory whilst the inode is dirty. * * We have to be careful when we grab the inode cluster buffer due to lock * ordering constraints. The unlinked inode modifications (xfs_iunlink_item) * require AGI -> inode cluster buffer lock order. The inode cluster buffer is * not locked until ->precommit, so it happens after everything else has been * modified. * * Further, we have AGI -> AGF lock ordering, and with O_TMPFILE handling we * have AGI -> AGF -> iunlink item -> inode cluster buffer lock order. Hence we * cannot safely lock the inode cluster buffer in xfs_trans_log_inode() because * it can be called on a inode (e.g. via bumplink/droplink) before we take the * AGF lock modifying directory blocks. * * Rather than force a complete rework of all the transactions to call * xfs_trans_log_inode() once and once only at the end of every transaction, we * move the pinning of the inode cluster buffer to a ->precommit operation. This * matches how the xfs_iunlink_item locks the inode cluster buffer, and it * ensures that the inode cluster buffer locking is always done last in a * transaction. i.e. we ensure the lock order is always AGI -> AGF -> inode * cluster buffer. * * If we return the inode number as the precommit sort key then we'll also * guarantee that the order all inode cluster buffer locking is the same all the * inodes and unlink items in the transaction.
*/ staticint
xfs_inode_item_precommit( struct xfs_trans *tp, struct xfs_log_item *lip)
{ struct xfs_inode_log_item *iip = INODE_ITEM(lip); struct xfs_inode *ip = iip->ili_inode; struct inode *inode = VFS_I(ip); unsignedint flags = iip->ili_dirty_flags;
/* * Don't bother with i_lock for the I_DIRTY_TIME check here, as races * don't matter - we either will need an extra transaction in 24 hours * to log the timestamps, or will clear already cleared fields in the * worst case.
*/ if (inode->i_state & I_DIRTY_TIME) {
spin_lock(&inode->i_lock);
inode->i_state &= ~I_DIRTY_TIME;
spin_unlock(&inode->i_lock);
}
/* * If we're updating the inode core or the timestamps and it's possible * to upgrade this inode to bigtime format, do so now.
*/ if ((flags & (XFS_ILOG_CORE | XFS_ILOG_TIMESTAMP)) &&
xfs_has_bigtime(ip->i_mount) &&
!xfs_inode_has_bigtime(ip)) {
ip->i_diflags2 |= XFS_DIFLAG2_BIGTIME;
flags |= XFS_ILOG_CORE;
}
/* * Inode verifiers do not check that the extent size hint is an integer * multiple of the rt extent size on a directory with both rtinherit * and extszinherit flags set. If we're logging a directory that is * misconfigured in this way, clear the hint.
*/ if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
(ip->i_diflags & XFS_DIFLAG_EXTSZINHERIT) &&
xfs_extlen_to_rtxmod(ip->i_mount, ip->i_extsize) > 0) {
ip->i_diflags &= ~(XFS_DIFLAG_EXTSIZE |
XFS_DIFLAG_EXTSZINHERIT);
ip->i_extsize = 0;
flags |= XFS_ILOG_CORE;
}
/* * Record the specific change for fdatasync optimisation. This allows * fdatasync to skip log forces for inodes that are only timestamp * dirty. Once we've processed the XFS_ILOG_IVERSION flag, convert it * to XFS_ILOG_CORE so that the actual on-disk dirty tracking * (ili_fields) correctly tracks that the version has changed.
*/
spin_lock(&iip->ili_lock);
iip->ili_fsync_fields |= (flags & ~XFS_ILOG_IVERSION); if (flags & XFS_ILOG_IVERSION)
flags = ((flags & ~XFS_ILOG_IVERSION) | XFS_ILOG_CORE);
/* * Inode verifiers do not check that the CoW extent size hint is an * integer multiple of the rt extent size on a directory with both * rtinherit and cowextsize flags set. If we're logging a directory * that is misconfigured in this way, clear the hint.
*/ if ((ip->i_diflags & XFS_DIFLAG_RTINHERIT) &&
(ip->i_diflags2 & XFS_DIFLAG2_COWEXTSIZE) &&
xfs_extlen_to_rtxmod(ip->i_mount, ip->i_cowextsize) > 0) {
ip->i_diflags2 &= ~XFS_DIFLAG2_COWEXTSIZE;
ip->i_cowextsize = 0;
flags |= XFS_ILOG_CORE;
}
if (!iip->ili_item.li_buf) { struct xfs_buf *bp; int error;
/* * We hold the ILOCK here, so this inode is not going to be * flushed while we are here. Further, because there is no * buffer attached to the item, we know that there is no IO in * progress, so nothing will clear the ili_fields while we read * in the buffer. Hence we can safely drop the spin lock and * read the buffer knowing that the state will not change from * here.
*/
spin_unlock(&iip->ili_lock);
error = xfs_imap_to_bp(ip->i_mount, tp, &ip->i_imap, &bp); if (error) return error;
/* * We need an explicit buffer reference for the log item but * don't want the buffer to remain attached to the transaction. * Hold the buffer but release the transaction reference once * we've attached the inode log item to the buffer log item * list.
*/
xfs_buf_hold(bp);
spin_lock(&iip->ili_lock);
iip->ili_item.li_buf = bp;
bp->b_iodone = xfs_buf_inode_iodone;
list_add_tail(&iip->ili_item.li_bio_list, &bp->b_li_list);
xfs_trans_brelse(tp, bp);
}
/* * Always OR in the bits from the ili_last_fields field. This is to * coordinate with the xfs_iflush() and xfs_buf_inode_iodone() routines * in the eventual clearing of the ili_fields bits. See the big comment * in xfs_iflush() for an explanation of this coordination mechanism.
*/
iip->ili_fields |= (flags | iip->ili_last_fields);
spin_unlock(&iip->ili_lock);
xfs_inode_item_precommit_check(ip);
/* * We are done with the log item transaction dirty state, so clear it so * that it doesn't pollute future transactions.
*/
iip->ili_dirty_flags = 0; return 0;
}
/* * The logged size of an inode fork is always the current size of the inode * fork. This means that when an inode fork is relogged, the size of the logged * region is determined by the current state, not the combination of the * previously logged state + the current state. This is different relogging * behaviour to most other log items which will retain the size of the * previously logged changes when smaller regions are relogged. * * Hence operations that remove data from the inode fork (e.g. shortform * dir/attr remove, extent form extent removal, etc), the size of the relogged * inode gets -smaller- rather than stays the same size as the previously logged * size and this can result in the committing transaction reducing the amount of * space being consumed by the CIL.
*/ STATICvoid
xfs_inode_item_data_fork_size( struct xfs_inode_log_item *iip, int *nvecs, int *nbytes)
{ struct xfs_inode *ip = iip->ili_inode;
/* * This returns the number of iovecs needed to log the given inode item. * * We need one iovec for the inode log format structure, one for the * inode core, and possibly one for the inode data/extents/b-tree root * and one for the inode attribute data/extents/b-tree root.
*/ STATICvoid
xfs_inode_item_size( struct xfs_log_item *lip, int *nvecs, int *nbytes)
{ struct xfs_inode_log_item *iip = INODE_ITEM(lip); struct xfs_inode *ip = iip->ili_inode;
/* * The legacy DMAPI fields are only present in the on-disk and in-log inodes, * but not in the in-memory one. But we are guaranteed to have an inode buffer * in memory when logging an inode, so we can just copy it from the on-disk * inode to the in-log inode here so that recovery of file system with these * fields set to non-zero values doesn't lose them. For all other cases we zero * the fields.
*/ staticvoid
xfs_copy_dm_fields_to_log_dinode( struct xfs_inode *ip, struct xfs_log_dinode *to)
{ struct xfs_dinode *dip;
/* * Format the inode core. Current timestamp data is only in the VFS inode * fields, so we need to grab them from there. Hence rather than just copying * the XFS inode core structure, format the fields directly into the iovec.
*/ staticvoid
xfs_inode_item_format_core( struct xfs_inode *ip, struct xfs_log_vec *lv, struct xfs_log_iovec **vecp)
{ struct xfs_log_dinode *dic;
/* * This is called to fill in the vector of log iovecs for the given inode * log item. It fills the first item with an inode log format structure, * the second with the on-disk inode structure, and a possible third and/or * fourth with the inode data/extents/b-tree root and inode attributes * data/extents/b-tree root. * * Note: Always use the 64 bit inode log format structure so we don't * leave an uninitialised hole in the format item on 64 bit systems. Log * recovery on 32 bit systems handles this just fine, so there's no reason * for not using an initialising the properly padded structure all the time.
*/ STATICvoid
xfs_inode_item_format( struct xfs_log_item *lip, struct xfs_log_vec *lv)
{ struct xfs_inode_log_item *iip = INODE_ITEM(lip); struct xfs_inode *ip = iip->ili_inode; struct xfs_log_iovec *vecp = NULL; struct xfs_inode_log_format *ilf;
/* * make sure we don't leak uninitialised data into the log in the case * when we don't log every field in the inode.
*/
ilf->ilf_dsize = 0;
ilf->ilf_asize = 0;
ilf->ilf_pad = 0;
memset(&ilf->ilf_u, 0, sizeof(ilf->ilf_u));
/* update the format with the exact fields we actually logged */
ilf->ilf_fields |= (iip->ili_fields & ~XFS_ILOG_TIMESTAMP);
}
/* * This is called to pin the inode associated with the inode log * item in memory so it cannot be written out.
*/ STATICvoid
xfs_inode_item_pin( struct xfs_log_item *lip)
{ struct xfs_inode *ip = INODE_ITEM(lip)->ili_inode;
/* * This is called to unpin the inode associated with the inode log * item which was previously pinned with a call to xfs_inode_item_pin(). * * Also wake up anyone in xfs_iunpin_wait() if the count goes to 0. * * Note that unpin can race with inode cluster buffer freeing marking the buffer * stale. In that case, flush completions are run from the buffer unpin call, * which may happen before the inode is unpinned. If we lose the race, there * will be no buffer attached to the log item, but the inode will be marked * XFS_ISTALE.
*/ STATICvoid
xfs_inode_item_unpin( struct xfs_log_item *lip, int remove)
{ struct xfs_inode *ip = INODE_ITEM(lip)->ili_inode;
if (!bp || (ip->i_flags & XFS_ISTALE)) { /* * Inode item/buffer is being aborted due to cluster * buffer deletion. Trigger a log force to have that operation * completed and items removed from the AIL before the next push * attempt.
*/
trace_xfs_inode_push_stale(ip, _RET_IP_); return XFS_ITEM_PINNED;
}
if (xfs_iflags_test(ip, XFS_IFLUSHING)) return XFS_ITEM_FLUSHING;
if (!xfs_buf_trylock(bp)) return XFS_ITEM_LOCKED;
spin_unlock(&lip->li_ailp->ail_lock);
/* * We need to hold a reference for flushing the cluster buffer as it may * fail the buffer without IO submission. In which case, we better get a * reference for that completion because otherwise we don't get a * reference for IO until we queue the buffer for delwri submission.
*/
xfs_buf_hold(bp);
error = xfs_iflush_cluster(bp); if (!error) { if (!xfs_buf_delwri_queue(bp, buffer_list))
rval = XFS_ITEM_FLUSHING;
xfs_buf_relse(bp);
} else { /* * Release the buffer if we were unable to flush anything. On * any other error, the buffer has already been released.
*/ if (error == -EAGAIN)
xfs_buf_relse(bp);
rval = XFS_ITEM_LOCKED;
}
/* * This is called to find out where the oldest active copy of the inode log * item in the on disk log resides now that the last log write of it completed * at the given lsn. Since we always re-log all dirty data in an inode, the * latest copy in the on disk log is the only one that matters. Therefore, * simply return the given lsn. * * If the inode has been marked stale because the cluster is being freed, we * don't want to (re-)insert this inode into the AIL. There is a race condition * where the cluster buffer may be unpinned before the inode is inserted into * the AIL during transaction committed processing. If the buffer is unpinned * before the inode item has been committed and inserted, then it is possible * for the buffer to be written and IO completes before the inode is inserted * into the AIL. In that case, we'd be inserting a clean, stale inode into the * AIL which will never get removed. It will, however, get reclaimed which * triggers an assert in xfs_inode_free() complaining about freein an inode * still in the AIL. * * To avoid this, just unpin the inode directly and return a LSN of -1 so the * transaction committed code knows that it does not need to do any further * processing on the item.
*/ STATIC xfs_lsn_t
xfs_inode_item_committed( struct xfs_log_item *lip,
xfs_lsn_t lsn)
{ struct xfs_inode_log_item *iip = INODE_ITEM(lip); struct xfs_inode *ip = iip->ili_inode;
/* * Free the inode log item and any memory hanging off of it.
*/ void
xfs_inode_item_destroy( struct xfs_inode *ip)
{ struct xfs_inode_log_item *iip = ip->i_itemp;
/* * We only want to pull the item from the AIL if it is actually there * and its location in the log has not changed since we started the * flush. Thus, we only bother if the inode's lsn has not changed.
*/ staticvoid
xfs_iflush_ail_updates( struct xfs_ail *ailp, struct list_head *list)
{ struct xfs_log_item *lip;
xfs_lsn_t tail_lsn = 0;
/* this is an opencoded batch version of xfs_trans_ail_delete */
spin_lock(&ailp->ail_lock);
list_for_each_entry(lip, list, li_bio_list) {
xfs_lsn_t lsn;
clear_bit(XFS_LI_FAILED, &lip->li_flags); if (INODE_ITEM(lip)->ili_flush_lsn != lip->li_lsn) continue;
/* * dgc: Not sure how this happens, but it happens very * occassionaly via generic/388. xfs_iflush_abort() also * silently handles this same "under writeback but not in AIL at * shutdown" condition via xfs_trans_ail_delete().
*/ if (!test_bit(XFS_LI_IN_AIL, &lip->li_flags)) {
ASSERT(xlog_is_shutdown(lip->li_log)); continue;
}
/* * Walk the list of inodes that have completed their IOs. If they are clean * remove them from the list and dissociate them from the buffer. Buffers that * are still dirty remain linked to the buffer and on the list. Caller must * handle them appropriately.
*/ staticvoid
xfs_iflush_finish( struct xfs_buf *bp, struct list_head *list)
{ struct xfs_log_item *lip, *n;
/* * Remove the reference to the cluster buffer if the inode is * clean in memory and drop the buffer reference once we've * dropped the locks we hold.
*/
ASSERT(iip->ili_item.li_buf == bp); if (!iip->ili_fields) {
iip->ili_item.li_buf = NULL;
list_del_init(&lip->li_bio_list);
drop_buffer = true;
}
iip->ili_last_fields = 0;
iip->ili_flush_lsn = 0;
clear_bit(XFS_LI_FLUSHING, &lip->li_flags);
spin_unlock(&iip->ili_lock);
xfs_iflags_clear(iip->ili_inode, XFS_IFLUSHING); if (drop_buffer)
xfs_buf_rele(bp);
}
}
/* * Inode buffer IO completion routine. It is responsible for removing inodes * attached to the buffer from the AIL if they have not been re-logged and * completing the inode flush.
*/ void
xfs_buf_inode_iodone( struct xfs_buf *bp)
{ struct xfs_log_item *lip, *n;
LIST_HEAD(flushed_inodes);
LIST_HEAD(ail_updates);
/* * Pull the attached inodes from the buffer one at a time and take the * appropriate action on them.
*/
list_for_each_entry_safe(lip, n, &bp->b_li_list, li_bio_list) { struct xfs_inode_log_item *iip = INODE_ITEM(lip);
if (xfs_iflags_test(iip->ili_inode, XFS_ISTALE)) {
xfs_iflush_abort(iip->ili_inode); continue;
} if (!iip->ili_last_fields) continue;
/* Do an unlocked check for needing the AIL lock. */ if (iip->ili_flush_lsn == lip->li_lsn ||
test_bit(XFS_LI_FAILED, &lip->li_flags))
list_move_tail(&lip->li_bio_list, &ail_updates); else
list_move_tail(&lip->li_bio_list, &flushed_inodes);
}
if (!list_empty(&ail_updates)) {
xfs_iflush_ail_updates(bp->b_mount->m_ail, &ail_updates);
list_splice_tail(&ail_updates, &flushed_inodes);
}
xfs_iflush_finish(bp, &flushed_inodes); if (!list_empty(&flushed_inodes))
list_splice_tail(&flushed_inodes, &bp->b_li_list);
}
/* * Clear the inode logging fields so no more flushes are attempted. If we are * on a buffer list, it is now safe to remove it because the buffer is * guaranteed to be locked. The caller will drop the reference to the buffer * the log item held.
*/ staticvoid
xfs_iflush_abort_clean( struct xfs_inode_log_item *iip)
{
iip->ili_last_fields = 0;
iip->ili_fields = 0;
iip->ili_fsync_fields = 0;
iip->ili_flush_lsn = 0;
iip->ili_item.li_buf = NULL;
list_del_init(&iip->ili_item.li_bio_list);
clear_bit(XFS_LI_FLUSHING, &iip->ili_item.li_flags);
}
/* * Abort flushing the inode from a context holding the cluster buffer locked. * * This is the normal runtime method of aborting writeback of an inode that is * attached to a cluster buffer. It occurs when the inode and the backing * cluster buffer have been freed (i.e. inode is XFS_ISTALE), or when cluster * flushing or buffer IO completion encounters a log shutdown situation. * * If we need to abort inode writeback and we don't already hold the buffer * locked, call xfs_iflush_shutdown_abort() instead as this should only ever be * necessary in a shutdown situation.
*/ void
xfs_iflush_abort( struct xfs_inode *ip)
{ struct xfs_inode_log_item *iip = ip->i_itemp; struct xfs_buf *bp;
if (!iip) { /* clean inode, nothing to do */
xfs_iflags_clear(ip, XFS_IFLUSHING); return;
}
/* * Remove the inode item from the AIL before we clear its internal * state. Whilst the inode is in the AIL, it should have a valid buffer * pointer for push operations to access - it is only safe to remove the * inode from the buffer once it has been removed from the AIL.
*/
xfs_trans_ail_delete(&iip->ili_item, 0);
/* * Grab the inode buffer so can we release the reference the inode log * item holds on it.
*/
spin_lock(&iip->ili_lock);
bp = iip->ili_item.li_buf;
xfs_iflush_abort_clean(iip);
spin_unlock(&iip->ili_lock);
xfs_iflags_clear(ip, XFS_IFLUSHING); if (bp)
xfs_buf_rele(bp);
}
/* * Abort an inode flush in the case of a shutdown filesystem. This can be called * from anywhere with just an inode reference and does not require holding the * inode cluster buffer locked. If the inode is attached to a cluster buffer, * it will grab and lock it safely, then abort the inode flush.
*/ void
xfs_iflush_shutdown_abort( struct xfs_inode *ip)
{ struct xfs_inode_log_item *iip = ip->i_itemp; struct xfs_buf *bp;
if (!iip) { /* clean inode, nothing to do */
xfs_iflags_clear(ip, XFS_IFLUSHING); return;
}
spin_lock(&iip->ili_lock);
bp = iip->ili_item.li_buf; if (!bp) {
spin_unlock(&iip->ili_lock);
xfs_iflush_abort(ip); return;
}
/* * We have to take a reference to the buffer so that it doesn't get * freed when we drop the ili_lock and then wait to lock the buffer. * We'll clean up the extra reference after we pick up the ili_lock * again.
*/
xfs_buf_hold(bp);
spin_unlock(&iip->ili_lock);
xfs_buf_lock(bp);
spin_lock(&iip->ili_lock); if (!iip->ili_item.li_buf) { /* * Raced with another removal, hold the only reference * to bp now. Inode should not be in the AIL now, so just clean * up and return;
*/
ASSERT(list_empty(&iip->ili_item.li_bio_list));
ASSERT(!test_bit(XFS_LI_IN_AIL, &iip->ili_item.li_flags));
xfs_iflush_abort_clean(iip);
spin_unlock(&iip->ili_lock);
xfs_iflags_clear(ip, XFS_IFLUSHING);
xfs_buf_relse(bp); return;
}
/* * Got two references to bp. The first will get dropped by * xfs_iflush_abort() when the item is removed from the buffer list, but * we can't drop our reference until _abort() returns because we have to * unlock the buffer as well. Hence we abort and then unlock and release * our reference to the buffer.
*/
ASSERT(iip->ili_item.li_buf == bp);
spin_unlock(&iip->ili_lock);
xfs_iflush_abort(ip);
xfs_buf_relse(bp);
}
/* * convert an xfs_inode_log_format struct from the old 32 bit version * (which can have different field alignments) to the native 64 bit version
*/ int
xfs_inode_item_format_convert( struct kvec *buf, struct xfs_inode_log_format *in_f)
{ struct xfs_inode_log_format_32 *in_f32 = buf->iov_base;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.