diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-10-24 03:15:11 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-10-24 03:15:11 +0000 |
commit | 30c6b9905bca5e1761ea2fac751b6250ddd5ca86 (patch) | |
tree | 30779e6c9e9d1b55b75cc250cd48b82adefbabfc | |
parent | 794d6411d976253c1761e3dcc0008bd63f79dc99 (diff) |
Fix 32-bit pread(2) / pwrite(2) syscalls.
-rw-r--r-- | arch/mips64/kernel/linux32.c | 67 | ||||
-rw-r--r-- | arch/mips64/kernel/scall_o32.S | 4 |
2 files changed, 69 insertions, 2 deletions
diff --git a/arch/mips64/kernel/linux32.c b/arch/mips64/kernel/linux32.c index 981c639df..e4fd26e3d 100644 --- a/arch/mips64/kernel/linux32.c +++ b/arch/mips64/kernel/linux32.c @@ -26,6 +26,7 @@ #include <linux/utsname.h> #include <linux/personality.h> #include <linux/timex.h> +#include <linux/dnotify.h> #include <asm/uaccess.h> #include <asm/mman.h> @@ -1039,6 +1040,72 @@ bad_file: return ret; } +/* From the Single Unix Spec: pread & pwrite act like lseek to pos + op + + lseek back to original location. They fail just like lseek does on + non-seekable files. */ + +asmlinkage ssize_t sys32_pread(unsigned int fd, char * buf, + size_t count, u32 unused, loff_t pos) +{ + ssize_t ret; + struct file * file; + ssize_t (*read)(struct file *, char *, size_t, loff_t *); + + ret = -EBADF; + file = fget(fd); + if (!file) + goto bad_file; + if (!(file->f_mode & FMODE_READ)) + goto out; + ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode, + file, pos, count); + if (ret) + goto out; + ret = -EINVAL; + if (!file->f_op || !(read = file->f_op->read)) + goto out; + if (pos < 0) + goto out; + ret = read(file, buf, count, &pos); + if (ret > 0) + inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_ACCESS); +out: + fput(file); +bad_file: + return ret; +} + +asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char * buf, + size_t count, u32 unused, loff_t pos) +{ + ssize_t ret; + struct file * file; + ssize_t (*write)(struct file *, const char *, size_t, loff_t *); + + ret = -EBADF; + file = fget(fd); + if (!file) + goto bad_file; + if (!(file->f_mode & FMODE_WRITE)) + goto out; + ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode, + file, pos, count); + if (ret) + goto out; + ret = -EINVAL; + if (!file->f_op || !(write = file->f_op->write)) + goto out; + if (pos < 0) + goto out; + + ret = write(file, buf, count, &pos); + if (ret > 0) + inode_dir_notify(file->f_dentry->d_parent->d_inode, DN_MODIFY); +out: + fput(file); +bad_file: + return ret; +} /* * Ooo, nasty. We need here to frob 32-bit unsigned longs to * 64-bit unsigned longs. diff --git a/arch/mips64/kernel/scall_o32.S b/arch/mips64/kernel/scall_o32.S index 3a814fd7f..9640826bb 100644 --- a/arch/mips64/kernel/scall_o32.S +++ b/arch/mips64/kernel/scall_o32.S @@ -401,8 +401,8 @@ illegal_syscall: sys sys32_rt_sigtimedwait 4 sys sys32_rt_sigqueueinfo 3 sys sys32_rt_sigsuspend 0 - sys sys_pread 4 /* 4200 */ - sys sys_pwrite 4 + sys sys32_pread 6 /* 4200 */ + sys sys32_pwrite 6 sys sys_chown 3 sys sys_getcwd 2 sys sys_capget 2 |