Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/ceph/ceph_common.c
15109 views
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
19
20
#include <linux/ceph/libceph.h>
21
#include <linux/ceph/debugfs.h>
22
#include <linux/ceph/decode.h>
23
#include <linux/ceph/mon_client.h>
24
#include <linux/ceph/auth.h>
25
#include "crypto.h"
26
27
28
29
/*
30
* find filename portion of a path (/foo/bar/baz -> baz)
31
*/
32
const char *ceph_file_part(const char *s, int len)
33
{
34
const char *e = s + len;
35
36
while (e != s && *(e-1) != '/')
37
e--;
38
return e;
39
}
40
EXPORT_SYMBOL(ceph_file_part);
41
42
const char *ceph_msg_type_name(int type)
43
{
44
switch (type) {
45
case CEPH_MSG_SHUTDOWN: return "shutdown";
46
case CEPH_MSG_PING: return "ping";
47
case CEPH_MSG_AUTH: return "auth";
48
case CEPH_MSG_AUTH_REPLY: return "auth_reply";
49
case CEPH_MSG_MON_MAP: return "mon_map";
50
case CEPH_MSG_MON_GET_MAP: return "mon_get_map";
51
case CEPH_MSG_MON_SUBSCRIBE: return "mon_subscribe";
52
case CEPH_MSG_MON_SUBSCRIBE_ACK: return "mon_subscribe_ack";
53
case CEPH_MSG_STATFS: return "statfs";
54
case CEPH_MSG_STATFS_REPLY: return "statfs_reply";
55
case CEPH_MSG_MDS_MAP: return "mds_map";
56
case CEPH_MSG_CLIENT_SESSION: return "client_session";
57
case CEPH_MSG_CLIENT_RECONNECT: return "client_reconnect";
58
case CEPH_MSG_CLIENT_REQUEST: return "client_request";
59
case CEPH_MSG_CLIENT_REQUEST_FORWARD: return "client_request_forward";
60
case CEPH_MSG_CLIENT_REPLY: return "client_reply";
61
case CEPH_MSG_CLIENT_CAPS: return "client_caps";
62
case CEPH_MSG_CLIENT_CAPRELEASE: return "client_cap_release";
63
case CEPH_MSG_CLIENT_SNAP: return "client_snap";
64
case CEPH_MSG_CLIENT_LEASE: return "client_lease";
65
case CEPH_MSG_OSD_MAP: return "osd_map";
66
case CEPH_MSG_OSD_OP: return "osd_op";
67
case CEPH_MSG_OSD_OPREPLY: return "osd_opreply";
68
case CEPH_MSG_WATCH_NOTIFY: return "watch_notify";
69
default: return "unknown";
70
}
71
}
72
EXPORT_SYMBOL(ceph_msg_type_name);
73
74
/*
75
* Initially learn our fsid, or verify an fsid matches.
76
*/
77
int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid)
78
{
79
if (client->have_fsid) {
80
if (ceph_fsid_compare(&client->fsid, fsid)) {
81
pr_err("bad fsid, had %pU got %pU",
82
&client->fsid, fsid);
83
return -1;
84
}
85
} else {
86
pr_info("client%lld fsid %pU\n", ceph_client_id(client), fsid);
87
memcpy(&client->fsid, fsid, sizeof(*fsid));
88
ceph_debugfs_client_init(client);
89
client->have_fsid = true;
90
}
91
return 0;
92
}
93
EXPORT_SYMBOL(ceph_check_fsid);
94
95
static int strcmp_null(const char *s1, const char *s2)
96
{
97
if (!s1 && !s2)
98
return 0;
99
if (s1 && !s2)
100
return -1;
101
if (!s1 && s2)
102
return 1;
103
return strcmp(s1, s2);
104
}
105
106
int ceph_compare_options(struct ceph_options *new_opt,
107
struct ceph_client *client)
108
{
109
struct ceph_options *opt1 = new_opt;
110
struct ceph_options *opt2 = client->options;
111
int ofs = offsetof(struct ceph_options, mon_addr);
112
int i;
113
int ret;
114
115
ret = memcmp(opt1, opt2, ofs);
116
if (ret)
117
return ret;
118
119
ret = strcmp_null(opt1->name, opt2->name);
120
if (ret)
121
return ret;
122
123
if (opt1->key && !opt2->key)
124
return -1;
125
if (!opt1->key && opt2->key)
126
return 1;
127
if (opt1->key && opt2->key) {
128
if (opt1->key->type != opt2->key->type)
129
return -1;
130
if (opt1->key->created.tv_sec != opt2->key->created.tv_sec)
131
return -1;
132
if (opt1->key->created.tv_nsec != opt2->key->created.tv_nsec)
133
return -1;
134
if (opt1->key->len != opt2->key->len)
135
return -1;
136
if (opt1->key->key && !opt2->key->key)
137
return -1;
138
if (!opt1->key->key && opt2->key->key)
139
return 1;
140
if (opt1->key->key && opt2->key->key) {
141
ret = memcmp(opt1->key->key, opt2->key->key, opt1->key->len);
142
if (ret)
143
return ret;
144
}
145
}
146
147
/* any matching mon ip implies a match */
148
for (i = 0; i < opt1->num_mon; i++) {
149
if (ceph_monmap_contains(client->monc.monmap,
150
&opt1->mon_addr[i]))
151
return 0;
152
}
153
return -1;
154
}
155
EXPORT_SYMBOL(ceph_compare_options);
156
157
158
static int parse_fsid(const char *str, struct ceph_fsid *fsid)
159
{
160
int i = 0;
161
char tmp[3];
162
int err = -EINVAL;
163
int d;
164
165
dout("parse_fsid '%s'\n", str);
166
tmp[2] = 0;
167
while (*str && i < 16) {
168
if (ispunct(*str)) {
169
str++;
170
continue;
171
}
172
if (!isxdigit(str[0]) || !isxdigit(str[1]))
173
break;
174
tmp[0] = str[0];
175
tmp[1] = str[1];
176
if (sscanf(tmp, "%x", &d) < 1)
177
break;
178
fsid->fsid[i] = d & 0xff;
179
i++;
180
str += 2;
181
}
182
183
if (i == 16)
184
err = 0;
185
dout("parse_fsid ret %d got fsid %pU", err, fsid);
186
return err;
187
}
188
189
/*
190
* ceph options
191
*/
192
enum {
193
Opt_osdtimeout,
194
Opt_osdkeepalivetimeout,
195
Opt_mount_timeout,
196
Opt_osd_idle_ttl,
197
Opt_last_int,
198
/* int args above */
199
Opt_fsid,
200
Opt_name,
201
Opt_secret,
202
Opt_key,
203
Opt_ip,
204
Opt_last_string,
205
/* string args above */
206
Opt_noshare,
207
Opt_nocrc,
208
};
209
210
static match_table_t opt_tokens = {
211
{Opt_osdtimeout, "osdtimeout=%d"},
212
{Opt_osdkeepalivetimeout, "osdkeepalive=%d"},
213
{Opt_mount_timeout, "mount_timeout=%d"},
214
{Opt_osd_idle_ttl, "osd_idle_ttl=%d"},
215
/* int args above */
216
{Opt_fsid, "fsid=%s"},
217
{Opt_name, "name=%s"},
218
{Opt_secret, "secret=%s"},
219
{Opt_key, "key=%s"},
220
{Opt_ip, "ip=%s"},
221
/* string args above */
222
{Opt_noshare, "noshare"},
223
{Opt_nocrc, "nocrc"},
224
{-1, NULL}
225
};
226
227
void ceph_destroy_options(struct ceph_options *opt)
228
{
229
dout("destroy_options %p\n", opt);
230
kfree(opt->name);
231
if (opt->key) {
232
ceph_crypto_key_destroy(opt->key);
233
kfree(opt->key);
234
}
235
kfree(opt);
236
}
237
EXPORT_SYMBOL(ceph_destroy_options);
238
239
/* get secret from key store */
240
static int get_secret(struct ceph_crypto_key *dst, const char *name) {
241
struct key *ukey;
242
int key_err;
243
int err = 0;
244
struct ceph_crypto_key *ckey;
245
246
ukey = request_key(&key_type_ceph, name, NULL);
247
if (!ukey || IS_ERR(ukey)) {
248
/* request_key errors don't map nicely to mount(2)
249
errors; don't even try, but still printk */
250
key_err = PTR_ERR(ukey);
251
switch (key_err) {
252
case -ENOKEY:
253
pr_warning("ceph: Mount failed due to key not found: %s\n", name);
254
break;
255
case -EKEYEXPIRED:
256
pr_warning("ceph: Mount failed due to expired key: %s\n", name);
257
break;
258
case -EKEYREVOKED:
259
pr_warning("ceph: Mount failed due to revoked key: %s\n", name);
260
break;
261
default:
262
pr_warning("ceph: Mount failed due to unknown key error"
263
" %d: %s\n", key_err, name);
264
}
265
err = -EPERM;
266
goto out;
267
}
268
269
ckey = ukey->payload.data;
270
err = ceph_crypto_key_clone(dst, ckey);
271
if (err)
272
goto out_key;
273
/* pass through, err is 0 */
274
275
out_key:
276
key_put(ukey);
277
out:
278
return err;
279
}
280
281
int ceph_parse_options(struct ceph_options **popt, char *options,
282
const char *dev_name, const char *dev_name_end,
283
int (*parse_extra_token)(char *c, void *private),
284
void *private)
285
{
286
struct ceph_options *opt;
287
const char *c;
288
int err = -ENOMEM;
289
substring_t argstr[MAX_OPT_ARGS];
290
291
opt = kzalloc(sizeof(*opt), GFP_KERNEL);
292
if (!opt)
293
return err;
294
opt->mon_addr = kcalloc(CEPH_MAX_MON, sizeof(*opt->mon_addr),
295
GFP_KERNEL);
296
if (!opt->mon_addr)
297
goto out;
298
299
dout("parse_options %p options '%s' dev_name '%s'\n", opt, options,
300
dev_name);
301
302
/* start with defaults */
303
opt->flags = CEPH_OPT_DEFAULT;
304
opt->osd_timeout = CEPH_OSD_TIMEOUT_DEFAULT;
305
opt->osd_keepalive_timeout = CEPH_OSD_KEEPALIVE_DEFAULT;
306
opt->mount_timeout = CEPH_MOUNT_TIMEOUT_DEFAULT; /* seconds */
307
opt->osd_idle_ttl = CEPH_OSD_IDLE_TTL_DEFAULT; /* seconds */
308
309
/* get mon ip(s) */
310
/* ip1[:port1][,ip2[:port2]...] */
311
err = ceph_parse_ips(dev_name, dev_name_end, opt->mon_addr,
312
CEPH_MAX_MON, &opt->num_mon);
313
if (err < 0)
314
goto out;
315
316
/* parse mount options */
317
while ((c = strsep(&options, ",")) != NULL) {
318
int token, intval, ret;
319
if (!*c)
320
continue;
321
err = -EINVAL;
322
token = match_token((char *)c, opt_tokens, argstr);
323
if (token < 0 && parse_extra_token) {
324
/* extra? */
325
err = parse_extra_token((char *)c, private);
326
if (err < 0) {
327
pr_err("bad option at '%s'\n", c);
328
goto out;
329
}
330
continue;
331
}
332
if (token < Opt_last_int) {
333
ret = match_int(&argstr[0], &intval);
334
if (ret < 0) {
335
pr_err("bad mount option arg (not int) "
336
"at '%s'\n", c);
337
continue;
338
}
339
dout("got int token %d val %d\n", token, intval);
340
} else if (token > Opt_last_int && token < Opt_last_string) {
341
dout("got string token %d val %s\n", token,
342
argstr[0].from);
343
} else {
344
dout("got token %d\n", token);
345
}
346
switch (token) {
347
case Opt_ip:
348
err = ceph_parse_ips(argstr[0].from,
349
argstr[0].to,
350
&opt->my_addr,
351
1, NULL);
352
if (err < 0)
353
goto out;
354
opt->flags |= CEPH_OPT_MYIP;
355
break;
356
357
case Opt_fsid:
358
err = parse_fsid(argstr[0].from, &opt->fsid);
359
if (err == 0)
360
opt->flags |= CEPH_OPT_FSID;
361
break;
362
case Opt_name:
363
opt->name = kstrndup(argstr[0].from,
364
argstr[0].to-argstr[0].from,
365
GFP_KERNEL);
366
break;
367
case Opt_secret:
368
opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
369
if (!opt->key) {
370
err = -ENOMEM;
371
goto out;
372
}
373
err = ceph_crypto_key_unarmor(opt->key, argstr[0].from);
374
if (err < 0)
375
goto out;
376
break;
377
case Opt_key:
378
opt->key = kzalloc(sizeof(*opt->key), GFP_KERNEL);
379
if (!opt->key) {
380
err = -ENOMEM;
381
goto out;
382
}
383
err = get_secret(opt->key, argstr[0].from);
384
if (err < 0)
385
goto out;
386
break;
387
388
/* misc */
389
case Opt_osdtimeout:
390
opt->osd_timeout = intval;
391
break;
392
case Opt_osdkeepalivetimeout:
393
opt->osd_keepalive_timeout = intval;
394
break;
395
case Opt_osd_idle_ttl:
396
opt->osd_idle_ttl = intval;
397
break;
398
case Opt_mount_timeout:
399
opt->mount_timeout = intval;
400
break;
401
402
case Opt_noshare:
403
opt->flags |= CEPH_OPT_NOSHARE;
404
break;
405
406
case Opt_nocrc:
407
opt->flags |= CEPH_OPT_NOCRC;
408
break;
409
410
default:
411
BUG_ON(token);
412
}
413
}
414
415
/* success */
416
*popt = opt;
417
return 0;
418
419
out:
420
ceph_destroy_options(opt);
421
return err;
422
}
423
EXPORT_SYMBOL(ceph_parse_options);
424
425
u64 ceph_client_id(struct ceph_client *client)
426
{
427
return client->monc.auth->global_id;
428
}
429
EXPORT_SYMBOL(ceph_client_id);
430
431
/*
432
* create a fresh client instance
433
*/
434
struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private)
435
{
436
struct ceph_client *client;
437
int err = -ENOMEM;
438
439
client = kzalloc(sizeof(*client), GFP_KERNEL);
440
if (client == NULL)
441
return ERR_PTR(-ENOMEM);
442
443
client->private = private;
444
client->options = opt;
445
446
mutex_init(&client->mount_mutex);
447
init_waitqueue_head(&client->auth_wq);
448
client->auth_err = 0;
449
450
client->extra_mon_dispatch = NULL;
451
client->supported_features = CEPH_FEATURE_SUPPORTED_DEFAULT;
452
client->required_features = CEPH_FEATURE_REQUIRED_DEFAULT;
453
454
client->msgr = NULL;
455
456
/* subsystems */
457
err = ceph_monc_init(&client->monc, client);
458
if (err < 0)
459
goto fail;
460
err = ceph_osdc_init(&client->osdc, client);
461
if (err < 0)
462
goto fail_monc;
463
464
return client;
465
466
fail_monc:
467
ceph_monc_stop(&client->monc);
468
fail:
469
kfree(client);
470
return ERR_PTR(err);
471
}
472
EXPORT_SYMBOL(ceph_create_client);
473
474
void ceph_destroy_client(struct ceph_client *client)
475
{
476
dout("destroy_client %p\n", client);
477
478
/* unmount */
479
ceph_osdc_stop(&client->osdc);
480
481
/*
482
* make sure osd connections close out before destroying the
483
* auth module, which is needed to free those connections'
484
* ceph_authorizers.
485
*/
486
ceph_msgr_flush();
487
488
ceph_monc_stop(&client->monc);
489
490
ceph_debugfs_client_cleanup(client);
491
492
if (client->msgr)
493
ceph_messenger_destroy(client->msgr);
494
495
ceph_destroy_options(client->options);
496
497
kfree(client);
498
dout("destroy_client %p done\n", client);
499
}
500
EXPORT_SYMBOL(ceph_destroy_client);
501
502
/*
503
* true if we have the mon map (and have thus joined the cluster)
504
*/
505
static int have_mon_and_osd_map(struct ceph_client *client)
506
{
507
return client->monc.monmap && client->monc.monmap->epoch &&
508
client->osdc.osdmap && client->osdc.osdmap->epoch;
509
}
510
511
/*
512
* mount: join the ceph cluster, and open root directory.
513
*/
514
int __ceph_open_session(struct ceph_client *client, unsigned long started)
515
{
516
struct ceph_entity_addr *myaddr = NULL;
517
int err;
518
unsigned long timeout = client->options->mount_timeout * HZ;
519
520
/* initialize the messenger */
521
if (client->msgr == NULL) {
522
if (ceph_test_opt(client, MYIP))
523
myaddr = &client->options->my_addr;
524
client->msgr = ceph_messenger_create(myaddr,
525
client->supported_features,
526
client->required_features);
527
if (IS_ERR(client->msgr)) {
528
client->msgr = NULL;
529
return PTR_ERR(client->msgr);
530
}
531
client->msgr->nocrc = ceph_test_opt(client, NOCRC);
532
}
533
534
/* open session, and wait for mon and osd maps */
535
err = ceph_monc_open_session(&client->monc);
536
if (err < 0)
537
return err;
538
539
while (!have_mon_and_osd_map(client)) {
540
err = -EIO;
541
if (timeout && time_after_eq(jiffies, started + timeout))
542
return err;
543
544
/* wait */
545
dout("mount waiting for mon_map\n");
546
err = wait_event_interruptible_timeout(client->auth_wq,
547
have_mon_and_osd_map(client) || (client->auth_err < 0),
548
timeout);
549
if (err == -EINTR || err == -ERESTARTSYS)
550
return err;
551
if (client->auth_err < 0)
552
return client->auth_err;
553
}
554
555
return 0;
556
}
557
EXPORT_SYMBOL(__ceph_open_session);
558
559
560
int ceph_open_session(struct ceph_client *client)
561
{
562
int ret;
563
unsigned long started = jiffies; /* note the start time */
564
565
dout("open_session start\n");
566
mutex_lock(&client->mount_mutex);
567
568
ret = __ceph_open_session(client, started);
569
570
mutex_unlock(&client->mount_mutex);
571
return ret;
572
}
573
EXPORT_SYMBOL(ceph_open_session);
574
575
576
static int __init init_ceph_lib(void)
577
{
578
int ret = 0;
579
580
ret = ceph_debugfs_init();
581
if (ret < 0)
582
goto out;
583
584
ret = ceph_crypto_init();
585
if (ret < 0)
586
goto out_debugfs;
587
588
ret = ceph_msgr_init();
589
if (ret < 0)
590
goto out_crypto;
591
592
pr_info("loaded (mon/osd proto %d/%d, osdmap %d/%d %d/%d)\n",
593
CEPH_MONC_PROTOCOL, CEPH_OSDC_PROTOCOL,
594
CEPH_OSDMAP_VERSION, CEPH_OSDMAP_VERSION_EXT,
595
CEPH_OSDMAP_INC_VERSION, CEPH_OSDMAP_INC_VERSION_EXT);
596
597
return 0;
598
599
out_crypto:
600
ceph_crypto_shutdown();
601
out_debugfs:
602
ceph_debugfs_cleanup();
603
out:
604
return ret;
605
}
606
607
static void __exit exit_ceph_lib(void)
608
{
609
dout("exit_ceph_lib\n");
610
ceph_msgr_exit();
611
ceph_crypto_shutdown();
612
ceph_debugfs_cleanup();
613
}
614
615
module_init(init_ceph_lib);
616
module_exit(exit_ceph_lib);
617
618
MODULE_AUTHOR("Sage Weil <[email protected]>");
619
MODULE_AUTHOR("Yehuda Sadeh <[email protected]>");
620
MODULE_AUTHOR("Patience Warnick <[email protected]>");
621
MODULE_DESCRIPTION("Ceph filesystem for Linux");
622
MODULE_LICENSE("GPL");
623
624