diff --git a/rust/hg-core/src/dirstate_tree/status.rs b/rust/hg-core/src/dirstate_tree/status.rs
index ecf9788cd9c409b5d835218c5b3de3fef7d0e287_cnVzdC9oZy1jb3JlL3NyYy9kaXJzdGF0ZV90cmVlL3N0YXR1cy5ycw==..8ee3889bab927284e2ebb5ad75eb943f40e2fd5f_cnVzdC9oZy1jb3JlL3NyYy9kaXJzdGF0ZV90cmVlL3N0YXR1cy5ycw== 100644
--- a/rust/hg-core/src/dirstate_tree/status.rs
+++ b/rust/hg-core/src/dirstate_tree/status.rs
@@ -303,7 +303,7 @@
     fn check_for_outdated_directory_cache(
         &self,
         dirstate_node: &NodeRef<'tree, 'on_disk>,
-    ) -> Result<(), DirstateV2ParseError> {
+    ) -> Result<bool, DirstateV2ParseError> {
         if self.ignore_patterns_have_changed == Some(true)
             && dirstate_node.cached_directory_mtime()?.is_some()
         {
@@ -311,5 +311,6 @@
                 dirstate_node
                     .full_path_borrowed(self.dmap.on_disk)?
                     .detach_from_tree(),
-            )
+            );
+            return Ok(true);
         }
@@ -315,5 +316,5 @@
         }
-        Ok(())
+        Ok(false)
     }
 
     /// If this returns true, we can get accurate results by only using
@@ -473,7 +474,8 @@
         dirstate_node: NodeRef<'tree, 'on_disk>,
         has_ignored_ancestor: &'ancestor HasIgnoredAncestor<'ancestor>,
     ) -> Result<(), DirstateV2ParseError> {
-        self.check_for_outdated_directory_cache(&dirstate_node)?;
+        let outdated_dircache =
+            self.check_for_outdated_directory_cache(&dirstate_node)?;
         let hg_path = &dirstate_node.full_path_borrowed(self.dmap.on_disk)?;
         let file_type = fs_metadata.file_type();
         let file_or_symlink = file_type.is_file() || file_type.is_symlink();
@@ -510,6 +512,7 @@
                 children_all_have_dirstate_node_or_are_ignored,
                 fs_metadata,
                 dirstate_node,
+                outdated_dircache,
             )?
         } else {
             if file_or_symlink && self.matcher.matches(&hg_path) {
@@ -549,8 +552,13 @@
         Ok(())
     }
 
+    /// Save directory mtime if applicable.
+    ///
+    /// `outdated_directory_cache` is `true` if we've just invalidated the
+    /// cache for this directory in `check_for_outdated_directory_cache`,
+    /// which forces the update.
     fn maybe_save_directory_mtime(
         &self,
         children_all_have_dirstate_node_or_are_ignored: bool,
         directory_metadata: &std::fs::Metadata,
         dirstate_node: NodeRef<'tree, 'on_disk>,
@@ -552,8 +560,9 @@
     fn maybe_save_directory_mtime(
         &self,
         children_all_have_dirstate_node_or_are_ignored: bool,
         directory_metadata: &std::fs::Metadata,
         dirstate_node: NodeRef<'tree, 'on_disk>,
+        outdated_directory_cache: bool,
     ) -> Result<(), DirstateV2ParseError> {
         if !children_all_have_dirstate_node_or_are_ignored {
             return Ok(());
@@ -621,12 +630,13 @@
         // We deem this scenario (unlike the previous one) to be
         // unlikely enough in practice.
 
-        let is_up_to_date =
-            if let Some(cached) = dirstate_node.cached_directory_mtime()? {
-                cached.likely_equal(directory_mtime)
-            } else {
-                false
-            };
+        let is_up_to_date = if let Some(cached) =
+            dirstate_node.cached_directory_mtime()?
+        {
+            !outdated_directory_cache && cached.likely_equal(directory_mtime)
+        } else {
+            false
+        };
         if !is_up_to_date {
             let hg_path = dirstate_node
                 .full_path_borrowed(self.dmap.on_disk)?
diff --git a/tests/test-status.t b/tests/test-status.t
index ecf9788cd9c409b5d835218c5b3de3fef7d0e287_dGVzdHMvdGVzdC1zdGF0dXMudA==..8ee3889bab927284e2ebb5ad75eb943f40e2fd5f_dGVzdHMvdGVzdC1zdGF0dXMudA== 100644
--- a/tests/test-status.t
+++ b/tests/test-status.t
@@ -993,16 +993,8 @@
   $ hg status
   ? another-subdir/something-else
 
-  $ hg debugdirstate --all --no-dates | grep '^ '
-      0         -1 unset               subdir (known-bad-output !)
-
-For some reason the first [status] is not enough to save the updated
-directory mtime into the cache. The second invocation does it.
-The first call only clears the directory cache by marking the directories
-as "outdated", which seems like a bug.
-
-  $ hg status
-  ? another-subdir/something-else
+One invocation of status is enough to populate the cache even if it's invalidated
+in the same run.
 
   $ hg debugdirstate --all --no-dates | grep '^ '
       0         -1 set                 subdir