commit 5ebfd99e69ee54b24f159812c400b5c3217d55cb
Author: Erez_Zadok <[EMAIL PROTECTED]>
Date:   Fri Nov 16 14:10:16 2007 -0500

    Unionfs: cache-coherency calls to maintain the time invariants
    
    This patch represents several types of related changes.  First, we invoke
    functions to synchronize the upper and lower times as and when needed.  Many
    of these were bug fixes which were discovered during the development of the
    cache-coherency code.  That is, Unionfs itself wasn't maintaining
    appropriate
    times in some places, which if not fixed would have been detected by the
    invariant-checking code as a false positive (incorrectly considered as if a
    user modified the lower objects directly).
    
    Second, we do not call invariant-validation functions (unionfs_check_file,
    unionfs_check_dentry, etc.) until *after* we've revalidated them.  Otherwise
    we produced false positives.
    
    Third, we pass a flag "willwrite" to __unionfs_d_revalidate_chain to tell it
    to purge data pages if the inode lower times appear to be newer.
    
    See Documentation/filesystems/unionfs/concepts.txt under the "Cache
    Coherency" section for more details of this design and implementation.
    
    Signed-off-by: Erez Zadok <[EMAIL PROTECTED]>

diff --git a/fs/unionfs/commonfops.c b/fs/unionfs/commonfops.c
index b3791a5..acda073 100644
--- a/fs/unionfs/commonfops.c
+++ b/fs/unionfs/commonfops.c
@@ -390,7 +390,7 @@ int unionfs_file_revalidate(struct file *file, int 
willwrite)
         * but not unhashed dentries.
         */
        if (!d_deleted(dentry) &&
-           !__unionfs_d_revalidate_chain(dentry, NULL)) {
+           !__unionfs_d_revalidate_chain(dentry, NULL, willwrite)) {
                err = -ESTALE;
                goto out_nofree;
        }
@@ -671,7 +671,10 @@ out:
 out_nofree:
        unionfs_read_unlock(inode->i_sb);
        unionfs_check_inode(inode);
-       unionfs_check_file(file);
+       if (!err) {
+               unionfs_check_file(file);
+               unionfs_check_dentry(file->f_dentry->d_parent);
+       }
        return err;
 }
 
@@ -684,7 +687,6 @@ int unionfs_file_release(struct inode *inode, struct file 
*file)
        int bindex, bstart, bend;
        int fgen, err = 0;
 
-       unionfs_check_file(file);
        unionfs_read_lock(sb);
        /*
         * Yes, we have to revalidate this file even if it's being released.
@@ -693,6 +695,7 @@ int unionfs_file_release(struct inode *inode, struct file 
*file)
         */
        if ((err = unionfs_file_revalidate(file, 1)))
                goto out;
+       unionfs_check_file(file);
        fileinfo = UNIONFS_F(file);
        BUG_ON(file->f_dentry->d_inode != inode);
 
@@ -852,7 +855,7 @@ int unionfs_flush(struct file *file, fl_owner_t id)
        struct dentry *dentry = file->f_dentry;
        int bindex, bstart, bend;
 
-       unionfs_read_lock(file->f_dentry->d_sb);
+       unionfs_read_lock(dentry->d_sb);
 
        if ((err = unionfs_file_revalidate(file, 1)))
                goto out;
@@ -884,10 +887,15 @@ int unionfs_flush(struct file *file, fl_owner_t id)
 
        }
 
+       /* on success, update our times */
+       unionfs_copy_attr_times(dentry->d_inode);
+       /* parent time could have changed too (async) */
+       unionfs_copy_attr_times(dentry->d_parent->d_inode);
+
 out_lock:
        unionfs_unlock_dentry(dentry);
 out:
-       unionfs_read_unlock(file->f_dentry->d_sb);
+       unionfs_read_unlock(dentry->d_sb);
        unionfs_check_file(file);
        return err;
 }
diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
index 351541c..cd33c5a 100644
--- a/fs/unionfs/copyup.c
+++ b/fs/unionfs/copyup.c
@@ -503,6 +503,8 @@ out_free:
                }
        }
        unionfs_inherit_mnt(dentry);
+       /* sync inode times from copied-up inode to our inode */
+       unionfs_copy_attr_times(dentry->d_inode);
        unionfs_check_inode(dir);
        unionfs_check_dentry(dentry);
 out:
@@ -803,6 +805,12 @@ begin:
 
        __set_inode(child_dentry, lower_dentry, bindex);
        __set_dentry(child_dentry, lower_dentry, bindex);
+       /*
+        * update times of this dentry, but also the parent, because if
+        * we changed, the parent may have changed too.
+        */
+       unionfs_copy_attr_times(parent_dentry->d_inode);
+       unionfs_copy_attr_times(child_dentry->d_inode);
 
        parent_dentry = child_dentry;
        child_dentry = path[--count];
diff --git a/fs/unionfs/dentry.c b/fs/unionfs/dentry.c
index da94cbc..d38f1ae 100644
--- a/fs/unionfs/dentry.c
+++ b/fs/unionfs/dentry.c
@@ -188,9 +188,8 @@ static int __unionfs_d_revalidate_one(struct dentry *dentry,
                 * caller (__unionfs_d_revalidate_chain) by calling
                 * purge_inode_data.
                 */
-               fsstack_copy_attr_all(dentry->d_inode,
-                                     unionfs_lower_inode(dentry->d_inode),
-                                     unionfs_get_nlinks);
+               unionfs_copy_attr_all(dentry->d_inode,
+                                     unionfs_lower_inode(dentry->d_inode));
                fsstack_copy_inode_size(dentry->d_inode,
                                        unionfs_lower_inode(dentry->d_inode));
        }
@@ -425,9 +424,8 @@ static int unionfs_d_revalidate(struct dentry *dentry, 
struct nameidata *nd)
 {
        int err;
 
-       unionfs_check_dentry(dentry);
        unionfs_lock_dentry(dentry);
-       err = __unionfs_d_revalidate_chain(dentry, nd);
+       err = __unionfs_d_revalidate_chain(dentry, nd, 0);
        unionfs_unlock_dentry(dentry);
        unionfs_check_dentry(dentry);
 
diff --git a/fs/unionfs/file.c b/fs/unionfs/file.c
index 62da4e4..df413eb 100644
--- a/fs/unionfs/file.c
+++ b/fs/unionfs/file.c
@@ -24,9 +24,9 @@ static ssize_t unionfs_read(struct file *file, char __user 
*buf,
        int err;
 
        unionfs_read_lock(file->f_dentry->d_sb);
-       unionfs_check_file(file);
        if ((err = unionfs_file_revalidate(file, 0)))
                goto out;
+       unionfs_check_file(file);
 
        err = do_sync_read(file, buf, count, ppos);
 
@@ -47,9 +47,9 @@ static ssize_t unionfs_aio_read(struct kiocb *iocb, const 
struct iovec *iov,
        struct file *file = iocb->ki_filp;
 
        unionfs_read_lock(file->f_dentry->d_sb);
-       unionfs_check_file(file);
        if ((err = unionfs_file_revalidate(file, 0)))
                goto out;
+       unionfs_check_file(file);
 
        err = generic_file_aio_read(iocb, iov, nr_segs, pos);
 
@@ -65,21 +65,26 @@ out:
        unionfs_check_file(file);
        return err;
 }
-static ssize_t unionfs_write(struct file * file, const char __user * buf,
+
+static ssize_t unionfs_write(struct file *file, const char __user *buf,
                             size_t count, loff_t *ppos)
 {
        int err = 0;
 
        unionfs_read_lock(file->f_dentry->d_sb);
-       unionfs_check_file(file);
        if ((err = unionfs_file_revalidate(file, 1)))
                goto out;
+       unionfs_check_file(file);
 
        err = do_sync_write(file, buf, count, ppos);
+       /* update our inode times upon a successful lower write */
+       if (err >= 0) {
+               unionfs_copy_attr_times(file->f_dentry->d_inode);
+               unionfs_check_file(file);
+       }
 
 out:
        unionfs_read_unlock(file->f_dentry->d_sb);
-       unionfs_check_file(file);
        return err;
 }
 
@@ -96,14 +101,12 @@ static int unionfs_mmap(struct file *file, struct 
vm_area_struct *vma)
        struct file *lower_file;
 
        unionfs_read_lock(file->f_dentry->d_sb);
-       unionfs_check_file(file);
-       if ((err = unionfs_file_revalidate(file, 1)))
-               goto out;
 
        /* This might be deferred to mmap's writepage */
        willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags);
        if ((err = unionfs_file_revalidate(file, willwrite)))
                goto out;
+       unionfs_check_file(file);
 
        /*
         * File systems which do not implement ->writepage may use
@@ -128,7 +131,12 @@ static int unionfs_mmap(struct file *file, struct 
vm_area_struct *vma)
 
 out:
        unionfs_read_unlock(file->f_dentry->d_sb);
-       unionfs_check_file(file);
+       if (!err) {
+               /* copyup could cause parent dir times to change */
+               unionfs_copy_attr_times(file->f_dentry->d_parent->d_inode);
+               unionfs_check_file(file);
+               unionfs_check_dentry(file->f_dentry->d_parent);
+       }
        return err;
 }
 
diff --git a/fs/unionfs/inode.c b/fs/unionfs/inode.c
index e3961ff..c99f325 100644
--- a/fs/unionfs/inode.c
+++ b/fs/unionfs/inode.c
@@ -41,13 +41,13 @@ static int unionfs_create(struct inode *parent, struct 
dentry *dentry,
        unionfs_lock_dentry(dentry);
 
        unionfs_lock_dentry(dentry->d_parent);
-       valid = __unionfs_d_revalidate_chain(dentry->d_parent, nd);
+       valid = __unionfs_d_revalidate_chain(dentry->d_parent, nd, 0);
        unionfs_unlock_dentry(dentry->d_parent);
        if (!valid) {
                err = -ESTALE;  /* same as what real_lookup does */
                goto out;
        }
-       valid = __unionfs_d_revalidate_chain(dentry, nd);
+       valid = __unionfs_d_revalidate_chain(dentry, nd, 0);
        /*
         * It's only a bug if this dentry was not negative and couldn't be
         * revalidated (shouldn't happen).
@@ -108,8 +108,7 @@ static int unionfs_create(struct inode *parent, struct 
dentry *dentry,
                        err = PTR_ERR(unionfs_interpose(dentry, parent->i_sb,
                                                        0));
                if (!err) {
-                       fsstack_copy_attr_times(parent,
-                                               lower_parent_dentry->d_inode);
+                       unionfs_copy_attr_times(parent);
                        fsstack_copy_inode_size(parent,
                                                lower_parent_dentry->d_inode);
                        /* update number of links on parent directory */
@@ -125,7 +124,8 @@ out:
        unionfs_read_unlock(dentry->d_sb);
 
        unionfs_check_inode(parent);
-       unionfs_check_dentry(dentry->d_parent);
+       if (!err)
+               unionfs_check_dentry(dentry->d_parent);
        unionfs_check_dentry(dentry);
        return err;
 }
@@ -160,10 +160,13 @@ static struct dentry *unionfs_lookup(struct inode *parent,
        if (!IS_ERR(ret)) {
                if (ret)
                        dentry = ret;
+               /* parent times may have changed */
+               unionfs_copy_attr_times(dentry->d_parent->d_inode);
        }
 
        unionfs_check_inode(parent);
        unionfs_check_dentry(dentry);
+       unionfs_check_dentry(dentry->d_parent);
        return ret;
 }
 
@@ -177,12 +180,12 @@ static int unionfs_link(struct dentry *old_dentry, struct 
inode *dir,
 
        unionfs_double_lock_dentry(new_dentry, old_dentry);
 
-       if (!__unionfs_d_revalidate_chain(old_dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(old_dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
        if (new_dentry->d_inode &&
-           !__unionfs_d_revalidate_chain(new_dentry, NULL)) {
+           !__unionfs_d_revalidate_chain(new_dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -284,8 +287,7 @@ check_link:
        /* Its a hard link, so use the same inode */
        new_dentry->d_inode = igrab(old_dentry->d_inode);
        d_instantiate(new_dentry, new_dentry->d_inode);
-       fsstack_copy_attr_all(dir, lower_new_dentry->d_parent->d_inode,
-                             unionfs_get_nlinks);
+       unionfs_copy_attr_all(dir, lower_new_dentry->d_parent->d_inode);
        fsstack_copy_inode_size(dir, lower_new_dentry->d_parent->d_inode);
        /* update odf, FIXME: what to do in case of err?  */
        err = odf_link(old_dentry, new_dentry);
@@ -293,6 +295,8 @@ check_link:
 
        /* propagate number of hard-links */
        old_dentry->d_inode->i_nlink = unionfs_get_nlinks(old_dentry->d_inode);
+       /* new dentry's ctime may have changed due to hard-link counts */
+       unionfs_copy_attr_times(new_dentry->d_inode);
 
 out:
        if (!new_dentry->d_inode)
@@ -322,7 +326,7 @@ static int unionfs_symlink(struct inode *dir, struct dentry 
*dentry,
        unionfs_lock_dentry(dentry);
 
        if (dentry->d_inode &&
-           !__unionfs_d_revalidate_chain(dentry, NULL)) {
+           !__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -416,7 +420,7 @@ static int unionfs_mkdir(struct inode *parent, struct 
dentry *dentry, int mode)
        unionfs_lock_dentry(dentry);
 
        if (dentry->d_inode &&
-           !__unionfs_d_revalidate_chain(dentry, NULL)) {
+           !__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -502,6 +506,8 @@ out:
 
        kfree(name);
 
+       if (!err)
+               unionfs_copy_attr_times(dentry->d_inode);
        unionfs_unlock_dentry(dentry);
        unionfs_check_inode(parent);
        unionfs_check_dentry(dentry);
@@ -519,7 +525,7 @@ static int unionfs_mknod(struct inode *dir, struct dentry 
*dentry, int mode,
        unionfs_lock_dentry(dentry);
 
        if (dentry->d_inode &&
-           !__unionfs_d_revalidate_chain(dentry, NULL)) {
+           !__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -605,7 +611,7 @@ static int unionfs_readlink(struct dentry *dentry, char 
__user *buf,
 
        unionfs_lock_dentry(dentry);
 
-       if (!__unionfs_d_revalidate_chain(dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -640,7 +646,7 @@ static void *unionfs_follow_link(struct dentry *dentry, 
struct nameidata *nd)
        unionfs_lock_dentry(dentry);
 
        if (dentry->d_inode &&
-           !__unionfs_d_revalidate_chain(dentry, nd)) {
+           !__unionfs_d_revalidate_chain(dentry, nd, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -676,7 +682,7 @@ static void unionfs_put_link(struct dentry *dentry, struct 
nameidata *nd,
                             void *cookie)
 {
        unionfs_lock_dentry(dentry);
-       if (!__unionfs_d_revalidate_chain(dentry, nd))
+       if (!__unionfs_d_revalidate_chain(dentry, nd, 0))
                printk("unionfs: put_link failed to revalidate dentry\n");
        unionfs_unlock_dentry(dentry);
 
@@ -817,6 +823,8 @@ static int unionfs_permission(struct inode *inode, int mask,
                        break;
                }
        }
+       /* sync times which may have changed (asynchronously) below */
+       unionfs_copy_attr_times(inode);
 
 out:
        if (!list_empty(&UNIONFS_SB(inode->i_sb)->rwsem.wait_list))
@@ -837,7 +845,7 @@ static int unionfs_setattr(struct dentry *dentry, struct 
iattr *ia)
 
        unionfs_lock_dentry(dentry);
 
-       if (!__unionfs_d_revalidate_chain(dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -900,12 +908,15 @@ static int unionfs_setattr(struct dentry *dentry, struct 
iattr *ia)
        }
 
        /* get the size from the first lower inode */
-       lower_inode = unionfs_lower_inode(dentry->d_inode);
-       fsstack_copy_attr_all(inode, lower_inode, unionfs_get_nlinks);
+       lower_inode = unionfs_lower_inode(inode);
+       unionfs_copy_attr_all(inode, lower_inode);
        fsstack_copy_inode_size(inode, lower_inode);
+       /* if setattr succeeded, then parent dir may have changed */
+       unionfs_copy_attr_times(dentry->d_parent->d_inode);
 out:
        unionfs_unlock_dentry(dentry);
        unionfs_check_dentry(dentry);
+       unionfs_check_dentry(dentry->d_parent);
        return err;
 }
 
diff --git a/fs/unionfs/main.c b/fs/unionfs/main.c
index cf12d49..e8eb67c 100644
--- a/fs/unionfs/main.c
+++ b/fs/unionfs/main.c
@@ -149,7 +149,7 @@ fill_i_info:
                                   lower_inode->i_rdev);
 
        /* all well, copy inode attributes */
-       fsstack_copy_attr_all(inode, lower_inode, unionfs_get_nlinks);
+       unionfs_copy_attr_all(inode, lower_inode);
        fsstack_copy_inode_size(inode, lower_inode);
 
        if(spliced)
diff --git a/fs/unionfs/mmap.c b/fs/unionfs/mmap.c
index f5a1242..7b4a6f5 100644
--- a/fs/unionfs/mmap.c
+++ b/fs/unionfs/mmap.c
@@ -88,19 +88,16 @@ int unionfs_writepage(struct page *page, struct 
writeback_control *wbc)
        err = lower_inode->i_mapping->a_ops->writepage(lower_page, wbc);
        wbc->for_writepages = saved_for_writepages; /* restore value */
 
-       /*
-        * update mtime and ctime of lower level file system
-        * unionfs' mtime and ctime are updated by generic_file_write
-        */
-       lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
-
        /* b/c grab_cache_page increased refcnt */
        page_cache_release(lower_page);
 
        if (err)
                ClearPageUptodate(page);
-       else
+       else {
                SetPageUptodate(page);
+               /* lower mtimes has changed: update ours */
+               unionfs_copy_attr_times(inode);
+       }
 
 out:
        unlock_page(page);
@@ -204,15 +201,17 @@ int unionfs_readpage(struct file *file, struct page *page)
        int err;
 
        unionfs_read_lock(file->f_dentry->d_sb);
-       unionfs_check_file(file);
        if ((err = unionfs_file_revalidate(file, 0)))
                goto out;
+       unionfs_check_file(file);
 
        err = unionfs_do_readpage(file, page);
 
-       if (!err)
+       if (!err) {
                touch_atime(unionfs_lower_mnt(file->f_path.dentry),
                            unionfs_lower_dentry(file->f_path.dentry));
+               unionfs_copy_attr_times(file->f_dentry->d_inode);
+       }
 
        /*
         * we have to unlock our page, b/c we _might_ have gotten a locked
@@ -233,7 +232,18 @@ int unionfs_prepare_write(struct file *file, struct page 
*page, unsigned from,
        int err;
 
        unionfs_read_lock(file->f_dentry->d_sb);
-       unionfs_check_file(file);
+       /*
+        * This is the only place where we unconditionally copy the lower
+        * attribute times before calling unionfs_file_revalidate.  The
+        * reason is that our ->write calls do_sync_write which in turn will
+        * call our ->prepare_write and then ->commit_write.  Before our
+        * ->write is called, the lower mtimes are in sync, but by the time
+        * the VFS calls our ->commit_write, the lower mtimes have changed.
+        * Therefore, the only reasonable time for us to sync up from the
+        * changed lower mtimes, and avoid an invariant violation warning,
+        * is here, in ->prepare_write.
+        */
+       unionfs_copy_attr_times(file->f_dentry->d_inode);
        err = unionfs_file_revalidate(file, 1);
        unionfs_check_file(file);
        unionfs_read_unlock(file->f_dentry->d_sb);
@@ -255,9 +265,9 @@ int unionfs_commit_write(struct file *file, struct page 
*page, unsigned from,
        BUG_ON(file == NULL);
 
        unionfs_read_lock(file->f_dentry->d_sb);
-       unionfs_check_file(file);
        if ((err = unionfs_file_revalidate(file, 1)))
                goto out;
+       unionfs_check_file(file);
 
        inode = page->mapping->host;
        lower_inode = unionfs_lower_inode(inode);
@@ -294,13 +304,8 @@ int unionfs_commit_write(struct file *file, struct page 
*page, unsigned from,
        pos = ((loff_t) page->index << PAGE_CACHE_SHIFT) + to;
        if (pos > i_size_read(inode))
                i_size_write(inode, pos);
-
-       /*
-        * update mtime and ctime of lower level file system
-        * unionfs' mtime and ctime are updated by generic_file_write
-        */
-       lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME;
-
+       /* if vfs_write succeeded above, sync up our times */
+       unionfs_copy_attr_times(inode);
        mark_inode_dirty_sync(inode);
 
 out:
diff --git a/fs/unionfs/rename.c b/fs/unionfs/rename.c
index 2488ebe..3a4827a 100644
--- a/fs/unionfs/rename.c
+++ b/fs/unionfs/rename.c
@@ -349,12 +349,12 @@ int unionfs_rename(struct inode *old_dir, struct dentry 
*old_dentry,
 
        unionfs_double_lock_dentry(old_dentry, new_dentry);
 
-       if (!__unionfs_d_revalidate_chain(old_dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(old_dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
        if (!d_deleted(new_dentry) && new_dentry->d_inode &&
-           !__unionfs_d_revalidate_chain(new_dentry, NULL)) {
+           !__unionfs_d_revalidate_chain(new_dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -453,6 +453,11 @@ out:
                        }
                }
 
+               /* if all of this renaming succeeded, update our times */
+               unionfs_copy_attr_times(old_dir);
+               unionfs_copy_attr_times(new_dir);
+               unionfs_copy_attr_times(old_dentry->d_inode);
+               unionfs_copy_attr_times(new_dentry->d_inode);
                unionfs_check_inode(old_dir);
                unionfs_check_inode(new_dir);
                unionfs_check_dentry(old_dentry);
diff --git a/fs/unionfs/super.c b/fs/unionfs/super.c
index 7859609..bb0f9d4 100644
--- a/fs/unionfs/super.c
+++ b/fs/unionfs/super.c
@@ -117,13 +117,13 @@ static int unionfs_statfs(struct dentry *dentry, struct 
kstatfs *buf)
        struct super_block *sb;
        struct dentry *lower_dentry;
 
-       unionfs_check_dentry(dentry);
        unionfs_lock_dentry(dentry);
 
-       if (!__unionfs_d_revalidate_chain(dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
+       unionfs_check_dentry(dentry);
 
        sb = dentry->d_sb;
 
diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c
index 53259bb..b0d7be9 100644
--- a/fs/unionfs/unlink.c
+++ b/fs/unionfs/unlink.c
@@ -49,6 +49,9 @@ static int unionfs_do_unlink(struct inode *dir, struct dentry 
*dentry)
                                         lower_dentry);
                else
                        err = -EROFS;
+               /* if vfs_unlink succeeded, update our inode's times */
+               if (!err)
+                       unionfs_copy_attr_times(dentry->d_inode);
                dput(lower_dentry);
                fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);
                unlock_dir(lower_dir_dentry);
@@ -99,13 +102,13 @@ int unionfs_unlink(struct inode *dir, struct dentry 
*dentry)
 {
        int err = 0;
 
-       unionfs_check_dentry(dentry);
        unionfs_lock_dentry(dentry);
 
-       if (!__unionfs_d_revalidate_chain(dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
+       unionfs_check_dentry(dentry);
 
        err = unionfs_do_unlink(dir, dentry);
 
@@ -123,11 +126,19 @@ int unionfs_unlink(struct inode *dir, struct dentry 
*dentry)
        if (!err) {
                if (!S_ISDIR(dentry->d_inode->i_mode))
                        unionfs_purge_extras(dentry);
-               unionfs_check_dentry(dentry);
                d_drop(dentry);
+               /*
+                * if unlink/whiteout succeeded, parent dir mtime has
+                * changed
+                */
+               unionfs_copy_attr_times(dir);
        }
 
 out:
+       if (!err) {
+               unionfs_check_dentry(dentry);
+               unionfs_check_inode(dir);
+       }
        unionfs_unlock_dentry(dentry);
        return err;
 }
@@ -212,13 +223,13 @@ int unionfs_rmdir(struct inode *dir, struct dentry 
*dentry)
        int err = 0;
        struct unionfs_dir_state *namelist = NULL;
 
-       unionfs_check_dentry(dentry);
        unionfs_lock_dentry(dentry);
 
-       if (!__unionfs_d_revalidate_chain(dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
+       unionfs_check_dentry(dentry);
 
        /* check if this unionfs directory is empty or not */
        err = check_empty(dentry, &namelist);
diff --git a/fs/unionfs/xattr.c b/fs/unionfs/xattr.c
index 02a87c5..b5ae59c 100644
--- a/fs/unionfs/xattr.c
+++ b/fs/unionfs/xattr.c
@@ -59,7 +59,7 @@ ssize_t unionfs_getxattr(struct dentry *dentry, const char 
*name, void *value,
 
        unionfs_lock_dentry(dentry);
 
-       if (!__unionfs_d_revalidate_chain(dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -86,7 +86,7 @@ int unionfs_setxattr(struct dentry *dentry, const char *name,
 
        unionfs_lock_dentry(dentry);
 
-       if (!__unionfs_d_revalidate_chain(dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -113,7 +113,7 @@ int unionfs_removexattr(struct dentry *dentry, const char 
*name)
 
        unionfs_lock_dentry(dentry);
 
-       if (!__unionfs_d_revalidate_chain(dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
@@ -140,7 +140,7 @@ ssize_t unionfs_listxattr(struct dentry *dentry, char 
*list, size_t size)
 
        unionfs_lock_dentry(dentry);
 
-       if (!__unionfs_d_revalidate_chain(dentry, NULL)) {
+       if (!__unionfs_d_revalidate_chain(dentry, NULL, 0)) {
                err = -ESTALE;
                goto out;
        }
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs

Reply via email to