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>
This commit is contained in:
Родитель
9902af79c0
Коммит
63b6df1413
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
12
fs/compat.c
12
fs/compat.c
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
12
fs/readdir.c
12
fs/readdir.c
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче