162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/ceph/ceph_debug.h>
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/module.h>
562306a36Sopenharmony_ci#include <linux/types.h>
662306a36Sopenharmony_ci#include <linux/slab.h>
762306a36Sopenharmony_ci#include <linux/random.h>
862306a36Sopenharmony_ci#include <linux/sched.h>
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/ceph/ceph_features.h>
1162306a36Sopenharmony_ci#include <linux/ceph/mon_client.h>
1262306a36Sopenharmony_ci#include <linux/ceph/libceph.h>
1362306a36Sopenharmony_ci#include <linux/ceph/debugfs.h>
1462306a36Sopenharmony_ci#include <linux/ceph/decode.h>
1562306a36Sopenharmony_ci#include <linux/ceph/auth.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci/*
1862306a36Sopenharmony_ci * Interact with Ceph monitor cluster.  Handle requests for new map
1962306a36Sopenharmony_ci * versions, and periodically resend as needed.  Also implement
2062306a36Sopenharmony_ci * statfs() and umount().
2162306a36Sopenharmony_ci *
2262306a36Sopenharmony_ci * A small cluster of Ceph "monitors" are responsible for managing critical
2362306a36Sopenharmony_ci * cluster configuration and state information.  An odd number (e.g., 3, 5)
2462306a36Sopenharmony_ci * of cmon daemons use a modified version of the Paxos part-time parliament
2562306a36Sopenharmony_ci * algorithm to manage the MDS map (mds cluster membership), OSD map, and
2662306a36Sopenharmony_ci * list of clients who have mounted the file system.
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * We maintain an open, active session with a monitor at all times in order to
2962306a36Sopenharmony_ci * receive timely MDSMap updates.  We periodically send a keepalive byte on the
3062306a36Sopenharmony_ci * TCP socket to ensure we detect a failure.  If the connection does break, we
3162306a36Sopenharmony_ci * randomly hunt for a new monitor.  Once the connection is reestablished, we
3262306a36Sopenharmony_ci * resend any outstanding requests.
3362306a36Sopenharmony_ci */
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic const struct ceph_connection_operations mon_con_ops;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic int __validate_auth(struct ceph_mon_client *monc);
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic int decode_mon_info(void **p, void *end, bool msgr2,
4062306a36Sopenharmony_ci			   struct ceph_entity_addr *addr)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci	void *mon_info_end;
4362306a36Sopenharmony_ci	u32 struct_len;
4462306a36Sopenharmony_ci	u8 struct_v;
4562306a36Sopenharmony_ci	int ret;
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci	ret = ceph_start_decoding(p, end, 1, "mon_info_t", &struct_v,
4862306a36Sopenharmony_ci				  &struct_len);
4962306a36Sopenharmony_ci	if (ret)
5062306a36Sopenharmony_ci		return ret;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	mon_info_end = *p + struct_len;
5362306a36Sopenharmony_ci	ceph_decode_skip_string(p, end, e_inval);  /* skip mon name */
5462306a36Sopenharmony_ci	ret = ceph_decode_entity_addrvec(p, end, msgr2, addr);
5562306a36Sopenharmony_ci	if (ret)
5662306a36Sopenharmony_ci		return ret;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	*p = mon_info_end;
5962306a36Sopenharmony_ci	return 0;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_cie_inval:
6262306a36Sopenharmony_ci	return -EINVAL;
6362306a36Sopenharmony_ci}
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_ci/*
6662306a36Sopenharmony_ci * Decode a monmap blob (e.g., during mount).
6762306a36Sopenharmony_ci *
6862306a36Sopenharmony_ci * Assume MonMap v3 (i.e. encoding with MONNAMES and MONENC).
6962306a36Sopenharmony_ci */
7062306a36Sopenharmony_cistatic struct ceph_monmap *ceph_monmap_decode(void **p, void *end, bool msgr2)
7162306a36Sopenharmony_ci{
7262306a36Sopenharmony_ci	struct ceph_monmap *monmap = NULL;
7362306a36Sopenharmony_ci	struct ceph_fsid fsid;
7462306a36Sopenharmony_ci	u32 struct_len;
7562306a36Sopenharmony_ci	int blob_len;
7662306a36Sopenharmony_ci	int num_mon;
7762306a36Sopenharmony_ci	u8 struct_v;
7862306a36Sopenharmony_ci	u32 epoch;
7962306a36Sopenharmony_ci	int ret;
8062306a36Sopenharmony_ci	int i;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	ceph_decode_32_safe(p, end, blob_len, e_inval);
8362306a36Sopenharmony_ci	ceph_decode_need(p, end, blob_len, e_inval);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	ret = ceph_start_decoding(p, end, 6, "monmap", &struct_v, &struct_len);
8662306a36Sopenharmony_ci	if (ret)
8762306a36Sopenharmony_ci		goto fail;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	dout("%s struct_v %d\n", __func__, struct_v);
9062306a36Sopenharmony_ci	ceph_decode_copy_safe(p, end, &fsid, sizeof(fsid), e_inval);
9162306a36Sopenharmony_ci	ceph_decode_32_safe(p, end, epoch, e_inval);
9262306a36Sopenharmony_ci	if (struct_v >= 6) {
9362306a36Sopenharmony_ci		u32 feat_struct_len;
9462306a36Sopenharmony_ci		u8 feat_struct_v;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci		*p += sizeof(struct ceph_timespec);  /* skip last_changed */
9762306a36Sopenharmony_ci		*p += sizeof(struct ceph_timespec);  /* skip created */
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci		ret = ceph_start_decoding(p, end, 1, "mon_feature_t",
10062306a36Sopenharmony_ci					  &feat_struct_v, &feat_struct_len);
10162306a36Sopenharmony_ci		if (ret)
10262306a36Sopenharmony_ci			goto fail;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci		*p += feat_struct_len;  /* skip persistent_features */
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		ret = ceph_start_decoding(p, end, 1, "mon_feature_t",
10762306a36Sopenharmony_ci					  &feat_struct_v, &feat_struct_len);
10862306a36Sopenharmony_ci		if (ret)
10962306a36Sopenharmony_ci			goto fail;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci		*p += feat_struct_len;  /* skip optional_features */
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci	ceph_decode_32_safe(p, end, num_mon, e_inval);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	dout("%s fsid %pU epoch %u num_mon %d\n", __func__, &fsid, epoch,
11662306a36Sopenharmony_ci	     num_mon);
11762306a36Sopenharmony_ci	if (num_mon > CEPH_MAX_MON)
11862306a36Sopenharmony_ci		goto e_inval;
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_ci	monmap = kmalloc(struct_size(monmap, mon_inst, num_mon), GFP_NOIO);
12162306a36Sopenharmony_ci	if (!monmap) {
12262306a36Sopenharmony_ci		ret = -ENOMEM;
12362306a36Sopenharmony_ci		goto fail;
12462306a36Sopenharmony_ci	}
12562306a36Sopenharmony_ci	monmap->fsid = fsid;
12662306a36Sopenharmony_ci	monmap->epoch = epoch;
12762306a36Sopenharmony_ci	monmap->num_mon = num_mon;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	/* legacy_mon_addr map or mon_info map */
13062306a36Sopenharmony_ci	for (i = 0; i < num_mon; i++) {
13162306a36Sopenharmony_ci		struct ceph_entity_inst *inst = &monmap->mon_inst[i];
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci		ceph_decode_skip_string(p, end, e_inval);  /* skip mon name */
13462306a36Sopenharmony_ci		inst->name.type = CEPH_ENTITY_TYPE_MON;
13562306a36Sopenharmony_ci		inst->name.num = cpu_to_le64(i);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci		if (struct_v >= 6)
13862306a36Sopenharmony_ci			ret = decode_mon_info(p, end, msgr2, &inst->addr);
13962306a36Sopenharmony_ci		else
14062306a36Sopenharmony_ci			ret = ceph_decode_entity_addr(p, end, &inst->addr);
14162306a36Sopenharmony_ci		if (ret)
14262306a36Sopenharmony_ci			goto fail;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci		dout("%s mon%d addr %s\n", __func__, i,
14562306a36Sopenharmony_ci		     ceph_pr_addr(&inst->addr));
14662306a36Sopenharmony_ci	}
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci	return monmap;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_cie_inval:
15162306a36Sopenharmony_ci	ret = -EINVAL;
15262306a36Sopenharmony_cifail:
15362306a36Sopenharmony_ci	kfree(monmap);
15462306a36Sopenharmony_ci	return ERR_PTR(ret);
15562306a36Sopenharmony_ci}
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci/*
15862306a36Sopenharmony_ci * return true if *addr is included in the monmap.
15962306a36Sopenharmony_ci */
16062306a36Sopenharmony_ciint ceph_monmap_contains(struct ceph_monmap *m, struct ceph_entity_addr *addr)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	int i;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	for (i = 0; i < m->num_mon; i++) {
16562306a36Sopenharmony_ci		if (ceph_addr_equal_no_type(addr, &m->mon_inst[i].addr))
16662306a36Sopenharmony_ci			return 1;
16762306a36Sopenharmony_ci	}
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	return 0;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci/*
17362306a36Sopenharmony_ci * Send an auth request.
17462306a36Sopenharmony_ci */
17562306a36Sopenharmony_cistatic void __send_prepared_auth_request(struct ceph_mon_client *monc, int len)
17662306a36Sopenharmony_ci{
17762306a36Sopenharmony_ci	monc->pending_auth = 1;
17862306a36Sopenharmony_ci	monc->m_auth->front.iov_len = len;
17962306a36Sopenharmony_ci	monc->m_auth->hdr.front_len = cpu_to_le32(len);
18062306a36Sopenharmony_ci	ceph_msg_revoke(monc->m_auth);
18162306a36Sopenharmony_ci	ceph_msg_get(monc->m_auth);  /* keep our ref */
18262306a36Sopenharmony_ci	ceph_con_send(&monc->con, monc->m_auth);
18362306a36Sopenharmony_ci}
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci/*
18662306a36Sopenharmony_ci * Close monitor session, if any.
18762306a36Sopenharmony_ci */
18862306a36Sopenharmony_cistatic void __close_session(struct ceph_mon_client *monc)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	dout("__close_session closing mon%d\n", monc->cur_mon);
19162306a36Sopenharmony_ci	ceph_msg_revoke(monc->m_auth);
19262306a36Sopenharmony_ci	ceph_msg_revoke_incoming(monc->m_auth_reply);
19362306a36Sopenharmony_ci	ceph_msg_revoke(monc->m_subscribe);
19462306a36Sopenharmony_ci	ceph_msg_revoke_incoming(monc->m_subscribe_ack);
19562306a36Sopenharmony_ci	ceph_con_close(&monc->con);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	monc->pending_auth = 0;
19862306a36Sopenharmony_ci	ceph_auth_reset(monc->auth);
19962306a36Sopenharmony_ci}
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci/*
20262306a36Sopenharmony_ci * Pick a new monitor at random and set cur_mon.  If we are repicking
20362306a36Sopenharmony_ci * (i.e. cur_mon is already set), be sure to pick a different one.
20462306a36Sopenharmony_ci */
20562306a36Sopenharmony_cistatic void pick_new_mon(struct ceph_mon_client *monc)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	int old_mon = monc->cur_mon;
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_ci	BUG_ON(monc->monmap->num_mon < 1);
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	if (monc->monmap->num_mon == 1) {
21262306a36Sopenharmony_ci		monc->cur_mon = 0;
21362306a36Sopenharmony_ci	} else {
21462306a36Sopenharmony_ci		int max = monc->monmap->num_mon;
21562306a36Sopenharmony_ci		int o = -1;
21662306a36Sopenharmony_ci		int n;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci		if (monc->cur_mon >= 0) {
21962306a36Sopenharmony_ci			if (monc->cur_mon < monc->monmap->num_mon)
22062306a36Sopenharmony_ci				o = monc->cur_mon;
22162306a36Sopenharmony_ci			if (o >= 0)
22262306a36Sopenharmony_ci				max--;
22362306a36Sopenharmony_ci		}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci		n = get_random_u32_below(max);
22662306a36Sopenharmony_ci		if (o >= 0 && n >= o)
22762306a36Sopenharmony_ci			n++;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci		monc->cur_mon = n;
23062306a36Sopenharmony_ci	}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	dout("%s mon%d -> mon%d out of %d mons\n", __func__, old_mon,
23362306a36Sopenharmony_ci	     monc->cur_mon, monc->monmap->num_mon);
23462306a36Sopenharmony_ci}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci/*
23762306a36Sopenharmony_ci * Open a session with a new monitor.
23862306a36Sopenharmony_ci */
23962306a36Sopenharmony_cistatic void __open_session(struct ceph_mon_client *monc)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	int ret;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	pick_new_mon(monc);
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	monc->hunting = true;
24662306a36Sopenharmony_ci	if (monc->had_a_connection) {
24762306a36Sopenharmony_ci		monc->hunt_mult *= CEPH_MONC_HUNT_BACKOFF;
24862306a36Sopenharmony_ci		if (monc->hunt_mult > CEPH_MONC_HUNT_MAX_MULT)
24962306a36Sopenharmony_ci			monc->hunt_mult = CEPH_MONC_HUNT_MAX_MULT;
25062306a36Sopenharmony_ci	}
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	monc->sub_renew_after = jiffies; /* i.e., expired */
25362306a36Sopenharmony_ci	monc->sub_renew_sent = 0;
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	dout("%s opening mon%d\n", __func__, monc->cur_mon);
25662306a36Sopenharmony_ci	ceph_con_open(&monc->con, CEPH_ENTITY_TYPE_MON, monc->cur_mon,
25762306a36Sopenharmony_ci		      &monc->monmap->mon_inst[monc->cur_mon].addr);
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	/*
26062306a36Sopenharmony_ci	 * Queue a keepalive to ensure that in case of an early fault
26162306a36Sopenharmony_ci	 * the messenger doesn't put us into STANDBY state and instead
26262306a36Sopenharmony_ci	 * retries.  This also ensures that our timestamp is valid by
26362306a36Sopenharmony_ci	 * the time we finish hunting and delayed_work() checks it.
26462306a36Sopenharmony_ci	 */
26562306a36Sopenharmony_ci	ceph_con_keepalive(&monc->con);
26662306a36Sopenharmony_ci	if (ceph_msgr2(monc->client)) {
26762306a36Sopenharmony_ci		monc->pending_auth = 1;
26862306a36Sopenharmony_ci		return;
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	/* initiate authentication handshake */
27262306a36Sopenharmony_ci	ret = ceph_auth_build_hello(monc->auth,
27362306a36Sopenharmony_ci				    monc->m_auth->front.iov_base,
27462306a36Sopenharmony_ci				    monc->m_auth->front_alloc_len);
27562306a36Sopenharmony_ci	BUG_ON(ret <= 0);
27662306a36Sopenharmony_ci	__send_prepared_auth_request(monc, ret);
27762306a36Sopenharmony_ci}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic void reopen_session(struct ceph_mon_client *monc)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	if (!monc->hunting)
28262306a36Sopenharmony_ci		pr_info("mon%d %s session lost, hunting for new mon\n",
28362306a36Sopenharmony_ci		    monc->cur_mon, ceph_pr_addr(&monc->con.peer_addr));
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	__close_session(monc);
28662306a36Sopenharmony_ci	__open_session(monc);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_civoid ceph_monc_reopen_session(struct ceph_mon_client *monc)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
29262306a36Sopenharmony_ci	reopen_session(monc);
29362306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_cistatic void un_backoff(struct ceph_mon_client *monc)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	monc->hunt_mult /= 2; /* reduce by 50% */
29962306a36Sopenharmony_ci	if (monc->hunt_mult < 1)
30062306a36Sopenharmony_ci		monc->hunt_mult = 1;
30162306a36Sopenharmony_ci	dout("%s hunt_mult now %d\n", __func__, monc->hunt_mult);
30262306a36Sopenharmony_ci}
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci/*
30562306a36Sopenharmony_ci * Reschedule delayed work timer.
30662306a36Sopenharmony_ci */
30762306a36Sopenharmony_cistatic void __schedule_delayed(struct ceph_mon_client *monc)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	unsigned long delay;
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	if (monc->hunting)
31262306a36Sopenharmony_ci		delay = CEPH_MONC_HUNT_INTERVAL * monc->hunt_mult;
31362306a36Sopenharmony_ci	else
31462306a36Sopenharmony_ci		delay = CEPH_MONC_PING_INTERVAL;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci	dout("__schedule_delayed after %lu\n", delay);
31762306a36Sopenharmony_ci	mod_delayed_work(system_wq, &monc->delayed_work,
31862306a36Sopenharmony_ci			 round_jiffies_relative(delay));
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciconst char *ceph_sub_str[] = {
32262306a36Sopenharmony_ci	[CEPH_SUB_MONMAP] = "monmap",
32362306a36Sopenharmony_ci	[CEPH_SUB_OSDMAP] = "osdmap",
32462306a36Sopenharmony_ci	[CEPH_SUB_FSMAP]  = "fsmap.user",
32562306a36Sopenharmony_ci	[CEPH_SUB_MDSMAP] = "mdsmap",
32662306a36Sopenharmony_ci};
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/*
32962306a36Sopenharmony_ci * Send subscribe request for one or more maps, according to
33062306a36Sopenharmony_ci * monc->subs.
33162306a36Sopenharmony_ci */
33262306a36Sopenharmony_cistatic void __send_subscribe(struct ceph_mon_client *monc)
33362306a36Sopenharmony_ci{
33462306a36Sopenharmony_ci	struct ceph_msg *msg = monc->m_subscribe;
33562306a36Sopenharmony_ci	void *p = msg->front.iov_base;
33662306a36Sopenharmony_ci	void *const end = p + msg->front_alloc_len;
33762306a36Sopenharmony_ci	int num = 0;
33862306a36Sopenharmony_ci	int i;
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_ci	dout("%s sent %lu\n", __func__, monc->sub_renew_sent);
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	BUG_ON(monc->cur_mon < 0);
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_ci	if (!monc->sub_renew_sent)
34562306a36Sopenharmony_ci		monc->sub_renew_sent = jiffies | 1; /* never 0 */
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	msg->hdr.version = cpu_to_le16(2);
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(monc->subs); i++) {
35062306a36Sopenharmony_ci		if (monc->subs[i].want)
35162306a36Sopenharmony_ci			num++;
35262306a36Sopenharmony_ci	}
35362306a36Sopenharmony_ci	BUG_ON(num < 1); /* monmap sub is always there */
35462306a36Sopenharmony_ci	ceph_encode_32(&p, num);
35562306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(monc->subs); i++) {
35662306a36Sopenharmony_ci		char buf[32];
35762306a36Sopenharmony_ci		int len;
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci		if (!monc->subs[i].want)
36062306a36Sopenharmony_ci			continue;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci		len = sprintf(buf, "%s", ceph_sub_str[i]);
36362306a36Sopenharmony_ci		if (i == CEPH_SUB_MDSMAP &&
36462306a36Sopenharmony_ci		    monc->fs_cluster_id != CEPH_FS_CLUSTER_ID_NONE)
36562306a36Sopenharmony_ci			len += sprintf(buf + len, ".%d", monc->fs_cluster_id);
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		dout("%s %s start %llu flags 0x%x\n", __func__, buf,
36862306a36Sopenharmony_ci		     le64_to_cpu(monc->subs[i].item.start),
36962306a36Sopenharmony_ci		     monc->subs[i].item.flags);
37062306a36Sopenharmony_ci		ceph_encode_string(&p, end, buf, len);
37162306a36Sopenharmony_ci		memcpy(p, &monc->subs[i].item, sizeof(monc->subs[i].item));
37262306a36Sopenharmony_ci		p += sizeof(monc->subs[i].item);
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	BUG_ON(p > end);
37662306a36Sopenharmony_ci	msg->front.iov_len = p - msg->front.iov_base;
37762306a36Sopenharmony_ci	msg->hdr.front_len = cpu_to_le32(msg->front.iov_len);
37862306a36Sopenharmony_ci	ceph_msg_revoke(msg);
37962306a36Sopenharmony_ci	ceph_con_send(&monc->con, ceph_msg_get(msg));
38062306a36Sopenharmony_ci}
38162306a36Sopenharmony_ci
38262306a36Sopenharmony_cistatic void handle_subscribe_ack(struct ceph_mon_client *monc,
38362306a36Sopenharmony_ci				 struct ceph_msg *msg)
38462306a36Sopenharmony_ci{
38562306a36Sopenharmony_ci	unsigned int seconds;
38662306a36Sopenharmony_ci	struct ceph_mon_subscribe_ack *h = msg->front.iov_base;
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci	if (msg->front.iov_len < sizeof(*h))
38962306a36Sopenharmony_ci		goto bad;
39062306a36Sopenharmony_ci	seconds = le32_to_cpu(h->duration);
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
39362306a36Sopenharmony_ci	if (monc->sub_renew_sent) {
39462306a36Sopenharmony_ci		/*
39562306a36Sopenharmony_ci		 * This is only needed for legacy (infernalis or older)
39662306a36Sopenharmony_ci		 * MONs -- see delayed_work().
39762306a36Sopenharmony_ci		 */
39862306a36Sopenharmony_ci		monc->sub_renew_after = monc->sub_renew_sent +
39962306a36Sopenharmony_ci					    (seconds >> 1) * HZ - 1;
40062306a36Sopenharmony_ci		dout("%s sent %lu duration %d renew after %lu\n", __func__,
40162306a36Sopenharmony_ci		     monc->sub_renew_sent, seconds, monc->sub_renew_after);
40262306a36Sopenharmony_ci		monc->sub_renew_sent = 0;
40362306a36Sopenharmony_ci	} else {
40462306a36Sopenharmony_ci		dout("%s sent %lu renew after %lu, ignoring\n", __func__,
40562306a36Sopenharmony_ci		     monc->sub_renew_sent, monc->sub_renew_after);
40662306a36Sopenharmony_ci	}
40762306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
40862306a36Sopenharmony_ci	return;
40962306a36Sopenharmony_cibad:
41062306a36Sopenharmony_ci	pr_err("got corrupt subscribe-ack msg\n");
41162306a36Sopenharmony_ci	ceph_msg_dump(msg);
41262306a36Sopenharmony_ci}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci/*
41562306a36Sopenharmony_ci * Register interest in a map
41662306a36Sopenharmony_ci *
41762306a36Sopenharmony_ci * @sub: one of CEPH_SUB_*
41862306a36Sopenharmony_ci * @epoch: X for "every map since X", or 0 for "just the latest"
41962306a36Sopenharmony_ci */
42062306a36Sopenharmony_cistatic bool __ceph_monc_want_map(struct ceph_mon_client *monc, int sub,
42162306a36Sopenharmony_ci				 u32 epoch, bool continuous)
42262306a36Sopenharmony_ci{
42362306a36Sopenharmony_ci	__le64 start = cpu_to_le64(epoch);
42462306a36Sopenharmony_ci	u8 flags = !continuous ? CEPH_SUBSCRIBE_ONETIME : 0;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	dout("%s %s epoch %u continuous %d\n", __func__, ceph_sub_str[sub],
42762306a36Sopenharmony_ci	     epoch, continuous);
42862306a36Sopenharmony_ci
42962306a36Sopenharmony_ci	if (monc->subs[sub].want &&
43062306a36Sopenharmony_ci	    monc->subs[sub].item.start == start &&
43162306a36Sopenharmony_ci	    monc->subs[sub].item.flags == flags)
43262306a36Sopenharmony_ci		return false;
43362306a36Sopenharmony_ci
43462306a36Sopenharmony_ci	monc->subs[sub].item.start = start;
43562306a36Sopenharmony_ci	monc->subs[sub].item.flags = flags;
43662306a36Sopenharmony_ci	monc->subs[sub].want = true;
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ci	return true;
43962306a36Sopenharmony_ci}
44062306a36Sopenharmony_ci
44162306a36Sopenharmony_cibool ceph_monc_want_map(struct ceph_mon_client *monc, int sub, u32 epoch,
44262306a36Sopenharmony_ci			bool continuous)
44362306a36Sopenharmony_ci{
44462306a36Sopenharmony_ci	bool need_request;
44562306a36Sopenharmony_ci
44662306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
44762306a36Sopenharmony_ci	need_request = __ceph_monc_want_map(monc, sub, epoch, continuous);
44862306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	return need_request;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_want_map);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci/*
45562306a36Sopenharmony_ci * Keep track of which maps we have
45662306a36Sopenharmony_ci *
45762306a36Sopenharmony_ci * @sub: one of CEPH_SUB_*
45862306a36Sopenharmony_ci */
45962306a36Sopenharmony_cistatic void __ceph_monc_got_map(struct ceph_mon_client *monc, int sub,
46062306a36Sopenharmony_ci				u32 epoch)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	dout("%s %s epoch %u\n", __func__, ceph_sub_str[sub], epoch);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	if (monc->subs[sub].want) {
46562306a36Sopenharmony_ci		if (monc->subs[sub].item.flags & CEPH_SUBSCRIBE_ONETIME)
46662306a36Sopenharmony_ci			monc->subs[sub].want = false;
46762306a36Sopenharmony_ci		else
46862306a36Sopenharmony_ci			monc->subs[sub].item.start = cpu_to_le64(epoch + 1);
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci
47162306a36Sopenharmony_ci	monc->subs[sub].have = epoch;
47262306a36Sopenharmony_ci}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_civoid ceph_monc_got_map(struct ceph_mon_client *monc, int sub, u32 epoch)
47562306a36Sopenharmony_ci{
47662306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
47762306a36Sopenharmony_ci	__ceph_monc_got_map(monc, sub, epoch);
47862306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
47962306a36Sopenharmony_ci}
48062306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_got_map);
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_civoid ceph_monc_renew_subs(struct ceph_mon_client *monc)
48362306a36Sopenharmony_ci{
48462306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
48562306a36Sopenharmony_ci	__send_subscribe(monc);
48662306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
48762306a36Sopenharmony_ci}
48862306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_renew_subs);
48962306a36Sopenharmony_ci
49062306a36Sopenharmony_ci/*
49162306a36Sopenharmony_ci * Wait for an osdmap with a given epoch.
49262306a36Sopenharmony_ci *
49362306a36Sopenharmony_ci * @epoch: epoch to wait for
49462306a36Sopenharmony_ci * @timeout: in jiffies, 0 means "wait forever"
49562306a36Sopenharmony_ci */
49662306a36Sopenharmony_ciint ceph_monc_wait_osdmap(struct ceph_mon_client *monc, u32 epoch,
49762306a36Sopenharmony_ci			  unsigned long timeout)
49862306a36Sopenharmony_ci{
49962306a36Sopenharmony_ci	unsigned long started = jiffies;
50062306a36Sopenharmony_ci	long ret;
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
50362306a36Sopenharmony_ci	while (monc->subs[CEPH_SUB_OSDMAP].have < epoch) {
50462306a36Sopenharmony_ci		mutex_unlock(&monc->mutex);
50562306a36Sopenharmony_ci
50662306a36Sopenharmony_ci		if (timeout && time_after_eq(jiffies, started + timeout))
50762306a36Sopenharmony_ci			return -ETIMEDOUT;
50862306a36Sopenharmony_ci
50962306a36Sopenharmony_ci		ret = wait_event_interruptible_timeout(monc->client->auth_wq,
51062306a36Sopenharmony_ci				     monc->subs[CEPH_SUB_OSDMAP].have >= epoch,
51162306a36Sopenharmony_ci				     ceph_timeout_jiffies(timeout));
51262306a36Sopenharmony_ci		if (ret < 0)
51362306a36Sopenharmony_ci			return ret;
51462306a36Sopenharmony_ci
51562306a36Sopenharmony_ci		mutex_lock(&monc->mutex);
51662306a36Sopenharmony_ci	}
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
51962306a36Sopenharmony_ci	return 0;
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_wait_osdmap);
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci/*
52462306a36Sopenharmony_ci * Open a session with a random monitor.  Request monmap and osdmap,
52562306a36Sopenharmony_ci * which are waited upon in __ceph_open_session().
52662306a36Sopenharmony_ci */
52762306a36Sopenharmony_ciint ceph_monc_open_session(struct ceph_mon_client *monc)
52862306a36Sopenharmony_ci{
52962306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
53062306a36Sopenharmony_ci	__ceph_monc_want_map(monc, CEPH_SUB_MONMAP, 0, true);
53162306a36Sopenharmony_ci	__ceph_monc_want_map(monc, CEPH_SUB_OSDMAP, 0, false);
53262306a36Sopenharmony_ci	__open_session(monc);
53362306a36Sopenharmony_ci	__schedule_delayed(monc);
53462306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
53562306a36Sopenharmony_ci	return 0;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_open_session);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cistatic void ceph_monc_handle_map(struct ceph_mon_client *monc,
54062306a36Sopenharmony_ci				 struct ceph_msg *msg)
54162306a36Sopenharmony_ci{
54262306a36Sopenharmony_ci	struct ceph_client *client = monc->client;
54362306a36Sopenharmony_ci	struct ceph_monmap *monmap;
54462306a36Sopenharmony_ci	void *p, *end;
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	dout("handle_monmap\n");
54962306a36Sopenharmony_ci	p = msg->front.iov_base;
55062306a36Sopenharmony_ci	end = p + msg->front.iov_len;
55162306a36Sopenharmony_ci
55262306a36Sopenharmony_ci	monmap = ceph_monmap_decode(&p, end, ceph_msgr2(client));
55362306a36Sopenharmony_ci	if (IS_ERR(monmap)) {
55462306a36Sopenharmony_ci		pr_err("problem decoding monmap, %d\n",
55562306a36Sopenharmony_ci		       (int)PTR_ERR(monmap));
55662306a36Sopenharmony_ci		ceph_msg_dump(msg);
55762306a36Sopenharmony_ci		goto out;
55862306a36Sopenharmony_ci	}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_ci	if (ceph_check_fsid(client, &monmap->fsid) < 0) {
56162306a36Sopenharmony_ci		kfree(monmap);
56262306a36Sopenharmony_ci		goto out;
56362306a36Sopenharmony_ci	}
56462306a36Sopenharmony_ci
56562306a36Sopenharmony_ci	kfree(monc->monmap);
56662306a36Sopenharmony_ci	monc->monmap = monmap;
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci	__ceph_monc_got_map(monc, CEPH_SUB_MONMAP, monc->monmap->epoch);
56962306a36Sopenharmony_ci	client->have_fsid = true;
57062306a36Sopenharmony_ci
57162306a36Sopenharmony_ciout:
57262306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
57362306a36Sopenharmony_ci	wake_up_all(&client->auth_wq);
57462306a36Sopenharmony_ci}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci/*
57762306a36Sopenharmony_ci * generic requests (currently statfs, mon_get_version)
57862306a36Sopenharmony_ci */
57962306a36Sopenharmony_ciDEFINE_RB_FUNCS(generic_request, struct ceph_mon_generic_request, tid, node)
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_cistatic void release_generic_request(struct kref *kref)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	struct ceph_mon_generic_request *req =
58462306a36Sopenharmony_ci		container_of(kref, struct ceph_mon_generic_request, kref);
58562306a36Sopenharmony_ci
58662306a36Sopenharmony_ci	dout("%s greq %p request %p reply %p\n", __func__, req, req->request,
58762306a36Sopenharmony_ci	     req->reply);
58862306a36Sopenharmony_ci	WARN_ON(!RB_EMPTY_NODE(&req->node));
58962306a36Sopenharmony_ci
59062306a36Sopenharmony_ci	if (req->reply)
59162306a36Sopenharmony_ci		ceph_msg_put(req->reply);
59262306a36Sopenharmony_ci	if (req->request)
59362306a36Sopenharmony_ci		ceph_msg_put(req->request);
59462306a36Sopenharmony_ci
59562306a36Sopenharmony_ci	kfree(req);
59662306a36Sopenharmony_ci}
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_cistatic void put_generic_request(struct ceph_mon_generic_request *req)
59962306a36Sopenharmony_ci{
60062306a36Sopenharmony_ci	if (req)
60162306a36Sopenharmony_ci		kref_put(&req->kref, release_generic_request);
60262306a36Sopenharmony_ci}
60362306a36Sopenharmony_ci
60462306a36Sopenharmony_cistatic void get_generic_request(struct ceph_mon_generic_request *req)
60562306a36Sopenharmony_ci{
60662306a36Sopenharmony_ci	kref_get(&req->kref);
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic struct ceph_mon_generic_request *
61062306a36Sopenharmony_cialloc_generic_request(struct ceph_mon_client *monc, gfp_t gfp)
61162306a36Sopenharmony_ci{
61262306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
61362306a36Sopenharmony_ci
61462306a36Sopenharmony_ci	req = kzalloc(sizeof(*req), gfp);
61562306a36Sopenharmony_ci	if (!req)
61662306a36Sopenharmony_ci		return NULL;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	req->monc = monc;
61962306a36Sopenharmony_ci	kref_init(&req->kref);
62062306a36Sopenharmony_ci	RB_CLEAR_NODE(&req->node);
62162306a36Sopenharmony_ci	init_completion(&req->completion);
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	dout("%s greq %p\n", __func__, req);
62462306a36Sopenharmony_ci	return req;
62562306a36Sopenharmony_ci}
62662306a36Sopenharmony_ci
62762306a36Sopenharmony_cistatic void register_generic_request(struct ceph_mon_generic_request *req)
62862306a36Sopenharmony_ci{
62962306a36Sopenharmony_ci	struct ceph_mon_client *monc = req->monc;
63062306a36Sopenharmony_ci
63162306a36Sopenharmony_ci	WARN_ON(req->tid);
63262306a36Sopenharmony_ci
63362306a36Sopenharmony_ci	get_generic_request(req);
63462306a36Sopenharmony_ci	req->tid = ++monc->last_tid;
63562306a36Sopenharmony_ci	insert_generic_request(&monc->generic_request_tree, req);
63662306a36Sopenharmony_ci}
63762306a36Sopenharmony_ci
63862306a36Sopenharmony_cistatic void send_generic_request(struct ceph_mon_client *monc,
63962306a36Sopenharmony_ci				 struct ceph_mon_generic_request *req)
64062306a36Sopenharmony_ci{
64162306a36Sopenharmony_ci	WARN_ON(!req->tid);
64262306a36Sopenharmony_ci
64362306a36Sopenharmony_ci	dout("%s greq %p tid %llu\n", __func__, req, req->tid);
64462306a36Sopenharmony_ci	req->request->hdr.tid = cpu_to_le64(req->tid);
64562306a36Sopenharmony_ci	ceph_con_send(&monc->con, ceph_msg_get(req->request));
64662306a36Sopenharmony_ci}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_cistatic void __finish_generic_request(struct ceph_mon_generic_request *req)
64962306a36Sopenharmony_ci{
65062306a36Sopenharmony_ci	struct ceph_mon_client *monc = req->monc;
65162306a36Sopenharmony_ci
65262306a36Sopenharmony_ci	dout("%s greq %p tid %llu\n", __func__, req, req->tid);
65362306a36Sopenharmony_ci	erase_generic_request(&monc->generic_request_tree, req);
65462306a36Sopenharmony_ci
65562306a36Sopenharmony_ci	ceph_msg_revoke(req->request);
65662306a36Sopenharmony_ci	ceph_msg_revoke_incoming(req->reply);
65762306a36Sopenharmony_ci}
65862306a36Sopenharmony_ci
65962306a36Sopenharmony_cistatic void finish_generic_request(struct ceph_mon_generic_request *req)
66062306a36Sopenharmony_ci{
66162306a36Sopenharmony_ci	__finish_generic_request(req);
66262306a36Sopenharmony_ci	put_generic_request(req);
66362306a36Sopenharmony_ci}
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic void complete_generic_request(struct ceph_mon_generic_request *req)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	if (req->complete_cb)
66862306a36Sopenharmony_ci		req->complete_cb(req);
66962306a36Sopenharmony_ci	else
67062306a36Sopenharmony_ci		complete_all(&req->completion);
67162306a36Sopenharmony_ci	put_generic_request(req);
67262306a36Sopenharmony_ci}
67362306a36Sopenharmony_ci
67462306a36Sopenharmony_cistatic void cancel_generic_request(struct ceph_mon_generic_request *req)
67562306a36Sopenharmony_ci{
67662306a36Sopenharmony_ci	struct ceph_mon_client *monc = req->monc;
67762306a36Sopenharmony_ci	struct ceph_mon_generic_request *lookup_req;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	dout("%s greq %p tid %llu\n", __func__, req, req->tid);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
68262306a36Sopenharmony_ci	lookup_req = lookup_generic_request(&monc->generic_request_tree,
68362306a36Sopenharmony_ci					    req->tid);
68462306a36Sopenharmony_ci	if (lookup_req) {
68562306a36Sopenharmony_ci		WARN_ON(lookup_req != req);
68662306a36Sopenharmony_ci		finish_generic_request(req);
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
69062306a36Sopenharmony_ci}
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_cistatic int wait_generic_request(struct ceph_mon_generic_request *req)
69362306a36Sopenharmony_ci{
69462306a36Sopenharmony_ci	int ret;
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci	dout("%s greq %p tid %llu\n", __func__, req, req->tid);
69762306a36Sopenharmony_ci	ret = wait_for_completion_interruptible(&req->completion);
69862306a36Sopenharmony_ci	if (ret)
69962306a36Sopenharmony_ci		cancel_generic_request(req);
70062306a36Sopenharmony_ci	else
70162306a36Sopenharmony_ci		ret = req->result; /* completed */
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	return ret;
70462306a36Sopenharmony_ci}
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_cistatic struct ceph_msg *get_generic_reply(struct ceph_connection *con,
70762306a36Sopenharmony_ci					 struct ceph_msg_header *hdr,
70862306a36Sopenharmony_ci					 int *skip)
70962306a36Sopenharmony_ci{
71062306a36Sopenharmony_ci	struct ceph_mon_client *monc = con->private;
71162306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
71262306a36Sopenharmony_ci	u64 tid = le64_to_cpu(hdr->tid);
71362306a36Sopenharmony_ci	struct ceph_msg *m;
71462306a36Sopenharmony_ci
71562306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
71662306a36Sopenharmony_ci	req = lookup_generic_request(&monc->generic_request_tree, tid);
71762306a36Sopenharmony_ci	if (!req) {
71862306a36Sopenharmony_ci		dout("get_generic_reply %lld dne\n", tid);
71962306a36Sopenharmony_ci		*skip = 1;
72062306a36Sopenharmony_ci		m = NULL;
72162306a36Sopenharmony_ci	} else {
72262306a36Sopenharmony_ci		dout("get_generic_reply %lld got %p\n", tid, req->reply);
72362306a36Sopenharmony_ci		*skip = 0;
72462306a36Sopenharmony_ci		m = ceph_msg_get(req->reply);
72562306a36Sopenharmony_ci		/*
72662306a36Sopenharmony_ci		 * we don't need to track the connection reading into
72762306a36Sopenharmony_ci		 * this reply because we only have one open connection
72862306a36Sopenharmony_ci		 * at a time, ever.
72962306a36Sopenharmony_ci		 */
73062306a36Sopenharmony_ci	}
73162306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
73262306a36Sopenharmony_ci	return m;
73362306a36Sopenharmony_ci}
73462306a36Sopenharmony_ci
73562306a36Sopenharmony_ci/*
73662306a36Sopenharmony_ci * statfs
73762306a36Sopenharmony_ci */
73862306a36Sopenharmony_cistatic void handle_statfs_reply(struct ceph_mon_client *monc,
73962306a36Sopenharmony_ci				struct ceph_msg *msg)
74062306a36Sopenharmony_ci{
74162306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
74262306a36Sopenharmony_ci	struct ceph_mon_statfs_reply *reply = msg->front.iov_base;
74362306a36Sopenharmony_ci	u64 tid = le64_to_cpu(msg->hdr.tid);
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	dout("%s msg %p tid %llu\n", __func__, msg, tid);
74662306a36Sopenharmony_ci
74762306a36Sopenharmony_ci	if (msg->front.iov_len != sizeof(*reply))
74862306a36Sopenharmony_ci		goto bad;
74962306a36Sopenharmony_ci
75062306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
75162306a36Sopenharmony_ci	req = lookup_generic_request(&monc->generic_request_tree, tid);
75262306a36Sopenharmony_ci	if (!req) {
75362306a36Sopenharmony_ci		mutex_unlock(&monc->mutex);
75462306a36Sopenharmony_ci		return;
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	req->result = 0;
75862306a36Sopenharmony_ci	*req->u.st = reply->st; /* struct */
75962306a36Sopenharmony_ci	__finish_generic_request(req);
76062306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
76162306a36Sopenharmony_ci
76262306a36Sopenharmony_ci	complete_generic_request(req);
76362306a36Sopenharmony_ci	return;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_cibad:
76662306a36Sopenharmony_ci	pr_err("corrupt statfs reply, tid %llu\n", tid);
76762306a36Sopenharmony_ci	ceph_msg_dump(msg);
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_ci/*
77162306a36Sopenharmony_ci * Do a synchronous statfs().
77262306a36Sopenharmony_ci */
77362306a36Sopenharmony_ciint ceph_monc_do_statfs(struct ceph_mon_client *monc, u64 data_pool,
77462306a36Sopenharmony_ci			struct ceph_statfs *buf)
77562306a36Sopenharmony_ci{
77662306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
77762306a36Sopenharmony_ci	struct ceph_mon_statfs *h;
77862306a36Sopenharmony_ci	int ret = -ENOMEM;
77962306a36Sopenharmony_ci
78062306a36Sopenharmony_ci	req = alloc_generic_request(monc, GFP_NOFS);
78162306a36Sopenharmony_ci	if (!req)
78262306a36Sopenharmony_ci		goto out;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	req->request = ceph_msg_new(CEPH_MSG_STATFS, sizeof(*h), GFP_NOFS,
78562306a36Sopenharmony_ci				    true);
78662306a36Sopenharmony_ci	if (!req->request)
78762306a36Sopenharmony_ci		goto out;
78862306a36Sopenharmony_ci
78962306a36Sopenharmony_ci	req->reply = ceph_msg_new(CEPH_MSG_STATFS_REPLY, 64, GFP_NOFS, true);
79062306a36Sopenharmony_ci	if (!req->reply)
79162306a36Sopenharmony_ci		goto out;
79262306a36Sopenharmony_ci
79362306a36Sopenharmony_ci	req->u.st = buf;
79462306a36Sopenharmony_ci	req->request->hdr.version = cpu_to_le16(2);
79562306a36Sopenharmony_ci
79662306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
79762306a36Sopenharmony_ci	register_generic_request(req);
79862306a36Sopenharmony_ci	/* fill out request */
79962306a36Sopenharmony_ci	h = req->request->front.iov_base;
80062306a36Sopenharmony_ci	h->monhdr.have_version = 0;
80162306a36Sopenharmony_ci	h->monhdr.session_mon = cpu_to_le16(-1);
80262306a36Sopenharmony_ci	h->monhdr.session_mon_tid = 0;
80362306a36Sopenharmony_ci	h->fsid = monc->monmap->fsid;
80462306a36Sopenharmony_ci	h->contains_data_pool = (data_pool != CEPH_NOPOOL);
80562306a36Sopenharmony_ci	h->data_pool = cpu_to_le64(data_pool);
80662306a36Sopenharmony_ci	send_generic_request(monc, req);
80762306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
80862306a36Sopenharmony_ci
80962306a36Sopenharmony_ci	ret = wait_generic_request(req);
81062306a36Sopenharmony_ciout:
81162306a36Sopenharmony_ci	put_generic_request(req);
81262306a36Sopenharmony_ci	return ret;
81362306a36Sopenharmony_ci}
81462306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_do_statfs);
81562306a36Sopenharmony_ci
81662306a36Sopenharmony_cistatic void handle_get_version_reply(struct ceph_mon_client *monc,
81762306a36Sopenharmony_ci				     struct ceph_msg *msg)
81862306a36Sopenharmony_ci{
81962306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
82062306a36Sopenharmony_ci	u64 tid = le64_to_cpu(msg->hdr.tid);
82162306a36Sopenharmony_ci	void *p = msg->front.iov_base;
82262306a36Sopenharmony_ci	void *end = p + msg->front_alloc_len;
82362306a36Sopenharmony_ci	u64 handle;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	dout("%s msg %p tid %llu\n", __func__, msg, tid);
82662306a36Sopenharmony_ci
82762306a36Sopenharmony_ci	ceph_decode_need(&p, end, 2*sizeof(u64), bad);
82862306a36Sopenharmony_ci	handle = ceph_decode_64(&p);
82962306a36Sopenharmony_ci	if (tid != 0 && tid != handle)
83062306a36Sopenharmony_ci		goto bad;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
83362306a36Sopenharmony_ci	req = lookup_generic_request(&monc->generic_request_tree, handle);
83462306a36Sopenharmony_ci	if (!req) {
83562306a36Sopenharmony_ci		mutex_unlock(&monc->mutex);
83662306a36Sopenharmony_ci		return;
83762306a36Sopenharmony_ci	}
83862306a36Sopenharmony_ci
83962306a36Sopenharmony_ci	req->result = 0;
84062306a36Sopenharmony_ci	req->u.newest = ceph_decode_64(&p);
84162306a36Sopenharmony_ci	__finish_generic_request(req);
84262306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
84362306a36Sopenharmony_ci
84462306a36Sopenharmony_ci	complete_generic_request(req);
84562306a36Sopenharmony_ci	return;
84662306a36Sopenharmony_ci
84762306a36Sopenharmony_cibad:
84862306a36Sopenharmony_ci	pr_err("corrupt mon_get_version reply, tid %llu\n", tid);
84962306a36Sopenharmony_ci	ceph_msg_dump(msg);
85062306a36Sopenharmony_ci}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_cistatic struct ceph_mon_generic_request *
85362306a36Sopenharmony_ci__ceph_monc_get_version(struct ceph_mon_client *monc, const char *what,
85462306a36Sopenharmony_ci			ceph_monc_callback_t cb, u64 private_data)
85562306a36Sopenharmony_ci{
85662306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	req = alloc_generic_request(monc, GFP_NOIO);
85962306a36Sopenharmony_ci	if (!req)
86062306a36Sopenharmony_ci		goto err_put_req;
86162306a36Sopenharmony_ci
86262306a36Sopenharmony_ci	req->request = ceph_msg_new(CEPH_MSG_MON_GET_VERSION,
86362306a36Sopenharmony_ci				    sizeof(u64) + sizeof(u32) + strlen(what),
86462306a36Sopenharmony_ci				    GFP_NOIO, true);
86562306a36Sopenharmony_ci	if (!req->request)
86662306a36Sopenharmony_ci		goto err_put_req;
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	req->reply = ceph_msg_new(CEPH_MSG_MON_GET_VERSION_REPLY, 32, GFP_NOIO,
86962306a36Sopenharmony_ci				  true);
87062306a36Sopenharmony_ci	if (!req->reply)
87162306a36Sopenharmony_ci		goto err_put_req;
87262306a36Sopenharmony_ci
87362306a36Sopenharmony_ci	req->complete_cb = cb;
87462306a36Sopenharmony_ci	req->private_data = private_data;
87562306a36Sopenharmony_ci
87662306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
87762306a36Sopenharmony_ci	register_generic_request(req);
87862306a36Sopenharmony_ci	{
87962306a36Sopenharmony_ci		void *p = req->request->front.iov_base;
88062306a36Sopenharmony_ci		void *const end = p + req->request->front_alloc_len;
88162306a36Sopenharmony_ci
88262306a36Sopenharmony_ci		ceph_encode_64(&p, req->tid); /* handle */
88362306a36Sopenharmony_ci		ceph_encode_string(&p, end, what, strlen(what));
88462306a36Sopenharmony_ci		WARN_ON(p != end);
88562306a36Sopenharmony_ci	}
88662306a36Sopenharmony_ci	send_generic_request(monc, req);
88762306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
88862306a36Sopenharmony_ci
88962306a36Sopenharmony_ci	return req;
89062306a36Sopenharmony_ci
89162306a36Sopenharmony_cierr_put_req:
89262306a36Sopenharmony_ci	put_generic_request(req);
89362306a36Sopenharmony_ci	return ERR_PTR(-ENOMEM);
89462306a36Sopenharmony_ci}
89562306a36Sopenharmony_ci
89662306a36Sopenharmony_ci/*
89762306a36Sopenharmony_ci * Send MMonGetVersion and wait for the reply.
89862306a36Sopenharmony_ci *
89962306a36Sopenharmony_ci * @what: one of "mdsmap", "osdmap" or "monmap"
90062306a36Sopenharmony_ci */
90162306a36Sopenharmony_ciint ceph_monc_get_version(struct ceph_mon_client *monc, const char *what,
90262306a36Sopenharmony_ci			  u64 *newest)
90362306a36Sopenharmony_ci{
90462306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
90562306a36Sopenharmony_ci	int ret;
90662306a36Sopenharmony_ci
90762306a36Sopenharmony_ci	req = __ceph_monc_get_version(monc, what, NULL, 0);
90862306a36Sopenharmony_ci	if (IS_ERR(req))
90962306a36Sopenharmony_ci		return PTR_ERR(req);
91062306a36Sopenharmony_ci
91162306a36Sopenharmony_ci	ret = wait_generic_request(req);
91262306a36Sopenharmony_ci	if (!ret)
91362306a36Sopenharmony_ci		*newest = req->u.newest;
91462306a36Sopenharmony_ci
91562306a36Sopenharmony_ci	put_generic_request(req);
91662306a36Sopenharmony_ci	return ret;
91762306a36Sopenharmony_ci}
91862306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_get_version);
91962306a36Sopenharmony_ci
92062306a36Sopenharmony_ci/*
92162306a36Sopenharmony_ci * Send MMonGetVersion,
92262306a36Sopenharmony_ci *
92362306a36Sopenharmony_ci * @what: one of "mdsmap", "osdmap" or "monmap"
92462306a36Sopenharmony_ci */
92562306a36Sopenharmony_ciint ceph_monc_get_version_async(struct ceph_mon_client *monc, const char *what,
92662306a36Sopenharmony_ci				ceph_monc_callback_t cb, u64 private_data)
92762306a36Sopenharmony_ci{
92862306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
92962306a36Sopenharmony_ci
93062306a36Sopenharmony_ci	req = __ceph_monc_get_version(monc, what, cb, private_data);
93162306a36Sopenharmony_ci	if (IS_ERR(req))
93262306a36Sopenharmony_ci		return PTR_ERR(req);
93362306a36Sopenharmony_ci
93462306a36Sopenharmony_ci	put_generic_request(req);
93562306a36Sopenharmony_ci	return 0;
93662306a36Sopenharmony_ci}
93762306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_get_version_async);
93862306a36Sopenharmony_ci
93962306a36Sopenharmony_cistatic void handle_command_ack(struct ceph_mon_client *monc,
94062306a36Sopenharmony_ci			       struct ceph_msg *msg)
94162306a36Sopenharmony_ci{
94262306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
94362306a36Sopenharmony_ci	void *p = msg->front.iov_base;
94462306a36Sopenharmony_ci	void *const end = p + msg->front_alloc_len;
94562306a36Sopenharmony_ci	u64 tid = le64_to_cpu(msg->hdr.tid);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	dout("%s msg %p tid %llu\n", __func__, msg, tid);
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ci	ceph_decode_need(&p, end, sizeof(struct ceph_mon_request_header) +
95062306a36Sopenharmony_ci							    sizeof(u32), bad);
95162306a36Sopenharmony_ci	p += sizeof(struct ceph_mon_request_header);
95262306a36Sopenharmony_ci
95362306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
95462306a36Sopenharmony_ci	req = lookup_generic_request(&monc->generic_request_tree, tid);
95562306a36Sopenharmony_ci	if (!req) {
95662306a36Sopenharmony_ci		mutex_unlock(&monc->mutex);
95762306a36Sopenharmony_ci		return;
95862306a36Sopenharmony_ci	}
95962306a36Sopenharmony_ci
96062306a36Sopenharmony_ci	req->result = ceph_decode_32(&p);
96162306a36Sopenharmony_ci	__finish_generic_request(req);
96262306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	complete_generic_request(req);
96562306a36Sopenharmony_ci	return;
96662306a36Sopenharmony_ci
96762306a36Sopenharmony_cibad:
96862306a36Sopenharmony_ci	pr_err("corrupt mon_command ack, tid %llu\n", tid);
96962306a36Sopenharmony_ci	ceph_msg_dump(msg);
97062306a36Sopenharmony_ci}
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_cistatic __printf(2, 0)
97362306a36Sopenharmony_ciint do_mon_command_vargs(struct ceph_mon_client *monc, const char *fmt,
97462306a36Sopenharmony_ci			 va_list ap)
97562306a36Sopenharmony_ci{
97662306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
97762306a36Sopenharmony_ci	struct ceph_mon_command *h;
97862306a36Sopenharmony_ci	int ret = -ENOMEM;
97962306a36Sopenharmony_ci	int len;
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	req = alloc_generic_request(monc, GFP_NOIO);
98262306a36Sopenharmony_ci	if (!req)
98362306a36Sopenharmony_ci		goto out;
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	req->request = ceph_msg_new(CEPH_MSG_MON_COMMAND, 256, GFP_NOIO, true);
98662306a36Sopenharmony_ci	if (!req->request)
98762306a36Sopenharmony_ci		goto out;
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_ci	req->reply = ceph_msg_new(CEPH_MSG_MON_COMMAND_ACK, 512, GFP_NOIO,
99062306a36Sopenharmony_ci				  true);
99162306a36Sopenharmony_ci	if (!req->reply)
99262306a36Sopenharmony_ci		goto out;
99362306a36Sopenharmony_ci
99462306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
99562306a36Sopenharmony_ci	register_generic_request(req);
99662306a36Sopenharmony_ci	h = req->request->front.iov_base;
99762306a36Sopenharmony_ci	h->monhdr.have_version = 0;
99862306a36Sopenharmony_ci	h->monhdr.session_mon = cpu_to_le16(-1);
99962306a36Sopenharmony_ci	h->monhdr.session_mon_tid = 0;
100062306a36Sopenharmony_ci	h->fsid = monc->monmap->fsid;
100162306a36Sopenharmony_ci	h->num_strs = cpu_to_le32(1);
100262306a36Sopenharmony_ci	len = vsprintf(h->str, fmt, ap);
100362306a36Sopenharmony_ci	h->str_len = cpu_to_le32(len);
100462306a36Sopenharmony_ci	send_generic_request(monc, req);
100562306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
100662306a36Sopenharmony_ci
100762306a36Sopenharmony_ci	ret = wait_generic_request(req);
100862306a36Sopenharmony_ciout:
100962306a36Sopenharmony_ci	put_generic_request(req);
101062306a36Sopenharmony_ci	return ret;
101162306a36Sopenharmony_ci}
101262306a36Sopenharmony_ci
101362306a36Sopenharmony_cistatic __printf(2, 3)
101462306a36Sopenharmony_ciint do_mon_command(struct ceph_mon_client *monc, const char *fmt, ...)
101562306a36Sopenharmony_ci{
101662306a36Sopenharmony_ci	va_list ap;
101762306a36Sopenharmony_ci	int ret;
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_ci	va_start(ap, fmt);
102062306a36Sopenharmony_ci	ret = do_mon_command_vargs(monc, fmt, ap);
102162306a36Sopenharmony_ci	va_end(ap);
102262306a36Sopenharmony_ci	return ret;
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ciint ceph_monc_blocklist_add(struct ceph_mon_client *monc,
102662306a36Sopenharmony_ci			    struct ceph_entity_addr *client_addr)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	int ret;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	ret = do_mon_command(monc,
103162306a36Sopenharmony_ci			     "{ \"prefix\": \"osd blocklist\", \
103262306a36Sopenharmony_ci				\"blocklistop\": \"add\", \
103362306a36Sopenharmony_ci				\"addr\": \"%pISpc/%u\" }",
103462306a36Sopenharmony_ci			     &client_addr->in_addr,
103562306a36Sopenharmony_ci			     le32_to_cpu(client_addr->nonce));
103662306a36Sopenharmony_ci	if (ret == -EINVAL) {
103762306a36Sopenharmony_ci		/*
103862306a36Sopenharmony_ci		 * The monitor returns EINVAL on an unrecognized command.
103962306a36Sopenharmony_ci		 * Try the legacy command -- it is exactly the same except
104062306a36Sopenharmony_ci		 * for the name.
104162306a36Sopenharmony_ci		 */
104262306a36Sopenharmony_ci		ret = do_mon_command(monc,
104362306a36Sopenharmony_ci				     "{ \"prefix\": \"osd blacklist\", \
104462306a36Sopenharmony_ci					\"blacklistop\": \"add\", \
104562306a36Sopenharmony_ci					\"addr\": \"%pISpc/%u\" }",
104662306a36Sopenharmony_ci				     &client_addr->in_addr,
104762306a36Sopenharmony_ci				     le32_to_cpu(client_addr->nonce));
104862306a36Sopenharmony_ci	}
104962306a36Sopenharmony_ci	if (ret)
105062306a36Sopenharmony_ci		return ret;
105162306a36Sopenharmony_ci
105262306a36Sopenharmony_ci	/*
105362306a36Sopenharmony_ci	 * Make sure we have the osdmap that includes the blocklist
105462306a36Sopenharmony_ci	 * entry.  This is needed to ensure that the OSDs pick up the
105562306a36Sopenharmony_ci	 * new blocklist before processing any future requests from
105662306a36Sopenharmony_ci	 * this client.
105762306a36Sopenharmony_ci	 */
105862306a36Sopenharmony_ci	return ceph_wait_for_latest_osdmap(monc->client, 0);
105962306a36Sopenharmony_ci}
106062306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_blocklist_add);
106162306a36Sopenharmony_ci
106262306a36Sopenharmony_ci/*
106362306a36Sopenharmony_ci * Resend pending generic requests.
106462306a36Sopenharmony_ci */
106562306a36Sopenharmony_cistatic void __resend_generic_request(struct ceph_mon_client *monc)
106662306a36Sopenharmony_ci{
106762306a36Sopenharmony_ci	struct ceph_mon_generic_request *req;
106862306a36Sopenharmony_ci	struct rb_node *p;
106962306a36Sopenharmony_ci
107062306a36Sopenharmony_ci	for (p = rb_first(&monc->generic_request_tree); p; p = rb_next(p)) {
107162306a36Sopenharmony_ci		req = rb_entry(p, struct ceph_mon_generic_request, node);
107262306a36Sopenharmony_ci		ceph_msg_revoke(req->request);
107362306a36Sopenharmony_ci		ceph_msg_revoke_incoming(req->reply);
107462306a36Sopenharmony_ci		ceph_con_send(&monc->con, ceph_msg_get(req->request));
107562306a36Sopenharmony_ci	}
107662306a36Sopenharmony_ci}
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci/*
107962306a36Sopenharmony_ci * Delayed work.  If we haven't mounted yet, retry.  Otherwise,
108062306a36Sopenharmony_ci * renew/retry subscription as needed (in case it is timing out, or we
108162306a36Sopenharmony_ci * got an ENOMEM).  And keep the monitor connection alive.
108262306a36Sopenharmony_ci */
108362306a36Sopenharmony_cistatic void delayed_work(struct work_struct *work)
108462306a36Sopenharmony_ci{
108562306a36Sopenharmony_ci	struct ceph_mon_client *monc =
108662306a36Sopenharmony_ci		container_of(work, struct ceph_mon_client, delayed_work.work);
108762306a36Sopenharmony_ci
108862306a36Sopenharmony_ci	dout("monc delayed_work\n");
108962306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
109062306a36Sopenharmony_ci	if (monc->hunting) {
109162306a36Sopenharmony_ci		dout("%s continuing hunt\n", __func__);
109262306a36Sopenharmony_ci		reopen_session(monc);
109362306a36Sopenharmony_ci	} else {
109462306a36Sopenharmony_ci		int is_auth = ceph_auth_is_authenticated(monc->auth);
109562306a36Sopenharmony_ci		if (ceph_con_keepalive_expired(&monc->con,
109662306a36Sopenharmony_ci					       CEPH_MONC_PING_TIMEOUT)) {
109762306a36Sopenharmony_ci			dout("monc keepalive timeout\n");
109862306a36Sopenharmony_ci			is_auth = 0;
109962306a36Sopenharmony_ci			reopen_session(monc);
110062306a36Sopenharmony_ci		}
110162306a36Sopenharmony_ci
110262306a36Sopenharmony_ci		if (!monc->hunting) {
110362306a36Sopenharmony_ci			ceph_con_keepalive(&monc->con);
110462306a36Sopenharmony_ci			__validate_auth(monc);
110562306a36Sopenharmony_ci			un_backoff(monc);
110662306a36Sopenharmony_ci		}
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci		if (is_auth &&
110962306a36Sopenharmony_ci		    !(monc->con.peer_features & CEPH_FEATURE_MON_STATEFUL_SUB)) {
111062306a36Sopenharmony_ci			unsigned long now = jiffies;
111162306a36Sopenharmony_ci
111262306a36Sopenharmony_ci			dout("%s renew subs? now %lu renew after %lu\n",
111362306a36Sopenharmony_ci			     __func__, now, monc->sub_renew_after);
111462306a36Sopenharmony_ci			if (time_after_eq(now, monc->sub_renew_after))
111562306a36Sopenharmony_ci				__send_subscribe(monc);
111662306a36Sopenharmony_ci		}
111762306a36Sopenharmony_ci	}
111862306a36Sopenharmony_ci	__schedule_delayed(monc);
111962306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
112062306a36Sopenharmony_ci}
112162306a36Sopenharmony_ci
112262306a36Sopenharmony_ci/*
112362306a36Sopenharmony_ci * On startup, we build a temporary monmap populated with the IPs
112462306a36Sopenharmony_ci * provided by mount(2).
112562306a36Sopenharmony_ci */
112662306a36Sopenharmony_cistatic int build_initial_monmap(struct ceph_mon_client *monc)
112762306a36Sopenharmony_ci{
112862306a36Sopenharmony_ci	__le32 my_type = ceph_msgr2(monc->client) ?
112962306a36Sopenharmony_ci		CEPH_ENTITY_ADDR_TYPE_MSGR2 : CEPH_ENTITY_ADDR_TYPE_LEGACY;
113062306a36Sopenharmony_ci	struct ceph_options *opt = monc->client->options;
113162306a36Sopenharmony_ci	int num_mon = opt->num_mon;
113262306a36Sopenharmony_ci	int i;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	/* build initial monmap */
113562306a36Sopenharmony_ci	monc->monmap = kzalloc(struct_size(monc->monmap, mon_inst, num_mon),
113662306a36Sopenharmony_ci			       GFP_KERNEL);
113762306a36Sopenharmony_ci	if (!monc->monmap)
113862306a36Sopenharmony_ci		return -ENOMEM;
113962306a36Sopenharmony_ci
114062306a36Sopenharmony_ci	for (i = 0; i < num_mon; i++) {
114162306a36Sopenharmony_ci		struct ceph_entity_inst *inst = &monc->monmap->mon_inst[i];
114262306a36Sopenharmony_ci
114362306a36Sopenharmony_ci		memcpy(&inst->addr.in_addr, &opt->mon_addr[i].in_addr,
114462306a36Sopenharmony_ci		       sizeof(inst->addr.in_addr));
114562306a36Sopenharmony_ci		inst->addr.type = my_type;
114662306a36Sopenharmony_ci		inst->addr.nonce = 0;
114762306a36Sopenharmony_ci		inst->name.type = CEPH_ENTITY_TYPE_MON;
114862306a36Sopenharmony_ci		inst->name.num = cpu_to_le64(i);
114962306a36Sopenharmony_ci	}
115062306a36Sopenharmony_ci	monc->monmap->num_mon = num_mon;
115162306a36Sopenharmony_ci	return 0;
115262306a36Sopenharmony_ci}
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ciint ceph_monc_init(struct ceph_mon_client *monc, struct ceph_client *cl)
115562306a36Sopenharmony_ci{
115662306a36Sopenharmony_ci	int err;
115762306a36Sopenharmony_ci
115862306a36Sopenharmony_ci	dout("init\n");
115962306a36Sopenharmony_ci	memset(monc, 0, sizeof(*monc));
116062306a36Sopenharmony_ci	monc->client = cl;
116162306a36Sopenharmony_ci	mutex_init(&monc->mutex);
116262306a36Sopenharmony_ci
116362306a36Sopenharmony_ci	err = build_initial_monmap(monc);
116462306a36Sopenharmony_ci	if (err)
116562306a36Sopenharmony_ci		goto out;
116662306a36Sopenharmony_ci
116762306a36Sopenharmony_ci	/* connection */
116862306a36Sopenharmony_ci	/* authentication */
116962306a36Sopenharmony_ci	monc->auth = ceph_auth_init(cl->options->name, cl->options->key,
117062306a36Sopenharmony_ci				    cl->options->con_modes);
117162306a36Sopenharmony_ci	if (IS_ERR(monc->auth)) {
117262306a36Sopenharmony_ci		err = PTR_ERR(monc->auth);
117362306a36Sopenharmony_ci		goto out_monmap;
117462306a36Sopenharmony_ci	}
117562306a36Sopenharmony_ci	monc->auth->want_keys =
117662306a36Sopenharmony_ci		CEPH_ENTITY_TYPE_AUTH | CEPH_ENTITY_TYPE_MON |
117762306a36Sopenharmony_ci		CEPH_ENTITY_TYPE_OSD | CEPH_ENTITY_TYPE_MDS;
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	/* msgs */
118062306a36Sopenharmony_ci	err = -ENOMEM;
118162306a36Sopenharmony_ci	monc->m_subscribe_ack = ceph_msg_new(CEPH_MSG_MON_SUBSCRIBE_ACK,
118262306a36Sopenharmony_ci				     sizeof(struct ceph_mon_subscribe_ack),
118362306a36Sopenharmony_ci				     GFP_KERNEL, true);
118462306a36Sopenharmony_ci	if (!monc->m_subscribe_ack)
118562306a36Sopenharmony_ci		goto out_auth;
118662306a36Sopenharmony_ci
118762306a36Sopenharmony_ci	monc->m_subscribe = ceph_msg_new(CEPH_MSG_MON_SUBSCRIBE, 128,
118862306a36Sopenharmony_ci					 GFP_KERNEL, true);
118962306a36Sopenharmony_ci	if (!monc->m_subscribe)
119062306a36Sopenharmony_ci		goto out_subscribe_ack;
119162306a36Sopenharmony_ci
119262306a36Sopenharmony_ci	monc->m_auth_reply = ceph_msg_new(CEPH_MSG_AUTH_REPLY, 4096,
119362306a36Sopenharmony_ci					  GFP_KERNEL, true);
119462306a36Sopenharmony_ci	if (!monc->m_auth_reply)
119562306a36Sopenharmony_ci		goto out_subscribe;
119662306a36Sopenharmony_ci
119762306a36Sopenharmony_ci	monc->m_auth = ceph_msg_new(CEPH_MSG_AUTH, 4096, GFP_KERNEL, true);
119862306a36Sopenharmony_ci	monc->pending_auth = 0;
119962306a36Sopenharmony_ci	if (!monc->m_auth)
120062306a36Sopenharmony_ci		goto out_auth_reply;
120162306a36Sopenharmony_ci
120262306a36Sopenharmony_ci	ceph_con_init(&monc->con, monc, &mon_con_ops,
120362306a36Sopenharmony_ci		      &monc->client->msgr);
120462306a36Sopenharmony_ci
120562306a36Sopenharmony_ci	monc->cur_mon = -1;
120662306a36Sopenharmony_ci	monc->had_a_connection = false;
120762306a36Sopenharmony_ci	monc->hunt_mult = 1;
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	INIT_DELAYED_WORK(&monc->delayed_work, delayed_work);
121062306a36Sopenharmony_ci	monc->generic_request_tree = RB_ROOT;
121162306a36Sopenharmony_ci	monc->last_tid = 0;
121262306a36Sopenharmony_ci
121362306a36Sopenharmony_ci	monc->fs_cluster_id = CEPH_FS_CLUSTER_ID_NONE;
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_ci	return 0;
121662306a36Sopenharmony_ci
121762306a36Sopenharmony_ciout_auth_reply:
121862306a36Sopenharmony_ci	ceph_msg_put(monc->m_auth_reply);
121962306a36Sopenharmony_ciout_subscribe:
122062306a36Sopenharmony_ci	ceph_msg_put(monc->m_subscribe);
122162306a36Sopenharmony_ciout_subscribe_ack:
122262306a36Sopenharmony_ci	ceph_msg_put(monc->m_subscribe_ack);
122362306a36Sopenharmony_ciout_auth:
122462306a36Sopenharmony_ci	ceph_auth_destroy(monc->auth);
122562306a36Sopenharmony_ciout_monmap:
122662306a36Sopenharmony_ci	kfree(monc->monmap);
122762306a36Sopenharmony_ciout:
122862306a36Sopenharmony_ci	return err;
122962306a36Sopenharmony_ci}
123062306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_init);
123162306a36Sopenharmony_ci
123262306a36Sopenharmony_civoid ceph_monc_stop(struct ceph_mon_client *monc)
123362306a36Sopenharmony_ci{
123462306a36Sopenharmony_ci	dout("stop\n");
123562306a36Sopenharmony_ci	cancel_delayed_work_sync(&monc->delayed_work);
123662306a36Sopenharmony_ci
123762306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
123862306a36Sopenharmony_ci	__close_session(monc);
123962306a36Sopenharmony_ci	monc->cur_mon = -1;
124062306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
124162306a36Sopenharmony_ci
124262306a36Sopenharmony_ci	/*
124362306a36Sopenharmony_ci	 * flush msgr queue before we destroy ourselves to ensure that:
124462306a36Sopenharmony_ci	 *  - any work that references our embedded con is finished.
124562306a36Sopenharmony_ci	 *  - any osd_client or other work that may reference an authorizer
124662306a36Sopenharmony_ci	 *    finishes before we shut down the auth subsystem.
124762306a36Sopenharmony_ci	 */
124862306a36Sopenharmony_ci	ceph_msgr_flush();
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	ceph_auth_destroy(monc->auth);
125162306a36Sopenharmony_ci
125262306a36Sopenharmony_ci	WARN_ON(!RB_EMPTY_ROOT(&monc->generic_request_tree));
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	ceph_msg_put(monc->m_auth);
125562306a36Sopenharmony_ci	ceph_msg_put(monc->m_auth_reply);
125662306a36Sopenharmony_ci	ceph_msg_put(monc->m_subscribe);
125762306a36Sopenharmony_ci	ceph_msg_put(monc->m_subscribe_ack);
125862306a36Sopenharmony_ci
125962306a36Sopenharmony_ci	kfree(monc->monmap);
126062306a36Sopenharmony_ci}
126162306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_stop);
126262306a36Sopenharmony_ci
126362306a36Sopenharmony_cistatic void finish_hunting(struct ceph_mon_client *monc)
126462306a36Sopenharmony_ci{
126562306a36Sopenharmony_ci	if (monc->hunting) {
126662306a36Sopenharmony_ci		dout("%s found mon%d\n", __func__, monc->cur_mon);
126762306a36Sopenharmony_ci		monc->hunting = false;
126862306a36Sopenharmony_ci		monc->had_a_connection = true;
126962306a36Sopenharmony_ci		un_backoff(monc);
127062306a36Sopenharmony_ci		__schedule_delayed(monc);
127162306a36Sopenharmony_ci	}
127262306a36Sopenharmony_ci}
127362306a36Sopenharmony_ci
127462306a36Sopenharmony_cistatic void finish_auth(struct ceph_mon_client *monc, int auth_err,
127562306a36Sopenharmony_ci			bool was_authed)
127662306a36Sopenharmony_ci{
127762306a36Sopenharmony_ci	dout("%s auth_err %d was_authed %d\n", __func__, auth_err, was_authed);
127862306a36Sopenharmony_ci	WARN_ON(auth_err > 0);
127962306a36Sopenharmony_ci
128062306a36Sopenharmony_ci	monc->pending_auth = 0;
128162306a36Sopenharmony_ci	if (auth_err) {
128262306a36Sopenharmony_ci		monc->client->auth_err = auth_err;
128362306a36Sopenharmony_ci		wake_up_all(&monc->client->auth_wq);
128462306a36Sopenharmony_ci		return;
128562306a36Sopenharmony_ci	}
128662306a36Sopenharmony_ci
128762306a36Sopenharmony_ci	if (!was_authed && ceph_auth_is_authenticated(monc->auth)) {
128862306a36Sopenharmony_ci		dout("%s authenticated, starting session global_id %llu\n",
128962306a36Sopenharmony_ci		     __func__, monc->auth->global_id);
129062306a36Sopenharmony_ci
129162306a36Sopenharmony_ci		monc->client->msgr.inst.name.type = CEPH_ENTITY_TYPE_CLIENT;
129262306a36Sopenharmony_ci		monc->client->msgr.inst.name.num =
129362306a36Sopenharmony_ci					cpu_to_le64(monc->auth->global_id);
129462306a36Sopenharmony_ci
129562306a36Sopenharmony_ci		__send_subscribe(monc);
129662306a36Sopenharmony_ci		__resend_generic_request(monc);
129762306a36Sopenharmony_ci
129862306a36Sopenharmony_ci		pr_info("mon%d %s session established\n", monc->cur_mon,
129962306a36Sopenharmony_ci			ceph_pr_addr(&monc->con.peer_addr));
130062306a36Sopenharmony_ci	}
130162306a36Sopenharmony_ci}
130262306a36Sopenharmony_ci
130362306a36Sopenharmony_cistatic void handle_auth_reply(struct ceph_mon_client *monc,
130462306a36Sopenharmony_ci			      struct ceph_msg *msg)
130562306a36Sopenharmony_ci{
130662306a36Sopenharmony_ci	bool was_authed;
130762306a36Sopenharmony_ci	int ret;
130862306a36Sopenharmony_ci
130962306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
131062306a36Sopenharmony_ci	was_authed = ceph_auth_is_authenticated(monc->auth);
131162306a36Sopenharmony_ci	ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base,
131262306a36Sopenharmony_ci				     msg->front.iov_len,
131362306a36Sopenharmony_ci				     monc->m_auth->front.iov_base,
131462306a36Sopenharmony_ci				     monc->m_auth->front_alloc_len);
131562306a36Sopenharmony_ci	if (ret > 0) {
131662306a36Sopenharmony_ci		__send_prepared_auth_request(monc, ret);
131762306a36Sopenharmony_ci	} else {
131862306a36Sopenharmony_ci		finish_auth(monc, ret, was_authed);
131962306a36Sopenharmony_ci		finish_hunting(monc);
132062306a36Sopenharmony_ci	}
132162306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
132262306a36Sopenharmony_ci}
132362306a36Sopenharmony_ci
132462306a36Sopenharmony_cistatic int __validate_auth(struct ceph_mon_client *monc)
132562306a36Sopenharmony_ci{
132662306a36Sopenharmony_ci	int ret;
132762306a36Sopenharmony_ci
132862306a36Sopenharmony_ci	if (monc->pending_auth)
132962306a36Sopenharmony_ci		return 0;
133062306a36Sopenharmony_ci
133162306a36Sopenharmony_ci	ret = ceph_build_auth(monc->auth, monc->m_auth->front.iov_base,
133262306a36Sopenharmony_ci			      monc->m_auth->front_alloc_len);
133362306a36Sopenharmony_ci	if (ret <= 0)
133462306a36Sopenharmony_ci		return ret; /* either an error, or no need to authenticate */
133562306a36Sopenharmony_ci	__send_prepared_auth_request(monc, ret);
133662306a36Sopenharmony_ci	return 0;
133762306a36Sopenharmony_ci}
133862306a36Sopenharmony_ci
133962306a36Sopenharmony_ciint ceph_monc_validate_auth(struct ceph_mon_client *monc)
134062306a36Sopenharmony_ci{
134162306a36Sopenharmony_ci	int ret;
134262306a36Sopenharmony_ci
134362306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
134462306a36Sopenharmony_ci	ret = __validate_auth(monc);
134562306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
134662306a36Sopenharmony_ci	return ret;
134762306a36Sopenharmony_ci}
134862306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_monc_validate_auth);
134962306a36Sopenharmony_ci
135062306a36Sopenharmony_cistatic int mon_get_auth_request(struct ceph_connection *con,
135162306a36Sopenharmony_ci				void *buf, int *buf_len,
135262306a36Sopenharmony_ci				void **authorizer, int *authorizer_len)
135362306a36Sopenharmony_ci{
135462306a36Sopenharmony_ci	struct ceph_mon_client *monc = con->private;
135562306a36Sopenharmony_ci	int ret;
135662306a36Sopenharmony_ci
135762306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
135862306a36Sopenharmony_ci	ret = ceph_auth_get_request(monc->auth, buf, *buf_len);
135962306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
136062306a36Sopenharmony_ci	if (ret < 0)
136162306a36Sopenharmony_ci		return ret;
136262306a36Sopenharmony_ci
136362306a36Sopenharmony_ci	*buf_len = ret;
136462306a36Sopenharmony_ci	*authorizer = NULL;
136562306a36Sopenharmony_ci	*authorizer_len = 0;
136662306a36Sopenharmony_ci	return 0;
136762306a36Sopenharmony_ci}
136862306a36Sopenharmony_ci
136962306a36Sopenharmony_cistatic int mon_handle_auth_reply_more(struct ceph_connection *con,
137062306a36Sopenharmony_ci				      void *reply, int reply_len,
137162306a36Sopenharmony_ci				      void *buf, int *buf_len,
137262306a36Sopenharmony_ci				      void **authorizer, int *authorizer_len)
137362306a36Sopenharmony_ci{
137462306a36Sopenharmony_ci	struct ceph_mon_client *monc = con->private;
137562306a36Sopenharmony_ci	int ret;
137662306a36Sopenharmony_ci
137762306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
137862306a36Sopenharmony_ci	ret = ceph_auth_handle_reply_more(monc->auth, reply, reply_len,
137962306a36Sopenharmony_ci					  buf, *buf_len);
138062306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
138162306a36Sopenharmony_ci	if (ret < 0)
138262306a36Sopenharmony_ci		return ret;
138362306a36Sopenharmony_ci
138462306a36Sopenharmony_ci	*buf_len = ret;
138562306a36Sopenharmony_ci	*authorizer = NULL;
138662306a36Sopenharmony_ci	*authorizer_len = 0;
138762306a36Sopenharmony_ci	return 0;
138862306a36Sopenharmony_ci}
138962306a36Sopenharmony_ci
139062306a36Sopenharmony_cistatic int mon_handle_auth_done(struct ceph_connection *con,
139162306a36Sopenharmony_ci				u64 global_id, void *reply, int reply_len,
139262306a36Sopenharmony_ci				u8 *session_key, int *session_key_len,
139362306a36Sopenharmony_ci				u8 *con_secret, int *con_secret_len)
139462306a36Sopenharmony_ci{
139562306a36Sopenharmony_ci	struct ceph_mon_client *monc = con->private;
139662306a36Sopenharmony_ci	bool was_authed;
139762306a36Sopenharmony_ci	int ret;
139862306a36Sopenharmony_ci
139962306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
140062306a36Sopenharmony_ci	WARN_ON(!monc->hunting);
140162306a36Sopenharmony_ci	was_authed = ceph_auth_is_authenticated(monc->auth);
140262306a36Sopenharmony_ci	ret = ceph_auth_handle_reply_done(monc->auth, global_id,
140362306a36Sopenharmony_ci					  reply, reply_len,
140462306a36Sopenharmony_ci					  session_key, session_key_len,
140562306a36Sopenharmony_ci					  con_secret, con_secret_len);
140662306a36Sopenharmony_ci	finish_auth(monc, ret, was_authed);
140762306a36Sopenharmony_ci	if (!ret)
140862306a36Sopenharmony_ci		finish_hunting(monc);
140962306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
141062306a36Sopenharmony_ci	return 0;
141162306a36Sopenharmony_ci}
141262306a36Sopenharmony_ci
141362306a36Sopenharmony_cistatic int mon_handle_auth_bad_method(struct ceph_connection *con,
141462306a36Sopenharmony_ci				      int used_proto, int result,
141562306a36Sopenharmony_ci				      const int *allowed_protos, int proto_cnt,
141662306a36Sopenharmony_ci				      const int *allowed_modes, int mode_cnt)
141762306a36Sopenharmony_ci{
141862306a36Sopenharmony_ci	struct ceph_mon_client *monc = con->private;
141962306a36Sopenharmony_ci	bool was_authed;
142062306a36Sopenharmony_ci
142162306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
142262306a36Sopenharmony_ci	WARN_ON(!monc->hunting);
142362306a36Sopenharmony_ci	was_authed = ceph_auth_is_authenticated(monc->auth);
142462306a36Sopenharmony_ci	ceph_auth_handle_bad_method(monc->auth, used_proto, result,
142562306a36Sopenharmony_ci				    allowed_protos, proto_cnt,
142662306a36Sopenharmony_ci				    allowed_modes, mode_cnt);
142762306a36Sopenharmony_ci	finish_auth(monc, -EACCES, was_authed);
142862306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
142962306a36Sopenharmony_ci	return 0;
143062306a36Sopenharmony_ci}
143162306a36Sopenharmony_ci
143262306a36Sopenharmony_ci/*
143362306a36Sopenharmony_ci * handle incoming message
143462306a36Sopenharmony_ci */
143562306a36Sopenharmony_cistatic void mon_dispatch(struct ceph_connection *con, struct ceph_msg *msg)
143662306a36Sopenharmony_ci{
143762306a36Sopenharmony_ci	struct ceph_mon_client *monc = con->private;
143862306a36Sopenharmony_ci	int type = le16_to_cpu(msg->hdr.type);
143962306a36Sopenharmony_ci
144062306a36Sopenharmony_ci	switch (type) {
144162306a36Sopenharmony_ci	case CEPH_MSG_AUTH_REPLY:
144262306a36Sopenharmony_ci		handle_auth_reply(monc, msg);
144362306a36Sopenharmony_ci		break;
144462306a36Sopenharmony_ci
144562306a36Sopenharmony_ci	case CEPH_MSG_MON_SUBSCRIBE_ACK:
144662306a36Sopenharmony_ci		handle_subscribe_ack(monc, msg);
144762306a36Sopenharmony_ci		break;
144862306a36Sopenharmony_ci
144962306a36Sopenharmony_ci	case CEPH_MSG_STATFS_REPLY:
145062306a36Sopenharmony_ci		handle_statfs_reply(monc, msg);
145162306a36Sopenharmony_ci		break;
145262306a36Sopenharmony_ci
145362306a36Sopenharmony_ci	case CEPH_MSG_MON_GET_VERSION_REPLY:
145462306a36Sopenharmony_ci		handle_get_version_reply(monc, msg);
145562306a36Sopenharmony_ci		break;
145662306a36Sopenharmony_ci
145762306a36Sopenharmony_ci	case CEPH_MSG_MON_COMMAND_ACK:
145862306a36Sopenharmony_ci		handle_command_ack(monc, msg);
145962306a36Sopenharmony_ci		break;
146062306a36Sopenharmony_ci
146162306a36Sopenharmony_ci	case CEPH_MSG_MON_MAP:
146262306a36Sopenharmony_ci		ceph_monc_handle_map(monc, msg);
146362306a36Sopenharmony_ci		break;
146462306a36Sopenharmony_ci
146562306a36Sopenharmony_ci	case CEPH_MSG_OSD_MAP:
146662306a36Sopenharmony_ci		ceph_osdc_handle_map(&monc->client->osdc, msg);
146762306a36Sopenharmony_ci		break;
146862306a36Sopenharmony_ci
146962306a36Sopenharmony_ci	default:
147062306a36Sopenharmony_ci		/* can the chained handler handle it? */
147162306a36Sopenharmony_ci		if (monc->client->extra_mon_dispatch &&
147262306a36Sopenharmony_ci		    monc->client->extra_mon_dispatch(monc->client, msg) == 0)
147362306a36Sopenharmony_ci			break;
147462306a36Sopenharmony_ci
147562306a36Sopenharmony_ci		pr_err("received unknown message type %d %s\n", type,
147662306a36Sopenharmony_ci		       ceph_msg_type_name(type));
147762306a36Sopenharmony_ci	}
147862306a36Sopenharmony_ci	ceph_msg_put(msg);
147962306a36Sopenharmony_ci}
148062306a36Sopenharmony_ci
148162306a36Sopenharmony_ci/*
148262306a36Sopenharmony_ci * Allocate memory for incoming message
148362306a36Sopenharmony_ci */
148462306a36Sopenharmony_cistatic struct ceph_msg *mon_alloc_msg(struct ceph_connection *con,
148562306a36Sopenharmony_ci				      struct ceph_msg_header *hdr,
148662306a36Sopenharmony_ci				      int *skip)
148762306a36Sopenharmony_ci{
148862306a36Sopenharmony_ci	struct ceph_mon_client *monc = con->private;
148962306a36Sopenharmony_ci	int type = le16_to_cpu(hdr->type);
149062306a36Sopenharmony_ci	int front_len = le32_to_cpu(hdr->front_len);
149162306a36Sopenharmony_ci	struct ceph_msg *m = NULL;
149262306a36Sopenharmony_ci
149362306a36Sopenharmony_ci	*skip = 0;
149462306a36Sopenharmony_ci
149562306a36Sopenharmony_ci	switch (type) {
149662306a36Sopenharmony_ci	case CEPH_MSG_MON_SUBSCRIBE_ACK:
149762306a36Sopenharmony_ci		m = ceph_msg_get(monc->m_subscribe_ack);
149862306a36Sopenharmony_ci		break;
149962306a36Sopenharmony_ci	case CEPH_MSG_STATFS_REPLY:
150062306a36Sopenharmony_ci	case CEPH_MSG_MON_COMMAND_ACK:
150162306a36Sopenharmony_ci		return get_generic_reply(con, hdr, skip);
150262306a36Sopenharmony_ci	case CEPH_MSG_AUTH_REPLY:
150362306a36Sopenharmony_ci		m = ceph_msg_get(monc->m_auth_reply);
150462306a36Sopenharmony_ci		break;
150562306a36Sopenharmony_ci	case CEPH_MSG_MON_GET_VERSION_REPLY:
150662306a36Sopenharmony_ci		if (le64_to_cpu(hdr->tid) != 0)
150762306a36Sopenharmony_ci			return get_generic_reply(con, hdr, skip);
150862306a36Sopenharmony_ci
150962306a36Sopenharmony_ci		/*
151062306a36Sopenharmony_ci		 * Older OSDs don't set reply tid even if the original
151162306a36Sopenharmony_ci		 * request had a non-zero tid.  Work around this weirdness
151262306a36Sopenharmony_ci		 * by allocating a new message.
151362306a36Sopenharmony_ci		 */
151462306a36Sopenharmony_ci		fallthrough;
151562306a36Sopenharmony_ci	case CEPH_MSG_MON_MAP:
151662306a36Sopenharmony_ci	case CEPH_MSG_MDS_MAP:
151762306a36Sopenharmony_ci	case CEPH_MSG_OSD_MAP:
151862306a36Sopenharmony_ci	case CEPH_MSG_FS_MAP_USER:
151962306a36Sopenharmony_ci		m = ceph_msg_new(type, front_len, GFP_NOFS, false);
152062306a36Sopenharmony_ci		if (!m)
152162306a36Sopenharmony_ci			return NULL;	/* ENOMEM--return skip == 0 */
152262306a36Sopenharmony_ci		break;
152362306a36Sopenharmony_ci	}
152462306a36Sopenharmony_ci
152562306a36Sopenharmony_ci	if (!m) {
152662306a36Sopenharmony_ci		pr_info("alloc_msg unknown type %d\n", type);
152762306a36Sopenharmony_ci		*skip = 1;
152862306a36Sopenharmony_ci	} else if (front_len > m->front_alloc_len) {
152962306a36Sopenharmony_ci		pr_warn("mon_alloc_msg front %d > prealloc %d (%u#%llu)\n",
153062306a36Sopenharmony_ci			front_len, m->front_alloc_len,
153162306a36Sopenharmony_ci			(unsigned int)con->peer_name.type,
153262306a36Sopenharmony_ci			le64_to_cpu(con->peer_name.num));
153362306a36Sopenharmony_ci		ceph_msg_put(m);
153462306a36Sopenharmony_ci		m = ceph_msg_new(type, front_len, GFP_NOFS, false);
153562306a36Sopenharmony_ci	}
153662306a36Sopenharmony_ci
153762306a36Sopenharmony_ci	return m;
153862306a36Sopenharmony_ci}
153962306a36Sopenharmony_ci
154062306a36Sopenharmony_ci/*
154162306a36Sopenharmony_ci * If the monitor connection resets, pick a new monitor and resubmit
154262306a36Sopenharmony_ci * any pending requests.
154362306a36Sopenharmony_ci */
154462306a36Sopenharmony_cistatic void mon_fault(struct ceph_connection *con)
154562306a36Sopenharmony_ci{
154662306a36Sopenharmony_ci	struct ceph_mon_client *monc = con->private;
154762306a36Sopenharmony_ci
154862306a36Sopenharmony_ci	mutex_lock(&monc->mutex);
154962306a36Sopenharmony_ci	dout("%s mon%d\n", __func__, monc->cur_mon);
155062306a36Sopenharmony_ci	if (monc->cur_mon >= 0) {
155162306a36Sopenharmony_ci		if (!monc->hunting) {
155262306a36Sopenharmony_ci			dout("%s hunting for new mon\n", __func__);
155362306a36Sopenharmony_ci			reopen_session(monc);
155462306a36Sopenharmony_ci			__schedule_delayed(monc);
155562306a36Sopenharmony_ci		} else {
155662306a36Sopenharmony_ci			dout("%s already hunting\n", __func__);
155762306a36Sopenharmony_ci		}
155862306a36Sopenharmony_ci	}
155962306a36Sopenharmony_ci	mutex_unlock(&monc->mutex);
156062306a36Sopenharmony_ci}
156162306a36Sopenharmony_ci
156262306a36Sopenharmony_ci/*
156362306a36Sopenharmony_ci * We can ignore refcounting on the connection struct, as all references
156462306a36Sopenharmony_ci * will come from the messenger workqueue, which is drained prior to
156562306a36Sopenharmony_ci * mon_client destruction.
156662306a36Sopenharmony_ci */
156762306a36Sopenharmony_cistatic struct ceph_connection *mon_get_con(struct ceph_connection *con)
156862306a36Sopenharmony_ci{
156962306a36Sopenharmony_ci	return con;
157062306a36Sopenharmony_ci}
157162306a36Sopenharmony_ci
157262306a36Sopenharmony_cistatic void mon_put_con(struct ceph_connection *con)
157362306a36Sopenharmony_ci{
157462306a36Sopenharmony_ci}
157562306a36Sopenharmony_ci
157662306a36Sopenharmony_cistatic const struct ceph_connection_operations mon_con_ops = {
157762306a36Sopenharmony_ci	.get = mon_get_con,
157862306a36Sopenharmony_ci	.put = mon_put_con,
157962306a36Sopenharmony_ci	.alloc_msg = mon_alloc_msg,
158062306a36Sopenharmony_ci	.dispatch = mon_dispatch,
158162306a36Sopenharmony_ci	.fault = mon_fault,
158262306a36Sopenharmony_ci	.get_auth_request = mon_get_auth_request,
158362306a36Sopenharmony_ci	.handle_auth_reply_more = mon_handle_auth_reply_more,
158462306a36Sopenharmony_ci	.handle_auth_done = mon_handle_auth_done,
158562306a36Sopenharmony_ci	.handle_auth_bad_method = mon_handle_auth_bad_method,
158662306a36Sopenharmony_ci};
1587