···708708 return 0;709709}710710711711+void712712+__xfs_inode_set_reclaim_tag(713713+ struct xfs_perag *pag,714714+ struct xfs_inode *ip)715715+{716716+ radix_tree_tag_set(&pag->pag_ici_root,717717+ XFS_INO_TO_AGINO(ip->i_mount, ip->i_ino),718718+ XFS_ICI_RECLAIM_TAG);719719+}720720+711721/*712722 * We set the inode flag atomically with the radix tree tag.713723 * Once we get tag lookups on the radix tree, this inode flag···732722733723 read_lock(&pag->pag_ici_lock);734724 spin_lock(&ip->i_flags_lock);735735- radix_tree_tag_set(&pag->pag_ici_root,736736- XFS_INO_TO_AGINO(mp, ip->i_ino), XFS_ICI_RECLAIM_TAG);725725+ __xfs_inode_set_reclaim_tag(pag, ip);737726 __xfs_iflags_set(ip, XFS_IRECLAIMABLE);738727 spin_unlock(&ip->i_flags_lock);739728 read_unlock(&pag->pag_ici_lock);
···191191 int flags,192192 int lock_flags) __releases(pag->pag_ici_lock)193193{194194+ struct inode *inode = VFS_I(ip);194195 struct xfs_mount *mp = ip->i_mount;195195- int error = EAGAIN;196196+ int error;197197+198198+ spin_lock(&ip->i_flags_lock);196199197200 /*198198- * If INEW is set this inode is being set up199199- * If IRECLAIM is set this inode is being torn down200200- * Pause and try again.201201+ * If we are racing with another cache hit that is currently202202+ * instantiating this inode or currently recycling it out of203203+ * reclaimabe state, wait for the initialisation to complete204204+ * before continuing.205205+ *206206+ * XXX(hch): eventually we should do something equivalent to207207+ * wait_on_inode to wait for these flags to be cleared208208+ * instead of polling for it.201209 */202202- if (xfs_iflags_test(ip, (XFS_INEW|XFS_IRECLAIM))) {210210+ if (ip->i_flags & (XFS_INEW|XFS_IRECLAIM)) {203211 XFS_STATS_INC(xs_ig_frecycle);212212+ error = EAGAIN;204213 goto out_error;205214 }206215207207- /* If IRECLAIMABLE is set, we've torn down the vfs inode part */208208- if (xfs_iflags_test(ip, XFS_IRECLAIMABLE)) {216216+ /*217217+ * If lookup is racing with unlink return an error immediately.218218+ */219219+ if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) {220220+ error = ENOENT;221221+ goto out_error;222222+ }209223210210- /*211211- * If lookup is racing with unlink, then we should return an212212- * error immediately so we don't remove it from the reclaim213213- * list and potentially leak the inode.214214- */215215- if ((ip->i_d.di_mode == 0) && !(flags & XFS_IGET_CREATE)) {216216- error = ENOENT;217217- goto out_error;218218- }219219-224224+ /*225225+ * If IRECLAIMABLE is set, we've torn down the VFS inode already.226226+ * Need to carefully get it back into useable state.227227+ */228228+ if (ip->i_flags & XFS_IRECLAIMABLE) {220229 xfs_itrace_exit_tag(ip, "xfs_iget.alloc");221230222231 /*223223- * We need to re-initialise the VFS inode as it has been224224- * 'freed' by the VFS. Do this here so we can deal with225225- * errors cleanly, then tag it so it can be set up correctly226226- * later.232232+ * We need to set XFS_INEW atomically with clearing the233233+ * reclaimable tag so that we do have an indicator of the234234+ * inode still being initialized.227235 */228228- if (inode_init_always(mp->m_super, VFS_I(ip))) {229229- error = ENOMEM;236236+ ip->i_flags |= XFS_INEW;237237+ ip->i_flags &= ~XFS_IRECLAIMABLE;238238+ __xfs_inode_clear_reclaim_tag(mp, pag, ip);239239+240240+ spin_unlock(&ip->i_flags_lock);241241+ read_unlock(&pag->pag_ici_lock);242242+243243+ error = -inode_init_always(mp->m_super, inode);244244+ if (error) {245245+ /*246246+ * Re-initializing the inode failed, and we are in deep247247+ * trouble. Try to re-add it to the reclaim list.248248+ */249249+ read_lock(&pag->pag_ici_lock);250250+ spin_lock(&ip->i_flags_lock);251251+252252+ ip->i_flags &= ~XFS_INEW;253253+ ip->i_flags |= XFS_IRECLAIMABLE;254254+ __xfs_inode_set_reclaim_tag(pag, ip);255255+ goto out_error;256256+ }257257+ inode->i_state = I_LOCK|I_NEW;258258+ } else {259259+ /* If the VFS inode is being torn down, pause and try again. */260260+ if (!igrab(inode)) {261261+ error = EAGAIN;230262 goto out_error;231263 }232264233233- /*234234- * We must set the XFS_INEW flag before clearing the235235- * XFS_IRECLAIMABLE flag so that if a racing lookup does236236- * not find the XFS_IRECLAIMABLE above but has the igrab()237237- * below succeed we can safely check XFS_INEW to detect238238- * that this inode is still being initialised.239239- */240240- xfs_iflags_set(ip, XFS_INEW);241241- xfs_iflags_clear(ip, XFS_IRECLAIMABLE);242242-243243- /* clear the radix tree reclaim flag as well. */244244- __xfs_inode_clear_reclaim_tag(mp, pag, ip);245245- } else if (!igrab(VFS_I(ip))) {246246- /* If the VFS inode is being torn down, pause and try again. */247247- XFS_STATS_INC(xs_ig_frecycle);248248- goto out_error;249249- } else if (xfs_iflags_test(ip, XFS_INEW)) {250250- /*251251- * We are racing with another cache hit that is252252- * currently recycling this inode out of the XFS_IRECLAIMABLE253253- * state. Wait for the initialisation to complete before254254- * continuing.255255- */256256- wait_on_inode(VFS_I(ip));265265+ /* We've got a live one. */266266+ spin_unlock(&ip->i_flags_lock);267267+ read_unlock(&pag->pag_ici_lock);257268 }258258-259259- if (ip->i_d.di_mode == 0 && !(flags & XFS_IGET_CREATE)) {260260- error = ENOENT;261261- iput(VFS_I(ip));262262- goto out_error;263263- }264264-265265- /* We've got a live one. */266266- read_unlock(&pag->pag_ici_lock);267269268270 if (lock_flags != 0)269271 xfs_ilock(ip, lock_flags);···276274 return 0;277275278276out_error:277277+ spin_unlock(&ip->i_flags_lock);279278 read_unlock(&pag->pag_ici_lock);280279 return error;281280}