@@ -34,6 +34,7 @@
#define O_PATH 040000000
#define __O_TMPFILE 0100000000
+#define O_EMPTY_PATH 0200000000
#define F_GETLK 7
#define F_SETLK 8
@@ -19,6 +19,7 @@
#define O_PATH 020000000
#define __O_TMPFILE 040000000
+#define O_EMPTY_PATH 0100000000
#define F_GETLK64 8
#define F_SETLK64 9
@@ -37,6 +37,7 @@
#define O_PATH 0x1000000
#define __O_TMPFILE 0x2000000
+#define O_EMPTY_PATH 0x8000000
#define F_GETOWN 5 /* for sockets. */
#define F_SETOWN 6 /* for sockets. */
@@ -1027,7 +1027,7 @@ static int __init fcntl_init(void)
* Exceptions: O_NONBLOCK is a two bit define on parisc; O_NDELAY
* is defined as O_NONBLOCK on some platforms and not on others.
*/
- BUILD_BUG_ON(21 - 1 /* for O_RDONLY being 0 */ !=
+ BUILD_BUG_ON(22 - 1 /* for O_RDONLY being 0 */ !=
HWEIGHT32(
(VALID_OPEN_FLAGS & ~(O_NONBLOCK | O_NDELAY)) |
__FMODE_EXEC | __FMODE_NONOTIFY));
@@ -192,7 +192,7 @@ getname_flags(const char __user *filename, int flags, int *empty)
if (unlikely(!len)) {
if (empty)
*empty = 1;
- if (!(flags & LOOKUP_EMPTY)) {
+ if (!(flags & (LOOKUP_EMPTY | O_EMPTY_PATH))) {
putname(result);
return ERR_PTR(-ENOENT);
}
@@ -2347,7 +2347,7 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
if ((flags & (LOOKUP_RCU | LOOKUP_CACHED)) == LOOKUP_CACHED)
return ERR_PTR(-EAGAIN);
- if (!*s)
+ if (!*s && unlikely(!(flags & O_EMPTY_PATH)))
flags &= ~LOOKUP_RCU;
if (flags & LOOKUP_RCU)
rcu_read_lock();
@@ -1301,7 +1301,7 @@ static long do_sys_openat2(int dfd, const char __user *filename,
if (fd)
return fd;
- tmp = getname(filename);
+ tmp = getname_flags(filename, how->flags & O_EMPTY_PATH, NULL);
if (IS_ERR(tmp))
return PTR_ERR(tmp);
@@ -10,7 +10,7 @@
(O_RDONLY | O_WRONLY | O_RDWR | O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC | \
O_APPEND | O_NDELAY | O_NONBLOCK | __O_SYNC | O_DSYNC | \
FASYNC | O_DIRECT | O_LARGEFILE | O_DIRECTORY | O_NOFOLLOW | \
- O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE)
+ O_NOATIME | O_CLOEXEC | O_PATH | __O_TMPFILE | O_EMPTY_PATH)
/* List of all valid flags for the how->resolve argument: */
#define VALID_RESOLVE_FLAGS \
@@ -89,6 +89,10 @@
#define __O_TMPFILE 020000000
#endif
+#ifndef O_EMPTY_PATH
+#define O_EMPTY_PATH 040000000
+#endif
+
/* a horrid kludge trying to make sure that this will fail on old kernels */
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT)
@@ -89,6 +89,10 @@
#define __O_TMPFILE 020000000
#endif
+#ifndef O_EMPTY_PATH
+#define O_EMPTY_PATH 040000000
+#endif
+
/* a horrid kludge trying to make sure that this will fail on old kernels */
#define O_TMPFILE (__O_TMPFILE | O_DIRECTORY)
#define O_TMPFILE_MASK (__O_TMPFILE | O_DIRECTORY | O_CREAT)
This patch adds a new flag O_EMPTY_PATH that allows openat and open system calls to open a file referenced by fd if the path is empty, and it is very similar to the FreeBSD O_EMPTY_PATH flag. This can be beneficial in some cases since it would avoid having to grant /proc access to things like samba containers for reopening files to change flags in a race-free way. Signed-off-by: Ameer Hamza <ahamza@ixsystems.com> --- Change in v3: resolve O_EMPTY_PATH conflict with __FMODE_NONOTIFY for sparc. Change in v2: add nonconflicting values for O_EMPTY_PATH on architectures where default conflicts with existing flags. --- --- arch/alpha/include/uapi/asm/fcntl.h | 1 + arch/parisc/include/uapi/asm/fcntl.h | 1 + arch/sparc/include/uapi/asm/fcntl.h | 1 + fs/fcntl.c | 2 +- fs/namei.c | 4 ++-- fs/open.c | 2 +- include/linux/fcntl.h | 2 +- include/uapi/asm-generic/fcntl.h | 4 ++++ tools/include/uapi/asm-generic/fcntl.h | 4 ++++ 9 files changed, 16 insertions(+), 5 deletions(-)