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