dout(15) << "trim_cache unlinking dn " << dn->name
<< " in dir " << hex << dn->dir->parent_inode->ino
<< dendl;
+ if (dn->dir->parent_inode->flags & I_COMPLETE) {
+ dout(10) << " clearing I_COMPLETE on " << *dn->dir->parent_inode << dendl;
+ dn->dir->parent_inode->flags &= ~I_COMPLETE;
+ dn->dir->release_count++;
+ }
unlink(dn);
}
update_inode_file_bits(in, st->truncate_seq, st->truncate_size, st->size,
st->time_warp_seq, st->ctime, st->mtime, st->atime,
in->caps_issued());
+
+ if (in->is_dir() &&
+ (st->cap.caps & CEPH_CAP_FILE_SHARED) &&
+ in->dirstat.nfiles == 0 &&
+ in->dirstat.nsubdirs == 0) {
+ dout(10) << " marking I_COMPLETE on empty dir " << *in << dendl;
+ in->flags |= I_COMPLETE;
+ }
}
// symlink?
!(had & CEPH_CAP_FILE_SHARED)) {
in->shared_gen++;
- if (in->is_dir()) {
- // ...
+ if (in->is_dir() && (in->flags & I_COMPLETE)) {
+ dout(10) << " clearing I_COMPLETE on " << *in << dendl;
+ in->flags &= ~I_COMPLETE;
}
}
-
}
void Client::add_update_cap(Inode *in, int mds, __u64 cap_id,
*target = dn->inode;
goto done;
}
+ } else {
+ // can we conclude ENOENT locally?
+ if (dir->caps_issued_mask(CEPH_CAP_FILE_SHARED) &&
+ (dir->flags & I_COMPLETE)) {
+ dout(10) << "_lookup concluded ENOENT locally for " << *dir << " dn '" << dname << "'" << dendl;
+ return -ENOENT;
+ }
}
r = _do_lookup(dir, dname.c_str(), target);
{
*dirpp = new DirResult(in);
(*dirpp)->set_frag(in->dirfragtree[0]);
+ if (in->dir)
+ (*dirpp)->release_count = in->dir->release_count;
dout(10) << "_opendir " << in->ino << ", our cache says the first dirfrag is " << (*dirpp)->frag() << dendl;
// get the first frag
numdn--;
}
}
+
+ if (diri->dir->release_count == dirp->release_count) {
+ dout(10) << " marking I_COMPLETE on " << *diri << dendl;
+ diri->flags |= I_COMPLETE;
+ }
} else {
dout(10) << "_readdir_get_frag got error " << res << ", setting end flag" << dendl;
dirp->set_end();
public:
Inode *parent_inode; // my inode
hash_map<nstring, Dentry*> dentries;
+ __u64 release_count;
- Dir(Inode* in) { parent_inode = in; }
+ Dir(Inode* in) : release_count(0) { parent_inode = in; }
bool is_empty() { return dentries.empty(); }
};
};
+// inode flags
+#define I_COMPLETE 1
+
class Inode {
public:
// -- the actual inode --
bool is_dir() const { return (mode & S_IFMT) == S_IFDIR; }
bool is_file() const { return (mode & S_IFMT) == S_IFREG; }
+ unsigned flags;
+
// about the dir (if this is one!)
int dir_auth;
set<int> dir_contacts;
}
Inode(vinodeno_t vino, ceph_file_layout *layout) :
- //inode(_inode),
ino(vino.ino), snapid(vino.snapid),
rdev(0), mode(0), uid(0), gid(0), nlink(0), size(0), truncate_seq(0), truncate_size(0), truncate_from(0),
time_warp_seq(0), max_size(0), version(0), xattr_version(0),
+ flags(0),
dir_auth(-1), dir_hashed(false), dir_replicated(false),
dirty_caps(0), flushing_caps(0), flushing_cap_seq(0), shared_gen(0), cache_gen(0),
snap_caps(0), snap_cap_refs(0),
Inode *inode;
int64_t offset; // high bits: frag_t, low bits: an offset
+ __u64 release_count;
map<frag_t, vector<DirEntry> > buffer;
- DirResult(Inode *in) : inode(in), offset(0) {
+ DirResult(Inode *in) : inode(in), offset(0), release_count(0) {
inode->get();
}