[RFC 22/26] union-mount: white-out changes for copy-on-open
From: Jan Blunck
Date: Mon Jul 30 2007 - 12:24:27 EST
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 <jblunck@xxxxxxx>
---
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@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/