Commit 63b6df14 authored by Al Viro's avatar Al Viro

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: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent 9902af79
...@@ -147,7 +147,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd, ...@@ -147,7 +147,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
long __user *, basep) long __user *, basep)
{ {
int error; int error;
struct fd arg = fdget(fd); struct fd arg = fdget_pos(fd);
struct osf_dirent_callback buf = { struct osf_dirent_callback buf = {
.ctx.actor = osf_filldir, .ctx.actor = osf_filldir,
.dirent = dirent, .dirent = dirent,
...@@ -164,7 +164,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd, ...@@ -164,7 +164,7 @@ SYSCALL_DEFINE4(osf_getdirentries, unsigned int, fd,
if (count != buf.count) if (count != buf.count)
error = count - buf.count; error = count - buf.count;
fdput(arg); fdput_pos(arg);
return error; return error;
} }
......
...@@ -884,7 +884,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, ...@@ -884,7 +884,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
struct compat_old_linux_dirent __user *, dirent, unsigned int, count) struct compat_old_linux_dirent __user *, dirent, unsigned int, count)
{ {
int error; int error;
struct fd f = fdget(fd); struct fd f = fdget_pos(fd);
struct compat_readdir_callback buf = { struct compat_readdir_callback buf = {
.ctx.actor = compat_fillonedir, .ctx.actor = compat_fillonedir,
.dirent = dirent .dirent = dirent
...@@ -897,7 +897,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd, ...@@ -897,7 +897,7 @@ COMPAT_SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
if (buf.result) if (buf.result)
error = buf.result; error = buf.result;
fdput(f); fdput_pos(f);
return error; return error;
} }
...@@ -975,7 +975,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, ...@@ -975,7 +975,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
if (!access_ok(VERIFY_WRITE, dirent, count)) if (!access_ok(VERIFY_WRITE, dirent, count))
return -EFAULT; return -EFAULT;
f = fdget(fd); f = fdget_pos(fd);
if (!f.file) if (!f.file)
return -EBADF; return -EBADF;
...@@ -989,7 +989,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd, ...@@ -989,7 +989,7 @@ COMPAT_SYSCALL_DEFINE3(getdents, unsigned int, fd,
else else
error = count - buf.count; error = count - buf.count;
} }
fdput(f); fdput_pos(f);
return error; return error;
} }
...@@ -1062,7 +1062,7 @@ COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd, ...@@ -1062,7 +1062,7 @@ COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd,
if (!access_ok(VERIFY_WRITE, dirent, count)) if (!access_ok(VERIFY_WRITE, dirent, count))
return -EFAULT; return -EFAULT;
f = fdget(fd); f = fdget_pos(fd);
if (!f.file) if (!f.file)
return -EBADF; return -EBADF;
...@@ -1077,7 +1077,7 @@ COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd, ...@@ -1077,7 +1077,7 @@ COMPAT_SYSCALL_DEFINE3(getdents64, unsigned int, fd,
else else
error = count - buf.count; error = count - buf.count;
} }
fdput(f); fdput_pos(f);
return error; return error;
} }
#endif /* __ARCH_WANT_COMPAT_SYS_GETDENTS64 */ #endif /* __ARCH_WANT_COMPAT_SYS_GETDENTS64 */
......
...@@ -784,6 +784,11 @@ unsigned long __fdget_pos(unsigned int fd) ...@@ -784,6 +784,11 @@ unsigned long __fdget_pos(unsigned int fd)
return v; 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 * 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 * 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,7 +713,7 @@ static int do_dentry_open(struct file *f,
} }
/* POSIX.1-2008/SUSv4 Section XSI 2.9.7 */ /* 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_mode |= FMODE_ATOMIC_POS;
f->f_op = fops_get(inode->i_fop); f->f_op = fops_get(inode->i_fop);
......
...@@ -302,18 +302,6 @@ loff_t vfs_llseek(struct file *file, loff_t offset, int whence) ...@@ -302,18 +302,6 @@ loff_t vfs_llseek(struct file *file, loff_t offset, int whence)
} }
EXPORT_SYMBOL(vfs_llseek); 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) SYSCALL_DEFINE3(lseek, unsigned int, fd, off_t, offset, unsigned int, whence)
{ {
off_t retval; off_t retval;
......
...@@ -112,7 +112,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, ...@@ -112,7 +112,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
struct old_linux_dirent __user *, dirent, unsigned int, count) struct old_linux_dirent __user *, dirent, unsigned int, count)
{ {
int error; int error;
struct fd f = fdget(fd); struct fd f = fdget_pos(fd);
struct readdir_callback buf = { struct readdir_callback buf = {
.ctx.actor = fillonedir, .ctx.actor = fillonedir,
.dirent = dirent .dirent = dirent
...@@ -125,7 +125,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd, ...@@ -125,7 +125,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned int, fd,
if (buf.result) if (buf.result)
error = buf.result; error = buf.result;
fdput(f); fdput_pos(f);
return error; return error;
} }
...@@ -209,7 +209,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, ...@@ -209,7 +209,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
if (!access_ok(VERIFY_WRITE, dirent, count)) if (!access_ok(VERIFY_WRITE, dirent, count))
return -EFAULT; return -EFAULT;
f = fdget(fd); f = fdget_pos(fd);
if (!f.file) if (!f.file)
return -EBADF; return -EBADF;
...@@ -223,7 +223,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd, ...@@ -223,7 +223,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, fd,
else else
error = count - buf.count; error = count - buf.count;
} }
fdput(f); fdput_pos(f);
return error; return error;
} }
...@@ -290,7 +290,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, ...@@ -290,7 +290,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
if (!access_ok(VERIFY_WRITE, dirent, count)) if (!access_ok(VERIFY_WRITE, dirent, count))
return -EFAULT; return -EFAULT;
f = fdget(fd); f = fdget_pos(fd);
if (!f.file) if (!f.file)
return -EBADF; return -EBADF;
...@@ -305,6 +305,6 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd, ...@@ -305,6 +305,6 @@ SYSCALL_DEFINE3(getdents64, unsigned int, fd,
else else
error = count - buf.count; error = count - buf.count;
} }
fdput(f); fdput_pos(f);
return error; return error;
} }
...@@ -44,6 +44,7 @@ extern struct file *fget_raw(unsigned int fd); ...@@ -44,6 +44,7 @@ extern struct file *fget_raw(unsigned int fd);
extern unsigned long __fdget(unsigned int fd); extern unsigned long __fdget(unsigned int fd);
extern unsigned long __fdget_raw(unsigned int fd); extern unsigned long __fdget_raw(unsigned int fd);
extern unsigned long __fdget_pos(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) static inline struct fd __to_fd(unsigned long v)
{ {
...@@ -60,6 +61,18 @@ static inline struct fd fdget_raw(unsigned int fd) ...@@ -60,6 +61,18 @@ static inline struct fd fdget_raw(unsigned int fd)
return __to_fd(__fdget_raw(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 f_dupfd(unsigned int from, struct file *file, unsigned flags);
extern int replace_fd(unsigned fd, 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); extern void set_close_on_exec(unsigned int fd, int flag);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment