diff options
author | Douglas Fuller <dfuller@redhat.com> | 2015-06-18 16:06:10 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2016-08-24 17:49:15 -0400 |
commit | f66241cb99dac861aa2cedb9f05ffa98d70cbc6e (patch) | |
tree | f3ef9ad38ebb057b0e0942b2a87d585a8f3fb41f | |
parent | 428a715811fe74e8a8f09b830c8d3b5245096f8d (diff) |
libceph: support for advisory locking on RADOS objects
This patch adds support for rados lock, unlock and break lock.
Based heavily on code by Mike Christie <michaelc@cs.wisc.edu>.
Signed-off-by: Douglas Fuller <dfuller@redhat.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Mike Christie <mchristi@redhat.com>
Reviewed-by: Alex Elder <elder@linaro.org>
-rw-r--r-- | include/linux/ceph/cls_lock_client.h | 27 | ||||
-rw-r--r-- | net/ceph/Makefile | 1 | ||||
-rw-r--r-- | net/ceph/cls_lock_client.c | 180 |
3 files changed, 208 insertions, 0 deletions
diff --git a/include/linux/ceph/cls_lock_client.h b/include/linux/ceph/cls_lock_client.h new file mode 100644 index 000000000000..4e4dffef22bb --- /dev/null +++ b/include/linux/ceph/cls_lock_client.h | |||
@@ -0,0 +1,27 @@ | |||
1 | #ifndef _LINUX_CEPH_CLS_LOCK_CLIENT_H | ||
2 | #define _LINUX_CEPH_CLS_LOCK_CLIENT_H | ||
3 | |||
4 | #include <linux/ceph/osd_client.h> | ||
5 | |||
6 | enum ceph_cls_lock_type { | ||
7 | CEPH_CLS_LOCK_NONE = 0, | ||
8 | CEPH_CLS_LOCK_EXCLUSIVE = 1, | ||
9 | CEPH_CLS_LOCK_SHARED = 2, | ||
10 | }; | ||
11 | |||
12 | int ceph_cls_lock(struct ceph_osd_client *osdc, | ||
13 | struct ceph_object_id *oid, | ||
14 | struct ceph_object_locator *oloc, | ||
15 | char *lock_name, u8 type, char *cookie, | ||
16 | char *tag, char *desc, u8 flags); | ||
17 | int ceph_cls_unlock(struct ceph_osd_client *osdc, | ||
18 | struct ceph_object_id *oid, | ||
19 | struct ceph_object_locator *oloc, | ||
20 | char *lock_name, char *cookie); | ||
21 | int ceph_cls_break_lock(struct ceph_osd_client *osdc, | ||
22 | struct ceph_object_id *oid, | ||
23 | struct ceph_object_locator *oloc, | ||
24 | char *lock_name, char *cookie, | ||
25 | struct ceph_entity_name *locker); | ||
26 | |||
27 | #endif | ||
diff --git a/net/ceph/Makefile b/net/ceph/Makefile index 84cbed630c4b..6a5180903e7b 100644 --- a/net/ceph/Makefile +++ b/net/ceph/Makefile | |||
@@ -5,6 +5,7 @@ obj-$(CONFIG_CEPH_LIB) += libceph.o | |||
5 | 5 | ||
6 | libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \ | 6 | libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \ |
7 | mon_client.o \ | 7 | mon_client.o \ |
8 | cls_lock_client.o \ | ||
8 | osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \ | 9 | osd_client.o osdmap.o crush/crush.o crush/mapper.o crush/hash.o \ |
9 | debugfs.o \ | 10 | debugfs.o \ |
10 | auth.o auth_none.o \ | 11 | auth.o auth_none.o \ |
diff --git a/net/ceph/cls_lock_client.c b/net/ceph/cls_lock_client.c new file mode 100644 index 000000000000..2a314537f958 --- /dev/null +++ b/net/ceph/cls_lock_client.c | |||
@@ -0,0 +1,180 @@ | |||
1 | #include <linux/ceph/ceph_debug.h> | ||
2 | |||
3 | #include <linux/types.h> | ||
4 | #include <linux/slab.h> | ||
5 | |||
6 | #include <linux/ceph/cls_lock_client.h> | ||
7 | #include <linux/ceph/decode.h> | ||
8 | |||
9 | /** | ||
10 | * ceph_cls_lock - grab rados lock for object | ||
11 | * @oid, @oloc: object to lock | ||
12 | * @lock_name: the name of the lock | ||
13 | * @type: lock type (CEPH_CLS_LOCK_EXCLUSIVE or CEPH_CLS_LOCK_SHARED) | ||
14 | * @cookie: user-defined identifier for this instance of the lock | ||
15 | * @tag: user-defined tag | ||
16 | * @desc: user-defined lock description | ||
17 | * @flags: lock flags | ||
18 | * | ||
19 | * All operations on the same lock should use the same tag. | ||
20 | */ | ||
21 | int ceph_cls_lock(struct ceph_osd_client *osdc, | ||
22 | struct ceph_object_id *oid, | ||
23 | struct ceph_object_locator *oloc, | ||
24 | char *lock_name, u8 type, char *cookie, | ||
25 | char *tag, char *desc, u8 flags) | ||
26 | { | ||
27 | int lock_op_buf_size; | ||
28 | int name_len = strlen(lock_name); | ||
29 | int cookie_len = strlen(cookie); | ||
30 | int tag_len = strlen(tag); | ||
31 | int desc_len = strlen(desc); | ||
32 | void *p, *end; | ||
33 | struct page *lock_op_page; | ||
34 | struct timespec mtime; | ||
35 | int ret; | ||
36 | |||
37 | lock_op_buf_size = name_len + sizeof(__le32) + | ||
38 | cookie_len + sizeof(__le32) + | ||
39 | tag_len + sizeof(__le32) + | ||
40 | desc_len + sizeof(__le32) + | ||
41 | sizeof(struct ceph_timespec) + | ||
42 | /* flag and type */ | ||
43 | sizeof(u8) + sizeof(u8) + | ||
44 | CEPH_ENCODING_START_BLK_LEN; | ||
45 | if (lock_op_buf_size > PAGE_SIZE) | ||
46 | return -E2BIG; | ||
47 | |||
48 | lock_op_page = alloc_page(GFP_NOIO); | ||
49 | if (!lock_op_page) | ||
50 | return -ENOMEM; | ||
51 | |||
52 | p = page_address(lock_op_page); | ||
53 | end = p + lock_op_buf_size; | ||
54 | |||
55 | /* encode cls_lock_lock_op struct */ | ||
56 | ceph_start_encoding(&p, 1, 1, | ||
57 | lock_op_buf_size - CEPH_ENCODING_START_BLK_LEN); | ||
58 | ceph_encode_string(&p, end, lock_name, name_len); | ||
59 | ceph_encode_8(&p, type); | ||
60 | ceph_encode_string(&p, end, cookie, cookie_len); | ||
61 | ceph_encode_string(&p, end, tag, tag_len); | ||
62 | ceph_encode_string(&p, end, desc, desc_len); | ||
63 | /* only support infinite duration */ | ||
64 | memset(&mtime, 0, sizeof(mtime)); | ||
65 | ceph_encode_timespec(p, &mtime); | ||
66 | p += sizeof(struct ceph_timespec); | ||
67 | ceph_encode_8(&p, flags); | ||
68 | |||
69 | dout("%s lock_name %s type %d cookie %s tag %s desc %s flags 0x%x\n", | ||
70 | __func__, lock_name, type, cookie, tag, desc, flags); | ||
71 | ret = ceph_osdc_call(osdc, oid, oloc, "lock", "lock", | ||
72 | CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, | ||
73 | lock_op_page, lock_op_buf_size, NULL, NULL); | ||
74 | |||
75 | dout("%s: status %d\n", __func__, ret); | ||
76 | __free_page(lock_op_page); | ||
77 | return ret; | ||
78 | } | ||
79 | EXPORT_SYMBOL(ceph_cls_lock); | ||
80 | |||
81 | /** | ||
82 | * ceph_cls_unlock - release rados lock for object | ||
83 | * @oid, @oloc: object to lock | ||
84 | * @lock_name: the name of the lock | ||
85 | * @cookie: user-defined identifier for this instance of the lock | ||
86 | */ | ||
87 | int ceph_cls_unlock(struct ceph_osd_client *osdc, | ||
88 | struct ceph_object_id *oid, | ||
89 | struct ceph_object_locator *oloc, | ||
90 | char *lock_name, char *cookie) | ||
91 | { | ||
92 | int unlock_op_buf_size; | ||
93 | int name_len = strlen(lock_name); | ||
94 | int cookie_len = strlen(cookie); | ||
95 | void *p, *end; | ||
96 | struct page *unlock_op_page; | ||
97 | int ret; | ||
98 | |||
99 | unlock_op_buf_size = name_len + sizeof(__le32) + | ||
100 | cookie_len + sizeof(__le32) + | ||
101 | CEPH_ENCODING_START_BLK_LEN; | ||
102 | if (unlock_op_buf_size > PAGE_SIZE) | ||
103 | return -E2BIG; | ||
104 | |||
105 | unlock_op_page = alloc_page(GFP_NOIO); | ||
106 | if (!unlock_op_page) | ||
107 | return -ENOMEM; | ||
108 | |||
109 | p = page_address(unlock_op_page); | ||
110 | end = p + unlock_op_buf_size; | ||
111 | |||
112 | /* encode cls_lock_unlock_op struct */ | ||
113 | ceph_start_encoding(&p, 1, 1, | ||
114 | unlock_op_buf_size - CEPH_ENCODING_START_BLK_LEN); | ||
115 | ceph_encode_string(&p, end, lock_name, name_len); | ||
116 | ceph_encode_string(&p, end, cookie, cookie_len); | ||
117 | |||
118 | dout("%s lock_name %s cookie %s\n", __func__, lock_name, cookie); | ||
119 | ret = ceph_osdc_call(osdc, oid, oloc, "lock", "unlock", | ||
120 | CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, | ||
121 | unlock_op_page, unlock_op_buf_size, NULL, NULL); | ||
122 | |||
123 | dout("%s: status %d\n", __func__, ret); | ||
124 | __free_page(unlock_op_page); | ||
125 | return ret; | ||
126 | } | ||
127 | EXPORT_SYMBOL(ceph_cls_unlock); | ||
128 | |||
129 | /** | ||
130 | * ceph_cls_break_lock - release rados lock for object for specified client | ||
131 | * @oid, @oloc: object to lock | ||
132 | * @lock_name: the name of the lock | ||
133 | * @cookie: user-defined identifier for this instance of the lock | ||
134 | * @locker: current lock owner | ||
135 | */ | ||
136 | int ceph_cls_break_lock(struct ceph_osd_client *osdc, | ||
137 | struct ceph_object_id *oid, | ||
138 | struct ceph_object_locator *oloc, | ||
139 | char *lock_name, char *cookie, | ||
140 | struct ceph_entity_name *locker) | ||
141 | { | ||
142 | int break_op_buf_size; | ||
143 | int name_len = strlen(lock_name); | ||
144 | int cookie_len = strlen(cookie); | ||
145 | struct page *break_op_page; | ||
146 | void *p, *end; | ||
147 | int ret; | ||
148 | |||
149 | break_op_buf_size = name_len + sizeof(__le32) + | ||
150 | cookie_len + sizeof(__le32) + | ||
151 | sizeof(u8) + sizeof(__le64) + | ||
152 | CEPH_ENCODING_START_BLK_LEN; | ||
153 | if (break_op_buf_size > PAGE_SIZE) | ||
154 | return -E2BIG; | ||
155 | |||
156 | break_op_page = alloc_page(GFP_NOIO); | ||
157 | if (!break_op_page) | ||
158 | return -ENOMEM; | ||
159 | |||
160 | p = page_address(break_op_page); | ||
161 | end = p + break_op_buf_size; | ||
162 | |||
163 | /* encode cls_lock_break_op struct */ | ||
164 | ceph_start_encoding(&p, 1, 1, | ||
165 | break_op_buf_size - CEPH_ENCODING_START_BLK_LEN); | ||
166 | ceph_encode_string(&p, end, lock_name, name_len); | ||
167 | ceph_encode_copy(&p, locker, sizeof(*locker)); | ||
168 | ceph_encode_string(&p, end, cookie, cookie_len); | ||
169 | |||
170 | dout("%s lock_name %s cookie %s locker %s%llu\n", __func__, lock_name, | ||
171 | cookie, ENTITY_NAME(*locker)); | ||
172 | ret = ceph_osdc_call(osdc, oid, oloc, "lock", "break_lock", | ||
173 | CEPH_OSD_FLAG_WRITE | CEPH_OSD_FLAG_ONDISK, | ||
174 | break_op_page, break_op_buf_size, NULL, NULL); | ||
175 | |||
176 | dout("%s: status %d\n", __func__, ret); | ||
177 | __free_page(break_op_page); | ||
178 | return ret; | ||
179 | } | ||
180 | EXPORT_SYMBOL(ceph_cls_break_lock); | ||