]> git.proxmox.com Git - ceph.git/blame - ceph/src/cls/cephfs/cls_cephfs.cc
update sources to v12.1.0
[ceph.git] / ceph / src / cls / cephfs / cls_cephfs.cc
CommitLineData
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"
20
21#include "cls_cephfs.h"
22
23CLS_VER(1,0)
24CLS_NAME(cephfs)
25
26
27std::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 */
45template <typename A>
46static 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
85static 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.
125class PGLSCephFSFilter : public PGLSFilter {
126protected:
127 std::string scrub_tag;
128public:
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
153bool 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
182PGLSFilter *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 */
193CLS_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