diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc
index 847bfc3..4396889 100644
--- a/includes/bootstrap.inc
+++ b/includes/bootstrap.inc
@@ -835,7 +835,10 @@ function drupal_settings_initialize() {
 function drupal_get_filename($type, $name, $filename = NULL) {
   // The location of files will not change during the request, so do not use
   // drupal_static().
-  static $files = array(), $dirs = array();
+  // The $files static variable will hold the locations of all requested files,
+  // and any file that gets added during the request will have been checked
+  // with a file_exists() at some point.
+  static $files = array(), $dirs = array(), $files_scanned = array();
 
   // Profiles are a special case: they have a fixed location and naming.
   if ($type == 'profile') {
@@ -850,18 +853,28 @@ function drupal_get_filename($type, $name, $filename = NULL) {
     $files[$type][$name] = $filename;
   }
   elseif (isset($files[$type][$name])) {
-    // nothing
+    // This item had already been found earlier in the request. Do nothing.
   }
-  // Verify that we have an active database connection, before querying
-  // the database. This is required because this function is called both
-  // before we have a database connection (i.e. during installation) and
-  // when a database connection fails.
   else {
+    // Look for the location listed in the {system} table.
+    // Verify that we have an active database connection, before querying
+    // the database. This is required because this function is called both
+    // before we have a database connection (i.e. during installation) and
+    // when a database connection fails.
     try {
+      $database_file_exists = NULL;
       if (function_exists('db_query')) {
         $file = db_query("SELECT filename FROM {system} WHERE name = :name AND type = :type", array(':name' => $name, ':type' => $type))->fetchField();
-        if ($file !== FALSE && file_exists(DRUPAL_ROOT . '/' . $file)) {
-          $files[$type][$name] = $file;
+        if ($file !== FALSE) {
+          if (file_exists(DRUPAL_ROOT . '/' . $file)) {
+            $files[$type][$name] = $file;
+            $database_file_exists = TRUE;
+          }
+          else {
+            // Flag that the filename in the database does not exist for the
+            // requested item, so we can figure out if it has moved.
+            $database_file_exists = FALSE;
+          }
         }
       }
     }
@@ -871,7 +884,8 @@ function drupal_get_filename($type, $name, $filename = NULL) {
       // hide the error completely.
     }
     // Fallback to searching the filesystem if the database could not find the
-    // file or the file returned by the database is not found.
+    // file or the filename returned by the database is not found. We cache
+    // missing and moved files in order to prevent unnecessary file scans.
     if (!isset($files[$type][$name])) {
       // We have a consistent directory naming: modules, themes...
       $dir = $type . 's';
@@ -886,7 +900,59 @@ function drupal_get_filename($type, $name, $filename = NULL) {
         $extension = $type;
       }
 
-      if (!isset($dirs[$dir][$extension])) {
+      // This static variable will hold all missing and moved files, in order
+      // to prevent unnecessary file scans. It is an associative array with as
+      // keys the file type and name, and as value the boolean TRUE (if the
+      // module is missing) or a string (if the module has moved from the
+      // location listed in the {system} table) with the location that was
+      // found in a file scan.
+      $missing = &drupal_static('drupal_get_filename:missing');
+      if (!isset($missing)) {
+        $missing = array();
+      }
+      // Get the missing and moved files from persistent cache, if available.
+      if (!isset($missing['#cache_merge_done'])) {
+        try {
+          if (function_exists('cache_get')) {
+            $cache = cache_get('drupal_get_filename:missing', 'cache_bootstrap');
+            if (!empty($cache->data)) {
+              // Merge the changes already done in the current request
+              // (including the setting of missing records to NULL) into the
+              // values saved in persistent cache.
+              $missing = drupal_array_merge_deep($cache->data, $missing);
+              // Set a flag so we know that we've already done a merge with
+              // the values in persistent cache.
+              $missing['#cache_merge_done'] = TRUE;
+            }
+          }
+        }
+        catch (Exception $e) {
+          // Hide the error.
+        }
+      }
+
+      // Check whether this file had previously moved from its location in
+      // the {system} table, and the new location found in a file scan had
+      // been cached.
+      if (isset($missing[$type][$name]) && is_string($missing[$type][$name])) {
+        // This file has moved and the result of a file scan had been cached.
+        if (file_exists($missing[$type][$name])) {
+          // We found the file at the cached location.
+          $files[$type][$name] = $missing[$type][$name];
+        }
+        else {
+          // File is not available anymore at the cached location. Remove the
+          // missing/moved file record so a new file scan will be performed.
+          $missing[$type][$name] = NULL;
+          $missing['#write_cache'] = TRUE;
+        }
+      }
+
+      // Check if we had already scanned this directory/extension combination,
+      // or if this file had been marked as missing/moved.
+      if (!isset($dirs[$dir][$extension]) && !isset($missing[$type][$name])) {
+        // Log that we have now scanned this directory/extension combination
+        // into a static variable to prevent unnecessary scans.
         $dirs[$dir][$extension] = TRUE;
         if (!function_exists('drupal_system_listing')) {
           require_once DRUPAL_ROOT . '/includes/common.inc';
@@ -897,15 +963,80 @@ function drupal_get_filename($type, $name, $filename = NULL) {
         // called more than once in the same page request.
         $matches = drupal_system_listing("/^" . DRUPAL_PHP_FUNCTION_PATTERN . "\.$extension$/", $dir, 'name', 0);
         foreach ($matches as $matched_name => $file) {
-          $files[$type][$matched_name] = $file->uri;
+          // Log the locations found in the file scan into a static variable.
+          $files_scanned[$type][$matched_name] = $file->uri;
+        }
+      }
+
+      // If current file had been found in a file scan earlier on in this
+      // request, use the new location that had been found in the file scan.
+      if (isset($files_scanned[$type][$name])) {
+        // Use the location from the file scan earlier on in this request.
+        $files[$type][$name] = $files_scanned[$type][$name];
+        // Check whether the current file was listed as being in another
+        // location in the {system} table.
+        if (isset($database_file_exists) && $database_file_exists === FALSE) {
+          // This file has moved. Cache its new location into the missing and
+          // moved files list.
+          $missing[$type][$name] = $files_scanned[$type][$name];
+          // Make sure our change to the missing and moved files list will be
+          // written to persistent cache.
+          $missing['#write_cache'] = TRUE;
+          trigger_error(format_string('The following @type has moved on the file system: @name. Clearing caches may help fix this. For more information, see <a href="@documentation">the documentation page</a>.', array('@type' => $type, '@name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING);
         }
       }
     }
   }
 
   if (isset($files[$type][$name])) {
+    // The requested file exists.
+    // Check if the file had previously been marked as missing or moved.
+    if (isset($missing[$type][$name]) && ($missing[$type][$name] === TRUE || (is_string($missing[$type][$name]) && $missing[$type][$name] != $files[$type][$name]))) {
+      // Previously missing/moved file has reappeared.
+      $missing[$type][$name] = NULL;
+      $missing['#write_cache'] = TRUE;
+    }
     return $files[$type][$name];
   }
+  else {
+    // The requested file does not exist in any location.
+    if (!isset($missing[$type][$name])) {
+      // Mark the file as missing.
+      $missing[$type][$name] = TRUE;
+      // Make sure our change to the missing files list will be written to
+      // persistent cache.
+      // This cache will be cleared on module/theme rebuild.
+      $missing['#write_cache'] = TRUE;
+    }
+    // Trigger a user-level warning on every request for the missing file.
+    trigger_error(format_string('The following @type is missing from the file system: @name. For more information, see <a href="@documentation">the documentation page</a>.', array('@type' => $type, '@name' => $name, '@documentation' => 'https://www.drupal.org/node/2487215')), E_USER_WARNING);
+  }
+}
+
+/**
+ * Writes the missing and moved files to persistent cache.
+ *
+ * @param array $missing
+ *   The array of missing and moved files.
+ */
+function drupal_missing_write_cache() {
+  // Only write to cache if we are fully bootstrapped.
+  if (drupal_get_bootstrap_phase() != DRUPAL_BOOTSTRAP_FULL) {
+    return;
+  }
+  $missing = &drupal_static('drupal_get_filename:missing');
+  if (isset($missing['#write_cache'])) {
+    // Merge the newly found out missing and moved file data with
+    // the previously existing data, if we hadn't done so yet.
+    if (!isset($missing['#cache_merge_done'])) {
+      $cache = cache_get('drupal_get_filename:missing', 'cache_bootstrap');
+      if (isset($cache->data)) {
+        $missing = drupal_array_merge_deep($cache->data, $missing);
+      }
+    }
+    $missing['#write_cache'] = NULL;
+    cache_set('drupal_get_filename:missing', $missing, 'cache_bootstrap');
+  }
 }
 
 /**
diff --git a/includes/common.inc b/includes/common.inc
index cd30145..ffb35a4 100644
--- a/includes/common.inc
+++ b/includes/common.inc
@@ -2751,6 +2751,7 @@ function drupal_page_footer() {
   _registry_check_code(REGISTRY_WRITE_LOOKUP_CACHE);
   drupal_cache_system_paths();
   module_implements_write_cache();
+  drupal_missing_write_cache();
   system_run_automated_cron();
 }
 
diff --git a/includes/update.inc b/includes/update.inc
index a17161c..c23519d 100644
--- a/includes/update.inc
+++ b/includes/update.inc
@@ -795,6 +795,14 @@ function update_fix_d7_requirements() {
 function update_fix_d7_install_profile() {
   $profile = drupal_get_profile();
 
+  // 'Default' profile has been renamed to 'Standard' in D7.
+  // We change the profile here to prevent a broken record in the system table.
+  // @see system_update_7049()
+  if ($profile == 'default') {
+    $profile = 'standard';
+    variable_set('install_profile', $profile);
+  }
+
   $results = db_select('system', 's')
     ->fields('s', array('name', 'schema_version'))
     ->condition('name', $profile)
diff --git a/modules/simpletest/simpletest.module b/modules/simpletest/simpletest.module
index 91f0f90..73cd14f 100644
--- a/modules/simpletest/simpletest.module
+++ b/modules/simpletest/simpletest.module
@@ -371,7 +371,18 @@ function simpletest_test_get_all() {
           // If this test class requires a non-existing module, skip it.
           if (!empty($info['dependencies'])) {
             foreach ($info['dependencies'] as $module) {
-              if (!drupal_get_filename('module', $module)) {
+
+              // Searching for an item that does not exist triggers an PHP
+              // error. Set a custom error handler so we can ignore the file
+              // not found error.
+              set_error_handler('_simpletest_file_not_found_error_handler');
+
+              $found_module = drupal_get_filename('module', $module);
+
+              // Restore the original error handler.
+              restore_error_handler();
+
+              if (!$found_module) {
                 continue 2;
               }
             }
@@ -395,6 +406,16 @@ function simpletest_test_get_all() {
   return $groups;
 }
 
+/**
+ * Skips handling of "file not found" errors.
+ */
+function _simpletest_file_not_found_error_handler($error_level, $message, $filename, $line, $context) {
+   if (strstr($message, 'is missing from the file system:')) {
+     return;
+   }
+   _drupal_error_handler($error_level, $message, $filename, $line, $context);
+}
+
 /*
  * Register a simple class loader that can find D8-style PSR-0 test classes.
  *
diff --git a/modules/simpletest/tests/bootstrap.test b/modules/simpletest/tests/bootstrap.test
index ece1cd9..71bcaff 100644
--- a/modules/simpletest/tests/bootstrap.test
+++ b/modules/simpletest/tests/bootstrap.test
@@ -382,6 +382,15 @@ class BootstrapGetFilenameTestCase extends DrupalUnitTestCase {
   }
 
   /**
+   * Whether the filename test triggered the right error.
+   *
+   * Used by BootstrapGetFilenameTestCase::testDrupalGetFilename().
+   *
+   * @var boolean
+   */
+  protected $getFilenameTestTriggeredError = FALSE;
+
+  /**
    * Test that drupal_get_filename() works correctly when the file is not found in the database.
    */
   function testDrupalGetFilename() {
@@ -410,6 +419,36 @@ class BootstrapGetFilenameTestCase extends DrupalUnitTestCase {
     // automatically check there for 'script' files, just as it does for (e.g.)
     // 'module' files in modules.
     $this->assertIdentical(drupal_get_filename('script', 'test'), 'scripts/test.script', t('Retrieve test script location.'));
+
+    // Generate a non-existing module name.
+    $non_existing_module = $this->randomName();
+
+    // Searching for an item that does not exist returns NULL.
+    // Set a custom error handler so we can ignore the file not found error.
+    set_error_handler(array($this, 'fileNotFoundErrorHandler'));
+    $this->assertNull(drupal_get_filename('module', $non_existing_module), 'Searching for an item that does not exist returns NULL.');
+    $this->assertTrue($this->getFilenameTestTriggeredError, 'Searching for an item that does not exist triggers an error.');
+    // Restore the original error handler.
+    restore_error_handler();
+
+    // Get the missing records static from drupal_get_filename().
+    $missing = &drupal_static('drupal_get_filename:missing');
+
+    // Searching for an item that does not exist creates a static record in
+    // drupal_get_filename().
+    $this->assertTrue($missing['module'][$non_existing_module], 'Searching for an item that does not exist creates a static record in drupal_get_filename().');
+  }
+
+  /**
+   * Skips handling of "file not found" errors.
+   */
+  public function fileNotFoundErrorHandler($error_level, $message, $filename, $line, $context) {
+    // Skip error handling if this is a "file not found" error.
+    if (strstr($message, 'is missing from the file system:')) {
+      $this->getFilenameTestTriggeredError = TRUE;
+      return;
+    }
+    _drupal_error_handler($error_level, $message, $filename, $line, $context);
   }
 }
 
diff --git a/modules/system/system.module b/modules/system/system.module
index 8fc517f..10e672e 100644
--- a/modules/system/system.module
+++ b/modules/system/system.module
@@ -2365,6 +2365,10 @@ function system_get_info($type, $name = NULL) {
  *   An associative array of module information.
  */
 function _system_rebuild_module_data() {
+  // Clean up the bootstrap "missing files" cache when rebuilding module data.
+  drupal_static_reset('drupal_get_filename:missing');
+  cache_clear_all('drupal_get_filename:missing', 'cache');
+
   // Find modules
   $modules = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.module$/', 'modules', 'name', 0);
 
@@ -2501,6 +2505,10 @@ function _system_update_bootstrap_status() {
  *   An associative array of themes information.
  */
 function _system_rebuild_theme_data() {
+  // Clean up the bootstrap "missing files" cache when rebuilding theme data.
+  drupal_static_reset('drupal_get_filename:missing');
+  cache_clear_all('drupal_get_filename:missing', 'cache');
+
   // Find themes
   $themes = drupal_system_listing('/^' . DRUPAL_PHP_FUNCTION_PATTERN . '\.info$/', 'themes');
   // Allow modules to add further themes.
