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