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.
20 #include "SnapClient.h"
25 #include "LogSegment.h"
27 #include "messages/MLock.h"
29 #define dout_context g_ceph_context
30 #define dout_subsys ceph_subsys_mds
32 #define dout_prefix *_dout << "mds." << dir->mdcache->mds->get_nodeid() << ".cache.den(" << dir->dirfrag() << " " << name << ") "
36 ostream
& CDentry::print_db_line_prefix(ostream
& out
)
38 return out
<< ceph_clock_now() << " mds." << dir
->mdcache
->mds
->get_nodeid() << ".cache.den(" << dir
->ino() << " " << name
<< ") ";
41 LockType
CDentry::lock_type(CEPH_LOCK_DN
);
42 LockType
CDentry::versionlock_type(CEPH_LOCK_DVERSION
);
47 ostream
& operator<<(ostream
& out
, const CDentry
& dn
)
52 out
<< "[dentry " << path
;
54 if (true || dn
.first
!= 0 || dn
.last
!= CEPH_NOSNAP
) {
55 out
<< " [" << dn
.first
<< ",";
56 if (dn
.last
== CEPH_NOSNAP
)
65 if (dn
.is_replicated())
66 out
<< dn
.get_replicas();
68 mds_authority_t a
= dn
.authority();
69 out
<< " rep@" << a
.first
;
70 if (a
.second
!= CDIR_AUTH_UNKNOWN
)
71 out
<< "," << a
.second
;
72 out
<< "." << dn
.get_replica_nonce();
75 if (dn
.get_linkage()->is_null()) out
<< " NULL";
76 if (dn
.get_linkage()->is_remote()) {
78 out
<< dn
.get_linkage()->get_remote_d_type_string();
82 if (!dn
.lock
.is_sync_and_unlocked())
83 out
<< " " << dn
.lock
;
84 if (!dn
.versionlock
.is_sync_and_unlocked())
85 out
<< " " << dn
.versionlock
;
87 if (dn
.get_projected_version() != dn
.get_version())
88 out
<< " pv=" << dn
.get_projected_version();
89 out
<< " v=" << dn
.get_version();
91 if (dn
.get_num_auth_pins()) {
92 out
<< " ap=" << dn
.get_num_auth_pins();
93 #ifdef MDS_AUTHPIN_SET
94 dn
.print_authpin_set(out
);
99 const CInode
*inode
= dn
.get_linkage()->get_inode();
108 out
<< " state=" << dn
.get_state();
109 if (dn
.is_new()) out
<< "|new";
110 if (dn
.state_test(CDentry::STATE_BOTTOMLRU
)) out
<< "|bottomlru";
111 if (dn
.state_test(CDentry::STATE_UNLINKING
)) out
<< "|unlinking";
112 if (dn
.state_test(CDentry::STATE_REINTEGRATING
)) out
<< "|reintegrating";
114 if (dn
.get_num_ref()) {
116 dn
.print_pin_set(out
);
119 if (dn
.get_alternate_name().size()) {
120 out
<< " altname=" << binstrprint(dn
.get_alternate_name(), 16);
129 bool operator<(const CDentry
& l
, const CDentry
& r
)
131 if ((l
.get_dir()->ino() < r
.get_dir()->ino()) ||
132 (l
.get_dir()->ino() == r
.get_dir()->ino() &&
133 (l
.get_name() < r
.get_name() ||
134 (l
.get_name() == r
.get_name() && l
.last
< r
.last
))))
140 void CDentry::print(ostream
& out
)
147 inodeno_t CDentry::get_ino()
150 return get_inode()->ino();
155 mds_authority_t
CDentry::authority() const
157 return dir
->authority();
161 void CDentry::add_waiter(uint64_t tag
, MDSContext
*c
)
163 // wait on the directory?
164 if (tag
& (WAIT_UNFREEZE
|WAIT_SINGLEAUTH
)) {
165 dir
->add_waiter(tag
, c
);
168 MDSCacheObject::add_waiter(tag
, c
);
172 version_t
CDentry::pre_dirty(version_t min
)
174 projected_version
= dir
->pre_dirty(min
);
175 dout(10) << __func__
<< " " << *this << dendl
;
176 return projected_version
;
180 void CDentry::_mark_dirty(LogSegment
*ls
)
183 if (!state_test(STATE_DIRTY
)) {
184 state_set(STATE_DIRTY
);
186 dir
->inc_num_dirty();
187 dir
->dirty_dentries
.push_back(&item_dir_dirty
);
191 ls
->dirty_dentries
.push_back(&item_dirty
);
194 void CDentry::mark_dirty(version_t pv
, LogSegment
*ls
)
196 dout(10) << __func__
<< " " << *this << dendl
;
198 // i now live in this new dir version
199 ceph_assert(pv
<= projected_version
);
204 dir
->mark_dirty(ls
, pv
);
208 void CDentry::mark_clean()
210 dout(10) << __func__
<< " " << *this << dendl
;
211 ceph_assert(is_dirty());
213 // not always true for recalc_auth_bits during resolve finish
214 //assert(dir->get_version() == 0 || version <= dir->get_version()); // hmm?
216 state_clear(STATE_DIRTY
|STATE_NEW
);
217 dir
->dec_num_dirty();
219 item_dir_dirty
.remove_myself();
220 item_dirty
.remove_myself();
225 void CDentry::mark_new()
227 dout(10) << __func__
<< " " << *this << dendl
;
228 state_set(STATE_NEW
);
231 void CDentry::mark_auth()
234 state_set(STATE_AUTH
);
235 dir
->adjust_dentry_lru(this);
239 void CDentry::clear_auth()
242 state_clear(STATE_AUTH
);
243 dir
->adjust_dentry_lru(this);
247 void CDentry::make_path_string(string
& s
, bool projected
) const
250 dir
->inode
->make_path_string(s
, projected
);
255 s
.append(name
.data(), name
.length());
258 void CDentry::make_path(filepath
& fp
, bool projected
) const
261 dir
->inode
->make_path(fp
, projected
);
262 fp
.push_dentry(get_name());
266 * we only add ourselves to remote_parents when the linkage is
267 * active (no longer projected). if the passed dnl is projected,
268 * don't link in, and do that work later in pop_projected_linkage().
270 void CDentry::link_remote(CDentry::linkage_t
*dnl
, CInode
*in
)
272 ceph_assert(dnl
->is_remote());
273 ceph_assert(in
->ino() == dnl
->get_remote_ino());
277 in
->add_remote_parent(this);
279 // check for reintegration
280 dir
->mdcache
->eval_remote(this);
283 void CDentry::unlink_remote(CDentry::linkage_t
*dnl
)
285 ceph_assert(dnl
->is_remote());
286 ceph_assert(dnl
->inode
);
289 dnl
->inode
->remove_remote_parent(this);
294 void CDentry::push_projected_linkage()
299 CInode
*diri
= dir
->inode
;
300 if (diri
->is_stray())
301 diri
->mdcache
->notify_stray_removed();
306 void CDentry::push_projected_linkage(CInode
*inode
)
308 // dirty rstat tracking is in the projected plane
309 bool dirty_rstat
= inode
->is_dirty_rstat();
311 inode
->clear_dirty_rstat();
313 _project_linkage()->inode
= inode
;
314 inode
->push_projected_parent(this);
317 inode
->mark_dirty_rstat();
320 CInode
*diri
= dir
->inode
;
321 if (diri
->is_stray())
322 diri
->mdcache
->notify_stray_created();
326 CDentry::linkage_t
*CDentry::pop_projected_linkage()
328 ceph_assert(projected
.size());
330 linkage_t
& n
= projected
.front();
333 * the idea here is that the link_remote_inode(), link_primary_inode(),
334 * etc. calls should make linkage identical to &n (and we assert as
339 dir
->link_remote_inode(this, n
.remote_ino
, n
.remote_d_type
);
341 linkage
.inode
= n
.inode
;
342 linkage
.inode
->add_remote_parent(this);
346 dir
->link_primary_inode(this, n
.inode
);
347 n
.inode
->pop_projected_parent();
351 ceph_assert(n
.inode
== linkage
.inode
);
352 ceph_assert(n
.remote_ino
== linkage
.remote_ino
);
353 ceph_assert(n
.remote_d_type
== linkage
.remote_d_type
);
355 projected
.pop_front();
362 // ----------------------------
365 int CDentry::get_num_dir_auth_pins() const
367 ceph_assert(!is_projected());
368 if (get_linkage()->is_primary())
369 return auth_pins
+ get_linkage()->get_inode()->get_num_auth_pins();
373 bool CDentry::can_auth_pin(int *err_ret
) const
376 return dir
->can_auth_pin(err_ret
);
379 void CDentry::auth_pin(void *by
)
385 #ifdef MDS_AUTHPIN_SET
386 auth_pin_set
.insert(by
);
389 dout(10) << "auth_pin by " << by
<< " on " << *this << " now " << auth_pins
<< dendl
;
391 dir
->adjust_nested_auth_pins(1, by
);
394 void CDentry::auth_unpin(void *by
)
398 #ifdef MDS_AUTHPIN_SET
400 auto it
= auth_pin_set
.find(by
);
401 ceph_assert(it
!= auth_pin_set
.end());
402 auth_pin_set
.erase(it
);
409 dout(10) << "auth_unpin by " << by
<< " on " << *this << " now " << auth_pins
<< dendl
;
410 ceph_assert(auth_pins
>= 0);
412 dir
->adjust_nested_auth_pins(-1, by
);
415 void CDentry::adjust_nested_auth_pins(int diradj
, void *by
)
417 dir
->adjust_nested_auth_pins(diradj
, by
);
420 bool CDentry::is_frozen() const
422 return dir
->is_frozen();
425 bool CDentry::is_freezing() const
427 return dir
->is_freezing();
430 // ----------------------------
433 void CDentry::set_object_info(MDSCacheObjectInfo
&info
)
435 info
.dirfrag
= dir
->dirfrag();
440 void CDentry::encode_lock_state(int type
, bufferlist
& bl
)
444 // null, ino, or remote_ino?
446 if (linkage
.is_primary()) {
449 encode(linkage
.get_inode()->ino(), bl
);
451 else if (linkage
.is_remote()) {
454 encode(linkage
.get_remote_ino(), bl
);
456 else if (linkage
.is_null()) {
462 void CDentry::decode_lock_state(int type
, const bufferlist
& bl
)
464 auto p
= bl
.cbegin();
469 if (!is_auth() && newfirst
!= first
) {
470 dout(10) << __func__
<< " first " << first
<< " -> " << newfirst
<< dendl
;
471 ceph_assert(newfirst
> first
);
477 ceph_assert(linkage
.is_null());
490 if (linkage
.is_null() && !is_auth()) {
491 // force trim from cache!
492 dout(10) << __func__
<< " replica dentry null -> non-null, must trim" << dendl
;
493 //assert(get_num_ref() == 0);
505 ClientLease
*CDentry::add_client_lease(client_t c
, Session
*session
)
508 if (client_lease_map
.count(c
))
509 l
= client_lease_map
[c
];
511 dout(20) << __func__
<< " client." << c
<< " on " << lock
<< dendl
;
512 if (client_lease_map
.empty()) {
513 get(PIN_CLIENTLEASE
);
514 lock
.get_client_lease();
516 l
= client_lease_map
[c
] = new ClientLease(c
, this);
517 l
->seq
= ++session
->lease_seq
;
524 void CDentry::remove_client_lease(ClientLease
*l
, Locker
*locker
)
526 ceph_assert(l
->parent
== this);
530 dout(20) << __func__
<< " client." << l
->client
<< " on " << lock
<< dendl
;
532 client_lease_map
.erase(l
->client
);
533 l
->item_lease
.remove_myself();
534 l
->item_session_lease
.remove_myself();
537 if (client_lease_map
.empty()) {
538 gather
= !lock
.is_stable();
539 lock
.put_client_lease();
540 put(PIN_CLIENTLEASE
);
544 locker
->eval_gather(&lock
);
547 void CDentry::remove_client_leases(Locker
*locker
)
549 while (!client_lease_map
.empty())
550 remove_client_lease(client_lease_map
.begin()->second
, locker
);
555 if (get_num_ref() <= ((int)is_dirty() + 1)) {
556 CDentry::linkage_t
*dnl
= get_projected_linkage();
557 if (dnl
->is_primary()) {
558 CInode
*in
= dnl
->get_inode();
559 if (get_num_ref() == (int)is_dirty() + !!in
->get_num_ref())
560 in
->mdcache
->maybe_eval_stray(in
, true);
565 void CDentry::encode_remote(inodeno_t
& ino
, unsigned char d_type
,
566 std::string_view alternate_name
,
569 bl
.append('l'); // remote link
572 ENCODE_START(2, 1, bl
);
575 encode(alternate_name
, bl
);
579 void CDentry::decode_remote(char icode
, inodeno_t
& ino
, unsigned char& d_type
,
580 mempool::mds_co::string
& alternate_name
,
581 ceph::buffer::list::const_iterator
& bl
)
588 decode(alternate_name
, bl
);
590 } else if (icode
== 'L') {
593 } else ceph_assert(0);
596 void CDentry::dump(Formatter
*f
) const
598 ceph_assert(f
!= NULL
);
603 f
->dump_string("path", path
.get_path());
604 f
->dump_unsigned("path_ino", path
.get_ino().val
);
605 f
->dump_unsigned("snap_first", first
);
606 f
->dump_unsigned("snap_last", last
);
608 f
->dump_bool("is_primary", get_linkage()->is_primary());
609 f
->dump_bool("is_remote", get_linkage()->is_remote());
610 f
->dump_bool("is_null", get_linkage()->is_null());
611 f
->dump_bool("is_new", is_new());
612 if (get_linkage()->get_inode()) {
613 f
->dump_unsigned("inode", get_linkage()->get_inode()->ino());
615 f
->dump_unsigned("inode", 0);
618 if (linkage
.is_remote()) {
619 f
->dump_string("remote_type", linkage
.get_remote_d_type_string());
621 f
->dump_string("remote_type", "");
624 f
->dump_unsigned("version", get_version());
625 f
->dump_unsigned("projected_version", get_projected_version());
627 f
->dump_int("auth_pins", auth_pins
);
629 MDSCacheObject::dump(f
);
631 f
->open_object_section("lock");
635 f
->open_object_section("versionlock");
639 f
->open_array_section("states");
640 MDSCacheObject::dump_states(f
);
641 if (state_test(STATE_NEW
))
642 f
->dump_string("state", "new");
643 if (state_test(STATE_FRAGMENTING
))
644 f
->dump_string("state", "fragmenting");
645 if (state_test(STATE_PURGING
))
646 f
->dump_string("state", "purging");
647 if (state_test(STATE_BADREMOTEINO
))
648 f
->dump_string("state", "badremoteino");
649 if (state_test(STATE_STRAY
))
650 f
->dump_string("state", "stray");
654 std::string
CDentry::linkage_t::get_remote_d_type_string() const
656 switch (DTTOIF(remote_d_type
)) {
657 case S_IFSOCK
: return "sock";
658 case S_IFLNK
: return "lnk";
659 case S_IFREG
: return "reg";
660 case S_IFBLK
: return "blk";
661 case S_IFDIR
: return "dir";
662 case S_IFCHR
: return "chr";
663 case S_IFIFO
: return "fifo";
664 default: ceph_abort(); return "";
668 bool CDentry::scrub(snapid_t next_seq
)
670 dout(20) << "scrubbing " << *this << " next_seq = " << next_seq
<< dendl
;
672 /* attempt to locate damage in first of CDentry, see:
673 * https://tracker.ceph.com/issues/56140
675 /* skip projected dentries as first/last may have placeholder values */
676 if (!is_projected()) {
677 CDir
* dir
= get_dir();
679 if (first
> next_seq
) {
680 derr
<< __func__
<< ": first > next_seq (" << next_seq
<< ") " << *this << dendl
;
681 dir
->go_bad_dentry(last
, get_name());
683 } else if (first
> last
) {
684 derr
<< __func__
<< ": first > last " << *this << dendl
;
685 dir
->go_bad_dentry(last
, get_name());
689 auto&& realm
= dir
->get_inode()->find_snaprealm();
691 auto&& snaps
= realm
->get_snaps();
692 auto it
= snaps
.lower_bound(first
);
693 bool stale
= last
!= CEPH_NOSNAP
&& (it
== snaps
.end() || *it
> last
);
695 dout(20) << "is stale" << dendl
;
696 /* TODO: maybe trim? */
703 bool CDentry::check_corruption(bool load
)
705 auto&& snapclient
= dir
->mdcache
->mds
->snapclient
;
706 auto next_snap
= snapclient
->get_last_seq()+1;
707 if (first
> last
|| (snapclient
->is_server_ready() && first
> next_snap
)) {
709 dout(1) << "loaded already corrupt dentry: " << *this << dendl
;
710 corrupt_first_loaded
= true;
712 derr
<< "newly corrupt dentry to be committed: " << *this << dendl
;
714 if (g_conf().get_val
<bool>("mds_go_bad_corrupt_dentry")) {
715 dir
->go_bad_dentry(last
, get_name());
717 if (!load
&& g_conf().get_val
<bool>("mds_abort_on_newly_corrupt_dentry")) {
718 dir
->mdcache
->mds
->clog
->error() << "MDS abort because newly corrupt dentry to be committed: " << *this;
719 ceph_abort("detected newly corrupt dentry"); /* avoid writing out newly corrupted dn */
726 MEMPOOL_DEFINE_OBJECT_FACTORY(CDentry
, co_dentry
, mds_co
);