]> git.proxmox.com Git - ceph.git/blob - ceph/src/mds/CDentry.cc
add stop-gap to fix compat with CPUs not supporting SSE 4.1
[ceph.git] / ceph / src / mds / CDentry.cc
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) 2004-2006 Sage Weil <sage@newdream.net>
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
17 #include "CDentry.h"
18 #include "CInode.h"
19 #include "CDir.h"
20 #include "SnapClient.h"
21
22 #include "MDSRank.h"
23 #include "MDCache.h"
24 #include "Locker.h"
25 #include "LogSegment.h"
26
27 #include "messages/MLock.h"
28
29 #define dout_context g_ceph_context
30 #define dout_subsys ceph_subsys_mds
31 #undef dout_prefix
32 #define dout_prefix *_dout << "mds." << dir->mdcache->mds->get_nodeid() << ".cache.den(" << dir->dirfrag() << " " << name << ") "
33
34 using namespace std;
35
36 ostream& CDentry::print_db_line_prefix(ostream& out)
37 {
38 return out << ceph_clock_now() << " mds." << dir->mdcache->mds->get_nodeid() << ".cache.den(" << dir->ino() << " " << name << ") ";
39 }
40
41 LockType CDentry::lock_type(CEPH_LOCK_DN);
42 LockType CDentry::versionlock_type(CEPH_LOCK_DVERSION);
43
44
45 // CDentry
46
47 ostream& operator<<(ostream& out, const CDentry& dn)
48 {
49 filepath path;
50 dn.make_path(path);
51
52 out << "[dentry " << path;
53
54 if (true || dn.first != 0 || dn.last != CEPH_NOSNAP) {
55 out << " [" << dn.first << ",";
56 if (dn.last == CEPH_NOSNAP)
57 out << "head";
58 else
59 out << dn.last;
60 out << ']';
61 }
62
63 if (dn.is_auth()) {
64 out << " auth";
65 if (dn.is_replicated())
66 out << dn.get_replicas();
67 } else {
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();
73 }
74
75 if (dn.get_linkage()->is_null()) out << " NULL";
76 if (dn.get_linkage()->is_remote()) {
77 out << " REMOTE(";
78 out << dn.get_linkage()->get_remote_d_type_string();
79 out << ")";
80 }
81
82 if (!dn.lock.is_sync_and_unlocked())
83 out << " " << dn.lock;
84 if (!dn.versionlock.is_sync_and_unlocked())
85 out << " " << dn.versionlock;
86
87 if (dn.get_projected_version() != dn.get_version())
88 out << " pv=" << dn.get_projected_version();
89 out << " v=" << dn.get_version();
90
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);
95 #endif
96 }
97
98 {
99 const CInode *inode = dn.get_linkage()->get_inode();
100 out << " ino=";
101 if (inode) {
102 out << inode->ino();
103 } else {
104 out << "(nil)";
105 }
106 }
107
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";
113
114 if (dn.get_num_ref()) {
115 out << " |";
116 dn.print_pin_set(out);
117 }
118
119 if (dn.get_alternate_name().size()) {
120 out << " altname=" << binstrprint(dn.get_alternate_name(), 16);
121 }
122
123 out << " " << &dn;
124 out << "]";
125 return out;
126 }
127
128
129 bool operator<(const CDentry& l, const CDentry& r)
130 {
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))))
135 return true;
136 return false;
137 }
138
139
140 void CDentry::print(ostream& out)
141 {
142 out << *this;
143 }
144
145
146 /*
147 inodeno_t CDentry::get_ino()
148 {
149 if (get_inode())
150 return get_inode()->ino();
151 return inodeno_t();
152 }
153 */
154
155 mds_authority_t CDentry::authority() const
156 {
157 return dir->authority();
158 }
159
160
161 void CDentry::add_waiter(uint64_t tag, MDSContext *c)
162 {
163 // wait on the directory?
164 if (tag & (WAIT_UNFREEZE|WAIT_SINGLEAUTH)) {
165 dir->add_waiter(tag, c);
166 return;
167 }
168 MDSCacheObject::add_waiter(tag, c);
169 }
170
171
172 version_t CDentry::pre_dirty(version_t min)
173 {
174 projected_version = dir->pre_dirty(min);
175 dout(10) << __func__ << " " << *this << dendl;
176 return projected_version;
177 }
178
179
180 void CDentry::_mark_dirty(LogSegment *ls)
181 {
182 // state+pin
183 if (!state_test(STATE_DIRTY)) {
184 state_set(STATE_DIRTY);
185 get(PIN_DIRTY);
186 dir->inc_num_dirty();
187 dir->dirty_dentries.push_back(&item_dir_dirty);
188 ceph_assert(ls);
189 }
190 if (ls)
191 ls->dirty_dentries.push_back(&item_dirty);
192 }
193
194 void CDentry::mark_dirty(version_t pv, LogSegment *ls)
195 {
196 dout(10) << __func__ << " " << *this << dendl;
197
198 // i now live in this new dir version
199 ceph_assert(pv <= projected_version);
200 version = pv;
201 _mark_dirty(ls);
202
203 // mark dir too
204 dir->mark_dirty(ls, pv);
205 }
206
207
208 void CDentry::mark_clean()
209 {
210 dout(10) << __func__ << " " << *this << dendl;
211 ceph_assert(is_dirty());
212
213 // not always true for recalc_auth_bits during resolve finish
214 //assert(dir->get_version() == 0 || version <= dir->get_version()); // hmm?
215
216 state_clear(STATE_DIRTY|STATE_NEW);
217 dir->dec_num_dirty();
218
219 item_dir_dirty.remove_myself();
220 item_dirty.remove_myself();
221
222 put(PIN_DIRTY);
223 }
224
225 void CDentry::mark_new()
226 {
227 dout(10) << __func__ << " " << *this << dendl;
228 state_set(STATE_NEW);
229 }
230
231 void CDentry::mark_auth()
232 {
233 if (!is_auth()) {
234 state_set(STATE_AUTH);
235 dir->adjust_dentry_lru(this);
236 }
237 }
238
239 void CDentry::clear_auth()
240 {
241 if (is_auth()) {
242 state_clear(STATE_AUTH);
243 dir->adjust_dentry_lru(this);
244 }
245 }
246
247 void CDentry::make_path_string(string& s, bool projected) const
248 {
249 if (dir) {
250 dir->inode->make_path_string(s, projected);
251 } else {
252 s = "???";
253 }
254 s += "/";
255 s.append(name.data(), name.length());
256 }
257
258 void CDentry::make_path(filepath& fp, bool projected) const
259 {
260 ceph_assert(dir);
261 dir->inode->make_path(fp, projected);
262 fp.push_dentry(get_name());
263 }
264
265 /*
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().
269 */
270 void CDentry::link_remote(CDentry::linkage_t *dnl, CInode *in)
271 {
272 ceph_assert(dnl->is_remote());
273 ceph_assert(in->ino() == dnl->get_remote_ino());
274 dnl->inode = in;
275
276 if (dnl == &linkage)
277 in->add_remote_parent(this);
278
279 // check for reintegration
280 dir->mdcache->eval_remote(this);
281 }
282
283 void CDentry::unlink_remote(CDentry::linkage_t *dnl)
284 {
285 ceph_assert(dnl->is_remote());
286 ceph_assert(dnl->inode);
287
288 if (dnl == &linkage)
289 dnl->inode->remove_remote_parent(this);
290
291 dnl->inode = 0;
292 }
293
294 void CDentry::push_projected_linkage()
295 {
296 _project_linkage();
297
298 if (is_auth()) {
299 CInode *diri = dir->inode;
300 if (diri->is_stray())
301 diri->mdcache->notify_stray_removed();
302 }
303 }
304
305
306 void CDentry::push_projected_linkage(CInode *inode)
307 {
308 // dirty rstat tracking is in the projected plane
309 bool dirty_rstat = inode->is_dirty_rstat();
310 if (dirty_rstat)
311 inode->clear_dirty_rstat();
312
313 _project_linkage()->inode = inode;
314 inode->push_projected_parent(this);
315
316 if (dirty_rstat)
317 inode->mark_dirty_rstat();
318
319 if (is_auth()) {
320 CInode *diri = dir->inode;
321 if (diri->is_stray())
322 diri->mdcache->notify_stray_created();
323 }
324 }
325
326 CDentry::linkage_t *CDentry::pop_projected_linkage()
327 {
328 ceph_assert(projected.size());
329
330 linkage_t& n = projected.front();
331
332 /*
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
335 * much).
336 */
337
338 if (n.remote_ino) {
339 dir->link_remote_inode(this, n.remote_ino, n.remote_d_type);
340 if (n.inode) {
341 linkage.inode = n.inode;
342 linkage.inode->add_remote_parent(this);
343 }
344 } else {
345 if (n.inode) {
346 dir->link_primary_inode(this, n.inode);
347 n.inode->pop_projected_parent();
348 }
349 }
350
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);
354
355 projected.pop_front();
356
357 return &linkage;
358 }
359
360
361
362 // ----------------------------
363 // auth pins
364
365 int CDentry::get_num_dir_auth_pins() const
366 {
367 ceph_assert(!is_projected());
368 if (get_linkage()->is_primary())
369 return auth_pins + get_linkage()->get_inode()->get_num_auth_pins();
370 return auth_pins;
371 }
372
373 bool CDentry::can_auth_pin(int *err_ret) const
374 {
375 ceph_assert(dir);
376 return dir->can_auth_pin(err_ret);
377 }
378
379 void CDentry::auth_pin(void *by)
380 {
381 if (auth_pins == 0)
382 get(PIN_AUTHPIN);
383 auth_pins++;
384
385 #ifdef MDS_AUTHPIN_SET
386 auth_pin_set.insert(by);
387 #endif
388
389 dout(10) << "auth_pin by " << by << " on " << *this << " now " << auth_pins << dendl;
390
391 dir->adjust_nested_auth_pins(1, by);
392 }
393
394 void CDentry::auth_unpin(void *by)
395 {
396 auth_pins--;
397
398 #ifdef MDS_AUTHPIN_SET
399 {
400 auto it = auth_pin_set.find(by);
401 ceph_assert(it != auth_pin_set.end());
402 auth_pin_set.erase(it);
403 }
404 #endif
405
406 if (auth_pins == 0)
407 put(PIN_AUTHPIN);
408
409 dout(10) << "auth_unpin by " << by << " on " << *this << " now " << auth_pins << dendl;
410 ceph_assert(auth_pins >= 0);
411
412 dir->adjust_nested_auth_pins(-1, by);
413 }
414
415 void CDentry::adjust_nested_auth_pins(int diradj, void *by)
416 {
417 dir->adjust_nested_auth_pins(diradj, by);
418 }
419
420 bool CDentry::is_frozen() const
421 {
422 return dir->is_frozen();
423 }
424
425 bool CDentry::is_freezing() const
426 {
427 return dir->is_freezing();
428 }
429
430 // ----------------------------
431 // locking
432
433 void CDentry::set_object_info(MDSCacheObjectInfo &info)
434 {
435 info.dirfrag = dir->dirfrag();
436 info.dname = name;
437 info.snapid = last;
438 }
439
440 void CDentry::encode_lock_state(int type, bufferlist& bl)
441 {
442 encode(first, bl);
443
444 // null, ino, or remote_ino?
445 char c;
446 if (linkage.is_primary()) {
447 c = 1;
448 encode(c, bl);
449 encode(linkage.get_inode()->ino(), bl);
450 }
451 else if (linkage.is_remote()) {
452 c = 2;
453 encode(c, bl);
454 encode(linkage.get_remote_ino(), bl);
455 }
456 else if (linkage.is_null()) {
457 // encode nothing.
458 }
459 else ceph_abort();
460 }
461
462 void CDentry::decode_lock_state(int type, const bufferlist& bl)
463 {
464 auto p = bl.cbegin();
465
466 snapid_t newfirst;
467 decode(newfirst, p);
468
469 if (!is_auth() && newfirst != first) {
470 dout(10) << __func__ << " first " << first << " -> " << newfirst << dendl;
471 ceph_assert(newfirst > first);
472 first = newfirst;
473 }
474
475 if (p.end()) {
476 // null
477 ceph_assert(linkage.is_null());
478 return;
479 }
480
481 char c;
482 inodeno_t ino;
483 decode(c, p);
484
485 switch (c) {
486 case 1:
487 case 2:
488 decode(ino, p);
489 // newly linked?
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);
494 } else {
495 // verify?
496
497 }
498 break;
499 default:
500 ceph_abort();
501 }
502 }
503
504
505 ClientLease *CDentry::add_client_lease(client_t c, Session *session)
506 {
507 ClientLease *l;
508 if (client_lease_map.count(c))
509 l = client_lease_map[c];
510 else {
511 dout(20) << __func__ << " client." << c << " on " << lock << dendl;
512 if (client_lease_map.empty()) {
513 get(PIN_CLIENTLEASE);
514 lock.get_client_lease();
515 }
516 l = client_lease_map[c] = new ClientLease(c, this);
517 l->seq = ++session->lease_seq;
518
519 }
520
521 return l;
522 }
523
524 void CDentry::remove_client_lease(ClientLease *l, Locker *locker)
525 {
526 ceph_assert(l->parent == this);
527
528 bool gather = false;
529
530 dout(20) << __func__ << " client." << l->client << " on " << lock << dendl;
531
532 client_lease_map.erase(l->client);
533 l->item_lease.remove_myself();
534 l->item_session_lease.remove_myself();
535 delete l;
536
537 if (client_lease_map.empty()) {
538 gather = !lock.is_stable();
539 lock.put_client_lease();
540 put(PIN_CLIENTLEASE);
541 }
542
543 if (gather)
544 locker->eval_gather(&lock);
545 }
546
547 void CDentry::remove_client_leases(Locker *locker)
548 {
549 while (!client_lease_map.empty())
550 remove_client_lease(client_lease_map.begin()->second, locker);
551 }
552
553 void CDentry::_put()
554 {
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);
561 }
562 }
563 }
564
565 void CDentry::encode_remote(inodeno_t& ino, unsigned char d_type,
566 std::string_view alternate_name,
567 bufferlist &bl)
568 {
569 bl.append('l'); // remote link
570
571 // marker, name, ino
572 ENCODE_START(2, 1, bl);
573 encode(ino, bl);
574 encode(d_type, bl);
575 encode(alternate_name, bl);
576 ENCODE_FINISH(bl);
577 }
578
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)
582 {
583 if (icode == 'l') {
584 DECODE_START(2, bl);
585 decode(ino, bl);
586 decode(d_type, bl);
587 if (struct_v >= 2)
588 decode(alternate_name, bl);
589 DECODE_FINISH(bl);
590 } else if (icode == 'L') {
591 decode(ino, bl);
592 decode(d_type, bl);
593 } else ceph_assert(0);
594 }
595
596 void CDentry::dump(Formatter *f) const
597 {
598 ceph_assert(f != NULL);
599
600 filepath path;
601 make_path(path);
602
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);
607
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());
614 } else {
615 f->dump_unsigned("inode", 0);
616 }
617
618 if (linkage.is_remote()) {
619 f->dump_string("remote_type", linkage.get_remote_d_type_string());
620 } else {
621 f->dump_string("remote_type", "");
622 }
623
624 f->dump_unsigned("version", get_version());
625 f->dump_unsigned("projected_version", get_projected_version());
626
627 f->dump_int("auth_pins", auth_pins);
628
629 MDSCacheObject::dump(f);
630
631 f->open_object_section("lock");
632 lock.dump(f);
633 f->close_section();
634
635 f->open_object_section("versionlock");
636 versionlock.dump(f);
637 f->close_section();
638
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");
651 f->close_section();
652 }
653
654 std::string CDentry::linkage_t::get_remote_d_type_string() const
655 {
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 "";
665 }
666 }
667
668 bool CDentry::scrub(snapid_t next_seq)
669 {
670 dout(20) << "scrubbing " << *this << " next_seq = " << next_seq << dendl;
671
672 /* attempt to locate damage in first of CDentry, see:
673 * https://tracker.ceph.com/issues/56140
674 */
675 /* skip projected dentries as first/last may have placeholder values */
676 if (!is_projected()) {
677 CDir* dir = get_dir();
678
679 if (first > next_seq) {
680 derr << __func__ << ": first > next_seq (" << next_seq << ") " << *this << dendl;
681 dir->go_bad_dentry(last, get_name());
682 return true;
683 } else if (first > last) {
684 derr << __func__ << ": first > last " << *this << dendl;
685 dir->go_bad_dentry(last, get_name());
686 return true;
687 }
688
689 auto&& realm = dir->get_inode()->find_snaprealm();
690 if (realm) {
691 auto&& snaps = realm->get_snaps();
692 auto it = snaps.lower_bound(first);
693 bool stale = last != CEPH_NOSNAP && (it == snaps.end() || *it > last);
694 if (stale) {
695 dout(20) << "is stale" << dendl;
696 /* TODO: maybe trim? */
697 }
698 }
699 }
700 return false;
701 }
702
703 bool CDentry::check_corruption(bool load)
704 {
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)) {
708 if (load) {
709 dout(1) << "loaded already corrupt dentry: " << *this << dendl;
710 corrupt_first_loaded = true;
711 } else {
712 derr << "newly corrupt dentry to be committed: " << *this << dendl;
713 }
714 if (g_conf().get_val<bool>("mds_go_bad_corrupt_dentry")) {
715 dir->go_bad_dentry(last, get_name());
716 }
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 */
720 }
721 return true;
722 }
723 return false;
724 }
725
726 MEMPOOL_DEFINE_OBJECT_FACTORY(CDentry, co_dentry, mds_co);