aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2014-10-23 18:14:37 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2014-10-23 18:14:37 -0400
commit46fdb794e3f52ef18b859ebc92f0a9d7db21c5df (patch)
tree293f678cfc7e83ee5c901071b0f8fbab11b84c78
parentcd808deced431b66b5fa4e5c193cb7ec0059eaff (diff)
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>
-rw-r--r--mm/shmem.c36
1 files changed, 35 insertions, 1 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index cd6fc7590e54..185836ba53ef 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -2345,6 +2345,32 @@ static int shmem_exchange(struct inode *old_dir, struct dentry *old_dentry, stru
2345 return 0; 2345 return 0;
2346} 2346}
2347 2347
2348static int shmem_whiteout(struct inode *old_dir, struct dentry *old_dentry)
2349{
2350 struct dentry *whiteout;
2351 int error;
2352
2353 whiteout = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
2354 if (!whiteout)
2355 return -ENOMEM;
2356
2357 error = shmem_mknod(old_dir, whiteout,
2358 S_IFCHR | WHITEOUT_MODE, WHITEOUT_DEV);
2359 dput(whiteout);
2360 if (error)
2361 return error;
2362
2363 /*
2364 * Cheat and hash the whiteout while the old dentry is still in
2365 * place, instead of playing games with FS_RENAME_DOES_D_MOVE.
2366 *
2367 * d_lookup() will consistently find one of them at this point,
2368 * not sure which one, but that isn't even important.
2369 */
2370 d_rehash(whiteout);
2371 return 0;
2372}
2373
2348/* 2374/*
2349 * The VFS layer already does all the dentry stuff for rename, 2375 * The VFS layer already does all the dentry stuff for rename,
2350 * we just have to decrement the usage count for the target if 2376 * 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 struct inode *inode = old_dentry->d_inode; 2382 struct inode *inode = old_dentry->d_inode;
2357 int they_are_dirs = S_ISDIR(inode->i_mode); 2383 int they_are_dirs = S_ISDIR(inode->i_mode);
2358 2384
2359 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE)) 2385 if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
2360 return -EINVAL; 2386 return -EINVAL;
2361 2387
2362 if (flags & RENAME_EXCHANGE) 2388 if (flags & RENAME_EXCHANGE)
@@ -2365,6 +2391,14 @@ static int shmem_rename2(struct inode *old_dir, struct dentry *old_dentry, struc
2365 if (!simple_empty(new_dentry)) 2391 if (!simple_empty(new_dentry))
2366 return -ENOTEMPTY; 2392 return -ENOTEMPTY;
2367 2393
2394 if (flags & RENAME_WHITEOUT) {
2395 int error;
2396
2397 error = shmem_whiteout(old_dir, old_dentry);
2398 if (error)
2399 return error;
2400 }
2401
2368 if (new_dentry->d_inode) { 2402 if (new_dentry->d_inode) {
2369 (void) shmem_unlink(new_dir, new_dentry); 2403 (void) shmem_unlink(new_dir, new_dentry);
2370 if (they_are_dirs) { 2404 if (they_are_dirs) {