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