mds = in->fragmap[fg];
if (phash_diri)
*phash_diri = in;
+ } else if (in->auth_cap) {
+ mds = in->auth_cap->session->mds_num;
+ }
+ if (mds >= 0) {
ldout(cct, 10) << "choose_target_mds from dirfragtree hash" << dendl;
goto out;
}
dn->dir = dir;
dir->dentries[dn->name] = dn;
lru.lru_insert_mid(dn); // mid or top?
+ if (!in)
+ dir->num_null_dentries++;
ldout(cct, 15) << "link dir " << dir->parent_inode << " '" << name << "' to inode " << in
<< " dn " << dn << " (new dn)" << dendl;
} else {
+ assert(!dn->inode);
+ if (in)
+ dir->num_null_dentries--;
ldout(cct, 15) << "link dir " << dir->parent_inode << " '" << name << "' to inode " << in
<< " dn " << dn << " (old dn)" << dendl;
}
if (keepdentry) {
dn->lease_mds = -1;
+ if (in)
+ dn->dir->num_null_dentries++;
} else {
ldout(cct, 15) << "unlink removing '" << dn->name << "' dn " << dn << dendl;
// unlink from dir
dn->dir->dentries.erase(dn->name);
+ if (!in)
+ dn->dir->num_null_dentries--;
if (dn->dir->is_empty() && !keepdir)
close_dir(dn->dir);
dn->dir = 0;
unsigned old_caps = cap->issued;
cap->cap_id = cap_id;
- cap->issued |= issued;
+ cap->issued = issued;
cap->implemented |= issued;
cap->seq = seq;
cap->issue_seq = seq;
sync_cond.Signal();
}
-int Client::_do_remount(void)
+int Client::_do_remount(bool retry_on_error)
{
+ uint64_t max_retries = cct->_conf->get_val<uint64_t>("mds_max_retries_on_remount_failure");
+
errno = 0;
int r = remount_cb(callback_handle);
- if (r != 0) {
+ if (r == 0) {
+ retries_on_invalidate = 0;
+ } else {
int e = errno;
client_t whoami = get_nodeid();
if (r == -1) {
"failed to remount (to trim kernel dentries): "
"return code = " << r << dendl;
}
- bool should_abort = cct->_conf->get_val<bool>("client_die_on_failed_remount") ||
- cct->_conf->get_val<bool>("client_die_on_failed_dentry_invalidate");
+ bool should_abort =
+ (cct->_conf->get_val<bool>("client_die_on_failed_remount") ||
+ cct->_conf->get_val<bool>("client_die_on_failed_dentry_invalidate")) &&
+ !(retry_on_error && (++retries_on_invalidate < max_retries));
if (should_abort && !unmounting) {
lderr(cct) << "failed to remount for kernel dentry trimming; quitting!" << dendl;
ceph_abort();
explicit C_Client_Remount(Client *c) : client(c) {}
void finish(int r) override {
assert(r == 0);
- client->_do_remount();
+ client->_do_remount(true);
}
};
}
}
+void Client::_trim_negative_child_dentries(InodeRef& in)
+{
+ if (!in->is_dir())
+ return;
+
+ Dir* dir = in->dir;
+ if (dir && dir->dentries.size() == dir->num_null_dentries) {
+ for (auto p = dir->dentries.begin(); p != dir->dentries.end(); ) {
+ Dentry *dn = p->second;
+ ++p;
+ assert(!dn->inode);
+ if (dn->lru_is_expireable())
+ unlink(dn, true, false); // keep dir, drop dentry
+ }
+ if (dir->dentries.empty()) {
+ close_dir(dir);
+ }
+ }
+
+ if (in->flags & I_SNAPDIR_OPEN) {
+ InodeRef snapdir = open_snapdir(in.get());
+ _trim_negative_child_dentries(snapdir);
+ }
+}
+
void Client::trim_caps(MetaSession *s, uint64_t max)
{
mds_rank_t mds = s->mds_num;
}
} else {
ldout(cct, 20) << " trying to trim dentries for " << *in << dendl;
+ _trim_negative_child_dentries(in);
bool all = true;
set<Dentry*>::iterator q = in->dn_set.begin();
while (q != in->dn_set.end()) {
}
// mtime
- in->mtime = ceph_clock_now();
+ in->mtime = in->ctime = ceph_clock_now();
in->change_attr++;
in->mark_caps_dirty(CEPH_CAP_FILE_WR);
{
Mutex::Locker l(client_lock);
tout(cct) << "statfs" << std::endl;
+ unsigned long int total_files_on_fs;
if (unmounting)
return -ENOTCONN;
client_lock.Unlock();
int rval = cond.wait();
+ assert(root);
+ total_files_on_fs = root->rstat.rfiles + root->rstat.rsubdirs;
client_lock.Lock();
if (rval < 0) {
const int CEPH_BLOCK_SHIFT = 22;
stbuf->f_frsize = 1 << CEPH_BLOCK_SHIFT;
stbuf->f_bsize = 1 << CEPH_BLOCK_SHIFT;
- stbuf->f_files = stats.num_objects;
- stbuf->f_ffree = -1;
+ stbuf->f_files = total_files_on_fs;
+ stbuf->f_ffree = 0;
stbuf->f_favail = -1;
stbuf->f_fsid = -1; // ??
stbuf->f_flag = 0; // ??
r = 0;
} else if (remount_cb) {
ldout(cct, 1) << "using remount_cb" << dendl;
- r = _do_remount();
+ r = _do_remount(false);
}
if (r) {
bool should_abort = cct->_conf->get_val<bool>("client_die_on_failed_dentry_invalidate");
in->inline_data = bl;
in->inline_version++;
}
- in->mtime = ceph_clock_now();
+ in->mtime = in->ctime = ceph_clock_now();
in->change_attr++;
in->mark_caps_dirty(CEPH_CAP_FILE_WR);
} else {
offset, length,
ceph::real_clock::now(),
0, true, onfinish);
- in->mtime = ceph_clock_now();
+ in->mtime = in->ctime = ceph_clock_now();
in->change_attr++;
in->mark_caps_dirty(CEPH_CAP_FILE_WR);
uint64_t size = offset + length;
if (size > in->size) {
in->size = size;
- in->mtime = ceph_clock_now();
+ in->mtime = in->ctime = ceph_clock_now();
in->change_attr++;
in->mark_caps_dirty(CEPH_CAP_FILE_WR);
int Client::ll_release(Fh *fh)
{
Mutex::Locker lock(client_lock);
+
+ if (unmounting)
+ return -ENOTCONN;
+
ldout(cct, 3) << "ll_release (fh)" << fh << " " << fh->inode->ino << " " <<
dendl;
tout(cct) << "ll_release (fh)" << std::endl;
tout(cct) << (unsigned long)fh << std::endl;
- if (unmounting)
- return -ENOTCONN;
-
if (ll_unclosed_fh_set.count(fh))
ll_unclosed_fh_set.erase(fh);
return _release_fh(fh);