Index: modules/block/block.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.module,v
retrieving revision 1.421
diff -u -p -r1.421 block.module
--- modules/block/block.module	13 May 2010 07:53:02 -0000	1.421
+++ modules/block/block.module	24 May 2010 19:27:12 -0000
@@ -356,6 +356,11 @@ function _block_rehash($theme = NULL) {
   foreach ($database_blocks as $block) {
     // Preserve info which is not in the database.
     $block->info = $current_blocks[$block->module][$block->delta]['info'];
+    // The cache mode can only by set from hook_block_info(), so that has
+    // precedence over the database's value.
+    if (isset($current_blocks[$block->module][$block->delta]['cache'])) {
+      $block->cache = $current_blocks[$block->module][$block->delta]['cache'];
+    }
     // Blocks stored in the database override the blocks defined in code.
     $current_blocks[$block->module][$block->delta] = get_object_vars($block);
     // Preserve this block.
@@ -386,7 +391,7 @@ function _block_rehash($theme = NULL) {
         $block['region'] = BLOCK_REGION_NONE;
       }
       // There is no point saving disabled blocks. Still, we need to save them
-      // beecause the 'title' attribute is saved to the {blocks} table.
+      // because the 'title' attribute is saved to the {blocks} table.
       if (isset($block['bid'])) {
         // If the block has a bid property, it comes from the database and
         // the record needs to be updated, so set the primary key to 'bid'
@@ -553,7 +558,7 @@ function block_theme_initialize($theme) 
     $result = db_query("SELECT * FROM {block} WHERE theme = :theme", array(':theme' => $default_theme), array('fetch' => PDO::FETCH_ASSOC));
     foreach ($result as $block) {
       // If the region isn't supported by the theme, assign the block to the theme's default region.
-      if (!array_key_exists($block['region'], $regions)) {
+      if ($block['status'] && !array_key_exists($block['region'], $regions)) {
         $block['region'] = system_default_region($theme);
       }
       $block['theme'] = $theme;
@@ -833,6 +838,18 @@ function _block_get_cache_id($block) {
  * Implements hook_flush_caches().
  */
 function block_flush_caches() {
+  // Rehash blocks for active themes. We don't use list_themes() here,
+  // because if MAINTENANCE_MODE is defined it skips reading the database,
+  // and we can't tell which themes are active.
+  $themes = db_query("SELECT name FROM {system} WHERE type = 'theme' AND status = 1");
+  foreach($themes as $theme) {
+    _block_rehash($theme->name);
+  }
+  // Some menu static variables are indirectly primed during _block_rehash(),
+  // which can cause problems at this stage during drupal_flush_all_caches().
+  // Reset them to be safe.
+  menu_reset_static_cache();
+
   return array('cache_block');
 }
 
Index: modules/block/block.test
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/block.test,v
retrieving revision 1.52
diff -u -p -r1.52 block.test
--- modules/block/block.test	26 Apr 2010 14:10:40 -0000	1.52
+++ modules/block/block.test	24 May 2010 19:27:12 -0000
@@ -261,6 +261,29 @@ class BlockTestCase extends DrupalWebTes
     ));
     $this->assertFieldByXPath($xpath, FALSE, t('Custom block found in %region_name region.', array('%region_name' => $region['name'])));
   }
+
+  /**
+   * Test _block_rehash().
+   */
+  function testBlockRehash() {
+    module_enable(array('block_test'));
+    $this->assertTrue(module_exists('block_test'), t('Test block module enabled.'));
+
+    // Our new block should be inserted in the database when we visit the
+    // block management page.
+    $this->drupalGet('admin/structure/block');
+    // Our test block's caching should default to DRUPAL_CACHE_PER_ROLE.
+    $current_caching = db_query("SELECT cache FROM {block} WHERE module = 'block_test' AND delta = 'test_cache'")->fetchField();
+    $this->assertEqual($current_caching, DRUPAL_CACHE_PER_ROLE, t('Test block cache mode defaults to DRUPAL_CACHE_PER_ROLE.'));
+
+    // Disable caching for this block.
+    variable_set('block_test_caching', DRUPAL_NO_CACHE);
+    // Flushing all caches should call _block_rehash().
+    drupal_flush_all_caches();
+    // Verify that the database is updated with the new caching mode.
+    $current_caching = db_query("SELECT cache FROM {block} WHERE module = 'block_test' AND delta = 'test_cache'")->fetchField();
+    $this->assertEqual($current_caching, DRUPAL_NO_CACHE, t("Test block's database entry updated to DRUPAL_NO_CACHE."));
+  }
 }
 
 class NonDefaultBlockAdmin extends DrupalWebTestCase {
Index: modules/block/tests/block_test.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/block/tests/block_test.module,v
retrieving revision 1.2
diff -u -p -r1.2 block_test.module
--- modules/block/tests/block_test.module	26 Apr 2010 14:10:40 -0000	1.2
+++ modules/block/tests/block_test.module	24 May 2010 19:27:12 -0000
@@ -12,6 +12,7 @@
 function block_test_block_info() {
   $blocks['test_cache'] = array(
     'info' => t('Test block caching'),
+    'cache' => variable_get('block_test_caching', DRUPAL_CACHE_PER_ROLE),
   );
 
   $blocks['test_html_id'] = array(
