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