Unionfs: implement d_iput method
authorErez Zadok <ezk@cs.sunysb.edu>
Fri, 28 Dec 2007 00:05:05 +0000 (19:05 -0500)
committerErez Zadok <ezk@cs.sunysb.edu>
Fri, 29 Apr 2011 02:25:42 +0000 (22:25 -0400)
This is needed to drop lower objects early enough, under certain conditions,
so the lower objects don't stay behind until umount(). [LTP testing]

Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
fs/unionfs/dentry.c

index 0e893085efec6dd79fcd4bd1c31ae34ffba2b341..0369d938b960d192d2710804b157048e71fab07e 100644 (file)
@@ -484,7 +484,49 @@ out:
        return;
 }
 
+/*
+ * Called when we're removing the last reference to our dentry.  So we
+ * should drop all lower references too.
+ */
+static void unionfs_d_iput(struct dentry *dentry, struct inode *inode)
+{
+       int bindex, rc;
+
+       unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD);
+
+       if (dbstart(dentry) < 0)
+               goto drop_lower_inodes;
+       for (bindex = dbstart(dentry); bindex <= dbend(dentry); bindex++) {
+               if (unionfs_lower_mnt_idx(dentry, bindex)) {
+                       unionfs_mntput(dentry, bindex);
+                       unionfs_set_lower_mnt_idx(dentry, bindex, NULL);
+               }
+               if (unionfs_lower_dentry_idx(dentry, bindex)) {
+                       dput(unionfs_lower_dentry_idx(dentry, bindex));
+                       unionfs_set_lower_dentry_idx(dentry, bindex, NULL);
+               }
+       }
+       set_dbstart(dentry, -1);
+       set_dbend(dentry, -1);
+
+drop_lower_inodes:
+       rc = atomic_read(&inode->i_count);
+       if (rc == 1 && inode->i_nlink == 1 && ibstart(inode) >= 0) {
+               /* see Documentation/filesystems/unionfs/issues.txt */
+               lockdep_off();
+               iput(unionfs_lower_inode(inode));
+               lockdep_on();
+               unionfs_set_lower_inode(inode, NULL);
+               /* XXX: may need to set start/end to -1? */
+       }
+
+       iput(inode);
+
+       unionfs_read_unlock(dentry->d_sb);
+}
+
 struct dentry_operations unionfs_dops = {
        .d_revalidate   = unionfs_d_revalidate,
        .d_release      = unionfs_d_release,
+       .d_iput         = unionfs_d_iput,
 };