diff mbox series

test error handling during mount stage

Message ID 20220424131126.2569-1-heming.zhao@suse.com (mailing list archive)
State New
Headers show
Series test error handling during mount stage | expand

Commit Message

Heming Zhao April 24, 2022, 1:11 p.m. UTC
this patch is for test my serial patch only.
I don't any plan to add this patch into upstream code.

test script:

```
path="/sys/kernel/debug/ocfs2/mnt_dbg"
dev=$1
mnt=$2

if [ -z "$dev" ];then
    echo "input device. eg: /dev/vdd"
    exit 1
fi
if [ -z "$mnt" ];then
    echo "input mount point. eg: /mnt"
    exit 1
fi

echo "please monitor: journalctl -f"

for i in {1..39}; do
    already_mount=`lsblk | grep $mnt`
    if [ -n "$already_mount" ]; then
        umount $mnt
    fi
    echo "===> error $i <===="
    echo "$i" > $path
    echo "$path: `cat $path`"
    mount -t ocfs2 $dev $mnt
    sleep 1
done
```

Signed-off-by: Heming Zhao <heming.zhao@suse.com>
---
 fs/ocfs2/super.c | 169 ++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 151 insertions(+), 18 deletions(-)
diff mbox series

Patch

diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index f7298816d8d9..4af861f973fc 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -66,6 +66,52 @@  struct kmem_cache *ocfs2_qf_chunk_cachep;
 
 static struct dentry *ocfs2_debugfs_root;
 
+enum {
+	mnt_dbg_off,
+	mnt_dbg_fill_super_1,
+	mnt_dbg_fill_super_2,//useless
+	mnt_dbg_fill_super_3,//useless
+	mnt_dbg_fill_super_4,
+	mnt_dbg_fill_super_5,
+	mnt_dbg_fill_super_6,
+	mnt_dbg_fill_super_7,
+	mnt_dbg_fill_super_8,
+	mnt_dbg_fill_super_9,
+	mnt_dbg_fill_super_10,//useless
+	mnt_dbg_fill_super_11,
+	mnt_dbg_fill_super_12,
+	mnt_dbg_fill_super_13,
+	mnt_dbg_fill_super_14,
+	mnt_dbg_fill_super_15,
+	mnt_dbg_sb_probe_1,
+	mnt_dbg_sb_probe_2,
+	mnt_dbg_sb_probe_3,
+	mnt_dbg_init_super_1,
+	mnt_dbg_init_super_2,
+	mnt_dbg_init_super_3,
+	mnt_dbg_init_super_4,
+	mnt_dbg_init_super_5,
+	mnt_dbg_init_super_6,
+	mnt_dbg_init_super_7,
+	mnt_dbg_init_super_8,
+	mnt_dbg_init_super_9,
+	mnt_dbg_init_super_10,
+	mnt_dbg_init_super_11,
+	mnt_dbg_init_super_12,
+	mnt_dbg_init_super_13,
+	mnt_dbg_init_super_14,
+	mnt_dbg_init_super_15,
+	mnt_dbg_mount_volume_1,
+	mnt_dbg_mount_volume_2,
+	mnt_dbg_mount_volume_3,
+	mnt_dbg_mount_volume_4,
+	mnt_dbg_mount_volume_5,
+	mnt_dbg_mount_volume_6,
+	mnt_dbg_last = mnt_dbg_mount_volume_6,
+};
+
+static u64 mnt_dbg;
+
 MODULE_AUTHOR("Oracle");
 MODULE_LICENSE("GPL");
 MODULE_DESCRIPTION("OCFS2 cluster file system");
@@ -121,6 +167,7 @@  static void ocfs2_free_inode(struct inode *inode);
 static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend);
 static int ocfs2_enable_quotas(struct ocfs2_super *osb);
 static void ocfs2_disable_quotas(struct ocfs2_super *osb);
+int mnt_err_inject(u64 mnt_dbg_num);
 
 static struct dquot **ocfs2_get_dquots(struct inode *inode)
 {
@@ -727,6 +774,15 @@  static int ocfs2_remount(struct super_block *sb, int *flags, char *data)
 	return ret;
 }
 
+int mnt_err_inject(u64 mnt_dbg_num)
+{
+	if (mnt_dbg == mnt_dbg_num) {
+		mlog(ML_ERROR, "trigger dbg num: %llu\n", mnt_dbg);
+		return -EINVAL;
+	}
+	return 0;
+}
+
 static int ocfs2_sb_probe(struct super_block *sb,
 			  struct buffer_head **bh,
 			  int *sector_size,
@@ -741,7 +797,7 @@  static int ocfs2_sb_probe(struct super_block *sb,
 
 	/* may be > 512 */
 	*sector_size = bdev_logical_block_size(sb->s_bdev);
-	if (*sector_size > OCFS2_MAX_BLOCKSIZE) {
+	if (*sector_size > OCFS2_MAX_BLOCKSIZE || mnt_err_inject(mnt_dbg_sb_probe_1) < 0) {
 		mlog(ML_ERROR, "Hardware sector size too large: %d (max=%d)\n",
 		     *sector_size, OCFS2_MAX_BLOCKSIZE);
 		status = -EINVAL;
@@ -772,7 +828,7 @@  static int ocfs2_sb_probe(struct super_block *sb,
 	}
 	brelse(*bh);
 	*bh = NULL;
-	if (status < 0) {
+	if (status < 0 || (status = mnt_err_inject(mnt_dbg_sb_probe_2)) < 0) {
 		mlog(ML_ERROR, "This is an ocfs v1 filesystem which must be "
 		     "upgraded before mounting with ocfs v2\n");
 		goto bail;
@@ -808,6 +864,10 @@  static int ocfs2_sb_probe(struct super_block *sb,
 			break;
 		}
 	}
+	if ((status = mnt_err_inject(mnt_dbg_sb_probe_3)) < 0) {
+		brelse(*bh);
+		*bh = NULL;
+	}
 
 bail:
 	return status;
@@ -987,7 +1047,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 
 	trace_ocfs2_fill_super(sb, data, silent);
 
-	if (!ocfs2_parse_options(sb, data, &parsed_options, 0)) {
+	if (!ocfs2_parse_options(sb, data, &parsed_options, 0) || mnt_err_inject(mnt_dbg_fill_super_1) < 0) {
 		status = -EINVAL;
 		goto out;
 	}
@@ -999,6 +1059,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 		goto out;
 	}
 
+	//add mnt_err_inject() in ocfs2_initialize_super()
 	status = ocfs2_initialize_super(sb, bh, sector_size, &stats);
 	brelse(bh);
 	bh = NULL;
@@ -1007,7 +1068,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 
 	osb = OCFS2_SB(sb);
 
-	if (!ocfs2_check_set_options(sb, &parsed_options)) {
+	if (!ocfs2_check_set_options(sb, &parsed_options) || mnt_err_inject(mnt_dbg_fill_super_4) < 0) {
 		status = -EINVAL;
 		goto out_super;
 	}
@@ -1025,7 +1086,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 		osb->osb_dir_resv_level = parsed_options.dir_resv_level;
 
 	status = ocfs2_verify_userspace_stack(osb, &parsed_options);
-	if (status)
+	if (status || (status = mnt_err_inject(mnt_dbg_fill_super_5)) < 0)
 		goto out_super;
 
 	sb->s_magic = OCFS2_SUPER_MAGIC;
@@ -1036,7 +1097,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	/* Hard readonly mode only if: bdev_read_only, SB_RDONLY,
 	 * heartbeat=none */
 	if (bdev_read_only(sb->s_bdev)) {
-		if (!sb_rdonly(sb)) {
+		if (!sb_rdonly(sb) || mnt_err_inject(mnt_dbg_fill_super_6) < 0) {
 			status = -EACCES;
 			mlog(ML_ERROR, "Readonly device detected but readonly "
 			     "mount was not specified.\n");
@@ -1045,7 +1106,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 
 		/* You should not be able to start a local heartbeat
 		 * on a readonly device. */
-		if (osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) {
+		if ((osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) || mnt_err_inject(mnt_dbg_fill_super_7) < 0) {
 			status = -EROFS;
 			mlog(ML_ERROR, "Local heartbeat specified on readonly "
 			     "device.\n");
@@ -1053,7 +1114,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 		}
 
 		status = ocfs2_check_journals_nolocks(osb);
-		if (status < 0) {
+		if (status < 0 || (status = mnt_err_inject(mnt_dbg_fill_super_8)) < 0) {
 			if (status == -EROFS)
 				mlog(ML_ERROR, "Recovery required on readonly "
 				     "file system, but write access is "
@@ -1074,7 +1135,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	}
 
 	status = ocfs2_verify_heartbeat(osb);
-	if (status < 0)
+	if (status < 0 || (status = mnt_err_inject(mnt_dbg_fill_super_9)) < 0)
 		goto out_super;
 
 	osb->osb_debug_root = debugfs_create_dir(osb->uuid_str,
@@ -1087,6 +1148,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 		ocfs2_blockcheck_stats_debugfs_install( &osb->osb_ecc_stats,
 							osb->osb_debug_root);
 
+	//add mnt_err_inject() in ocfs2_mount_volume()
 	status = ocfs2_mount_volume(sb);
 	if (status < 0)
 		goto out_debugfs;
@@ -1094,14 +1156,14 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	if (osb->root_inode)
 		inode = igrab(osb->root_inode);
 
-	if (!inode) {
+	if (!inode || mnt_err_inject(mnt_dbg_fill_super_11) < 0) {
 		status = -EIO;
 		goto out_dismount;
 	}
 
 	osb->osb_dev_kset = kset_create_and_add(sb->s_id, NULL,
 						&ocfs2_kset->kobj);
-	if (!osb->osb_dev_kset) {
+	if (!osb->osb_dev_kset || mnt_err_inject(mnt_dbg_fill_super_12) < 0) {
 		status = -ENOMEM;
 		mlog(ML_ERROR, "Unable to create device kset %s.\n", sb->s_id);
 		goto out_dismount;
@@ -1109,7 +1171,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 
 	/* Create filecheck sysfs related directories/files at
 	 * /sys/fs/ocfs2/<devname>/filecheck */
-	if (ocfs2_filecheck_create_sysfs(osb)) {
+	if (ocfs2_filecheck_create_sysfs(osb) || mnt_err_inject(mnt_dbg_fill_super_13) < 0) {
 		status = -ENOMEM;
 		mlog(ML_ERROR, "Unable to create filecheck sysfs directory at "
 			"/sys/fs/ocfs2/%s/filecheck.\n", sb->s_id);
@@ -1117,7 +1179,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	}
 
 	root = d_make_root(inode);
-	if (!root) {
+	if (!root || mnt_err_inject(mnt_dbg_fill_super_14) < 0) {
 		status = -ENOMEM;
 		goto out_dismount;
 	}
@@ -1150,7 +1212,7 @@  static int ocfs2_fill_super(struct super_block *sb, void *data, int silent)
 	 * log recovery can happen but that waits for proper quota setup */
 	if (!sb_rdonly(sb)) {
 		status = ocfs2_enable_quotas(osb);
-		if (status < 0) {
+		if (status < 0 || (status = mnt_err_inject(mnt_dbg_fill_super_15)) < 0) {
 			/* We have to err-out specially here because
 			 * s_root is already set */
 			mlog_errno(status);
@@ -1572,6 +1634,21 @@  static int ocfs2_show_options(struct seq_file *s, struct dentry *root)
 	return 0;
 }
 
+static int ocfs2_mnt_dbg_set(void *data, u64 val)
+{
+	u64 *mnt_dbg_num = (u64 *) data;
+	*mnt_dbg_num = val;
+	mlog(ML_ERROR, "set value: %llu\n", val);
+	return 0;
+}
+static int ocfs2_mnt_dbg_get(void *data, u64 *val)
+{
+	u64 *mnt_dbg_num = (u64 *) data;
+	*val = *mnt_dbg_num;
+	return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(ocfs2_mnt_dbg_fops, ocfs2_mnt_dbg_get, ocfs2_mnt_dbg_set, "%llu\n");
+
 static int __init ocfs2_init(void)
 {
 	int status;
@@ -1586,6 +1663,9 @@  static int __init ocfs2_init(void)
 
 	ocfs2_debugfs_root = debugfs_create_dir("ocfs2", NULL);
 
+	debugfs_create_file("mnt_dbg", S_IFREG|S_IRUSR, ocfs2_debugfs_root,
+			    &mnt_dbg, &ocfs2_mnt_dbg_fops);
+
 	ocfs2_set_locking_protocol();
 
 	status = register_quota_format(&ocfs2_quota_format);
@@ -1815,16 +1895,22 @@  static int ocfs2_mount_volume(struct super_block *sb)
 			" disk does not match the running cluster name.\n");
 		goto out;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_mount_volume_1)) < 0) {
+		goto out_dlm;
+	}
 
 	status = ocfs2_super_lock(osb, 1);
 	if (status < 0) {
 		mlog_errno(status);
 		goto out_dlm;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_mount_volume_2)) < 0) {
+		goto out_super_lock;
+	}
 
 	/* This will load up the node map and add ourselves to it. */
 	status = ocfs2_find_slot(osb);
-	if (status < 0) {
+	if (status < 0 || (status = mnt_err_inject(mnt_dbg_mount_volume_3)) < 0) {
 		mlog_errno(status);
 		goto out_super_lock;
 	}
@@ -1835,9 +1921,12 @@  static int ocfs2_mount_volume(struct super_block *sb)
 		mlog_errno(status);
 		goto out_super_lock;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_mount_volume_4)) < 0) {
+		goto out_system_inodes;
+	}
 
 	status = ocfs2_check_volume(osb);
-	if (status < 0) {
+	if (status < 0 || (status = mnt_err_inject(mnt_dbg_mount_volume_5)) < 0) {
 		mlog_errno(status);
 		goto out_system_inodes;
 	}
@@ -1847,6 +1936,10 @@  static int ocfs2_mount_volume(struct super_block *sb)
 		mlog_errno(status);
 		goto out_system_inodes;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_mount_volume_6)) < 0) {
+		ocfs2_truncate_log_shutdown(osb);
+		goto out_system_inodes;
+	}
 
 	ocfs2_super_unlock(osb, 1);
 	return 0;
@@ -2032,6 +2125,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		mlog_errno(status);
 		goto out;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_1)) < 0) {
+		goto out;
+	}
 
 	sb->s_fs_info = osb;
 	sb->s_op = &ocfs2_sops;
@@ -2087,7 +2183,7 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		 MAJOR(osb->sb->s_dev), MINOR(osb->sb->s_dev));
 
 	osb->max_slots = le16_to_cpu(di->id2.i_super.s_max_slots);
-	if (osb->max_slots > OCFS2_MAX_SLOTS || osb->max_slots == 0) {
+	if (osb->max_slots > OCFS2_MAX_SLOTS || osb->max_slots == 0 || mnt_err_inject(mnt_dbg_init_super_2) < 0) {
 		mlog(ML_ERROR, "Invalid number of node slots (%u)\n",
 		     osb->max_slots);
 		status = -EINVAL;
@@ -2102,6 +2198,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		mlog_errno(status);
 		goto out;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_3)) < 0) {
+		goto out_recovery_map;
+	}
 
 	init_waitqueue_head(&osb->checkpoint_event);
 
@@ -2126,6 +2225,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		status = -ENOMEM;
 		goto out_recovery_map;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_4)) < 0) {
+		goto out_vol_label;
+	}
 
 	osb->slot_recovery_generations =
 		kcalloc(osb->max_slots, sizeof(*osb->slot_recovery_generations),
@@ -2135,6 +2237,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		mlog_errno(status);
 		goto out_vol_label;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_5)) < 0) {
+		goto out_slot_recovery_gen;
+	}
 
 	init_waitqueue_head(&osb->osb_wipe_event);
 	osb->osb_orphan_wipes = kcalloc(osb->max_slots,
@@ -2145,6 +2250,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		mlog_errno(status);
 		goto out_slot_recovery_gen;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_6)) < 0) {
+		goto out_orphan_wipes;
+	}
 
 	osb->osb_rf_lock_tree = RB_ROOT;
 
@@ -2207,6 +2315,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 	status = ocfs2_journal_alloc(osb);
 	if (status < 0)
 		goto out_orphan_wipes;
+	if ((status = mnt_err_inject(mnt_dbg_init_super_7)) < 0) {
+		goto out_journal;
+	}
 
 	INIT_WORK(&osb->dquot_drop_work, ocfs2_drop_dquot_refs);
 	init_llist_head(&osb->dquot_drop_list);
@@ -2223,6 +2334,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		status = -EINVAL;
 		goto out_journal;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_8)) < 0) {
+		goto out_journal;
+	}
 
 	total_blocks = ocfs2_clusters_to_blocks(osb->sb,
 						le32_to_cpu(di->i_clusters));
@@ -2235,6 +2349,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		status = -EFBIG;
 		goto out_journal;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_9)) < 0) {
+		goto out_journal;
+	}
 
 	if (ocfs2_setup_osb_uuid(osb, di->id2.i_super.s_uuid,
 				 sizeof(di->id2.i_super.s_uuid))) {
@@ -2242,6 +2359,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		status = -ENOMEM;
 		goto out_journal;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_10)) < 0) {
+		goto out_uuid_str;
+	}
 
 	strlcpy(osb->vol_label, di->id2.i_super.s_label,
 		OCFS2_MAX_VOL_LABEL_LEN);
@@ -2262,6 +2382,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		mlog_errno(status);
 		goto out_uuid_str;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_11)) < 0) {
+		goto out_dlm_out;
+	}
 
 	atomic_set(&osb->vol_state, VOLUME_INIT);
 
@@ -2271,13 +2394,16 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		mlog_errno(status);
 		goto out_dlm_out;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_12)) < 0) {
+		goto out_system_inodes;
+	}
 
 	/*
 	 * global bitmap
 	 */
 	inode = ocfs2_get_system_file_inode(osb, GLOBAL_BITMAP_SYSTEM_INODE,
 					    OCFS2_INVALID_SLOT);
-	if (!inode) {
+	if (!inode || mnt_err_inject(mnt_dbg_init_super_13) < 0) {
 		status = -EINVAL;
 		mlog_errno(status);
 		goto out_system_inodes;
@@ -2295,6 +2421,9 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		mlog_errno(status);
 		goto out_system_inodes;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_14)) < 0) {
+		goto out_slot_info;
+	}
 
 	osb->ocfs2_wq = alloc_ordered_workqueue("ocfs2_wq", WQ_MEM_RECLAIM);
 	if (!osb->ocfs2_wq) {
@@ -2302,6 +2431,10 @@  static int ocfs2_initialize_super(struct super_block *sb,
 		mlog_errno(status);
 		goto out_slot_info;
 	}
+	if ((status = mnt_err_inject(mnt_dbg_init_super_15)) < 0) {
+		destroy_workqueue(osb->ocfs2_wq);
+		goto out_slot_info;
+	}
 
 	return status;