summaryrefslogtreecommitdiffstats
path: root/src/mds/CDentry.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/mds/CDentry.h')
-rw-r--r--src/mds/CDentry.h403
1 files changed, 403 insertions, 0 deletions
diff --git a/src/mds/CDentry.h b/src/mds/CDentry.h
new file mode 100644
index 000000000..efd277192
--- /dev/null
+++ b/src/mds/CDentry.h
@@ -0,0 +1,403 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph - scalable distributed file system
+ *
+ * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
+ *
+ * This is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License version 2.1, as published by the Free Software
+ * Foundation. See file COPYING.
+ *
+ */
+
+#ifndef CEPH_CDENTRY_H
+#define CEPH_CDENTRY_H
+
+#include <string>
+#include <string_view>
+#include <set>
+
+#include "include/counter.h"
+#include "include/types.h"
+#include "include/buffer_fwd.h"
+#include "include/lru.h"
+#include "include/elist.h"
+#include "include/filepath.h"
+
+#include "BatchOp.h"
+#include "MDSCacheObject.h"
+#include "MDSContext.h"
+#include "Mutation.h"
+#include "SimpleLock.h"
+#include "LocalLockC.h"
+#include "ScrubHeader.h"
+
+class CInode;
+class CDir;
+class Locker;
+class CDentry;
+class LogSegment;
+
+class Session;
+
+// define an ordering
+bool operator<(const CDentry& l, const CDentry& r);
+
+// dentry
+class CDentry : public MDSCacheObject, public LRUObject, public Counter<CDentry> {
+public:
+ MEMPOOL_CLASS_HELPERS();
+ friend class CDir;
+
+ struct linkage_t {
+ CInode *inode = nullptr;
+ inodeno_t remote_ino = 0;
+ unsigned char remote_d_type = 0;
+
+ linkage_t() {}
+
+ // dentry type is primary || remote || null
+ // inode ptr is required for primary, optional for remote, undefined for null
+ bool is_primary() const { return remote_ino == 0 && inode != 0; }
+ bool is_remote() const { return remote_ino > 0; }
+ bool is_null() const { return remote_ino == 0 && inode == 0; }
+
+ CInode *get_inode() { return inode; }
+ const CInode *get_inode() const { return inode; }
+ inodeno_t get_remote_ino() const { return remote_ino; }
+ unsigned char get_remote_d_type() const { return remote_d_type; }
+ std::string get_remote_d_type_string() const;
+
+ void set_remote(inodeno_t ino, unsigned char d_type) {
+ remote_ino = ino;
+ remote_d_type = d_type;
+ inode = 0;
+ }
+ void link_remote(CInode *in);
+ };
+
+
+ // -- state --
+ static const int STATE_NEW = (1<<0);
+ static const int STATE_FRAGMENTING = (1<<1);
+ static const int STATE_PURGING = (1<<2);
+ static const int STATE_BADREMOTEINO = (1<<3);
+ static const int STATE_EVALUATINGSTRAY = (1<<4);
+ static const int STATE_PURGINGPINNED = (1<<5);
+ static const int STATE_BOTTOMLRU = (1<<6);
+ static const int STATE_UNLINKING = (1<<7);
+ // stray dentry needs notification of releasing reference
+ static const int STATE_STRAY = STATE_NOTIFYREF;
+ static const int MASK_STATE_IMPORT_KEPT = STATE_BOTTOMLRU;
+
+ // -- pins --
+ static const int PIN_INODEPIN = 1; // linked inode is pinned
+ static const int PIN_FRAGMENTING = -2; // containing dir is refragmenting
+ static const int PIN_PURGING = 3;
+ static const int PIN_SCRUBPARENT = 4;
+ static const int PIN_WAITUNLINKSTATE = 5;
+
+ static const unsigned EXPORT_NONCE = 1;
+
+ const static uint64_t WAIT_UNLINK_STATE = (1<<0);
+ const static uint64_t WAIT_UNLINK_FINISH = (1<<1);
+ uint32_t replica_unlinking_ref = 0;
+
+ CDentry(std::string_view n, __u32 h,
+ mempool::mds_co::string alternate_name,
+ snapid_t f, snapid_t l) :
+ hash(h),
+ first(f), last(l),
+ item_dirty(this),
+ lock(this, &lock_type),
+ versionlock(this, &versionlock_type),
+ name(n),
+ alternate_name(std::move(alternate_name))
+ {}
+ CDentry(std::string_view n, __u32 h,
+ mempool::mds_co::string alternate_name,
+ inodeno_t ino, unsigned char dt,
+ snapid_t f, snapid_t l) :
+ hash(h),
+ first(f), last(l),
+ item_dirty(this),
+ lock(this, &lock_type),
+ versionlock(this, &versionlock_type),
+ name(n),
+ alternate_name(std::move(alternate_name))
+ {
+ linkage.remote_ino = ino;
+ linkage.remote_d_type = dt;
+ }
+
+ ~CDentry() override {
+ ceph_assert(batch_ops.empty());
+ }
+
+ std::string_view pin_name(int p) const override {
+ switch (p) {
+ case PIN_INODEPIN: return "inodepin";
+ case PIN_FRAGMENTING: return "fragmenting";
+ case PIN_PURGING: return "purging";
+ case PIN_SCRUBPARENT: return "scrubparent";
+ case PIN_WAITUNLINKSTATE: return "waitunlinkstate";
+ default: return generic_pin_name(p);
+ }
+ }
+
+ // -- wait --
+ //static const int WAIT_LOCK_OFFSET = 8;
+
+ void add_waiter(uint64_t tag, MDSContext *c) override;
+
+ bool is_lt(const MDSCacheObject *r) const override {
+ return *this < *static_cast<const CDentry*>(r);
+ }
+
+ dentry_key_t key() {
+ return dentry_key_t(last, name.c_str(), hash);
+ }
+
+ const CDir *get_dir() const { return dir; }
+ CDir *get_dir() { return dir; }
+ std::string_view get_name() const { return std::string_view(name); }
+ std::string_view get_alternate_name() const {
+ return std::string_view(alternate_name);
+ }
+ void set_alternate_name(mempool::mds_co::string altn) {
+ alternate_name = std::move(altn);
+ }
+ void set_alternate_name(std::string_view altn) {
+ alternate_name = mempool::mds_co::string(altn);
+ }
+
+ __u32 get_hash() const { return hash; }
+
+ // linkage
+ const linkage_t *get_linkage() const { return &linkage; }
+ linkage_t *get_linkage() { return &linkage; }
+
+ linkage_t *_project_linkage() {
+ projected.push_back(linkage_t());
+ return &projected.back();
+ }
+ void push_projected_linkage();
+ void push_projected_linkage(inodeno_t ino, char d_type) {
+ linkage_t *p = _project_linkage();
+ p->remote_ino = ino;
+ p->remote_d_type = d_type;
+ }
+ void push_projected_linkage(CInode *inode);
+ linkage_t *pop_projected_linkage();
+
+ bool is_projected() const { return !projected.empty(); }
+
+ linkage_t *get_projected_linkage() {
+ if (!projected.empty())
+ return &projected.back();
+ return &linkage;
+ }
+
+ const linkage_t *get_projected_linkage() const {
+ if (!projected.empty())
+ return &projected.back();
+ return &linkage;
+ }
+
+ CInode *get_projected_inode() {
+ return get_projected_linkage()->inode;
+ }
+
+ bool use_projected(client_t client, const MutationRef& mut) const {
+ return lock.can_read_projected(client) ||
+ lock.get_xlock_by() == mut;
+ }
+ linkage_t *get_linkage(client_t client, const MutationRef& mut) {
+ return use_projected(client, mut) ? get_projected_linkage() : get_linkage();
+ }
+
+ // ref counts: pin ourselves in the LRU when we're pinned.
+ void first_get() override {
+ lru_pin();
+ }
+ void last_put() override {
+ lru_unpin();
+ }
+ void _put() override;
+
+ // auth pins
+ bool can_auth_pin(int *err_ret=nullptr) const override;
+ void auth_pin(void *by) override;
+ void auth_unpin(void *by) override;
+ void adjust_nested_auth_pins(int diradj, void *by);
+ bool is_frozen() const override;
+ bool is_freezing() const override;
+ int get_num_dir_auth_pins() const;
+
+ // remote links
+ void link_remote(linkage_t *dnl, CInode *in);
+ void unlink_remote(linkage_t *dnl);
+
+ // copy cons
+ CDentry(const CDentry& m);
+ const CDentry& operator= (const CDentry& right);
+
+ // misc
+ void make_path_string(std::string& s, bool projected=false) const;
+ void make_path(filepath& fp, bool projected=false) const;
+
+ // -- version --
+ version_t get_version() const { return version; }
+ void set_version(version_t v) { projected_version = version = v; }
+ version_t get_projected_version() const { return projected_version; }
+ void set_projected_version(version_t v) { projected_version = v; }
+
+ mds_authority_t authority() const override;
+
+ version_t pre_dirty(version_t min=0);
+ void _mark_dirty(LogSegment *ls);
+ void mark_dirty(version_t pv, LogSegment *ls);
+ void mark_clean();
+
+ void mark_new();
+ bool is_new() const { return state_test(STATE_NEW); }
+ void clear_new() { state_clear(STATE_NEW); }
+
+ // -- exporting
+ // note: this assumes the dentry already exists.
+ // i.e., the name is already extracted... so we just need the other state.
+ void encode_export(ceph::buffer::list& bl) {
+ ENCODE_START(1, 1, bl);
+ encode(first, bl);
+ encode(state, bl);
+ encode(version, bl);
+ encode(projected_version, bl);
+ encode(lock, bl);
+ encode(get_replicas(), bl);
+ get(PIN_TEMPEXPORTING);
+ ENCODE_FINISH(bl);
+ }
+ void finish_export() {
+ // twiddle
+ clear_replica_map();
+ replica_nonce = EXPORT_NONCE;
+ state_clear(CDentry::STATE_AUTH);
+ if (is_dirty())
+ mark_clean();
+ put(PIN_TEMPEXPORTING);
+ }
+ void abort_export() {
+ put(PIN_TEMPEXPORTING);
+ }
+ void decode_import(ceph::buffer::list::const_iterator& blp, LogSegment *ls) {
+ DECODE_START(1, blp);
+ decode(first, blp);
+ __u32 nstate;
+ decode(nstate, blp);
+ decode(version, blp);
+ decode(projected_version, blp);
+ decode(lock, blp);
+ decode(get_replicas(), blp);
+
+ // twiddle
+ state &= MASK_STATE_IMPORT_KEPT;
+ state_set(CDentry::STATE_AUTH);
+ if (nstate & STATE_DIRTY)
+ _mark_dirty(ls);
+ if (is_replicated())
+ get(PIN_REPLICATED);
+ replica_nonce = 0;
+ DECODE_FINISH(blp);
+ }
+
+ // -- locking --
+ SimpleLock* get_lock(int type) override {
+ ceph_assert(type == CEPH_LOCK_DN);
+ return &lock;
+ }
+ void set_object_info(MDSCacheObjectInfo &info) override;
+ void encode_lock_state(int type, ceph::buffer::list& bl) override;
+ void decode_lock_state(int type, const ceph::buffer::list& bl) override;
+
+ // ---------------------------------------------
+ // replicas (on clients)
+
+ bool is_any_leases() const {
+ return !client_lease_map.empty();
+ }
+ const ClientLease *get_client_lease(client_t c) const {
+ if (client_lease_map.count(c))
+ return client_lease_map.find(c)->second;
+ return 0;
+ }
+ ClientLease *get_client_lease(client_t c) {
+ if (client_lease_map.count(c))
+ return client_lease_map.find(c)->second;
+ return 0;
+ }
+ bool have_client_lease(client_t c) const {
+ const ClientLease *l = get_client_lease(c);
+ if (l)
+ return true;
+ else
+ return false;
+ }
+
+ ClientLease *add_client_lease(client_t c, Session *session);
+ void remove_client_lease(ClientLease *r, Locker *locker); // returns remaining mask (if any), and kicks locker eval_gathers
+ void remove_client_leases(Locker *locker);
+
+ std::ostream& print_db_line_prefix(std::ostream& out) override;
+ void print(std::ostream& out) override;
+ void dump(ceph::Formatter *f) const;
+
+ static void encode_remote(inodeno_t& ino, unsigned char d_type,
+ std::string_view alternate_name,
+ bufferlist &bl);
+ static void decode_remote(char icode, inodeno_t& ino, unsigned char& d_type,
+ mempool::mds_co::string& alternate_name,
+ ceph::buffer::list::const_iterator& bl);
+
+ __u32 hash;
+ snapid_t first, last;
+
+ elist<CDentry*>::item item_dirty, item_dir_dirty;
+ elist<CDentry*>::item item_stray;
+
+ // lock
+ static LockType lock_type;
+ static LockType versionlock_type;
+
+ SimpleLock lock; // FIXME referenced containers not in mempool
+ LocalLockC versionlock; // FIXME referenced containers not in mempool
+
+ mempool::mds_co::map<client_t,ClientLease*> client_lease_map;
+ std::map<int, std::unique_ptr<BatchOp>> batch_ops;
+
+
+protected:
+ friend class Migrator;
+ friend class Locker;
+ friend class MDCache;
+ friend class StrayManager;
+ friend class CInode;
+ friend class C_MDC_XlockRequest;
+
+ CDir *dir = nullptr; // containing dirfrag
+ linkage_t linkage; /* durable */
+ mempool::mds_co::list<linkage_t> projected;
+
+ version_t version = 0; // dir version when last touched.
+ version_t projected_version = 0; // what it will be when i unlock/commit.
+
+private:
+ mempool::mds_co::string name;
+ mempool::mds_co::string alternate_name;
+};
+
+std::ostream& operator<<(std::ostream& out, const CDentry& dn);
+
+
+#endif