xref: /openbmc/linux/net/ceph/cls_lock_client.c (revision dc915ecd)
1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2f66241cbSDouglas Fuller #include <linux/ceph/ceph_debug.h>
3f66241cbSDouglas Fuller 
4f66241cbSDouglas Fuller #include <linux/types.h>
5f66241cbSDouglas Fuller #include <linux/slab.h>
6f66241cbSDouglas Fuller 
7f66241cbSDouglas Fuller #include <linux/ceph/cls_lock_client.h>
8f66241cbSDouglas Fuller #include <linux/ceph/decode.h>
922e8bd51SIlya Dryomov #include <linux/ceph/libceph.h>
10f66241cbSDouglas Fuller 
11f66241cbSDouglas Fuller /**
12f66241cbSDouglas Fuller  * ceph_cls_lock - grab rados lock for object
13*dc915ecdSBaokun Li  * @osdc: OSD client instance
14*dc915ecdSBaokun Li  * @oid: object to lock
15*dc915ecdSBaokun Li  * @oloc: object to lock
16f66241cbSDouglas Fuller  * @lock_name: the name of the lock
17f66241cbSDouglas Fuller  * @type: lock type (CEPH_CLS_LOCK_EXCLUSIVE or CEPH_CLS_LOCK_SHARED)
18f66241cbSDouglas Fuller  * @cookie: user-defined identifier for this instance of the lock
19f66241cbSDouglas Fuller  * @tag: user-defined tag
20f66241cbSDouglas Fuller  * @desc: user-defined lock description
21f66241cbSDouglas Fuller  * @flags: lock flags
22f66241cbSDouglas Fuller  *
23f66241cbSDouglas Fuller  * All operations on the same lock should use the same tag.
24f66241cbSDouglas Fuller  */
ceph_cls_lock(struct ceph_osd_client * osdc,struct ceph_object_id * oid,struct ceph_object_locator * oloc,char * lock_name,u8 type,char * cookie,char * tag,char * desc,u8 flags)25f66241cbSDouglas Fuller int ceph_cls_lock(struct ceph_osd_client *osdc,
26f66241cbSDouglas Fuller 		  struct ceph_object_id *oid,
27f66241cbSDouglas Fuller 		  struct ceph_object_locator *oloc,
28f66241cbSDouglas Fuller 		  char *lock_name, u8 type, char *cookie,
29f66241cbSDouglas Fuller 		  char *tag, char *desc, u8 flags)
30f66241cbSDouglas Fuller {
31f66241cbSDouglas Fuller 	int lock_op_buf_size;
32f66241cbSDouglas Fuller 	int name_len = strlen(lock_name);
33f66241cbSDouglas Fuller 	int cookie_len = strlen(cookie);
34f66241cbSDouglas Fuller 	int tag_len = strlen(tag);
35f66241cbSDouglas Fuller 	int desc_len = strlen(desc);
36f66241cbSDouglas Fuller 	void *p, *end;
37f66241cbSDouglas Fuller 	struct page *lock_op_page;
38473bd2d7SArnd Bergmann 	struct timespec64 mtime;
39f66241cbSDouglas Fuller 	int ret;
40f66241cbSDouglas Fuller 
41f66241cbSDouglas Fuller 	lock_op_buf_size = name_len + sizeof(__le32) +
42f66241cbSDouglas Fuller 			   cookie_len + sizeof(__le32) +
43f66241cbSDouglas Fuller 			   tag_len + sizeof(__le32) +
44f66241cbSDouglas Fuller 			   desc_len + sizeof(__le32) +
45f66241cbSDouglas Fuller 			   sizeof(struct ceph_timespec) +
46f66241cbSDouglas Fuller 			   /* flag and type */
47f66241cbSDouglas Fuller 			   sizeof(u8) + sizeof(u8) +
48f66241cbSDouglas Fuller 			   CEPH_ENCODING_START_BLK_LEN;
49f66241cbSDouglas Fuller 	if (lock_op_buf_size > PAGE_SIZE)
50f66241cbSDouglas Fuller 		return -E2BIG;
51f66241cbSDouglas Fuller 
52f66241cbSDouglas Fuller 	lock_op_page = alloc_page(GFP_NOIO);
53f66241cbSDouglas Fuller 	if (!lock_op_page)
54f66241cbSDouglas Fuller 		return -ENOMEM;
55f66241cbSDouglas Fuller 
56f66241cbSDouglas Fuller 	p = page_address(lock_op_page);
57f66241cbSDouglas Fuller 	end = p + lock_op_buf_size;
58f66241cbSDouglas Fuller 
59f66241cbSDouglas Fuller 	/* encode cls_lock_lock_op struct */
60f66241cbSDouglas Fuller 	ceph_start_encoding(&p, 1, 1,
61f66241cbSDouglas Fuller 			    lock_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
62f66241cbSDouglas Fuller 	ceph_encode_string(&p, end, lock_name, name_len);
63f66241cbSDouglas Fuller 	ceph_encode_8(&p, type);
64f66241cbSDouglas Fuller 	ceph_encode_string(&p, end, cookie, cookie_len);
65f66241cbSDouglas Fuller 	ceph_encode_string(&p, end, tag, tag_len);
66f66241cbSDouglas Fuller 	ceph_encode_string(&p, end, desc, desc_len);
67f66241cbSDouglas Fuller 	/* only support infinite duration */
68f66241cbSDouglas Fuller 	memset(&mtime, 0, sizeof(mtime));
69473bd2d7SArnd Bergmann 	ceph_encode_timespec64(p, &mtime);
70f66241cbSDouglas Fuller 	p += sizeof(struct ceph_timespec);
71f66241cbSDouglas Fuller 	ceph_encode_8(&p, flags);
72f66241cbSDouglas Fuller 
73f66241cbSDouglas Fuller 	dout("%s lock_name %s type %d cookie %s tag %s desc %s flags 0x%x\n",
74f66241cbSDouglas Fuller 	     __func__, lock_name, type, cookie, tag, desc, flags);
75f66241cbSDouglas Fuller 	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "lock",
7654ea0046SIlya Dryomov 			     CEPH_OSD_FLAG_WRITE, lock_op_page,
7754ea0046SIlya Dryomov 			     lock_op_buf_size, NULL, NULL);
78f66241cbSDouglas Fuller 
79f66241cbSDouglas Fuller 	dout("%s: status %d\n", __func__, ret);
80f66241cbSDouglas Fuller 	__free_page(lock_op_page);
81f66241cbSDouglas Fuller 	return ret;
82f66241cbSDouglas Fuller }
83f66241cbSDouglas Fuller EXPORT_SYMBOL(ceph_cls_lock);
84f66241cbSDouglas Fuller 
85f66241cbSDouglas Fuller /**
86f66241cbSDouglas Fuller  * ceph_cls_unlock - release rados lock for object
87*dc915ecdSBaokun Li  * @osdc: OSD client instance
88*dc915ecdSBaokun Li  * @oid: object to lock
89*dc915ecdSBaokun Li  * @oloc: object to lock
90f66241cbSDouglas Fuller  * @lock_name: the name of the lock
91f66241cbSDouglas Fuller  * @cookie: user-defined identifier for this instance of the lock
92f66241cbSDouglas Fuller  */
ceph_cls_unlock(struct ceph_osd_client * osdc,struct ceph_object_id * oid,struct ceph_object_locator * oloc,char * lock_name,char * cookie)93f66241cbSDouglas Fuller int ceph_cls_unlock(struct ceph_osd_client *osdc,
94f66241cbSDouglas Fuller 		    struct ceph_object_id *oid,
95f66241cbSDouglas Fuller 		    struct ceph_object_locator *oloc,
96f66241cbSDouglas Fuller 		    char *lock_name, char *cookie)
97f66241cbSDouglas Fuller {
98f66241cbSDouglas Fuller 	int unlock_op_buf_size;
99f66241cbSDouglas Fuller 	int name_len = strlen(lock_name);
100f66241cbSDouglas Fuller 	int cookie_len = strlen(cookie);
101f66241cbSDouglas Fuller 	void *p, *end;
102f66241cbSDouglas Fuller 	struct page *unlock_op_page;
103f66241cbSDouglas Fuller 	int ret;
104f66241cbSDouglas Fuller 
105f66241cbSDouglas Fuller 	unlock_op_buf_size = name_len + sizeof(__le32) +
106f66241cbSDouglas Fuller 			     cookie_len + sizeof(__le32) +
107f66241cbSDouglas Fuller 			     CEPH_ENCODING_START_BLK_LEN;
108f66241cbSDouglas Fuller 	if (unlock_op_buf_size > PAGE_SIZE)
109f66241cbSDouglas Fuller 		return -E2BIG;
110f66241cbSDouglas Fuller 
111f66241cbSDouglas Fuller 	unlock_op_page = alloc_page(GFP_NOIO);
112f66241cbSDouglas Fuller 	if (!unlock_op_page)
113f66241cbSDouglas Fuller 		return -ENOMEM;
114f66241cbSDouglas Fuller 
115f66241cbSDouglas Fuller 	p = page_address(unlock_op_page);
116f66241cbSDouglas Fuller 	end = p + unlock_op_buf_size;
117f66241cbSDouglas Fuller 
118f66241cbSDouglas Fuller 	/* encode cls_lock_unlock_op struct */
119f66241cbSDouglas Fuller 	ceph_start_encoding(&p, 1, 1,
120f66241cbSDouglas Fuller 			    unlock_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
121f66241cbSDouglas Fuller 	ceph_encode_string(&p, end, lock_name, name_len);
122f66241cbSDouglas Fuller 	ceph_encode_string(&p, end, cookie, cookie_len);
123f66241cbSDouglas Fuller 
124f66241cbSDouglas Fuller 	dout("%s lock_name %s cookie %s\n", __func__, lock_name, cookie);
125f66241cbSDouglas Fuller 	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "unlock",
12654ea0046SIlya Dryomov 			     CEPH_OSD_FLAG_WRITE, unlock_op_page,
12754ea0046SIlya Dryomov 			     unlock_op_buf_size, NULL, NULL);
128f66241cbSDouglas Fuller 
129f66241cbSDouglas Fuller 	dout("%s: status %d\n", __func__, ret);
130f66241cbSDouglas Fuller 	__free_page(unlock_op_page);
131f66241cbSDouglas Fuller 	return ret;
132f66241cbSDouglas Fuller }
133f66241cbSDouglas Fuller EXPORT_SYMBOL(ceph_cls_unlock);
134f66241cbSDouglas Fuller 
135f66241cbSDouglas Fuller /**
136f66241cbSDouglas Fuller  * ceph_cls_break_lock - release rados lock for object for specified client
137*dc915ecdSBaokun Li  * @osdc: OSD client instance
138*dc915ecdSBaokun Li  * @oid: object to lock
139*dc915ecdSBaokun Li  * @oloc: object to lock
140f66241cbSDouglas Fuller  * @lock_name: the name of the lock
141f66241cbSDouglas Fuller  * @cookie: user-defined identifier for this instance of the lock
142f66241cbSDouglas Fuller  * @locker: current lock owner
143f66241cbSDouglas Fuller  */
ceph_cls_break_lock(struct ceph_osd_client * osdc,struct ceph_object_id * oid,struct ceph_object_locator * oloc,char * lock_name,char * cookie,struct ceph_entity_name * locker)144f66241cbSDouglas Fuller int ceph_cls_break_lock(struct ceph_osd_client *osdc,
145f66241cbSDouglas Fuller 			struct ceph_object_id *oid,
146f66241cbSDouglas Fuller 			struct ceph_object_locator *oloc,
147f66241cbSDouglas Fuller 			char *lock_name, char *cookie,
148f66241cbSDouglas Fuller 			struct ceph_entity_name *locker)
149f66241cbSDouglas Fuller {
150f66241cbSDouglas Fuller 	int break_op_buf_size;
151f66241cbSDouglas Fuller 	int name_len = strlen(lock_name);
152f66241cbSDouglas Fuller 	int cookie_len = strlen(cookie);
153f66241cbSDouglas Fuller 	struct page *break_op_page;
154f66241cbSDouglas Fuller 	void *p, *end;
155f66241cbSDouglas Fuller 	int ret;
156f66241cbSDouglas Fuller 
157f66241cbSDouglas Fuller 	break_op_buf_size = name_len + sizeof(__le32) +
158f66241cbSDouglas Fuller 			    cookie_len + sizeof(__le32) +
159f66241cbSDouglas Fuller 			    sizeof(u8) + sizeof(__le64) +
160f66241cbSDouglas Fuller 			    CEPH_ENCODING_START_BLK_LEN;
161f66241cbSDouglas Fuller 	if (break_op_buf_size > PAGE_SIZE)
162f66241cbSDouglas Fuller 		return -E2BIG;
163f66241cbSDouglas Fuller 
164f66241cbSDouglas Fuller 	break_op_page = alloc_page(GFP_NOIO);
165f66241cbSDouglas Fuller 	if (!break_op_page)
166f66241cbSDouglas Fuller 		return -ENOMEM;
167f66241cbSDouglas Fuller 
168f66241cbSDouglas Fuller 	p = page_address(break_op_page);
169f66241cbSDouglas Fuller 	end = p + break_op_buf_size;
170f66241cbSDouglas Fuller 
171f66241cbSDouglas Fuller 	/* encode cls_lock_break_op struct */
172f66241cbSDouglas Fuller 	ceph_start_encoding(&p, 1, 1,
173f66241cbSDouglas Fuller 			    break_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
174f66241cbSDouglas Fuller 	ceph_encode_string(&p, end, lock_name, name_len);
175f66241cbSDouglas Fuller 	ceph_encode_copy(&p, locker, sizeof(*locker));
176f66241cbSDouglas Fuller 	ceph_encode_string(&p, end, cookie, cookie_len);
177f66241cbSDouglas Fuller 
178f66241cbSDouglas Fuller 	dout("%s lock_name %s cookie %s locker %s%llu\n", __func__, lock_name,
179f66241cbSDouglas Fuller 	     cookie, ENTITY_NAME(*locker));
180f66241cbSDouglas Fuller 	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "break_lock",
18154ea0046SIlya Dryomov 			     CEPH_OSD_FLAG_WRITE, break_op_page,
18254ea0046SIlya Dryomov 			     break_op_buf_size, NULL, NULL);
183f66241cbSDouglas Fuller 
184f66241cbSDouglas Fuller 	dout("%s: status %d\n", __func__, ret);
185f66241cbSDouglas Fuller 	__free_page(break_op_page);
186f66241cbSDouglas Fuller 	return ret;
187f66241cbSDouglas Fuller }
188f66241cbSDouglas Fuller EXPORT_SYMBOL(ceph_cls_break_lock);
189d4ed4a53SDouglas Fuller 
ceph_cls_set_cookie(struct ceph_osd_client * osdc,struct ceph_object_id * oid,struct ceph_object_locator * oloc,char * lock_name,u8 type,char * old_cookie,char * tag,char * new_cookie)19014bb211dSIlya Dryomov int ceph_cls_set_cookie(struct ceph_osd_client *osdc,
19114bb211dSIlya Dryomov 			struct ceph_object_id *oid,
19214bb211dSIlya Dryomov 			struct ceph_object_locator *oloc,
19314bb211dSIlya Dryomov 			char *lock_name, u8 type, char *old_cookie,
19414bb211dSIlya Dryomov 			char *tag, char *new_cookie)
19514bb211dSIlya Dryomov {
19614bb211dSIlya Dryomov 	int cookie_op_buf_size;
19714bb211dSIlya Dryomov 	int name_len = strlen(lock_name);
19814bb211dSIlya Dryomov 	int old_cookie_len = strlen(old_cookie);
19914bb211dSIlya Dryomov 	int tag_len = strlen(tag);
20014bb211dSIlya Dryomov 	int new_cookie_len = strlen(new_cookie);
20114bb211dSIlya Dryomov 	void *p, *end;
20214bb211dSIlya Dryomov 	struct page *cookie_op_page;
20314bb211dSIlya Dryomov 	int ret;
20414bb211dSIlya Dryomov 
20514bb211dSIlya Dryomov 	cookie_op_buf_size = name_len + sizeof(__le32) +
20614bb211dSIlya Dryomov 			     old_cookie_len + sizeof(__le32) +
20714bb211dSIlya Dryomov 			     tag_len + sizeof(__le32) +
20814bb211dSIlya Dryomov 			     new_cookie_len + sizeof(__le32) +
20914bb211dSIlya Dryomov 			     sizeof(u8) + CEPH_ENCODING_START_BLK_LEN;
21014bb211dSIlya Dryomov 	if (cookie_op_buf_size > PAGE_SIZE)
21114bb211dSIlya Dryomov 		return -E2BIG;
21214bb211dSIlya Dryomov 
21314bb211dSIlya Dryomov 	cookie_op_page = alloc_page(GFP_NOIO);
21414bb211dSIlya Dryomov 	if (!cookie_op_page)
21514bb211dSIlya Dryomov 		return -ENOMEM;
21614bb211dSIlya Dryomov 
21714bb211dSIlya Dryomov 	p = page_address(cookie_op_page);
21814bb211dSIlya Dryomov 	end = p + cookie_op_buf_size;
21914bb211dSIlya Dryomov 
22014bb211dSIlya Dryomov 	/* encode cls_lock_set_cookie_op struct */
22114bb211dSIlya Dryomov 	ceph_start_encoding(&p, 1, 1,
22214bb211dSIlya Dryomov 			    cookie_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
22314bb211dSIlya Dryomov 	ceph_encode_string(&p, end, lock_name, name_len);
22414bb211dSIlya Dryomov 	ceph_encode_8(&p, type);
22514bb211dSIlya Dryomov 	ceph_encode_string(&p, end, old_cookie, old_cookie_len);
22614bb211dSIlya Dryomov 	ceph_encode_string(&p, end, tag, tag_len);
22714bb211dSIlya Dryomov 	ceph_encode_string(&p, end, new_cookie, new_cookie_len);
22814bb211dSIlya Dryomov 
22914bb211dSIlya Dryomov 	dout("%s lock_name %s type %d old_cookie %s tag %s new_cookie %s\n",
23014bb211dSIlya Dryomov 	     __func__, lock_name, type, old_cookie, tag, new_cookie);
23114bb211dSIlya Dryomov 	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "set_cookie",
23214bb211dSIlya Dryomov 			     CEPH_OSD_FLAG_WRITE, cookie_op_page,
23314bb211dSIlya Dryomov 			     cookie_op_buf_size, NULL, NULL);
23414bb211dSIlya Dryomov 
23514bb211dSIlya Dryomov 	dout("%s: status %d\n", __func__, ret);
23614bb211dSIlya Dryomov 	__free_page(cookie_op_page);
23714bb211dSIlya Dryomov 	return ret;
23814bb211dSIlya Dryomov }
23914bb211dSIlya Dryomov EXPORT_SYMBOL(ceph_cls_set_cookie);
24014bb211dSIlya Dryomov 
ceph_free_lockers(struct ceph_locker * lockers,u32 num_lockers)241d4ed4a53SDouglas Fuller void ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers)
242d4ed4a53SDouglas Fuller {
243d4ed4a53SDouglas Fuller 	int i;
244d4ed4a53SDouglas Fuller 
245d4ed4a53SDouglas Fuller 	for (i = 0; i < num_lockers; i++)
246d4ed4a53SDouglas Fuller 		kfree(lockers[i].id.cookie);
247d4ed4a53SDouglas Fuller 	kfree(lockers);
248d4ed4a53SDouglas Fuller }
249d4ed4a53SDouglas Fuller EXPORT_SYMBOL(ceph_free_lockers);
250d4ed4a53SDouglas Fuller 
decode_locker(void ** p,void * end,struct ceph_locker * locker)251d4ed4a53SDouglas Fuller static int decode_locker(void **p, void *end, struct ceph_locker *locker)
252d4ed4a53SDouglas Fuller {
253d4ed4a53SDouglas Fuller 	u8 struct_v;
254d4ed4a53SDouglas Fuller 	u32 len;
255d4ed4a53SDouglas Fuller 	char *s;
256d4ed4a53SDouglas Fuller 	int ret;
257d4ed4a53SDouglas Fuller 
258d4ed4a53SDouglas Fuller 	ret = ceph_start_decoding(p, end, 1, "locker_id_t", &struct_v, &len);
259d4ed4a53SDouglas Fuller 	if (ret)
260d4ed4a53SDouglas Fuller 		return ret;
261d4ed4a53SDouglas Fuller 
262d4ed4a53SDouglas Fuller 	ceph_decode_copy(p, &locker->id.name, sizeof(locker->id.name));
263d4ed4a53SDouglas Fuller 	s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
264d4ed4a53SDouglas Fuller 	if (IS_ERR(s))
265d4ed4a53SDouglas Fuller 		return PTR_ERR(s);
266d4ed4a53SDouglas Fuller 
267d4ed4a53SDouglas Fuller 	locker->id.cookie = s;
268d4ed4a53SDouglas Fuller 
269d4ed4a53SDouglas Fuller 	ret = ceph_start_decoding(p, end, 1, "locker_info_t", &struct_v, &len);
270d4ed4a53SDouglas Fuller 	if (ret)
271d4ed4a53SDouglas Fuller 		return ret;
272d4ed4a53SDouglas Fuller 
273d4ed4a53SDouglas Fuller 	*p += sizeof(struct ceph_timespec); /* skip expiration */
2742f9800c8SJeff Layton 
2752f9800c8SJeff Layton 	ret = ceph_decode_entity_addr(p, end, &locker->info.addr);
2762f9800c8SJeff Layton 	if (ret)
2772f9800c8SJeff Layton 		return ret;
2782f9800c8SJeff Layton 
279d4ed4a53SDouglas Fuller 	len = ceph_decode_32(p);
280d4ed4a53SDouglas Fuller 	*p += len; /* skip description */
281d4ed4a53SDouglas Fuller 
282d4ed4a53SDouglas Fuller 	dout("%s %s%llu cookie %s addr %s\n", __func__,
283d4ed4a53SDouglas Fuller 	     ENTITY_NAME(locker->id.name), locker->id.cookie,
284b726ec97SJeff Layton 	     ceph_pr_addr(&locker->info.addr));
285d4ed4a53SDouglas Fuller 	return 0;
286d4ed4a53SDouglas Fuller }
287d4ed4a53SDouglas Fuller 
decode_lockers(void ** p,void * end,u8 * type,char ** tag,struct ceph_locker ** lockers,u32 * num_lockers)288d4ed4a53SDouglas Fuller static int decode_lockers(void **p, void *end, u8 *type, char **tag,
289d4ed4a53SDouglas Fuller 			  struct ceph_locker **lockers, u32 *num_lockers)
290d4ed4a53SDouglas Fuller {
291d4ed4a53SDouglas Fuller 	u8 struct_v;
292d4ed4a53SDouglas Fuller 	u32 struct_len;
293d4ed4a53SDouglas Fuller 	char *s;
294d4ed4a53SDouglas Fuller 	int i;
295d4ed4a53SDouglas Fuller 	int ret;
296d4ed4a53SDouglas Fuller 
297d4ed4a53SDouglas Fuller 	ret = ceph_start_decoding(p, end, 1, "cls_lock_get_info_reply",
298d4ed4a53SDouglas Fuller 				  &struct_v, &struct_len);
299d4ed4a53SDouglas Fuller 	if (ret)
300d4ed4a53SDouglas Fuller 		return ret;
301d4ed4a53SDouglas Fuller 
302d4ed4a53SDouglas Fuller 	*num_lockers = ceph_decode_32(p);
303d4ed4a53SDouglas Fuller 	*lockers = kcalloc(*num_lockers, sizeof(**lockers), GFP_NOIO);
304d4ed4a53SDouglas Fuller 	if (!*lockers)
305d4ed4a53SDouglas Fuller 		return -ENOMEM;
306d4ed4a53SDouglas Fuller 
307d4ed4a53SDouglas Fuller 	for (i = 0; i < *num_lockers; i++) {
308d4ed4a53SDouglas Fuller 		ret = decode_locker(p, end, *lockers + i);
309d4ed4a53SDouglas Fuller 		if (ret)
310d4ed4a53SDouglas Fuller 			goto err_free_lockers;
311d4ed4a53SDouglas Fuller 	}
312d4ed4a53SDouglas Fuller 
313d4ed4a53SDouglas Fuller 	*type = ceph_decode_8(p);
314d4ed4a53SDouglas Fuller 	s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
315d4ed4a53SDouglas Fuller 	if (IS_ERR(s)) {
316d4ed4a53SDouglas Fuller 		ret = PTR_ERR(s);
317d4ed4a53SDouglas Fuller 		goto err_free_lockers;
318d4ed4a53SDouglas Fuller 	}
319d4ed4a53SDouglas Fuller 
320d4ed4a53SDouglas Fuller 	*tag = s;
321d4ed4a53SDouglas Fuller 	return 0;
322d4ed4a53SDouglas Fuller 
323d4ed4a53SDouglas Fuller err_free_lockers:
324d4ed4a53SDouglas Fuller 	ceph_free_lockers(*lockers, *num_lockers);
325d4ed4a53SDouglas Fuller 	return ret;
326d4ed4a53SDouglas Fuller }
327d4ed4a53SDouglas Fuller 
328d4ed4a53SDouglas Fuller /*
329d4ed4a53SDouglas Fuller  * On success, the caller is responsible for:
330d4ed4a53SDouglas Fuller  *
331d4ed4a53SDouglas Fuller  *     kfree(tag);
332d4ed4a53SDouglas Fuller  *     ceph_free_lockers(lockers, num_lockers);
333d4ed4a53SDouglas Fuller  */
ceph_cls_lock_info(struct ceph_osd_client * osdc,struct ceph_object_id * oid,struct ceph_object_locator * oloc,char * lock_name,u8 * type,char ** tag,struct ceph_locker ** lockers,u32 * num_lockers)334d4ed4a53SDouglas Fuller int ceph_cls_lock_info(struct ceph_osd_client *osdc,
335d4ed4a53SDouglas Fuller 		       struct ceph_object_id *oid,
336d4ed4a53SDouglas Fuller 		       struct ceph_object_locator *oloc,
337d4ed4a53SDouglas Fuller 		       char *lock_name, u8 *type, char **tag,
338d4ed4a53SDouglas Fuller 		       struct ceph_locker **lockers, u32 *num_lockers)
339d4ed4a53SDouglas Fuller {
340d4ed4a53SDouglas Fuller 	int get_info_op_buf_size;
341d4ed4a53SDouglas Fuller 	int name_len = strlen(lock_name);
342d4ed4a53SDouglas Fuller 	struct page *get_info_op_page, *reply_page;
3432544a020SIlya Dryomov 	size_t reply_len = PAGE_SIZE;
344d4ed4a53SDouglas Fuller 	void *p, *end;
345d4ed4a53SDouglas Fuller 	int ret;
346d4ed4a53SDouglas Fuller 
347d4ed4a53SDouglas Fuller 	get_info_op_buf_size = name_len + sizeof(__le32) +
348d4ed4a53SDouglas Fuller 			       CEPH_ENCODING_START_BLK_LEN;
349d4ed4a53SDouglas Fuller 	if (get_info_op_buf_size > PAGE_SIZE)
350d4ed4a53SDouglas Fuller 		return -E2BIG;
351d4ed4a53SDouglas Fuller 
352d4ed4a53SDouglas Fuller 	get_info_op_page = alloc_page(GFP_NOIO);
353d4ed4a53SDouglas Fuller 	if (!get_info_op_page)
354d4ed4a53SDouglas Fuller 		return -ENOMEM;
355d4ed4a53SDouglas Fuller 
356d4ed4a53SDouglas Fuller 	reply_page = alloc_page(GFP_NOIO);
357d4ed4a53SDouglas Fuller 	if (!reply_page) {
358d4ed4a53SDouglas Fuller 		__free_page(get_info_op_page);
359d4ed4a53SDouglas Fuller 		return -ENOMEM;
360d4ed4a53SDouglas Fuller 	}
361d4ed4a53SDouglas Fuller 
362d4ed4a53SDouglas Fuller 	p = page_address(get_info_op_page);
363d4ed4a53SDouglas Fuller 	end = p + get_info_op_buf_size;
364d4ed4a53SDouglas Fuller 
365d4ed4a53SDouglas Fuller 	/* encode cls_lock_get_info_op struct */
366d4ed4a53SDouglas Fuller 	ceph_start_encoding(&p, 1, 1,
367d4ed4a53SDouglas Fuller 			    get_info_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
368d4ed4a53SDouglas Fuller 	ceph_encode_string(&p, end, lock_name, name_len);
369d4ed4a53SDouglas Fuller 
370d4ed4a53SDouglas Fuller 	dout("%s lock_name %s\n", __func__, lock_name);
371d4ed4a53SDouglas Fuller 	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "get_info",
372d4ed4a53SDouglas Fuller 			     CEPH_OSD_FLAG_READ, get_info_op_page,
37368ada915SIlya Dryomov 			     get_info_op_buf_size, &reply_page, &reply_len);
374d4ed4a53SDouglas Fuller 
375d4ed4a53SDouglas Fuller 	dout("%s: status %d\n", __func__, ret);
376d4ed4a53SDouglas Fuller 	if (ret >= 0) {
377d4ed4a53SDouglas Fuller 		p = page_address(reply_page);
378d4ed4a53SDouglas Fuller 		end = p + reply_len;
379d4ed4a53SDouglas Fuller 
380d4ed4a53SDouglas Fuller 		ret = decode_lockers(&p, end, type, tag, lockers, num_lockers);
381d4ed4a53SDouglas Fuller 	}
382d4ed4a53SDouglas Fuller 
383d4ed4a53SDouglas Fuller 	__free_page(get_info_op_page);
384d4ed4a53SDouglas Fuller 	__free_page(reply_page);
385d4ed4a53SDouglas Fuller 	return ret;
386d4ed4a53SDouglas Fuller }
387d4ed4a53SDouglas Fuller EXPORT_SYMBOL(ceph_cls_lock_info);
38822e8bd51SIlya Dryomov 
ceph_cls_assert_locked(struct ceph_osd_request * req,int which,char * lock_name,u8 type,char * cookie,char * tag)38922e8bd51SIlya Dryomov int ceph_cls_assert_locked(struct ceph_osd_request *req, int which,
39022e8bd51SIlya Dryomov 			   char *lock_name, u8 type, char *cookie, char *tag)
39122e8bd51SIlya Dryomov {
39222e8bd51SIlya Dryomov 	int assert_op_buf_size;
39322e8bd51SIlya Dryomov 	int name_len = strlen(lock_name);
39422e8bd51SIlya Dryomov 	int cookie_len = strlen(cookie);
39522e8bd51SIlya Dryomov 	int tag_len = strlen(tag);
39622e8bd51SIlya Dryomov 	struct page **pages;
39722e8bd51SIlya Dryomov 	void *p, *end;
39822e8bd51SIlya Dryomov 	int ret;
39922e8bd51SIlya Dryomov 
40022e8bd51SIlya Dryomov 	assert_op_buf_size = name_len + sizeof(__le32) +
40122e8bd51SIlya Dryomov 			     cookie_len + sizeof(__le32) +
40222e8bd51SIlya Dryomov 			     tag_len + sizeof(__le32) +
40322e8bd51SIlya Dryomov 			     sizeof(u8) + CEPH_ENCODING_START_BLK_LEN;
40422e8bd51SIlya Dryomov 	if (assert_op_buf_size > PAGE_SIZE)
40522e8bd51SIlya Dryomov 		return -E2BIG;
40622e8bd51SIlya Dryomov 
40722e8bd51SIlya Dryomov 	ret = osd_req_op_cls_init(req, which, "lock", "assert_locked");
40822e8bd51SIlya Dryomov 	if (ret)
40922e8bd51SIlya Dryomov 		return ret;
41022e8bd51SIlya Dryomov 
41122e8bd51SIlya Dryomov 	pages = ceph_alloc_page_vector(1, GFP_NOIO);
41222e8bd51SIlya Dryomov 	if (IS_ERR(pages))
41322e8bd51SIlya Dryomov 		return PTR_ERR(pages);
41422e8bd51SIlya Dryomov 
41522e8bd51SIlya Dryomov 	p = page_address(pages[0]);
41622e8bd51SIlya Dryomov 	end = p + assert_op_buf_size;
41722e8bd51SIlya Dryomov 
41822e8bd51SIlya Dryomov 	/* encode cls_lock_assert_op struct */
41922e8bd51SIlya Dryomov 	ceph_start_encoding(&p, 1, 1,
42022e8bd51SIlya Dryomov 			    assert_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
42122e8bd51SIlya Dryomov 	ceph_encode_string(&p, end, lock_name, name_len);
42222e8bd51SIlya Dryomov 	ceph_encode_8(&p, type);
42322e8bd51SIlya Dryomov 	ceph_encode_string(&p, end, cookie, cookie_len);
42422e8bd51SIlya Dryomov 	ceph_encode_string(&p, end, tag, tag_len);
42522e8bd51SIlya Dryomov 	WARN_ON(p != end);
42622e8bd51SIlya Dryomov 
42722e8bd51SIlya Dryomov 	osd_req_op_cls_request_data_pages(req, which, pages, assert_op_buf_size,
42822e8bd51SIlya Dryomov 					  0, false, true);
42922e8bd51SIlya Dryomov 	return 0;
43022e8bd51SIlya Dryomov }
43122e8bd51SIlya Dryomov EXPORT_SYMBOL(ceph_cls_assert_locked);
432