Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / cls / cephfs / cls_cephfs.cc
1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
3 /*
4  * Ceph - scalable distributed file system
5  *
6  * Copyright (C) 2015 Red Hat
7  *
8  * This is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License version 2.1, as published by the Free Software
11  * Foundation.  See file COPYING.
12  *
13  */
14
15
16 #include <string>
17 #include <errno.h>
18
19 #include "objclass/objclass.h"
20
21 #include "cls_cephfs.h"
22
23 CLS_VER(1,0)
24 CLS_NAME(cephfs)
25
26
27 std::ostream &operator<<(std::ostream &out, const ObjCeiling &in)
28 {
29   out << "id: " << in.id << " size: " << in.size;
30   return out;
31 }
32
33
34 /**
35  * Set a named xattr to a given value, if and only if the xattr
36  * is not already set to a greater value.
37  *
38  * If the xattr is missing, then it is set to the input integer.
39  *
40  * @param xattr_name: name of xattr to compare against and set
41  * @param input_val: candidate new value, of ::encode()'able type
42  * @returns 0 on success (irrespective of whether our new value
43  *          was used) else an error code
44  */
45 template <typename A>
46 static int set_if_greater(cls_method_context_t hctx,
47     const std::string &xattr_name, const A input_val)
48 {
49   bufferlist existing_val_bl;
50
51   bool set_val = false;
52   int r = cls_cxx_getxattr(hctx, xattr_name.c_str(), &existing_val_bl);
53   if (r == -ENOENT || existing_val_bl.length() == 0) {
54     set_val = true;
55   } else if (r >= 0) {
56     bufferlist::iterator existing_p = existing_val_bl.begin();
57     try {
58       A existing_val;
59       ::decode(existing_val, existing_p);
60       if (!existing_p.end()) {
61         // Trailing junk?  Consider it invalid and overwrite
62         set_val = true;
63       } else {
64         // Valid existing value, do comparison
65         set_val = input_val > existing_val;
66       }
67     } catch (const buffer::error &err) {
68       // Corrupt or empty existing value, overwrite it
69       set_val = true;
70     }
71   } else {
72     return r;
73   }
74
75   // Conditionally set the new xattr
76   if (set_val) {
77     bufferlist set_bl;
78     ::encode(input_val, set_bl);
79     return cls_cxx_setxattr(hctx, xattr_name.c_str(), &set_bl);
80   } else {
81     return 0;
82   }
83 }
84
85 static int accumulate_inode_metadata(cls_method_context_t hctx,
86     bufferlist *in, bufferlist *out)
87 {
88   assert(in != NULL);
89   assert(out != NULL);
90
91   int r = 0;
92
93   // Decode `in`
94   bufferlist::iterator q = in->begin();
95   AccumulateArgs args;
96   try {
97     args.decode(q);
98   } catch (const buffer::error &err) {
99     return -EINVAL;
100   }
101
102   ObjCeiling ceiling(args.obj_index, args.obj_size);
103   r = set_if_greater(hctx, args.obj_xattr_name, ceiling);
104   if (r < 0) {
105     return r;
106   }
107
108   r = set_if_greater(hctx, args.mtime_xattr_name, args.mtime);
109   if (r < 0) {
110     return r;
111   }
112
113   r = set_if_greater(hctx, args.obj_size_xattr_name, args.obj_size);
114   if (r < 0) {
115     return r;
116   }
117
118   return 0;
119 }
120
121 // I want to select objects that have a name ending 00000000
122 // and an xattr (scrub_tag) not equal to a specific value.
123 // This is so special case that we can't really pretend it's
124 // generic, so just fess up and call this the cephfs filter.
125 class PGLSCephFSFilter : public PGLSFilter {
126 protected:
127   std::string scrub_tag;
128 public:
129   int init(bufferlist::iterator& params) override {
130     try {
131       InodeTagFilterArgs args;
132       args.decode(params);
133       scrub_tag = args.scrub_tag;
134     } catch (buffer::error &e) {
135       return -EINVAL;
136     }
137
138     if (scrub_tag.empty()) {
139       xattr = "";
140     } else {
141       xattr = "_scrub_tag";
142     }
143
144     return 0;
145   }
146
147   ~PGLSCephFSFilter() override {}
148   bool reject_empty_xattr() override { return false; }
149   bool filter(const hobject_t &obj, bufferlist& xattr_data,
150                       bufferlist& outdata) override;
151 };
152
153 bool PGLSCephFSFilter::filter(const hobject_t &obj,
154                              bufferlist& xattr_data, bufferlist& outdata)
155 {
156   const std::string need_ending = ".00000000";
157   const std::string &obj_name = obj.oid.name;
158
159   if (obj_name.length() < need_ending.length()) {
160     return false;
161   }
162
163   const bool match = obj_name.compare (obj_name.length() - need_ending.length(), need_ending.length(), need_ending) == 0;
164   if (!match) {
165     return false;
166   }
167
168   if (!scrub_tag.empty() && xattr_data.length() > 0) {
169     std::string tag_ondisk;
170     bufferlist::iterator q = xattr_data.begin();
171     try {
172       ::decode(tag_ondisk, q);
173       if (tag_ondisk == scrub_tag)
174         return false;
175     } catch (const buffer::error &err) {
176     }
177   }
178
179   return true;
180 }
181
182 PGLSFilter *inode_tag_filter()
183 {
184   return new PGLSCephFSFilter();
185 }
186
187 /**
188  * initialize class
189  *
190  * We do two things here: we register the new class, and then register
191  * all of the class's methods.
192  */
193 CLS_INIT(cephfs)
194 {
195   // this log message, at level 0, will always appear in the ceph-osd
196   // log file.
197   CLS_LOG(0, "loading cephfs");
198
199   cls_handle_t h_class;
200   cls_method_handle_t h_accumulate_inode_metadata;
201
202   cls_register("cephfs", &h_class);
203   cls_register_cxx_method(h_class, "accumulate_inode_metadata",
204                           CLS_METHOD_WR | CLS_METHOD_RD,
205                           accumulate_inode_metadata, &h_accumulate_inode_metadata);
206
207   // A PGLS filter
208   cls_register_cxx_filter(h_class, "inode_tag", inode_tag_filter);
209 }
210