xref: /linux/net/ceph/ceph_common.c (revision 905e46acd3272d04566fec49afbd7ad9e2ed9ae3)
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/nsproxy.h>
13 #include <linux/parser.h>
14 #include <linux/sched.h>
15 #include <linux/seq_file.h>
16 #include <linux/slab.h>
17 #include <linux/statfs.h>
18 #include <linux/string.h>
19 #include <linux/vmalloc.h>
20 
21 
22 #include <linux/ceph/ceph_features.h>
23 #include <linux/ceph/libceph.h>
24 #include <linux/ceph/debugfs.h>
25 #include <linux/ceph/decode.h>
26 #include <linux/ceph/mon_client.h>
27 #include <linux/ceph/auth.h>
28 #include "crypto.h"
29 
30 
31 /*
32  * Module compatibility interface.  For now it doesn't do anything,
33  * but its existence signals a certain level of functionality.
34  *
35  * The data buffer is used to pass information both to and from
36  * libceph.  The return value indicates whether libceph determines
37  * it is compatible with the caller (from another kernel module),
38  * given the provided data.
39  *
40  * The data pointer can be null.
41  */
42 bool libceph_compatible(void *data)
43 {
44 	return true;
45 }
46 EXPORT_SYMBOL(libceph_compatible);
47 
48 static int param_get_supported_features(char *buffer,
49 					const struct kernel_param *kp)
50 {
51 	return sprintf(buffer, "0x%llx", CEPH_FEATURES_SUPPORTED_DEFAULT);
52 }
53 static const struct kernel_param_ops param_ops_supported_features = {
54 	.get = param_get_supported_features,
55 };
56 module_param_cb(supported_features, &param_ops_supported_features, NULL,
57 		S_IRUGO);
58 
59 /*
60  * find filename portion of a path (/foo/bar/baz -> baz)
61  */
62 const char *ceph_file_part(const char *s, int len)
63 {
64 	const char *e = s + len;
65 
66 	while (e != s && *(e-1) != '/')
67 		e--;
68 	return e;
69 }
70 EXPORT_SYMBOL(ceph_file_part);
71 
72 const char *ceph_msg_type_name(int type)
73 {
74 	switch (type) {
75 	case CEPH_MSG_SHUTDOWN: return "shutdown";
76 	case CEPH_MSG_PING: return "ping";
77 	case CEPH_MSG_AUTH: return "auth";
78 	case CEPH_MSG_AUTH_REPLY: return "auth_reply";
79 	case CEPH_MSG_MON_MAP: return "mon_map";
80 	case CEPH_MSG_MON_GET_MAP: return "mon_get_map";
81 	case CEPH_MSG_MON_SUBSCRIBE: return "mon_subscribe";
82 	case CEPH_MSG_MON_SUBSCRIBE_ACK: return "mon_subscribe_ack";
83 	case CEPH_MSG_STATFS: return "statfs";
84 	case CEPH_MSG_STATFS_REPLY: return "statfs_reply";
85 	case CEPH_MSG_MON_GET_VERSION: return "mon_get_version";
86 	case CEPH_MSG_MON_GET_VERSION_REPLY: return "mon_get_version_reply";
87 	case CEPH_MSG_MDS_MAP: return "mds_map";
88 	case CEPH_MSG_CLIENT_SESSION: return "client_session";
89 	case CEPH_MSG_CLIENT_RECONNECT: return "client_reconnect";
90 	case CEPH_MSG_CLIENT_REQUEST: return "client_request";
91 	case CEPH_MSG_CLIENT_REQUEST_FORWARD: return "client_request_forward";
92 	case CEPH_MSG_CLIENT_REPLY: return "client_reply";
93 	case CEPH_MSG_CLIENT_CAPS: return "client_caps";
94 	case CEPH_MSG_CLIENT_CAPRELEASE: return "client_cap_release";
95 	case CEPH_MSG_CLIENT_SNAP: return "client_snap";
96 	case CEPH_MSG_CLIENT_LEASE: return "client_lease";
97 	case CEPH_MSG_OSD_MAP: return "osd_map";
98 	case CEPH_MSG_OSD_OP: return "osd_op";
99 	case CEPH_MSG_OSD_OPREPLY: return "osd_opreply";
100 	case CEPH_MSG_WATCH_NOTIFY: return "watch_notify";
101 	default: return "unknown";
102 	}
103 }
104 EXPORT_SYMBOL(ceph_msg_type_name);
105 
106 /*
107  * Initially learn our fsid, or verify an fsid matches.
108  */
109 int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid)
110 {
111 	if (client->have_fsid) {
112 		if (ceph_fsid_compare(&client->fsid, fsid)) {
113 			pr_err("bad fsid, had %pU got %pU",
114 			       &client->fsid, fsid);
115 			return -1;
116 		}
117 	} else {
118 		memcpy(&client->fsid, fsid, sizeof(*fsid));
119 	}
120 	return 0;
121 }
122 EXPORT_SYMBOL(ceph_check_fsid);
123 
124 static int strcmp_null(const char *s1, const char *s2)
125 {
126 	if (!s1 && !s2)
127 		return 0;
128 	if (s1 && !s2)
129 		return -1;
130 	if (!s1 && s2)
131 		return 1;
132 	return strcmp(s1, s2);
133 }
134 
135 int ceph_compare_options(struct ceph_options *new_opt,
136 			 struct ceph_client *client)
137 {
138 	struct ceph_options *opt1 = new_opt;
139 	struct ceph_options *opt2 = client->options;
140 	int ofs = offsetof(struct ceph_options, mon_addr);
141 	int i;
142 	int ret;
143 
144 	/*
145 	 * Don't bother comparing options if network namespaces don't
146 	 * match.
147 	 */
148 	if (!net_eq(current->nsproxy->net_ns, read_pnet(&client->msgr.net)))
149 		return -1;
150 
151 	ret = memcmp(opt1, opt2, ofs);
152 	if (ret)
153 		return ret;
154 
155 	ret = strcmp_null(opt1->name, opt2->name);
156 	if (ret)
157 		return ret;
158 
159 	if (opt1->key && !opt2->key)
160 		return -1;
161 	if (!opt1->key && opt2->key)
162 		return 1;
163 	if (opt1->key && opt2->key) {
164 		if (opt1->key->type != opt2->key->type)
165 			return -1;
166 		if (opt1->key->created.tv_sec != opt2->key->created.tv_sec)
167 			return -1;
168 		if (opt1->key->created.tv_nsec != opt2->key->created.tv_nsec)
169 			return -1;
170 		if (opt1->key->len != opt2->key->len)
171 			return -1;
172 		if (opt1->key->key && !opt2->key->key)
173 			return -1;
174 		if (!opt1->key->key && opt2->key->key)
175 			return 1;
176 		if (opt1->key->key && opt2->key->key) {
177 			ret = memcmp(opt1->key->key, opt2->key->key, opt1->key->len);
178 			if (ret)
179 				return ret;
180 		}
181 	}
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 
193 void *ceph_kvmalloc(size_t size, gfp_t flags)
194 {
195 	if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
196 		void *ptr = kmalloc(size, flags | __GFP_NOWARN);
197 		if (ptr)
198 			return ptr;
199 	}
200 
201 	return __vmalloc(size, flags, PAGE_KERNEL);
202 }
203 
204 
205 static int parse_fsid(const char *str, struct ceph_fsid *fsid)
206 {
207 	int i = 0;
208 	char tmp[3];
209 	int err = -EINVAL;
210 	int d;
211 
212 	dout("parse_fsid '%s'\n", str);
213 	tmp[2] = 0;
214 	while (*str && i < 16) {
215 		if (ispunct(*str)) {
216 			str++;
217 			continue;
218 		}
219 		if (!isxdigit(str[0]) || !isxdigit(str[1]))
220 			break;
221 		tmp[0] = str[0];
222 		tmp[1] = str[1];
223 		if (sscanf(tmp, "%x", &d) < 1)
224 			break;
225 		fsid->fsid[i] = d & 0xff;
226 		i++;
227 		str += 2;
228 	}
229 
230 	if (i == 16)
231 		err = 0;
232 	dout("parse_fsid ret %d got fsid %pU", err, fsid);
233 	return err;
234 }
235 
236 /*
237  * ceph options
238  */
239 enum {
240 	Opt_osdtimeout,
241 	Opt_osdkeepalivetimeout,
242 	Opt_mount_timeout,
243 	Opt_osd_idle_ttl,
244 	Opt_osd_request_timeout,
245 	Opt_last_int,
246 	/* int args above */
247 	Opt_fsid,
248 	Opt_name,
249 	Opt_secret,
250 	Opt_key,
251 	Opt_ip,
252 	Opt_last_string,
253 	/* string args above */
254 	Opt_share,
255 	Opt_noshare,
256 	Opt_crc,
257 	Opt_nocrc,
258 	Opt_cephx_require_signatures,
259 	Opt_nocephx_require_signatures,
260 	Opt_cephx_sign_messages,
261 	Opt_nocephx_sign_messages,
262 	Opt_tcp_nodelay,
263 	Opt_notcp_nodelay,
264 };
265 
266 static match_table_t opt_tokens = {
267 	{Opt_osdtimeout, "osdtimeout=%d"},
268 	{Opt_osdkeepalivetimeout, "osdkeepalive=%d"},
269 	{Opt_mount_timeout, "mount_timeout=%d"},
270 	{Opt_osd_idle_ttl, "osd_idle_ttl=%d"},
271 	{Opt_osd_request_timeout, "osd_request_timeout=%d"},
272 	/* int args above */
273 	{Opt_fsid, "fsid=%s"},
274 	{Opt_name, "name=%s"},
275 	{Opt_secret, "secret=%s"},
276 	{Opt_key, "key=%s"},
277 	{Opt_ip, "ip=%s"},
278 	/* string args above */
279 	{Opt_share, "share"},
280 	{Opt_noshare, "noshare"},
281 	{Opt_crc, "crc"},
282 	{Opt_nocrc, "nocrc"},
283 	{Opt_cephx_require_signatures, "cephx_require_signatures"},
284 	{Opt_nocephx_require_signatures, "nocephx_require_signatures"},
285 	{Opt_cephx_sign_messages, "cephx_sign_messages"},
286 	{Opt_nocephx_sign_messages, "nocephx_sign_messages"},
287 	{Opt_tcp_nodelay, "tcp_nodelay"},
288 	{Opt_notcp_nodelay, "notcp_nodelay"},
289 	{-1, NULL}
290 };
291 
292 void ceph_destroy_options(struct ceph_options *opt)
293 {
294 	dout("destroy_options %p\n", opt);
295 	kfree(opt->name);
296 	if (opt->key) {
297 		ceph_crypto_key_destroy(opt->key);
298 		kfree(opt->key);
299 	}
300 	kfree(opt->mon_addr);
301 	kfree(opt);
302 }
303 EXPORT_SYMBOL(ceph_destroy_options);
304 
305 /* get secret from key store */
306 static int get_secret(struct ceph_crypto_key *dst, const char *name) {
307 	struct key *ukey;
308 	int key_err;
309 	int err = 0;
310 	struct ceph_crypto_key *ckey;
311 
312 	ukey = request_key(&key_type_ceph, name, NULL);
313 	if (!ukey || IS_ERR(ukey)) {
314 		/* request_key errors don't map nicely to mount(2)
315 		   errors; don't even try, but still printk */
316 		key_err = PTR_ERR(ukey);
317 		switch (key_err) {
318 		case -ENOKEY:
319 			pr_warn("ceph: Mount failed due to key not found: %s\n",
320 				name);
321 			break;
322 		case -EKEYEXPIRED:
323 			pr_warn("ceph: Mount failed due to expired key: %s\n",
324 				name);
325 			break;
326 		case -EKEYREVOKED:
327 			pr_warn("ceph: Mount failed due to revoked key: %s\n",
328 				name);
329 			break;
330 		default:
331 			pr_warn("ceph: Mount failed due to unknown key error %d: %s\n",
332 				key_err, name);
333 		}
334 		err = -EPERM;
335 		goto out;
336 	}
337 
338 	ckey = ukey->payload.data[0];
339 	err = ceph_crypto_key_clone(dst, ckey);
340 	if (err)
341 		goto out_key;
342 	/* pass through, err is 0 */
343 
344 out_key:
345 	key_put(ukey);
346 out:
347 	return err;
348 }
349 
350 struct ceph_options *
351 ceph_parse_options(char *options, const char *dev_name,
352 			const char *dev_name_end,
353 			int (*parse_extra_token)(char *c, void *private),
354 			void *private)
355 {
356 	struct ceph_options *opt;
357 	const char *c;
358 	int err = -ENOMEM;
359 	substring_t argstr[MAX_OPT_ARGS];
360 
361 	opt = kzalloc(sizeof(*opt), GFP_KERNEL);
362 	if (!opt)
363 		return ERR_PTR(-ENOMEM);
364 	opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
365 				GFP_KERNEL);
366 	if (!opt->mon_addr)
367 		goto out;
368 
369 	dout("parse_options %p options '%s' dev_name '%s'\n", opt, options,
370 	     dev_name);
371 
372 	/* start with defaults */
373 	opt->flags = CEPH_OPT_DEFAULT;
374 	opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
375 	opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT;
376 	opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT;
377 	opt->osd_request_timeout = CEPH_OSD_REQUEST_TIMEOUT_DEFAULT;
378 
379 	/* get mon ip(s) */
380 	/* ip1[:port1][,ip2[:port2]...] */
381 	err = ceph_parse_ips(dev_name, dev_name_end, opt->mon_addr,
382 			     CEPH_MAX_MON, &opt->num_mon);
383 	if (err < 0)
384 		goto out;
385 
386 	/* parse mount options */
387 	while ((c = strsep(&options, ",")) != NULL) {
388 		int token, intval, ret;
389 		if (!*c)
390 			continue;
391 		err = -EINVAL;
392 		token = match_token((char *)c, opt_tokens, argstr);
393 		if (token < 0 && parse_extra_token) {
394 			/* extra? */
395 			err = parse_extra_token((char *)c, private);
396 			if (err < 0) {
397 				pr_err("bad option at '%s'\n", c);
398 				goto out;
399 			}
400 			continue;
401 		}
402 		if (token < Opt_last_int) {
403 			ret = match_int(&argstr[0], &intval);
404 			if (ret < 0) {
405 				pr_err("bad mount option arg (not int) "
406 				       "at '%s'\n", c);
407 				continue;
408 			}
409 			dout("got int token %d val %d\n", token, intval);
410 		} else if (token > Opt_last_int && token < Opt_last_string) {
411 			dout("got string token %d val %s\n", token,
412 			     argstr[0].from);
413 		} else {
414 			dout("got token %d\n", token);
415 		}
416 		switch (token) {
417 		case Opt_ip:
418 			err = ceph_parse_ips(argstr[0].from,
419 					     argstr[0].to,
420 					     &opt->my_addr,
421 					     1, NULL);
422 			if (err < 0)
423 				goto out;
424 			opt->flags |= CEPH_OPT_MYIP;
425 			break;
426 
427 		case Opt_fsid:
428 			err = parse_fsid(argstr[0].from, &opt->fsid);
429 			if (err == 0)
430 				opt->flags |= CEPH_OPT_FSID;
431 			break;
432 		case Opt_name:
433 			opt->name = kstrndup(argstr[0].from,
434 					      argstr[0].to-argstr[0].from,
435 					      GFP_KERNEL);
436 			break;
437 		case Opt_secret:
438 		        opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
439 			if (!opt->key) {
440 				err = -ENOMEM;
441 				goto out;
442 			}
443 			err = ceph_crypto_key_unarmor(opt->key, argstr[0].from);
444 			if (err < 0)
445 				goto out;
446 			break;
447 		case Opt_key:
448 		        opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
449 			if (!opt->key) {
450 				err = -ENOMEM;
451 				goto out;
452 			}
453 			err = get_secret(opt->key, argstr[0].from);
454 			if (err < 0)
455 				goto out;
456 			break;
457 
458 			/* misc */
459 		case Opt_osdtimeout:
460 			pr_warn("ignoring deprecated osdtimeout option\n");
461 			break;
462 		case Opt_osdkeepalivetimeout:
463 			/* 0 isn't well defined right now, reject it */
464 			if (intval < 1 || intval > INT_MAX / 1000) {
465 				pr_err("osdkeepalive out of range\n");
466 				err = -EINVAL;
467 				goto out;
468 			}
469 			opt->osd_keepalive_timeout =
470 					msecs_to_jiffies(intval * 1000);
471 			break;
472 		case Opt_osd_idle_ttl:
473 			/* 0 isn't well defined right now, reject it */
474 			if (intval < 1 || intval > INT_MAX / 1000) {
475 				pr_err("osd_idle_ttl out of range\n");
476 				err = -EINVAL;
477 				goto out;
478 			}
479 			opt->osd_idle_ttl = msecs_to_jiffies(intval * 1000);
480 			break;
481 		case Opt_mount_timeout:
482 			/* 0 is "wait forever" (i.e. infinite timeout) */
483 			if (intval < 0 || intval > INT_MAX / 1000) {
484 				pr_err("mount_timeout out of range\n");
485 				err = -EINVAL;
486 				goto out;
487 			}
488 			opt->mount_timeout = msecs_to_jiffies(intval * 1000);
489 			break;
490 		case Opt_osd_request_timeout:
491 			/* 0 is "wait forever" (i.e. infinite timeout) */
492 			if (intval < 0 || intval > INT_MAX / 1000) {
493 				pr_err("osd_request_timeout out of range\n");
494 				err = -EINVAL;
495 				goto out;
496 			}
497 			opt->osd_request_timeout = msecs_to_jiffies(intval * 1000);
498 			break;
499 
500 		case Opt_share:
501 			opt->flags &= ~CEPH_OPT_NOSHARE;
502 			break;
503 		case Opt_noshare:
504 			opt->flags |= CEPH_OPT_NOSHARE;
505 			break;
506 
507 		case Opt_crc:
508 			opt->flags &= ~CEPH_OPT_NOCRC;
509 			break;
510 		case Opt_nocrc:
511 			opt->flags |= CEPH_OPT_NOCRC;
512 			break;
513 
514 		case Opt_cephx_require_signatures:
515 			opt->flags &= ~CEPH_OPT_NOMSGAUTH;
516 			break;
517 		case Opt_nocephx_require_signatures:
518 			opt->flags |= CEPH_OPT_NOMSGAUTH;
519 			break;
520 		case Opt_cephx_sign_messages:
521 			opt->flags &= ~CEPH_OPT_NOMSGSIGN;
522 			break;
523 		case Opt_nocephx_sign_messages:
524 			opt->flags |= CEPH_OPT_NOMSGSIGN;
525 			break;
526 
527 		case Opt_tcp_nodelay:
528 			opt->flags |= CEPH_OPT_TCP_NODELAY;
529 			break;
530 		case Opt_notcp_nodelay:
531 			opt->flags &= ~CEPH_OPT_TCP_NODELAY;
532 			break;
533 
534 		default:
535 			BUG_ON(token);
536 		}
537 	}
538 
539 	/* success */
540 	return opt;
541 
542 out:
543 	ceph_destroy_options(opt);
544 	return ERR_PTR(err);
545 }
546 EXPORT_SYMBOL(ceph_parse_options);
547 
548 int ceph_print_client_options(struct seq_file *m, struct ceph_client *client)
549 {
550 	struct ceph_options *opt = client->options;
551 	size_t pos = m->count;
552 
553 	if (opt->name) {
554 		seq_puts(m, "name=");
555 		seq_escape(m, opt->name, ", \t\n\\");
556 		seq_putc(m, ',');
557 	}
558 	if (opt->key)
559 		seq_puts(m, "secret=<hidden>,");
560 
561 	if (opt->flags & CEPH_OPT_FSID)
562 		seq_printf(m, "fsid=%pU,", &opt->fsid);
563 	if (opt->flags & CEPH_OPT_NOSHARE)
564 		seq_puts(m, "noshare,");
565 	if (opt->flags & CEPH_OPT_NOCRC)
566 		seq_puts(m, "nocrc,");
567 	if (opt->flags & CEPH_OPT_NOMSGAUTH)
568 		seq_puts(m, "nocephx_require_signatures,");
569 	if (opt->flags & CEPH_OPT_NOMSGSIGN)
570 		seq_puts(m, "nocephx_sign_messages,");
571 	if ((opt->flags & CEPH_OPT_TCP_NODELAY) == 0)
572 		seq_puts(m, "notcp_nodelay,");
573 
574 	if (opt->mount_timeout != CEPH_MOUNT_TIMEOUT_DEFAULT)
575 		seq_printf(m, "mount_timeout=%d,",
576 			   jiffies_to_msecs(opt->mount_timeout) / 1000);
577 	if (opt->osd_idle_ttl != CEPH_OSD_IDLE_TTL_DEFAULT)
578 		seq_printf(m, "osd_idle_ttl=%d,",
579 			   jiffies_to_msecs(opt->osd_idle_ttl) / 1000);
580 	if (opt->osd_keepalive_timeout != CEPH_OSD_KEEPALIVE_DEFAULT)
581 		seq_printf(m, "osdkeepalivetimeout=%d,",
582 		    jiffies_to_msecs(opt->osd_keepalive_timeout) / 1000);
583 	if (opt->osd_request_timeout != CEPH_OSD_REQUEST_TIMEOUT_DEFAULT)
584 		seq_printf(m, "osd_request_timeout=%d,",
585 			   jiffies_to_msecs(opt->osd_request_timeout) / 1000);
586 
587 	/* drop redundant comma */
588 	if (m->count != pos)
589 		m->count--;
590 
591 	return 0;
592 }
593 EXPORT_SYMBOL(ceph_print_client_options);
594 
595 struct ceph_entity_addr *ceph_client_addr(struct ceph_client *client)
596 {
597 	return &client->msgr.inst.addr;
598 }
599 EXPORT_SYMBOL(ceph_client_addr);
600 
601 u64 ceph_client_gid(struct ceph_client *client)
602 {
603 	return client->monc.auth->global_id;
604 }
605 EXPORT_SYMBOL(ceph_client_gid);
606 
607 /*
608  * create a fresh client instance
609  */
610 struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private)
611 {
612 	struct ceph_client *client;
613 	struct ceph_entity_addr *myaddr = NULL;
614 	int err = -ENOMEM;
615 
616 	client = kzalloc(sizeof(*client), GFP_KERNEL);
617 	if (client == NULL)
618 		return ERR_PTR(-ENOMEM);
619 
620 	client->private = private;
621 	client->options = opt;
622 
623 	mutex_init(&client->mount_mutex);
624 	init_waitqueue_head(&client->auth_wq);
625 	client->auth_err = 0;
626 
627 	client->extra_mon_dispatch = NULL;
628 	client->supported_features = CEPH_FEATURES_SUPPORTED_DEFAULT;
629 	client->required_features = CEPH_FEATURES_REQUIRED_DEFAULT;
630 
631 	if (!ceph_test_opt(client, NOMSGAUTH))
632 		client->required_features |= CEPH_FEATURE_MSG_AUTH;
633 
634 	/* msgr */
635 	if (ceph_test_opt(client, MYIP))
636 		myaddr = &client->options->my_addr;
637 
638 	ceph_messenger_init(&client->msgr, myaddr);
639 
640 	/* subsystems */
641 	err = ceph_monc_init(&client->monc, client);
642 	if (err < 0)
643 		goto fail;
644 	err = ceph_osdc_init(&client->osdc, client);
645 	if (err < 0)
646 		goto fail_monc;
647 
648 	return client;
649 
650 fail_monc:
651 	ceph_monc_stop(&client->monc);
652 fail:
653 	ceph_messenger_fini(&client->msgr);
654 	kfree(client);
655 	return ERR_PTR(err);
656 }
657 EXPORT_SYMBOL(ceph_create_client);
658 
659 void ceph_destroy_client(struct ceph_client *client)
660 {
661 	dout("destroy_client %p\n", client);
662 
663 	atomic_set(&client->msgr.stopping, 1);
664 
665 	/* unmount */
666 	ceph_osdc_stop(&client->osdc);
667 	ceph_monc_stop(&client->monc);
668 	ceph_messenger_fini(&client->msgr);
669 
670 	ceph_debugfs_client_cleanup(client);
671 
672 	ceph_destroy_options(client->options);
673 
674 	kfree(client);
675 	dout("destroy_client %p done\n", client);
676 }
677 EXPORT_SYMBOL(ceph_destroy_client);
678 
679 /*
680  * true if we have the mon map (and have thus joined the cluster)
681  */
682 static bool have_mon_and_osd_map(struct ceph_client *client)
683 {
684 	return client->monc.monmap && client->monc.monmap->epoch &&
685 	       client->osdc.osdmap && client->osdc.osdmap->epoch;
686 }
687 
688 /*
689  * mount: join the ceph cluster, and open root directory.
690  */
691 int __ceph_open_session(struct ceph_client *client, unsigned long started)
692 {
693 	unsigned long timeout = client->options->mount_timeout;
694 	long err;
695 
696 	/* open session, and wait for mon and osd maps */
697 	err = ceph_monc_open_session(&client->monc);
698 	if (err < 0)
699 		return err;
700 
701 	while (!have_mon_and_osd_map(client)) {
702 		if (timeout && time_after_eq(jiffies, started + timeout))
703 			return -ETIMEDOUT;
704 
705 		/* wait */
706 		dout("mount waiting for mon_map\n");
707 		err = wait_event_interruptible_timeout(client->auth_wq,
708 			have_mon_and_osd_map(client) || (client->auth_err < 0),
709 			ceph_timeout_jiffies(timeout));
710 		if (err < 0)
711 			return err;
712 		if (client->auth_err < 0)
713 			return client->auth_err;
714 	}
715 
716 	pr_info("client%llu fsid %pU\n", ceph_client_gid(client),
717 		&client->fsid);
718 	ceph_debugfs_client_init(client);
719 
720 	return 0;
721 }
722 EXPORT_SYMBOL(__ceph_open_session);
723 
724 
725 int ceph_open_session(struct ceph_client *client)
726 {
727 	int ret;
728 	unsigned long started = jiffies;  /* note the start time */
729 
730 	dout("open_session start\n");
731 	mutex_lock(&client->mount_mutex);
732 
733 	ret = __ceph_open_session(client, started);
734 
735 	mutex_unlock(&client->mount_mutex);
736 	return ret;
737 }
738 EXPORT_SYMBOL(ceph_open_session);
739 
740 
741 static int __init init_ceph_lib(void)
742 {
743 	int ret = 0;
744 
745 	ret = ceph_debugfs_init();
746 	if (ret < 0)
747 		goto out;
748 
749 	ret = ceph_crypto_init();
750 	if (ret < 0)
751 		goto out_debugfs;
752 
753 	ret = ceph_msgr_init();
754 	if (ret < 0)
755 		goto out_crypto;
756 
757 	ret = ceph_osdc_setup();
758 	if (ret < 0)
759 		goto out_msgr;
760 
761 	pr_info("loaded (mon/osd proto %d/%d)\n",
762 		CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL);
763 
764 	return 0;
765 
766 out_msgr:
767 	ceph_msgr_exit();
768 out_crypto:
769 	ceph_crypto_shutdown();
770 out_debugfs:
771 	ceph_debugfs_cleanup();
772 out:
773 	return ret;
774 }
775 
776 static void __exit exit_ceph_lib(void)
777 {
778 	dout("exit_ceph_lib\n");
779 	WARN_ON(!ceph_strings_empty());
780 
781 	ceph_osdc_cleanup();
782 	ceph_msgr_exit();
783 	ceph_crypto_shutdown();
784 	ceph_debugfs_cleanup();
785 }
786 
787 module_init(init_ceph_lib);
788 module_exit(exit_ceph_lib);
789 
790 MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
791 MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
792 MODULE_AUTHOR("Patience Warnick <patience@newdream.net>");
793 MODULE_DESCRIPTION("Ceph core library");
794 MODULE_LICENSE("GPL");
795