]> git.proxmox.com Git - ceph.git/blame - ceph/src/cls/cephfs/cls_cephfs.cc
bump version to 18.2.4-pve3
[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"
9f95a23c 20#include "osd/osd_types.h"
7c673cae
FG
21
22#include "cls_cephfs.h"
23
24CLS_VER(1,0)
25CLS_NAME(cephfs)
26
f67539c2
TL
27using ceph::bufferlist;
28using ceph::decode;
29using ceph::encode;
7c673cae
FG
30
31std::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 */
49template <typename A>
50static 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
89static 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.
129class PGLSCephFSFilter : public PGLSFilter {
130protected:
131 std::string scrub_tag;
132public:
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
157bool 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
186PGLSFilter *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 */
197CLS_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