Unionfs: release lower resources on successful rmdir
authorRachita Kothiyal <rachita@dewey.fsl.cs.sunysb.edu>
Sun, 25 Nov 2007 22:55:36 +0000 (17:55 -0500)
committerRachita Kothiyal <rachita@dewey.fsl.cs.sunysb.edu>
Thu, 1 May 2008 23:03:22 +0000 (19:03 -0400)
This patch prevents those resources from lingering around until memory
pressure would have forced them out.  The patch also properly handles
directories that have been rmdir'ed which are still some process's cwd.

CC: Hugh Dickins <hugh@veritas.com>
Signed-off-by: Erez Zadok <ezk@cs.sunysb.edu>
Conflicts:

fs/unionfs/unlink.c

fs/unionfs/inode.c
fs/unionfs/mmap.c
fs/unionfs/unlink.c

index c646c80f678b712b5ff77f0370e96da8b4cfff36..149f7032744d138ebee81e5aa40f0b0baacbded7 100644 (file)
@@ -764,7 +764,8 @@ static int unionfs_permission(struct inode *inode, int mask,
                 * 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;
        }
 
index 1e10280a767ea7729b469b2d7888a67421de75b2..3f65e524f0df9ad7adda13800a483aaf8a3e6458 100644 (file)
@@ -123,8 +123,11 @@ static int unionfs_writepages(struct address_space *mapping,
        struct inode *inode;
 
        inode = mapping->host;
+       if (ibstart(inode) < 0 && ibend(inode) < 0)
+               goto out;
        lower_inode = unionfs_lower_inode(inode);
-       BUG_ON(!lower_inode);
+       if (!lower_inode)
+               goto out;
 
        if (!mapping_cap_writeback_dirty(lower_inode->i_mapping))
                goto out;
index f2b43f0547844507101f0f5c04aa367bbab7be80..8bad9bce7cc200ad073a3f92ea357842430a99e7 100644 (file)
@@ -228,6 +228,7 @@ int unionfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int err = 0;
        struct unionfs_dir_state *namelist = NULL;
+       int dstart, dend;
 
        unionfs_read_lock(dentry->d_sb);
        unionfs_lock_dentry(dentry);
@@ -250,9 +251,29 @@ int unionfs_rmdir(struct inode *dir, struct 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);