···708 return 0;709}7100000000000711/*712 * We set the inode flag atomically with the radix tree tag.713 * Once we get tag lookups on the radix tree, this inode flag···732733 read_lock(&pag->pag_ici_lock);734 spin_lock(&ip->i_flags_lock);735- radix_tree_tag_set(&pag->pag_ici_root,736- XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);737 __xfs_iflags_set(ip, XFS_IRECLAIMABLE);738 spin_unlock(&ip->i_flags_lock);739 read_unlock(&pag->pag_ici_lock);
···708 return 0;709}710711+void712+__xfs_inode_set_reclaim_tag(713+ struct xfs_perag *pag,714+ struct xfs_inode *ip)715+{716+ radix_tree_tag_set(&pag->pag_ici_root,717+ XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino),718+ XFS_ICI_RECLAIM_TAG);719+}720+721/*722 * We set the inode flag atomically with the radix tree tag.723 * Once we get tag lookups on the radix tree, this inode flag···722723 read_lock(&pag->pag_ici_lock);724 spin_lock(&ip->i_flags_lock);725+ __xfs_inode_set_reclaim_tag(pag, ip);0726 __xfs_iflags_set(ip, XFS_IRECLAIMABLE);727 spin_unlock(&ip->i_flags_lock);728 read_unlock(&pag->pag_ici_lock);
···191 int flags,192 int lock_flags) __releases(pag->pag_ici_lock)193{0194 struct xfs_mount *mp = ip->i_mount;195- int error = EAGAIN;00196197 /*198- * If INEW is set this inode is being set up199- * If IRECLAIM is set this inode is being torn down200- * Pause and try again.00000201 */202- if (xfs_iflags_test(ip, (XFS_INEW|XFS_IRECLAIM))) {203 XFS_STATS_INC(xs_ig_frecycle);0204 goto out_error;205 }206207- /* If IRECLAIMABLE is set, we've torn down the vfs inode part */208- if (xfs_iflags_test(ip, XFS_IRECLAIMABLE)) {00000209210- /*211- * If lookup is racing with unlink, then we should return an212- * error immediately so we don't remove it from the reclaim213- * list and potentially leak the inode.214- */215- if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {216- error = ENOENT;217- goto out_error;218- }219-220 xfs_itrace_exit_tag(ip, "xfs_iget.alloc");221222 /*223- * We need to re-initialise the VFS inode as it has been224- * 'freed' by the VFS. Do this here so we can deal with225- * errors cleanly, then tag it so it can be set up correctly226- * later.227 */228- if (inode_init_always(mp->m_super, VFS_I(ip))) {229- error = ENOMEM;000000000000000000000000230 goto out_error;231 }232233- /*234- * We must set the XFS_INEW flag before clearing the235- * XFS_IRECLAIMABLE flag so that if a racing lookup does236- * not find the XFS_IRECLAIMABLE above but has the igrab()237- * below succeed we can safely check XFS_INEW to detect238- * that this inode is still being initialised.239- */240- xfs_iflags_set(ip, XFS_INEW);241- xfs_iflags_clear(ip, XFS_IRECLAIMABLE);242-243- /* clear the radix tree reclaim flag as well. */244- __xfs_inode_clear_reclaim_tag(mp, pag, ip);245- } else if (!igrab(VFS_I(ip))) {246- /* If the VFS inode is being torn down, pause and try again. */247- XFS_STATS_INC(xs_ig_frecycle);248- goto out_error;249- } else if (xfs_iflags_test(ip, XFS_INEW)) {250- /*251- * We are racing with another cache hit that is252- * currently recycling this inode out of the XFS_IRECLAIMABLE253- * state. Wait for the initialisation to complete before254- * continuing.255- */256- wait_on_inode(VFS_I(ip));257 }258-259- if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) {260- error = ENOENT;261- iput(VFS_I(ip));262- goto out_error;263- }264-265- /* We've got a live one. */266- read_unlock(&pag->pag_ici_lock);267268 if (lock_flags != 0)269 xfs_ilock(ip, lock_flags);···276 return 0;277278out_error:0279 read_unlock(&pag->pag_ici_lock);280 return error;281}
···191 int flags,192 int lock_flags) __releases(pag->pag_ici_lock)193{194+ struct inode *inode = VFS_I(ip);195 struct xfs_mount *mp = ip->i_mount;196+ int error;197+198+ spin_lock(&ip->i_flags_lock);199200 /*201+ * If we are racing with another cache hit that is currently202+ * instantiating this inode or currently recycling it out of203+ * reclaimabe state, wait for the initialisation to complete204+ * before continuing.205+ *206+ * XXX(hch): eventually we should do something equivalent to207+ * wait_on_inode to wait for these flags to be cleared208+ * instead of polling for it.209 */210+ if (ip->i_flags & (XFS_INEW|XFS_IRECLAIM)) {211 XFS_STATS_INC(xs_ig_frecycle);212+ error = EAGAIN;213 goto out_error;214 }215216+ /*217+ * If lookup is racing with unlink return an error immediately.218+ */219+ if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) {220+ error = ENOENT;221+ goto out_error;222+ }223224+ /*225+ * If IRECLAIMABLE is set, we've torn down the VFS inode already.226+ * Need to carefully get it back into useable state.227+ */228+ if (ip->i_flags & XFS_IRECLAIMABLE) {00000229 xfs_itrace_exit_tag(ip, "xfs_iget.alloc");230231 /*232+ * We need to set XFS_INEW atomically with clearing the233+ * reclaimable tag so that we do have an indicator of the234+ * inode still being initialized.0235 */236+ ip->i_flags |= XFS_INEW;237+ ip->i_flags &= ~XFS_IRECLAIMABLE;238+ __xfs_inode_clear_reclaim_tag(mp, pag, ip);239+240+ spin_unlock(&ip->i_flags_lock);241+ read_unlock(&pag->pag_ici_lock);242+243+ error = -inode_init_always(mp->m_super, inode);244+ if (error) {245+ /*246+ * Re-initializing the inode failed, and we are in deep247+ * trouble. Try to re-add it to the reclaim list.248+ */249+ read_lock(&pag->pag_ici_lock);250+ spin_lock(&ip->i_flags_lock);251+252+ ip->i_flags &= ~XFS_INEW;253+ ip->i_flags |= XFS_IRECLAIMABLE;254+ __xfs_inode_set_reclaim_tag(pag, ip);255+ goto out_error;256+ }257+ inode->i_state = I_LOCK|I_NEW;258+ } else {259+ /* If the VFS inode is being torn down, pause and try again. */260+ if (!igrab(inode)) {261+ error = EAGAIN;262 goto out_error;263 }264265+ /* We've got a live one. */266+ spin_unlock(&ip->i_flags_lock);267+ read_unlock(&pag->pag_ici_lock);000000000000000000000268 }000000000269270 if (lock_flags != 0)271 xfs_ilock(ip, lock_flags);···274 return 0;275276out_error:277+ spin_unlock(&ip->i_flags_lock);278 read_unlock(&pag->pag_ici_lock);279 return error;280}