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) 2015 Red Hat
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.
16 #include "common/perf_counters.h"
18 #include "mds/MDSRank.h"
19 #include "mds/MDCache.h"
20 #include "mds/MDLog.h"
22 #include "mds/CDentry.h"
23 #include "events/EUpdate.h"
24 #include "messages/MClientRequest.h"
26 #include "StrayManager.h"
28 #define dout_context g_ceph_context
29 #define dout_subsys ceph_subsys_mds
31 #define dout_prefix _prefix(_dout, mds)
35 static ostream
& _prefix(std::ostream
*_dout
, MDSRank
*mds
) {
36 return *_dout
<< "mds." << mds
->get_nodeid() << ".cache.strays ";
39 class StrayManagerIOContext
: public virtual MDSIOContextBase
{
42 MDSRank
*get_mds() override
47 explicit StrayManagerIOContext(StrayManager
*sm_
) : sm(sm_
) {}
50 class StrayManagerLogContext
: public virtual MDSLogContextBase
{
53 MDSRank
*get_mds() override
58 explicit StrayManagerLogContext(StrayManager
*sm_
) : sm(sm_
) {}
61 class StrayManagerContext
: public virtual MDSContext
{
64 MDSRank
*get_mds() override
69 explicit StrayManagerContext(StrayManager
*sm_
) : sm(sm_
) {}
74 * Context wrapper for _purge_stray_purged completion
76 class C_IO_PurgeStrayPurged
: public StrayManagerIOContext
{
80 C_IO_PurgeStrayPurged(StrayManager
*sm_
, CDentry
*d
, bool oh
) :
81 StrayManagerIOContext(sm_
), dn(d
), only_head(oh
) { }
82 void finish(int r
) override
{
83 ceph_assert(r
== 0 || r
== -CEPHFS_ENOENT
);
84 sm
->_purge_stray_purged(dn
, only_head
);
86 void print(ostream
& out
) const override
{
87 CInode
*in
= dn
->get_projected_linkage()->get_inode();
88 out
<< "purge_stray(" << in
->ino() << ")";
93 void StrayManager::purge(CDentry
*dn
)
95 CDentry::linkage_t
*dnl
= dn
->get_projected_linkage();
96 CInode
*in
= dnl
->get_inode();
97 dout(10) << __func__
<< " " << *dn
<< " " << *in
<< dendl
;
98 ceph_assert(!dn
->is_replicated());
100 // CHEAT. there's no real need to journal our intent to purge, since
101 // that is implicit in the dentry's presence and non-use in the stray
102 // dir. on recovery, we'll need to re-eval all strays anyway.
104 SnapContext nullsnapc
;
107 item
.ino
= in
->ino();
108 item
.stamp
= ceph_clock_now();
110 item
.action
= PurgeItem::PURGE_DIR
;
111 item
.fragtree
= in
->dirfragtree
;
113 item
.action
= PurgeItem::PURGE_FILE
;
115 const SnapContext
*snapc
;
116 SnapRealm
*realm
= in
->find_snaprealm();
118 dout(10) << " realm " << *realm
<< dendl
;
119 snapc
= &realm
->get_snap_context();
121 dout(10) << " NO realm, using null context" << dendl
;
123 ceph_assert(in
->last
== CEPH_NOSNAP
);
126 const auto& pi
= in
->get_projected_inode();
130 to
= std::max(pi
->size
, pi
->get_max_size());
131 // when truncating a file, the filer does not delete stripe objects that are
132 // truncated to zero. so we need to purge stripe objects up to the max size
133 // the file has ever been.
134 to
= std::max(pi
->max_size_ever
, to
);
138 item
.layout
= pi
->layout
;
139 item
.old_pools
.reserve(pi
->old_pools
.size());
140 for (const auto &p
: pi
->old_pools
) {
141 if (p
!= pi
->layout
.pool_id
)
142 item
.old_pools
.push_back(p
);
147 purge_queue
.push(item
, new C_IO_PurgeStrayPurged(
151 class C_PurgeStrayLogged
: public StrayManagerLogContext
{
156 C_PurgeStrayLogged(StrayManager
*sm_
, CDentry
*d
, version_t v
, MutationRef
& m
) :
157 StrayManagerLogContext(sm_
), dn(d
), pdv(v
), mut(m
) { }
158 void finish(int r
) override
{
159 sm
->_purge_stray_logged(dn
, pdv
, mut
);
163 class C_TruncateStrayLogged
: public StrayManagerLogContext
{
167 C_TruncateStrayLogged(StrayManager
*sm
, CDentry
*d
, MutationRef
& m
) :
168 StrayManagerLogContext(sm
), dn(d
), mut(m
) {}
169 void finish(int r
) override
{
170 sm
->_truncate_stray_logged(dn
, mut
);
174 void StrayManager::_purge_stray_purged(
175 CDentry
*dn
, bool only_head
)
177 CInode
*in
= dn
->get_projected_linkage()->get_inode();
178 dout(10) << "_purge_stray_purged " << *dn
<< " " << *in
<< dendl
;
180 logger
->inc(l_mdc_strays_enqueued
);
181 num_strays_enqueuing
--;
182 logger
->set(l_mdc_num_strays_enqueuing
, num_strays_enqueuing
);
185 /* This was a ::truncate */
186 MutationRef
mut(new MutationImpl());
187 mut
->ls
= mds
->mdlog
->get_current_segment();
189 auto pi
= in
->project_inode(mut
);
191 pi
.inode
->max_size_ever
= 0;
192 pi
.inode
->client_ranges
.clear();
193 pi
.inode
->truncate_size
= 0;
194 pi
.inode
->truncate_from
= 0;
195 pi
.inode
->version
= in
->pre_dirty();
196 pi
.inode
->client_ranges
.clear();
197 in
->clear_clientwriteable();
199 CDir
*dir
= dn
->get_dir();
200 auto pf
= dir
->project_fnode(mut
);
201 pf
->version
= dir
->pre_dirty();
203 EUpdate
*le
= new EUpdate(mds
->mdlog
, "purge_stray truncate");
204 mds
->mdlog
->start_entry(le
);
206 le
->metablob
.add_dir_context(dir
);
207 auto& dl
= le
->metablob
.add_dir(dn
->dir
, true);
208 le
->metablob
.add_primary_dentry(dl
, dn
, in
, EMetaBlob::fullbit::STATE_DIRTY
);
210 mds
->mdlog
->submit_entry(le
, new C_TruncateStrayLogged(this, dn
, mut
));
212 if (in
->get_num_ref() != (int)in
->is_dirty() ||
214 (int)dn
->is_dirty() +
215 !!dn
->state_test(CDentry::STATE_FRAGMENTING
) +
216 !!in
->get_num_ref() + 1 /* PIN_PURGING */) {
217 // Nobody should be taking new references to an inode when it
218 // is being purged (aside from it were
220 derr
<< "Rogue reference after purge to " << *dn
<< dendl
;
221 ceph_abort_msg("rogue reference to purging inode");
224 MutationRef
mut(new MutationImpl());
225 mut
->ls
= mds
->mdlog
->get_current_segment();
228 version_t pdv
= dn
->pre_dirty();
229 dn
->push_projected_linkage(); // NULL
231 EUpdate
*le
= new EUpdate(mds
->mdlog
, "purge_stray");
232 mds
->mdlog
->start_entry(le
);
234 // update dirfrag fragstat, rstat
235 CDir
*dir
= dn
->get_dir();
236 auto pf
= dir
->project_fnode(mut
);
237 pf
->version
= dir
->pre_dirty();
239 pf
->fragstat
.nsubdirs
--;
241 pf
->fragstat
.nfiles
--;
242 pf
->rstat
.sub(in
->get_inode()->accounted_rstat
);
244 le
->metablob
.add_dir_context(dn
->dir
);
245 auto& dl
= le
->metablob
.add_dir(dn
->dir
, true);
246 le
->metablob
.add_null_dentry(dl
, dn
, true);
247 le
->metablob
.add_destroyed_inode(in
->ino());
249 mds
->mdlog
->submit_entry(le
, new C_PurgeStrayLogged(this, dn
, pdv
, mut
));
253 void StrayManager::_purge_stray_logged(CDentry
*dn
, version_t pdv
, MutationRef
& mut
)
255 CInode
*in
= dn
->get_linkage()->get_inode();
256 CDir
*dir
= dn
->get_dir();
257 dout(10) << "_purge_stray_logged " << *dn
<< " " << *in
<< dendl
;
259 ceph_assert(!in
->state_test(CInode::STATE_RECOVERING
));
260 ceph_assert(!dir
->is_frozen_dir());
262 bool new_dn
= dn
->is_new();
265 ceph_assert(dn
->get_projected_linkage()->is_null());
266 dir
->unlink_inode(dn
, !new_dn
);
267 dn
->pop_projected_linkage();
268 dn
->mark_dirty(pdv
, mut
->ls
);
272 in
->state_clear(CInode::STATE_ORPHAN
);
273 dn
->state_clear(CDentry::STATE_PURGING
| CDentry::STATE_PURGINGPINNED
);
274 dn
->put(CDentry::PIN_PURGING
);
279 dout(20) << " dn is new, removing" << dendl
;
281 dir
->remove_dentry(dn
);
284 // Once we are here normally the waiter list are mostly empty
285 // but in corner case that the clients pass a invalidate ino,
286 // which maybe under unlinking, the link caller will add the
287 // request to the waiter list. We need try to wake them up
289 MDSContext::vec finished
;
290 in
->take_waiting(CInode::WAIT_UNLINK
, finished
);
291 if (!finished
.empty()) {
292 mds
->queue_waiters(finished
);
296 inodeno_t ino
= in
->ino();
299 mds
->mdcache
->remove_inode(in
);
301 dir
->auth_unpin(this);
303 if (mds
->is_stopping())
304 mds
->mdcache
->shutdown_export_stray_finish(ino
);
307 void StrayManager::enqueue(CDentry
*dn
, bool trunc
)
309 CDentry::linkage_t
*dnl
= dn
->get_projected_linkage();
311 CInode
*in
= dnl
->get_inode();
314 /* We consider a stray to be purging as soon as it is enqueued, to avoid
315 * enqueing it twice */
316 dn
->state_set(CDentry::STATE_PURGING
);
317 in
->state_set(CInode::STATE_PURGING
);
319 /* We must clear this as soon as enqueuing it, to prevent the journal
320 * expiry code from seeing a dirty parent and trying to write a backtrace */
322 if (in
->is_dirty_parent()) {
323 in
->clear_dirty_parent();
327 dout(20) << __func__
<< ": purging dn: " << *dn
<< dendl
;
329 if (!dn
->state_test(CDentry::STATE_PURGINGPINNED
)) {
330 dn
->get(CDentry::PIN_PURGING
);
331 dn
->state_set(CDentry::STATE_PURGINGPINNED
);
334 ++num_strays_enqueuing
;
335 logger
->set(l_mdc_num_strays_enqueuing
, num_strays_enqueuing
);
337 // Resources are available, acquire them and execute the purge
340 dout(10) << __func__
<< ": purging this dentry immediately: "
344 class C_RetryEnqueue
: public StrayManagerContext
{
348 C_RetryEnqueue(StrayManager
*sm_
, CDentry
*dn_
, bool t
) :
349 StrayManagerContext(sm_
), dn(dn_
), trunc(t
) { }
350 void finish(int r
) override
{
351 sm
->_enqueue(dn
, trunc
);
355 void StrayManager::_enqueue(CDentry
*dn
, bool trunc
)
357 ceph_assert(started
);
359 CDir
*dir
= dn
->get_dir();
360 if (!dir
->can_auth_pin()) {
361 dout(10) << " can't auth_pin (freezing?) " << *dir
<< ", waiting" << dendl
;
362 dir
->add_waiter(CDir::WAIT_UNFREEZE
, new C_RetryEnqueue(this, dn
, trunc
));
366 dn
->get_dir()->auth_pin(this);
374 void StrayManager::queue_delayed(CDentry
*dn
)
379 if (dn
->state_test(CDentry::STATE_EVALUATINGSTRAY
))
382 if (!dn
->item_stray
.is_on_list()) {
383 delayed_eval_stray
.push_back(&dn
->item_stray
);
384 num_strays_delayed
++;
385 logger
->set(l_mdc_num_strays_delayed
, num_strays_delayed
);
389 void StrayManager::advance_delayed()
394 while (!delayed_eval_stray
.empty()) {
395 CDentry
*dn
= delayed_eval_stray
.front();
396 dn
->item_stray
.remove_myself();
397 num_strays_delayed
--;
399 if (dn
->get_projected_linkage()->is_null()) {
400 /* A special case: a stray dentry can go null if its inode is being
401 * re-linked into another MDS's stray dir during a shutdown migration. */
402 dout(4) << __func__
<< ": delayed dentry is now null: " << *dn
<< dendl
;
408 logger
->set(l_mdc_num_strays_delayed
, num_strays_delayed
);
411 void StrayManager::set_num_strays(uint64_t num
)
413 ceph_assert(!started
);
415 logger
->set(l_mdc_num_strays
, num_strays
);
418 void StrayManager::notify_stray_created()
421 logger
->set(l_mdc_num_strays
, num_strays
);
422 logger
->inc(l_mdc_strays_created
);
425 void StrayManager::notify_stray_removed()
428 logger
->set(l_mdc_num_strays
, num_strays
);
431 struct C_EvalStray
: public StrayManagerContext
{
433 C_EvalStray(StrayManager
*sm_
, CDentry
*d
) : StrayManagerContext(sm_
), dn(d
) {}
434 void finish(int r
) override
{
439 struct C_MDC_EvalStray
: public StrayManagerContext
{
441 C_MDC_EvalStray(StrayManager
*sm_
, CDentry
*d
) : StrayManagerContext(sm_
), dn(d
) {}
442 void finish(int r
) override
{
447 bool StrayManager::_eval_stray(CDentry
*dn
)
449 dout(10) << "eval_stray " << *dn
<< dendl
;
450 CDentry::linkage_t
*dnl
= dn
->get_projected_linkage();
451 ceph_assert(dnl
->is_primary());
452 dout(10) << " inode is " << *dnl
->get_inode() << dendl
;
453 CInode
*in
= dnl
->get_inode();
455 ceph_assert(!in
->state_test(CInode::STATE_REJOINUNDEF
));
457 // The only dentries elegible for purging are those
458 // in the stray directories
459 ceph_assert(dn
->get_dir()->get_inode()->is_stray());
461 // Inode may not pass through this function if it
462 // was already identified for purging (i.e. cannot
463 // call eval_stray() after purge()
464 ceph_assert(!dn
->state_test(CDentry::STATE_PURGING
));
472 if (dn
->item_stray
.is_on_list()) {
473 dn
->item_stray
.remove_myself();
474 num_strays_delayed
--;
475 logger
->set(l_mdc_num_strays_delayed
, num_strays_delayed
);
479 if (in
->get_inode()->nlink
== 0) {
480 // past snaprealm parents imply snapped dentry remote links.
481 // only important for directories. normal file data snaps are handled
482 // by the object store.
484 in
->snaprealm
->prune_past_parent_snaps();
485 in
->purge_stale_snap_data(in
->snaprealm
->get_snaps());
488 if (in
->snaprealm
&& in
->snaprealm
->has_past_parent_snaps()) {
489 dout(20) << " directory has past parents "
490 << in
->snaprealm
<< dendl
;
491 if (in
->state_test(CInode::STATE_MISSINGOBJS
)) {
492 mds
->clog
->error() << "previous attempt at committing dirfrag of ino "
493 << in
->ino() << " has failed, missing object";
494 mds
->handle_write_error(-CEPHFS_ENOENT
);
496 return false; // not until some snaps are deleted.
499 mds
->mdcache
->clear_dirty_bits_for_stray(in
);
501 if (!in
->remote_parents
.empty()) {
502 // unlink any stale remote snap dentry.
503 for (auto it
= in
->remote_parents
.begin(); it
!= in
->remote_parents
.end(); ) {
504 CDentry
*remote_dn
= *it
;
506 ceph_assert(remote_dn
->last
!= CEPH_NOSNAP
);
507 remote_dn
->unlink_remote(remote_dn
->get_linkage());
511 if (dn
->is_replicated()) {
512 dout(20) << " replicated" << dendl
;
515 if (dn
->is_any_leases() || in
->is_any_caps()) {
516 dout(20) << " caps | leases" << dendl
;
517 return false; // wait
519 if (in
->state_test(CInode::STATE_NEEDSRECOVER
) ||
520 in
->state_test(CInode::STATE_RECOVERING
)) {
521 dout(20) << " pending recovery" << dendl
;
522 return false; // don't mess with file size probing
524 if (in
->get_num_ref() > (int)in
->is_dirty() + (int)in
->is_dirty_parent()) {
525 dout(20) << " too many inode refs" << dendl
;
528 if (dn
->get_num_ref() > (int)dn
->is_dirty() + !!in
->get_num_ref()) {
529 dout(20) << " too many dn refs" << dendl
;
532 // don't purge multiversion inode with snap data
533 if (in
->snaprealm
&& in
->snaprealm
->has_past_parent_snaps() &&
534 in
->is_any_old_inodes()) {
535 // A file with snapshots: we will truncate the HEAD revision
536 // but leave the metadata intact.
537 ceph_assert(!in
->is_dir());
538 dout(20) << " file has past parents "
539 << in
->snaprealm
<< dendl
;
540 if (in
->is_file() && in
->get_projected_inode()->size
> 0) {
541 enqueue(dn
, true); // truncate head objects
544 // A straightforward file, ready to be purged. Enqueue it.
546 in
->close_dirfrags();
555 * Where a stray has some links, they should be remotes, check
556 * if we can do anything with them if we happen to have them in
559 _eval_stray_remote(dn
, NULL
);
564 void StrayManager::activate()
566 dout(10) << __func__
<< dendl
;
568 purge_queue
.activate();
571 bool StrayManager::eval_stray(CDentry
*dn
)
573 // avoid nested eval_stray
574 if (dn
->state_test(CDentry::STATE_EVALUATINGSTRAY
))
577 dn
->state_set(CDentry::STATE_EVALUATINGSTRAY
);
578 bool ret
= _eval_stray(dn
);
579 dn
->state_clear(CDentry::STATE_EVALUATINGSTRAY
);
583 void StrayManager::eval_remote(CDentry
*remote_dn
)
585 dout(10) << __func__
<< " " << *remote_dn
<< dendl
;
587 CDentry::linkage_t
*dnl
= remote_dn
->get_projected_linkage();
588 ceph_assert(dnl
->is_remote());
589 CInode
*in
= dnl
->get_inode();
592 dout(20) << __func__
<< ": no inode, cannot evaluate" << dendl
;
596 if (remote_dn
->last
!= CEPH_NOSNAP
) {
597 dout(20) << __func__
<< ": snap dentry, cannot evaluate" << dendl
;
602 CDentry
*primary_dn
= in
->get_projected_parent_dn();
603 ceph_assert(primary_dn
!= NULL
);
604 if (primary_dn
->get_dir()->get_inode()->is_stray()) {
605 _eval_stray_remote(primary_dn
, remote_dn
);
607 dout(20) << __func__
<< ": inode's primary dn not stray" << dendl
;
611 class C_RetryEvalRemote
: public StrayManagerContext
{
614 C_RetryEvalRemote(StrayManager
*sm_
, CDentry
*dn_
) :
615 StrayManagerContext(sm_
), dn(dn_
) {
616 dn
->get(CDentry::PIN_PTRWAITER
);
618 void finish(int r
) override
{
619 if (dn
->get_projected_linkage()->is_remote())
621 dn
->put(CDentry::PIN_PTRWAITER
);
625 void StrayManager::_eval_stray_remote(CDentry
*stray_dn
, CDentry
*remote_dn
)
627 dout(20) << __func__
<< " " << *stray_dn
<< dendl
;
628 ceph_assert(stray_dn
!= NULL
);
629 ceph_assert(stray_dn
->get_dir()->get_inode()->is_stray());
630 CDentry::linkage_t
*stray_dnl
= stray_dn
->get_projected_linkage();
631 ceph_assert(stray_dnl
->is_primary());
632 CInode
*stray_in
= stray_dnl
->get_inode();
633 ceph_assert(stray_in
->get_inode()->nlink
>= 1);
634 ceph_assert(stray_in
->last
== CEPH_NOSNAP
);
636 /* If no remote_dn hinted, pick one arbitrarily */
637 if (remote_dn
== NULL
) {
638 if (!stray_in
->remote_parents
.empty()) {
639 for (const auto &dn
: stray_in
->remote_parents
) {
640 if (dn
->last
== CEPH_NOSNAP
&& !dn
->is_projected()) {
643 if (remote_dn
->dir
->can_auth_pin())
645 } else if (!remote_dn
) {
652 dout(20) << __func__
<< ": not reintegrating (no remote parents in cache)" << dendl
;
656 ceph_assert(remote_dn
->last
== CEPH_NOSNAP
);
657 // NOTE: we repeat this check in _rename(), since our submission path is racey.
658 if (!remote_dn
->is_projected()) {
659 if (remote_dn
->is_auth()) {
660 if (remote_dn
->dir
->can_auth_pin()) {
661 reintegrate_stray(stray_dn
, remote_dn
);
663 remote_dn
->dir
->add_waiter(CDir::WAIT_UNFREEZE
, new C_RetryEvalRemote(this, remote_dn
));
664 dout(20) << __func__
<< ": not reintegrating (can't authpin remote parent)" << dendl
;
667 } else if (stray_dn
->is_auth()) {
668 migrate_stray(stray_dn
, remote_dn
->authority().first
);
670 dout(20) << __func__
<< ": not reintegrating" << dendl
;
673 // don't do anything if the remote parent is projected, or we may
674 // break user-visible semantics!
675 dout(20) << __func__
<< ": not reintegrating (projected)" << dendl
;
679 void StrayManager::reintegrate_stray(CDentry
*straydn
, CDentry
*rdn
)
681 dout(10) << __func__
<< " " << *straydn
<< " to " << *rdn
<< dendl
;
683 logger
->inc(l_mdc_strays_reintegrated
);
685 // rename it to remote linkage .
686 filepath
src(straydn
->get_name(), straydn
->get_dir()->ino());
687 filepath
dst(rdn
->get_name(), rdn
->get_dir()->ino());
689 ceph_tid_t tid
= mds
->issue_tid();
691 auto req
= make_message
<MClientRequest
>(CEPH_MDS_OP_RENAME
);
692 req
->set_filepath(dst
);
693 req
->set_filepath2(src
);
696 rdn
->state_set(CDentry::STATE_REINTEGRATING
);
697 mds
->internal_client_requests
.emplace(std::piecewise_construct
,
698 std::make_tuple(tid
),
699 std::make_tuple(CEPH_MDS_OP_RENAME
,
702 mds
->send_message_mds(req
, rdn
->authority().first
);
705 void StrayManager::migrate_stray(CDentry
*dn
, mds_rank_t to
)
707 dout(10) << __func__
<< " " << *dn
<< " to mds." << to
<< dendl
;
709 logger
->inc(l_mdc_strays_migrated
);
711 // rename it to another mds.
712 inodeno_t dirino
= dn
->get_dir()->ino();
713 ceph_assert(MDS_INO_IS_STRAY(dirino
));
715 filepath
src(dn
->get_name(), dirino
);
716 filepath
dst(dn
->get_name(), MDS_INO_STRAY(to
, MDS_INO_STRAY_INDEX(dirino
)));
718 ceph_tid_t tid
= mds
->issue_tid();
720 auto req
= make_message
<MClientRequest
>(CEPH_MDS_OP_RENAME
);
721 req
->set_filepath(dst
);
722 req
->set_filepath2(src
);
725 mds
->internal_client_requests
.emplace(std::piecewise_construct
,
726 std::make_tuple(tid
),
727 std::make_tuple(CEPH_MDS_OP_RENAME
,
730 mds
->send_message_mds(req
, to
);
733 StrayManager::StrayManager(MDSRank
*mds
, PurgeQueue
&purge_queue_
)
734 : delayed_eval_stray(member_offset(CDentry
, item_stray
)),
735 mds(mds
), purge_queue(purge_queue_
)
737 ceph_assert(mds
!= NULL
);
740 void StrayManager::truncate(CDentry
*dn
)
742 const CDentry::linkage_t
*dnl
= dn
->get_projected_linkage();
743 const CInode
*in
= dnl
->get_inode();
745 dout(10) << __func__
<< ": " << *dn
<< " " << *in
<< dendl
;
746 ceph_assert(!dn
->is_replicated());
748 const SnapRealm
*realm
= in
->find_snaprealm();
750 dout(10) << " realm " << *realm
<< dendl
;
751 const SnapContext
*snapc
= &realm
->get_snap_context();
753 uint64_t to
= std::max(in
->get_inode()->size
, in
->get_inode()->get_max_size());
754 // when truncating a file, the filer does not delete stripe objects that are
755 // truncated to zero. so we need to purge stripe objects up to the max size
756 // the file has ever been.
757 to
= std::max(in
->get_inode()->max_size_ever
, to
);
762 item
.action
= PurgeItem::TRUNCATE_FILE
;
763 item
.ino
= in
->ino();
764 item
.layout
= in
->get_inode()->layout
;
767 item
.stamp
= ceph_clock_now();
769 purge_queue
.push(item
, new C_IO_PurgeStrayPurged(
773 void StrayManager::_truncate_stray_logged(CDentry
*dn
, MutationRef
& mut
)
775 CInode
*in
= dn
->get_projected_linkage()->get_inode();
777 dout(10) << __func__
<< ": " << *dn
<< " " << *in
<< dendl
;
781 in
->state_clear(CInode::STATE_PURGING
);
782 dn
->state_clear(CDentry::STATE_PURGING
| CDentry::STATE_PURGINGPINNED
);
783 dn
->put(CDentry::PIN_PURGING
);
785 dn
->get_dir()->auth_unpin(this);
789 if (!dn
->state_test(CDentry::STATE_PURGING
) && mds
->is_stopping())
790 mds
->mdcache
->shutdown_export_stray_finish(in
->ino());