When files on an upper layer of the union stack are removed we need to white-out the removed filename. Signed-off-by: Jan Blunck --- fs/namei.c | 46 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 44 insertions(+), 2 deletions(-) --- a/fs/namei.c +++ b/fs/namei.c @@ -2253,6 +2253,13 @@ do_last: /* Negative dentry, just create the file */ if (!path.dentry->d_inode || S_ISWHT(path.dentry->d_inode->i_mode)) { + if (path.dentry->d_parent != dir) { + dput_path(&path, nd); + path.dentry = __lookup_hash_kern(&nd->last, dir, nd); + path.mnt = nd->mnt; + goto do_last; + } + error = open_namei_create(nd, &path, flag, mode); if (error) goto exit; @@ -2373,6 +2380,16 @@ int lookup_create(struct nameidata *nd, { int err = -EEXIST; + if (is_unionized(nd->dentry, nd->mnt)) { + err = union_relookup_topmost(nd, nd->flags & ~LOOKUP_PARENT); + if (err) { + /* FIXME: This really sucks */ + mutex_lock_nested(&nd->dentry->d_inode->i_mutex, + I_MUTEX_PARENT); + goto fail; + } + } + mutex_lock_nested(&nd->dentry->d_inode->i_mutex, I_MUTEX_PARENT); /* * Yucky last component or no last component at all? @@ -2391,6 +2408,16 @@ int lookup_create(struct nameidata *nd, if (err) goto fail; + /* Special case - we found a whiteout */ + if (path->dentry->d_inode && S_ISWHT(path->dentry->d_inode->i_mode)) { + if (path->dentry->d_parent != nd->dentry) { + dput_path(path, nd); + path->dentry = __lookup_hash_kern(&nd->last, nd->dentry, + nd); + path->mnt = nd->mnt; + } + } + /* * Special case - lookup gave negative, but... we had foo/bar/ * From the vfs_mknod() POV we just have a negative dentry - @@ -2682,6 +2709,15 @@ static int do_whiteout(struct nameidata if (isdir && !directory_is_empty(path->dentry, path->mnt)) goto out; + mutex_unlock(&nd->dentry->d_inode->i_mutex); + err = union_relookup_topmost(nd, nd->flags & ~LOOKUP_PARENT); + if (err) { + mutex_lock_nested(&nd->dentry->d_inode->i_mutex, + I_MUTEX_PARENT); + goto out; + } + mutex_lock_nested(&nd->dentry->d_inode->i_mutex, I_MUTEX_PARENT); + /* safe the name for a later lookup */ err = -ENOMEM; name.name = kmalloc(dentry->d_name.len, GFP_KERNEL); @@ -3012,7 +3048,10 @@ static long do_rmdir(int dfd, const char error = hash_lookup_union(&nd, &nd.last, &path); if (error) goto exit2; - error = vfs_rmdir(nd.dentry->d_inode, path.dentry); + if (is_unionized(nd.dentry, nd.mnt)) + error = do_whiteout(&nd, &path, 1); + else + error = vfs_rmdir(nd.dentry->d_inode, path.dentry); dput_path(&path, &nd); exit2: mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -3091,7 +3130,10 @@ static long do_unlinkat(int dfd, const c inode = path.dentry->d_inode; if (inode) atomic_inc(&inode->i_count); - error = vfs_unlink(nd.dentry->d_inode, path.dentry); + if (is_unionized(nd.dentry, nd.mnt)) + error = do_whiteout(&nd, &path, 0); + else + error = vfs_unlink(nd.dentry->d_inode, path.dentry); exit2: dput_path(&path, &nd); } -- - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/