Skip to content

Commit

Permalink
shmem: support RENAME_WHITEOUT
Browse files Browse the repository at this point in the history
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: Miklos Szeredi <mszeredi@suse.cz>
Cc: Hugh Dickins <hughd@google.com>
  • Loading branch information
Miklos Szeredi committed Oct 23, 2014
1 parent cd808de commit 46fdb79
Showing 1 changed file with 35 additions and 1 deletion.
36 changes: 35 additions & 1 deletion mm/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -2345,6 +2345,32 @@ static int shmem_exchange(struct inode *old_dir, struct dentry *old_dentry, stru
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,
* we just have to decrement the usage count for the target if
Expand All @@ -2356,7 +2382,7 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc
struct inode *inode = old_dentry->d_inode;
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;

if (flags & RENAME_EXCHANGE)
Expand All @@ -2365,6 +2391,14 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc
if (!simple_empty(new_dentry))
return -ENOTEMPTY;

if (flags & RENAME_WHITEOUT) {
int error;

error = shmem_whiteout(old_dir, old_dentry);
if (error)
return error;
}

if (new_dentry->d_inode) {
(void) shmem_unlink(new_dir, new_dentry);
if (they_are_dirs) {
Expand Down

0 comments on commit 46fdb79

Please sign in to comment.