Commit 46fdb794 authored by Miklos Szeredi's avatar Miklos Szeredi

shmem: support RENAME_WHITEOUT

Allocate a dentry, initialize it with a whiteout and hash it in the place
of the old dentry.  Later the old dentry will be moved away and the
whiteout will remain.

i_mutex protects agains concurrent readdir.
Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
Cc: Hugh Dickins <hughd@google.com>
parent cd808dec
...@@ -2345,6 +2345,32 @@ static int shmem_exchange(struct inode *old_dir, struct dentry *old_dentry, stru ...@@ -2345,6 +2345,32 @@ static int shmem_exchange(struct inode *old_dir, struct dentry *old_dentry, stru
return 0; return 0;
} }
static int shmem_whiteout(struct inode *old_dir, struct dentry *old_dentry)
{
struct dentry *whiteout;
int error;
whiteout = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
if (!whiteout)
return -ENOMEM;
error = shmem_mknod(old_dir, whiteout,
S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV);
dput(whiteout);
if (error)
return error;
/*
* Cheat and hash the whiteout while the old dentry is still in
* place, instead of playing games with FS_RENAME_DOES_D_MOVE.
*
* d_lookup() will consistently find one of them at this point,
* not sure which one, but that isn't even important.
*/
d_rehash(whiteout);
return 0;
}
/* /*
* The VFS layer already does all the dentry stuff for rename, * The VFS layer already does all the dentry stuff for rename,
* we just have to decrement the usage count for the target if * we just have to decrement the usage count for the target if
...@@ -2356,7 +2382,7 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc ...@@ -2356,7 +2382,7 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc
struct inode *inode = old_dentry->d_inode; struct inode *inode = old_dentry->d_inode;
int they_are_dirs = S_ISDIR(inode->i_mode); int they_are_dirs = S_ISDIR(inode->i_mode);
if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
return -EINVAL; return -EINVAL;
if (flags & RENAME_EXCHANGE) if (flags & RENAME_EXCHANGE)
...@@ -2365,6 +2391,14 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc ...@@ -2365,6 +2391,14 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc
if (!simple_empty(new_dentry)) if (!simple_empty(new_dentry))
return -ENOTEMPTY; return -ENOTEMPTY;
if (flags & RENAME_WHITEOUT) {
int error;
error = shmem_whiteout(old_dir, old_dentry);
if (error)
return error;
}
if (new_dentry->d_inode) { if (new_dentry->d_inode) {
(void) shmem_unlink(new_dir, new_dentry); (void) shmem_unlink(new_dir, new_dentry);
if (they_are_dirs) { if (they_are_dirs) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment