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