Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

Al Viro 63b6df14 9902af79

+33 -27
+2 -2
arch/alpha/kernel/osf_sys.c
··· 147 147 long __user *, basep) 148 148 { 149 149 int error; 150 - struct fd arg = fdget(fd); 150 + struct fd arg = fdget_pos(fd); 151 151 struct osf_dirent_callback buf = { 152 152 .ctx.actor = osf_filldir, 153 153 .dirent = dirent, ··· 164 164 if (count != buf.count) 165 165 error = count - buf.count; 166 166 167 - fdput(arg); 167 + fdput_pos(arg); 168 168 return error; 169 169 } 170 170
+6 -6
fs/compat.c
··· 884 884 struct compat_old_linux_dirent __user *, dirent, unsigned int, count) 885 885 { 886 886 int error; 887 - struct fd f = fdget(fd); 887 + struct fd f = fdget_pos(fd); 888 888 struct compat_readdir_callback buf = { 889 889 .ctx.actor = compat_fillonedir, 890 890 .dirent = dirent ··· 897 897 if (buf.result) 898 898 error = buf.result; 899 899 900 - fdput(f); 900 + fdput_pos(f); 901 901 return error; 902 902 } 903 903 ··· 975 975 if (!access_ok(VERIFY_WRITE, dirent, count)) 976 976 return -EFAULT; 977 977 978 - f = fdget(fd); 978 + f = fdget_pos(fd); 979 979 if (!f.file) 980 980 return -EBADF; 981 981 ··· 989 989 else 990 990 error = count - buf.count; 991 991 } 992 - fdput(f); 992 + fdput_pos(f); 993 993 return error; 994 994 } 995 995 ··· 1062 1062 if (!access_ok(VERIFY_WRITE, dirent, count)) 1063 1063 return -EFAULT; 1064 1064 1065 - f = fdget(fd); 1065 + f = fdget_pos(fd); 1066 1066 if (!f.file) 1067 1067 return -EBADF; 1068 1068 ··· 1077 1077 else 1078 1078 error = count - buf.count; 1079 1079 } 1080 - fdput(f); 1080 + fdput_pos(f); 1081 1081 return error; 1082 1082 } 1083 1083 #endif /* __ARCH_WANT_COMPAT_SYS_GETDENTS64 */
+5
fs/file.c
··· 784 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 793 * We only lock f_pos if we have threads or if the file might be 789 794 * shared with another process. In both cases we'll have an elevated
+1 -1
fs/open.c
··· 713 713 } 714 714 715 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 717 f->f_mode |= FMODE_ATOMIC_POS; 718 718 719 719 f->f_op = fops_get(inode->i_fop);
-12
fs/read_write.c
··· 302 302 } 303 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 305 SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence) 318 306 { 319 307 off_t retval;
+6 -6
fs/readdir.c
··· 112 112 struct old_linux_dirent __user *, dirent, unsigned int, count) 113 113 { 114 114 int error; 115 - struct fd f = fdget(fd); 115 + struct fd f = fdget_pos(fd); 116 116 struct readdir_callback buf = { 117 117 .ctx.actor = fillonedir, 118 118 .dirent = dirent ··· 125 125 if (buf.result) 126 126 error = buf.result; 127 127 128 - fdput(f); 128 + fdput_pos(f); 129 129 return error; 130 130 } 131 131 ··· 209 209 if (!access_ok(VERIFY_WRITE, dirent, count)) 210 210 return -EFAULT; 211 211 212 - f = fdget(fd); 212 + f = fdget_pos(fd); 213 213 if (!f.file) 214 214 return -EBADF; 215 215 ··· 223 223 else 224 224 error = count - buf.count; 225 225 } 226 - fdput(f); 226 + fdput_pos(f); 227 227 return error; 228 228 } 229 229 ··· 290 290 if (!access_ok(VERIFY_WRITE, dirent, count)) 291 291 return -EFAULT; 292 292 293 - f = fdget(fd); 293 + f = fdget_pos(fd); 294 294 if (!f.file) 295 295 return -EBADF; 296 296 ··· 305 305 else 306 306 error = count - buf.count; 307 307 } 308 - fdput(f); 308 + fdput_pos(f); 309 309 return error; 310 310 }
+13
include/linux/file.h
··· 44 44 extern unsigned long __fdget(unsigned int fd); 45 45 extern unsigned long __fdget_raw(unsigned int fd); 46 46 extern unsigned long __fdget_pos(unsigned int fd); 47 + extern void __f_unlock_pos(struct file *); 47 48 48 49 static inline struct fd __to_fd(unsigned long v) 49 50 { ··· 59 58 static inline struct fd fdget_raw(unsigned int fd) 60 59 { 61 60 return __to_fd(__fdget_raw(fd)); 61 + } 62 + 63 + static inline struct fd fdget_pos(int fd) 64 + { 65 + return __to_fd(__fdget_pos(fd)); 66 + } 67 + 68 + static inline void fdput_pos(struct fd f) 69 + { 70 + if (f.flags & FDPUT_POS_UNLOCK) 71 + __f_unlock_pos(f.file); 72 + fdput(f); 62 73 } 63 74 64 75 extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);