From dd6595e90768ea30a0a41d96ceb5da3cc1916bd2 Mon Sep 17 00:00:00 2001 From: Alexey Makhalov <amakhalov@vmware.com> Date: Wed, 16 Aug 2017 21:14:17 +0000 Subject: [PATCH] Implement the f*xattrat family of functions Inspired by https://lkml.org/lkml/2014/1/21/266 --- arch/x86/entry/syscalls/syscall_64.tbl | 4 ++ fs/xattr.c | 123 +++++++++++++++++++++++++++++++++ include/linux/syscalls.h | 11 ++- 4 files changed, 141 insertions(+), 1 deletion(-) diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index 314a90b..3c2dfa1 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -339,6 +339,14 @@ 330 common pkey_alloc sys_pkey_alloc 331 common pkey_free sys_pkey_free + +# +# Photon OS specific syscalls. +# +508 common fsetxattrat sys_fsetxattrat +509 common fgetxattrat sys_fgetxattrat +510 common flistxattrat sys_flistxattrat +511 common fremovexattrat sys_fremovexattrat # # x32-specific system call numbers start at 512 to avoid cache impact # for native 64-bit operation. diff --git a/fs/xattr.c b/fs/xattr.c index f0da9d2..d5e4944 100644 --- a/fs/xattr.c +++ b/fs/xattr.c @@ -419,6 +419,41 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name, return error; } +SYSCALL_DEFINE6(fsetxattrat, int, fd, const char __user *, pathname, + const char __user *, name, const void __user *, value, + size_t, size, int, flags) +{ + struct path path; + int error; + unsigned int lookup_flags = 0; + + if (flags & ~(XATTR_CREATE | XATTR_REPLACE | + AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) + return -EINVAL; + + if (!(flags & AT_SYMLINK_NOFOLLOW)) + lookup_flags |= LOOKUP_FOLLOW; + if (flags & AT_EMPTY_PATH) + lookup_flags |= LOOKUP_EMPTY; + +retry: + error = user_path_at(fd, pathname, lookup_flags, &path); + if (error) + return error; + error = mnt_want_write(path.mnt); + if (!error) { + error = setxattr(path.dentry, name, value, size, + flags & (XATTR_CREATE | XATTR_REPLACE)); + mnt_drop_write(path.mnt); + } + path_put(&path); + if (retry_estale(error, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } + return error; +} + /* * Extended attribute GET operations */ @@ -513,6 +548,35 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name, return error; } +SYSCALL_DEFINE6(fgetxattrat, int, fd, const char __user *, pathname, + const char __user *, name, void __user *, value, size_t, size, + int, flags) +{ + struct path path; + ssize_t error; + unsigned int lookup_flags = 0; + + if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) + return -EINVAL; + + if (!(flags & AT_SYMLINK_NOFOLLOW)) + lookup_flags |= LOOKUP_FOLLOW; + if (flags & AT_EMPTY_PATH) + lookup_flags |= LOOKUP_EMPTY; + +retry: + error = user_path_at(fd, pathname, lookup_flags, &path); + if (error) + return error; + error = getxattr(path.dentry, name, value, size); + path_put(&path); + if (retry_estale(error, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } + return error; +} + /* * Extended attribute LIST operations */ @@ -594,6 +658,34 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size) return error; } +SYSCALL_DEFINE5(flistxattrat, int, fd, const char __user *, pathname, + char __user *, list, size_t, size, int, flags) +{ + struct path path; + ssize_t error; + unsigned int lookup_flags = 0; + + if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) + return -EINVAL; + + if (!(flags & AT_SYMLINK_NOFOLLOW)) + lookup_flags |= LOOKUP_FOLLOW; + if (flags & AT_EMPTY_PATH) + lookup_flags |= LOOKUP_EMPTY; + +retry: + error = user_path_at(fd, pathname, lookup_flags, &path); + if (error) + return error; + error = listxattr(path.dentry, list, size); + path_put(&path); + if (retry_estale(error, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } + return error; +} + /* * Extended attribute REMOVE operations */ @@ -663,6 +755,38 @@ SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name) return error; } +SYSCALL_DEFINE4(fremovexattrat, int, fd, const char __user *, pathname, + const char __user *, name, int, flags) +{ + struct path path; + int error; + unsigned int lookup_flags = 0; + + if (flags & ~(AT_SYMLINK_NOFOLLOW | AT_EMPTY_PATH)) + return -EINVAL; + + if (!(flags & AT_SYMLINK_NOFOLLOW)) + lookup_flags |= LOOKUP_FOLLOW; + if (flags & AT_EMPTY_PATH) + lookup_flags |= LOOKUP_EMPTY; + +retry: + error = user_path_at(fd, pathname, lookup_flags, &path); + if (error) + return error; + error = mnt_want_write(path.mnt); + if (!error) { + error = removexattr(path.dentry, name); + mnt_drop_write(path.mnt); + } + path_put(&path); + if (retry_estale(error, lookup_flags)) { + lookup_flags |= LOOKUP_REVAL; + goto retry; + } + return error; +} + /* * Combine the results of the list() operation from every xattr_handler in the * list. diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index c2b66a2..daf1856 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h @@ -430,23 +430,32 @@ asmlinkage long sys_lsetxattr(const char __user *path, const char __user *name, const void __user *value, size_t size, int flags); asmlinkage long sys_fsetxattr(int fd, const char __user *name, const void __user *value, size_t size, int flags); +asmlinkage long sys_fsetxattrat(int fd, const char __user *pathname, + const char __user *name, + const void __user *value, size_t size, int flags); asmlinkage long sys_getxattr(const char __user *path, const char __user *name, void __user *value, size_t size); asmlinkage long sys_lgetxattr(const char __user *path, const char __user *name, void __user *value, size_t size); asmlinkage long sys_fgetxattr(int fd, const char __user *name, void __user *value, size_t size); +asmlinkage long sys_fgetxattrat(int fd, const char __user *pathname, + const char __user *name, + void __user *value, size_t size, int flags); asmlinkage long sys_listxattr(const char __user *path, char __user *list, size_t size); asmlinkage long sys_llistxattr(const char __user *path, char __user *list, size_t size); asmlinkage long sys_flistxattr(int fd, char __user *list, size_t size); +asmlinkage long sys_flistxattrat(int fd, const char __user *pathname, + char __user *list, size_t size, int flags); asmlinkage long sys_removexattr(const char __user *path, const char __user *name); asmlinkage long sys_lremovexattr(const char __user *path, const char __user *name); asmlinkage long sys_fremovexattr(int fd, const char __user *name); - +asmlinkage long sys_fremovexattrat(int fd, const char __user *pathname, + const char __user *name, int flags); asmlinkage long sys_brk(unsigned long brk); asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot); -- 2.8.1