summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@suse.cz>2014-10-24 00:14:37 +0200
committerMiklos Szeredi <mszeredi@suse.cz>2014-10-24 00:14:37 +0200
commit0d7a855526dd672e114aff2ac22b60fc6f155b08 (patch)
tree5354ed84bddf7ca55c6cdd3509a71fd8e0bcf63e
parent787fb6bc9682ec7c05fb5d9561b57100fbc1cc41 (diff)
vfs: add RENAME_WHITEOUT
This adds a new RENAME_WHITEOUT flag. This flag makes rename() create a whiteout of source. The whiteout creation is atomic relative to the rename. Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
-rw-r--r--fs/namei.c8
-rw-r--r--include/uapi/linux/fs.h1
2 files changed, 7 insertions, 2 deletions
diff --git a/fs/namei.c b/fs/namei.c
index d20191c0ebf5..42df664e95e5 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -4209,12 +4209,16 @@ SYSCALL_DEFINE5(renameat2, int, olddfd, const char __user *, oldname,
bool should_retry = false;
int error;
- if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE))
+ if (flags & ~(RENAME_NOREPLACE | RENAME_EXCHANGE | RENAME_WHITEOUT))
return -EINVAL;
- if ((flags & RENAME_NOREPLACE) && (flags & RENAME_EXCHANGE))
+ if ((flags & (RENAME_NOREPLACE | RENAME_WHITEOUT)) &&
+ (flags & RENAME_EXCHANGE))
return -EINVAL;
+ if ((flags & RENAME_WHITEOUT) && !capable(CAP_MKNOD))
+ return -EPERM;
+
retry:
from = user_path_parent(olddfd, oldname, &oldnd, lookup_flags);
if (IS_ERR(from)) {
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index ca1a11bb4443..3735fa0a6784 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -37,6 +37,7 @@
#define RENAME_NOREPLACE (1 << 0) /* Don't overwrite target */
#define RENAME_EXCHANGE (1 << 1) /* Exchange source and dest */
+#define RENAME_WHITEOUT (1 << 2) /* Whiteout source */
struct fstrim_range {
__u64 start;