#include "xfs_utils.h"
#include "xfs_dir2_trace.h"
#include "xfs_quota.h"
-#include "xfs_mac.h"
#include "xfs_acl.h"
xfs_trans_t *tp,
xfs_ino_t ino,
xfs_inode_t **ipp,
- xfs_daddr_t bno)
+ xfs_daddr_t bno,
+ uint imap_flags)
{
xfs_buf_t *bp;
xfs_dinode_t *dip;
ip = kmem_zone_zalloc(xfs_inode_zone, KM_SLEEP);
ip->i_ino = ino;
ip->i_mount = mp;
+ spin_lock_init(&ip->i_flags_lock);
/*
* Get pointer's to the on-disk inode and the buffer containing it.
* return NULL as well. Set i_blkno to 0 so that xfs_itobp() will
* know that this is a new incore inode.
*/
- error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, 0);
+ error = xfs_itobp(mp, tp, ip, &dip, &bp, bno, imap_flags);
if (error) {
kmem_zone_free(xfs_inode_zone, ip);
return error;
* to prevent others from looking at until we're done.
*/
error = xfs_trans_iget(tp->t_mountp, tp, ino,
- IGET_CREATE, XFS_ILOCK_EXCL, &ip);
+ XFS_IGET_CREATE, XFS_ILOCK_EXCL, &ip);
if (error != 0) {
return error;
}
* Duplicate the transaction that has the permanent
* reservation and commit the old transaction.
*/
- error = xfs_bmap_finish(tp, &free_list, first_block,
- &committed);
+ error = xfs_bmap_finish(tp, &free_list, &committed);
ntp = *tp;
if (error) {
/*
* and any blocks between the old and new file sizes.
*/
error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size,
- ip->i_d.di_size, new_size);
+ ip->i_d.di_size);
return error;
}
return 0;
}
-static __inline__ int xfs_inode_clean(xfs_inode_t *ip)
+STATIC_INLINE int xfs_inode_clean(xfs_inode_t *ip)
{
return (((ip->i_itemp == NULL) ||
!(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL)) &&
/* Inode not in memory or we found it already,
* nothing to do
*/
- if (!ip || (ip->i_flags & XFS_ISTALE)) {
+ if (!ip || xfs_iflags_test(ip, XFS_ISTALE)) {
read_unlock(&ih->ih_lock);
continue;
}
if (ip == free_ip) {
if (xfs_iflock_nowait(ip)) {
- ip->i_flags |= XFS_ISTALE;
-
+ xfs_iflags_set(ip, XFS_ISTALE);
if (xfs_inode_clean(ip)) {
xfs_ifunlock(ip);
} else {
if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL)) {
if (xfs_iflock_nowait(ip)) {
- ip->i_flags |= XFS_ISTALE;
+ xfs_iflags_set(ip, XFS_ISTALE);
if (xfs_inode_clean(ip)) {
xfs_ifunlock(ip);
AIL_LOCK(mp,s);
iip->ili_flush_lsn = iip->ili_item.li_lsn;
AIL_UNLOCK(mp, s);
- iip->ili_inode->i_flags |= XFS_ISTALE;
+ xfs_iflags_set(iip->ili_inode, XFS_ISTALE);
pre_flushed++;
}
lip = lip->li_bio_list;
ktrace_free(ip->i_dir_trace);
#endif
if (ip->i_itemp) {
- /* XXXdpd should be able to assert this but shutdown
- * is leaving the AIL behind. */
- ASSERT(((ip->i_itemp->ili_item.li_flags & XFS_LI_IN_AIL) == 0) ||
- XFS_FORCED_SHUTDOWN(ip->i_mount));
+ /*
+ * Only if we are shutting down the fs will we see an
+ * inode still in the AIL. If it is there, we should remove
+ * it to prevent a use-after-free from occurring.
+ */
+ xfs_mount_t *mp = ip->i_mount;
+ xfs_log_item_t *lip = &ip->i_itemp->ili_item;
+ int s;
+
+ ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) ||
+ XFS_FORCED_SHUTDOWN(ip->i_mount));
+ if (lip->li_flags & XFS_LI_IN_AIL) {
+ AIL_LOCK(mp, s);
+ if (lip->li_flags & XFS_LI_IN_AIL)
+ xfs_trans_delete_ail(mp, lip, s);
+ else
+ AIL_UNLOCK(mp, s);
+ }
xfs_inode_item_destroy(ip);
}
kmem_zone_free(xfs_inode_zone, ip);
{
ASSERT(atomic_read(&ip->i_pincount) > 0);
- if (atomic_dec_and_test(&ip->i_pincount)) {
+ if (atomic_dec_and_lock(&ip->i_pincount, &ip->i_flags_lock)) {
+
/*
- * If the inode is currently being reclaimed, the
- * linux inode _and_ the xfs vnode may have been
- * freed so we cannot reference either of them safely.
- * Hence we should not try to do anything to them
- * if the xfs inode is currently in the reclaim
- * path.
+ * If the inode is currently being reclaimed, the link between
+ * the bhv_vnode and the xfs_inode will be broken after the
+ * XFS_IRECLAIM* flag is set. Hence, if these flags are not
+ * set, then we can move forward and mark the linux inode dirty
+ * knowing that it is still valid as it won't freed until after
+ * the bhv_vnode<->xfs_inode link is broken in xfs_reclaim. The
+ * i_flags_lock is used to synchronise the setting of the
+ * XFS_IRECLAIM* flags and the breaking of the link, and so we
+ * can execute atomically w.r.t to reclaim by holding this lock
+ * here.
*
- * However, we still need to issue the unpin wakeup
- * call as the inode reclaim may be blocked waiting for
- * the inode to become unpinned.
+ * However, we still need to issue the unpin wakeup call as the
+ * inode reclaim may be blocked waiting for the inode to become
+ * unpinned.
*/
- if (!(ip->i_flags & (XFS_IRECLAIM|XFS_IRECLAIMABLE))) {
+
+ if (!__xfs_iflags_test(ip, XFS_IRECLAIM|XFS_IRECLAIMABLE)) {
bhv_vnode_t *vp = XFS_ITOV_NULL(ip);
+ struct inode *inode = NULL;
- /* make sync come back and flush this inode */
- if (vp) {
- struct inode *inode = vn_to_inode(vp);
+ BUG_ON(vp == NULL);
+ inode = vn_to_inode(vp);
+ BUG_ON(inode->i_state & I_CLEAR);
- if (!(inode->i_state &
- (I_NEW|I_FREEING|I_CLEAR)))
- mark_inode_dirty_sync(inode);
- }
+ /* make sync come back and flush this inode */
+ if (!(inode->i_state & (I_NEW|I_FREEING)))
+ mark_inode_dirty_sync(inode);
}
+ spin_unlock(&ip->i_flags_lock);
wake_up(&ip->i_ipin_wait);
}
}