]> git.proxmox.com Git - ceph.git/blob - ceph/src/mds/CDentry.cc
update source to Ceph Pacific 16.2.2
[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
21 #include "MDSRank.h"
22 #include "MDCache.h"
23 #include "Locker.h"
24 #include "LogSegment.h"
25
26 #include "messages/MLock.h"
27
28 #define dout_context g_ceph_context
29 #define dout_subsys ceph_subsys_mds
30 #undef dout_prefix
31 #define dout_prefix *_dout << "mds." << dir->mdcache->mds->get_nodeid() << ".cache.den(" << dir->dirfrag() << " " << name << ") "
32
33
34 ostream& CDentry::print_db_line_prefix(ostream& out)
35 {
36 return out << ceph_clock_now() << " mds." << dir->mdcache->mds->get_nodeid() << ".cache.den(" << dir->ino() << " " << name << ") ";
37 }
38
39 LockType CDentry::lock_type(CEPH_LOCK_DN);
40 LockType CDentry::versionlock_type(CEPH_LOCK_DVERSION);
41
42
43 // CDentry
44
45 ostream& operator<<(ostream& out, const CDentry& dn)
46 {
47 filepath path;
48 dn.make_path(path);
49
50 out << "[dentry " << path;
51
52 if (true || dn.first != 0 || dn.last != CEPH_NOSNAP) {
53 out << " [" << dn.first << ",";
54 if (dn.last == CEPH_NOSNAP)
55 out << "head";
56 else
57 out << dn.last;
58 out << ']';
59 }
60
61 if (dn.is_auth()) {
62 out << " auth";
63 if (dn.is_replicated())
64 out << dn.get_replicas();
65 } else {
66 out << " rep@" << dn.authority();
67 out << "." << dn.get_replica_nonce();
68 }
69
70 if (dn.get_linkage()->is_null()) out << " NULL";
71 if (dn.get_linkage()->is_remote()) {
72 out << " REMOTE(";
73 out << dn.get_linkage()->get_remote_d_type_string();
74 out << ")";
75 }
76
77 if (!dn.lock.is_sync_and_unlocked())
78 out << " " << dn.lock;
79 if (!dn.versionlock.is_sync_and_unlocked())
80 out << " " << dn.versionlock;
81
82 if (dn.get_projected_version() != dn.get_version())
83 out << " pv=" << dn.get_projected_version();
84 out << " v=" << dn.get_version();
85
86 if (dn.get_num_auth_pins()) {
87 out << " ap=" << dn.get_num_auth_pins();
88 #ifdef MDS_AUTHPIN_SET
89 dn.print_authpin_set(out);
90 #endif
91 }
92
93 {
94 const CInode *inode = dn.get_linkage()->get_inode();
95 out << " ino=";
96 if (inode) {
97 out << inode->ino();
98 } else {
99 out << "(nil)";
100 }
101 }
102
103 out << " state=" << dn.get_state();
104 if (dn.is_new()) out << "|new";
105 if (dn.state_test(CDentry::STATE_BOTTOMLRU)) out << "|bottomlru";
106
107 if (dn.get_num_ref()) {
108 out << " |";
109 dn.print_pin_set(out);
110 }
111
112 if (dn.get_alternate_name().size()) {
113 out << " altname=" << binstrprint(dn.get_alternate_name(), 16);
114 }
115
116 out << " " << &dn;
117 out << "]";
118 return out;
119 }
120
121
122 bool operator<(const CDentry& l, const CDentry& r)
123 {
124 if ((l.get_dir()->ino() < r.get_dir()->ino()) ||
125 (l.get_dir()->ino() == r.get_dir()->ino() &&
126 (l.get_name() < r.get_name() ||
127 (l.get_name() == r.get_name() && l.last < r.last))))
128 return true;
129 return false;
130 }
131
132
133 void CDentry::print(ostream& out)
134 {
135 out << *this;
136 }
137
138
139 /*
140 inodeno_t CDentry::get_ino()
141 {
142 if (get_inode())
143 return get_inode()->ino();
144 return inodeno_t();
145 }
146 */
147
148 mds_authority_t CDentry::authority() const
149 {
150 return dir->authority();
151 }
152
153
154 void CDentry::add_waiter(uint64_t tag, MDSContext *c)
155 {
156 // wait on the directory?
157 if (tag & (WAIT_UNFREEZE|WAIT_SINGLEAUTH)) {
158 dir->add_waiter(tag, c);
159 return;
160 }
161 MDSCacheObject::add_waiter(tag, c);
162 }
163
164
165 version_t CDentry::pre_dirty(version_t min)
166 {
167 projected_version = dir->pre_dirty(min);
168 dout(10) << __func__ << " " << *this << dendl;
169 return projected_version;
170 }
171
172
173 void CDentry::_mark_dirty(LogSegment *ls)
174 {
175 // state+pin
176 if (!state_test(STATE_DIRTY)) {
177 state_set(STATE_DIRTY);
178 get(PIN_DIRTY);
179 dir->inc_num_dirty();
180 dir->dirty_dentries.push_back(&item_dir_dirty);
181 ceph_assert(ls);
182 }
183 if (ls)
184 ls->dirty_dentries.push_back(&item_dirty);
185 }
186
187 void CDentry::mark_dirty(version_t pv, LogSegment *ls)
188 {
189 dout(10) << __func__ << " " << *this << dendl;
190
191 // i now live in this new dir version
192 ceph_assert(pv <= projected_version);
193 version = pv;
194 _mark_dirty(ls);
195
196 // mark dir too
197 dir->mark_dirty(ls, pv);
198 }
199
200
201 void CDentry::mark_clean()
202 {
203 dout(10) << __func__ << " " << *this << dendl;
204 ceph_assert(is_dirty());
205
206 // not always true for recalc_auth_bits during resolve finish
207 //assert(dir->get_version() == 0 || version <= dir->get_version()); // hmm?
208
209 state_clear(STATE_DIRTY|STATE_NEW);
210 dir->dec_num_dirty();
211
212 item_dir_dirty.remove_myself();
213 item_dirty.remove_myself();
214
215 put(PIN_DIRTY);
216 }
217
218 void CDentry::mark_new()
219 {
220 dout(10) << __func__ << " " << *this << dendl;
221 state_set(STATE_NEW);
222 }
223
224 void CDentry::make_path_string(string& s, bool projected) const
225 {
226 if (dir) {
227 dir->inode->make_path_string(s, projected);
228 } else {
229 s = "???";
230 }
231 s += "/";
232 s.append(name.data(), name.length());
233 }
234
235 void CDentry::make_path(filepath& fp, bool projected) const
236 {
237 ceph_assert(dir);
238 dir->inode->make_path(fp, projected);
239 fp.push_dentry(get_name());
240 }
241
242 /*
243 * we only add ourselves to remote_parents when the linkage is
244 * active (no longer projected). if the passed dnl is projected,
245 * don't link in, and do that work later in pop_projected_linkage().
246 */
247 void CDentry::link_remote(CDentry::linkage_t *dnl, CInode *in)
248 {
249 ceph_assert(dnl->is_remote());
250 ceph_assert(in->ino() == dnl->get_remote_ino());
251 dnl->inode = in;
252
253 if (dnl == &linkage)
254 in->add_remote_parent(this);
255 }
256
257 void CDentry::unlink_remote(CDentry::linkage_t *dnl)
258 {
259 ceph_assert(dnl->is_remote());
260 ceph_assert(dnl->inode);
261
262 if (dnl == &linkage)
263 dnl->inode->remove_remote_parent(this);
264
265 dnl->inode = 0;
266 }
267
268 void CDentry::push_projected_linkage()
269 {
270 _project_linkage();
271
272 if (is_auth()) {
273 CInode *diri = dir->inode;
274 if (diri->is_stray())
275 diri->mdcache->notify_stray_removed();
276 }
277 }
278
279
280 void CDentry::push_projected_linkage(CInode *inode)
281 {
282 // dirty rstat tracking is in the projected plane
283 bool dirty_rstat = inode->is_dirty_rstat();
284 if (dirty_rstat)
285 inode->clear_dirty_rstat();
286
287 _project_linkage()->inode = inode;
288 inode->push_projected_parent(this);
289
290 if (dirty_rstat)
291 inode->mark_dirty_rstat();
292
293 if (is_auth()) {
294 CInode *diri = dir->inode;
295 if (diri->is_stray())
296 diri->mdcache->notify_stray_created();
297 }
298 }
299
300 CDentry::linkage_t *CDentry::pop_projected_linkage()
301 {
302 ceph_assert(projected.size());
303
304 linkage_t& n = projected.front();
305
306 /*
307 * the idea here is that the link_remote_inode(), link_primary_inode(),
308 * etc. calls should make linkage identical to &n (and we assert as
309 * much).
310 */
311
312 if (n.remote_ino) {
313 dir->link_remote_inode(this, n.remote_ino, n.remote_d_type);
314 if (n.inode) {
315 linkage.inode = n.inode;
316 linkage.inode->add_remote_parent(this);
317 }
318 } else {
319 if (n.inode) {
320 dir->link_primary_inode(this, n.inode);
321 n.inode->pop_projected_parent();
322 }
323 }
324
325 ceph_assert(n.inode == linkage.inode);
326 ceph_assert(n.remote_ino == linkage.remote_ino);
327 ceph_assert(n.remote_d_type == linkage.remote_d_type);
328
329 projected.pop_front();
330
331 return &linkage;
332 }
333
334
335
336 // ----------------------------
337 // auth pins
338
339 int CDentry::get_num_dir_auth_pins() const
340 {
341 ceph_assert(!is_projected());
342 if (get_linkage()->is_primary())
343 return auth_pins + get_linkage()->get_inode()->get_num_auth_pins();
344 return auth_pins;
345 }
346
347 bool CDentry::can_auth_pin(int *err_ret) const
348 {
349 ceph_assert(dir);
350 return dir->can_auth_pin(err_ret);
351 }
352
353 void CDentry::auth_pin(void *by)
354 {
355 if (auth_pins == 0)
356 get(PIN_AUTHPIN);
357 auth_pins++;
358
359 #ifdef MDS_AUTHPIN_SET
360 auth_pin_set.insert(by);
361 #endif
362
363 dout(10) << "auth_pin by " << by << " on " << *this << " now " << auth_pins << dendl;
364
365 dir->adjust_nested_auth_pins(1, by);
366 }
367
368 void CDentry::auth_unpin(void *by)
369 {
370 auth_pins--;
371
372 #ifdef MDS_AUTHPIN_SET
373 {
374 auto it = auth_pin_set.find(by);
375 ceph_assert(it != auth_pin_set.end());
376 auth_pin_set.erase(it);
377 }
378 #endif
379
380 if (auth_pins == 0)
381 put(PIN_AUTHPIN);
382
383 dout(10) << "auth_unpin by " << by << " on " << *this << " now " << auth_pins << dendl;
384 ceph_assert(auth_pins >= 0);
385
386 dir->adjust_nested_auth_pins(-1, by);
387 }
388
389 void CDentry::adjust_nested_auth_pins(int diradj, void *by)
390 {
391 dir->adjust_nested_auth_pins(diradj, by);
392 }
393
394 bool CDentry::is_frozen() const
395 {
396 return dir->is_frozen();
397 }
398
399 bool CDentry::is_freezing() const
400 {
401 return dir->is_freezing();
402 }
403
404 // ----------------------------
405 // locking
406
407 void CDentry::set_object_info(MDSCacheObjectInfo &info)
408 {
409 info.dirfrag = dir->dirfrag();
410 info.dname = name;
411 info.snapid = last;
412 }
413
414 void CDentry::encode_lock_state(int type, bufferlist& bl)
415 {
416 encode(first, bl);
417
418 // null, ino, or remote_ino?
419 char c;
420 if (linkage.is_primary()) {
421 c = 1;
422 encode(c, bl);
423 encode(linkage.get_inode()->ino(), bl);
424 }
425 else if (linkage.is_remote()) {
426 c = 2;
427 encode(c, bl);
428 encode(linkage.get_remote_ino(), bl);
429 }
430 else if (linkage.is_null()) {
431 // encode nothing.
432 }
433 else ceph_abort();
434 }
435
436 void CDentry::decode_lock_state(int type, const bufferlist& bl)
437 {
438 auto p = bl.cbegin();
439
440 snapid_t newfirst;
441 decode(newfirst, p);
442
443 if (!is_auth() && newfirst != first) {
444 dout(10) << __func__ << " first " << first << " -> " << newfirst << dendl;
445 ceph_assert(newfirst > first);
446 first = newfirst;
447 }
448
449 if (p.end()) {
450 // null
451 ceph_assert(linkage.is_null());
452 return;
453 }
454
455 char c;
456 inodeno_t ino;
457 decode(c, p);
458
459 switch (c) {
460 case 1:
461 case 2:
462 decode(ino, p);
463 // newly linked?
464 if (linkage.is_null() && !is_auth()) {
465 // force trim from cache!
466 dout(10) << __func__ << " replica dentry null -> non-null, must trim" << dendl;
467 //assert(get_num_ref() == 0);
468 } else {
469 // verify?
470
471 }
472 break;
473 default:
474 ceph_abort();
475 }
476 }
477
478
479 ClientLease *CDentry::add_client_lease(client_t c, Session *session)
480 {
481 ClientLease *l;
482 if (client_lease_map.count(c))
483 l = client_lease_map[c];
484 else {
485 dout(20) << __func__ << " client." << c << " on " << lock << dendl;
486 if (client_lease_map.empty()) {
487 get(PIN_CLIENTLEASE);
488 lock.get_client_lease();
489 }
490 l = client_lease_map[c] = new ClientLease(c, this);
491 l->seq = ++session->lease_seq;
492
493 }
494
495 return l;
496 }
497
498 void CDentry::remove_client_lease(ClientLease *l, Locker *locker)
499 {
500 ceph_assert(l->parent == this);
501
502 bool gather = false;
503
504 dout(20) << __func__ << " client." << l->client << " on " << lock << dendl;
505
506 client_lease_map.erase(l->client);
507 l->item_lease.remove_myself();
508 l->item_session_lease.remove_myself();
509 delete l;
510
511 if (client_lease_map.empty()) {
512 gather = !lock.is_stable();
513 lock.put_client_lease();
514 put(PIN_CLIENTLEASE);
515 }
516
517 if (gather)
518 locker->eval_gather(&lock);
519 }
520
521 void CDentry::remove_client_leases(Locker *locker)
522 {
523 while (!client_lease_map.empty())
524 remove_client_lease(client_lease_map.begin()->second, locker);
525 }
526
527 void CDentry::_put()
528 {
529 if (get_num_ref() <= ((int)is_dirty() + 1)) {
530 CDentry::linkage_t *dnl = get_projected_linkage();
531 if (dnl->is_primary()) {
532 CInode *in = dnl->get_inode();
533 if (get_num_ref() == (int)is_dirty() + !!in->get_num_ref())
534 in->mdcache->maybe_eval_stray(in, true);
535 }
536 }
537 }
538
539 void CDentry::encode_remote(inodeno_t& ino, unsigned char d_type,
540 std::string_view alternate_name,
541 bufferlist &bl)
542 {
543 bl.append('l'); // remote link
544
545 // marker, name, ino
546 ENCODE_START(2, 1, bl);
547 encode(ino, bl);
548 encode(d_type, bl);
549 encode(alternate_name, bl);
550 ENCODE_FINISH(bl);
551 }
552
553 void CDentry::decode_remote(char icode, inodeno_t& ino, unsigned char& d_type,
554 mempool::mds_co::string& alternate_name,
555 ceph::buffer::list::const_iterator& bl)
556 {
557 if (icode == 'l') {
558 DECODE_START(2, bl);
559 decode(ino, bl);
560 decode(d_type, bl);
561 if (struct_v >= 2)
562 decode(alternate_name, bl);
563 DECODE_FINISH(bl);
564 } else if (icode == 'L') {
565 decode(ino, bl);
566 decode(d_type, bl);
567 } else ceph_assert(0);
568 }
569
570 void CDentry::dump(Formatter *f) const
571 {
572 ceph_assert(f != NULL);
573
574 filepath path;
575 make_path(path);
576
577 f->dump_string("path", path.get_path());
578 f->dump_unsigned("path_ino", path.get_ino().val);
579 f->dump_unsigned("snap_first", first);
580 f->dump_unsigned("snap_last", last);
581
582 f->dump_bool("is_primary", get_linkage()->is_primary());
583 f->dump_bool("is_remote", get_linkage()->is_remote());
584 f->dump_bool("is_null", get_linkage()->is_null());
585 f->dump_bool("is_new", is_new());
586 if (get_linkage()->get_inode()) {
587 f->dump_unsigned("inode", get_linkage()->get_inode()->ino());
588 } else {
589 f->dump_unsigned("inode", 0);
590 }
591
592 if (linkage.is_remote()) {
593 f->dump_string("remote_type", linkage.get_remote_d_type_string());
594 } else {
595 f->dump_string("remote_type", "");
596 }
597
598 f->dump_unsigned("version", get_version());
599 f->dump_unsigned("projected_version", get_projected_version());
600
601 f->dump_int("auth_pins", auth_pins);
602
603 MDSCacheObject::dump(f);
604
605 f->open_object_section("lock");
606 lock.dump(f);
607 f->close_section();
608
609 f->open_object_section("versionlock");
610 versionlock.dump(f);
611 f->close_section();
612
613 f->open_array_section("states");
614 MDSCacheObject::dump_states(f);
615 if (state_test(STATE_NEW))
616 f->dump_string("state", "new");
617 if (state_test(STATE_FRAGMENTING))
618 f->dump_string("state", "fragmenting");
619 if (state_test(STATE_PURGING))
620 f->dump_string("state", "purging");
621 if (state_test(STATE_BADREMOTEINO))
622 f->dump_string("state", "badremoteino");
623 if (state_test(STATE_STRAY))
624 f->dump_string("state", "stray");
625 f->close_section();
626 }
627
628 std::string CDentry::linkage_t::get_remote_d_type_string() const
629 {
630 switch (DTTOIF(remote_d_type)) {
631 case S_IFSOCK: return "sock";
632 case S_IFLNK: return "lnk";
633 case S_IFREG: return "reg";
634 case S_IFBLK: return "blk";
635 case S_IFDIR: return "dir";
636 case S_IFCHR: return "chr";
637 case S_IFIFO: return "fifo";
638 default: ceph_abort(); return "";
639 }
640 }
641
642 MEMPOOL_DEFINE_OBJECT_FACTORY(CDentry, co_dentry, mds_co);