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: Miklos Szeredi <mszeredi@suse.cz> Cc: Hugh Dickins <hughd@google.com>
This commit is contained in:
Родитель
cd808deced
Коммит
46fdb794e3
36
mm/shmem.c
36
mm/shmem.c
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
|
Загрузка…
Ссылка в новой задаче