]> git.proxmox.com Git - ceph.git/blob - ceph/src/cls/cephfs/cls_cephfs.cc
update sources to v12.1.0
[ceph.git] / 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