]> git.proxmox.com Git - ceph.git/blame - ceph/src/mds/StrayManager.cc
Import ceph 15.2.8
[ceph.git] / ceph / src / mds / StrayManager.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph - scalable distributed file system
5 *
6 * Copyright (C) 2015 Red Hat
7 *
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.
12 *
13 */
14
15
16#include "common/perf_counters.h"
17
18#include "mds/MDSRank.h"
19#include "mds/MDCache.h"
20#include "mds/MDLog.h"
21#include "mds/CDir.h"
22#include "mds/CDentry.h"
23#include "events/EUpdate.h"
24#include "messages/MClientRequest.h"
25
26#include "StrayManager.h"
27
28#define dout_context g_ceph_context
29#define dout_subsys ceph_subsys_mds
30#undef dout_prefix
31#define dout_prefix _prefix(_dout, mds)
32static ostream& _prefix(std::ostream *_dout, MDSRank *mds) {
33 return *_dout << "mds." << mds->get_nodeid() << ".cache.strays ";
34}
35
36class StrayManagerIOContext : public virtual MDSIOContextBase {
37protected:
38 StrayManager *sm;
39 MDSRank *get_mds() override
40 {
41 return sm->mds;
42 }
43public:
44 explicit StrayManagerIOContext(StrayManager *sm_) : sm(sm_) {}
45};
46
47class StrayManagerLogContext : public virtual MDSLogContextBase {
48protected:
49 StrayManager *sm;
50 MDSRank *get_mds() override
51 {
52 return sm->mds;
53 }
54public:
55 explicit StrayManagerLogContext(StrayManager *sm_) : sm(sm_) {}
56};
57
11fdf7f2 58class StrayManagerContext : public virtual MDSContext {
7c673cae
FG
59protected:
60 StrayManager *sm;
61 MDSRank *get_mds() override
62 {
63 return sm->mds;
64 }
65public:
66 explicit StrayManagerContext(StrayManager *sm_) : sm(sm_) {}
67};
68
69
70/**
71 * Context wrapper for _purge_stray_purged completion
72 */
73class C_IO_PurgeStrayPurged : public StrayManagerIOContext {
74 CDentry *dn;
75 bool only_head;
7c673cae
FG
76public:
77 C_IO_PurgeStrayPurged(StrayManager *sm_, CDentry *d, bool oh) :
78 StrayManagerIOContext(sm_), dn(d), only_head(oh) { }
79 void finish(int r) override {
11fdf7f2 80 ceph_assert(r == 0 || r == -ENOENT);
d2e6a577 81 sm->_purge_stray_purged(dn, only_head);
7c673cae 82 }
91327a77
AA
83 void print(ostream& out) const override {
84 CInode *in = dn->get_projected_linkage()->get_inode();
85 out << "purge_stray(" << in->ino() << ")";
86 }
7c673cae
FG
87};
88
89
90void StrayManager::purge(CDentry *dn)
91{
92 CDentry::linkage_t *dnl = dn->get_projected_linkage();
93 CInode *in = dnl->get_inode();
94 dout(10) << __func__ << " " << *dn << " " << *in << dendl;
11fdf7f2 95 ceph_assert(!dn->is_replicated());
7c673cae
FG
96
97 // CHEAT. there's no real need to journal our intent to purge, since
98 // that is implicit in the dentry's presence and non-use in the stray
99 // dir. on recovery, we'll need to re-eval all strays anyway.
100
101 SnapContext nullsnapc;
102
103 PurgeItem item;
104 item.ino = in->inode.ino;
11fdf7f2 105 item.stamp = ceph_clock_now();
7c673cae
FG
106 if (in->is_dir()) {
107 item.action = PurgeItem::PURGE_DIR;
108 item.fragtree = in->dirfragtree;
109 } else {
110 item.action = PurgeItem::PURGE_FILE;
111
112 const SnapContext *snapc;
113 SnapRealm *realm = in->find_snaprealm();
114 if (realm) {
115 dout(10) << " realm " << *realm << dendl;
116 snapc = &realm->get_snap_context();
117 } else {
118 dout(10) << " NO realm, using null context" << dendl;
119 snapc = &nullsnapc;
11fdf7f2 120 ceph_assert(in->last == CEPH_NOSNAP);
7c673cae
FG
121 }
122
123 uint64_t to = 0;
124 if (in->is_file()) {
125 to = in->inode.get_max_size();
11fdf7f2 126 to = std::max(in->inode.size, to);
7c673cae
FG
127 // when truncating a file, the filer does not delete stripe objects that are
128 // truncated to zero. so we need to purge stripe objects up to the max size
129 // the file has ever been.
11fdf7f2 130 to = std::max(in->inode.max_size_ever, to);
7c673cae
FG
131 }
132
94b18763 133 auto pi = in->get_projected_inode();
7c673cae
FG
134
135 item.size = to;
136 item.layout = pi->layout;
94b18763
FG
137 item.old_pools.clear();
138 for (const auto &p : pi->old_pools)
139 item.old_pools.insert(p);
7c673cae
FG
140 item.snapc = *snapc;
141 }
142
143 purge_queue.push(item, new C_IO_PurgeStrayPurged(
144 this, dn, false));
145}
146
147class C_PurgeStrayLogged : public StrayManagerLogContext {
148 CDentry *dn;
149 version_t pdv;
150 LogSegment *ls;
151public:
152 C_PurgeStrayLogged(StrayManager *sm_, CDentry *d, version_t v, LogSegment *s) :
153 StrayManagerLogContext(sm_), dn(d), pdv(v), ls(s) { }
154 void finish(int r) override {
155 sm->_purge_stray_logged(dn, pdv, ls);
156 }
157};
158
159class C_TruncateStrayLogged : public StrayManagerLogContext {
160 CDentry *dn;
161 LogSegment *ls;
162public:
163 C_TruncateStrayLogged(StrayManager *sm, CDentry *d, LogSegment *s) :
164 StrayManagerLogContext(sm), dn(d), ls(s) { }
165 void finish(int r) override {
166 sm->_truncate_stray_logged(dn, ls);
167 }
168};
169
170void StrayManager::_purge_stray_purged(
d2e6a577 171 CDentry *dn, bool only_head)
7c673cae
FG
172{
173 CInode *in = dn->get_projected_linkage()->get_inode();
174 dout(10) << "_purge_stray_purged " << *dn << " " << *in << dendl;
175
176 logger->inc(l_mdc_strays_enqueued);
177 num_strays_enqueuing--;
178 logger->set(l_mdc_num_strays_enqueuing, num_strays_enqueuing);
179
180 if (only_head) {
181 /* This was a ::truncate */
182 EUpdate *le = new EUpdate(mds->mdlog, "purge_stray truncate");
183 mds->mdlog->start_entry(le);
184
94b18763
FG
185 auto &pi = in->project_inode();
186 pi.inode.size = 0;
187 pi.inode.max_size_ever = 0;
94b18763
FG
188 pi.inode.truncate_size = 0;
189 pi.inode.truncate_from = 0;
190 pi.inode.version = in->pre_dirty();
f91f0fd5
TL
191 pi.inode.client_ranges.clear();
192 in->clear_clientwriteable();
7c673cae
FG
193
194 le->metablob.add_dir_context(dn->dir);
195 le->metablob.add_primary_dentry(dn, in, true);
196
197 mds->mdlog->submit_entry(le,
198 new C_TruncateStrayLogged(
199 this, dn, mds->mdlog->get_current_segment()));
200 } else {
201 if (in->get_num_ref() != (int)in->is_dirty() ||
202 dn->get_num_ref() != (int)dn->is_dirty() + !!in->get_num_ref() + 1/*PIN_PURGING*/) {
203 // Nobody should be taking new references to an inode when it
204 // is being purged (aside from it were
205
206 derr << "Rogue reference after purge to " << *dn << dendl;
11fdf7f2 207 ceph_abort_msg("rogue reference to purging inode");
7c673cae
FG
208 }
209
210 // kill dentry.
211 version_t pdv = dn->pre_dirty();
212 dn->push_projected_linkage(); // NULL
213
214 EUpdate *le = new EUpdate(mds->mdlog, "purge_stray");
215 mds->mdlog->start_entry(le);
216
217 // update dirfrag fragstat, rstat
218 CDir *dir = dn->get_dir();
219 fnode_t *pf = dir->project_fnode();
220 pf->version = dir->pre_dirty();
221 if (in->is_dir())
222 pf->fragstat.nsubdirs--;
223 else
224 pf->fragstat.nfiles--;
225 pf->rstat.sub(in->inode.accounted_rstat);
226
227 le->metablob.add_dir_context(dn->dir);
228 EMetaBlob::dirlump& dl = le->metablob.add_dir(dn->dir, true);
229 le->metablob.add_null_dentry(dl, dn, true);
230 le->metablob.add_destroyed_inode(in->ino());
231
232 mds->mdlog->submit_entry(le, new C_PurgeStrayLogged(this, dn, pdv,
233 mds->mdlog->get_current_segment()));
7c673cae
FG
234 }
235}
236
237void StrayManager::_purge_stray_logged(CDentry *dn, version_t pdv, LogSegment *ls)
238{
239 CInode *in = dn->get_linkage()->get_inode();
240 dout(10) << "_purge_stray_logged " << *dn << " " << *in << dendl;
241
11fdf7f2 242 ceph_assert(!in->state_test(CInode::STATE_RECOVERING));
7c673cae 243
31f18b77
FG
244 bool new_dn = dn->is_new();
245
7c673cae 246 // unlink
11fdf7f2 247 ceph_assert(dn->get_projected_linkage()->is_null());
31f18b77 248 dn->dir->unlink_inode(dn, !new_dn);
7c673cae
FG
249 dn->pop_projected_linkage();
250 dn->mark_dirty(pdv, ls);
251
252 dn->dir->pop_and_dirty_projected_fnode(ls);
253
254 in->state_clear(CInode::STATE_ORPHAN);
255 dn->state_clear(CDentry::STATE_PURGING | CDentry::STATE_PURGINGPINNED);
256 dn->put(CDentry::PIN_PURGING);
257
258 // drop dentry?
31f18b77 259 if (new_dn) {
7c673cae
FG
260 dout(20) << " dn is new, removing" << dendl;
261 dn->mark_clean();
262 dn->dir->remove_dentry(dn);
7c673cae
FG
263 }
264
265 // drop inode
f64942e4 266 inodeno_t ino = in->ino();
7c673cae
FG
267 if (in->is_dirty())
268 in->mark_clean();
f64942e4
AA
269 mds->mdcache->remove_inode(in);
270
271 if (mds->is_stopping())
272 mds->mdcache->shutdown_export_stray_finish(ino);
7c673cae
FG
273}
274
275void StrayManager::enqueue(CDentry *dn, bool trunc)
276{
277 CDentry::linkage_t *dnl = dn->get_projected_linkage();
11fdf7f2 278 ceph_assert(dnl);
7c673cae 279 CInode *in = dnl->get_inode();
11fdf7f2 280 ceph_assert(in);
7c673cae
FG
281
282 /* We consider a stray to be purging as soon as it is enqueued, to avoid
283 * enqueing it twice */
284 dn->state_set(CDentry::STATE_PURGING);
285 in->state_set(CInode::STATE_PURGING);
286
287 /* We must clear this as soon as enqueuing it, to prevent the journal
288 * expiry code from seeing a dirty parent and trying to write a backtrace */
289 if (!trunc) {
290 if (in->is_dirty_parent()) {
291 in->clear_dirty_parent();
292 }
293 }
294
295 dout(20) << __func__ << ": purging dn: " << *dn << dendl;
296
297 if (!dn->state_test(CDentry::STATE_PURGINGPINNED)) {
298 dn->get(CDentry::PIN_PURGING);
299 dn->state_set(CDentry::STATE_PURGINGPINNED);
300 }
301
302 ++num_strays_enqueuing;
303 logger->set(l_mdc_num_strays_enqueuing, num_strays_enqueuing);
304
305 // Resources are available, acquire them and execute the purge
306 _enqueue(dn, trunc);
307
308 dout(10) << __func__ << ": purging this dentry immediately: "
309 << *dn << dendl;
310}
311
312class C_OpenSnapParents : public StrayManagerContext {
313 CDentry *dn;
314 bool trunc;
315 public:
316 C_OpenSnapParents(StrayManager *sm_, CDentry *dn_, bool t) :
317 StrayManagerContext(sm_), dn(dn_), trunc(t) { }
318 void finish(int r) override {
319 sm->_enqueue(dn, trunc);
320 }
321};
322
323void StrayManager::_enqueue(CDentry *dn, bool trunc)
324{
11fdf7f2 325 ceph_assert(started);
c07f9fc5 326
7c673cae
FG
327 CInode *in = dn->get_linkage()->get_inode();
328 if (in->snaprealm &&
329 !in->snaprealm->have_past_parents_open() &&
330 !in->snaprealm->open_parents(new C_OpenSnapParents(this, dn, trunc))) {
331 // this can happen if the dentry had been trimmed from cache.
332 return;
333 }
334
7c673cae
FG
335 if (trunc) {
336 truncate(dn);
337 } else {
338 purge(dn);
339 }
340}
341
11fdf7f2
TL
342void StrayManager::queue_delayed(CDentry *dn)
343{
344 if (!started)
345 return;
346
347 if (dn->state_test(CDentry::STATE_EVALUATINGSTRAY))
348 return;
349
350 if (!dn->item_stray.is_on_list()) {
351 delayed_eval_stray.push_back(&dn->item_stray);
352 num_strays_delayed++;
353 logger->set(l_mdc_num_strays_delayed, num_strays_delayed);
354 }
355}
7c673cae
FG
356
357void StrayManager::advance_delayed()
358{
c07f9fc5
FG
359 if (!started)
360 return;
361
11fdf7f2
TL
362 while (!delayed_eval_stray.empty()) {
363 CDentry *dn = delayed_eval_stray.front();
7c673cae
FG
364 dn->item_stray.remove_myself();
365 num_strays_delayed--;
366
367 if (dn->get_projected_linkage()->is_null()) {
368 /* A special case: a stray dentry can go null if its inode is being
369 * re-linked into another MDS's stray dir during a shutdown migration. */
370 dout(4) << __func__ << ": delayed dentry is now null: " << *dn << dendl;
371 continue;
372 }
373
81eedcae 374 eval_stray(dn);
7c673cae
FG
375 }
376 logger->set(l_mdc_num_strays_delayed, num_strays_delayed);
377}
378
379void StrayManager::set_num_strays(uint64_t num)
380{
11fdf7f2 381 ceph_assert(!started);
7c673cae
FG
382 num_strays = num;
383 logger->set(l_mdc_num_strays, num_strays);
384}
385
386void StrayManager::notify_stray_created()
387{
388 num_strays++;
389 logger->set(l_mdc_num_strays, num_strays);
390 logger->inc(l_mdc_strays_created);
391}
392
393void StrayManager::notify_stray_removed()
394{
395 num_strays--;
396 logger->set(l_mdc_num_strays, num_strays);
397}
398
399struct C_EvalStray : public StrayManagerContext {
400 CDentry *dn;
401 C_EvalStray(StrayManager *sm_, CDentry *d) : StrayManagerContext(sm_), dn(d) {}
402 void finish(int r) override {
403 sm->eval_stray(dn);
404 }
405};
406
407struct C_MDC_EvalStray : public StrayManagerContext {
408 CDentry *dn;
409 C_MDC_EvalStray(StrayManager *sm_, CDentry *d) : StrayManagerContext(sm_), dn(d) {}
410 void finish(int r) override {
411 sm->eval_stray(dn);
412 }
413};
414
11fdf7f2 415bool StrayManager::_eval_stray(CDentry *dn)
7c673cae
FG
416{
417 dout(10) << "eval_stray " << *dn << dendl;
418 CDentry::linkage_t *dnl = dn->get_projected_linkage();
11fdf7f2 419 ceph_assert(dnl->is_primary());
7c673cae
FG
420 dout(10) << " inode is " << *dnl->get_inode() << dendl;
421 CInode *in = dnl->get_inode();
11fdf7f2
TL
422 ceph_assert(in);
423 ceph_assert(!in->state_test(CInode::STATE_REJOINUNDEF));
7c673cae
FG
424
425 // The only dentries elegible for purging are those
426 // in the stray directories
11fdf7f2 427 ceph_assert(dn->get_dir()->get_inode()->is_stray());
7c673cae
FG
428
429 // Inode may not pass through this function if it
430 // was already identified for purging (i.e. cannot
431 // call eval_stray() after purge()
11fdf7f2 432 ceph_assert(!dn->state_test(CDentry::STATE_PURGING));
7c673cae 433
11fdf7f2 434 if (!dn->is_auth())
7c673cae 435 return false;
7c673cae 436
c07f9fc5 437 if (!started)
11fdf7f2 438 return false;
c07f9fc5 439
7c673cae 440 if (dn->item_stray.is_on_list()) {
7c673cae
FG
441 dn->item_stray.remove_myself();
442 num_strays_delayed--;
443 logger->set(l_mdc_num_strays_delayed, num_strays_delayed);
444 }
445
446 // purge?
447 if (in->inode.nlink == 0) {
448 // past snaprealm parents imply snapped dentry remote links.
449 // only important for directories. normal file data snaps are handled
450 // by the object store.
451 if (in->snaprealm) {
452 if (!in->snaprealm->have_past_parents_open() &&
453 !in->snaprealm->open_parents(new C_MDC_EvalStray(this, dn))) {
454 return false;
455 }
456 in->snaprealm->prune_past_parents();
457 in->purge_stale_snap_data(in->snaprealm->get_snaps());
458 }
459 if (in->is_dir()) {
460 if (in->snaprealm && in->snaprealm->has_past_parents()) {
461 dout(20) << " directory has past parents "
11fdf7f2 462 << in->snaprealm << dendl;
7c673cae
FG
463 if (in->state_test(CInode::STATE_MISSINGOBJS)) {
464 mds->clog->error() << "previous attempt at committing dirfrag of ino "
465 << in->ino() << " has failed, missing object";
466 mds->handle_write_error(-ENOENT);
467 }
468 return false; // not until some snaps are deleted.
469 }
470
f64942e4 471 mds->mdcache->clear_dirty_bits_for_stray(in);
7c673cae
FG
472
473 if (!in->remote_parents.empty()) {
474 // unlink any stale remote snap dentry.
94b18763
FG
475 for (auto it = in->remote_parents.begin(); it != in->remote_parents.end(); ) {
476 CDentry *remote_dn = *it;
477 ++it;
11fdf7f2 478 ceph_assert(remote_dn->last != CEPH_NOSNAP);
7c673cae
FG
479 remote_dn->unlink_remote(remote_dn->get_linkage());
480 }
481 }
482 }
483 if (dn->is_replicated()) {
484 dout(20) << " replicated" << dendl;
485 return false;
486 }
487 if (dn->is_any_leases() || in->is_any_caps()) {
488 dout(20) << " caps | leases" << dendl;
489 return false; // wait
490 }
491 if (in->state_test(CInode::STATE_NEEDSRECOVER) ||
492 in->state_test(CInode::STATE_RECOVERING)) {
493 dout(20) << " pending recovery" << dendl;
494 return false; // don't mess with file size probing
495 }
496 if (in->get_num_ref() > (int)in->is_dirty() + (int)in->is_dirty_parent()) {
497 dout(20) << " too many inode refs" << dendl;
498 return false;
499 }
500 if (dn->get_num_ref() > (int)dn->is_dirty() + !!in->get_num_ref()) {
501 dout(20) << " too many dn refs" << dendl;
502 return false;
503 }
7c673cae 504 // don't purge multiversion inode with snap data
11fdf7f2 505 if (in->snaprealm && in->snaprealm->has_past_parents() &&
7c673cae
FG
506 !in->old_inodes.empty()) {
507 // A file with snapshots: we will truncate the HEAD revision
508 // but leave the metadata intact.
11fdf7f2 509 ceph_assert(!in->is_dir());
7c673cae 510 dout(20) << " file has past parents "
11fdf7f2 511 << in->snaprealm << dendl;
7c673cae
FG
512 if (in->is_file() && in->get_projected_inode()->size > 0) {
513 enqueue(dn, true); // truncate head objects
514 }
515 } else {
516 // A straightforward file, ready to be purged. Enqueue it.
517 if (in->is_dir()) {
518 in->close_dirfrags();
519 }
520
521 enqueue(dn, false);
522 }
523
524 return true;
525 } else {
526 /*
527 * Where a stray has some links, they should be remotes, check
528 * if we can do anything with them if we happen to have them in
529 * cache.
530 */
31f18b77 531 _eval_stray_remote(dn, NULL);
7c673cae
FG
532 return false;
533 }
534}
535
536void StrayManager::activate()
537{
538 dout(10) << __func__ << dendl;
539 started = true;
c07f9fc5 540 purge_queue.activate();
7c673cae
FG
541}
542
11fdf7f2 543bool StrayManager::eval_stray(CDentry *dn)
7c673cae
FG
544{
545 // avoid nested eval_stray
546 if (dn->state_test(CDentry::STATE_EVALUATINGSTRAY))
547 return false;
548
549 dn->state_set(CDentry::STATE_EVALUATINGSTRAY);
11fdf7f2 550 bool ret = _eval_stray(dn);
7c673cae
FG
551 dn->state_clear(CDentry::STATE_EVALUATINGSTRAY);
552 return ret;
553}
554
31f18b77 555void StrayManager::eval_remote(CDentry *remote_dn)
7c673cae 556{
31f18b77
FG
557 dout(10) << __func__ << " " << *remote_dn << dendl;
558
559 CDentry::linkage_t *dnl = remote_dn->get_projected_linkage();
11fdf7f2 560 ceph_assert(dnl->is_remote());
31f18b77
FG
561 CInode *in = dnl->get_inode();
562
563 if (!in) {
564 dout(20) << __func__ << ": no inode, cannot evaluate" << dendl;
565 return;
566 }
567
568 if (remote_dn->last != CEPH_NOSNAP) {
569 dout(20) << __func__ << ": snap dentry, cannot evaluate" << dendl;
570 return;
571 }
572
573 // refers to stray?
574 CDentry *primary_dn = in->get_projected_parent_dn();
11fdf7f2 575 ceph_assert(primary_dn != NULL);
31f18b77
FG
576 if (primary_dn->get_dir()->get_inode()->is_stray()) {
577 _eval_stray_remote(primary_dn, remote_dn);
578 } else {
579 dout(20) << __func__ << ": inode's primary dn not stray" << dendl;
580 }
581}
582
583class C_RetryEvalRemote : public StrayManagerContext {
584 CDentry *dn;
585 public:
586 C_RetryEvalRemote(StrayManager *sm_, CDentry *dn_) :
587 StrayManagerContext(sm_), dn(dn_) {
588 dn->get(CDentry::PIN_PTRWAITER);
589 }
590 void finish(int r) override {
591 if (dn->get_projected_linkage()->is_remote())
592 sm->eval_remote(dn);
593 dn->put(CDentry::PIN_PTRWAITER);
594 }
595};
596
597void StrayManager::_eval_stray_remote(CDentry *stray_dn, CDentry *remote_dn)
598{
599 dout(20) << __func__ << " " << *stray_dn << dendl;
11fdf7f2
TL
600 ceph_assert(stray_dn != NULL);
601 ceph_assert(stray_dn->get_dir()->get_inode()->is_stray());
7c673cae 602 CDentry::linkage_t *stray_dnl = stray_dn->get_projected_linkage();
11fdf7f2 603 ceph_assert(stray_dnl->is_primary());
7c673cae 604 CInode *stray_in = stray_dnl->get_inode();
11fdf7f2
TL
605 ceph_assert(stray_in->inode.nlink >= 1);
606 ceph_assert(stray_in->last == CEPH_NOSNAP);
7c673cae
FG
607
608 /* If no remote_dn hinted, pick one arbitrarily */
609 if (remote_dn == NULL) {
610 if (!stray_in->remote_parents.empty()) {
94b18763
FG
611 for (const auto &dn : stray_in->remote_parents) {
612 if (dn->last == CEPH_NOSNAP && !dn->is_projected()) {
613 if (dn->is_auth()) {
614 remote_dn = dn;
31f18b77
FG
615 if (remote_dn->dir->can_auth_pin())
616 break;
617 } else if (!remote_dn) {
94b18763 618 remote_dn = dn;
31f18b77 619 }
7c673cae 620 }
94b18763 621 }
7c673cae
FG
622 }
623 if (!remote_dn) {
624 dout(20) << __func__ << ": not reintegrating (no remote parents in cache)" << dendl;
625 return;
626 }
627 }
11fdf7f2 628 ceph_assert(remote_dn->last == CEPH_NOSNAP);
7c673cae
FG
629 // NOTE: we repeat this check in _rename(), since our submission path is racey.
630 if (!remote_dn->is_projected()) {
31f18b77
FG
631 if (remote_dn->is_auth()) {
632 if (remote_dn->dir->can_auth_pin()) {
633 reintegrate_stray(stray_dn, remote_dn);
634 } else {
635 remote_dn->dir->add_waiter(CDir::WAIT_UNFREEZE, new C_RetryEvalRemote(this, remote_dn));
636 dout(20) << __func__ << ": not reintegrating (can't authpin remote parent)" << dendl;
637 }
638
7c673cae
FG
639 } else if (!remote_dn->is_auth() && stray_dn->is_auth()) {
640 migrate_stray(stray_dn, remote_dn->authority().first);
641 } else {
642 dout(20) << __func__ << ": not reintegrating" << dendl;
643 }
644 } else {
645 // don't do anything if the remote parent is projected, or we may
646 // break user-visible semantics!
647 dout(20) << __func__ << ": not reintegrating (projected)" << dendl;
648 }
649}
650
651void StrayManager::reintegrate_stray(CDentry *straydn, CDentry *rdn)
652{
9f95a23c 653 dout(10) << __func__ << " " << *straydn << " to " << *rdn << dendl;
7c673cae
FG
654
655 logger->inc(l_mdc_strays_reintegrated);
656
9f95a23c
TL
657 // rename it to remote linkage .
658 filepath src(straydn->get_name(), straydn->get_dir()->ino());
659 filepath dst(rdn->get_name(), rdn->get_dir()->ino());
7c673cae 660
9f95a23c 661 auto req = make_message<MClientRequest>(CEPH_MDS_OP_RENAME);
7c673cae
FG
662 req->set_filepath(dst);
663 req->set_filepath2(src);
664 req->set_tid(mds->issue_tid());
665
666 mds->send_message_mds(req, rdn->authority().first);
667}
668
669void StrayManager::migrate_stray(CDentry *dn, mds_rank_t to)
670{
9f95a23c 671 dout(10) << __func__ << " " << *dn << " to mds." << to << dendl;
7c673cae
FG
672
673 logger->inc(l_mdc_strays_migrated);
674
675 // rename it to another mds.
9f95a23c
TL
676 inodeno_t dirino = dn->get_dir()->ino();
677 ceph_assert(MDS_INO_IS_STRAY(dirino));
7c673cae 678
9f95a23c
TL
679 filepath src(dn->get_name(), dirino);
680 filepath dst(dn->get_name(), MDS_INO_STRAY(to, MDS_INO_STRAY_INDEX(dirino)));
7c673cae 681
9f95a23c 682 auto req = make_message<MClientRequest>(CEPH_MDS_OP_RENAME);
7c673cae
FG
683 req->set_filepath(dst);
684 req->set_filepath2(src);
685 req->set_tid(mds->issue_tid());
686
687 mds->send_message_mds(req, to);
688}
689
690StrayManager::StrayManager(MDSRank *mds, PurgeQueue &purge_queue_)
691 : delayed_eval_stray(member_offset(CDentry, item_stray)),
9f95a23c 692 mds(mds), purge_queue(purge_queue_)
7c673cae 693{
11fdf7f2 694 ceph_assert(mds != NULL);
7c673cae
FG
695}
696
697void StrayManager::truncate(CDentry *dn)
698{
699 const CDentry::linkage_t *dnl = dn->get_projected_linkage();
700 const CInode *in = dnl->get_inode();
11fdf7f2 701 ceph_assert(in);
7c673cae 702 dout(10) << __func__ << ": " << *dn << " " << *in << dendl;
11fdf7f2 703 ceph_assert(!dn->is_replicated());
7c673cae
FG
704
705 const SnapRealm *realm = in->find_snaprealm();
11fdf7f2 706 ceph_assert(realm);
7c673cae
FG
707 dout(10) << " realm " << *realm << dendl;
708 const SnapContext *snapc = &realm->get_snap_context();
709
710 uint64_t to = in->inode.get_max_size();
11fdf7f2 711 to = std::max(in->inode.size, to);
7c673cae
FG
712 // when truncating a file, the filer does not delete stripe objects that are
713 // truncated to zero. so we need to purge stripe objects up to the max size
714 // the file has ever been.
11fdf7f2 715 to = std::max(in->inode.max_size_ever, to);
7c673cae 716
11fdf7f2 717 ceph_assert(to > 0);
7c673cae
FG
718
719 PurgeItem item;
b32b8144 720 item.action = PurgeItem::TRUNCATE_FILE;
7c673cae
FG
721 item.ino = in->inode.ino;
722 item.layout = in->inode.layout;
723 item.snapc = *snapc;
724 item.size = to;
11fdf7f2 725 item.stamp = ceph_clock_now();
7c673cae
FG
726
727 purge_queue.push(item, new C_IO_PurgeStrayPurged(
728 this, dn, true));
729}
730
731void StrayManager::_truncate_stray_logged(CDentry *dn, LogSegment *ls)
732{
733 CInode *in = dn->get_projected_linkage()->get_inode();
734
735 dout(10) << __func__ << ": " << *dn << " " << *in << dendl;
736
f64942e4
AA
737 in->pop_and_dirty_projected_inode(ls);
738
739 in->state_clear(CInode::STATE_PURGING);
7c673cae
FG
740 dn->state_clear(CDentry::STATE_PURGING | CDentry::STATE_PURGINGPINNED);
741 dn->put(CDentry::PIN_PURGING);
742
7c673cae 743 eval_stray(dn);
f64942e4
AA
744
745 if (!dn->state_test(CDentry::STATE_PURGING) && mds->is_stopping())
746 mds->mdcache->shutdown_export_stray_finish(in->ino());
7c673cae
FG
747}
748