From 915a29ec1c5e34283a6231af1036114e4d612cb0 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 7 Aug 2004 02:08:23 -0700 Subject: [PATCH] Add pread/pwrite support bits to match the lseek bit. This also removes the ESPIPE logic from pipes and seq_files, since the VFS layer now supports it. --- arch/mips/kernel/linux32.c | 7 +++++++ fs/fifo.c | 4 +++- fs/file_table.c | 2 +- fs/nfsd/nfs4state.c | 7 +++---- fs/open.c | 2 +- fs/pipe.c | 8 -------- fs/read_write.c | 4 ++-- fs/seq_file.c | 6 +++--- include/linux/fs.h | 6 +++++- 9 files changed, 25 insertions(+), 21 deletions(-) diff --git a/arch/mips/kernel/linux32.c b/arch/mips/kernel/linux32.c index bcb3e0c5a3ec7..afd36307070a8 100644 --- a/arch/mips/kernel/linux32.c +++ b/arch/mips/kernel/linux32.c @@ -477,6 +477,9 @@ asmlinkage ssize_t sys32_pread(unsigned int fd, char * buf, goto out; if (pos < 0) goto out; + ret = -ESPIPE; + if (!(file->f_mode & FMODE_PREAD)) + goto out; ret = read(file, buf, count, &pos); if (ret > 0) dnotify_parent(file->f_dentry, DN_ACCESS); @@ -511,6 +514,10 @@ asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char * buf, if (pos < 0) goto out; + ret = -ESPIPE; + if (!(file->f_mode & FMODE_PWRITE)) + goto out; + ret = write(file, buf, count, &pos); if (ret > 0) dnotify_parent(file->f_dentry, DN_MODIFY); diff --git a/fs/fifo.c b/fs/fifo.c index fcdc9952c7121..a045fa71630cd 100644 --- a/fs/fifo.c +++ b/fs/fifo.c @@ -44,7 +44,9 @@ static int fifo_open(struct inode *inode, struct file *filp) goto err_nocleanup; } filp->f_version = 0; - filp->f_mode &= ~FMODE_LSEEK; + + /* We can only do regular read/write on fifos */ + filp->f_mode &= (FMODE_READ | FMODE_WRITE); switch (filp->f_mode) { case 1: diff --git a/fs/file_table.c b/fs/file_table.c index 8a4bd0398e34d..6e97427ff0d8f 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -117,7 +117,7 @@ int open_private_file(struct file *filp, struct dentry *dentry, int flags) memset(filp, 0, sizeof(*filp)); eventpoll_init_file(filp); filp->f_flags = flags; - filp->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK; + filp->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; atomic_set(&filp->f_count, 1); filp->f_dentry = dentry; filp->f_mapping = dentry->d_inode->i_mapping; diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 342003bd23d46..0ff4425cae9ab 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -1140,10 +1140,9 @@ int status; if (share_access & NFS4_SHARE_ACCESS_WRITE) { status = get_write_access(filp->f_dentry->d_inode); - if (!status) - filp->f_mode = FMODE_WRITE | FMODE_LSEEK; - else + if (status) return nfserrno(status); + filp->f_mode = (filp->f_mode | FMODE_WRITE) & ~FMODE_READ; } return nfs_ok; } @@ -1153,7 +1152,7 @@ nfs4_file_downgrade(struct file *filp, unsigned int share_access) { if (share_access & NFS4_SHARE_ACCESS_WRITE) { put_write_access(filp->f_dentry->d_inode); - filp->f_mode = FMODE_READ | FMODE_LSEEK; + filp->f_mode = (filp->f_mode | FMODE_READ) & ~FMODE_WRITE; } } diff --git a/fs/open.c b/fs/open.c index 098ac8d30db23..22d42e94fc182 100644 --- a/fs/open.c +++ b/fs/open.c @@ -781,7 +781,7 @@ struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) if (!f) goto cleanup_dentry; f->f_flags = flags; - f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK; + f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE; inode = dentry->d_inode; if (f->f_mode & FMODE_WRITE) { error = get_write_access(inode); diff --git a/fs/pipe.c b/fs/pipe.c index f0e16609595a5..2b42a25a414e4 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -94,10 +94,6 @@ pipe_readv(struct file *filp, const struct iovec *_iov, struct iovec *iov = (struct iovec *)_iov; size_t total_len; - /* pread is not allowed on pipes. */ - if (unlikely(ppos != &filp->f_pos)) - return -ESPIPE; - total_len = iov_length(iov, nr_segs); /* Null read succeeds. */ if (unlikely(total_len == 0)) @@ -187,10 +183,6 @@ pipe_writev(struct file *filp, const struct iovec *_iov, struct iovec *iov = (struct iovec *)_iov; size_t total_len; - /* pwrite is not allowed on pipes. */ - if (unlikely(ppos != &filp->f_pos)) - return -ESPIPE; - total_len = iov_length(iov, nr_segs); /* Null write succeeds. */ if (unlikely(total_len == 0)) diff --git a/fs/read_write.c b/fs/read_write.c index 6b226d11b6068..33ce2284c9d08 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -314,7 +314,7 @@ asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf, file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; - if (file->f_mode & FMODE_LSEEK) + if (file->f_mode & FMODE_PREAD) ret = vfs_read(file, buf, count, &pos); fput_light(file, fput_needed); } @@ -335,7 +335,7 @@ asmlinkage ssize_t sys_pwrite64(unsigned int fd, const char __user *buf, file = fget_light(fd, &fput_needed); if (file) { ret = -ESPIPE; - if (file->f_mode & FMODE_LSEEK) + if (file->f_mode & FMODE_PWRITE) ret = vfs_write(file, buf, count, &pos); fput_light(file, fput_needed); } diff --git a/fs/seq_file.c b/fs/seq_file.c index 8bd7097f3cfb6..5a73e085fb4e5 100644 --- a/fs/seq_file.c +++ b/fs/seq_file.c @@ -35,6 +35,9 @@ int seq_open(struct file *file, struct seq_operations *op) sema_init(&p->sem, 1); p->op = op; file->private_data = p; + + /* SEQ files support lseek, but not pread/pwrite */ + file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); return 0; } EXPORT_SYMBOL(seq_open); @@ -54,9 +57,6 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos) void *p; int err = 0; - if (ppos != &file->f_pos) - return -EPIPE; - down(&m->sem); /* grab buffer if we didn't have one */ if (!m->buf) { diff --git a/include/linux/fs.h b/include/linux/fs.h index 44dbcaea3ebda..d352f86782589 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -74,7 +74,11 @@ extern int leases_enable, dir_notify_enable, lease_break_time; #define FMODE_READ 1 #define FMODE_WRITE 2 -#define FMODE_LSEEK 4 /* Internal kernel extension */ + +/* Internal kernel extensions */ +#define FMODE_LSEEK 4 +#define FMODE_PREAD 8 +#define FMODE_PWRITE FMODE_PREAD /* These go hand in hand */ #define RW_MASK 1 #define RWA_MASK 2 -- 2.53.0