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