mdr->no_early_reply = true;
pip = pi.inode.get();
adjust_realm = true;
+ } else if (name == "ceph.dir.subvolume.snaps.visible"sv) {
+ if (!cur->is_dir()) {
+ respond_to_request(mdr, -EINVAL);
+ return;
+ }
+
+ bool val = true;
+ try {
+ std::string errstr;
+ val = strict_strtob(value, &errstr);
+ if (!errstr.empty()) {
+ dout(10) << "bad vxattr value, unable to parse bool for " << name
+ << ": " << errstr << dendl;
+ respond_to_request(mdr, -EINVAL);
+ return;
+ }
+ } catch (boost::bad_lexical_cast const& e) {
+ dout(10) << "bad vxattr value, unable to parse bool for " << name
+ << ": " << e.what() << dendl;
+ respond_to_request(mdr, -EINVAL);
+ return;
+ }
+
+ // perform few checks with lightweight rdlock
+ if (!mdr->more()->rdonly_checks) {
+ lov.add_rdlock(&cur->snaplock);
+ if (!mds->locker->acquire_locks(mdr, lov)) {
+ dout(20) << "handle_client_getvxattr could not acquire rdlock on "
+ << *cur << dendl;
+ return;
+ }
+
+ const auto srnode = cur->get_projected_srnode();
+ if (!srnode) {
+ dout(10) << "no-op since no snaprealm node found for "
+ << req->get_filepath() << dendl;
+ respond_to_request(mdr, 0);
+ return;
+ }
+ // check if visibility already matches the desired value
+ if (val == srnode->is_snapdir_visible()) {
+ dout(20) << "snapdir visibility for " << req->get_filepath()
+ << " is already set to " << std::boolalpha << val << dendl;
+ respond_to_request(mdr, 0);
+ return;
+ }
+
+ mdr->more()->rdonly_checks = true;
+ dout(20) << "dropping rdlock on " << *cur << dendl;
+ mds->locker->drop_locks(mdr.get());
+ }
+
+ if (!xlock_policylock(mdr, cur, false, true)) {
+ return;
+ }
+
+ /* Repeat rdlocks checks to see if anything changed b/w rdlock release and
+ * xlock policylock acquisition
+ */
+ {
+ const auto srnode = cur->get_projected_srnode();
+ if (!srnode) {
+ dout(10) << "no-op since no snaprealm node found for "
+ << req->get_filepath() << dendl;
+ respond_to_request(mdr, 0);
+ return;
+ }
+
+ if (val == srnode->is_snapdir_visible()) {
+ dout(20) << "snapdir visibility for " << req->get_filepath()
+ << " is already set to " << std::boolalpha << val << dendl;
+ respond_to_request(mdr, 0);
+ return;
+ }
+ }
+
+ adjust_realm = true;
+ auto pi = cur->project_inode(mdr, false, adjust_realm);
+ dout(20) << "setting snapdir visibility to " << std::boolalpha
+ << val << " for " << req->get_filepath() << dendl;
+ if (val) {
+ pi.snapnode->set_snapdir_visibility();
+ } else {
+ pi.snapnode->unset_snapdir_visibility();
+ }
+ pi.snapnode->last_modified = mdr->get_op_stamp();
+ pi.snapnode->change_attr++;
+
+ mdr->no_early_reply = true;
+ pip = pi.inode.get();
} else if (name == "ceph.dir.pin"sv) {
if (!cur->is_dir() || cur->is_root()) {
respond_to_request(mdr, -EINVAL);
// since we only handle ceph vxattrs here
r = -ENODATA; // no such attribute
}
+ } else if (xattr_name == "ceph.dir.subvolume.snaps.visible"sv) {
+ if (!cur->is_dir()) {
+ r = -ENOTDIR;
+ } else {
+ const auto srnode = cur->get_projected_srnode();
+ if (!srnode) {
+ dout(10) << "no-op since no snaprealm node found for "
+ << mdr->client_request->get_filepath() << dendl;
+ r = 0;
+ } else {
+ *css << srnode->is_snapdir_visible();
+ }
+ }
} else {
// otherwise respond as invalid request
// since we only handle ceph vxattrs here
xattr_name == "ceph.dir.charmap"sv ||
xattr_name == "ceph.dir.normalization"sv ||
xattr_name == "ceph.dir.encoding"sv ||
- xattr_name == "ceph.dir.casesensitive"sv;
+ xattr_name == "ceph.dir.casesensitive"sv ||
+ xattr_name == "ceph.dir.subvolume.snaps.visible"sv;
}
static bool is_ceph_dir_vxattr(std::string_view xattr_name) {
xattr_name == "ceph.dir.charmap"sv ||
xattr_name == "ceph.dir.normalization"sv ||
xattr_name == "ceph.dir.encoding"sv ||
- xattr_name == "ceph.dir.casesensitive"sv;
+ xattr_name == "ceph.dir.casesensitive"sv ||
+ xattr_name == "ceph.dir.subvolume.snaps.visible"sv;
}
static bool is_ceph_file_vxattr(std::string_view xattr_name) {
f->dump_unsigned("last_destroyed", last_destroyed);
f->dump_stream("last_modified") << last_modified;
f->dump_unsigned("change_attr", change_attr);
+ f->dump_unsigned("is_snapdir_visible", is_snapdir_visible());
f->dump_unsigned("current_parent_since", current_parent_since);
f->open_array_section("snaps");
return ls;
}
+void sr_t::print(std::ostream& out) const {
+ out << "sr_t(seq=" << seq
+ << " created=" << created
+ << " last_created=" << last_created
+ << " last_destroyed=" << last_destroyed
+ << " flags=" << flags << ")";
+}
+
void clear_subvolume() { flags &= ~SUBVOLUME; }
bool is_subvolume() const { return flags & SUBVOLUME; }
+ void set_snapdir_visibility() { flags |= SNAPDIR_VISIBILITY; }
+ void unset_snapdir_visibility() { flags &= ~SNAPDIR_VISIBILITY; }
+ bool is_snapdir_visible() const { return flags & SNAPDIR_VISIBILITY; }
+
void encode(ceph::buffer::list &bl) const;
void decode(ceph::buffer::list::const_iterator &bl);
void dump(ceph::Formatter *f) const;
static std::list<sr_t> generate_test_instances();
+ void print(std::ostream&) const;
snapid_t seq = 0; // basically, a version/seq # for changes to _this_ realm.
snapid_t created = 0; // when this realm was created.
uint64_t change_attr = 0; // tracks changes to snap
// realm attrs.
- __u32 flags = 0;
enum {
PARENT_GLOBAL = 1 << 0,
SUBVOLUME = 1 << 1,
+ SNAPDIR_VISIBILITY = 1 << 2,
};
+
+ __u32 flags = SNAPDIR_VISIBILITY; // snapdir visibility is always on by default
};
WRITE_CLASS_ENCODER(sr_t)