PCI: Global variable decls must match the defs in section attributes
[safe/jmp/linux-2.6] / fs / ocfs2 / super.c
index b1cb38f..14f47d2 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/highmem.h>
-#include <linux/utsname.h>
 #include <linux/init.h>
 #include <linux/random.h>
 #include <linux/statfs.h>
@@ -42,6 +41,7 @@
 #include <linux/mount.h>
 #include <linux/seq_file.h>
 #include <linux/quotaops.h>
+#include <linux/smp_lock.h>
 
 #define MLOG_MASK_PREFIX ML_SUPER
 #include <cluster/masklog.h>
@@ -68,6 +68,7 @@
 #include "ver.h"
 #include "xattr.h"
 #include "quota.h"
+#include "refcounttree.h"
 
 #include "buffer_head_io.h"
 
@@ -118,15 +119,16 @@ static void ocfs2_release_system_inodes(struct ocfs2_super *osb);
 static int ocfs2_check_volume(struct ocfs2_super *osb);
 static int ocfs2_verify_volume(struct ocfs2_dinode *di,
                               struct buffer_head *bh,
-                              u32 sectsize);
+                              u32 sectsize,
+                              struct ocfs2_blockcheck_stats *stats);
 static int ocfs2_initialize_super(struct super_block *sb,
                                  struct buffer_head *bh,
-                                 int sector_size);
+                                 int sector_size,
+                                 struct ocfs2_blockcheck_stats *stats);
 static int ocfs2_get_sector(struct super_block *sb,
                            struct buffer_head **bh,
                            int block,
                            int sect_size);
-static void ocfs2_write_super(struct super_block *sb);
 static struct inode *ocfs2_alloc_inode(struct super_block *sb);
 static void ocfs2_destroy_inode(struct inode *inode);
 static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend);
@@ -141,7 +143,6 @@ static const struct super_operations ocfs2_sops = {
        .clear_inode    = ocfs2_clear_inode,
        .delete_inode   = ocfs2_delete_inode,
        .sync_fs        = ocfs2_sync_fs,
-       .write_super    = ocfs2_write_super,
        .put_super      = ocfs2_put_super,
        .remount_fs     = ocfs2_remount,
        .show_options   = ocfs2_show_options,
@@ -201,24 +202,190 @@ static const match_table_t tokens = {
        {Opt_err, NULL}
 };
 
-/*
- * write_super and sync_fs ripped right out of ext3.
- */
-static void ocfs2_write_super(struct super_block *sb)
+#ifdef CONFIG_DEBUG_FS
+static int ocfs2_osb_dump(struct ocfs2_super *osb, char *buf, int len)
 {
-       if (mutex_trylock(&sb->s_lock) != 0)
-               BUG();
-       sb->s_dirt = 0;
+       struct ocfs2_cluster_connection *cconn = osb->cconn;
+       struct ocfs2_recovery_map *rm = osb->recovery_map;
+       struct ocfs2_orphan_scan *os = &osb->osb_orphan_scan;
+       int i, out = 0;
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Id: %-s  Uuid: %-s  Gen: 0x%X  Label: %-s\n",
+                       "Device", osb->dev_str, osb->uuid_str,
+                       osb->fs_generation, osb->vol_label);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => State: %d  Flags: 0x%lX\n", "Volume",
+                       atomic_read(&osb->vol_state), osb->osb_flags);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Block: %lu  Cluster: %d\n", "Sizes",
+                       osb->sb->s_blocksize, osb->s_clustersize);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Compat: 0x%X  Incompat: 0x%X  "
+                       "ROcompat: 0x%X\n",
+                       "Features", osb->s_feature_compat,
+                       osb->s_feature_incompat, osb->s_feature_ro_compat);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Opts: 0x%lX  AtimeQuanta: %u\n", "Mount",
+                       osb->s_mount_opt, osb->s_atime_quantum);
+
+       if (cconn) {
+               out += snprintf(buf + out, len - out,
+                               "%10s => Stack: %s  Name: %*s  "
+                               "Version: %d.%d\n", "Cluster",
+                               (*osb->osb_cluster_stack == '\0' ?
+                                "o2cb" : osb->osb_cluster_stack),
+                               cconn->cc_namelen, cconn->cc_name,
+                               cconn->cc_version.pv_major,
+                               cconn->cc_version.pv_minor);
+       }
+
+       spin_lock(&osb->dc_task_lock);
+       out += snprintf(buf + out, len - out,
+                       "%10s => Pid: %d  Count: %lu  WakeSeq: %lu  "
+                       "WorkSeq: %lu\n", "DownCnvt",
+                       (osb->dc_task ?  task_pid_nr(osb->dc_task) : -1),
+                       osb->blocked_lock_count, osb->dc_wake_sequence,
+                       osb->dc_work_sequence);
+       spin_unlock(&osb->dc_task_lock);
+
+       spin_lock(&osb->osb_lock);
+       out += snprintf(buf + out, len - out, "%10s => Pid: %d  Nodes:",
+                       "Recovery",
+                       (osb->recovery_thread_task ?
+                        task_pid_nr(osb->recovery_thread_task) : -1));
+       if (rm->rm_used == 0)
+               out += snprintf(buf + out, len - out, " None\n");
+       else {
+               for (i = 0; i < rm->rm_used; i++)
+                       out += snprintf(buf + out, len - out, " %d",
+                                       rm->rm_entries[i]);
+               out += snprintf(buf + out, len - out, "\n");
+       }
+       spin_unlock(&osb->osb_lock);
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => Pid: %d  Interval: %lu  Needs: %d\n", "Commit",
+                       (osb->commit_task ? task_pid_nr(osb->commit_task) : -1),
+                       osb->osb_commit_interval,
+                       atomic_read(&osb->needs_checkpoint));
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => State: %d  TxnId: %lu  NumTxns: %d\n",
+                       "Journal", osb->journal->j_state,
+                       osb->journal->j_trans_id,
+                       atomic_read(&osb->journal->j_num_trans));
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => GlobalAllocs: %d  LocalAllocs: %d  "
+                       "SubAllocs: %d  LAWinMoves: %d  SAExtends: %d\n",
+                       "Stats",
+                       atomic_read(&osb->alloc_stats.bitmap_data),
+                       atomic_read(&osb->alloc_stats.local_data),
+                       atomic_read(&osb->alloc_stats.bg_allocs),
+                       atomic_read(&osb->alloc_stats.moves),
+                       atomic_read(&osb->alloc_stats.bg_extends));
+
+       out += snprintf(buf + out, len - out,
+                       "%10s => State: %u  Descriptor: %llu  Size: %u bits  "
+                       "Default: %u bits\n",
+                       "LocalAlloc", osb->local_alloc_state,
+                       (unsigned long long)osb->la_last_gd,
+                       osb->local_alloc_bits, osb->local_alloc_default_bits);
+
+       spin_lock(&osb->osb_lock);
+       out += snprintf(buf + out, len - out,
+                       "%10s => Slot: %d  NumStolen: %d\n", "Steal",
+                       osb->s_inode_steal_slot,
+                       atomic_read(&osb->s_num_inodes_stolen));
+       spin_unlock(&osb->osb_lock);
+
+       out += snprintf(buf + out, len - out, "OrphanScan => ");
+       out += snprintf(buf + out, len - out, "Local: %u  Global: %u ",
+                       os->os_count, os->os_seqno);
+       out += snprintf(buf + out, len - out, " Last Scan: ");
+       if (atomic_read(&os->os_state) == ORPHAN_SCAN_INACTIVE)
+               out += snprintf(buf + out, len - out, "Disabled\n");
+       else
+               out += snprintf(buf + out, len - out, "%lu seconds ago\n",
+                               (get_seconds() - os->os_scantime.tv_sec));
+
+       out += snprintf(buf + out, len - out, "%10s => %3s  %10s\n",
+                       "Slots", "Num", "RecoGen");
+       for (i = 0; i < osb->max_slots; ++i) {
+               out += snprintf(buf + out, len - out,
+                               "%10s  %c %3d  %10d\n",
+                               " ",
+                               (i == osb->slot_num ? '*' : ' '),
+                               i, osb->slot_recovery_generations[i]);
+       }
+
+       return out;
 }
 
+static int ocfs2_osb_debug_open(struct inode *inode, struct file *file)
+{
+       struct ocfs2_super *osb = inode->i_private;
+       char *buf = NULL;
+
+       buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
+       if (!buf)
+               goto bail;
+
+       i_size_write(inode, ocfs2_osb_dump(osb, buf, PAGE_SIZE));
+
+       file->private_data = buf;
+
+       return 0;
+bail:
+       return -ENOMEM;
+}
+
+static int ocfs2_debug_release(struct inode *inode, struct file *file)
+{
+       kfree(file->private_data);
+       return 0;
+}
+
+static ssize_t ocfs2_debug_read(struct file *file, char __user *buf,
+                               size_t nbytes, loff_t *ppos)
+{
+       return simple_read_from_buffer(buf, nbytes, ppos, file->private_data,
+                                      i_size_read(file->f_mapping->host));
+}
+#else
+static int ocfs2_osb_debug_open(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+static int ocfs2_debug_release(struct inode *inode, struct file *file)
+{
+       return 0;
+}
+static ssize_t ocfs2_debug_read(struct file *file, char __user *buf,
+                               size_t nbytes, loff_t *ppos)
+{
+       return 0;
+}
+#endif /* CONFIG_DEBUG_FS */
+
+static const struct file_operations ocfs2_osb_debug_fops = {
+       .open =         ocfs2_osb_debug_open,
+       .release =      ocfs2_debug_release,
+       .read =         ocfs2_debug_read,
+       .llseek =       generic_file_llseek,
+};
+
 static int ocfs2_sync_fs(struct super_block *sb, int wait)
 {
        int status;
        tid_t target;
        struct ocfs2_super *osb = OCFS2_SB(sb);
 
-       sb->s_dirt = 0;
-
        if (ocfs2_is_hard_readonly(osb))
                return -EROFS;
 
@@ -391,7 +558,7 @@ static unsigned long long ocfs2_max_file_offset(unsigned int bbits,
         */
 
 #if BITS_PER_LONG == 32
-# if defined(CONFIG_LBD)
+# if defined(CONFIG_LBDAF)
        BUILD_BUG_ON(sizeof(sector_t) != 8);
        /*
         * We might be limited by page cache size.
@@ -431,6 +598,8 @@ static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
        struct mount_options parsed_options;
        struct ocfs2_super *osb = OCFS2_SB(sb);
 
+       lock_kernel();
+
        if (!ocfs2_parse_options(sb, data, &parsed_options, 1)) {
                ret = -EINVAL;
                goto out;
@@ -534,12 +703,14 @@ unlock_osb:
                        ocfs2_set_journal_params(osb);
        }
 out:
+       unlock_kernel();
        return ret;
 }
 
 static int ocfs2_sb_probe(struct super_block *sb,
                          struct buffer_head **bh,
-                         int *sector_size)
+                         int *sector_size,
+                         struct ocfs2_blockcheck_stats *stats)
 {
        int status, tmpstat;
        struct ocfs1_vol_disk_hdr *hdr;
@@ -549,7 +720,7 @@ static int ocfs2_sb_probe(struct super_block *sb,
        *bh = NULL;
 
        /* may be > 512 */
-       *sector_size = bdev_hardsect_size(sb->s_bdev);
+       *sector_size = bdev_logical_block_size(sb->s_bdev);
        if (*sector_size > OCFS2_MAX_BLOCKSIZE) {
                mlog(ML_ERROR, "Hardware sector size too large: %d (max=%d)\n",
                     *sector_size, OCFS2_MAX_BLOCKSIZE);
@@ -602,16 +773,20 @@ static int ocfs2_sb_probe(struct super_block *sb,
                if (tmpstat < 0) {
                        status = tmpstat;
                        mlog_errno(status);
-                       goto bail;
+                       break;
                }
                di = (struct ocfs2_dinode *) (*bh)->b_data;
-               status = ocfs2_verify_volume(di, *bh, blksize);
-               if (status >= 0)
-                       goto bail;
-               brelse(*bh);
-               *bh = NULL;
-               if (status != -EAGAIN)
+               memset(stats, 0, sizeof(struct ocfs2_blockcheck_stats));
+               spin_lock_init(&stats->b_lock);
+               tmpstat = ocfs2_verify_volume(di, *bh, blksize, stats);
+               if (tmpstat < 0) {
+                       brelse(*bh);
+                       *bh = NULL;
+               }
+               if (tmpstat != -EAGAIN) {
+                       status = tmpstat;
                        break;
+               }
        }
 
 bail:
@@ -792,7 +967,7 @@ static int ocfs2_quota_off(struct super_block *sb, int type, int remount)
        return vfs_quota_disable(sb, type, DQUOT_LIMITS_ENABLED);
 }
 
-static struct quotactl_ops ocfs2_quotactl_ops = {
+static const struct quotactl_ops ocfs2_quotactl_ops = {
        .quota_on       = ocfs2_quota_on,
        .quota_off      = ocfs2_quota_off,
        .quota_sync     = vfs_quota_sync,
@@ -811,6 +986,7 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        struct ocfs2_super *osb = NULL;
        struct buffer_head *bh = NULL;
        char nodestr[8];
+       struct ocfs2_blockcheck_stats stats;
 
        mlog_entry("%p, %p, %i", sb, data, silent);
 
@@ -820,13 +996,13 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        }
 
        /* probe for superblock */
-       status = ocfs2_sb_probe(sb, &bh, &sector_size);
+       status = ocfs2_sb_probe(sb, &bh, &sector_size, &stats);
        if (status < 0) {
                mlog(ML_ERROR, "superblock probe failed!\n");
                goto read_super_error;
        }
 
-       status = ocfs2_initialize_super(sb, bh, sector_size);
+       status = ocfs2_initialize_super(sb, bh, sector_size, &stats);
        osb = OCFS2_SB(sb);
        if (status < 0) {
                mlog_errno(status);
@@ -926,6 +1102,28 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
                goto read_super_error;
        }
 
+       osb->osb_ctxt = debugfs_create_file("fs_state", S_IFREG|S_IRUSR,
+                                           osb->osb_debug_root,
+                                           osb,
+                                           &ocfs2_osb_debug_fops);
+       if (!osb->osb_ctxt) {
+               status = -EINVAL;
+               mlog_errno(status);
+               goto read_super_error;
+       }
+
+       if (ocfs2_meta_ecc(osb)) {
+               status = ocfs2_blockcheck_stats_debugfs_install(
+                                               &osb->osb_ecc_stats,
+                                               osb->osb_debug_root);
+               if (status) {
+                       mlog(ML_ERROR,
+                            "Unable to create blockcheck statistics "
+                            "files\n");
+                       goto read_super_error;
+               }
+       }
+
        status = ocfs2_mount_volume(sb);
        if (osb->root_inode)
                inode = igrab(osb->root_inode);
@@ -986,6 +1184,9 @@ static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
        atomic_set(&osb->vol_state, VOLUME_MOUNTED_QUOTAS);
        wake_up(&osb->osb_mount_event);
 
+       /* Start this when the mount is almost sure of being successful */
+       ocfs2_orphan_scan_start(osb);
+
        mlog_exit(status);
        return status;
 
@@ -1015,14 +1216,31 @@ static int ocfs2_get_sb(struct file_system_type *fs_type,
                           mnt);
 }
 
+static void ocfs2_kill_sb(struct super_block *sb)
+{
+       struct ocfs2_super *osb = OCFS2_SB(sb);
+
+       /* Failed mount? */
+       if (!osb || atomic_read(&osb->vol_state) == VOLUME_DISABLED)
+               goto out;
+
+       /* Prevent further queueing of inode drop events */
+       spin_lock(&dentry_list_lock);
+       ocfs2_set_osb_flag(osb, OCFS2_OSB_DROP_DENTRY_LOCK_IMMED);
+       spin_unlock(&dentry_list_lock);
+       /* Wait for work to finish and/or remove it */
+       cancel_work_sync(&osb->dentry_lock_work);
+out:
+       kill_block_super(sb);
+}
+
 static struct file_system_type ocfs2_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "ocfs2",
        .get_sb         = ocfs2_get_sb, /* is this called when we mount
                                        * the fs? */
-       .kill_sb        = kill_block_super, /* set to the generic one
-                                            * right now, but do we
-                                            * need to change that? */
+       .kill_sb        = ocfs2_kill_sb,
+
        .fs_flags       = FS_REQUIRES_DEV|FS_RENAME_DOES_D_MOVE,
        .next           = NULL
 };
@@ -1376,9 +1594,13 @@ static void ocfs2_put_super(struct super_block *sb)
 {
        mlog_entry("(0x%p)\n", sb);
 
+       lock_kernel();
+
        ocfs2_sync_blockdev(sb);
        ocfs2_dismount_volume(sb, 0);
 
+       unlock_kernel();
+
        mlog_exit_void();
 }
 
@@ -1425,6 +1647,10 @@ static int ocfs2_statfs(struct dentry *dentry, struct kstatfs *buf)
        buf->f_bavail = buf->f_bfree;
        buf->f_files = numbits;
        buf->f_ffree = freebits;
+       buf->f_fsid.val[0] = crc32_le(0, osb->uuid_str, OCFS2_VOL_UUID_LEN)
+                               & 0xFFFFFFFFUL;
+       buf->f_fsid.val[1] = crc32_le(0, osb->uuid_str + OCFS2_VOL_UUID_LEN,
+                               OCFS2_VOL_UUID_LEN) & 0xFFFFFFFFUL;
 
        brelse(bh);
 
@@ -1448,8 +1674,6 @@ static void ocfs2_inode_init_once(void *data)
        spin_lock_init(&oi->ip_lock);
        ocfs2_extent_map_init(&oi->vfs_inode);
        INIT_LIST_HEAD(&oi->ip_io_markers);
-       oi->ip_created_trans = 0;
-       oi->ip_last_trans = 0;
        oi->ip_dir_start_lookup = 0;
 
        init_rwsem(&oi->ip_alloc_sem);
@@ -1463,7 +1687,8 @@ static void ocfs2_inode_init_once(void *data)
        ocfs2_lock_res_init_once(&oi->ip_inode_lockres);
        ocfs2_lock_res_init_once(&oi->ip_open_lockres);
 
-       ocfs2_metadata_cache_init(&oi->vfs_inode);
+       ocfs2_metadata_cache_init(INODE_CACHE(&oi->vfs_inode),
+                                 &ocfs2_inode_caching_ops);
 
        inode_init_once(&oi->vfs_inode);
 }
@@ -1537,6 +1762,13 @@ static int ocfs2_get_sector(struct super_block *sb,
        unlock_buffer(*bh);
        ll_rw_block(READ, 1, bh);
        wait_on_buffer(*bh);
+       if (!buffer_uptodate(*bh)) {
+               mlog_errno(-EIO);
+               brelse(*bh);
+               *bh = NULL;
+               return -EIO;
+       }
+
        return 0;
 }
 
@@ -1585,13 +1817,8 @@ static int ocfs2_mount_volume(struct super_block *sb)
        }
 
        status = ocfs2_truncate_log_init(osb);
-       if (status < 0) {
+       if (status < 0)
                mlog_errno(status);
-               goto leave;
-       }
-
-       if (ocfs2_mount_local(osb))
-               goto leave;
 
 leave:
        if (unlock_super)
@@ -1613,6 +1840,17 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
        osb = OCFS2_SB(sb);
        BUG_ON(!osb);
 
+       debugfs_remove(osb->osb_ctxt);
+
+       /*
+        * Flush inode dropping work queue so that deletes are
+        * performed while the filesystem is still working
+        */
+       ocfs2_drop_all_dl_inodes(osb);
+
+       /* Orphan scan should be stopped as early as possible */
+       ocfs2_orphan_scan_stop(osb);
+
        ocfs2_disable_quotas(osb);
 
        ocfs2_shutdown_local_alloc(osb);
@@ -1626,6 +1864,8 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
 
        ocfs2_sync_blockdev(sb);
 
+       ocfs2_purge_refcount_trees(osb);
+
        /* No cluster connection means we've failed during mount, so skip
         * all the steps which depended on that to complete. */
        if (osb->cconn) {
@@ -1656,6 +1896,7 @@ static void ocfs2_dismount_volume(struct super_block *sb, int mnt_err)
        if (osb->cconn)
                ocfs2_dlm_shutdown(osb, hangup_needed);
 
+       ocfs2_blockcheck_stats_debugfs_remove(&osb->osb_ecc_stats);
        debugfs_remove(osb->osb_debug_root);
 
        if (hangup_needed)
@@ -1703,7 +1944,8 @@ static int ocfs2_setup_osb_uuid(struct ocfs2_super *osb, const unsigned char *uu
 
 static int ocfs2_initialize_super(struct super_block *sb,
                                  struct buffer_head *bh,
-                                 int sector_size)
+                                 int sector_size,
+                                 struct ocfs2_blockcheck_stats *stats)
 {
        int status;
        int i, cbits, bbits;
@@ -1735,6 +1977,12 @@ static int ocfs2_initialize_super(struct super_block *sb,
        bbits = le32_to_cpu(di->id2.i_super.s_blocksize_bits);
        sb->s_maxbytes = ocfs2_max_file_offset(bbits, cbits);
 
+       osb->osb_dx_mask = (1 << (cbits - bbits)) - 1;
+
+       for (i = 0; i < 3; i++)
+               osb->osb_dx_seed[i] = le32_to_cpu(di->id2.i_super.s_dx_seed[i]);
+       osb->osb_dx_seed[3] = le32_to_cpu(di->id2.i_super.s_uuid_hash);
+
        osb->sb = sb;
        /* Save off for ocfs2_rw_direct */
        osb->s_sectsize_bits = blksize_bits(sector_size);
@@ -1747,6 +1995,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
        INIT_LIST_HEAD(&osb->blocked_lock_list);
        osb->blocked_lock_count = 0;
        spin_lock_init(&osb->osb_lock);
+       spin_lock_init(&osb->osb_xattr_lock);
        ocfs2_init_inode_steal_slot(osb);
 
        atomic_set(&osb->alloc_stats.moves, 0);
@@ -1755,11 +2004,16 @@ static int ocfs2_initialize_super(struct super_block *sb,
        atomic_set(&osb->alloc_stats.bg_allocs, 0);
        atomic_set(&osb->alloc_stats.bg_extends, 0);
 
+       /* Copy the blockcheck stats from the superblock probe */
+       osb->osb_ecc_stats = *stats;
+
        ocfs2_init_node_maps(osb);
 
        snprintf(osb->dev_str, sizeof(osb->dev_str), "%u,%u",
                 MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev));
 
+       ocfs2_orphan_scan_init(osb);
+
        status = ocfs2_recovery_init(osb);
        if (status) {
                mlog(ML_ERROR, "Unable to initialize recovery state\n");
@@ -1818,6 +2072,8 @@ static int ocfs2_initialize_super(struct super_block *sb,
                goto bail;
        }
 
+       osb->osb_rf_lock_tree = RB_ROOT;
+
        osb->s_feature_compat =
                le32_to_cpu(OCFS2_RAW_SB(di)->s_feature_compat);
        osb->s_feature_ro_compat =
@@ -1985,7 +2241,8 @@ bail:
  */
 static int ocfs2_verify_volume(struct ocfs2_dinode *di,
                               struct buffer_head *bh,
-                              u32 blksz)
+                              u32 blksz,
+                              struct ocfs2_blockcheck_stats *stats)
 {
        int status = -EAGAIN;
 
@@ -1998,7 +2255,8 @@ static int ocfs2_verify_volume(struct ocfs2_dinode *di,
                    OCFS2_FEATURE_INCOMPAT_META_ECC) {
                        status = ocfs2_block_check_validate(bh->b_data,
                                                            bh->b_size,
-                                                           &di->i_check);
+                                                           &di->i_check,
+                                                           stats);
                        if (status)
                                goto out;
                }
@@ -2122,6 +2380,12 @@ static int ocfs2_check_volume(struct ocfs2_super *osb)
         * lock, and it's marked as dirty, set the bit in the recover
         * map and launch a recovery thread for it. */
        status = ocfs2_mark_dead_nodes(osb);
+       if (status < 0) {
+               mlog_errno(status);
+               goto finally;
+       }
+
+       status = ocfs2_compute_replay_slots(osb);
        if (status < 0)
                mlog_errno(status);
 
@@ -2235,7 +2499,8 @@ void __ocfs2_abort(struct super_block* sb,
        /* Force a panic(). This stinks, but it's better than letting
         * things continue without having a proper hard readonly
         * here. */
-       OCFS2_SB(sb)->s_mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
+       if (!ocfs2_mount_local(OCFS2_SB(sb)))
+               OCFS2_SB(sb)->s_mount_opt |= OCFS2_MOUNT_ERRORS_PANIC;
        ocfs2_handle_error(sb);
 }