Linux Audio

Check our new training course

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