diff --git a/Annex.hs b/Annex.hs index 14890c58c0..96d55452ee 100644 --- a/Annex.hs +++ b/Annex.hs @@ -151,6 +151,7 @@ data AnnexState = AnnexState , cachedcurrentbranch :: (Maybe (Maybe Git.Branch, Maybe Adjustment)) , cachedgitenv :: Maybe (AltIndexFile, FilePath, [(String, String)]) , urloptions :: Maybe UrlOptions + , insmudgecleanfilter :: Bool } newState :: GitConfig -> Git.Repo -> IO AnnexState @@ -209,6 +210,7 @@ newState c r = do , cachedcurrentbranch = Nothing , cachedgitenv = Nothing , urloptions = Nothing + , insmudgecleanfilter = False } {- Makes an Annex state object for the specified git repo. diff --git a/Annex/Link.hs b/Annex/Link.hs index 59f79e838b..74990022ca 100644 --- a/Annex/Link.hs +++ b/Annex/Link.hs @@ -177,12 +177,18 @@ newtype Restage = Restage Bool restagePointerFile :: Restage -> RawFilePath -> InodeCache -> Annex () restagePointerFile (Restage False) f _ = toplevelWarning True $ unableToRestage $ Just $ fromRawFilePath f -restagePointerFile (Restage True) f orig = withTSDelta $ \tsd -> do - -- update-index is documented as picky about "./file" and it - -- fails on "../../repo/path/file" when cwd is not in the repo - -- being acted on. Avoid these problems with an absolute path. - absf <- liftIO $ absPath $ fromRawFilePath f - Annex.Queue.addInternalAction runner [(absf, isunmodified tsd)] +restagePointerFile (Restage True) f orig = withTSDelta $ \tsd -> + -- Avoid refreshing the index if run by the + -- smudge clean filter, because git uses that when + -- it's already refreshing the index, probably because + -- this very action is running. Running it again would likely + -- deadlock. + unlessM (Annex.getState Annex.insmudgecleanfilter) $ do + -- update-index is documented as picky about "./file" and it + -- fails on "../../repo/path/file" when cwd is not in the repo + -- being acted on. Avoid these problems with an absolute path. + absf <- liftIO $ absPath $ fromRawFilePath f + Annex.Queue.addInternalAction runner [(absf, isunmodified tsd)] where isunmodified tsd = genInodeCache f tsd >>= return . \case Nothing -> False diff --git a/CHANGELOG b/CHANGELOG index 9845cf7737..673e75001b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,11 @@ +git-annex (8.20200618) UNRELEASED; urgency=medium + + * Fix a deadlock that could occur after git-annex got an unlocked + file, causing the command to hang indefinitely. Known to happen on + vfat filesystems, possibly others. + + -- Joey Hess Thu, 18 Jun 2020 12:21:14 -0400 + git-annex (8.20200617) upstream; urgency=medium * Added annex.skipunknown git config, that can be set to false to change diff --git a/Command/Smudge.hs b/Command/Smudge.hs index 6b20ad3fee..75f0627c5a 100644 --- a/Command/Smudge.hs +++ b/Command/Smudge.hs @@ -88,18 +88,23 @@ clean file = do b <- liftIO $ L.hGetContents stdin ifM fileoutsiderepo ( liftIO $ L.hPut stdout b - , case parseLinkTargetOrPointerLazy b of - Just k -> do - getMoveRaceRecovery k (toRawFilePath file) - liftIO $ L.hPut stdout b - Nothing -> do - let fileref = Git.Ref.fileRef (toRawFilePath file) - indexmeta <- catObjectMetaData fileref - go b indexmeta =<< catKey' fileref indexmeta + , do + -- Avoid a potential deadlock. + Annex.changeState $ \s -> s + { Annex.insmudgecleanfilter = True } + go b ) stop where - go b indexmeta oldkey = ifM (shouldAnnex file indexmeta oldkey) + go b = case parseLinkTargetOrPointerLazy b of + Just k -> do + getMoveRaceRecovery k (toRawFilePath file) + liftIO $ L.hPut stdout b + Nothing -> do + let fileref = Git.Ref.fileRef (toRawFilePath file) + indexmeta <- catObjectMetaData fileref + go' b indexmeta =<< catKey' fileref indexmeta + go' b indexmeta oldkey = ifM (shouldAnnex file indexmeta oldkey) ( do -- Before git 2.5, failing to consume all stdin here -- would cause a SIGPIPE and crash it.