18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <linux/ceph/ceph_debug.h>
38c2ecf20Sopenharmony_ci
48c2ecf20Sopenharmony_ci#include <linux/types.h>
58c2ecf20Sopenharmony_ci#include <linux/slab.h>
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <linux/ceph/cls_lock_client.h>
88c2ecf20Sopenharmony_ci#include <linux/ceph/decode.h>
98c2ecf20Sopenharmony_ci#include <linux/ceph/libceph.h>
108c2ecf20Sopenharmony_ci
118c2ecf20Sopenharmony_ci/**
128c2ecf20Sopenharmony_ci * ceph_cls_lock - grab rados lock for object
138c2ecf20Sopenharmony_ci * @oid, @oloc: object to lock
148c2ecf20Sopenharmony_ci * @lock_name: the name of the lock
158c2ecf20Sopenharmony_ci * @type: lock type (CEPH_CLS_LOCK_EXCLUSIVE or CEPH_CLS_LOCK_SHARED)
168c2ecf20Sopenharmony_ci * @cookie: user-defined identifier for this instance of the lock
178c2ecf20Sopenharmony_ci * @tag: user-defined tag
188c2ecf20Sopenharmony_ci * @desc: user-defined lock description
198c2ecf20Sopenharmony_ci * @flags: lock flags
208c2ecf20Sopenharmony_ci *
218c2ecf20Sopenharmony_ci * All operations on the same lock should use the same tag.
228c2ecf20Sopenharmony_ci */
238c2ecf20Sopenharmony_ciint ceph_cls_lock(struct ceph_osd_client *osdc,
248c2ecf20Sopenharmony_ci		  struct ceph_object_id *oid,
258c2ecf20Sopenharmony_ci		  struct ceph_object_locator *oloc,
268c2ecf20Sopenharmony_ci		  char *lock_name, u8 type, char *cookie,
278c2ecf20Sopenharmony_ci		  char *tag, char *desc, u8 flags)
288c2ecf20Sopenharmony_ci{
298c2ecf20Sopenharmony_ci	int lock_op_buf_size;
308c2ecf20Sopenharmony_ci	int name_len = strlen(lock_name);
318c2ecf20Sopenharmony_ci	int cookie_len = strlen(cookie);
328c2ecf20Sopenharmony_ci	int tag_len = strlen(tag);
338c2ecf20Sopenharmony_ci	int desc_len = strlen(desc);
348c2ecf20Sopenharmony_ci	void *p, *end;
358c2ecf20Sopenharmony_ci	struct page *lock_op_page;
368c2ecf20Sopenharmony_ci	struct timespec64 mtime;
378c2ecf20Sopenharmony_ci	int ret;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	lock_op_buf_size = name_len + sizeof(__le32) +
408c2ecf20Sopenharmony_ci			   cookie_len + sizeof(__le32) +
418c2ecf20Sopenharmony_ci			   tag_len + sizeof(__le32) +
428c2ecf20Sopenharmony_ci			   desc_len + sizeof(__le32) +
438c2ecf20Sopenharmony_ci			   sizeof(struct ceph_timespec) +
448c2ecf20Sopenharmony_ci			   /* flag and type */
458c2ecf20Sopenharmony_ci			   sizeof(u8) + sizeof(u8) +
468c2ecf20Sopenharmony_ci			   CEPH_ENCODING_START_BLK_LEN;
478c2ecf20Sopenharmony_ci	if (lock_op_buf_size > PAGE_SIZE)
488c2ecf20Sopenharmony_ci		return -E2BIG;
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci	lock_op_page = alloc_page(GFP_NOIO);
518c2ecf20Sopenharmony_ci	if (!lock_op_page)
528c2ecf20Sopenharmony_ci		return -ENOMEM;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	p = page_address(lock_op_page);
558c2ecf20Sopenharmony_ci	end = p + lock_op_buf_size;
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci	/* encode cls_lock_lock_op struct */
588c2ecf20Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
598c2ecf20Sopenharmony_ci			    lock_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
608c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
618c2ecf20Sopenharmony_ci	ceph_encode_8(&p, type);
628c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, cookie, cookie_len);
638c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, tag, tag_len);
648c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, desc, desc_len);
658c2ecf20Sopenharmony_ci	/* only support infinite duration */
668c2ecf20Sopenharmony_ci	memset(&mtime, 0, sizeof(mtime));
678c2ecf20Sopenharmony_ci	ceph_encode_timespec64(p, &mtime);
688c2ecf20Sopenharmony_ci	p += sizeof(struct ceph_timespec);
698c2ecf20Sopenharmony_ci	ceph_encode_8(&p, flags);
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_ci	dout("%s lock_name %s type %d cookie %s tag %s desc %s flags 0x%x\n",
728c2ecf20Sopenharmony_ci	     __func__, lock_name, type, cookie, tag, desc, flags);
738c2ecf20Sopenharmony_ci	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "lock",
748c2ecf20Sopenharmony_ci			     CEPH_OSD_FLAG_WRITE, lock_op_page,
758c2ecf20Sopenharmony_ci			     lock_op_buf_size, NULL, NULL);
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	dout("%s: status %d\n", __func__, ret);
788c2ecf20Sopenharmony_ci	__free_page(lock_op_page);
798c2ecf20Sopenharmony_ci	return ret;
808c2ecf20Sopenharmony_ci}
818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_lock);
828c2ecf20Sopenharmony_ci
838c2ecf20Sopenharmony_ci/**
848c2ecf20Sopenharmony_ci * ceph_cls_unlock - release rados lock for object
858c2ecf20Sopenharmony_ci * @oid, @oloc: object to lock
868c2ecf20Sopenharmony_ci * @lock_name: the name of the lock
878c2ecf20Sopenharmony_ci * @cookie: user-defined identifier for this instance of the lock
888c2ecf20Sopenharmony_ci */
898c2ecf20Sopenharmony_ciint ceph_cls_unlock(struct ceph_osd_client *osdc,
908c2ecf20Sopenharmony_ci		    struct ceph_object_id *oid,
918c2ecf20Sopenharmony_ci		    struct ceph_object_locator *oloc,
928c2ecf20Sopenharmony_ci		    char *lock_name, char *cookie)
938c2ecf20Sopenharmony_ci{
948c2ecf20Sopenharmony_ci	int unlock_op_buf_size;
958c2ecf20Sopenharmony_ci	int name_len = strlen(lock_name);
968c2ecf20Sopenharmony_ci	int cookie_len = strlen(cookie);
978c2ecf20Sopenharmony_ci	void *p, *end;
988c2ecf20Sopenharmony_ci	struct page *unlock_op_page;
998c2ecf20Sopenharmony_ci	int ret;
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	unlock_op_buf_size = name_len + sizeof(__le32) +
1028c2ecf20Sopenharmony_ci			     cookie_len + sizeof(__le32) +
1038c2ecf20Sopenharmony_ci			     CEPH_ENCODING_START_BLK_LEN;
1048c2ecf20Sopenharmony_ci	if (unlock_op_buf_size > PAGE_SIZE)
1058c2ecf20Sopenharmony_ci		return -E2BIG;
1068c2ecf20Sopenharmony_ci
1078c2ecf20Sopenharmony_ci	unlock_op_page = alloc_page(GFP_NOIO);
1088c2ecf20Sopenharmony_ci	if (!unlock_op_page)
1098c2ecf20Sopenharmony_ci		return -ENOMEM;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	p = page_address(unlock_op_page);
1128c2ecf20Sopenharmony_ci	end = p + unlock_op_buf_size;
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci	/* encode cls_lock_unlock_op struct */
1158c2ecf20Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
1168c2ecf20Sopenharmony_ci			    unlock_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
1178c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
1188c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, cookie, cookie_len);
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	dout("%s lock_name %s cookie %s\n", __func__, lock_name, cookie);
1218c2ecf20Sopenharmony_ci	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "unlock",
1228c2ecf20Sopenharmony_ci			     CEPH_OSD_FLAG_WRITE, unlock_op_page,
1238c2ecf20Sopenharmony_ci			     unlock_op_buf_size, NULL, NULL);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	dout("%s: status %d\n", __func__, ret);
1268c2ecf20Sopenharmony_ci	__free_page(unlock_op_page);
1278c2ecf20Sopenharmony_ci	return ret;
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_unlock);
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci/**
1328c2ecf20Sopenharmony_ci * ceph_cls_break_lock - release rados lock for object for specified client
1338c2ecf20Sopenharmony_ci * @oid, @oloc: object to lock
1348c2ecf20Sopenharmony_ci * @lock_name: the name of the lock
1358c2ecf20Sopenharmony_ci * @cookie: user-defined identifier for this instance of the lock
1368c2ecf20Sopenharmony_ci * @locker: current lock owner
1378c2ecf20Sopenharmony_ci */
1388c2ecf20Sopenharmony_ciint ceph_cls_break_lock(struct ceph_osd_client *osdc,
1398c2ecf20Sopenharmony_ci			struct ceph_object_id *oid,
1408c2ecf20Sopenharmony_ci			struct ceph_object_locator *oloc,
1418c2ecf20Sopenharmony_ci			char *lock_name, char *cookie,
1428c2ecf20Sopenharmony_ci			struct ceph_entity_name *locker)
1438c2ecf20Sopenharmony_ci{
1448c2ecf20Sopenharmony_ci	int break_op_buf_size;
1458c2ecf20Sopenharmony_ci	int name_len = strlen(lock_name);
1468c2ecf20Sopenharmony_ci	int cookie_len = strlen(cookie);
1478c2ecf20Sopenharmony_ci	struct page *break_op_page;
1488c2ecf20Sopenharmony_ci	void *p, *end;
1498c2ecf20Sopenharmony_ci	int ret;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	break_op_buf_size = name_len + sizeof(__le32) +
1528c2ecf20Sopenharmony_ci			    cookie_len + sizeof(__le32) +
1538c2ecf20Sopenharmony_ci			    sizeof(u8) + sizeof(__le64) +
1548c2ecf20Sopenharmony_ci			    CEPH_ENCODING_START_BLK_LEN;
1558c2ecf20Sopenharmony_ci	if (break_op_buf_size > PAGE_SIZE)
1568c2ecf20Sopenharmony_ci		return -E2BIG;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	break_op_page = alloc_page(GFP_NOIO);
1598c2ecf20Sopenharmony_ci	if (!break_op_page)
1608c2ecf20Sopenharmony_ci		return -ENOMEM;
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	p = page_address(break_op_page);
1638c2ecf20Sopenharmony_ci	end = p + break_op_buf_size;
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_ci	/* encode cls_lock_break_op struct */
1668c2ecf20Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
1678c2ecf20Sopenharmony_ci			    break_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
1688c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
1698c2ecf20Sopenharmony_ci	ceph_encode_copy(&p, locker, sizeof(*locker));
1708c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, cookie, cookie_len);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci	dout("%s lock_name %s cookie %s locker %s%llu\n", __func__, lock_name,
1738c2ecf20Sopenharmony_ci	     cookie, ENTITY_NAME(*locker));
1748c2ecf20Sopenharmony_ci	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "break_lock",
1758c2ecf20Sopenharmony_ci			     CEPH_OSD_FLAG_WRITE, break_op_page,
1768c2ecf20Sopenharmony_ci			     break_op_buf_size, NULL, NULL);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	dout("%s: status %d\n", __func__, ret);
1798c2ecf20Sopenharmony_ci	__free_page(break_op_page);
1808c2ecf20Sopenharmony_ci	return ret;
1818c2ecf20Sopenharmony_ci}
1828c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_break_lock);
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ciint ceph_cls_set_cookie(struct ceph_osd_client *osdc,
1858c2ecf20Sopenharmony_ci			struct ceph_object_id *oid,
1868c2ecf20Sopenharmony_ci			struct ceph_object_locator *oloc,
1878c2ecf20Sopenharmony_ci			char *lock_name, u8 type, char *old_cookie,
1888c2ecf20Sopenharmony_ci			char *tag, char *new_cookie)
1898c2ecf20Sopenharmony_ci{
1908c2ecf20Sopenharmony_ci	int cookie_op_buf_size;
1918c2ecf20Sopenharmony_ci	int name_len = strlen(lock_name);
1928c2ecf20Sopenharmony_ci	int old_cookie_len = strlen(old_cookie);
1938c2ecf20Sopenharmony_ci	int tag_len = strlen(tag);
1948c2ecf20Sopenharmony_ci	int new_cookie_len = strlen(new_cookie);
1958c2ecf20Sopenharmony_ci	void *p, *end;
1968c2ecf20Sopenharmony_ci	struct page *cookie_op_page;
1978c2ecf20Sopenharmony_ci	int ret;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci	cookie_op_buf_size = name_len + sizeof(__le32) +
2008c2ecf20Sopenharmony_ci			     old_cookie_len + sizeof(__le32) +
2018c2ecf20Sopenharmony_ci			     tag_len + sizeof(__le32) +
2028c2ecf20Sopenharmony_ci			     new_cookie_len + sizeof(__le32) +
2038c2ecf20Sopenharmony_ci			     sizeof(u8) + CEPH_ENCODING_START_BLK_LEN;
2048c2ecf20Sopenharmony_ci	if (cookie_op_buf_size > PAGE_SIZE)
2058c2ecf20Sopenharmony_ci		return -E2BIG;
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci	cookie_op_page = alloc_page(GFP_NOIO);
2088c2ecf20Sopenharmony_ci	if (!cookie_op_page)
2098c2ecf20Sopenharmony_ci		return -ENOMEM;
2108c2ecf20Sopenharmony_ci
2118c2ecf20Sopenharmony_ci	p = page_address(cookie_op_page);
2128c2ecf20Sopenharmony_ci	end = p + cookie_op_buf_size;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	/* encode cls_lock_set_cookie_op struct */
2158c2ecf20Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
2168c2ecf20Sopenharmony_ci			    cookie_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
2178c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
2188c2ecf20Sopenharmony_ci	ceph_encode_8(&p, type);
2198c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, old_cookie, old_cookie_len);
2208c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, tag, tag_len);
2218c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, new_cookie, new_cookie_len);
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	dout("%s lock_name %s type %d old_cookie %s tag %s new_cookie %s\n",
2248c2ecf20Sopenharmony_ci	     __func__, lock_name, type, old_cookie, tag, new_cookie);
2258c2ecf20Sopenharmony_ci	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "set_cookie",
2268c2ecf20Sopenharmony_ci			     CEPH_OSD_FLAG_WRITE, cookie_op_page,
2278c2ecf20Sopenharmony_ci			     cookie_op_buf_size, NULL, NULL);
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci	dout("%s: status %d\n", __func__, ret);
2308c2ecf20Sopenharmony_ci	__free_page(cookie_op_page);
2318c2ecf20Sopenharmony_ci	return ret;
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_set_cookie);
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_civoid ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	int i;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	for (i = 0; i < num_lockers; i++)
2408c2ecf20Sopenharmony_ci		kfree(lockers[i].id.cookie);
2418c2ecf20Sopenharmony_ci	kfree(lockers);
2428c2ecf20Sopenharmony_ci}
2438c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ceph_free_lockers);
2448c2ecf20Sopenharmony_ci
2458c2ecf20Sopenharmony_cistatic int decode_locker(void **p, void *end, struct ceph_locker *locker)
2468c2ecf20Sopenharmony_ci{
2478c2ecf20Sopenharmony_ci	u8 struct_v;
2488c2ecf20Sopenharmony_ci	u32 len;
2498c2ecf20Sopenharmony_ci	char *s;
2508c2ecf20Sopenharmony_ci	int ret;
2518c2ecf20Sopenharmony_ci
2528c2ecf20Sopenharmony_ci	ret = ceph_start_decoding(p, end, 1, "locker_id_t", &struct_v, &len);
2538c2ecf20Sopenharmony_ci	if (ret)
2548c2ecf20Sopenharmony_ci		return ret;
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_ci	ceph_decode_copy(p, &locker->id.name, sizeof(locker->id.name));
2578c2ecf20Sopenharmony_ci	s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
2588c2ecf20Sopenharmony_ci	if (IS_ERR(s))
2598c2ecf20Sopenharmony_ci		return PTR_ERR(s);
2608c2ecf20Sopenharmony_ci
2618c2ecf20Sopenharmony_ci	locker->id.cookie = s;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	ret = ceph_start_decoding(p, end, 1, "locker_info_t", &struct_v, &len);
2648c2ecf20Sopenharmony_ci	if (ret)
2658c2ecf20Sopenharmony_ci		return ret;
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci	*p += sizeof(struct ceph_timespec); /* skip expiration */
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_ci	ret = ceph_decode_entity_addr(p, end, &locker->info.addr);
2708c2ecf20Sopenharmony_ci	if (ret)
2718c2ecf20Sopenharmony_ci		return ret;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_ci	len = ceph_decode_32(p);
2748c2ecf20Sopenharmony_ci	*p += len; /* skip description */
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci	dout("%s %s%llu cookie %s addr %s\n", __func__,
2778c2ecf20Sopenharmony_ci	     ENTITY_NAME(locker->id.name), locker->id.cookie,
2788c2ecf20Sopenharmony_ci	     ceph_pr_addr(&locker->info.addr));
2798c2ecf20Sopenharmony_ci	return 0;
2808c2ecf20Sopenharmony_ci}
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_cistatic int decode_lockers(void **p, void *end, u8 *type, char **tag,
2838c2ecf20Sopenharmony_ci			  struct ceph_locker **lockers, u32 *num_lockers)
2848c2ecf20Sopenharmony_ci{
2858c2ecf20Sopenharmony_ci	u8 struct_v;
2868c2ecf20Sopenharmony_ci	u32 struct_len;
2878c2ecf20Sopenharmony_ci	char *s;
2888c2ecf20Sopenharmony_ci	int i;
2898c2ecf20Sopenharmony_ci	int ret;
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	ret = ceph_start_decoding(p, end, 1, "cls_lock_get_info_reply",
2928c2ecf20Sopenharmony_ci				  &struct_v, &struct_len);
2938c2ecf20Sopenharmony_ci	if (ret)
2948c2ecf20Sopenharmony_ci		return ret;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	*num_lockers = ceph_decode_32(p);
2978c2ecf20Sopenharmony_ci	*lockers = kcalloc(*num_lockers, sizeof(**lockers), GFP_NOIO);
2988c2ecf20Sopenharmony_ci	if (!*lockers)
2998c2ecf20Sopenharmony_ci		return -ENOMEM;
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci	for (i = 0; i < *num_lockers; i++) {
3028c2ecf20Sopenharmony_ci		ret = decode_locker(p, end, *lockers + i);
3038c2ecf20Sopenharmony_ci		if (ret)
3048c2ecf20Sopenharmony_ci			goto err_free_lockers;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	*type = ceph_decode_8(p);
3088c2ecf20Sopenharmony_ci	s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
3098c2ecf20Sopenharmony_ci	if (IS_ERR(s)) {
3108c2ecf20Sopenharmony_ci		ret = PTR_ERR(s);
3118c2ecf20Sopenharmony_ci		goto err_free_lockers;
3128c2ecf20Sopenharmony_ci	}
3138c2ecf20Sopenharmony_ci
3148c2ecf20Sopenharmony_ci	*tag = s;
3158c2ecf20Sopenharmony_ci	return 0;
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_cierr_free_lockers:
3188c2ecf20Sopenharmony_ci	ceph_free_lockers(*lockers, *num_lockers);
3198c2ecf20Sopenharmony_ci	return ret;
3208c2ecf20Sopenharmony_ci}
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci/*
3238c2ecf20Sopenharmony_ci * On success, the caller is responsible for:
3248c2ecf20Sopenharmony_ci *
3258c2ecf20Sopenharmony_ci *     kfree(tag);
3268c2ecf20Sopenharmony_ci *     ceph_free_lockers(lockers, num_lockers);
3278c2ecf20Sopenharmony_ci */
3288c2ecf20Sopenharmony_ciint ceph_cls_lock_info(struct ceph_osd_client *osdc,
3298c2ecf20Sopenharmony_ci		       struct ceph_object_id *oid,
3308c2ecf20Sopenharmony_ci		       struct ceph_object_locator *oloc,
3318c2ecf20Sopenharmony_ci		       char *lock_name, u8 *type, char **tag,
3328c2ecf20Sopenharmony_ci		       struct ceph_locker **lockers, u32 *num_lockers)
3338c2ecf20Sopenharmony_ci{
3348c2ecf20Sopenharmony_ci	int get_info_op_buf_size;
3358c2ecf20Sopenharmony_ci	int name_len = strlen(lock_name);
3368c2ecf20Sopenharmony_ci	struct page *get_info_op_page, *reply_page;
3378c2ecf20Sopenharmony_ci	size_t reply_len = PAGE_SIZE;
3388c2ecf20Sopenharmony_ci	void *p, *end;
3398c2ecf20Sopenharmony_ci	int ret;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	get_info_op_buf_size = name_len + sizeof(__le32) +
3428c2ecf20Sopenharmony_ci			       CEPH_ENCODING_START_BLK_LEN;
3438c2ecf20Sopenharmony_ci	if (get_info_op_buf_size > PAGE_SIZE)
3448c2ecf20Sopenharmony_ci		return -E2BIG;
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	get_info_op_page = alloc_page(GFP_NOIO);
3478c2ecf20Sopenharmony_ci	if (!get_info_op_page)
3488c2ecf20Sopenharmony_ci		return -ENOMEM;
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci	reply_page = alloc_page(GFP_NOIO);
3518c2ecf20Sopenharmony_ci	if (!reply_page) {
3528c2ecf20Sopenharmony_ci		__free_page(get_info_op_page);
3538c2ecf20Sopenharmony_ci		return -ENOMEM;
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	p = page_address(get_info_op_page);
3578c2ecf20Sopenharmony_ci	end = p + get_info_op_buf_size;
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci	/* encode cls_lock_get_info_op struct */
3608c2ecf20Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
3618c2ecf20Sopenharmony_ci			    get_info_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
3628c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	dout("%s lock_name %s\n", __func__, lock_name);
3658c2ecf20Sopenharmony_ci	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "get_info",
3668c2ecf20Sopenharmony_ci			     CEPH_OSD_FLAG_READ, get_info_op_page,
3678c2ecf20Sopenharmony_ci			     get_info_op_buf_size, &reply_page, &reply_len);
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ci	dout("%s: status %d\n", __func__, ret);
3708c2ecf20Sopenharmony_ci	if (ret >= 0) {
3718c2ecf20Sopenharmony_ci		p = page_address(reply_page);
3728c2ecf20Sopenharmony_ci		end = p + reply_len;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci		ret = decode_lockers(&p, end, type, tag, lockers, num_lockers);
3758c2ecf20Sopenharmony_ci	}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	__free_page(get_info_op_page);
3788c2ecf20Sopenharmony_ci	__free_page(reply_page);
3798c2ecf20Sopenharmony_ci	return ret;
3808c2ecf20Sopenharmony_ci}
3818c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_lock_info);
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_ciint ceph_cls_assert_locked(struct ceph_osd_request *req, int which,
3848c2ecf20Sopenharmony_ci			   char *lock_name, u8 type, char *cookie, char *tag)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	int assert_op_buf_size;
3878c2ecf20Sopenharmony_ci	int name_len = strlen(lock_name);
3888c2ecf20Sopenharmony_ci	int cookie_len = strlen(cookie);
3898c2ecf20Sopenharmony_ci	int tag_len = strlen(tag);
3908c2ecf20Sopenharmony_ci	struct page **pages;
3918c2ecf20Sopenharmony_ci	void *p, *end;
3928c2ecf20Sopenharmony_ci	int ret;
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci	assert_op_buf_size = name_len + sizeof(__le32) +
3958c2ecf20Sopenharmony_ci			     cookie_len + sizeof(__le32) +
3968c2ecf20Sopenharmony_ci			     tag_len + sizeof(__le32) +
3978c2ecf20Sopenharmony_ci			     sizeof(u8) + CEPH_ENCODING_START_BLK_LEN;
3988c2ecf20Sopenharmony_ci	if (assert_op_buf_size > PAGE_SIZE)
3998c2ecf20Sopenharmony_ci		return -E2BIG;
4008c2ecf20Sopenharmony_ci
4018c2ecf20Sopenharmony_ci	ret = osd_req_op_cls_init(req, which, "lock", "assert_locked");
4028c2ecf20Sopenharmony_ci	if (ret)
4038c2ecf20Sopenharmony_ci		return ret;
4048c2ecf20Sopenharmony_ci
4058c2ecf20Sopenharmony_ci	pages = ceph_alloc_page_vector(1, GFP_NOIO);
4068c2ecf20Sopenharmony_ci	if (IS_ERR(pages))
4078c2ecf20Sopenharmony_ci		return PTR_ERR(pages);
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ci	p = page_address(pages[0]);
4108c2ecf20Sopenharmony_ci	end = p + assert_op_buf_size;
4118c2ecf20Sopenharmony_ci
4128c2ecf20Sopenharmony_ci	/* encode cls_lock_assert_op struct */
4138c2ecf20Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
4148c2ecf20Sopenharmony_ci			    assert_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
4158c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
4168c2ecf20Sopenharmony_ci	ceph_encode_8(&p, type);
4178c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, cookie, cookie_len);
4188c2ecf20Sopenharmony_ci	ceph_encode_string(&p, end, tag, tag_len);
4198c2ecf20Sopenharmony_ci	WARN_ON(p != end);
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_ci	osd_req_op_cls_request_data_pages(req, which, pages, assert_op_buf_size,
4228c2ecf20Sopenharmony_ci					  0, false, true);
4238c2ecf20Sopenharmony_ci	return 0;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_assert_locked);
426