From d98bc1e8475d8079fa7b6e61cb54850f7438e169 Mon Sep 17 00:00:00 2001 From: Christoph Hellwig Date: Tue, 14 Dec 2004 10:22:27 +1100 Subject: [PATCH] [XFS] handle inode creating race SGI-PV: 921072 SGI-Modid: xfs-linux:xfs-kern:181657a Signed-off-by: Christoph Hellwig Signed-off-by: Nathan Scott --- fs/xfs/linux-2.6/xfs_ioctl.c | 2 +- fs/xfs/linux-2.6/xfs_super.c | 4 +++ fs/xfs/quota/xfs_qm.c | 6 ++--- fs/xfs/quota/xfs_qm_syscalls.c | 12 +++++---- fs/xfs/xfs_iget.c | 47 ++++++++++++++++++++++++---------- fs/xfs/xfs_inode.c | 3 ++- fs/xfs/xfs_inode.h | 6 ++++- fs/xfs/xfs_itable.c | 2 +- fs/xfs/xfs_log_recover.c | 2 +- fs/xfs/xfs_mount.c | 2 +- fs/xfs/xfs_rtalloc.c | 18 ++++++------- fs/xfs/xfs_trans.h | 2 +- fs/xfs/xfs_trans_inode.c | 9 +++---- fs/xfs/xfs_utils.c | 2 +- fs/xfs/xfs_vfsops.c | 2 +- 15 files changed, 75 insertions(+), 44 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index a5d382cff479..284f2ad68e3a 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -270,7 +270,7 @@ xfs_vget_fsop_handlereq( /* * Get the XFS inode, building a vnode to go with it. */ - error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0); + error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); if (error) return error; if (ip == NULL) diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index 854b656c98bc..169da9dc9b9f 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -234,6 +234,10 @@ xfs_initialize_vnode( vp->v_type = IFTOVT(ip->i_d.di_mode); xfs_revalidate_inode(XFS_BHVTOM(bdp), vp, ip); xfs_set_inodeops(inode); + + ip->i_flags &= ~XFS_INEW; + barrier(); + unlock_new_inode(inode); } } diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index a7a9d664097d..89f2cd656ebf 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -1782,7 +1782,7 @@ xfs_qm_dqusage_adjust( * the case in all other instances. It's OK that we do this because * quotacheck is done only at mount time. */ - if ((error = xfs_iget(mp, NULL, ino, XFS_ILOCK_EXCL, &ip, bno))) { + if ((error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_EXCL, &ip, bno))) { *res = BULKSTAT_RV_NOTHING; return (error); } @@ -2010,14 +2010,14 @@ xfs_qm_init_quotainos( mp->m_sb.sb_uquotino != NULLFSINO) { ASSERT(mp->m_sb.sb_uquotino > 0); if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, - 0, &uip, 0))) + 0, 0, &uip, 0))) return XFS_ERROR(error); } if (XFS_IS_GQUOTA_ON(mp) && mp->m_sb.sb_gquotino != NULLFSINO) { ASSERT(mp->m_sb.sb_gquotino > 0); if ((error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, - 0, &gip, 0))) { + 0, 0, &gip, 0))) { if (uip) VN_RELE(XFS_ITOV(uip)); return XFS_ERROR(error); diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index b722dad83a6d..3548ced32724 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c @@ -404,7 +404,7 @@ xfs_qm_scall_trunc_qfiles( } if ((flags & XFS_DQ_USER) && mp->m_sb.sb_uquotino != NULLFSINO) { - error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &qip, 0); + error = xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, 0, &qip, 0); if (! error) { (void) xfs_truncate_file(mp, qip); VN_RELE(XFS_ITOV(qip)); @@ -412,7 +412,7 @@ xfs_qm_scall_trunc_qfiles( } if ((flags & XFS_DQ_GROUP) && mp->m_sb.sb_gquotino != NULLFSINO) { - error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &qip, 0); + error = xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, 0, &qip, 0); if (! error) { (void) xfs_truncate_file(mp, qip); VN_RELE(XFS_ITOV(qip)); @@ -555,11 +555,13 @@ xfs_qm_scall_getqstat( gip = mp->m_quotainfo->qi_gquotaip; } if (!uip && mp->m_sb.sb_uquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, 0, &uip, 0) == 0) + if (xfs_iget(mp, NULL, mp->m_sb.sb_uquotino, + 0, 0, &uip, 0) == 0) tempuqip = B_TRUE; } if (!gip && mp->m_sb.sb_gquotino != NULLFSINO) { - if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, 0, &gip, 0) == 0) + if (xfs_iget(mp, NULL, mp->m_sb.sb_gquotino, + 0, 0, &gip, 0) == 0) tempgqip = B_TRUE; } if (uip) { @@ -1338,7 +1340,7 @@ xfs_qm_internalqcheck_adjust( ipreleased = B_FALSE; again: lock_flags = XFS_ILOCK_SHARED; - if ((error = xfs_iget(mp, NULL, ino, lock_flags, &ip, bno))) { + if ((error = xfs_iget(mp, NULL, ino, 0, lock_flags, &ip, bno))) { *res = BULKSTAT_RV_NOTHING; return (error); } diff --git a/fs/xfs/xfs_iget.c b/fs/xfs/xfs_iget.c index 07641fc90d61..bef91642de88 100644 --- a/fs/xfs/xfs_iget.c +++ b/fs/xfs/xfs_iget.c @@ -169,6 +169,7 @@ xfs_iget_core( xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, + uint flags, uint lock_flags, xfs_inode_t **ipp, xfs_daddr_t bno) @@ -180,7 +181,6 @@ xfs_iget_core( ulong version; int error; /* REFERENCED */ - int newnode; xfs_chash_t *ch; xfs_chashlist_t *chl, *chlnew; SPLDECL(s); @@ -193,11 +193,22 @@ again: for (ip = ih->ih_next; ip != NULL; ip = ip->i_next) { if (ip->i_ino == ino) { + /* + * If INEW is set this inode is being set up + * we need to pause and try again. + */ + if (ip->i_flags & XFS_INEW) { + read_unlock(&ih->ih_lock); + delay(1); + XFS_STATS_INC(xs_ig_frecycle); - inode_vp = XFS_ITOV_NULL(ip); + goto again; + } + inode_vp = XFS_ITOV_NULL(ip); if (inode_vp == NULL) { - /* If IRECLAIM is set this inode is + /* + * If IRECLAIM is set this inode is * on its way out of the system, * we need to pause and try again. */ @@ -250,14 +261,15 @@ again: XFS_STATS_INC(xs_ig_found); finish_inode: - if (lock_flags != 0) { - xfs_ilock(ip, lock_flags); - } - - newnode = (ip->i_d.di_mode == 0); - if (newnode) { + if (ip->i_d.di_mode == 0) { + if (!(flags & IGET_CREATE)) + return ENOENT; xfs_iocore_inode_reinit(ip); } + + if (lock_flags != 0) + xfs_ilock(ip, lock_flags); + ip->i_flags &= ~XFS_ISTALE; vn_trace_exit(vp, "xfs_iget.found", @@ -293,6 +305,11 @@ finish_inode: if (lock_flags != 0) { xfs_ilock(ip, lock_flags); } + + if ((ip->i_d.di_mode == 0) && !(flags & IGET_CREATE)) { + xfs_idestroy(ip); + return ENOENT; + } /* * Put ip on its hash chain, unless someone else hashed a duplicate @@ -324,6 +341,7 @@ finish_inode: ih->ih_next = ip; ip->i_udquot = ip->i_gdquot = NULL; ih->ih_version++; + ip->i_flags |= XFS_INEW; write_unlock(&ih->ih_lock); @@ -404,8 +422,6 @@ finish_inode: XFS_MOUNT_IUNLOCK(mp); - newnode = 1; - return_ip: ASSERT(ip->i_df.if_ext_max == XFS_IFORK_DSIZE(ip) / sizeof(xfs_bmbt_rec_t)); @@ -434,6 +450,7 @@ xfs_iget( xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, + uint flags, uint lock_flags, xfs_inode_t **ipp, xfs_daddr_t bno) @@ -454,8 +471,8 @@ retry: if (inode->i_state & I_NEW) { inode_allocate: vn_initialize(inode); - error = xfs_iget_core(vp, mp, tp, ino, - lock_flags, ipp, bno); + error = xfs_iget_core(vp, mp, tp, ino, flags, + lock_flags, ipp, bno); if (error) { vn_mark_bad(vp); if (inode->i_state & I_NEW) @@ -576,6 +593,10 @@ xfs_iput_new(xfs_inode_t *ip, vn_trace_entry(vp, "xfs_iput_new", (inst_t *)__return_address); + if ((ip->i_d.di_mode == 0)) { + ASSERT(!(ip->i_flags & XFS_IRECLAIMABLE)); + vn_mark_bad(vp); + } if (inode->i_state & I_NEW) unlock_new_inode(inode); if (lock_flags) diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index c661c948b26d..5573702347ed 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -1163,7 +1163,8 @@ xfs_ialloc( * This is because we're setting fields here we need * to prevent others from looking at until we're done. */ - error = xfs_trans_iget(tp->t_mountp, tp, ino, XFS_ILOCK_EXCL, &ip); + error = xfs_trans_iget(tp->t_mountp, tp, ino, + IGET_CREATE, XFS_ILOCK_EXCL, &ip); if (error != 0) { return error; } diff --git a/fs/xfs/xfs_inode.h b/fs/xfs/xfs_inode.h index dc32e4aa8e53..97bd24ba4198 100644 --- a/fs/xfs/xfs_inode.h +++ b/fs/xfs/xfs_inode.h @@ -381,6 +381,7 @@ void xfs_ifork_next_set(xfs_inode_t *ip, int w, int n); #define XFS_IRECLAIM 0x0008 /* we have started reclaiming this inode */ #define XFS_ISTALE 0x0010 /* inode has been staled */ #define XFS_IRECLAIMABLE 0x0020 /* inode can be reclaimed */ +#define XFS_INEW 0x0040 /* * Flags for inode locking. @@ -465,6 +466,9 @@ xfs_inode_t *xfs_bhvtoi(struct bhv_desc *bhvp); /* * xfs_iget.c prototypes. */ + +#define IGET_CREATE 1 + void xfs_ihash_init(struct xfs_mount *); void xfs_ihash_free(struct xfs_mount *); void xfs_chash_init(struct xfs_mount *); @@ -473,7 +477,7 @@ xfs_inode_t *xfs_inode_incore(struct xfs_mount *, xfs_ino_t, struct xfs_trans *); void xfs_inode_lock_init(xfs_inode_t *, struct vnode *); int xfs_iget(struct xfs_mount *, struct xfs_trans *, xfs_ino_t, - uint, xfs_inode_t **, xfs_daddr_t); + uint, uint, xfs_inode_t **, xfs_daddr_t); void xfs_iput(xfs_inode_t *, uint); void xfs_iput_new(xfs_inode_t *, uint); void xfs_ilock(xfs_inode_t *, uint); diff --git a/fs/xfs/xfs_itable.c b/fs/xfs/xfs_itable.c index 36dc09c8c1aa..0e86be199cd1 100644 --- a/fs/xfs/xfs_itable.c +++ b/fs/xfs/xfs_itable.c @@ -102,7 +102,7 @@ xfs_bulkstat_one( /* We're not being passed a pointer to a dinode. This happens * if BULKSTAT_FG_IGET is selected. Do the iget. */ - error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, bno); + error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, bno); if (error) { *stat = BULKSTAT_RV_NOTHING; return error; diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 028685574c88..77adb46d6395 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -3262,7 +3262,7 @@ xlog_recover_process_iunlinks( xfs_buf_relse(agibp); ino = XFS_AGINO_TO_INO(mp, agno, agino); - error = xfs_iget(mp, NULL, ino, 0, &ip, 0); + error = xfs_iget(mp, NULL, ino, 0, 0, &ip, 0); ASSERT(error || (ip != NULL)); if (!error) { diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 17be35cf0bdf..e7342ed7757a 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -975,7 +975,7 @@ xfs_mountfs( * Get and sanity-check the root inode. * Save the pointer to it in the mount structure. */ - error = xfs_iget(mp, NULL, sbp->sb_rootino, XFS_ILOCK_EXCL, &rip, 0); + error = xfs_iget(mp, NULL, sbp->sb_rootino, 0, XFS_ILOCK_EXCL, &rip, 0); if (error) { cmn_err(CE_WARN, "XFS: failed to read root inode"); goto error3; diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 431c8f4506c3..2c37822d1012 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -149,7 +149,7 @@ xfs_growfs_rt_alloc( /* * Lock the inode. */ - if ((error = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL, &ip))) + if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL, &ip))) goto error_exit; XFS_BMAP_INIT(&flist, &firstblock); /* @@ -189,7 +189,7 @@ xfs_growfs_rt_alloc( /* * Lock the bitmap inode. */ - if ((error = xfs_trans_iget(mp, tp, ino, XFS_ILOCK_EXCL, + if ((error = xfs_trans_iget(mp, tp, ino, 0, XFS_ILOCK_EXCL, &ip))) goto error_exit; /* @@ -2042,7 +2042,7 @@ xfs_growfs_rt( /* * Lock out other callers by grabbing the bitmap inode lock. */ - if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, + if ((error = xfs_trans_iget(mp, tp, 0, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip))) goto error_exit; ASSERT(ip == mp->m_rbmip); @@ -2057,7 +2057,7 @@ xfs_growfs_rt( * Get the summary inode into the transaction. */ if ((error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rsumino, - XFS_ILOCK_EXCL, &ip))) + 0, XFS_ILOCK_EXCL, &ip))) goto error_exit; ASSERT(ip == mp->m_rsumip); /* @@ -2177,7 +2177,7 @@ xfs_rtallocate_extent( /* * Lock out other callers by grabbing the bitmap inode lock. */ - error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip); + error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip); if (error) { return error; } @@ -2240,7 +2240,7 @@ xfs_rtfree_extent( /* * Synchronize by locking the bitmap inode. */ - error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip); + error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip); if (error) { return error; } @@ -2348,12 +2348,12 @@ xfs_rtmount_inodes( sbp = &mp->m_sb; if (sbp->sb_rbmino == NULLFSINO) return 0; - error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, &mp->m_rbmip, 0); + error = xfs_iget(mp, NULL, sbp->sb_rbmino, 0, 0, &mp->m_rbmip, 0); if (error) return error; ASSERT(mp->m_rbmip != NULL); ASSERT(sbp->sb_rsumino != NULLFSINO); - error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, &mp->m_rsumip, 0); + error = xfs_iget(mp, NULL, sbp->sb_rsumino, 0, 0, &mp->m_rsumip, 0); if (error) { VN_RELE(XFS_ITOV(mp->m_rbmip)); return error; @@ -2384,7 +2384,7 @@ xfs_rtpick_extent( __uint64_t seq; /* sequence number of file creation */ __uint64_t *seqp; /* pointer to seqno in inode */ - error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, XFS_ILOCK_EXCL, &ip); + error = xfs_trans_iget(mp, tp, mp->m_sb.sb_rbmino, 0, XFS_ILOCK_EXCL, &ip); if (error) return error; ASSERT(ip == mp->m_rbmip); diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index 86e53377e874..bd37ccb85e76 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -1007,7 +1007,7 @@ void xfs_trans_stale_inode_buf(xfs_trans_t *, struct xfs_buf *); void xfs_trans_dquot_buf(xfs_trans_t *, struct xfs_buf *, uint); void xfs_trans_inode_alloc_buf(xfs_trans_t *, struct xfs_buf *); int xfs_trans_iget(struct xfs_mount *, xfs_trans_t *, - xfs_ino_t , uint, struct xfs_inode **); + xfs_ino_t , uint, uint, struct xfs_inode **); void xfs_trans_ijoin(xfs_trans_t *, struct xfs_inode *, uint); void xfs_trans_ihold(xfs_trans_t *, struct xfs_inode *); void xfs_trans_ihold_release(xfs_trans_t *, struct xfs_inode *); diff --git a/fs/xfs/xfs_trans_inode.c b/fs/xfs/xfs_trans_inode.c index c2f55e0d6d21..e2c3706f453d 100644 --- a/fs/xfs/xfs_trans_inode.c +++ b/fs/xfs/xfs_trans_inode.c @@ -95,6 +95,7 @@ xfs_trans_iget( xfs_mount_t *mp, xfs_trans_t *tp, xfs_ino_t ino, + uint flags, uint lock_flags, xfs_inode_t **ipp) { @@ -106,9 +107,8 @@ xfs_trans_iget( * If the transaction pointer is NULL, just call the normal * xfs_iget(). */ - if (tp == NULL) { - return (xfs_iget(mp, NULL, ino, lock_flags, ipp, 0)); - } + if (tp == NULL) + return xfs_iget(mp, NULL, ino, flags, lock_flags, ipp, 0); /* * If we find the inode in core with this transaction @@ -148,7 +148,7 @@ xfs_trans_iget( } ASSERT(lock_flags & XFS_ILOCK_EXCL); - error = xfs_iget(tp->t_mountp, tp, ino, lock_flags, &ip, 0); + error = xfs_iget(tp->t_mountp, tp, ino, flags, lock_flags, &ip, 0); if (error) { return error; } @@ -186,7 +186,6 @@ xfs_trans_iget( return 0; } - /* * Add the locked inode to the transaction. * The inode must be locked, and it cannot be associated with any diff --git a/fs/xfs/xfs_utils.c b/fs/xfs/xfs_utils.c index 4c4bd6bc208a..816b945fa0ea 100644 --- a/fs/xfs/xfs_utils.c +++ b/fs/xfs/xfs_utils.c @@ -110,7 +110,7 @@ xfs_dir_lookup_int( * reservation in the inactive routine. */ xfs_iunlock(dp, lock_mode); - error = xfs_iget(dp->i_mount, NULL, *inum, 0, ipp, 0); + error = xfs_iget(dp->i_mount, NULL, *inum, 0, 0, ipp, 0); xfs_ilock(dp, lock_mode); if (error) { diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index dc6037a467a8..863a67c586d9 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -1610,7 +1610,7 @@ xfs_vget( if (ino == 0) return XFS_ERROR(ESTALE); - error = xfs_iget(mp, NULL, ino, XFS_ILOCK_SHARED, &ip, 0); + error = xfs_iget(mp, NULL, ino, 0, XFS_ILOCK_SHARED, &ip, 0); if (error) { *vpp = NULL; return error; -- 2.39.5