@@ -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);
}
@@ -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)) {
@@ -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 */
@@ -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) {
The option make client reconnect to cluster, using new entity addr. It can be used for recovering from blacklistd. Signed-off-by: "Yan, Zheng" <zyan@redhat.com> --- fs/ceph/mds_client.c | 16 ++++++++--- fs/ceph/super.c | 60 +++++++++++++++++++++++++++++++++++++++--- fs/ceph/super.h | 1 + net/ceph/ceph_common.c | 30 ++++++++++++--------- 4 files changed, 88 insertions(+), 19 deletions(-)