summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-10-24 03:15:11 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-10-24 03:15:11 +0000
commit30c6b9905bca5e1761ea2fac751b6250ddd5ca86 (patch)
tree30779e6c9e9d1b55b75cc250cd48b82adefbabfc
parent794d6411d976253c1761e3dcc0008bd63f79dc99 (diff)
Fix 32-bit pread(2) / pwrite(2) syscalls.
-rw-r--r--arch/mips64/kernel/linux32.c67
-rw-r--r--arch/mips64/kernel/scall_o32.S4
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