162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <linux/ceph/ceph_debug.h>
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <linux/types.h>
562306a36Sopenharmony_ci#include <linux/slab.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/ceph/cls_lock_client.h>
862306a36Sopenharmony_ci#include <linux/ceph/decode.h>
962306a36Sopenharmony_ci#include <linux/ceph/libceph.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci/**
1262306a36Sopenharmony_ci * ceph_cls_lock - grab rados lock for object
1362306a36Sopenharmony_ci * @osdc: OSD client instance
1462306a36Sopenharmony_ci * @oid: object to lock
1562306a36Sopenharmony_ci * @oloc: object to lock
1662306a36Sopenharmony_ci * @lock_name: the name of the lock
1762306a36Sopenharmony_ci * @type: lock type (CEPH_CLS_LOCK_EXCLUSIVE or CEPH_CLS_LOCK_SHARED)
1862306a36Sopenharmony_ci * @cookie: user-defined identifier for this instance of the lock
1962306a36Sopenharmony_ci * @tag: user-defined tag
2062306a36Sopenharmony_ci * @desc: user-defined lock description
2162306a36Sopenharmony_ci * @flags: lock flags
2262306a36Sopenharmony_ci *
2362306a36Sopenharmony_ci * All operations on the same lock should use the same tag.
2462306a36Sopenharmony_ci */
2562306a36Sopenharmony_ciint ceph_cls_lock(struct ceph_osd_client *osdc,
2662306a36Sopenharmony_ci		  struct ceph_object_id *oid,
2762306a36Sopenharmony_ci		  struct ceph_object_locator *oloc,
2862306a36Sopenharmony_ci		  char *lock_name, u8 type, char *cookie,
2962306a36Sopenharmony_ci		  char *tag, char *desc, u8 flags)
3062306a36Sopenharmony_ci{
3162306a36Sopenharmony_ci	int lock_op_buf_size;
3262306a36Sopenharmony_ci	int name_len = strlen(lock_name);
3362306a36Sopenharmony_ci	int cookie_len = strlen(cookie);
3462306a36Sopenharmony_ci	int tag_len = strlen(tag);
3562306a36Sopenharmony_ci	int desc_len = strlen(desc);
3662306a36Sopenharmony_ci	void *p, *end;
3762306a36Sopenharmony_ci	struct page *lock_op_page;
3862306a36Sopenharmony_ci	struct timespec64 mtime;
3962306a36Sopenharmony_ci	int ret;
4062306a36Sopenharmony_ci
4162306a36Sopenharmony_ci	lock_op_buf_size = name_len + sizeof(__le32) +
4262306a36Sopenharmony_ci			   cookie_len + sizeof(__le32) +
4362306a36Sopenharmony_ci			   tag_len + sizeof(__le32) +
4462306a36Sopenharmony_ci			   desc_len + sizeof(__le32) +
4562306a36Sopenharmony_ci			   sizeof(struct ceph_timespec) +
4662306a36Sopenharmony_ci			   /* flag and type */
4762306a36Sopenharmony_ci			   sizeof(u8) + sizeof(u8) +
4862306a36Sopenharmony_ci			   CEPH_ENCODING_START_BLK_LEN;
4962306a36Sopenharmony_ci	if (lock_op_buf_size > PAGE_SIZE)
5062306a36Sopenharmony_ci		return -E2BIG;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	lock_op_page = alloc_page(GFP_NOIO);
5362306a36Sopenharmony_ci	if (!lock_op_page)
5462306a36Sopenharmony_ci		return -ENOMEM;
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	p = page_address(lock_op_page);
5762306a36Sopenharmony_ci	end = p + lock_op_buf_size;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	/* encode cls_lock_lock_op struct */
6062306a36Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
6162306a36Sopenharmony_ci			    lock_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
6262306a36Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
6362306a36Sopenharmony_ci	ceph_encode_8(&p, type);
6462306a36Sopenharmony_ci	ceph_encode_string(&p, end, cookie, cookie_len);
6562306a36Sopenharmony_ci	ceph_encode_string(&p, end, tag, tag_len);
6662306a36Sopenharmony_ci	ceph_encode_string(&p, end, desc, desc_len);
6762306a36Sopenharmony_ci	/* only support infinite duration */
6862306a36Sopenharmony_ci	memset(&mtime, 0, sizeof(mtime));
6962306a36Sopenharmony_ci	ceph_encode_timespec64(p, &mtime);
7062306a36Sopenharmony_ci	p += sizeof(struct ceph_timespec);
7162306a36Sopenharmony_ci	ceph_encode_8(&p, flags);
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci	dout("%s lock_name %s type %d cookie %s tag %s desc %s flags 0x%x\n",
7462306a36Sopenharmony_ci	     __func__, lock_name, type, cookie, tag, desc, flags);
7562306a36Sopenharmony_ci	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "lock",
7662306a36Sopenharmony_ci			     CEPH_OSD_FLAG_WRITE, lock_op_page,
7762306a36Sopenharmony_ci			     lock_op_buf_size, NULL, NULL);
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci	dout("%s: status %d\n", __func__, ret);
8062306a36Sopenharmony_ci	__free_page(lock_op_page);
8162306a36Sopenharmony_ci	return ret;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_lock);
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci/**
8662306a36Sopenharmony_ci * ceph_cls_unlock - release rados lock for object
8762306a36Sopenharmony_ci * @osdc: OSD client instance
8862306a36Sopenharmony_ci * @oid: object to lock
8962306a36Sopenharmony_ci * @oloc: object to lock
9062306a36Sopenharmony_ci * @lock_name: the name of the lock
9162306a36Sopenharmony_ci * @cookie: user-defined identifier for this instance of the lock
9262306a36Sopenharmony_ci */
9362306a36Sopenharmony_ciint ceph_cls_unlock(struct ceph_osd_client *osdc,
9462306a36Sopenharmony_ci		    struct ceph_object_id *oid,
9562306a36Sopenharmony_ci		    struct ceph_object_locator *oloc,
9662306a36Sopenharmony_ci		    char *lock_name, char *cookie)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	int unlock_op_buf_size;
9962306a36Sopenharmony_ci	int name_len = strlen(lock_name);
10062306a36Sopenharmony_ci	int cookie_len = strlen(cookie);
10162306a36Sopenharmony_ci	void *p, *end;
10262306a36Sopenharmony_ci	struct page *unlock_op_page;
10362306a36Sopenharmony_ci	int ret;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	unlock_op_buf_size = name_len + sizeof(__le32) +
10662306a36Sopenharmony_ci			     cookie_len + sizeof(__le32) +
10762306a36Sopenharmony_ci			     CEPH_ENCODING_START_BLK_LEN;
10862306a36Sopenharmony_ci	if (unlock_op_buf_size > PAGE_SIZE)
10962306a36Sopenharmony_ci		return -E2BIG;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	unlock_op_page = alloc_page(GFP_NOIO);
11262306a36Sopenharmony_ci	if (!unlock_op_page)
11362306a36Sopenharmony_ci		return -ENOMEM;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	p = page_address(unlock_op_page);
11662306a36Sopenharmony_ci	end = p + unlock_op_buf_size;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	/* encode cls_lock_unlock_op struct */
11962306a36Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
12062306a36Sopenharmony_ci			    unlock_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
12162306a36Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
12262306a36Sopenharmony_ci	ceph_encode_string(&p, end, cookie, cookie_len);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	dout("%s lock_name %s cookie %s\n", __func__, lock_name, cookie);
12562306a36Sopenharmony_ci	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "unlock",
12662306a36Sopenharmony_ci			     CEPH_OSD_FLAG_WRITE, unlock_op_page,
12762306a36Sopenharmony_ci			     unlock_op_buf_size, NULL, NULL);
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	dout("%s: status %d\n", __func__, ret);
13062306a36Sopenharmony_ci	__free_page(unlock_op_page);
13162306a36Sopenharmony_ci	return ret;
13262306a36Sopenharmony_ci}
13362306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_unlock);
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci/**
13662306a36Sopenharmony_ci * ceph_cls_break_lock - release rados lock for object for specified client
13762306a36Sopenharmony_ci * @osdc: OSD client instance
13862306a36Sopenharmony_ci * @oid: object to lock
13962306a36Sopenharmony_ci * @oloc: object to lock
14062306a36Sopenharmony_ci * @lock_name: the name of the lock
14162306a36Sopenharmony_ci * @cookie: user-defined identifier for this instance of the lock
14262306a36Sopenharmony_ci * @locker: current lock owner
14362306a36Sopenharmony_ci */
14462306a36Sopenharmony_ciint ceph_cls_break_lock(struct ceph_osd_client *osdc,
14562306a36Sopenharmony_ci			struct ceph_object_id *oid,
14662306a36Sopenharmony_ci			struct ceph_object_locator *oloc,
14762306a36Sopenharmony_ci			char *lock_name, char *cookie,
14862306a36Sopenharmony_ci			struct ceph_entity_name *locker)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	int break_op_buf_size;
15162306a36Sopenharmony_ci	int name_len = strlen(lock_name);
15262306a36Sopenharmony_ci	int cookie_len = strlen(cookie);
15362306a36Sopenharmony_ci	struct page *break_op_page;
15462306a36Sopenharmony_ci	void *p, *end;
15562306a36Sopenharmony_ci	int ret;
15662306a36Sopenharmony_ci
15762306a36Sopenharmony_ci	break_op_buf_size = name_len + sizeof(__le32) +
15862306a36Sopenharmony_ci			    cookie_len + sizeof(__le32) +
15962306a36Sopenharmony_ci			    sizeof(u8) + sizeof(__le64) +
16062306a36Sopenharmony_ci			    CEPH_ENCODING_START_BLK_LEN;
16162306a36Sopenharmony_ci	if (break_op_buf_size > PAGE_SIZE)
16262306a36Sopenharmony_ci		return -E2BIG;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	break_op_page = alloc_page(GFP_NOIO);
16562306a36Sopenharmony_ci	if (!break_op_page)
16662306a36Sopenharmony_ci		return -ENOMEM;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	p = page_address(break_op_page);
16962306a36Sopenharmony_ci	end = p + break_op_buf_size;
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_ci	/* encode cls_lock_break_op struct */
17262306a36Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
17362306a36Sopenharmony_ci			    break_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
17462306a36Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
17562306a36Sopenharmony_ci	ceph_encode_copy(&p, locker, sizeof(*locker));
17662306a36Sopenharmony_ci	ceph_encode_string(&p, end, cookie, cookie_len);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	dout("%s lock_name %s cookie %s locker %s%llu\n", __func__, lock_name,
17962306a36Sopenharmony_ci	     cookie, ENTITY_NAME(*locker));
18062306a36Sopenharmony_ci	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "break_lock",
18162306a36Sopenharmony_ci			     CEPH_OSD_FLAG_WRITE, break_op_page,
18262306a36Sopenharmony_ci			     break_op_buf_size, NULL, NULL);
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci	dout("%s: status %d\n", __func__, ret);
18562306a36Sopenharmony_ci	__free_page(break_op_page);
18662306a36Sopenharmony_ci	return ret;
18762306a36Sopenharmony_ci}
18862306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_break_lock);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ciint ceph_cls_set_cookie(struct ceph_osd_client *osdc,
19162306a36Sopenharmony_ci			struct ceph_object_id *oid,
19262306a36Sopenharmony_ci			struct ceph_object_locator *oloc,
19362306a36Sopenharmony_ci			char *lock_name, u8 type, char *old_cookie,
19462306a36Sopenharmony_ci			char *tag, char *new_cookie)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	int cookie_op_buf_size;
19762306a36Sopenharmony_ci	int name_len = strlen(lock_name);
19862306a36Sopenharmony_ci	int old_cookie_len = strlen(old_cookie);
19962306a36Sopenharmony_ci	int tag_len = strlen(tag);
20062306a36Sopenharmony_ci	int new_cookie_len = strlen(new_cookie);
20162306a36Sopenharmony_ci	void *p, *end;
20262306a36Sopenharmony_ci	struct page *cookie_op_page;
20362306a36Sopenharmony_ci	int ret;
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	cookie_op_buf_size = name_len + sizeof(__le32) +
20662306a36Sopenharmony_ci			     old_cookie_len + sizeof(__le32) +
20762306a36Sopenharmony_ci			     tag_len + sizeof(__le32) +
20862306a36Sopenharmony_ci			     new_cookie_len + sizeof(__le32) +
20962306a36Sopenharmony_ci			     sizeof(u8) + CEPH_ENCODING_START_BLK_LEN;
21062306a36Sopenharmony_ci	if (cookie_op_buf_size > PAGE_SIZE)
21162306a36Sopenharmony_ci		return -E2BIG;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	cookie_op_page = alloc_page(GFP_NOIO);
21462306a36Sopenharmony_ci	if (!cookie_op_page)
21562306a36Sopenharmony_ci		return -ENOMEM;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	p = page_address(cookie_op_page);
21862306a36Sopenharmony_ci	end = p + cookie_op_buf_size;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	/* encode cls_lock_set_cookie_op struct */
22162306a36Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
22262306a36Sopenharmony_ci			    cookie_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
22362306a36Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
22462306a36Sopenharmony_ci	ceph_encode_8(&p, type);
22562306a36Sopenharmony_ci	ceph_encode_string(&p, end, old_cookie, old_cookie_len);
22662306a36Sopenharmony_ci	ceph_encode_string(&p, end, tag, tag_len);
22762306a36Sopenharmony_ci	ceph_encode_string(&p, end, new_cookie, new_cookie_len);
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	dout("%s lock_name %s type %d old_cookie %s tag %s new_cookie %s\n",
23062306a36Sopenharmony_ci	     __func__, lock_name, type, old_cookie, tag, new_cookie);
23162306a36Sopenharmony_ci	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "set_cookie",
23262306a36Sopenharmony_ci			     CEPH_OSD_FLAG_WRITE, cookie_op_page,
23362306a36Sopenharmony_ci			     cookie_op_buf_size, NULL, NULL);
23462306a36Sopenharmony_ci
23562306a36Sopenharmony_ci	dout("%s: status %d\n", __func__, ret);
23662306a36Sopenharmony_ci	__free_page(cookie_op_page);
23762306a36Sopenharmony_ci	return ret;
23862306a36Sopenharmony_ci}
23962306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_set_cookie);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_civoid ceph_free_lockers(struct ceph_locker *lockers, u32 num_lockers)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	int i;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	for (i = 0; i < num_lockers; i++)
24662306a36Sopenharmony_ci		kfree(lockers[i].id.cookie);
24762306a36Sopenharmony_ci	kfree(lockers);
24862306a36Sopenharmony_ci}
24962306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_free_lockers);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_cistatic int decode_locker(void **p, void *end, struct ceph_locker *locker)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	u8 struct_v;
25462306a36Sopenharmony_ci	u32 len;
25562306a36Sopenharmony_ci	char *s;
25662306a36Sopenharmony_ci	int ret;
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci	ret = ceph_start_decoding(p, end, 1, "locker_id_t", &struct_v, &len);
25962306a36Sopenharmony_ci	if (ret)
26062306a36Sopenharmony_ci		return ret;
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	ceph_decode_copy(p, &locker->id.name, sizeof(locker->id.name));
26362306a36Sopenharmony_ci	s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
26462306a36Sopenharmony_ci	if (IS_ERR(s))
26562306a36Sopenharmony_ci		return PTR_ERR(s);
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	locker->id.cookie = s;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	ret = ceph_start_decoding(p, end, 1, "locker_info_t", &struct_v, &len);
27062306a36Sopenharmony_ci	if (ret)
27162306a36Sopenharmony_ci		return ret;
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	*p += sizeof(struct ceph_timespec); /* skip expiration */
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci	ret = ceph_decode_entity_addr(p, end, &locker->info.addr);
27662306a36Sopenharmony_ci	if (ret)
27762306a36Sopenharmony_ci		return ret;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci	len = ceph_decode_32(p);
28062306a36Sopenharmony_ci	*p += len; /* skip description */
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	dout("%s %s%llu cookie %s addr %s\n", __func__,
28362306a36Sopenharmony_ci	     ENTITY_NAME(locker->id.name), locker->id.cookie,
28462306a36Sopenharmony_ci	     ceph_pr_addr(&locker->info.addr));
28562306a36Sopenharmony_ci	return 0;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_cistatic int decode_lockers(void **p, void *end, u8 *type, char **tag,
28962306a36Sopenharmony_ci			  struct ceph_locker **lockers, u32 *num_lockers)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	u8 struct_v;
29262306a36Sopenharmony_ci	u32 struct_len;
29362306a36Sopenharmony_ci	char *s;
29462306a36Sopenharmony_ci	int i;
29562306a36Sopenharmony_ci	int ret;
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci	ret = ceph_start_decoding(p, end, 1, "cls_lock_get_info_reply",
29862306a36Sopenharmony_ci				  &struct_v, &struct_len);
29962306a36Sopenharmony_ci	if (ret)
30062306a36Sopenharmony_ci		return ret;
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	*num_lockers = ceph_decode_32(p);
30362306a36Sopenharmony_ci	*lockers = kcalloc(*num_lockers, sizeof(**lockers), GFP_NOIO);
30462306a36Sopenharmony_ci	if (!*lockers)
30562306a36Sopenharmony_ci		return -ENOMEM;
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	for (i = 0; i < *num_lockers; i++) {
30862306a36Sopenharmony_ci		ret = decode_locker(p, end, *lockers + i);
30962306a36Sopenharmony_ci		if (ret)
31062306a36Sopenharmony_ci			goto err_free_lockers;
31162306a36Sopenharmony_ci	}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	*type = ceph_decode_8(p);
31462306a36Sopenharmony_ci	s = ceph_extract_encoded_string(p, end, NULL, GFP_NOIO);
31562306a36Sopenharmony_ci	if (IS_ERR(s)) {
31662306a36Sopenharmony_ci		ret = PTR_ERR(s);
31762306a36Sopenharmony_ci		goto err_free_lockers;
31862306a36Sopenharmony_ci	}
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	*tag = s;
32162306a36Sopenharmony_ci	return 0;
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cierr_free_lockers:
32462306a36Sopenharmony_ci	ceph_free_lockers(*lockers, *num_lockers);
32562306a36Sopenharmony_ci	return ret;
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_ci/*
32962306a36Sopenharmony_ci * On success, the caller is responsible for:
33062306a36Sopenharmony_ci *
33162306a36Sopenharmony_ci *     kfree(tag);
33262306a36Sopenharmony_ci *     ceph_free_lockers(lockers, num_lockers);
33362306a36Sopenharmony_ci */
33462306a36Sopenharmony_ciint ceph_cls_lock_info(struct ceph_osd_client *osdc,
33562306a36Sopenharmony_ci		       struct ceph_object_id *oid,
33662306a36Sopenharmony_ci		       struct ceph_object_locator *oloc,
33762306a36Sopenharmony_ci		       char *lock_name, u8 *type, char **tag,
33862306a36Sopenharmony_ci		       struct ceph_locker **lockers, u32 *num_lockers)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	int get_info_op_buf_size;
34162306a36Sopenharmony_ci	int name_len = strlen(lock_name);
34262306a36Sopenharmony_ci	struct page *get_info_op_page, *reply_page;
34362306a36Sopenharmony_ci	size_t reply_len = PAGE_SIZE;
34462306a36Sopenharmony_ci	void *p, *end;
34562306a36Sopenharmony_ci	int ret;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	get_info_op_buf_size = name_len + sizeof(__le32) +
34862306a36Sopenharmony_ci			       CEPH_ENCODING_START_BLK_LEN;
34962306a36Sopenharmony_ci	if (get_info_op_buf_size > PAGE_SIZE)
35062306a36Sopenharmony_ci		return -E2BIG;
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci	get_info_op_page = alloc_page(GFP_NOIO);
35362306a36Sopenharmony_ci	if (!get_info_op_page)
35462306a36Sopenharmony_ci		return -ENOMEM;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	reply_page = alloc_page(GFP_NOIO);
35762306a36Sopenharmony_ci	if (!reply_page) {
35862306a36Sopenharmony_ci		__free_page(get_info_op_page);
35962306a36Sopenharmony_ci		return -ENOMEM;
36062306a36Sopenharmony_ci	}
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	p = page_address(get_info_op_page);
36362306a36Sopenharmony_ci	end = p + get_info_op_buf_size;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	/* encode cls_lock_get_info_op struct */
36662306a36Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
36762306a36Sopenharmony_ci			    get_info_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
36862306a36Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	dout("%s lock_name %s\n", __func__, lock_name);
37162306a36Sopenharmony_ci	ret = ceph_osdc_call(osdc, oid, oloc, "lock", "get_info",
37262306a36Sopenharmony_ci			     CEPH_OSD_FLAG_READ, get_info_op_page,
37362306a36Sopenharmony_ci			     get_info_op_buf_size, &reply_page, &reply_len);
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	dout("%s: status %d\n", __func__, ret);
37662306a36Sopenharmony_ci	if (ret >= 0) {
37762306a36Sopenharmony_ci		p = page_address(reply_page);
37862306a36Sopenharmony_ci		end = p + reply_len;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci		ret = decode_lockers(&p, end, type, tag, lockers, num_lockers);
38162306a36Sopenharmony_ci	}
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	__free_page(get_info_op_page);
38462306a36Sopenharmony_ci	__free_page(reply_page);
38562306a36Sopenharmony_ci	return ret;
38662306a36Sopenharmony_ci}
38762306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_lock_info);
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ciint ceph_cls_assert_locked(struct ceph_osd_request *req, int which,
39062306a36Sopenharmony_ci			   char *lock_name, u8 type, char *cookie, char *tag)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	int assert_op_buf_size;
39362306a36Sopenharmony_ci	int name_len = strlen(lock_name);
39462306a36Sopenharmony_ci	int cookie_len = strlen(cookie);
39562306a36Sopenharmony_ci	int tag_len = strlen(tag);
39662306a36Sopenharmony_ci	struct page **pages;
39762306a36Sopenharmony_ci	void *p, *end;
39862306a36Sopenharmony_ci	int ret;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci	assert_op_buf_size = name_len + sizeof(__le32) +
40162306a36Sopenharmony_ci			     cookie_len + sizeof(__le32) +
40262306a36Sopenharmony_ci			     tag_len + sizeof(__le32) +
40362306a36Sopenharmony_ci			     sizeof(u8) + CEPH_ENCODING_START_BLK_LEN;
40462306a36Sopenharmony_ci	if (assert_op_buf_size > PAGE_SIZE)
40562306a36Sopenharmony_ci		return -E2BIG;
40662306a36Sopenharmony_ci
40762306a36Sopenharmony_ci	ret = osd_req_op_cls_init(req, which, "lock", "assert_locked");
40862306a36Sopenharmony_ci	if (ret)
40962306a36Sopenharmony_ci		return ret;
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci	pages = ceph_alloc_page_vector(1, GFP_NOIO);
41262306a36Sopenharmony_ci	if (IS_ERR(pages))
41362306a36Sopenharmony_ci		return PTR_ERR(pages);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci	p = page_address(pages[0]);
41662306a36Sopenharmony_ci	end = p + assert_op_buf_size;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	/* encode cls_lock_assert_op struct */
41962306a36Sopenharmony_ci	ceph_start_encoding(&p, 1, 1,
42062306a36Sopenharmony_ci			    assert_op_buf_size - CEPH_ENCODING_START_BLK_LEN);
42162306a36Sopenharmony_ci	ceph_encode_string(&p, end, lock_name, name_len);
42262306a36Sopenharmony_ci	ceph_encode_8(&p, type);
42362306a36Sopenharmony_ci	ceph_encode_string(&p, end, cookie, cookie_len);
42462306a36Sopenharmony_ci	ceph_encode_string(&p, end, tag, tag_len);
42562306a36Sopenharmony_ci	WARN_ON(p != end);
42662306a36Sopenharmony_ci
42762306a36Sopenharmony_ci	osd_req_op_cls_request_data_pages(req, which, pages, assert_op_buf_size,
42862306a36Sopenharmony_ci					  0, false, true);
42962306a36Sopenharmony_ci	return 0;
43062306a36Sopenharmony_ci}
43162306a36Sopenharmony_ciEXPORT_SYMBOL(ceph_cls_assert_locked);
432