On Thu, 30 Jun 2005 10:42:55 +0200 Andi Kleen <[EMAIL PROTECTED]> wrote: > > > -ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, > > loff_t *pos) > > +static ssize_t do_vfs_write(struct file *file, const char __user *buf, > > + size_t count, loff_t *pos, int compat) > > Instead of the flag I would move the code figuring out the call vector > into the caller.
Like below? I am not sure that this is better as we duplicate the code that selects the write_func ... -- Cheers, Stephen Rothwell [EMAIL PROTECTED] http://www.canb.auug.org.au/~sfr/ diff -ruN linus/fs/compat.c linus-compat_write.2/fs/compat.c --- linus/fs/compat.c 2005-06-27 16:08:02.000000000 +1000 +++ linus-compat_write.2/fs/compat.c 2005-06-30 17:48:35.000000000 +1000 @@ -51,6 +51,12 @@ #include <asm/mmu_context.h> #include <asm/ioctls.h> +asmlinkage ssize_t compat_sys_write(unsigned int fd, const char __user * buf, + compat_size_t count) +{ + return do_sys_write(fd, buf, count, 1); +} + /* * Not all architectures have sys_utime, so implement this in terms * of sys_utimes. diff -ruN linus/fs/read_write.c linus-compat_write.2/fs/read_write.c --- linus/fs/read_write.c 2005-06-27 16:08:05.000000000 +1000 +++ linus-compat_write.2/fs/read_write.c 2005-07-01 00:31:08.000000000 +1000 @@ -14,6 +14,7 @@ #include <linux/security.h> #include <linux/module.h> #include <linux/syscalls.h> +#include <linux/compat.h> #include <asm/uaccess.h> #include <asm/unistd.h> @@ -283,13 +284,16 @@ EXPORT_SYMBOL(do_sync_write); -ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos) +static ssize_t do_vfs_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos, + ssize_t (*write_func)(struct file *, const char __user *, + size_t, loff_t *)) { ssize_t ret; if (!(file->f_mode & FMODE_WRITE)) return -EBADF; - if (!file->f_op || (!file->f_op->write && !file->f_op->aio_write)) + if (!write_func) return -EINVAL; if (unlikely(!access_ok(VERIFY_READ, buf, count))) return -EFAULT; @@ -298,10 +302,7 @@ if (!ret) { ret = security_file_permission (file, MAY_WRITE); if (!ret) { - if (file->f_op->write) - ret = file->f_op->write(file, buf, count, pos); - else - ret = do_sync_write(file, buf, count, pos); + ret = write_func(file, buf, count, pos); if (ret > 0) { dnotify_parent(file->f_dentry, DN_MODIFY); current->wchar += ret; @@ -313,6 +314,21 @@ return ret; } +ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, + loff_t *pos) +{ + ssize_t (*write_func)(struct file *, const char __user *, + size_t, loff_t *) = NULL; + + if (file->f_ops) { + if (file->f_op->write) + write_func = file->f_op->write; + else if (file->f_op->aio_write) + write_func = &do_sync_write; + } + return do_vfs_write(file, buf, count, pos, write_func); +} + EXPORT_SYMBOL(vfs_write); static inline loff_t file_pos_read(struct file *file) @@ -343,16 +359,27 @@ } EXPORT_SYMBOL_GPL(sys_read); -asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, size_t count) +ssize_t do_sys_write(unsigned int fd, const char __user * buf, size_t count, + int compat) { struct file *file; ssize_t ret = -EBADF; int fput_needed; + ssize_t (*write_func)(struct file *, const char __user *, + size_t, loff_t *) = NULL; file = fget_light(fd, &fput_needed); if (file) { loff_t pos = file_pos_read(file); - ret = vfs_write(file, buf, count, &pos); + if (file->f_ops) { + if (is_compat_write(compat, file->f_op->compat_write)) + write_func = file->f_op->compat_write; + else if (file->f_op->write) + write_func = file->f_op->write; + else if (file->f_op->aio_write) + write_func = &do_sync_write; + } + ret = do_vfs_write(file, buf, count, &pos, write_func); file_pos_write(file, pos); fput_light(file, fput_needed); } @@ -360,6 +387,12 @@ return ret; } +asmlinkage ssize_t sys_write(unsigned int fd, const char __user * buf, + size_t count) +{ + return do_sys_write(fd, buf, count, 0); +} + asmlinkage ssize_t sys_pread64(unsigned int fd, char __user *buf, size_t count, loff_t pos) { diff -ruN linus/include/linux/compat.h linus-compat_write.2/include/linux/compat.h --- linus/include/linux/compat.h 2005-06-27 16:08:11.000000000 +1000 +++ linus-compat_write.2/include/linux/compat.h 2005-06-30 17:52:59.000000000 +1000 @@ -158,5 +158,11 @@ int get_compat_sigevent(struct sigevent *event, const struct compat_sigevent __user *u_event); +#define is_compat_write(flag, func) ((flag) && (NULL != func)) + +#else /* CONFIG_COMPAT */ + +#define is_compat_write(flag, func) 0 + #endif /* CONFIG_COMPAT */ #endif /* _LINUX_COMPAT_H */ diff -ruN linus/include/linux/fs.h linus-compat_write.2/include/linux/fs.h --- linus/include/linux/fs.h 2005-06-28 10:05:27.000000000 +1000 +++ linus-compat_write.2/include/linux/fs.h 2005-06-30 17:50:59.000000000 +1000 @@ -951,6 +951,7 @@ ssize_t (*aio_read) (struct kiocb *, char __user *, size_t, loff_t); ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *); ssize_t (*aio_write) (struct kiocb *, const char __user *, size_t, loff_t); + ssize_t (*compat_write) (struct file *, const char __user *, size_t, loff_t *); int (*readdir) (struct file *, void *, filldir_t); unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); @@ -1498,6 +1499,8 @@ unsigned long, loff_t, loff_t *, size_t, ssize_t); extern ssize_t do_sync_read(struct file *filp, char __user *buf, size_t len, loff_t *ppos); extern ssize_t do_sync_write(struct file *filp, const char __user *buf, size_t len, loff_t *ppos); +extern ssize_t do_sys_write(unsigned int fd, const char __user * buf, + size_t count, int compat); ssize_t generic_file_write_nolock(struct file *file, const struct iovec *iov, unsigned long nr_segs, loff_t *ppos); extern ssize_t generic_file_sendfile(struct file *, loff_t *, size_t, read_actor_t, void *);
pgpir0hgzBuP7.pgp
Description: PGP signature
