From: Yan, Zheng Date: Tue, 4 Aug 2020 13:26:26 +0000 (+0800) Subject: mds: add vxattr that marks/clears subvolume flag X-Git-Tag: v14.2.12~115^2~5 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=b40d8c352b6e16ce2f701c555411437c6e4ea5ee;p=ceph.git mds: add vxattr that marks/clears subvolume flag Signed-off-by: "Yan, Zheng" (cherry picked from commit 8d531680cdf48ba43d93becd5a19072844e92c19) Conflicts: src/mds/Server.cc src/mds/SnapRealm.h src/mds/snap.h --- diff --git a/src/mds/Server.cc b/src/mds/Server.cc index ba99b52a63df4..4d9e65349ec3a 100644 --- a/src/mds/Server.cc +++ b/src/mds/Server.cc @@ -4512,15 +4512,17 @@ void Server::handle_client_readdir(MDRequestRef& mdr) */ class C_MDS_inode_update_finish : public ServerLogContext { CInode *in; - bool truncating_smaller, changed_ranges, new_realm; + bool truncating_smaller, changed_ranges, adjust_realm; public: C_MDS_inode_update_finish(Server *s, MDRequestRef& r, CInode *i, - bool sm=false, bool cr=false, bool nr=false) : + bool sm=false, bool cr=false, bool ar=false) : ServerLogContext(s, r), in(i), - truncating_smaller(sm), changed_ranges(cr), new_realm(nr) { } + truncating_smaller(sm), changed_ranges(cr), adjust_realm(ar) { } void finish(int r) override { ceph_assert(r == 0); + int snap_op = (in->snaprealm ? CEPH_SNAP_OP_UPDATE : CEPH_SNAP_OP_SPLIT); + // apply in->pop_and_dirty_projected_inode(mdr->ls); mdr->apply(); @@ -4533,10 +4535,9 @@ public: mds->mdcache->truncate_inode(in, mdr->ls); } - if (new_realm) { - int op = CEPH_SNAP_OP_SPLIT; - mds->mdcache->send_snap_update(in, 0, op); - mds->mdcache->do_realm_invalidate_and_update_notify(in, op); + if (adjust_realm) { + mds->mdcache->send_snap_update(in, 0, snap_op); + mds->mdcache->do_realm_invalidate_and_update_notify(in, snap_op); } get_mds()->balancer->hit_inode(in, META_POP_IWR); @@ -5298,7 +5299,7 @@ void Server::handle_set_vxattr(MDRequestRef& mdr, CInode *cur, return; } - bool new_realm = false; + bool adjust_realm = false; if (name.compare(0, 15, "ceph.dir.layout") == 0) { if (!cur->is_dir()) { respond_to_request(mdr, -EINVAL); @@ -5367,28 +5368,76 @@ void Server::handle_set_vxattr(MDRequestRef& mdr, CInode *cur, lov.add_xlock(&cur->policylock); if (quota.is_enable() && !cur->get_projected_srnode()) { lov.add_xlock(&cur->snaplock); - new_realm = true; + adjust_realm = true; } if (!mds->locker->acquire_locks(mdr, lov)) return; - auto &pi = cur->project_inode(false, new_realm); + if (cur->get_projected_inode()->quota == quota) { + respond_to_request(mdr, 0); + return; + } + + auto &pi = cur->project_inode(false, adjust_realm); pi.inode.quota = quota; - if (new_realm) { - SnapRealm *realm = cur->find_snaprealm(); - auto seq = realm->get_newest_seq(); - auto &newsnap = *pi.snapnode; - newsnap.created = seq; - newsnap.seq = seq; - } + if (adjust_realm) + pi.snapnode->created = pi.snapnode->seq = cur->find_snaprealm()->get_newest_seq(); + mdr->no_early_reply = true; pip = &pi.inode; client_t exclude_ct = mdr->get_client(); mdcache->broadcast_quota_to_client(cur, exclude_ct, true); - } else if (name.find("ceph.dir.pin") == 0) { + } else if (name == "ceph.dir.subvolume"sv) { + if (!cur->is_dir()) { + respond_to_request(mdr, -EINVAL); + return; + } + + bool val; + try { + val = boost::lexical_cast(value); + } catch (boost::bad_lexical_cast const&) { + dout(10) << "bad vxattr value, unable to parse bool for " << name << dendl; + respond_to_request(mdr, -EINVAL); + return; + } + + lov.add_xlock(&cur->policylock); + lov.add_xlock(&cur->snaplock); + if (!mds->locker->acquire_locks(mdr, lov)) + return; + + SnapRealm *realm = cur->find_snaprealm(); + if (val) { + inodeno_t subvol_ino = realm->get_subvolume_ino(); + // can't create subvolume inside another subvolume + if (subvol_ino && subvol_ino != cur->ino()) { + respond_to_request(mdr, -EINVAL); + return; + } + } + + const auto srnode = cur->get_projected_srnode(); + if (val == (srnode && srnode->is_subvolume())) { + respond_to_request(mdr, 0); + return; + } + + auto& pi = cur->project_inode(false, true); + if (!srnode) + pi.snapnode->created = pi.snapnode->seq = realm->get_newest_seq(); + if (val) + pi.snapnode->mark_subvolume(); + else + pi.snapnode->clear_subvolume(); + + mdr->no_early_reply = true; + pip = &pi.inode; + adjust_realm = true; + } else if (name == "ceph.dir.pin"sv) { if (!cur->is_dir() || cur->is_root()) { respond_to_request(mdr, -EINVAL); return; @@ -5434,7 +5483,7 @@ void Server::handle_set_vxattr(MDRequestRef& mdr, CInode *cur, mdcache->journal_dirty_inode(mdr.get(), &le->metablob, cur); journal_and_reply(mdr, cur, 0, le, new C_MDS_inode_update_finish(this, mdr, cur, - false, false, new_realm)); + false, false, adjust_realm)); return; } diff --git a/src/mds/SnapRealm.cc b/src/mds/SnapRealm.cc index ee906a3a48d35..4ef775dc69711 100644 --- a/src/mds/SnapRealm.cc +++ b/src/mds/SnapRealm.cc @@ -333,6 +333,13 @@ void SnapRealm::check_cache() const cached_seq = seq; cached_last_created = last_created; cached_last_destroyed = last_destroyed; + + cached_subvolume_ino = 0; + if (parent) + cached_subvolume_ino = parent->get_subvolume_ino(); + if (!cached_subvolume_ino && srnode.is_subvolume()) + cached_subvolume_ino = inode->ino(); + build_snap_set(); build_snap_trace(); diff --git a/src/mds/SnapRealm.h b/src/mds/SnapRealm.h index 17849e4f926f6..582daa2d2e047 100644 --- a/src/mds/SnapRealm.h +++ b/src/mds/SnapRealm.h @@ -33,6 +33,7 @@ protected: mutable set cached_snaps; mutable SnapContext cached_snap_context; mutable bufferlist cached_snap_trace; + mutable inodeno_t cached_subvolume_ino = 0; void check_cache() const; @@ -133,6 +134,11 @@ public: return (p != s.end() && *p <= last); } + inodeno_t get_subvolume_ino() { + check_cache(); + return cached_subvolume_ino; + } + void adjust_parent(); void split_at(SnapRealm *child); diff --git a/src/mds/snap.h b/src/mds/snap.h index b3c00ddf78ad2..41f48d8031e95 100644 --- a/src/mds/snap.h +++ b/src/mds/snap.h @@ -87,13 +87,18 @@ struct sr_t { __u32 flags; enum { - PARENT_GLOBAL = 1 << 0, + PARENT_GLOBAL = 1 << 0, + SUBVOLUME = 1 << 1, }; void mark_parent_global() { flags |= PARENT_GLOBAL; } void clear_parent_global() { flags &= ~PARENT_GLOBAL; } bool is_parent_global() const { return flags & PARENT_GLOBAL; } + void mark_subvolume() { flags |= SUBVOLUME; } + void clear_subvolume() { flags &= ~SUBVOLUME; } + bool is_subvolume() const { return flags & SUBVOLUME; } + sr_t() : seq(0), created(0), last_created(0), last_destroyed(0),