commit 4297fdd0702d856f7d5d05d9af7185b30f701c7d
Author: Erez Zadok <[EMAIL PROTECTED]>
Date:   Sun Nov 25 18:31:46 2007 -0500

    Unionfs: release lower resources on successful rmdir
    
    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 <[EMAIL PROTECTED]>
    
    Signed-off-by: Erez Zadok <[EMAIL PROTECTED]>

diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index a8f3590..77c7f33 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -933,7 +933,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;
        }
 
diff --git a/fs/unionfs/mmap.c b/fs/unionfs/mmap.c
index b97a737..b836abb 100644
--- a/fs/unionfs/mmap.c
+++ b/fs/unionfs/mmap.c
@@ -155,8 +155,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;
diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c
index a8de672..f65245d 100644
--- a/fs/unionfs/unlink.c
+++ b/fs/unionfs/unlink.c
@@ -148,6 +148,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);
@@ -164,28 +165,50 @@ int unionfs_rmdir(struct inode *dir, struct dentry 
*dentry)
                goto out;
 
        err = unionfs_rmdir_first(dir, dentry, namelist);
+       dstart = dbstart(dentry);
+       dend = dbend(dentry);
        /* create whiteout */
        if (!err) {
-               err = create_whiteout(dentry, dbstart(dentry));
+               err = create_whiteout(dentry, dstart);
        } else {
                int new_err;
 
-               if (dbstart(dentry) == 0)
+               if (dstart == 0)
                        goto out;
 
                /* exit if the error returned was NOT -EROFS */
                if (!IS_COPYUP_ERR(err))
                        goto out;
 
-               new_err = create_whiteout(dentry, dbstart(dentry) - 1);
+               new_err = create_whiteout(dentry, dstart - 1);
                if (new_err != -EEXIST)
                        err = new_err;
        }
 
 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);
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to