]> git.proxmox.com Git - ceph.git/blame - ceph/src/cls/cephfs/cls_cephfs.cc
add subtree-ish sources for 12.0.3
[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>
18#include <sstream>
19
20#include "objclass/objclass.h"
21
22#include "cls_cephfs.h"
23
24CLS_VER(1,0)
25CLS_NAME(cephfs)
26
27
28std::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 */
46template <typename A>
47static 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
86static 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.
126class PGLSCephFSFilter : public PGLSFilter {
127protected:
128 std::string scrub_tag;
129public:
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
154bool 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
183PGLSFilter *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 */
194CLS_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