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   */
libceph_compatible(void * data)44  bool libceph_compatible(void *data)
45  {
46  	return true;
47  }
48  EXPORT_SYMBOL(libceph_compatible);
49  
param_get_supported_features(char * buffer,const struct kernel_param * kp)50  static 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  }
55  static const struct kernel_param_ops param_ops_supported_features = {
56  	.get = param_get_supported_features,
57  };
58  module_param_cb(supported_features, &param_ops_supported_features, NULL,
59  		0444);
60  
ceph_msg_type_name(int type)61  const 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  }
100  EXPORT_SYMBOL(ceph_msg_type_name);
101  
102  /*
103   * Initially learn our fsid, or verify an fsid matches.
104   */
ceph_check_fsid(struct ceph_client * client,struct ceph_fsid * fsid)105  int 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  }
118  EXPORT_SYMBOL(ceph_check_fsid);
119  
strcmp_null(const char * s1,const char * s2)120  static 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  
ceph_compare_options(struct ceph_options * new_opt,struct ceph_client * client)131  int 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  }
191  EXPORT_SYMBOL(ceph_compare_options);
192  
ceph_parse_fsid(const char * str,struct ceph_fsid * fsid)193  int 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  }
223  EXPORT_SYMBOL(ceph_parse_fsid);
224  
225  /*
226   * ceph options
227   */
228  enum {
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  
252  enum {
253  	Opt_read_from_replica_no,
254  	Opt_read_from_replica_balance,
255  	Opt_read_from_replica_localize,
256  };
257  
258  static 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  
265  enum 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  
273  static 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  
282  static 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  
ceph_alloc_options(void)308  struct 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  }
334  EXPORT_SYMBOL(ceph_alloc_options);
335  
ceph_destroy_options(struct ceph_options * opt)336  void 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  }
351  EXPORT_SYMBOL(ceph_destroy_options);
352  
353  /* get secret from key store */
get_secret(struct ceph_crypto_key * dst,const char * name,struct p_log * log)354  static 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  
394  out_key:
395  	key_put(ukey);
396  out:
397  	return err;
398  }
399  
ceph_parse_mon_ips(const char * buf,size_t len,struct ceph_options * opt,struct fc_log * l,char delim)400  int 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  }
416  EXPORT_SYMBOL(ceph_parse_mon_ips);
417  
ceph_parse_param(struct fs_parameter * param,struct ceph_options * opt,struct fc_log * l)418  int 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  
599  out_of_range:
600  	return inval_plog(&log, "%s out of range", param->key);
601  }
602  EXPORT_SYMBOL(ceph_parse_param);
603  
ceph_print_client_options(struct seq_file * m,struct ceph_client * client,bool show_all)604  int 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  }
690  EXPORT_SYMBOL(ceph_print_client_options);
691  
ceph_client_addr(struct ceph_client * client)692  struct ceph_entity_addr *ceph_client_addr(struct ceph_client *client)
693  {
694  	return &client->msgr.inst.addr;
695  }
696  EXPORT_SYMBOL(ceph_client_addr);
697  
ceph_client_gid(struct ceph_client * client)698  u64 ceph_client_gid(struct ceph_client *client)
699  {
700  	return client->monc.auth->global_id;
701  }
702  EXPORT_SYMBOL(ceph_client_gid);
703  
704  /*
705   * create a fresh client instance
706   */
ceph_create_client(struct ceph_options * opt,void * private)707  struct 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  
751  fail_monc:
752  	ceph_monc_stop(&client->monc);
753  fail:
754  	ceph_messenger_fini(&client->msgr);
755  	kfree(client);
756  	return ERR_PTR(err);
757  }
758  EXPORT_SYMBOL(ceph_create_client);
759  
ceph_destroy_client(struct ceph_client * client)760  void 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  }
778  EXPORT_SYMBOL(ceph_destroy_client);
779  
ceph_reset_client_addr(struct ceph_client * client)780  void 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  }
786  EXPORT_SYMBOL(ceph_reset_client_addr);
787  
788  /*
789   * true if we have the mon map (and have thus joined the cluster)
790   */
have_mon_and_osd_map(struct ceph_client * client)791  static 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   */
__ceph_open_session(struct ceph_client * client,unsigned long started)800  int __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  }
831  EXPORT_SYMBOL(__ceph_open_session);
832  
ceph_open_session(struct ceph_client * client)833  int 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  }
846  EXPORT_SYMBOL(ceph_open_session);
847  
ceph_wait_for_latest_osdmap(struct ceph_client * client,unsigned long timeout)848  int 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  }
864  EXPORT_SYMBOL(ceph_wait_for_latest_osdmap);
865  
init_ceph_lib(void)866  static 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  
889  out_msgr:
890  	ceph_msgr_exit();
891  out_crypto:
892  	ceph_crypto_shutdown();
893  out_debugfs:
894  	ceph_debugfs_cleanup();
895  	return ret;
896  }
897  
exit_ceph_lib(void)898  static 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  
909  module_init(init_ceph_lib);
910  module_exit(exit_ceph_lib);
911  
912  MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
913  MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
914  MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
915  MODULE_DESCRIPTION("Ceph core library");
916  MODULE_LICENSE("GPL");
917