aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2016-04-20 17:08:21 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2016-05-02 19:49:28 -0400
commit63b6df14134ddd048984c8afadb46e721815bfc6 (patch)
tree7fecdc7f3ee6d9780b3fa5328a0acd1bb739b16e
parent9902af79c01a8e39bb99b922fa3eef6d4ea23d69 (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.c4
-rw-r--r--fs/compat.c12
-rw-r--r--fs/file.c5
-rw-r--r--fs/open.c2
-rw-r--r--fs/read_write.c12
-rw-r--r--fs/readdir.c12
-rw-r--r--include/linux/file.h13
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 */
diff --git a/fs/file.c b/fs/file.c
index 1fbc5c0555a9..6b1acdfe59da 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -784,6 +784,11 @@ unsigned long __fdget_pos(unsigned int fd)
784 return v; 784 return v;
785} 785}
786 786
787void __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
diff --git a/fs/open.c b/fs/open.c
index 17cb6b1dab75..938a658a5c6d 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -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}
303EXPORT_SYMBOL(vfs_llseek); 303EXPORT_SYMBOL(vfs_llseek);
304 304
305static inline struct fd fdget_pos(int fd)
306{
307 return __to_fd(__fdget_pos(fd));
308}
309
310static 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
317SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) 305SYSCALL_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);
44extern unsigned long __fdget(unsigned int fd); 44extern unsigned long __fdget(unsigned int fd);
45extern unsigned long __fdget_raw(unsigned int fd); 45extern unsigned long __fdget_raw(unsigned int fd);
46extern unsigned long __fdget_pos(unsigned int fd); 46extern unsigned long __fdget_pos(unsigned int fd);
47extern void __f_unlock_pos(struct file *);
47 48
48static inline struct fd __to_fd(unsigned long v) 49static 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
64static inline struct fd fdget_pos(int fd)
65{
66 return __to_fd(__fdget_pos(fd));
67}
68
69static 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
63extern int f_dupfd(unsigned int from, struct file *file, unsigned flags); 76extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
64extern int replace_fd(unsigned fd, struct file *file, unsigned flags); 77extern int replace_fd(unsigned fd, struct file *file, unsigned flags);
65extern void set_close_on_exec(unsigned int fd, int flag); 78extern void set_close_on_exec(unsigned int fd, int flag);