diff --git a/fs/ceph/mds_client.c b/fs/ceph/mds_client.c
index d4f07d3120cb..59172e63a61f 100644
--- a/fs/ceph/mds_client.c
+++ b/fs/ceph/mds_client.c
@@ -1394,9 +1394,12 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
 		struct ceph_cap_flush *cf;
 		struct ceph_mds_client *mdsc = fsc->mdsc;
 
-		if (ci->i_wrbuffer_ref > 0 &&
-		    READ_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN)
-			invalidate = true;
+		if (READ_ONCE(fsc->mount_state) == CEPH_MOUNT_SHUTDOWN) {
+			if (inode->i_data.nrpages > 0)
+				invalidate = true;
+			if (ci->i_wrbuffer_ref > 0)
+				mapping_set_error(&inode->i_data, -EIO);
+		}
 
 		while (!list_empty(&ci->i_cap_flush_list)) {
 			cf = list_first_entry(&ci->i_cap_flush_list,
@@ -4369,7 +4372,12 @@ void ceph_mdsc_force_umount(struct ceph_mds_client *mdsc)
 		session = __ceph_lookup_mds_session(mdsc, mds);
 		if (!session)
 			continue;
+
+		if (session->s_state == CEPH_MDS_SESSION_REJECTED)
+			__unregister_session(mdsc, session);
+		__wake_requests(mdsc, &session->s_waiting);
 		mutex_unlock(&mdsc->mutex);
+
 		mutex_lock(&session->s_mutex);
 		__close_session(mdsc, session);
 		if (session->s_state == CEPH_MDS_SESSION_CLOSING) {
@@ -4378,9 +4386,11 @@ void ceph_mdsc_force_umount(struct ceph_mds_client *mdsc)
 		}
 		mutex_unlock(&session->s_mutex);
 		ceph_put_mds_session(session);
+
 		mutex_lock(&mdsc->mutex);
 		kick_requests(mdsc, mds);
 	}
+
 	__wake_requests(mdsc, &mdsc->waiting_for_map);
 	mutex_unlock(&mdsc->mutex);
 }
diff --git a/fs/ceph/super.c b/fs/ceph/super.c
index 5f0c950ca966..04a9af66419d 100644
--- a/fs/ceph/super.c
+++ b/fs/ceph/super.c
@@ -169,6 +169,7 @@ enum {
 	Opt_noquotadf,
 	Opt_copyfrom,
 	Opt_nocopyfrom,
+	Opt_force_reconnect,
 };
 
 static match_table_t fsopt_tokens = {
@@ -210,6 +211,7 @@ static match_table_t fsopt_tokens = {
 	{Opt_noquotadf, "noquotadf"},
 	{Opt_copyfrom, "copyfrom"},
 	{Opt_nocopyfrom, "nocopyfrom"},
+	{Opt_force_reconnect, "force_reconnect"},
 	{-1, NULL}
 };
 
@@ -373,6 +375,9 @@ static int parse_fsopt_token(char *c, void *private)
 	case Opt_nocopyfrom:
 		fsopt->flags |= CEPH_MOUNT_OPT_NOCOPYFROM;
 		break;
+	case Opt_force_reconnect:
+		fsopt->flags |= CEPH_MOUNT_OPT_FORCERECONNCT;
+		break;
 #ifdef CONFIG_CEPH_FS_POSIX_ACL
 	case Opt_acl:
 		fsopt->sb_flags |= SB_POSIXACL;
@@ -832,10 +837,53 @@ static void ceph_umount_begin(struct super_block *sb)
 	return;
 }
 
-static int ceph_remount(struct super_block *sb, int *flags, char *data)
+static int ceph_remount(struct super_block *sb, int *flags, char *options)
 {
-	sync_filesystem(sb);
-	return 0;
+	struct ceph_fs_client *fsc = ceph_sb_to_client(sb);
+	struct ceph_options *opt;
+	struct ceph_mount_options *fsopt;
+	int err = 0;
+
+	fsopt = kzalloc(sizeof(*fsopt), GFP_KERNEL);
+	if (!fsopt)
+		return -ENOMEM;
+
+	opt = ceph_parse_options(options, NULL, NULL,
+				 parse_fsopt_token, (void *)fsopt);
+	if (IS_ERR(opt)) {
+		err = PTR_ERR(opt);
+		goto out;
+	}
+
+	if (!(fsopt->flags & CEPH_MOUNT_OPT_FORCERECONNCT)) {
+		sync_filesystem(sb);
+		goto out;
+	}
+
+	ceph_umount_begin(sb);
+
+	/* Make sure all page caches get invalidated.
+	 * see remove_session_caps_cb() */
+	flush_workqueue(fsc->inode_wq);
+
+	/* In case that we were blacklisted. This also reset
+	 * all mon/osd connections */
+	ceph_reset_client_addr(fsc->client);
+
+	ceph_osdc_clear_abort_err(&fsc->client->osdc);
+	fsc->mount_state = 0;
+
+	if (sb->s_root) {
+		err = __ceph_do_getattr(d_inode(sb->s_root), NULL,
+					CEPH_STAT_CAP_INODE, true);
+	} else {
+		err = 0;
+	}
+out:
+	if (!IS_ERR_OR_NULL(opt))
+		ceph_destroy_options(opt);
+	destroy_mount_options(fsopt);
+	return err;
 }
 
 static const struct super_operations ceph_super_ops = {
@@ -1067,6 +1115,12 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
 		goto out_final;
 	}
 
+	if (fsopt->flags & CEPH_MOUNT_OPT_FORCERECONNCT) {
+		pr_err("ceph: force_reconnect option is only for remount\n");
+		res = ERR_PTR(-EINVAL);
+		goto out_final;
+	}
+
 	/* create client (which we may/may not use) */
 	fsc = create_fs_client(fsopt, opt);
 	if (IS_ERR(fsc)) {
diff --git a/fs/ceph/super.h b/fs/ceph/super.h
index da33847bdc9a..71ac136b8758 100644
--- a/fs/ceph/super.h
+++ b/fs/ceph/super.h
@@ -31,6 +31,7 @@
 #define CEPH_BLOCK_SHIFT   22  /* 4 MB */
 #define CEPH_BLOCK         (1 << CEPH_BLOCK_SHIFT)
 
+#define CEPH_MOUNT_OPT_FORCERECONNCT   (1<<0) /* force reconnect, remount only */
 #define CEPH_MOUNT_OPT_DIRSTAT         (1<<4) /* `cat dirname` for stats */
 #define CEPH_MOUNT_OPT_RBYTES          (1<<5) /* dir st_bytes = rbytes */
 #define CEPH_MOUNT_OPT_NOASYNCREADDIR  (1<<7) /* no dcache readdir */
diff --git a/net/ceph/ceph_common.c b/net/ceph/ceph_common.c
index 6676f48d615c..3511782a5b0a 100644
--- a/net/ceph/ceph_common.c
+++ b/net/ceph/ceph_common.c
@@ -358,13 +358,6 @@ ceph_parse_options(char *options, const char *dev_name,
 	opt = kzalloc(sizeof(*opt), GFP_KERNEL);
 	if (!opt)
 		return ERR_PTR(-ENOMEM);
-	opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
-				GFP_KERNEL);
-	if (!opt->mon_addr)
-		goto out;
-
-	dout("parse_options %p options '%s' dev_name '%s'\n", opt, options,
-	     dev_name);
 
 	/* start with defaults */
 	opt->flags = CEPH_OPT_DEFAULT;
@@ -373,12 +366,23 @@ ceph_parse_options(char *options, const char *dev_name,
 	opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;
 	opt->osd_request_timeout = CEPH_OSD_REQUEST_TIMEOUT_DEFAULT;
 
-	/* get mon ip(s) */
-	/* ip1[:port1][,ip2[:port2]...] */
-	err = ceph_parse_ips(dev_name, dev_name_end, opt->mon_addr,
-			     CEPH_MAX_MON, &opt->num_mon);
-	if (err < 0)
-		goto out;
+	dout("parse_options %p options '%s' dev_name '%s'\n", opt, options,
+	     (dev_name ? : "null"));
+
+	if (dev_name) {
+		opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
+					GFP_KERNEL);
+		if (!opt->mon_addr)
+			goto out;
+
+
+		/* get mon ip(s) */
+		/* ip1[:port1][,ip2[:port2]...] */
+		err = ceph_parse_ips(dev_name, dev_name_end, opt->mon_addr,
+				     CEPH_MAX_MON, &opt->num_mon);
+		if (err < 0)
+			goto out;
+	}
 
 	/* parse mount options */
 	while ((c = strsep(&options, ",")) != NULL) {
