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