cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ceph_common.c (23527B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2
      3#include <linux/ceph/ceph_debug.h>
      4#include <linux/backing-dev.h>
      5#include <linux/ctype.h>
      6#include <linux/fs.h>
      7#include <linux/inet.h>
      8#include <linux/in6.h>
      9#include <linux/key.h>
     10#include <keys/ceph-type.h>
     11#include <linux/module.h>
     12#include <linux/mount.h>
     13#include <linux/nsproxy.h>
     14#include <linux/fs_parser.h>
     15#include <linux/sched.h>
     16#include <linux/sched/mm.h>
     17#include <linux/seq_file.h>
     18#include <linux/slab.h>
     19#include <linux/statfs.h>
     20#include <linux/string.h>
     21#include <linux/vmalloc.h>
     22
     23
     24#include <linux/ceph/ceph_features.h>
     25#include <linux/ceph/libceph.h>
     26#include <linux/ceph/debugfs.h>
     27#include <linux/ceph/decode.h>
     28#include <linux/ceph/mon_client.h>
     29#include <linux/ceph/auth.h>
     30#include "crypto.h"
     31
     32
     33/*
     34 * Module compatibility interface.  For now it doesn't do anything,
     35 * but its existence signals a certain level of functionality.
     36 *
     37 * The data buffer is used to pass information both to and from
     38 * libceph.  The return value indicates whether libceph determines
     39 * it is compatible with the caller (from another kernel module),
     40 * given the provided data.
     41 *
     42 * The data pointer can be null.
     43 */
     44bool libceph_compatible(void *data)
     45{
     46	return true;
     47}
     48EXPORT_SYMBOL(libceph_compatible);
     49
     50static int param_get_supported_features(char *buffer,
     51					const struct kernel_param *kp)
     52{
     53	return sprintf(buffer, "0x%llx", CEPH_FEATURES_SUPPORTED_DEFAULT);
     54}
     55static const struct kernel_param_ops param_ops_supported_features = {
     56	.get = param_get_supported_features,
     57};
     58module_param_cb(supported_features, &param_ops_supported_features, NULL,
     59		0444);
     60
     61const char *ceph_msg_type_name(int type)
     62{
     63	switch (type) {
     64	case CEPH_MSG_SHUTDOWN: return "shutdown";
     65	case CEPH_MSG_PING: return "ping";
     66	case CEPH_MSG_AUTH: return "auth";
     67	case CEPH_MSG_AUTH_REPLY: return "auth_reply";
     68	case CEPH_MSG_MON_MAP: return "mon_map";
     69	case CEPH_MSG_MON_GET_MAP: return "mon_get_map";
     70	case CEPH_MSG_MON_SUBSCRIBE: return "mon_subscribe";
     71	case CEPH_MSG_MON_SUBSCRIBE_ACK: return "mon_subscribe_ack";
     72	case CEPH_MSG_STATFS: return "statfs";
     73	case CEPH_MSG_STATFS_REPLY: return "statfs_reply";
     74	case CEPH_MSG_MON_GET_VERSION: return "mon_get_version";
     75	case CEPH_MSG_MON_GET_VERSION_REPLY: return "mon_get_version_reply";
     76	case CEPH_MSG_MDS_MAP: return "mds_map";
     77	case CEPH_MSG_FS_MAP_USER: return "fs_map_user";
     78	case CEPH_MSG_CLIENT_SESSION: return "client_session";
     79	case CEPH_MSG_CLIENT_RECONNECT: return "client_reconnect";
     80	case CEPH_MSG_CLIENT_REQUEST: return "client_request";
     81	case CEPH_MSG_CLIENT_REQUEST_FORWARD: return "client_request_forward";
     82	case CEPH_MSG_CLIENT_REPLY: return "client_reply";
     83	case CEPH_MSG_CLIENT_CAPS: return "client_caps";
     84	case CEPH_MSG_CLIENT_CAPRELEASE: return "client_cap_release";
     85	case CEPH_MSG_CLIENT_QUOTA: return "client_quota";
     86	case CEPH_MSG_CLIENT_SNAP: return "client_snap";
     87	case CEPH_MSG_CLIENT_LEASE: return "client_lease";
     88	case CEPH_MSG_POOLOP_REPLY: return "poolop_reply";
     89	case CEPH_MSG_POOLOP: return "poolop";
     90	case CEPH_MSG_MON_COMMAND: return "mon_command";
     91	case CEPH_MSG_MON_COMMAND_ACK: return "mon_command_ack";
     92	case CEPH_MSG_OSD_MAP: return "osd_map";
     93	case CEPH_MSG_OSD_OP: return "osd_op";
     94	case CEPH_MSG_OSD_OPREPLY: return "osd_opreply";
     95	case CEPH_MSG_WATCH_NOTIFY: return "watch_notify";
     96	case CEPH_MSG_OSD_BACKOFF: return "osd_backoff";
     97	default: return "unknown";
     98	}
     99}
    100EXPORT_SYMBOL(ceph_msg_type_name);
    101
    102/*
    103 * Initially learn our fsid, or verify an fsid matches.
    104 */
    105int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid)
    106{
    107	if (client->have_fsid) {
    108		if (ceph_fsid_compare(&client->fsid, fsid)) {
    109			pr_err("bad fsid, had %pU got %pU",
    110			       &client->fsid, fsid);
    111			return -1;
    112		}
    113	} else {
    114		memcpy(&client->fsid, fsid, sizeof(*fsid));
    115	}
    116	return 0;
    117}
    118EXPORT_SYMBOL(ceph_check_fsid);
    119
    120static int strcmp_null(const char *s1, const char *s2)
    121{
    122	if (!s1 && !s2)
    123		return 0;
    124	if (s1 && !s2)
    125		return -1;
    126	if (!s1 && s2)
    127		return 1;
    128	return strcmp(s1, s2);
    129}
    130
    131int ceph_compare_options(struct ceph_options *new_opt,
    132			 struct ceph_client *client)
    133{
    134	struct ceph_options *opt1 = new_opt;
    135	struct ceph_options *opt2 = client->options;
    136	int ofs = offsetof(struct ceph_options, mon_addr);
    137	int i;
    138	int ret;
    139
    140	/*
    141	 * Don't bother comparing options if network namespaces don't
    142	 * match.
    143	 */
    144	if (!net_eq(current->nsproxy->net_ns, read_pnet(&client->msgr.net)))
    145		return -1;
    146
    147	ret = memcmp(opt1, opt2, ofs);
    148	if (ret)
    149		return ret;
    150
    151	ret = strcmp_null(opt1->name, opt2->name);
    152	if (ret)
    153		return ret;
    154
    155	if (opt1->key && !opt2->key)
    156		return -1;
    157	if (!opt1->key && opt2->key)
    158		return 1;
    159	if (opt1->key && opt2->key) {
    160		if (opt1->key->type != opt2->key->type)
    161			return -1;
    162		if (opt1->key->created.tv_sec != opt2->key->created.tv_sec)
    163			return -1;
    164		if (opt1->key->created.tv_nsec != opt2->key->created.tv_nsec)
    165			return -1;
    166		if (opt1->key->len != opt2->key->len)
    167			return -1;
    168		if (opt1->key->key && !opt2->key->key)
    169			return -1;
    170		if (!opt1->key->key && opt2->key->key)
    171			return 1;
    172		if (opt1->key->key && opt2->key->key) {
    173			ret = memcmp(opt1->key->key, opt2->key->key, opt1->key->len);
    174			if (ret)
    175				return ret;
    176		}
    177	}
    178
    179	ret = ceph_compare_crush_locs(&opt1->crush_locs, &opt2->crush_locs);
    180	if (ret)
    181		return ret;
    182
    183	/* any matching mon ip implies a match */
    184	for (i = 0; i < opt1->num_mon; i++) {
    185		if (ceph_monmap_contains(client->monc.monmap,
    186				 &opt1->mon_addr[i]))
    187			return 0;
    188	}
    189	return -1;
    190}
    191EXPORT_SYMBOL(ceph_compare_options);
    192
    193int ceph_parse_fsid(const char *str, struct ceph_fsid *fsid)
    194{
    195	int i = 0;
    196	char tmp[3];
    197	int err = -EINVAL;
    198	int d;
    199
    200	dout("%s '%s'\n", __func__, str);
    201	tmp[2] = 0;
    202	while (*str && i < 16) {
    203		if (ispunct(*str)) {
    204			str++;
    205			continue;
    206		}
    207		if (!isxdigit(str[0]) || !isxdigit(str[1]))
    208			break;
    209		tmp[0] = str[0];
    210		tmp[1] = str[1];
    211		if (sscanf(tmp, "%x", &d) < 1)
    212			break;
    213		fsid->fsid[i] = d & 0xff;
    214		i++;
    215		str += 2;
    216	}
    217
    218	if (i == 16)
    219		err = 0;
    220	dout("%s ret %d got fsid %pU\n", __func__, err, fsid);
    221	return err;
    222}
    223EXPORT_SYMBOL(ceph_parse_fsid);
    224
    225/*
    226 * ceph options
    227 */
    228enum {
    229	Opt_osdkeepalivetimeout,
    230	Opt_mount_timeout,
    231	Opt_osd_idle_ttl,
    232	Opt_osd_request_timeout,
    233	/* int args above */
    234	Opt_fsid,
    235	Opt_name,
    236	Opt_secret,
    237	Opt_key,
    238	Opt_ip,
    239	Opt_crush_location,
    240	Opt_read_from_replica,
    241	Opt_ms_mode,
    242	/* string args above */
    243	Opt_share,
    244	Opt_crc,
    245	Opt_cephx_require_signatures,
    246	Opt_cephx_sign_messages,
    247	Opt_tcp_nodelay,
    248	Opt_abort_on_full,
    249	Opt_rxbounce,
    250};
    251
    252enum {
    253	Opt_read_from_replica_no,
    254	Opt_read_from_replica_balance,
    255	Opt_read_from_replica_localize,
    256};
    257
    258static const struct constant_table ceph_param_read_from_replica[] = {
    259	{"no",		Opt_read_from_replica_no},
    260	{"balance",	Opt_read_from_replica_balance},
    261	{"localize",	Opt_read_from_replica_localize},
    262	{}
    263};
    264
    265enum ceph_ms_mode {
    266	Opt_ms_mode_legacy,
    267	Opt_ms_mode_crc,
    268	Opt_ms_mode_secure,
    269	Opt_ms_mode_prefer_crc,
    270	Opt_ms_mode_prefer_secure
    271};
    272
    273static const struct constant_table ceph_param_ms_mode[] = {
    274	{"legacy",		Opt_ms_mode_legacy},
    275	{"crc",			Opt_ms_mode_crc},
    276	{"secure",		Opt_ms_mode_secure},
    277	{"prefer-crc",		Opt_ms_mode_prefer_crc},
    278	{"prefer-secure",	Opt_ms_mode_prefer_secure},
    279	{}
    280};
    281
    282static const struct fs_parameter_spec ceph_parameters[] = {
    283	fsparam_flag	("abort_on_full",		Opt_abort_on_full),
    284	__fsparam	(NULL, "cephx_require_signatures", Opt_cephx_require_signatures,
    285			 fs_param_neg_with_no|fs_param_deprecated, NULL),
    286	fsparam_flag_no ("cephx_sign_messages",		Opt_cephx_sign_messages),
    287	fsparam_flag_no ("crc",				Opt_crc),
    288	fsparam_string	("crush_location",		Opt_crush_location),
    289	fsparam_string	("fsid",			Opt_fsid),
    290	fsparam_string	("ip",				Opt_ip),
    291	fsparam_string	("key",				Opt_key),
    292	fsparam_u32	("mount_timeout",		Opt_mount_timeout),
    293	fsparam_string	("name",			Opt_name),
    294	fsparam_u32	("osd_idle_ttl",		Opt_osd_idle_ttl),
    295	fsparam_u32	("osd_request_timeout",		Opt_osd_request_timeout),
    296	fsparam_u32	("osdkeepalive",		Opt_osdkeepalivetimeout),
    297	fsparam_enum	("read_from_replica",		Opt_read_from_replica,
    298			 ceph_param_read_from_replica),
    299	fsparam_flag	("rxbounce",			Opt_rxbounce),
    300	fsparam_enum	("ms_mode",			Opt_ms_mode,
    301			 ceph_param_ms_mode),
    302	fsparam_string	("secret",			Opt_secret),
    303	fsparam_flag_no ("share",			Opt_share),
    304	fsparam_flag_no ("tcp_nodelay",			Opt_tcp_nodelay),
    305	{}
    306};
    307
    308struct ceph_options *ceph_alloc_options(void)
    309{
    310	struct ceph_options *opt;
    311
    312	opt = kzalloc(sizeof(*opt), GFP_KERNEL);
    313	if (!opt)
    314		return NULL;
    315
    316	opt->crush_locs = RB_ROOT;
    317	opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
    318				GFP_KERNEL);
    319	if (!opt->mon_addr) {
    320		kfree(opt);
    321		return NULL;
    322	}
    323
    324	opt->flags = CEPH_OPT_DEFAULT;
    325	opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
    326	opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT;
    327	opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;
    328	opt->osd_request_timeout = CEPH_OSD_REQUEST_TIMEOUT_DEFAULT;
    329	opt->read_from_replica = CEPH_READ_FROM_REPLICA_DEFAULT;
    330	opt->con_modes[0] = CEPH_CON_MODE_UNKNOWN;
    331	opt->con_modes[1] = CEPH_CON_MODE_UNKNOWN;
    332	return opt;
    333}
    334EXPORT_SYMBOL(ceph_alloc_options);
    335
    336void ceph_destroy_options(struct ceph_options *opt)
    337{
    338	dout("destroy_options %p\n", opt);
    339	if (!opt)
    340		return;
    341
    342	ceph_clear_crush_locs(&opt->crush_locs);
    343	kfree(opt->name);
    344	if (opt->key) {
    345		ceph_crypto_key_destroy(opt->key);
    346		kfree(opt->key);
    347	}
    348	kfree(opt->mon_addr);
    349	kfree(opt);
    350}
    351EXPORT_SYMBOL(ceph_destroy_options);
    352
    353/* get secret from key store */
    354static int get_secret(struct ceph_crypto_key *dst, const char *name,
    355		      struct p_log *log)
    356{
    357	struct key *ukey;
    358	int key_err;
    359	int err = 0;
    360	struct ceph_crypto_key *ckey;
    361
    362	ukey = request_key(&key_type_ceph, name, NULL);
    363	if (IS_ERR(ukey)) {
    364		/* request_key errors don't map nicely to mount(2)
    365		   errors; don't even try, but still printk */
    366		key_err = PTR_ERR(ukey);
    367		switch (key_err) {
    368		case -ENOKEY:
    369			error_plog(log, "Failed due to key not found: %s",
    370			       name);
    371			break;
    372		case -EKEYEXPIRED:
    373			error_plog(log, "Failed due to expired key: %s",
    374			       name);
    375			break;
    376		case -EKEYREVOKED:
    377			error_plog(log, "Failed due to revoked key: %s",
    378			       name);
    379			break;
    380		default:
    381			error_plog(log, "Failed due to key error %d: %s",
    382			       key_err, name);
    383		}
    384		err = -EPERM;
    385		goto out;
    386	}
    387
    388	ckey = ukey->payload.data[0];
    389	err = ceph_crypto_key_clone(dst, ckey);
    390	if (err)
    391		goto out_key;
    392	/* pass through, err is 0 */
    393
    394out_key:
    395	key_put(ukey);
    396out:
    397	return err;
    398}
    399
    400int ceph_parse_mon_ips(const char *buf, size_t len, struct ceph_options *opt,
    401		       struct fc_log *l, char delim)
    402{
    403	struct p_log log = {.prefix = "libceph", .log = l};
    404	int ret;
    405
    406	/* ip1[:port1][<delim>ip2[:port2]...] */
    407	ret = ceph_parse_ips(buf, buf + len, opt->mon_addr, CEPH_MAX_MON,
    408			     &opt->num_mon, delim);
    409	if (ret) {
    410		error_plog(&log, "Failed to parse monitor IPs: %d", ret);
    411		return ret;
    412	}
    413
    414	return 0;
    415}
    416EXPORT_SYMBOL(ceph_parse_mon_ips);
    417
    418int ceph_parse_param(struct fs_parameter *param, struct ceph_options *opt,
    419		     struct fc_log *l)
    420{
    421	struct fs_parse_result result;
    422	int token, err;
    423	struct p_log log = {.prefix = "libceph", .log = l};
    424
    425	token = __fs_parse(&log, ceph_parameters, param, &result);
    426	dout("%s fs_parse '%s' token %d\n", __func__, param->key, token);
    427	if (token < 0)
    428		return token;
    429
    430	switch (token) {
    431	case Opt_ip:
    432		err = ceph_parse_ips(param->string,
    433				     param->string + param->size,
    434				     &opt->my_addr, 1, NULL, ',');
    435		if (err) {
    436			error_plog(&log, "Failed to parse ip: %d", err);
    437			return err;
    438		}
    439		opt->flags |= CEPH_OPT_MYIP;
    440		break;
    441
    442	case Opt_fsid:
    443		err = ceph_parse_fsid(param->string, &opt->fsid);
    444		if (err) {
    445			error_plog(&log, "Failed to parse fsid: %d", err);
    446			return err;
    447		}
    448		opt->flags |= CEPH_OPT_FSID;
    449		break;
    450	case Opt_name:
    451		kfree(opt->name);
    452		opt->name = param->string;
    453		param->string = NULL;
    454		break;
    455	case Opt_secret:
    456		ceph_crypto_key_destroy(opt->key);
    457		kfree(opt->key);
    458
    459		opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
    460		if (!opt->key)
    461			return -ENOMEM;
    462		err = ceph_crypto_key_unarmor(opt->key, param->string);
    463		if (err) {
    464			error_plog(&log, "Failed to parse secret: %d", err);
    465			return err;
    466		}
    467		break;
    468	case Opt_key:
    469		ceph_crypto_key_destroy(opt->key);
    470		kfree(opt->key);
    471
    472		opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
    473		if (!opt->key)
    474			return -ENOMEM;
    475		return get_secret(opt->key, param->string, &log);
    476	case Opt_crush_location:
    477		ceph_clear_crush_locs(&opt->crush_locs);
    478		err = ceph_parse_crush_location(param->string,
    479						&opt->crush_locs);
    480		if (err) {
    481			error_plog(&log, "Failed to parse CRUSH location: %d",
    482				   err);
    483			return err;
    484		}
    485		break;
    486	case Opt_read_from_replica:
    487		switch (result.uint_32) {
    488		case Opt_read_from_replica_no:
    489			opt->read_from_replica = 0;
    490			break;
    491		case Opt_read_from_replica_balance:
    492			opt->read_from_replica = CEPH_OSD_FLAG_BALANCE_READS;
    493			break;
    494		case Opt_read_from_replica_localize:
    495			opt->read_from_replica = CEPH_OSD_FLAG_LOCALIZE_READS;
    496			break;
    497		default:
    498			BUG();
    499		}
    500		break;
    501	case Opt_ms_mode:
    502		switch (result.uint_32) {
    503		case Opt_ms_mode_legacy:
    504			opt->con_modes[0] = CEPH_CON_MODE_UNKNOWN;
    505			opt->con_modes[1] = CEPH_CON_MODE_UNKNOWN;
    506			break;
    507		case Opt_ms_mode_crc:
    508			opt->con_modes[0] = CEPH_CON_MODE_CRC;
    509			opt->con_modes[1] = CEPH_CON_MODE_UNKNOWN;
    510			break;
    511		case Opt_ms_mode_secure:
    512			opt->con_modes[0] = CEPH_CON_MODE_SECURE;
    513			opt->con_modes[1] = CEPH_CON_MODE_UNKNOWN;
    514			break;
    515		case Opt_ms_mode_prefer_crc:
    516			opt->con_modes[0] = CEPH_CON_MODE_CRC;
    517			opt->con_modes[1] = CEPH_CON_MODE_SECURE;
    518			break;
    519		case Opt_ms_mode_prefer_secure:
    520			opt->con_modes[0] = CEPH_CON_MODE_SECURE;
    521			opt->con_modes[1] = CEPH_CON_MODE_CRC;
    522			break;
    523		default:
    524			BUG();
    525		}
    526		break;
    527
    528	case Opt_osdkeepalivetimeout:
    529		/* 0 isn't well defined right now, reject it */
    530		if (result.uint_32 < 1 || result.uint_32 > INT_MAX / 1000)
    531			goto out_of_range;
    532		opt->osd_keepalive_timeout =
    533		    msecs_to_jiffies(result.uint_32 * 1000);
    534		break;
    535	case Opt_osd_idle_ttl:
    536		/* 0 isn't well defined right now, reject it */
    537		if (result.uint_32 < 1 || result.uint_32 > INT_MAX / 1000)
    538			goto out_of_range;
    539		opt->osd_idle_ttl = msecs_to_jiffies(result.uint_32 * 1000);
    540		break;
    541	case Opt_mount_timeout:
    542		/* 0 is "wait forever" (i.e. infinite timeout) */
    543		if (result.uint_32 > INT_MAX / 1000)
    544			goto out_of_range;
    545		opt->mount_timeout = msecs_to_jiffies(result.uint_32 * 1000);
    546		break;
    547	case Opt_osd_request_timeout:
    548		/* 0 is "wait forever" (i.e. infinite timeout) */
    549		if (result.uint_32 > INT_MAX / 1000)
    550			goto out_of_range;
    551		opt->osd_request_timeout =
    552		    msecs_to_jiffies(result.uint_32 * 1000);
    553		break;
    554
    555	case Opt_share:
    556		if (!result.negated)
    557			opt->flags &= ~CEPH_OPT_NOSHARE;
    558		else
    559			opt->flags |= CEPH_OPT_NOSHARE;
    560		break;
    561	case Opt_crc:
    562		if (!result.negated)
    563			opt->flags &= ~CEPH_OPT_NOCRC;
    564		else
    565			opt->flags |= CEPH_OPT_NOCRC;
    566		break;
    567	case Opt_cephx_require_signatures:
    568		if (!result.negated)
    569			warn_plog(&log, "Ignoring cephx_require_signatures");
    570		else
    571			warn_plog(&log, "Ignoring nocephx_require_signatures, use nocephx_sign_messages");
    572		break;
    573	case Opt_cephx_sign_messages:
    574		if (!result.negated)
    575			opt->flags &= ~CEPH_OPT_NOMSGSIGN;
    576		else
    577			opt->flags |= CEPH_OPT_NOMSGSIGN;
    578		break;
    579	case Opt_tcp_nodelay:
    580		if (!result.negated)
    581			opt->flags |= CEPH_OPT_TCP_NODELAY;
    582		else
    583			opt->flags &= ~CEPH_OPT_TCP_NODELAY;
    584		break;
    585
    586	case Opt_abort_on_full:
    587		opt->flags |= CEPH_OPT_ABORT_ON_FULL;
    588		break;
    589	case Opt_rxbounce:
    590		opt->flags |= CEPH_OPT_RXBOUNCE;
    591		break;
    592
    593	default:
    594		BUG();
    595	}
    596
    597	return 0;
    598
    599out_of_range:
    600	return inval_plog(&log, "%s out of range", param->key);
    601}
    602EXPORT_SYMBOL(ceph_parse_param);
    603
    604int ceph_print_client_options(struct seq_file *m, struct ceph_client *client,
    605			      bool show_all)
    606{
    607	struct ceph_options *opt = client->options;
    608	size_t pos = m->count;
    609	struct rb_node *n;
    610
    611	if (opt->name) {
    612		seq_puts(m, "name=");
    613		seq_escape(m, opt->name, ", \t\n\\");
    614		seq_putc(m, ',');
    615	}
    616	if (opt->key)
    617		seq_puts(m, "secret=<hidden>,");
    618
    619	if (!RB_EMPTY_ROOT(&opt->crush_locs)) {
    620		seq_puts(m, "crush_location=");
    621		for (n = rb_first(&opt->crush_locs); ; ) {
    622			struct crush_loc_node *loc =
    623			    rb_entry(n, struct crush_loc_node, cl_node);
    624
    625			seq_printf(m, "%s:%s", loc->cl_loc.cl_type_name,
    626				   loc->cl_loc.cl_name);
    627			n = rb_next(n);
    628			if (!n)
    629				break;
    630
    631			seq_putc(m, '|');
    632		}
    633		seq_putc(m, ',');
    634	}
    635	if (opt->read_from_replica == CEPH_OSD_FLAG_BALANCE_READS) {
    636		seq_puts(m, "read_from_replica=balance,");
    637	} else if (opt->read_from_replica == CEPH_OSD_FLAG_LOCALIZE_READS) {
    638		seq_puts(m, "read_from_replica=localize,");
    639	}
    640	if (opt->con_modes[0] != CEPH_CON_MODE_UNKNOWN) {
    641		if (opt->con_modes[0] == CEPH_CON_MODE_CRC &&
    642		    opt->con_modes[1] == CEPH_CON_MODE_UNKNOWN) {
    643			seq_puts(m, "ms_mode=crc,");
    644		} else if (opt->con_modes[0] == CEPH_CON_MODE_SECURE &&
    645			   opt->con_modes[1] == CEPH_CON_MODE_UNKNOWN) {
    646			seq_puts(m, "ms_mode=secure,");
    647		} else if (opt->con_modes[0] == CEPH_CON_MODE_CRC &&
    648			   opt->con_modes[1] == CEPH_CON_MODE_SECURE) {
    649			seq_puts(m, "ms_mode=prefer-crc,");
    650		} else if (opt->con_modes[0] == CEPH_CON_MODE_SECURE &&
    651			   opt->con_modes[1] == CEPH_CON_MODE_CRC) {
    652			seq_puts(m, "ms_mode=prefer-secure,");
    653		}
    654	}
    655
    656	if (opt->flags & CEPH_OPT_FSID)
    657		seq_printf(m, "fsid=%pU,", &opt->fsid);
    658	if (opt->flags & CEPH_OPT_NOSHARE)
    659		seq_puts(m, "noshare,");
    660	if (opt->flags & CEPH_OPT_NOCRC)
    661		seq_puts(m, "nocrc,");
    662	if (opt->flags & CEPH_OPT_NOMSGSIGN)
    663		seq_puts(m, "nocephx_sign_messages,");
    664	if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0)
    665		seq_puts(m, "notcp_nodelay,");
    666	if (show_all && (opt->flags & CEPH_OPT_ABORT_ON_FULL))
    667		seq_puts(m, "abort_on_full,");
    668	if (opt->flags & CEPH_OPT_RXBOUNCE)
    669		seq_puts(m, "rxbounce,");
    670
    671	if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
    672		seq_printf(m, "mount_timeout=%d,",
    673			   jiffies_to_msecs(opt->mount_timeout) / 1000);
    674	if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT)
    675		seq_printf(m, "osd_idle_ttl=%d,",
    676			   jiffies_to_msecs(opt->osd_idle_ttl) / 1000);
    677	if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT)
    678		seq_printf(m, "osdkeepalivetimeout=%d,",
    679		    jiffies_to_msecs(opt->osd_keepalive_timeout) / 1000);
    680	if (opt->osd_request_timeout != CEPH_OSD_REQUEST_TIMEOUT_DEFAULT)
    681		seq_printf(m, "osd_request_timeout=%d,",
    682			   jiffies_to_msecs(opt->osd_request_timeout) / 1000);
    683
    684	/* drop redundant comma */
    685	if (m->count != pos)
    686		m->count--;
    687
    688	return 0;
    689}
    690EXPORT_SYMBOL(ceph_print_client_options);
    691
    692struct ceph_entity_addr *ceph_client_addr(struct ceph_client *client)
    693{
    694	return &client->msgr.inst.addr;
    695}
    696EXPORT_SYMBOL(ceph_client_addr);
    697
    698u64 ceph_client_gid(struct ceph_client *client)
    699{
    700	return client->monc.auth->global_id;
    701}
    702EXPORT_SYMBOL(ceph_client_gid);
    703
    704/*
    705 * create a fresh client instance
    706 */
    707struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private)
    708{
    709	struct ceph_client *client;
    710	struct ceph_entity_addr *myaddr = NULL;
    711	int err;
    712
    713	err = wait_for_random_bytes();
    714	if (err < 0)
    715		return ERR_PTR(err);
    716
    717	client = kzalloc(sizeof(*client), GFP_KERNEL);
    718	if (client == NULL)
    719		return ERR_PTR(-ENOMEM);
    720
    721	client->private = private;
    722	client->options = opt;
    723
    724	mutex_init(&client->mount_mutex);
    725	init_waitqueue_head(&client->auth_wq);
    726	client->auth_err = 0;
    727
    728	client->extra_mon_dispatch = NULL;
    729	client->supported_features = CEPH_FEATURES_SUPPORTED_DEFAULT;
    730	client->required_features = CEPH_FEATURES_REQUIRED_DEFAULT;
    731
    732	if (!ceph_test_opt(client, NOMSGSIGN))
    733		client->required_features |= CEPH_FEATURE_MSG_AUTH;
    734
    735	/* msgr */
    736	if (ceph_test_opt(client, MYIP))
    737		myaddr = &client->options->my_addr;
    738
    739	ceph_messenger_init(&client->msgr, myaddr);
    740
    741	/* subsystems */
    742	err = ceph_monc_init(&client->monc, client);
    743	if (err < 0)
    744		goto fail;
    745	err = ceph_osdc_init(&client->osdc, client);
    746	if (err < 0)
    747		goto fail_monc;
    748
    749	return client;
    750
    751fail_monc:
    752	ceph_monc_stop(&client->monc);
    753fail:
    754	ceph_messenger_fini(&client->msgr);
    755	kfree(client);
    756	return ERR_PTR(err);
    757}
    758EXPORT_SYMBOL(ceph_create_client);
    759
    760void ceph_destroy_client(struct ceph_client *client)
    761{
    762	dout("destroy_client %p\n", client);
    763
    764	atomic_set(&client->msgr.stopping, 1);
    765
    766	/* unmount */
    767	ceph_osdc_stop(&client->osdc);
    768	ceph_monc_stop(&client->monc);
    769	ceph_messenger_fini(&client->msgr);
    770
    771	ceph_debugfs_client_cleanup(client);
    772
    773	ceph_destroy_options(client->options);
    774
    775	kfree(client);
    776	dout("destroy_client %p done\n", client);
    777}
    778EXPORT_SYMBOL(ceph_destroy_client);
    779
    780void ceph_reset_client_addr(struct ceph_client *client)
    781{
    782	ceph_messenger_reset_nonce(&client->msgr);
    783	ceph_monc_reopen_session(&client->monc);
    784	ceph_osdc_reopen_osds(&client->osdc);
    785}
    786EXPORT_SYMBOL(ceph_reset_client_addr);
    787
    788/*
    789 * true if we have the mon map (and have thus joined the cluster)
    790 */
    791static bool have_mon_and_osd_map(struct ceph_client *client)
    792{
    793	return client->monc.monmap && client->monc.monmap->epoch &&
    794	       client->osdc.osdmap && client->osdc.osdmap->epoch;
    795}
    796
    797/*
    798 * mount: join the ceph cluster, and open root directory.
    799 */
    800int __ceph_open_session(struct ceph_client *client, unsigned long started)
    801{
    802	unsigned long timeout = client->options->mount_timeout;
    803	long err;
    804
    805	/* open session, and wait for mon and osd maps */
    806	err = ceph_monc_open_session(&client->monc);
    807	if (err < 0)
    808		return err;
    809
    810	while (!have_mon_and_osd_map(client)) {
    811		if (timeout && time_after_eq(jiffies, started + timeout))
    812			return -ETIMEDOUT;
    813
    814		/* wait */
    815		dout("mount waiting for mon_map\n");
    816		err = wait_event_interruptible_timeout(client->auth_wq,
    817			have_mon_and_osd_map(client) || (client->auth_err < 0),
    818			ceph_timeout_jiffies(timeout));
    819		if (err < 0)
    820			return err;
    821		if (client->auth_err < 0)
    822			return client->auth_err;
    823	}
    824
    825	pr_info("client%llu fsid %pU\n", ceph_client_gid(client),
    826		&client->fsid);
    827	ceph_debugfs_client_init(client);
    828
    829	return 0;
    830}
    831EXPORT_SYMBOL(__ceph_open_session);
    832
    833int ceph_open_session(struct ceph_client *client)
    834{
    835	int ret;
    836	unsigned long started = jiffies;  /* note the start time */
    837
    838	dout("open_session start\n");
    839	mutex_lock(&client->mount_mutex);
    840
    841	ret = __ceph_open_session(client, started);
    842
    843	mutex_unlock(&client->mount_mutex);
    844	return ret;
    845}
    846EXPORT_SYMBOL(ceph_open_session);
    847
    848int ceph_wait_for_latest_osdmap(struct ceph_client *client,
    849				unsigned long timeout)
    850{
    851	u64 newest_epoch;
    852	int ret;
    853
    854	ret = ceph_monc_get_version(&client->monc, "osdmap", &newest_epoch);
    855	if (ret)
    856		return ret;
    857
    858	if (client->osdc.osdmap->epoch >= newest_epoch)
    859		return 0;
    860
    861	ceph_osdc_maybe_request_map(&client->osdc);
    862	return ceph_monc_wait_osdmap(&client->monc, newest_epoch, timeout);
    863}
    864EXPORT_SYMBOL(ceph_wait_for_latest_osdmap);
    865
    866static int __init init_ceph_lib(void)
    867{
    868	int ret = 0;
    869
    870	ceph_debugfs_init();
    871
    872	ret = ceph_crypto_init();
    873	if (ret < 0)
    874		goto out_debugfs;
    875
    876	ret = ceph_msgr_init();
    877	if (ret < 0)
    878		goto out_crypto;
    879
    880	ret = ceph_osdc_setup();
    881	if (ret < 0)
    882		goto out_msgr;
    883
    884	pr_info("loaded (mon/osd proto %d/%d)\n",
    885		CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL);
    886
    887	return 0;
    888
    889out_msgr:
    890	ceph_msgr_exit();
    891out_crypto:
    892	ceph_crypto_shutdown();
    893out_debugfs:
    894	ceph_debugfs_cleanup();
    895	return ret;
    896}
    897
    898static void __exit exit_ceph_lib(void)
    899{
    900	dout("exit_ceph_lib\n");
    901	WARN_ON(!ceph_strings_empty());
    902
    903	ceph_osdc_cleanup();
    904	ceph_msgr_exit();
    905	ceph_crypto_shutdown();
    906	ceph_debugfs_cleanup();
    907}
    908
    909module_init(init_ceph_lib);
    910module_exit(exit_ceph_lib);
    911
    912MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
    913MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
    914MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
    915MODULE_DESCRIPTION("Ceph core library");
    916MODULE_LICENSE("GPL");