]> git.proxmox.com Git - ceph.git/blame - ceph/src/client/Inode.cc
import quincy beta 17.1.0
[ceph.git] / ceph / src / client / Inode.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#include "Client.h"
5#include "Inode.h"
6#include "Dentry.h"
7#include "Dir.h"
8#include "Fh.h"
9#include "MetaSession.h"
10#include "ClientSnapRealm.h"
b32b8144 11#include "Delegation.h"
7c673cae
FG
12
13#include "mds/flock.h"
14
20effc67
TL
15using std::dec;
16using std::list;
17using std::oct;
18using std::ostream;
19using std::string;
20
7c673cae
FG
21Inode::~Inode()
22{
28e407b8
AA
23 delay_cap_item.remove_myself();
24 dirty_cap_item.remove_myself();
7c673cae
FG
25 snaprealm_item.remove_myself();
26
27 if (snapdir_parent) {
28 snapdir_parent->flags &= ~I_SNAPDIR_OPEN;
29 snapdir_parent.reset();
30 }
31
32 if (!oset.objects.empty()) {
33 lsubdout(client->cct, client, 0) << __func__ << ": leftover objects on inode 0x"
34 << std::hex << ino << std::dec << dendl;
11fdf7f2 35 ceph_assert(oset.objects.empty());
7c673cae
FG
36 }
37
b32b8144
FG
38 if (!delegations.empty()) {
39 lsubdout(client->cct, client, 0) << __func__ << ": leftover delegations on inode 0x"
40 << std::hex << ino << std::dec << dendl;
11fdf7f2 41 ceph_assert(delegations.empty());
b32b8144 42 }
7c673cae
FG
43}
44
45ostream& operator<<(ostream &out, const Inode &in)
46{
47 out << in.vino() << "("
48 << "faked_ino=" << in.faked_ino
b3b6e05e 49 << " nref=" << in.get_nref()
7c673cae
FG
50 << " ll_ref=" << in.ll_ref
51 << " cap_refs=" << in.cap_refs
52 << " open=" << in.open_by_mode
53 << " mode=" << oct << in.mode << dec
54 << " size=" << in.size << "/" << in.max_size
28e407b8 55 << " nlink=" << in.nlink
11fdf7f2 56 << " btime=" << in.btime
7c673cae 57 << " mtime=" << in.mtime
11fdf7f2 58 << " ctime=" << in.ctime
7c673cae
FG
59 << " caps=" << ccap_string(in.caps_issued());
60 if (!in.caps.empty()) {
61 out << "(";
11fdf7f2
TL
62 bool first = true;
63 for (const auto &pair : in.caps) {
64 if (!first)
7c673cae 65 out << ',';
11fdf7f2
TL
66 out << pair.first << '=' << ccap_string(pair.second.issued);
67 first = false;
7c673cae
FG
68 }
69 out << ")";
70 }
71 if (in.dirty_caps)
72 out << " dirty_caps=" << ccap_string(in.dirty_caps);
73 if (in.flushing_caps)
74 out << " flushing_caps=" << ccap_string(in.flushing_caps);
75
76 if (in.flags & I_COMPLETE)
77 out << " COMPLETE";
78
79 if (in.is_file())
80 out << " " << in.oset;
81
11fdf7f2
TL
82 if (!in.dentries.empty())
83 out << " parents=" << in.dentries;
7c673cae
FG
84
85 if (in.is_dir() && in.has_dir_layout())
86 out << " has_dir_layout";
87
88 if (in.quota.is_enable())
89 out << " " << in.quota;
90
91 out << ' ' << &in << ")";
92 return out;
93}
94
95
96void Inode::make_long_path(filepath& p)
97{
11fdf7f2
TL
98 if (!dentries.empty()) {
99 Dentry *dn = get_first_parent();
100 ceph_assert(dn->dir && dn->dir->parent_inode);
101 dn->dir->parent_inode->make_long_path(p);
102 p.push_dentry(dn->name);
7c673cae 103 } else if (snapdir_parent) {
f91f0fd5
TL
104 make_nosnap_relative_path(p);
105 } else
106 p = filepath(ino);
107}
108
109void Inode::make_short_path(filepath& p)
110{
111 if (!dentries.empty()) {
112 Dentry *dn = get_first_parent();
113 ceph_assert(dn->dir && dn->dir->parent_inode);
114 p = filepath(dn->name, dn->dir->parent_inode->ino);
115 } else if (snapdir_parent) {
116 make_nosnap_relative_path(p);
7c673cae
FG
117 } else
118 p = filepath(ino);
119}
120
121/*
122 * make a filepath suitable for an mds request:
123 * - if we are non-snapped/live, the ino is sufficient, e.g. #1234
124 * - if we are snapped, make filepath relative to first non-snapped parent.
125 */
126void Inode::make_nosnap_relative_path(filepath& p)
127{
128 if (snapid == CEPH_NOSNAP) {
129 p = filepath(ino);
130 } else if (snapdir_parent) {
131 snapdir_parent->make_nosnap_relative_path(p);
132 string empty;
133 p.push_dentry(empty);
11fdf7f2
TL
134 } else if (!dentries.empty()) {
135 Dentry *dn = get_first_parent();
136 ceph_assert(dn->dir && dn->dir->parent_inode);
137 dn->dir->parent_inode->make_nosnap_relative_path(p);
138 p.push_dentry(dn->name);
7c673cae
FG
139 } else {
140 p = filepath(ino);
141 }
142}
143
144void Inode::get_open_ref(int mode)
145{
f67539c2 146 client->inc_opened_files();
b3b6e05e 147 if (open_by_mode[mode] == 0) {
f67539c2 148 client->inc_opened_inodes();
b3b6e05e 149 }
7c673cae 150 open_by_mode[mode]++;
b32b8144 151 break_deleg(!(mode & CEPH_FILE_MODE_WR));
7c673cae
FG
152}
153
154bool Inode::put_open_ref(int mode)
155{
156 //cout << "open_by_mode[" << mode << "] " << open_by_mode[mode] << " -> " << (open_by_mode[mode]-1) << std::endl;
11fdf7f2
TL
157 auto& ref = open_by_mode.at(mode);
158 ceph_assert(ref > 0);
f67539c2
TL
159 client->dec_opened_files();
160 if (--ref == 0) {
161 client->dec_opened_inodes();
7c673cae 162 return true;
f67539c2 163 }
7c673cae
FG
164 return false;
165}
166
167void Inode::get_cap_ref(int cap)
168{
169 int n = 0;
170 while (cap) {
171 if (cap & 1) {
172 int c = 1 << n;
173 cap_refs[c]++;
174 //cout << "inode " << *this << " get " << cap_string(c) << " " << (cap_refs[c]-1) << " -> " << cap_refs[c] << std::endl;
175 }
176 cap >>= 1;
177 n++;
178 }
179}
180
181int Inode::put_cap_ref(int cap)
182{
7c673cae
FG
183 int last = 0;
184 int n = 0;
185 while (cap) {
186 if (cap & 1) {
187 int c = 1 << n;
188 if (cap_refs[c] <= 0) {
189 lderr(client->cct) << "put_cap_ref " << ccap_string(c) << " went negative on " << *this << dendl;
11fdf7f2 190 ceph_assert(cap_refs[c] > 0);
7c673cae
FG
191 }
192 if (--cap_refs[c] == 0)
193 last |= c;
194 //cout << "inode " << *this << " put " << cap_string(c) << " " << (cap_refs[c]+1) << " -> " << cap_refs[c] << std::endl;
195 }
196 cap >>= 1;
197 n++;
198 }
199 return last;
200}
201
202bool Inode::is_any_caps()
203{
204 return !caps.empty() || snap_caps;
205}
206
11fdf7f2 207bool Inode::cap_is_valid(const Cap &cap) const
7c673cae
FG
208{
209 /*cout << "cap_gen " << cap->session-> cap_gen << std::endl
210 << "session gen " << cap->gen << std::endl
211 << "cap expire " << cap->session->cap_ttl << std::endl
212 << "cur time " << ceph_clock_now(cct) << std::endl;*/
11fdf7f2
TL
213 if ((cap.session->cap_gen <= cap.gen)
214 && (ceph_clock_now() < cap.session->cap_ttl)) {
7c673cae
FG
215 return true;
216 }
217 return false;
218}
219
220int Inode::caps_issued(int *implemented) const
221{
222 int c = snap_caps;
223 int i = 0;
b3b6e05e 224 for (const auto &[mds, cap] : caps) {
11fdf7f2
TL
225 if (cap_is_valid(cap)) {
226 c |= cap.issued;
227 i |= cap.implemented;
7c673cae 228 }
11fdf7f2 229 }
94b18763
FG
230 // exclude caps issued by non-auth MDS, but are been revoking by
231 // the auth MDS. The non-auth MDS should be revoking/exporting
232 // these caps, but the message is delayed.
233 if (auth_cap)
234 c &= ~auth_cap->implemented | auth_cap->issued;
235
7c673cae
FG
236 if (implemented)
237 *implemented = i;
238 return c;
239}
240
7c673cae
FG
241void Inode::try_touch_cap(mds_rank_t mds)
242{
11fdf7f2
TL
243 auto it = caps.find(mds);
244 if (it != caps.end()) {
245 it->second.touch();
246 }
7c673cae
FG
247}
248
94b18763
FG
249/**
250 * caps_issued_mask - check whether we have all of the caps in the mask
251 * @mask: mask to check against
252 * @allow_impl: whether the caller can also use caps that are implemented but not issued
253 *
254 * This is the bog standard "check whether we have the required caps" operation.
255 * Typically, we only check against the capset that is currently "issued".
256 * In other words, we ignore caps that have been revoked but not yet released.
f67539c2 257 * Also account capability hit/miss stats.
94b18763
FG
258 *
259 * Some callers (particularly those doing attribute retrieval) can also make
260 * use of the full set of "implemented" caps to satisfy requests from the
261 * cache.
262 *
263 * Those callers should refrain from taking new references to implemented
264 * caps!
265 */
266bool Inode::caps_issued_mask(unsigned mask, bool allow_impl)
7c673cae
FG
267{
268 int c = snap_caps;
94b18763
FG
269 int i = 0;
270
7c673cae
FG
271 if ((c & mask) == mask)
272 return true;
273 // prefer auth cap
274 if (auth_cap &&
11fdf7f2 275 cap_is_valid(*auth_cap) &&
7c673cae 276 (auth_cap->issued & mask) == mask) {
11fdf7f2 277 auth_cap->touch();
f67539c2 278 client->cap_hit();
7c673cae
FG
279 return true;
280 }
281 // try any cap
11fdf7f2
TL
282 for (auto &pair : caps) {
283 Cap &cap = pair.second;
284 if (cap_is_valid(cap)) {
285 if ((cap.issued & mask) == mask) {
286 cap.touch();
f67539c2 287 client->cap_hit();
7c673cae
FG
288 return true;
289 }
11fdf7f2
TL
290 c |= cap.issued;
291 i |= cap.implemented;
7c673cae
FG
292 }
293 }
94b18763
FG
294
295 if (allow_impl)
296 c |= i;
297
7c673cae
FG
298 if ((c & mask) == mask) {
299 // bah.. touch them all
11fdf7f2
TL
300 for (auto &pair : caps) {
301 pair.second.touch();
302 }
f67539c2 303 client->cap_hit();
7c673cae
FG
304 return true;
305 }
f67539c2
TL
306
307 client->cap_miss();
7c673cae
FG
308 return false;
309}
310
311int Inode::caps_used()
312{
313 int w = 0;
b3b6e05e
TL
314 for (const auto &[cap, cnt] : cap_refs)
315 if (cnt)
316 w |= cap;
7c673cae
FG
317 return w;
318}
319
320int Inode::caps_file_wanted()
321{
322 int want = 0;
b3b6e05e
TL
323 for (const auto &[mode, cnt] : open_by_mode)
324 if (cnt)
325 want |= ceph_caps_for_mode(mode);
7c673cae
FG
326 return want;
327}
328
329int Inode::caps_wanted()
330{
331 int want = caps_file_wanted() | caps_used();
332 if (want & CEPH_CAP_FILE_BUFFER)
333 want |= CEPH_CAP_FILE_EXCL;
334 return want;
335}
336
337int Inode::caps_mds_wanted()
338{
339 int want = 0;
11fdf7f2
TL
340 for (const auto &pair : caps) {
341 want |= pair.second.wanted;
342 }
7c673cae
FG
343 return want;
344}
345
346int Inode::caps_dirty()
347{
348 return dirty_caps | flushing_caps;
349}
350
351const UserPerm* Inode::get_best_perms()
352{
353 const UserPerm *perms = NULL;
11fdf7f2
TL
354 for (const auto &pair : caps) {
355 const UserPerm& iperm = pair.second.latest_perms;
7c673cae
FG
356 if (!perms) { // we don't have any, take what's present
357 perms = &iperm;
358 } else if (iperm.uid() == uid) {
359 if (iperm.gid() == gid) { // we have the best possible, return
360 return &iperm;
361 }
362 if (perms->uid() != uid) { // take uid > gid every time
363 perms = &iperm;
364 }
365 } else if (perms->uid() != uid && iperm.gid() == gid) {
366 perms = &iperm; // a matching gid is better than nothing
367 }
368 }
369 return perms;
370}
371
372bool Inode::have_valid_size()
373{
374 // RD+RDCACHE or WR+WRBUFFER => valid size
375 if (caps_issued() & (CEPH_CAP_FILE_SHARED | CEPH_CAP_FILE_EXCL))
376 return true;
377 return false;
378}
379
380// open Dir for an inode. if it's not open, allocated it (and pin dentry in memory).
381Dir *Inode::open_dir()
382{
383 if (!dir) {
384 dir = new Dir(this);
385 lsubdout(client->cct, client, 15) << "open_dir " << dir << " on " << this << dendl;
11fdf7f2
TL
386 ceph_assert(dentries.size() < 2); // dirs can't be hard-linked
387 if (!dentries.empty())
388 get_first_parent()->get(); // pin dentry
b3b6e05e 389 iget(); // pin inode
7c673cae
FG
390 }
391 return dir;
392}
393
394bool Inode::check_mode(const UserPerm& perms, unsigned want)
395{
396 if (uid == perms.uid()) {
397 // if uid is owner, owner entry determines access
398 want = want << 6;
399 } else if (perms.gid_in_groups(gid)) {
400 // if a gid or sgid matches the owning group, group entry determines access
401 want = want << 3;
402 }
403
404 return (mode & want) == want;
405}
406
7c673cae
FG
407void Inode::dump(Formatter *f) const
408{
409 f->dump_stream("ino") << ino;
410 f->dump_stream("snapid") << snapid;
411 if (rdev)
412 f->dump_unsigned("rdev", rdev);
413 f->dump_stream("ctime") << ctime;
414 f->dump_stream("btime") << btime;
415 f->dump_stream("mode") << '0' << std::oct << mode << std::dec;
416 f->dump_unsigned("uid", uid);
417 f->dump_unsigned("gid", gid);
31f18b77 418 f->dump_int("nlink", nlink);
7c673cae 419
31f18b77
FG
420 f->dump_unsigned("size", size);
421 f->dump_unsigned("max_size", max_size);
422 f->dump_unsigned("truncate_seq", truncate_seq);
423 f->dump_unsigned("truncate_size", truncate_size);
7c673cae
FG
424 f->dump_stream("mtime") << mtime;
425 f->dump_stream("atime") << atime;
31f18b77
FG
426 f->dump_unsigned("time_warp_seq", time_warp_seq);
427 f->dump_unsigned("change_attr", change_attr);
7c673cae
FG
428
429 f->dump_object("layout", layout);
430 if (is_dir()) {
431 f->open_object_section("dir_layout");
432 ::dump(dir_layout, f);
433 f->close_section();
434
435 f->dump_bool("complete", flags & I_COMPLETE);
436 f->dump_bool("ordered", flags & I_DIR_ORDERED);
437
438 /* FIXME when wip-mds-encoding is merged ***
439 f->open_object_section("dir_stat");
440 dirstat.dump(f);
441 f->close_section();
442
443 f->open_object_section("rstat");
444 rstat.dump(f);
445 f->close_section();
446 */
447 }
448
449 f->dump_unsigned("version", version);
450 f->dump_unsigned("xattr_version", xattr_version);
451 f->dump_unsigned("flags", flags);
452
453 if (is_dir()) {
7c673cae
FG
454 f->dump_int("dir_hashed", (int)dir_hashed);
455 f->dump_int("dir_replicated", (int)dir_replicated);
f67539c2
TL
456 if (dir_replicated) {
457 f->open_array_section("dirfrags");
458 for (const auto &frag : frag_repmap) {
459 f->open_object_section("frags");
460 CachedStackStringStream css;
461 *css << std::hex << frag.first.value() << "/" << std::dec << frag.first.bits();
462 f->dump_string("frag", css->strv());
463
464 f->open_array_section("repmap");
465 for (const auto &mds : frag.second) {
466 f->dump_int("mds", mds);
467 }
468 f->close_section();
469
470 f->close_section();
471 }
472 f->close_section();
473 }
7c673cae
FG
474 }
475
476 f->open_array_section("caps");
11fdf7f2 477 for (const auto &pair : caps) {
7c673cae 478 f->open_object_section("cap");
11fdf7f2 479 if (&pair.second == auth_cap)
7c673cae 480 f->dump_int("auth", 1);
11fdf7f2 481 pair.second.dump(f);
7c673cae
FG
482 f->close_section();
483 }
484 f->close_section();
485 if (auth_cap)
486 f->dump_int("auth_cap", auth_cap->session->mds_num);
487
488 f->dump_stream("dirty_caps") << ccap_string(dirty_caps);
489 if (flushing_caps) {
490 f->dump_stream("flushings_caps") << ccap_string(flushing_caps);
491 f->open_object_section("flushing_cap_tid");
492 for (map<ceph_tid_t, int>::const_iterator p = flushing_cap_tids.begin();
493 p != flushing_cap_tids.end();
494 ++p) {
495 string n(ccap_string(p->second));
496 f->dump_unsigned(n.c_str(), p->first);
497 }
498 f->close_section();
499 }
500 f->dump_int("shared_gen", shared_gen);
501 f->dump_int("cache_gen", cache_gen);
502 if (snap_caps) {
503 f->dump_int("snap_caps", snap_caps);
504 f->dump_int("snap_cap_refs", snap_cap_refs);
505 }
506
507 f->dump_stream("hold_caps_until") << hold_caps_until;
508
509 if (snaprealm) {
510 f->open_object_section("snaprealm");
511 snaprealm->dump(f);
512 f->close_section();
513 }
514 if (!cap_snaps.empty()) {
515 for (const auto &p : cap_snaps) {
516 f->open_object_section("cap_snap");
517 f->dump_stream("follows") << p.first;
518 p.second.dump(f);
519 f->close_section();
520 }
521 }
522
523 // open
524 if (!open_by_mode.empty()) {
525 f->open_array_section("open_by_mode");
526 for (map<int,int>::const_iterator p = open_by_mode.begin(); p != open_by_mode.end(); ++p) {
527 f->open_object_section("ref");
31f18b77
FG
528 f->dump_int("mode", p->first);
529 f->dump_int("refs", p->second);
7c673cae
FG
530 f->close_section();
531 }
532 f->close_section();
533 }
534 if (!cap_refs.empty()) {
535 f->open_array_section("cap_refs");
536 for (map<int,int>::const_iterator p = cap_refs.begin(); p != cap_refs.end(); ++p) {
537 f->open_object_section("cap_ref");
538 f->dump_stream("cap") << ccap_string(p->first);
539 f->dump_int("refs", p->second);
540 f->close_section();
541 }
542 f->close_section();
543 }
544
545 f->dump_unsigned("reported_size", reported_size);
546 if (wanted_max_size != max_size)
547 f->dump_unsigned("wanted_max_size", wanted_max_size);
548 if (requested_max_size != max_size)
549 f->dump_unsigned("requested_max_size", requested_max_size);
550
b3b6e05e 551 f->dump_int("nref", get_nref());
7c673cae
FG
552 f->dump_int("ll_ref", ll_ref);
553
11fdf7f2 554 if (!dentries.empty()) {
7c673cae 555 f->open_array_section("parents");
9f95a23c 556 for (const auto &&dn : dentries) {
7c673cae 557 f->open_object_section("dentry");
11fdf7f2
TL
558 f->dump_stream("dir_ino") << dn->dir->parent_inode->ino;
559 f->dump_string("name", dn->name);
7c673cae
FG
560 f->close_section();
561 }
562 f->close_section();
563 }
564}
565
566void Cap::dump(Formatter *f) const
567{
568 f->dump_int("mds", session->mds_num);
11fdf7f2 569 f->dump_stream("ino") << inode.ino;
7c673cae
FG
570 f->dump_unsigned("cap_id", cap_id);
571 f->dump_stream("issued") << ccap_string(issued);
572 if (implemented != issued)
573 f->dump_stream("implemented") << ccap_string(implemented);
574 f->dump_stream("wanted") << ccap_string(wanted);
575 f->dump_unsigned("seq", seq);
576 f->dump_unsigned("issue_seq", issue_seq);
577 f->dump_unsigned("mseq", mseq);
578 f->dump_unsigned("gen", gen);
579}
580
581void CapSnap::dump(Formatter *f) const
582{
583 f->dump_stream("ino") << in->ino;
584 f->dump_stream("issued") << ccap_string(issued);
585 f->dump_stream("dirty") << ccap_string(dirty);
586 f->dump_unsigned("size", size);
587 f->dump_stream("ctime") << ctime;
588 f->dump_stream("mtime") << mtime;
589 f->dump_stream("atime") << atime;
590 f->dump_int("time_warp_seq", time_warp_seq);
591 f->dump_stream("mode") << '0' << std::oct << mode << std::dec;
592 f->dump_unsigned("uid", uid);
593 f->dump_unsigned("gid", gid);
594 if (!xattrs.empty()) {
595 f->open_object_section("xattr_lens");
596 for (map<string,bufferptr>::const_iterator p = xattrs.begin(); p != xattrs.end(); ++p)
597 f->dump_int(p->first.c_str(), p->second.length());
598 f->close_section();
599 }
600 f->dump_unsigned("xattr_version", xattr_version);
601 f->dump_int("writing", (int)writing);
602 f->dump_int("dirty_data", (int)dirty_data);
603 f->dump_unsigned("flush_tid", flush_tid);
604}
605
606void Inode::set_async_err(int r)
607{
608 for (const auto &fh : fhs) {
609 fh->async_err = r;
610 }
611}
612
b32b8144
FG
613bool Inode::has_recalled_deleg()
614{
615 if (delegations.empty())
616 return false;
617
618 // Either all delegations are recalled or none are. Just check the first.
619 Delegation& deleg = delegations.front();
620 return deleg.is_recalled();
621}
622
623void Inode::recall_deleg(bool skip_read)
624{
625 if (delegations.empty())
626 return;
627
628 // Issue any recalls
629 for (list<Delegation>::iterator d = delegations.begin();
630 d != delegations.end(); ++d) {
631
632 Delegation& deleg = *d;
633 deleg.recall(skip_read);
634 }
635}
636
637bool Inode::delegations_broken(bool skip_read)
638{
639 if (delegations.empty()) {
640 lsubdout(client->cct, client, 10) <<
641 __func__ << ": delegations empty on " << *this << dendl;
642 return true;
643 }
644
645 if (skip_read) {
646 Delegation& deleg = delegations.front();
647 lsubdout(client->cct, client, 10) <<
648 __func__ << ": read delegs only on " << *this << dendl;
649 if (deleg.get_type() == CEPH_FILE_MODE_RD) {
650 return true;
651 }
652 }
653 lsubdout(client->cct, client, 10) <<
654 __func__ << ": not broken" << *this << dendl;
655 return false;
656}
657
658void Inode::break_deleg(bool skip_read)
659{
660 lsubdout(client->cct, client, 10) <<
661 __func__ << ": breaking delegs on " << *this << dendl;
662
663 recall_deleg(skip_read);
664
665 while (!delegations_broken(skip_read))
666 client->wait_on_list(waitfor_deleg);
667}
668
669/**
670 * set_deleg: request a delegation on an open Fh
671 * @fh: filehandle on which to acquire it
672 * @type: delegation request type
673 * @cb: delegation recall callback function
674 * @priv: private pointer to be passed to callback
675 *
676 * Attempt to acquire a delegation on an open file handle. If there are no
677 * conflicts and we have the right caps, allocate a new delegation, fill it
678 * out and return 0. Return an error if we can't get one for any reason.
679 */
680int Inode::set_deleg(Fh *fh, unsigned type, ceph_deleg_cb_t cb, void *priv)
681{
682 lsubdout(client->cct, client, 10) <<
683 __func__ << ": inode " << *this << dendl;
684
685 /*
686 * 0 deleg timeout means that they haven't been explicitly enabled. Don't
687 * allow it, with an unusual error to make it clear.
688 */
689 if (!client->get_deleg_timeout())
f67539c2 690 return -CEPHFS_ETIME;
b32b8144
FG
691
692 // Just say no if we have any recalled delegs still outstanding
693 if (has_recalled_deleg()) {
694 lsubdout(client->cct, client, 10) << __func__ <<
695 ": has_recalled_deleg" << dendl;
f67539c2 696 return -CEPHFS_EAGAIN;
b32b8144
FG
697 }
698
699 // check vs. currently open files on this inode
700 switch (type) {
701 case CEPH_DELEGATION_RD:
702 if (open_count_for_write()) {
703 lsubdout(client->cct, client, 10) << __func__ <<
704 ": open for write" << dendl;
f67539c2 705 return -CEPHFS_EAGAIN;
b32b8144
FG
706 }
707 break;
708 case CEPH_DELEGATION_WR:
709 if (open_count() > 1) {
710 lsubdout(client->cct, client, 10) << __func__ << ": open" << dendl;
f67539c2 711 return -CEPHFS_EAGAIN;
b32b8144
FG
712 }
713 break;
714 default:
f67539c2 715 return -CEPHFS_EINVAL;
b32b8144
FG
716 }
717
718 /*
719 * A delegation is essentially a long-held container for cap references that
720 * we delegate to the client until recalled. The caps required depend on the
721 * type of delegation (read vs. rw). This is entirely an opportunistic thing.
722 * If we don't have the necessary caps for the delegation, then we just don't
723 * grant one.
724 *
725 * In principle we could request the caps from the MDS, but a delegation is
726 * usually requested just after an open. If we don't have the necessary caps
727 * already, then it's likely that there is some sort of conflicting access.
728 *
729 * In the future, we may need to add a way to have this request caps more
730 * aggressively -- for instance, to handle WANT_DELEGATION for NFSv4.1+.
731 */
732 int need = ceph_deleg_caps_for_type(type);
733 if (!caps_issued_mask(need)) {
734 lsubdout(client->cct, client, 10) << __func__ << ": cap mismatch, have="
735 << ccap_string(caps_issued()) << " need=" << ccap_string(need) << dendl;
f67539c2 736 return -CEPHFS_EAGAIN;
b32b8144
FG
737 }
738
739 for (list<Delegation>::iterator d = delegations.begin();
740 d != delegations.end(); ++d) {
741 Delegation& deleg = *d;
742 if (deleg.get_fh() == fh) {
743 deleg.reinit(type, cb, priv);
744 return 0;
745 }
746 }
747
748 delegations.emplace_back(fh, type, cb, priv);
749 return 0;
750}
751
752/**
753 * unset_deleg - remove a delegation that was previously set
754 * @fh: file handle to clear delegation of
755 *
756 * Unlink delegation from the Inode (if there is one), put caps and free it.
757 */
758void Inode::unset_deleg(Fh *fh)
759{
760 for (list<Delegation>::iterator d = delegations.begin();
761 d != delegations.end(); ++d) {
762 Delegation& deleg = *d;
763 if (deleg.get_fh() == fh) {
764 delegations.erase(d);
765 client->signal_cond_list(waitfor_deleg);
766 break;
767 }
768 }
769}
28e407b8
AA
770
771/**
772* mark_caps_dirty - mark some caps dirty
773* @caps: the dirty caps
774*
775* note that if there is no dirty and flushing caps before, we need to pin this inode.
776* it will be unpined by handle_cap_flush_ack when there are no dirty and flushing caps.
777*/
778void Inode::mark_caps_dirty(int caps)
779{
20effc67
TL
780 /*
781 * If auth_cap is nullptr means the reonnecting is not finished or
782 * already rejected.
783 */
784 if (!auth_cap) {
785 ceph_assert(!dirty_caps);
786
787 lsubdout(client->cct, client, 1) << __func__ << " " << *this << " dirty caps '" << ccap_string(caps)
788 << "', but no auth cap." << dendl;
789 return;
790 }
791
28e407b8
AA
792 lsubdout(client->cct, client, 10) << __func__ << " " << *this << " " << ccap_string(dirty_caps) << " -> "
793 << ccap_string(dirty_caps | caps) << dendl;
20effc67 794
28e407b8 795 if (caps && !caps_dirty())
b3b6e05e 796 iget();
20effc67 797
28e407b8 798 dirty_caps |= caps;
20effc67
TL
799 auth_cap->session->get_dirty_list().push_back(&dirty_cap_item);
800 client->cap_delay_requeue(this);
28e407b8
AA
801}
802
803/**
804* mark_caps_clean - only clean the dirty_caps and caller should start flushing the dirty caps.
805*/
806void Inode::mark_caps_clean()
807{
808 lsubdout(client->cct, client, 10) << __func__ << " " << *this << dendl;
809 dirty_caps = 0;
810 dirty_cap_item.remove_myself();
811}
812
813