Commit d98bc1e8 authored by Christoph Hellwig's avatar Christoph Hellwig Committed by Linus Torvalds

[XFS] handle inode creating race

SGI-PV: 921072
SGI-Modid: xfs-linux:xfs-kern:181657a
Signed-off-by: default avatarChristoph Hellwig <hch@sgi.com>
Signed-off-by: default avatarNathan Scott <nathans@sgi.com>
parent 36585c6b
......@@ -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)
......
......@@ -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);
}
}
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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 @@ xfs_iget_core(
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 @@ xfs_iget_core(
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 @@ xfs_iget_core(
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 @@ xfs_iget_core(
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 @@ xfs_iget_core(
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 @@ xfs_iget(
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)
......
......@@ -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;
}
......
......@@ -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);
......
......@@ -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;
......
......@@ -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) {
......
......@@ -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;
......
......@@ -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);
......
......@@ -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 *);
......
......@@ -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
......
......@@ -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) {
......
......@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment