give readdir(2)/getdents(2)/etc. uniform exclusion with lseek()
authorAl Viro <viro@zeniv.linux.org.uk>
Wed, 20 Apr 2016 21:08:21 +0000 (17:08 -0400)
committerAl Viro <viro@zeniv.linux.org.uk>
Mon, 2 May 2016 23:49:28 +0000 (19:49 -0400)
same as read() on regular files has, and for the same reason.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
arch/alpha/kernel/osf_sys.c
fs/compat.c
fs/file.c
fs/open.c
fs/read_write.c
fs/readdir.c
include/linux/file.h

index 6cc0816..ffb93f4 100644 (file)
@@ -147,7 +147,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
                long __user *, basep)
 {
        int error;
-       struct fd arg = fdget(fd);
+       struct fd arg = fdget_pos(fd);
        struct osf_dirent_callback buf = {
                .ctx.actor = osf_filldir,
                .dirent = dirent,
@@ -164,7 +164,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
        if (count != buf.count)
                error = count - buf.count;
 
-       fdput(arg);
+       fdput_pos(arg);
        return error;
 }
 
index a71936a..8754e9a 100644 (file)
@@ -884,7 +884,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
                struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
 {
        int error;
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        struct compat_readdir_callback buf = {
                .ctx.actor = compat_fillonedir,
                .dirent = dirent
@@ -897,7 +897,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
        if (buf.result)
                error = buf.result;
 
-       fdput(f);
+       fdput_pos(f);
        return error;
 }
 
@@ -975,7 +975,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
        if (!access_ok(VERIFY_WRITE, dirent, count))
                return -EFAULT;
 
-       f = fdget(fd);
+       f = fdget_pos(fd);
        if (!f.file)
                return -EBADF;
 
@@ -989,7 +989,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
                else
                        error = count - buf.count;
        }
-       fdput(f);
+       fdput_pos(f);
        return error;
 }
 
@@ -1062,7 +1062,7 @@ COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd,
        if (!access_ok(VERIFY_WRITE, dirent, count))
                return -EFAULT;
 
-       f = fdget(fd);
+       f = fdget_pos(fd);
        if (!f.file)
                return -EBADF;
 
@@ -1077,7 +1077,7 @@ COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd,
                else
                        error = count - buf.count;
        }
-       fdput(f);
+       fdput_pos(f);
        return error;
 }
 #endif /* __ARCH_WANT_COMPAT_SYS_GETDENTS64 */
index 1fbc5c0..6b1acdf 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -784,6 +784,11 @@ unsigned long __fdget_pos(unsigned int fd)
        return v;
 }
 
+void __f_unlock_pos(struct file *f)
+{
+       mutex_unlock(&f->f_pos_lock);
+}
+
 /*
  * We only lock f_pos if we have threads or if the file might be
  * shared with another process. In both cases we'll have an elevated
index 17cb6b1..938a658 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -713,7 +713,7 @@ static int do_dentry_open(struct file *f,
        }
 
        /* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */
-       if (S_ISREG(inode->i_mode))
+       if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))
                f->f_mode |= FMODE_ATOMIC_POS;
 
        f->f_op = fops_get(inode->i_fop);
index cf377cf..69c7c3c 100644 (file)
@@ -302,18 +302,6 @@ loff_t vfs_llseek(struct file *file, loff_t offset, int whence)
 }
 EXPORT_SYMBOL(vfs_llseek);
 
-static inline struct fd fdget_pos(int fd)
-{
-       return __to_fd(__fdget_pos(fd));
-}
-
-static inline void fdput_pos(struct fd f)
-{
-       if (f.flags & FDPUT_POS_UNLOCK)
-               mutex_unlock(&f.file->f_pos_lock);
-       fdput(f);
-}
-
 SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
 {
        off_t retval;
index bf583e8..d7308b8 100644 (file)
@@ -112,7 +112,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
                struct old_linux_dirent __user *, dirent, unsigned int, count)
 {
        int error;
-       struct fd f = fdget(fd);
+       struct fd f = fdget_pos(fd);
        struct readdir_callback buf = {
                .ctx.actor = fillonedir,
                .dirent = dirent
@@ -125,7 +125,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
        if (buf.result)
                error = buf.result;
 
-       fdput(f);
+       fdput_pos(f);
        return error;
 }
 
@@ -209,7 +209,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
        if (!access_ok(VERIFY_WRITE, dirent, count))
                return -EFAULT;
 
-       f = fdget(fd);
+       f = fdget_pos(fd);
        if (!f.file)
                return -EBADF;
 
@@ -223,7 +223,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
                else
                        error = count - buf.count;
        }
-       fdput(f);
+       fdput_pos(f);
        return error;
 }
 
@@ -290,7 +290,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
        if (!access_ok(VERIFY_WRITE, dirent, count))
                return -EFAULT;
 
-       f = fdget(fd);
+       f = fdget_pos(fd);
        if (!f.file)
                return -EBADF;
 
@@ -305,6 +305,6 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
                else
                        error = count - buf.count;
        }
-       fdput(f);
+       fdput_pos(f);
        return error;
 }
index f87d308..7444f5f 100644 (file)
@@ -44,6 +44,7 @@ extern struct file *fget_raw(unsigned int fd);
 extern unsigned long __fdget(unsigned int fd);
 extern unsigned long __fdget_raw(unsigned int fd);
 extern unsigned long __fdget_pos(unsigned int fd);
+extern void __f_unlock_pos(struct file *);
 
 static inline struct fd __to_fd(unsigned long v)
 {
@@ -60,6 +61,18 @@ static inline struct fd fdget_raw(unsigned int fd)
        return __to_fd(__fdget_raw(fd));
 }
 
+static inline struct fd fdget_pos(int fd)
+{
+       return __to_fd(__fdget_pos(fd));
+}
+
+static inline void fdput_pos(struct fd f)
+{
+       if (f.flags & FDPUT_POS_UNLOCK)
+               __f_unlock_pos(f.file);
+       fdput(f);
+}
+
 extern int f_dupfd(unsigned int from, struct file *file, unsigned flags);
 extern int replace_fd(unsigned fd, struct file *file, unsigned flags);
 extern void set_close_on_exec(unsigned int fd, int flag);