if (in) { // link to inode
dn->inode = in;
in->get();
- if (in->dir)
- dn->get(); // dir -> dn pin
+ if (in->is_dir()) {
+ if (in->dir)
+ dn->get(); // dir -> dn pin
+ if (in->ll_ref)
+ dn->get(); // ll_ref -> dn pin
+ }
assert(in->dn_set.count(dn) == 0);
// unlink from inode
if (in) {
- if (in->dir)
- dn->put(); // dir -> dn pin
+ if (in->is_dir()) {
+ if (in->dir)
+ dn->put(); // dir -> dn pin
+ if (in->ll_ref)
+ dn->put(); // ll_ref -> dn pin
+ }
dn->inode = 0;
assert(in->dn_set.count(dn));
in->dn_set.erase(dn);
void Client::_ll_get(Inode *in)
{
- if (in->ll_ref == 0)
+ if (in->ll_ref == 0) {
in->get();
+ if (in->is_dir() && !in->dn_set.empty()) {
+ assert(in->dn_set.size() == 1); // dirs can't be hard-linked
+ in->get_first_parent()->get(); // pin dentry
+ }
+ }
in->ll_get();
ldout(cct, 20) << "_ll_get " << in << " " << in->ino << " -> " << in->ll_ref << dendl;
}
in->ll_put(num);
ldout(cct, 20) << "_ll_put " << in << " " << in->ino << " " << num << " -> " << in->ll_ref << dendl;
if (in->ll_ref == 0) {
+ if (in->is_dir() && !in->dn_set.empty()) {
+ assert(in->dn_set.size() == 1); // dirs can't be hard-linked
+ in->get_first_parent()->put(); // unpin dentry
+ }
put_inode(in);
return 0;
} else {
ldout(cct, 1) << "WARNING: ll_forget on " << ino << " " << count
<< ", which only has ll_ref=" << in->ll_ref << dendl;
_ll_put(in, in->ll_ref);
- last = true;
- } else {
+ last = true;
+ } else {
if (_ll_put(in, count) == 0)
last = true;
}