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