]>
Commit | Line | Data |
---|---|---|
f67539c2 | 1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
11fdf7f2 TL |
2 | // vim: ts=8 sw=2 smarttab |
3 | ||
4 | #include <errno.h> | |
5 | ||
6 | #include "objclass/objclass.h" | |
7 | #include "cls_cas_ops.h" | |
f67539c2 | 8 | #include "cls_cas_internal.h" |
11fdf7f2 TL |
9 | |
10 | #include "include/compat.h" | |
11 | #include "osd/osd_types.h" | |
12 | ||
f67539c2 TL |
13 | using ceph::bufferlist; |
14 | using ceph::decode; | |
15 | ||
11fdf7f2 TL |
16 | CLS_VER(1,0) |
17 | CLS_NAME(cas) | |
18 | ||
11fdf7f2 | 19 | |
f67539c2 TL |
20 | // |
21 | // helpers | |
22 | // | |
23 | ||
24 | static int chunk_read_refcount( | |
25 | cls_method_context_t hctx, | |
26 | chunk_refs_t *objr) | |
11fdf7f2 TL |
27 | { |
28 | bufferlist bl; | |
f67539c2 | 29 | objr->clear(); |
11fdf7f2 TL |
30 | int ret = cls_cxx_getxattr(hctx, CHUNK_REFCOUNT_ATTR, &bl); |
31 | if (ret == -ENODATA) { | |
32 | return 0; | |
33 | } | |
34 | if (ret < 0) | |
35 | return ret; | |
36 | ||
37 | try { | |
38 | auto iter = bl.cbegin(); | |
39 | decode(*objr, iter); | |
f67539c2 | 40 | } catch (ceph::buffer::error& err) { |
11fdf7f2 TL |
41 | CLS_LOG(0, "ERROR: chunk_read_refcount(): failed to decode refcount entry\n"); |
42 | return -EIO; | |
43 | } | |
44 | ||
45 | return 0; | |
46 | } | |
47 | ||
f67539c2 TL |
48 | static int chunk_set_refcount( |
49 | cls_method_context_t hctx, | |
50 | const struct chunk_refs_t& objr) | |
11fdf7f2 TL |
51 | { |
52 | bufferlist bl; | |
53 | ||
54 | encode(objr, bl); | |
55 | ||
56 | int ret = cls_cxx_setxattr(hctx, CHUNK_REFCOUNT_ATTR, &bl); | |
57 | if (ret < 0) | |
58 | return ret; | |
59 | ||
60 | return 0; | |
61 | } | |
62 | ||
f67539c2 TL |
63 | |
64 | // | |
65 | // methods | |
66 | // | |
67 | ||
68 | static int chunk_create_or_get_ref(cls_method_context_t hctx, | |
69 | bufferlist *in, bufferlist *out) | |
11fdf7f2 TL |
70 | { |
71 | auto in_iter = in->cbegin(); | |
72 | ||
f67539c2 | 73 | cls_cas_chunk_create_or_get_ref_op op; |
11fdf7f2 TL |
74 | try { |
75 | decode(op, in_iter); | |
f67539c2 TL |
76 | } catch (ceph::buffer::error& err) { |
77 | CLS_LOG(1, "ERROR: failed to decode entry\n"); | |
11fdf7f2 TL |
78 | return -EINVAL; |
79 | } | |
80 | ||
f67539c2 | 81 | chunk_refs_t objr; |
11fdf7f2 | 82 | int ret = chunk_read_refcount(hctx, &objr); |
f67539c2 TL |
83 | if (ret == -ENOENT) { |
84 | // new chunk; init refs | |
85 | CLS_LOG(10, "create oid=%s\n", | |
86 | op.source.oid.name.c_str()); | |
87 | ret = cls_cxx_write_full(hctx, &op.data); | |
88 | if (ret < 0) { | |
89 | return ret; | |
90 | } | |
91 | objr.get(op.source); | |
92 | ret = chunk_set_refcount(hctx, objr); | |
93 | if (ret < 0) { | |
94 | return ret; | |
95 | } | |
96 | } else if (ret < 0) { | |
11fdf7f2 | 97 | return ret; |
f67539c2 TL |
98 | } else { |
99 | // existing chunk; inc ref | |
100 | if (op.flags & cls_cas_chunk_create_or_get_ref_op::FLAG_VERIFY) { | |
101 | bufferlist old; | |
102 | cls_cxx_read(hctx, 0, 0, &old); | |
103 | if (!old.contents_equal(op.data)) { | |
104 | return -ENOMSG; | |
105 | } | |
106 | } | |
107 | CLS_LOG(10, "inc ref oid=%s\n", | |
108 | op.source.oid.name.c_str()); | |
11fdf7f2 | 109 | |
f67539c2 | 110 | objr.get(op.source); |
11fdf7f2 | 111 | |
f67539c2 TL |
112 | ret = chunk_set_refcount(hctx, objr); |
113 | if (ret < 0) { | |
114 | return ret; | |
115 | } | |
116 | } | |
11fdf7f2 TL |
117 | return 0; |
118 | } | |
119 | ||
f67539c2 TL |
120 | static int chunk_get_ref(cls_method_context_t hctx, |
121 | bufferlist *in, bufferlist *out) | |
11fdf7f2 TL |
122 | { |
123 | auto in_iter = in->cbegin(); | |
124 | ||
f67539c2 | 125 | cls_cas_chunk_get_ref_op op; |
11fdf7f2 TL |
126 | try { |
127 | decode(op, in_iter); | |
f67539c2 TL |
128 | } catch (ceph::buffer::error& err) { |
129 | CLS_LOG(1, "ERROR: failed to decode entry\n"); | |
11fdf7f2 TL |
130 | return -EINVAL; |
131 | } | |
132 | ||
f67539c2 | 133 | chunk_refs_t objr; |
11fdf7f2 | 134 | int ret = chunk_read_refcount(hctx, &objr); |
f67539c2 TL |
135 | if (ret < 0) { |
136 | CLS_LOG(1, "ERROR: failed to read attr\n"); | |
11fdf7f2 | 137 | return ret; |
11fdf7f2 TL |
138 | } |
139 | ||
f67539c2 TL |
140 | // existing chunk; inc ref |
141 | CLS_LOG(10, "oid=%s\n", op.source.oid.name.c_str()); | |
142 | ||
143 | objr.get(op.source); | |
11fdf7f2 TL |
144 | |
145 | ret = chunk_set_refcount(hctx, objr); | |
f67539c2 | 146 | if (ret < 0) { |
11fdf7f2 | 147 | return ret; |
f67539c2 | 148 | } |
11fdf7f2 TL |
149 | return 0; |
150 | } | |
151 | ||
f67539c2 TL |
152 | static int chunk_put_ref(cls_method_context_t hctx, |
153 | bufferlist *in, bufferlist *out) | |
11fdf7f2 TL |
154 | { |
155 | auto in_iter = in->cbegin(); | |
156 | ||
f67539c2 | 157 | cls_cas_chunk_put_ref_op op; |
11fdf7f2 TL |
158 | try { |
159 | decode(op, in_iter); | |
f67539c2 TL |
160 | } catch (ceph::buffer::error& err) { |
161 | CLS_LOG(1, "ERROR: failed to decode entry\n"); | |
11fdf7f2 TL |
162 | return -EINVAL; |
163 | } | |
164 | ||
f67539c2 | 165 | chunk_refs_t objr; |
11fdf7f2 TL |
166 | int ret = chunk_read_refcount(hctx, &objr); |
167 | if (ret < 0) | |
168 | return ret; | |
169 | ||
f67539c2 TL |
170 | if (!objr.put(op.source)) { |
171 | CLS_LOG(10, "oid=%s (no ref)\n", op.source.oid.name.c_str()); | |
172 | return -ENOLINK; | |
11fdf7f2 TL |
173 | } |
174 | ||
f67539c2 TL |
175 | if (objr.empty()) { |
176 | CLS_LOG(10, "oid=%s (last ref)\n", op.source.oid.name.c_str()); | |
177 | return cls_cxx_remove(hctx); | |
11fdf7f2 TL |
178 | } |
179 | ||
f67539c2 | 180 | CLS_LOG(10, "oid=%s (dec)\n", op.source.oid.name.c_str()); |
11fdf7f2 TL |
181 | ret = chunk_set_refcount(hctx, objr); |
182 | if (ret < 0) | |
183 | return ret; | |
184 | ||
185 | return 0; | |
186 | } | |
187 | ||
f67539c2 TL |
188 | static int references_chunk(cls_method_context_t hctx, |
189 | bufferlist *in, bufferlist *out) | |
11fdf7f2 TL |
190 | { |
191 | auto in_iter = in->cbegin(); | |
f67539c2 | 192 | std::string fp_oid; |
11fdf7f2 TL |
193 | bufferlist indata, outdata; |
194 | try { | |
195 | decode (fp_oid, in_iter); | |
196 | } | |
f67539c2 | 197 | catch (ceph::buffer::error& e) { |
11fdf7f2 TL |
198 | return -EINVAL; |
199 | } | |
f67539c2 | 200 | CLS_LOG(10, "fp_oid: %s \n", fp_oid.c_str()); |
11fdf7f2 | 201 | |
f67539c2 | 202 | int ret = cls_get_manifest_ref_count(hctx, fp_oid); |
11fdf7f2 | 203 | if (ret) { |
f67539c2 | 204 | return ret; |
11fdf7f2 | 205 | } |
f67539c2 | 206 | return -ENOLINK; |
11fdf7f2 TL |
207 | } |
208 | ||
209 | CLS_INIT(cas) | |
210 | { | |
211 | CLS_LOG(1, "Loaded cas class!"); | |
212 | ||
213 | cls_handle_t h_class; | |
f67539c2 TL |
214 | cls_method_handle_t h_chunk_create_or_get_ref; |
215 | cls_method_handle_t h_chunk_get_ref; | |
216 | cls_method_handle_t h_chunk_put_ref; | |
217 | cls_method_handle_t h_references_chunk; | |
11fdf7f2 TL |
218 | |
219 | cls_register("cas", &h_class); | |
220 | ||
f67539c2 TL |
221 | cls_register_cxx_method(h_class, "chunk_create_or_get_ref", |
222 | CLS_METHOD_RD | CLS_METHOD_WR, | |
223 | chunk_create_or_get_ref, | |
224 | &h_chunk_create_or_get_ref); | |
225 | cls_register_cxx_method(h_class, "chunk_get_ref", | |
226 | CLS_METHOD_RD | CLS_METHOD_WR, | |
227 | chunk_get_ref, | |
228 | &h_chunk_get_ref); | |
229 | cls_register_cxx_method(h_class, "chunk_put_ref", | |
230 | CLS_METHOD_RD | CLS_METHOD_WR, | |
231 | chunk_put_ref, | |
232 | &h_chunk_put_ref); | |
233 | cls_register_cxx_method(h_class, "references_chunk", CLS_METHOD_RD, | |
234 | references_chunk, | |
235 | &h_references_chunk); | |
11fdf7f2 TL |
236 | |
237 | return; | |
238 | } | |
239 |