]> git.neil.brown.name Git - history.git/commitdiff
[XFS] handle inode creating race
authorChristoph Hellwig <hch@sgi.com>
Mon, 13 Dec 2004 23:22:27 +0000 (10:22 +1100)
committerLinus Torvalds <torvalds@ppc970.osdl.org>
Mon, 13 Dec 2004 23:22:27 +0000 (10:22 +1100)
SGI-PV: 921072
SGI-Modid: xfs-linux:xfs-kern:181657a
Signed-off-by: Christoph Hellwig <hch@sgi.com>
Signed-off-by: Nathan Scott <nathans@sgi.com>
15 files changed:
fs/xfs/linux-2.6/xfs_ioctl.c
fs/xfs/linux-2.6/xfs_super.c
fs/xfs/quota/xfs_qm.c
fs/xfs/quota/xfs_qm_syscalls.c
fs/xfs/xfs_iget.c
fs/xfs/xfs_inode.c
fs/xfs/xfs_inode.h
fs/xfs/xfs_itable.c
fs/xfs/xfs_log_recover.c
fs/xfs/xfs_mount.c
fs/xfs/xfs_rtalloc.c
fs/xfs/xfs_trans.h
fs/xfs/xfs_trans_inode.c
fs/xfs/xfs_utils.c
fs/xfs/xfs_vfsops.c

index a5d382cff479a1730ac3a85b08e0989e2b69dc5d..284f2ad68e3ab7f1d619d8b3fe36f79003873777 100644 (file)
@@ -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)
index 854b656c98bc019e8714791c902a1b49a6c2fb1d..169da9dc9b9fb28d57f74e79f43588aca06c8586 100644 (file)
@@ -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);
        }
 }
index a7a9d664097d08dad802850ac4053df5ab68cabb..89f2cd656ebfd3969bd0a40af131d3d9c24f8c16 100644 (file)
@@ -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);
index b722dad83a6d7b629b38e8ea29895261bdc1624b..3548ced3272434239fb0e404f94f99959b07eda5 100644 (file)
@@ -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);
        }
index 07641fc90d61350d834ce2b081382ddbaec32c8e..bef91642de8827b9ed6ab350505bdba7754b0c8b 100644 (file)
@@ -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)
index c661c948b26d6d54cf05aee0057296595953a511..5573702347ed6b1ae46b32b85f4af688c7a65d75 100644 (file)
@@ -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;
        }
index dc32e4aa8e536a3b1a66c241172522b3cdb7613b..97bd24ba4198f2eb6cd5e690a87b3dd9a4b0023f 100644 (file)
@@ -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);
index 36dc09c8c1aa1254afa2a07629bb163d7afb23c0..0e86be199cd10502168eb15459c2b2e92754634a 100644 (file)
@@ -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;
index 028685574c8840c3f57fd63d114df39d2506e511..77adb46d6395517c53aa9d14d1f22fb899e59e97 100644 (file)
@@ -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) {
index 17be35cf0bdf6d47daaa7640e5047b7bfe6282f6..e7342ed7757ab1dfc3e00f6f53d3a146e3802906 100644 (file)
@@ -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;
index 431c8f4506c37148f5989841c45166f5cc1f9104..2c37822d1012e60173d396d2fc4cf94097ba8f1b 100644 (file)
@@ -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);
index 86e53377e8743b9e31e7b17c7d71b10e49c827bc..bd37ccb85e76d30f98d2d61e6c7b79b47a4d9f26 100644 (file)
@@ -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 *);
index c2f55e0d6d21856be1bd771fa750b12b53c5501f..e2c3706f453de78c9b9063a87733f7d3f87d8618 100644 (file)
@@ -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
index 4c4bd6bc208ac31e2d536530cc47bce18be41b5e..816b945fa0ea88f92b11e6f69988f6748c8732c7 100644 (file)
@@ -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) {
index dc6037a467a847d4af4987422f6641c493695bbc..863a67c586d9c2c7323c585840800b6cecfb9cca 100644 (file)
@@ -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;