* dentry+inode. This should be equivalent to issuing
* __unionfs_d_revalidate_chain on nd.dentry here.
*/
- err = -ESTALE; /* force revalidate */
+ if (is_file) /* dirs can be unlinked but chdir'ed to */
+ err = -ESTALE; /* force revalidate */
goto out;
}
{
int err = 0;
struct unionfs_dir_state *namelist = NULL;
+ int dstart, dend;
unionfs_read_lock(dentry->d_sb);
unionfs_lock_dentry(dentry);
err = odf_remove(dentry, ODF_RMV_NOTWH);
out:
- /* call d_drop so the system "forgets" about us */
- if (!err)
+ /*
+ * Drop references to lower dentry/inode so storage space for them
+ * can be reclaimed. Then, call d_drop so the system "forgets"
+ * about us.
+ */
+ if (!err) {
+ struct inode *inode = dentry->d_inode;
+ BUG_ON(!inode);
+ iput(unionfs_lower_inode_idx(inode, dstart));
+ unionfs_set_lower_inode_idx(inode, dstart, NULL);
+ dput(unionfs_lower_dentry_idx(dentry, dstart));
+ unionfs_set_lower_dentry_idx(dentry, dstart, NULL);
+ /*
+ * If the last directory is unlinked, then mark istart/end
+ * as -1, (to maintain the invariant that if there are no
+ * lower objects, then branch index start and end are set to
+ * -1).
+ */
+ if (!unionfs_lower_inode_idx(inode, dstart) &&
+ !unionfs_lower_inode_idx(inode, dend))
+ ibstart(inode) = ibend(inode) = -1;
d_drop(dentry);
+ }
if (namelist)
free_rdstate(namelist);