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