1 // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2 // vim: ts=8 sw=2 smarttab
4 * Ceph - scalable distributed file system
6 * Copyright (C) 2004-2006 Sage Weil <sage@newdream.net>
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.
15 #ifndef CEPH_CDENTRY_H
16 #define CEPH_CDENTRY_H
19 #include <string_view>
22 #include "include/counter.h"
23 #include "include/types.h"
24 #include "include/buffer_fwd.h"
25 #include "include/lru.h"
26 #include "include/elist.h"
27 #include "include/filepath.h"
30 #include "MDSCacheObject.h"
31 #include "MDSContext.h"
32 #include "SimpleLock.h"
33 #include "LocalLockC.h"
34 #include "ScrubHeader.h"
45 bool operator<(const CDentry
& l
, const CDentry
& r
);
48 class CDentry
: public MDSCacheObject
, public LRUObject
, public Counter
<CDentry
> {
50 MEMPOOL_CLASS_HELPERS();
54 CInode
*inode
= nullptr;
55 inodeno_t remote_ino
= 0;
56 unsigned char remote_d_type
= 0;
60 // dentry type is primary || remote || null
61 // inode ptr is required for primary, optional for remote, undefined for null
62 bool is_primary() const { return remote_ino
== 0 && inode
!= 0; }
63 bool is_remote() const { return remote_ino
> 0; }
64 bool is_null() const { return remote_ino
== 0 && inode
== 0; }
66 CInode
*get_inode() { return inode
; }
67 const CInode
*get_inode() const { return inode
; }
68 inodeno_t
get_remote_ino() const { return remote_ino
; }
69 unsigned char get_remote_d_type() const { return remote_d_type
; }
70 std::string
get_remote_d_type_string() const;
72 void set_remote(inodeno_t ino
, unsigned char d_type
) {
74 remote_d_type
= d_type
;
77 void link_remote(CInode
*in
);
82 static const int STATE_NEW
= (1<<0);
83 static const int STATE_FRAGMENTING
= (1<<1);
84 static const int STATE_PURGING
= (1<<2);
85 static const int STATE_BADREMOTEINO
= (1<<3);
86 static const int STATE_EVALUATINGSTRAY
= (1<<4);
87 static const int STATE_PURGINGPINNED
= (1<<5);
88 static const int STATE_BOTTOMLRU
= (1<<6);
89 // stray dentry needs notification of releasing reference
90 static const int STATE_STRAY
= STATE_NOTIFYREF
;
91 static const int MASK_STATE_IMPORT_KEPT
= STATE_BOTTOMLRU
;
94 static const int PIN_INODEPIN
= 1; // linked inode is pinned
95 static const int PIN_FRAGMENTING
= -2; // containing dir is refragmenting
96 static const int PIN_PURGING
= 3;
97 static const int PIN_SCRUBPARENT
= 4;
99 static const unsigned EXPORT_NONCE
= 1;
102 CDentry(std::string_view n
, __u32 h
,
103 mempool::mds_co::string alternate_name
,
104 snapid_t f
, snapid_t l
) :
108 lock(this, &lock_type
),
109 versionlock(this, &versionlock_type
),
111 alternate_name(std::move(alternate_name
))
113 CDentry(std::string_view n
, __u32 h
,
114 mempool::mds_co::string alternate_name
,
115 inodeno_t ino
, unsigned char dt
,
116 snapid_t f
, snapid_t l
) :
120 lock(this, &lock_type
),
121 versionlock(this, &versionlock_type
),
123 alternate_name(std::move(alternate_name
))
125 linkage
.remote_ino
= ino
;
126 linkage
.remote_d_type
= dt
;
129 ~CDentry() override
{
130 ceph_assert(batch_ops
.empty());
133 std::string_view
pin_name(int p
) const override
{
135 case PIN_INODEPIN
: return "inodepin";
136 case PIN_FRAGMENTING
: return "fragmenting";
137 case PIN_PURGING
: return "purging";
138 case PIN_SCRUBPARENT
: return "scrubparent";
139 default: return generic_pin_name(p
);
144 //static const int WAIT_LOCK_OFFSET = 8;
146 void add_waiter(uint64_t tag
, MDSContext
*c
) override
;
148 bool is_lt(const MDSCacheObject
*r
) const override
{
149 return *this < *static_cast<const CDentry
*>(r
);
153 return dentry_key_t(last
, name
.c_str(), hash
);
156 bool check_corruption(bool load
);
158 const CDir
*get_dir() const { return dir
; }
159 CDir
*get_dir() { return dir
; }
160 std::string_view
get_name() const { return std::string_view(name
); }
161 std::string_view
get_alternate_name() const {
162 return std::string_view(alternate_name
);
164 void set_alternate_name(mempool::mds_co::string altn
) {
165 alternate_name
= std::move(altn
);
167 void set_alternate_name(std::string_view altn
) {
168 alternate_name
= mempool::mds_co::string(altn
);
171 __u32
get_hash() const { return hash
; }
174 const linkage_t
*get_linkage() const { return &linkage
; }
175 linkage_t
*get_linkage() { return &linkage
; }
177 linkage_t
*_project_linkage() {
178 projected
.push_back(linkage_t());
179 return &projected
.back();
181 void push_projected_linkage();
182 void push_projected_linkage(inodeno_t ino
, char d_type
) {
183 linkage_t
*p
= _project_linkage();
185 p
->remote_d_type
= d_type
;
187 void push_projected_linkage(CInode
*inode
);
188 linkage_t
*pop_projected_linkage();
190 bool is_projected() const { return !projected
.empty(); }
192 linkage_t
*get_projected_linkage() {
193 if (!projected
.empty())
194 return &projected
.back();
198 const linkage_t
*get_projected_linkage() const {
199 if (!projected
.empty())
200 return &projected
.back();
204 CInode
*get_projected_inode() {
205 return get_projected_linkage()->inode
;
208 bool use_projected(client_t client
, const MutationRef
& mut
) const {
209 return lock
.can_read_projected(client
) ||
210 lock
.get_xlock_by() == mut
;
212 linkage_t
*get_linkage(client_t client
, const MutationRef
& mut
) {
213 return use_projected(client
, mut
) ? get_projected_linkage() : get_linkage();
216 // ref counts: pin ourselves in the LRU when we're pinned.
217 void first_get() override
{
220 void last_put() override
{
223 void _put() override
;
226 bool can_auth_pin(int *err_ret
=nullptr) const override
;
227 void auth_pin(void *by
) override
;
228 void auth_unpin(void *by
) override
;
229 void adjust_nested_auth_pins(int diradj
, void *by
);
230 bool is_frozen() const override
;
231 bool is_freezing() const override
;
232 int get_num_dir_auth_pins() const;
235 void link_remote(linkage_t
*dnl
, CInode
*in
);
236 void unlink_remote(linkage_t
*dnl
);
239 CDentry(const CDentry
& m
);
240 const CDentry
& operator= (const CDentry
& right
);
243 void make_path_string(std::string
& s
, bool projected
=false) const;
244 void make_path(filepath
& fp
, bool projected
=false) const;
247 version_t
get_version() const { return version
; }
248 void set_version(version_t v
) { projected_version
= version
= v
; }
249 version_t
get_projected_version() const { return projected_version
; }
250 void set_projected_version(version_t v
) { projected_version
= v
; }
252 mds_authority_t
authority() const override
;
254 version_t
pre_dirty(version_t min
=0);
255 void _mark_dirty(LogSegment
*ls
);
256 void mark_dirty(version_t pv
, LogSegment
*ls
);
260 bool is_new() const { return state_test(STATE_NEW
); }
261 void clear_new() { state_clear(STATE_NEW
); }
266 bool scrub(snapid_t next_seq
);
269 // note: this assumes the dentry already exists.
270 // i.e., the name is already extracted... so we just need the other state.
271 void encode_export(ceph::buffer::list
& bl
) {
272 ENCODE_START(1, 1, bl
);
276 encode(projected_version
, bl
);
278 encode(get_replicas(), bl
);
279 get(PIN_TEMPEXPORTING
);
282 void finish_export() {
285 replica_nonce
= EXPORT_NONCE
;
289 put(PIN_TEMPEXPORTING
);
291 void abort_export() {
292 put(PIN_TEMPEXPORTING
);
294 void decode_import(ceph::buffer::list::const_iterator
& blp
, LogSegment
*ls
) {
295 DECODE_START(1, blp
);
299 decode(version
, blp
);
300 decode(projected_version
, blp
);
302 decode(get_replicas(), blp
);
305 state
&= MASK_STATE_IMPORT_KEPT
;
307 if (nstate
& STATE_DIRTY
)
316 SimpleLock
* get_lock(int type
) override
{
317 ceph_assert(type
== CEPH_LOCK_DN
);
320 void set_object_info(MDSCacheObjectInfo
&info
) override
;
321 void encode_lock_state(int type
, ceph::buffer::list
& bl
) override
;
322 void decode_lock_state(int type
, const ceph::buffer::list
& bl
) override
;
324 // ---------------------------------------------
325 // replicas (on clients)
327 bool is_any_leases() const {
328 return !client_lease_map
.empty();
330 const ClientLease
*get_client_lease(client_t c
) const {
331 if (client_lease_map
.count(c
))
332 return client_lease_map
.find(c
)->second
;
335 ClientLease
*get_client_lease(client_t c
) {
336 if (client_lease_map
.count(c
))
337 return client_lease_map
.find(c
)->second
;
340 bool have_client_lease(client_t c
) const {
341 const ClientLease
*l
= get_client_lease(c
);
348 ClientLease
*add_client_lease(client_t c
, Session
*session
);
349 void remove_client_lease(ClientLease
*r
, Locker
*locker
); // returns remaining mask (if any), and kicks locker eval_gathers
350 void remove_client_leases(Locker
*locker
);
352 std::ostream
& print_db_line_prefix(std::ostream
& out
) const override
;
353 void print(std::ostream
& out
) const override
;
354 void dump(ceph::Formatter
*f
) const;
356 static void encode_remote(inodeno_t
& ino
, unsigned char d_type
,
357 std::string_view alternate_name
,
359 static void decode_remote(char icode
, inodeno_t
& ino
, unsigned char& d_type
,
360 mempool::mds_co::string
& alternate_name
,
361 ceph::buffer::list::const_iterator
& bl
);
364 snapid_t first
, last
;
365 bool corrupt_first_loaded
= false; /* for Postgres corruption detection */
367 elist
<CDentry
*>::item item_dirty
, item_dir_dirty
;
368 elist
<CDentry
*>::item item_stray
;
371 static LockType lock_type
;
372 static LockType versionlock_type
;
374 SimpleLock lock
; // FIXME referenced containers not in mempool
375 LocalLockC versionlock
; // FIXME referenced containers not in mempool
377 mempool::mds_co::map
<client_t
,ClientLease
*> client_lease_map
;
378 std::map
<int, std::unique_ptr
<BatchOp
>> batch_ops
;
382 friend class Migrator
;
384 friend class MDCache
;
385 friend class StrayManager
;
387 friend class C_MDC_XlockRequest
;
389 CDir
*dir
= nullptr; // containing dirfrag
390 linkage_t linkage
; /* durable */
391 mempool::mds_co::list
<linkage_t
> projected
;
393 version_t version
= 0; // dir version when last touched.
394 version_t projected_version
= 0; // what it will be when i unlock/commit.
397 mempool::mds_co::string name
;
398 mempool::mds_co::string alternate_name
;
401 std::ostream
& operator<<(std::ostream
& out
, const CDentry
& dn
);