]> git.proxmox.com Git - ceph.git/blob - ceph/src/cls/refcount/cls_refcount.cc
add subtree-ish sources for 12.0.3
[ceph.git] / ceph / src / cls / refcount / cls_refcount.cc
1 // -*- mode:C; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3
4 #include <iostream>
5
6 #include <string.h>
7 #include <stdlib.h>
8 #include <errno.h>
9
10 #include "include/types.h"
11 #include "include/utime.h"
12 #include "objclass/objclass.h"
13 #include "cls/refcount/cls_refcount_ops.h"
14 #include "common/Clock.h"
15
16 #include "global/global_context.h"
17 #include "include/compat.h"
18
19 CLS_VER(1,0)
20 CLS_NAME(refcount)
21
22
23 #define REFCOUNT_ATTR "refcount"
24
25 struct obj_refcount {
26 map<string, bool> refs;
27
28 obj_refcount() {}
29
30 void encode(bufferlist& bl) const {
31 ENCODE_START(1, 1, bl);
32 ::encode(refs, bl);
33 ENCODE_FINISH(bl);
34 }
35
36 void decode(bufferlist::iterator& bl) {
37 DECODE_START(1, bl);
38 ::decode(refs, bl);
39 DECODE_FINISH(bl);
40 }
41 };
42 WRITE_CLASS_ENCODER(obj_refcount)
43
44 static string wildcard_tag;
45
46 static int read_refcount(cls_method_context_t hctx, bool implicit_ref, obj_refcount *objr)
47 {
48 bufferlist bl;
49 objr->refs.clear();
50 int ret = cls_cxx_getxattr(hctx, REFCOUNT_ATTR, &bl);
51 if (ret == -ENODATA) {
52 if (implicit_ref) {
53 objr->refs[wildcard_tag] = true;
54 }
55 return 0;
56 }
57 if (ret < 0)
58 return ret;
59
60 try {
61 bufferlist::iterator iter = bl.begin();
62 ::decode(*objr, iter);
63 } catch (buffer::error& err) {
64 CLS_LOG(0, "ERROR: read_refcount(): failed to decode refcount entry\n");
65 return -EIO;
66 }
67
68 return 0;
69 }
70
71 static int set_refcount(cls_method_context_t hctx, map<string, bool>& refs)
72 {
73 bufferlist bl;
74 struct obj_refcount objr;
75
76 objr.refs = refs;
77
78 ::encode(objr, bl);
79
80 int ret = cls_cxx_setxattr(hctx, REFCOUNT_ATTR, &bl);
81 if (ret < 0)
82 return ret;
83
84 return 0;
85 }
86
87 static int cls_rc_refcount_get(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
88 {
89 bufferlist::iterator in_iter = in->begin();
90
91 cls_refcount_get_op op;
92 try {
93 ::decode(op, in_iter);
94 } catch (buffer::error& err) {
95 CLS_LOG(1, "ERROR: cls_rc_refcount_get(): failed to decode entry\n");
96 return -EINVAL;
97 }
98
99 obj_refcount objr;
100 int ret = read_refcount(hctx, op.implicit_ref, &objr);
101 if (ret < 0)
102 return ret;
103
104 CLS_LOG(10, "cls_rc_refcount_get() tag=%s\n", op.tag.c_str());
105
106 objr.refs[op.tag] = true;
107
108 ret = set_refcount(hctx, objr.refs);
109 if (ret < 0)
110 return ret;
111
112 return 0;
113 }
114
115 static int cls_rc_refcount_put(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
116 {
117 bufferlist::iterator in_iter = in->begin();
118
119 cls_refcount_put_op op;
120 try {
121 ::decode(op, in_iter);
122 } catch (buffer::error& err) {
123 CLS_LOG(1, "ERROR: cls_rc_refcount_put(): failed to decode entry\n");
124 return -EINVAL;
125 }
126
127 obj_refcount objr;
128 int ret = read_refcount(hctx, op.implicit_ref, &objr);
129 if (ret < 0)
130 return ret;
131
132 if (objr.refs.empty()) {// shouldn't happen!
133 CLS_LOG(0, "ERROR: cls_rc_refcount_put() was called without any references!\n");
134 return -EINVAL;
135 }
136
137 CLS_LOG(10, "cls_rc_refcount_put() tag=%s\n", op.tag.c_str());
138
139 bool found = false;
140 map<string, bool>::iterator iter = objr.refs.find(op.tag);
141 if (iter != objr.refs.end()) {
142 found = true;
143 } else if (op.implicit_ref) {
144 iter = objr.refs.find(wildcard_tag);
145 if (iter != objr.refs.end()) {
146 found = true;
147 }
148 }
149
150 if (!found)
151 return 0;
152
153 objr.refs.erase(iter);
154
155 if (objr.refs.empty()) {
156 return cls_cxx_remove(hctx);
157 }
158
159 ret = set_refcount(hctx, objr.refs);
160 if (ret < 0)
161 return ret;
162
163 return 0;
164 }
165
166 static int cls_rc_refcount_set(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
167 {
168 bufferlist::iterator in_iter = in->begin();
169
170 cls_refcount_set_op op;
171 try {
172 ::decode(op, in_iter);
173 } catch (buffer::error& err) {
174 CLS_LOG(1, "ERROR: cls_refcount_set(): failed to decode entry\n");
175 return -EINVAL;
176 }
177
178 if (!op.refs.size()) {
179 return cls_cxx_remove(hctx);
180 }
181
182 obj_refcount objr;
183 list<string>::iterator iter;
184 for (iter = op.refs.begin(); iter != op.refs.end(); ++iter) {
185 objr.refs[*iter] = true;
186 }
187
188 int ret = set_refcount(hctx, objr.refs);
189 if (ret < 0)
190 return ret;
191
192 return 0;
193 }
194
195 static int cls_rc_refcount_read(cls_method_context_t hctx, bufferlist *in, bufferlist *out)
196 {
197 bufferlist::iterator in_iter = in->begin();
198
199 cls_refcount_read_op op;
200 try {
201 ::decode(op, in_iter);
202 } catch (buffer::error& err) {
203 CLS_LOG(1, "ERROR: cls_rc_refcount_read(): failed to decode entry\n");
204 return -EINVAL;
205 }
206
207 obj_refcount objr;
208
209 cls_refcount_read_ret read_ret;
210 int ret = read_refcount(hctx, op.implicit_ref, &objr);
211 if (ret < 0)
212 return ret;
213
214 map<string, bool>::iterator iter;
215 for (iter = objr.refs.begin(); iter != objr.refs.end(); ++iter) {
216 read_ret.refs.push_back(iter->first);
217 }
218
219 ::encode(read_ret, *out);
220
221 return 0;
222 }
223
224 CLS_INIT(refcount)
225 {
226 CLS_LOG(1, "Loaded refcount class!");
227
228 cls_handle_t h_class;
229 cls_method_handle_t h_refcount_get;
230 cls_method_handle_t h_refcount_put;
231 cls_method_handle_t h_refcount_set;
232 cls_method_handle_t h_refcount_read;
233
234 cls_register("refcount", &h_class);
235
236 /* refcount */
237 cls_register_cxx_method(h_class, "get", CLS_METHOD_RD | CLS_METHOD_WR, cls_rc_refcount_get, &h_refcount_get);
238 cls_register_cxx_method(h_class, "put", CLS_METHOD_RD | CLS_METHOD_WR, cls_rc_refcount_put, &h_refcount_put);
239 cls_register_cxx_method(h_class, "set", CLS_METHOD_RD | CLS_METHOD_WR, cls_rc_refcount_set, &h_refcount_set);
240 cls_register_cxx_method(h_class, "read", CLS_METHOD_RD, cls_rc_refcount_read, &h_refcount_read);
241
242 return;
243 }
244