#include "mds/flock.h"
+using std::dec;
+using std::list;
+using std::oct;
+using std::ostream;
+using std::string;
+
Inode::~Inode()
{
- cap_item.remove_myself();
+ delay_cap_item.remove_myself();
+ dirty_cap_item.remove_myself();
snaprealm_item.remove_myself();
if (snapdir_parent) {
if (!oset.objects.empty()) {
lsubdout(client->cct, client, 0) << __func__ << ": leftover objects on inode 0x"
<< std::hex << ino << std::dec << dendl;
- assert(oset.objects.empty());
+ ceph_assert(oset.objects.empty());
}
if (!delegations.empty()) {
lsubdout(client->cct, client, 0) << __func__ << ": leftover delegations on inode 0x"
<< std::hex << ino << std::dec << dendl;
- assert(delegations.empty());
+ ceph_assert(delegations.empty());
}
-
- delete fcntl_locks;
- delete flock_locks;
}
ostream& operator<<(ostream &out, const Inode &in)
{
out << in.vino() << "("
<< "faked_ino=" << in.faked_ino
- << " ref=" << in._ref
+ << " nref=" << in.get_nref()
<< " ll_ref=" << in.ll_ref
<< " cap_refs=" << in.cap_refs
<< " open=" << in.open_by_mode
<< " mode=" << oct << in.mode << dec
<< " size=" << in.size << "/" << in.max_size
+ << " nlink=" << in.nlink
+ << " btime=" << in.btime
<< " mtime=" << in.mtime
+ << " ctime=" << in.ctime
<< " caps=" << ccap_string(in.caps_issued());
if (!in.caps.empty()) {
out << "(";
- for (auto p = in.caps.begin(); p != in.caps.end(); ++p) {
- if (p != in.caps.begin())
+ bool first = true;
+ for (const auto &pair : in.caps) {
+ if (!first)
out << ',';
- out << p->first << '=' << ccap_string(p->second->issued);
+ out << pair.first << '=' << ccap_string(pair.second.issued);
+ first = false;
}
out << ")";
}
if (in.is_file())
out << " " << in.oset;
- if (!in.dn_set.empty())
- out << " parents=" << in.dn_set;
+ if (!in.dentries.empty())
+ out << " parents=" << in.dentries;
if (in.is_dir() && in.has_dir_layout())
out << " has_dir_layout";
void Inode::make_long_path(filepath& p)
{
- if (!dn_set.empty()) {
- assert((*dn_set.begin())->dir && (*dn_set.begin())->dir->parent_inode);
- (*dn_set.begin())->dir->parent_inode->make_long_path(p);
- p.push_dentry((*dn_set.begin())->name);
+ if (!dentries.empty()) {
+ Dentry *dn = get_first_parent();
+ ceph_assert(dn->dir && dn->dir->parent_inode);
+ dn->dir->parent_inode->make_long_path(p);
+ p.push_dentry(dn->name);
} else if (snapdir_parent) {
- snapdir_parent->make_nosnap_relative_path(p);
- string empty;
- p.push_dentry(empty);
+ make_nosnap_relative_path(p);
+ } else
+ p = filepath(ino);
+}
+
+void Inode::make_short_path(filepath& p)
+{
+ if (!dentries.empty()) {
+ Dentry *dn = get_first_parent();
+ ceph_assert(dn->dir && dn->dir->parent_inode);
+ p = filepath(dn->name, dn->dir->parent_inode->ino);
+ } else if (snapdir_parent) {
+ make_nosnap_relative_path(p);
} else
p = filepath(ino);
}
snapdir_parent->make_nosnap_relative_path(p);
string empty;
p.push_dentry(empty);
- } else if (!dn_set.empty()) {
- assert((*dn_set.begin())->dir && (*dn_set.begin())->dir->parent_inode);
- (*dn_set.begin())->dir->parent_inode->make_nosnap_relative_path(p);
- p.push_dentry((*dn_set.begin())->name);
+ } else if (!dentries.empty()) {
+ Dentry *dn = get_first_parent();
+ ceph_assert(dn->dir && dn->dir->parent_inode);
+ dn->dir->parent_inode->make_nosnap_relative_path(p);
+ p.push_dentry(dn->name);
} else {
p = filepath(ino);
}
void Inode::get_open_ref(int mode)
{
+ client->inc_opened_files();
+ if (open_by_mode[mode] == 0) {
+ client->inc_opened_inodes();
+ }
open_by_mode[mode]++;
break_deleg(!(mode & CEPH_FILE_MODE_WR));
}
bool Inode::put_open_ref(int mode)
{
//cout << "open_by_mode[" << mode << "] " << open_by_mode[mode] << " -> " << (open_by_mode[mode]-1) << std::endl;
- if (--open_by_mode[mode] == 0)
+ auto& ref = open_by_mode.at(mode);
+ ceph_assert(ref > 0);
+ client->dec_opened_files();
+ if (--ref == 0) {
+ client->dec_opened_inodes();
return true;
+ }
return false;
}
int c = 1 << n;
if (cap_refs[c] <= 0) {
lderr(client->cct) << "put_cap_ref " << ccap_string(c) << " went negative on " << *this << dendl;
- assert(cap_refs[c] > 0);
+ ceph_assert(cap_refs[c] > 0);
}
if (--cap_refs[c] == 0)
last |= c;
return !caps.empty() || snap_caps;
}
-bool Inode::cap_is_valid(Cap* cap) const
+bool Inode::cap_is_valid(const Cap &cap) const
{
/*cout << "cap_gen " << cap->session-> cap_gen << std::endl
<< "session gen " << cap->gen << std::endl
<< "cap expire " << cap->session->cap_ttl << std::endl
<< "cur time " << ceph_clock_now(cct) << std::endl;*/
- if ((cap->session->cap_gen <= cap->gen)
- && (ceph_clock_now() < cap->session->cap_ttl)) {
+ if ((cap.session->cap_gen <= cap.gen)
+ && (ceph_clock_now() < cap.session->cap_ttl)) {
return true;
}
return false;
{
int c = snap_caps;
int i = 0;
- for (map<mds_rank_t,Cap*>::const_iterator it = caps.begin();
- it != caps.end();
- ++it)
- if (cap_is_valid(it->second)) {
- c |= it->second->issued;
- i |= it->second->implemented;
+ for (const auto &[mds, cap] : caps) {
+ if (cap_is_valid(cap)) {
+ c |= cap.issued;
+ i |= cap.implemented;
}
-
+ }
// exclude caps issued by non-auth MDS, but are been revoking by
// the auth MDS. The non-auth MDS should be revoking/exporting
// these caps, but the message is delayed.
return c;
}
-void Inode::touch_cap(Cap *cap)
-{
- // move to back of LRU
- cap->session->caps.push_back(&cap->cap_item);
-}
-
void Inode::try_touch_cap(mds_rank_t mds)
{
- if (caps.count(mds))
- touch_cap(caps[mds]);
+ auto it = caps.find(mds);
+ if (it != caps.end()) {
+ it->second.touch();
+ }
}
/**
* This is the bog standard "check whether we have the required caps" operation.
* Typically, we only check against the capset that is currently "issued".
* In other words, we ignore caps that have been revoked but not yet released.
+ * Also account capability hit/miss stats.
*
* Some callers (particularly those doing attribute retrieval) can also make
* use of the full set of "implemented" caps to satisfy requests from the
return true;
// prefer auth cap
if (auth_cap &&
- cap_is_valid(auth_cap) &&
+ cap_is_valid(*auth_cap) &&
(auth_cap->issued & mask) == mask) {
- touch_cap(auth_cap);
+ auth_cap->touch();
+ client->cap_hit();
return true;
}
// try any cap
- for (map<mds_rank_t,Cap*>::iterator it = caps.begin();
- it != caps.end();
- ++it) {
- if (cap_is_valid(it->second)) {
- if ((it->second->issued & mask) == mask) {
- touch_cap(it->second);
+ for (auto &pair : caps) {
+ Cap &cap = pair.second;
+ if (cap_is_valid(cap)) {
+ if ((cap.issued & mask) == mask) {
+ cap.touch();
+ client->cap_hit();
return true;
}
- c |= it->second->issued;
- i |= it->second->implemented;
+ c |= cap.issued;
+ i |= cap.implemented;
}
}
if ((c & mask) == mask) {
// bah.. touch them all
- for (map<mds_rank_t,Cap*>::iterator it = caps.begin();
- it != caps.end();
- ++it)
- touch_cap(it->second);
+ for (auto &pair : caps) {
+ pair.second.touch();
+ }
+ client->cap_hit();
return true;
}
+
+ client->cap_miss();
return false;
}
int Inode::caps_used()
{
int w = 0;
- for (map<int,int>::iterator p = cap_refs.begin();
- p != cap_refs.end();
- ++p)
- if (p->second)
- w |= p->first;
+ for (const auto &[cap, cnt] : cap_refs)
+ if (cnt)
+ w |= cap;
return w;
}
int Inode::caps_file_wanted()
{
int want = 0;
- for (map<int,int>::iterator p = open_by_mode.begin();
- p != open_by_mode.end();
- ++p)
- if (p->second)
- want |= ceph_caps_for_mode(p->first);
+ for (const auto &[mode, cnt] : open_by_mode)
+ if (cnt)
+ want |= ceph_caps_for_mode(mode);
return want;
}
int Inode::caps_mds_wanted()
{
int want = 0;
- for (auto it = caps.begin(); it != caps.end(); ++it)
- want |= it->second->wanted;
+ for (const auto &pair : caps) {
+ want |= pair.second.wanted;
+ }
return want;
}
const UserPerm* Inode::get_best_perms()
{
const UserPerm *perms = NULL;
- for (const auto ci : caps) {
- const UserPerm& iperm = ci.second->latest_perms;
+ for (const auto &pair : caps) {
+ const UserPerm& iperm = pair.second.latest_perms;
if (!perms) { // we don't have any, take what's present
perms = &iperm;
} else if (iperm.uid() == uid) {
if (!dir) {
dir = new Dir(this);
lsubdout(client->cct, client, 15) << "open_dir " << dir << " on " << this << dendl;
- assert(dn_set.size() < 2); // dirs can't be hard-linked
- if (!dn_set.empty())
- (*dn_set.begin())->get(); // pin dentry
- get(); // pin inode
+ ceph_assert(dentries.size() < 2); // dirs can't be hard-linked
+ if (!dentries.empty())
+ get_first_parent()->get(); // pin dentry
+ iget(); // pin inode
}
return dir;
}
return (mode & want) == want;
}
-void Inode::get() {
- _ref++;
- lsubdout(client->cct, client, 15) << "inode.get on " << this << " " << ino << '.' << snapid
- << " now " << _ref << dendl;
-}
-
-//private method to put a reference; see Client::put_inode()
-int Inode::_put(int n) {
- _ref -= n;
- lsubdout(client->cct, client, 15) << "inode.put on " << this << " " << ino << '.' << snapid
- << " now " << _ref << dendl;
- assert(_ref >= 0);
- return _ref;
-}
-
-
void Inode::dump(Formatter *f) const
{
f->dump_stream("ino") << ino;
f->dump_unsigned("flags", flags);
if (is_dir()) {
- if (!dir_contacts.empty()) {
- f->open_object_section("dir_contants");
- for (set<int>::iterator p = dir_contacts.begin(); p != dir_contacts.end(); ++p)
- f->dump_int("mds", *p);
- f->close_section();
- }
f->dump_int("dir_hashed", (int)dir_hashed);
f->dump_int("dir_replicated", (int)dir_replicated);
+ if (dir_replicated) {
+ f->open_array_section("dirfrags");
+ for (const auto &frag : frag_repmap) {
+ f->open_object_section("frags");
+ CachedStackStringStream css;
+ *css << std::hex << frag.first.value() << "/" << std::dec << frag.first.bits();
+ f->dump_string("frag", css->strv());
+
+ f->open_array_section("repmap");
+ for (const auto &mds : frag.second) {
+ f->dump_int("mds", mds);
+ }
+ f->close_section();
+
+ f->close_section();
+ }
+ f->close_section();
+ }
}
f->open_array_section("caps");
- for (map<mds_rank_t,Cap*>::const_iterator p = caps.begin(); p != caps.end(); ++p) {
+ for (const auto &pair : caps) {
f->open_object_section("cap");
- f->dump_int("mds", p->first);
- if (p->second == auth_cap)
+ if (&pair.second == auth_cap)
f->dump_int("auth", 1);
- p->second->dump(f);
+ pair.second.dump(f);
f->close_section();
}
f->close_section();
if (requested_max_size != max_size)
f->dump_unsigned("requested_max_size", requested_max_size);
- f->dump_int("ref", _ref);
+ f->dump_int("nref", get_nref());
f->dump_int("ll_ref", ll_ref);
- if (!dn_set.empty()) {
+ if (!dentries.empty()) {
f->open_array_section("parents");
- for (set<Dentry*>::const_iterator p = dn_set.begin(); p != dn_set.end(); ++p) {
+ for (const auto &&dn : dentries) {
f->open_object_section("dentry");
- f->dump_stream("dir_ino") << (*p)->dir->parent_inode->ino;
- f->dump_string("name", (*p)->name);
+ f->dump_stream("dir_ino") << dn->dir->parent_inode->ino;
+ f->dump_string("name", dn->name);
f->close_section();
}
f->close_section();
void Cap::dump(Formatter *f) const
{
f->dump_int("mds", session->mds_num);
- f->dump_stream("ino") << inode->ino;
+ f->dump_stream("ino") << inode.ino;
f->dump_unsigned("cap_id", cap_id);
f->dump_stream("issued") << ccap_string(issued);
if (implemented != issued)
* allow it, with an unusual error to make it clear.
*/
if (!client->get_deleg_timeout())
- return -ETIME;
+ return -CEPHFS_ETIME;
// Just say no if we have any recalled delegs still outstanding
if (has_recalled_deleg()) {
lsubdout(client->cct, client, 10) << __func__ <<
": has_recalled_deleg" << dendl;
- return -EAGAIN;
+ return -CEPHFS_EAGAIN;
}
// check vs. currently open files on this inode
if (open_count_for_write()) {
lsubdout(client->cct, client, 10) << __func__ <<
": open for write" << dendl;
- return -EAGAIN;
+ return -CEPHFS_EAGAIN;
}
break;
case CEPH_DELEGATION_WR:
if (open_count() > 1) {
lsubdout(client->cct, client, 10) << __func__ << ": open" << dendl;
- return -EAGAIN;
+ return -CEPHFS_EAGAIN;
}
break;
default:
- return -EINVAL;
+ return -CEPHFS_EINVAL;
}
/*
if (!caps_issued_mask(need)) {
lsubdout(client->cct, client, 10) << __func__ << ": cap mismatch, have="
<< ccap_string(caps_issued()) << " need=" << ccap_string(need) << dendl;
- return -EAGAIN;
+ return -CEPHFS_EAGAIN;
}
for (list<Delegation>::iterator d = delegations.begin();
}
}
}
+
+/**
+* mark_caps_dirty - mark some caps dirty
+* @caps: the dirty caps
+*
+* note that if there is no dirty and flushing caps before, we need to pin this inode.
+* it will be unpined by handle_cap_flush_ack when there are no dirty and flushing caps.
+*/
+void Inode::mark_caps_dirty(int caps)
+{
+ /*
+ * If auth_cap is nullptr means the reonnecting is not finished or
+ * already rejected.
+ */
+ if (!auth_cap) {
+ ceph_assert(!dirty_caps);
+
+ lsubdout(client->cct, client, 1) << __func__ << " " << *this << " dirty caps '" << ccap_string(caps)
+ << "', but no auth cap." << dendl;
+ return;
+ }
+
+ lsubdout(client->cct, client, 10) << __func__ << " " << *this << " " << ccap_string(dirty_caps) << " -> "
+ << ccap_string(dirty_caps | caps) << dendl;
+
+ if (caps && !caps_dirty())
+ iget();
+
+ dirty_caps |= caps;
+ auth_cap->session->get_dirty_list().push_back(&dirty_cap_item);
+ client->cap_delay_requeue(this);
+}
+
+/**
+* mark_caps_clean - only clean the dirty_caps and caller should start flushing the dirty caps.
+*/
+void Inode::mark_caps_clean()
+{
+ lsubdout(client->cct, client, 10) << __func__ << " " << *this << dendl;
+ dirty_caps = 0;
+ dirty_cap_item.remove_myself();
+}
+
+