📄 xfs_inode_item.c
字号:
* failed to get the inode flush lock but did get the inode locked SHARED. * Here we're trying to see if the inode buffer is incore, and if so whether it's * marked delayed write. If that's the case, we'll initiate a bawrite on that * buffer to expedite the process. * * We aren't holding the AIL_LOCK (or the flush lock) when this gets called, * so it is inherently race-y. */STATIC voidxfs_inode_item_pushbuf( xfs_inode_log_item_t *iip){ xfs_inode_t *ip; xfs_mount_t *mp; xfs_buf_t *bp; uint dopush; ip = iip->ili_inode; ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS)); /* * The ili_pushbuf_flag keeps others from * trying to duplicate our effort. */ ASSERT(iip->ili_pushbuf_flag != 0); ASSERT(iip->ili_push_owner == current_pid()); /* * If flushlock isn't locked anymore, chances are that the * inode flush completed and the inode was taken off the AIL. * So, just get out. */ if (!issemalocked(&(ip->i_flock)) || ((iip->ili_item.li_flags & XFS_LI_IN_AIL) == 0)) { iip->ili_pushbuf_flag = 0; xfs_iunlock(ip, XFS_ILOCK_SHARED); return; } mp = ip->i_mount; bp = xfs_incore(mp->m_ddev_targp, iip->ili_format.ilf_blkno, iip->ili_format.ilf_len, XFS_INCORE_TRYLOCK); if (bp != NULL) { if (XFS_BUF_ISDELAYWRITE(bp)) { /* * We were racing with iflush because we don't hold * the AIL_LOCK or the flush lock. However, at this point, * we have the buffer, and we know that it's dirty. * So, it's possible that iflush raced with us, and * this item is already taken off the AIL. * If not, we can flush it async. */ dopush = ((iip->ili_item.li_flags & XFS_LI_IN_AIL) && issemalocked(&(ip->i_flock))); iip->ili_pushbuf_flag = 0; xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_buftrace("INODE ITEM PUSH", bp); if (XFS_BUF_ISPINNED(bp)) { xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE); } if (dopush) { xfs_bawrite(mp, bp); } else { xfs_buf_relse(bp); } } else { iip->ili_pushbuf_flag = 0; xfs_iunlock(ip, XFS_ILOCK_SHARED); xfs_buf_relse(bp); } return; } /* * We have to be careful about resetting pushbuf flag too early (above). * Even though in theory we can do it as soon as we have the buflock, * we don't want others to be doing work needlessly. They'll come to * this function thinking that pushing the buffer is their * responsibility only to find that the buffer is still locked by * another doing the same thing */ iip->ili_pushbuf_flag = 0; xfs_iunlock(ip, XFS_ILOCK_SHARED); return;}/* * This is called to asynchronously write the inode associated with this * inode log item out to disk. The inode will already have been locked by * a successful call to xfs_inode_item_trylock(). */STATIC voidxfs_inode_item_push( xfs_inode_log_item_t *iip){ xfs_inode_t *ip; ip = iip->ili_inode; ASSERT(ismrlocked(&(ip->i_lock), MR_ACCESS)); ASSERT(issemalocked(&(ip->i_flock))); /* * Since we were able to lock the inode's flush lock and * we found it on the AIL, the inode must be dirty. This * is because the inode is removed from the AIL while still * holding the flush lock in xfs_iflush_done(). Thus, if * we found it in the AIL and were able to obtain the flush * lock without sleeping, then there must not have been * anyone in the process of flushing the inode. */ ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || iip->ili_format.ilf_fields != 0); /* * Write out the inode. The completion routine ('iflush_done') will * pull it from the AIL, mark it clean, unlock the flush lock. */ (void) xfs_iflush(ip, XFS_IFLUSH_ASYNC); xfs_iunlock(ip, XFS_ILOCK_SHARED); return;}/* * XXX rcc - this one really has to do something. Probably needs * to stamp in a new field in the incore inode. *//* ARGSUSED */STATIC voidxfs_inode_item_committing( xfs_inode_log_item_t *iip, xfs_lsn_t lsn){ iip->ili_last_lsn = lsn; return;}/* * This is the ops vector shared by all buf log items. */static struct xfs_item_ops xfs_inode_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_inode_item_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_inode_item_format, .iop_pin = (void(*)(xfs_log_item_t*))xfs_inode_item_pin, .iop_unpin = (void(*)(xfs_log_item_t*, int))xfs_inode_item_unpin, .iop_unpin_remove = (void(*)(xfs_log_item_t*, xfs_trans_t*)) xfs_inode_item_unpin_remove, .iop_trylock = (uint(*)(xfs_log_item_t*))xfs_inode_item_trylock, .iop_unlock = (void(*)(xfs_log_item_t*))xfs_inode_item_unlock, .iop_committed = (xfs_lsn_t(*)(xfs_log_item_t*, xfs_lsn_t)) xfs_inode_item_committed, .iop_push = (void(*)(xfs_log_item_t*))xfs_inode_item_push, .iop_pushbuf = (void(*)(xfs_log_item_t*))xfs_inode_item_pushbuf, .iop_committing = (void(*)(xfs_log_item_t*, xfs_lsn_t)) xfs_inode_item_committing};/* * Initialize the inode log item for a newly allocated (in-core) inode. */voidxfs_inode_item_init( xfs_inode_t *ip, xfs_mount_t *mp){ xfs_inode_log_item_t *iip; ASSERT(ip->i_itemp == NULL); iip = ip->i_itemp = kmem_zone_zalloc(xfs_ili_zone, KM_SLEEP); iip->ili_item.li_type = XFS_LI_INODE; iip->ili_item.li_ops = &xfs_inode_item_ops; iip->ili_item.li_mountp = mp; iip->ili_inode = ip; /* We have zeroed memory. No need ... iip->ili_extents_buf = NULL; iip->ili_pushbuf_flag = 0; */ iip->ili_format.ilf_type = XFS_LI_INODE; iip->ili_format.ilf_ino = ip->i_ino; iip->ili_format.ilf_blkno = ip->i_blkno; iip->ili_format.ilf_len = ip->i_len; iip->ili_format.ilf_boffset = ip->i_boffset;}/* * Free the inode log item and any memory hanging off of it. */voidxfs_inode_item_destroy( xfs_inode_t *ip){#ifdef XFS_TRANS_DEBUG if (ip->i_itemp->ili_root_size != 0) { kmem_free(ip->i_itemp->ili_orig_root, ip->i_itemp->ili_root_size); }#endif kmem_zone_free(xfs_ili_zone, ip->i_itemp);}/* * This is the inode flushing I/O completion routine. It is called * from interrupt level when the buffer containing the inode is * flushed to disk. It is responsible for removing the inode item * from the AIL if it has not been re-logged, and unlocking the inode's * flush lock. *//*ARGSUSED*/voidxfs_iflush_done( xfs_buf_t *bp, xfs_inode_log_item_t *iip){ xfs_inode_t *ip; SPLDECL(s); ip = iip->ili_inode; /* * 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 ili_logged flag is set and the inode's lsn has not * changed. First we check the lsn outside * the lock since it's cheaper, and then we recheck while * holding the lock before removing the inode from the AIL. */ if (iip->ili_logged && (iip->ili_item.li_lsn == iip->ili_flush_lsn)) { AIL_LOCK(ip->i_mount, s); if (iip->ili_item.li_lsn == iip->ili_flush_lsn) { /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(ip->i_mount, (xfs_log_item_t*)iip, s); } else { AIL_UNLOCK(ip->i_mount, s); } } iip->ili_logged = 0; /* * Clear the ili_last_fields bits now that we know that the * data corresponding to them is safely on disk. */ iip->ili_last_fields = 0; /* * Release the inode's flush lock since we're done with it. */ xfs_ifunlock(ip); return;}/* * This is the inode flushing abort routine. It is called * from xfs_iflush when the filesystem is shutting down to clean * up the inode state. * It is responsible for removing the inode item * from the AIL if it has not been re-logged, and unlocking the inode's * flush lock. */voidxfs_iflush_abort( xfs_inode_t *ip){ xfs_inode_log_item_t *iip; xfs_mount_t *mp; SPLDECL(s); iip = ip->i_itemp; mp = ip->i_mount; if (iip) { if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { AIL_LOCK(mp, s); if (iip->ili_item.li_flags & XFS_LI_IN_AIL) { /* * xfs_trans_delete_ail() drops the AIL lock. */ xfs_trans_delete_ail(mp, (xfs_log_item_t *)iip, s); } else AIL_UNLOCK(mp, s); } iip->ili_logged = 0; /* * Clear the ili_last_fields bits now that we know that the * data corresponding to them is safely on disk. */ iip->ili_last_fields = 0; /* * Clear the inode logging fields so no more flushes are * attempted. */ iip->ili_format.ilf_fields = 0; } /* * Release the inode's flush lock since we're done with it. */ xfs_ifunlock(ip);}voidxfs_istale_done( xfs_buf_t *bp, xfs_inode_log_item_t *iip){ xfs_iflush_abort(iip->ili_inode);}/* * convert an xfs_inode_log_format struct from either 32 or 64 bit versions * (which can have different field alignments) to the native version */intxfs_inode_item_format_convert( xfs_log_iovec_t *buf, xfs_inode_log_format_t *in_f){ if (buf->i_len == sizeof(xfs_inode_log_format_32_t)) { xfs_inode_log_format_32_t *in_f32; in_f32 = (xfs_inode_log_format_32_t *)buf->i_addr; in_f->ilf_type = in_f32->ilf_type; in_f->ilf_size = in_f32->ilf_size; in_f->ilf_fields = in_f32->ilf_fields; in_f->ilf_asize = in_f32->ilf_asize; in_f->ilf_dsize = in_f32->ilf_dsize; in_f->ilf_ino = in_f32->ilf_ino; /* copy biggest field of ilf_u */ memcpy(in_f->ilf_u.ilfu_uuid.__u_bits, in_f32->ilf_u.ilfu_uuid.__u_bits, sizeof(uuid_t)); in_f->ilf_blkno = in_f32->ilf_blkno; in_f->ilf_len = in_f32->ilf_len; in_f->ilf_boffset = in_f32->ilf_boffset; return 0; } else if (buf->i_len == sizeof(xfs_inode_log_format_64_t)){ xfs_inode_log_format_64_t *in_f64; in_f64 = (xfs_inode_log_format_64_t *)buf->i_addr; in_f->ilf_type = in_f64->ilf_type; in_f->ilf_size = in_f64->ilf_size; in_f->ilf_fields = in_f64->ilf_fields; in_f->ilf_asize = in_f64->ilf_asize; in_f->ilf_dsize = in_f64->ilf_dsize; in_f->ilf_ino = in_f64->ilf_ino; /* copy biggest field of ilf_u */ memcpy(in_f->ilf_u.ilfu_uuid.__u_bits, in_f64->ilf_u.ilfu_uuid.__u_bits, sizeof(uuid_t)); in_f->ilf_blkno = in_f64->ilf_blkno; in_f->ilf_len = in_f64->ilf_len; in_f->ilf_boffset = in_f64->ilf_boffset; return 0; } return EFSCORRUPTED;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -