diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2016-04-20 17:08:21 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2016-05-02 19:49:28 -0400 |
commit | 63b6df14134ddd048984c8afadb46e721815bfc6 (patch) | |
tree | 7fecdc7f3ee6d9780b3fa5328a0acd1bb739b16e | |
parent | 9902af79c01a8e39bb99b922fa3eef6d4ea23d69 (diff) |
give readdir(2)/getdents(2)/etc. uniform exclusion with lseek()
same as read() on regular files has, and for the same reason.
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | arch/alpha/kernel/osf_sys.c | 4 | ||||
-rw-r--r-- | fs/compat.c | 12 | ||||
-rw-r--r-- | fs/file.c | 5 | ||||
-rw-r--r-- | fs/open.c | 2 | ||||
-rw-r--r-- | fs/read_write.c | 12 | ||||
-rw-r--r-- | fs/readdir.c | 12 | ||||
-rw-r--r-- | include/linux/file.h | 13 |
7 files changed, 33 insertions, 27 deletions
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c index 6cc08166ff00..ffb93f499c83 100644 --- a/arch/alpha/kernel/osf_sys.c +++ b/arch/alpha/kernel/osf_sys.c | |||
@@ -147,7 +147,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd, | |||
147 | long __user *, basep) | 147 | long __user *, basep) |
148 | { | 148 | { |
149 | int error; | 149 | int error; |
150 | struct fd arg = fdget(fd); | 150 | struct fd arg = fdget_pos(fd); |
151 | struct osf_dirent_callback buf = { | 151 | struct osf_dirent_callback buf = { |
152 | .ctx.actor = osf_filldir, | 152 | .ctx.actor = osf_filldir, |
153 | .dirent = dirent, | 153 | .dirent = dirent, |
@@ -164,7 +164,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd, | |||
164 | if (count != buf.count) | 164 | if (count != buf.count) |
165 | error = count - buf.count; | 165 | error = count - buf.count; |
166 | 166 | ||
167 | fdput(arg); | 167 | fdput_pos(arg); |
168 | return error; | 168 | return error; |
169 | } | 169 | } |
170 | 170 | ||
diff --git a/fs/compat.c b/fs/compat.c index a71936a3f4cb..8754e9aa14ad 100644 --- a/fs/compat.c +++ b/fs/compat.c | |||
@@ -884,7 +884,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, | |||
884 | struct compat_old_linux_dirent __user *, dirent, unsigned int, count) | 884 | struct compat_old_linux_dirent __user *, dirent, unsigned int, count) |
885 | { | 885 | { |
886 | int error; | 886 | int error; |
887 | struct fd f = fdget(fd); | 887 | struct fd f = fdget_pos(fd); |
888 | struct compat_readdir_callback buf = { | 888 | struct compat_readdir_callback buf = { |
889 | .ctx.actor = compat_fillonedir, | 889 | .ctx.actor = compat_fillonedir, |
890 | .dirent = dirent | 890 | .dirent = dirent |
@@ -897,7 +897,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, | |||
897 | if (buf.result) | 897 | if (buf.result) |
898 | error = buf.result; | 898 | error = buf.result; |
899 | 899 | ||
900 | fdput(f); | 900 | fdput_pos(f); |
901 | return error; | 901 | return error; |
902 | } | 902 | } |
903 | 903 | ||
@@ -975,7 +975,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, | |||
975 | if (!access_ok(VERIFY_WRITE, dirent, count)) | 975 | if (!access_ok(VERIFY_WRITE, dirent, count)) |
976 | return -EFAULT; | 976 | return -EFAULT; |
977 | 977 | ||
978 | f = fdget(fd); | 978 | f = fdget_pos(fd); |
979 | if (!f.file) | 979 | if (!f.file) |
980 | return -EBADF; | 980 | return -EBADF; |
981 | 981 | ||
@@ -989,7 +989,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, | |||
989 | else | 989 | else |
990 | error = count - buf.count; | 990 | error = count - buf.count; |
991 | } | 991 | } |
992 | fdput(f); | 992 | fdput_pos(f); |
993 | return error; | 993 | return error; |
994 | } | 994 | } |
995 | 995 | ||
@@ -1062,7 +1062,7 @@ COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd, | |||
1062 | if (!access_ok(VERIFY_WRITE, dirent, count)) | 1062 | if (!access_ok(VERIFY_WRITE, dirent, count)) |
1063 | return -EFAULT; | 1063 | return -EFAULT; |
1064 | 1064 | ||
1065 | f = fdget(fd); | 1065 | f = fdget_pos(fd); |
1066 | if (!f.file) | 1066 | if (!f.file) |
1067 | return -EBADF; | 1067 | return -EBADF; |
1068 | 1068 | ||
@@ -1077,7 +1077,7 @@ COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd, | |||
1077 | else | 1077 | else |
1078 | error = count - buf.count; | 1078 | error = count - buf.count; |
1079 | } | 1079 | } |
1080 | fdput(f); | 1080 | fdput_pos(f); |
1081 | return error; | 1081 | return error; |
1082 | } | 1082 | } |
1083 | #endif /* __ARCH_WANT_COMPAT_SYS_GETDENTS64 */ | 1083 | #endif /* __ARCH_WANT_COMPAT_SYS_GETDENTS64 */ |
@@ -784,6 +784,11 @@ unsigned long __fdget_pos(unsigned int fd) | |||
784 | return v; | 784 | return v; |
785 | } | 785 | } |
786 | 786 | ||
787 | void __f_unlock_pos(struct file *f) | ||
788 | { | ||
789 | mutex_unlock(&f->f_pos_lock); | ||
790 | } | ||
791 | |||
787 | /* | 792 | /* |
788 | * We only lock f_pos if we have threads or if the file might be | 793 | * We only lock f_pos if we have threads or if the file might be |
789 | * shared with another process. In both cases we'll have an elevated | 794 | * shared with another process. In both cases we'll have an elevated |
@@ -713,7 +713,7 @@ static int do_dentry_open(struct file *f, | |||
713 | } | 713 | } |
714 | 714 | ||
715 | /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */ | 715 | /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */ |
716 | if (S_ISREG(inode->i_mode)) | 716 | if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) |
717 | f->f_mode |= FMODE_ATOMIC_POS; | 717 | f->f_mode |= FMODE_ATOMIC_POS; |
718 | 718 | ||
719 | f->f_op = fops_get(inode->i_fop); | 719 | f->f_op = fops_get(inode->i_fop); |
diff --git a/fs/read_write.c b/fs/read_write.c index cf377cf9dfe3..69c7c3c2955c 100644 --- a/fs/read_write.c +++ b/fs/read_write.c | |||
@@ -302,18 +302,6 @@ loff_t vfs_llseek(struct file *file, loff_t offset, int whence) | |||
302 | } | 302 | } |
303 | EXPORT_SYMBOL(vfs_llseek); | 303 | EXPORT_SYMBOL(vfs_llseek); |
304 | 304 | ||
305 | static inline struct fd fdget_pos(int fd) | ||
306 | { | ||
307 | return __to_fd(__fdget_pos(fd)); | ||
308 | } | ||
309 | |||
310 | static inline void fdput_pos(struct fd f) | ||
311 | { | ||
312 | if (f.flags & FDPUT_POS_UNLOCK) | ||
313 | mutex_unlock(&f.file->f_pos_lock); | ||
314 | fdput(f); | ||
315 | } | ||
316 | |||
317 | SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) | 305 | SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) |
318 | { | 306 | { |
319 | off_t retval; | 307 | off_t retval; |
diff --git a/fs/readdir.c b/fs/readdir.c index bf583e848a1a..d7308b8f6cf7 100644 --- a/fs/readdir.c +++ b/fs/readdir.c | |||
@@ -112,7 +112,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, | |||
112 | struct old_linux_dirent __user *, dirent, unsigned int, count) | 112 | struct old_linux_dirent __user *, dirent, unsigned int, count) |
113 | { | 113 | { |
114 | int error; | 114 | int error; |
115 | struct fd f = fdget(fd); | 115 | struct fd f = fdget_pos(fd); |
116 | struct readdir_callback buf = { | 116 | struct readdir_callback buf = { |
117 | .ctx.actor = fillonedir, | 117 | .ctx.actor = fillonedir, |
118 | .dirent = dirent | 118 | .dirent = dirent |
@@ -125,7 +125,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, | |||
125 | if (buf.result) | 125 | if (buf.result) |
126 | error = buf.result; | 126 | error = buf.result; |
127 | 127 | ||
128 | fdput(f); | 128 | fdput_pos(f); |
129 | return error; | 129 | return error; |
130 | } | 130 | } |
131 | 131 | ||
@@ -209,7 +209,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, | |||
209 | if (!access_ok(VERIFY_WRITE, dirent, count)) | 209 | if (!access_ok(VERIFY_WRITE, dirent, count)) |
210 | return -EFAULT; | 210 | return -EFAULT; |
211 | 211 | ||
212 | f = fdget(fd); | 212 | f = fdget_pos(fd); |
213 | if (!f.file) | 213 | if (!f.file) |
214 | return -EBADF; | 214 | return -EBADF; |
215 | 215 | ||
@@ -223,7 +223,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, | |||
223 | else | 223 | else |
224 | error = count - buf.count; | 224 | error = count - buf.count; |
225 | } | 225 | } |
226 | fdput(f); | 226 | fdput_pos(f); |
227 | return error; | 227 | return error; |
228 | } | 228 | } |
229 | 229 | ||
@@ -290,7 +290,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, | |||
290 | if (!access_ok(VERIFY_WRITE, dirent, count)) | 290 | if (!access_ok(VERIFY_WRITE, dirent, count)) |
291 | return -EFAULT; | 291 | return -EFAULT; |
292 | 292 | ||
293 | f = fdget(fd); | 293 | f = fdget_pos(fd); |
294 | if (!f.file) | 294 | if (!f.file) |
295 | return -EBADF; | 295 | return -EBADF; |
296 | 296 | ||
@@ -305,6 +305,6 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, | |||
305 | else | 305 | else |
306 | error = count - buf.count; | 306 | error = count - buf.count; |
307 | } | 307 | } |
308 | fdput(f); | 308 | fdput_pos(f); |
309 | return error; | 309 | return error; |
310 | } | 310 | } |
diff --git a/include/linux/file.h b/include/linux/file.h index f87d30882a24..7444f5feda12 100644 --- a/include/linux/file.h +++ b/include/linux/file.h | |||
@@ -44,6 +44,7 @@ extern struct file *fget_raw(unsigned int fd); | |||
44 | extern unsigned long __fdget(unsigned int fd); | 44 | extern unsigned long __fdget(unsigned int fd); |
45 | extern unsigned long __fdget_raw(unsigned int fd); | 45 | extern unsigned long __fdget_raw(unsigned int fd); |
46 | extern unsigned long __fdget_pos(unsigned int fd); | 46 | extern unsigned long __fdget_pos(unsigned int fd); |
47 | extern void __f_unlock_pos(struct file *); | ||
47 | 48 | ||
48 | static inline struct fd __to_fd(unsigned long v) | 49 | static inline struct fd __to_fd(unsigned long v) |
49 | { | 50 | { |
@@ -60,6 +61,18 @@ static inline struct fd fdget_raw(unsigned int fd) | |||
60 | return __to_fd(__fdget_raw(fd)); | 61 | return __to_fd(__fdget_raw(fd)); |
61 | } | 62 | } |
62 | 63 | ||
64 | static inline struct fd fdget_pos(int fd) | ||
65 | { | ||
66 | return __to_fd(__fdget_pos(fd)); | ||
67 | } | ||
68 | |||
69 | static inline void fdput_pos(struct fd f) | ||
70 | { | ||
71 | if (f.flags & FDPUT_POS_UNLOCK) | ||
72 | __f_unlock_pos(f.file); | ||
73 | fdput(f); | ||
74 | } | ||
75 | |||
63 | extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); | 76 | extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); |
64 | extern int replace_fd(unsigned fd, struct file *file, unsigned flags); | 77 | extern int replace_fd(unsigned fd, struct file *file, unsigned flags); |
65 | extern void set_close_on_exec(unsigned int fd, int flag); | 78 | extern void set_close_on_exec(unsigned int fd, int flag); |