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