linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH] cleanup read/write
@ 2002-05-15 14:38 Christoph Hellwig
  0 siblings, 0 replies; only message in thread
From: Christoph Hellwig @ 2002-05-15 14:38 UTC (permalink / raw)
  To: Linus Torvalds, Marcelo Tosatti; +Cc: linux-kernel

Currently sys_read/sys_pread and sys_write/sys_pwrite basically contain
lots of duplication of the same checks/code.

The patch below moves all that into vfs_read/vfs_write helpers that have
the same prototypes as the read/write file operations.  In addition I
have choosen to export these interfaces to module so people doing inkernel
file reading/writing can use these instead of duplicating the checks
(which is very likely to be done wrong).

The patch applies against 2.4 and 2.5 without changes.

--- linux-2.4.19-pre8-ac3/fs/read_write.c	Fri May  3 13:38:32 2002
+++ linux/fs/read_write.c	Wed May 15 17:19:47 2002
@@ -144,57 +144,107 @@
 }
 #endif
 
-asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
+ssize_t vfs_read(struct file *file, char *buf, size_t count, loff_t *pos)
 {
+	struct inode *inode = file->f_dentry->d_inode;
 	ssize_t ret;
-	struct file * file;
 
-	ret = -EBADF;
-	file = fget(fd);
-	if (file) {
-		if (file->f_mode & FMODE_READ) {
-			ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
-						file, file->f_pos, count);
-			if (!ret) {
-				ssize_t (*read)(struct file *, char *, size_t, loff_t *);
-				ret = -EINVAL;
-				if (file->f_op && (read = file->f_op->read) != NULL)
-					ret = read(file, buf, count, &file->f_pos);
-			}
-		}
+	if (!(file->f_mode & FMODE_READ))
+		return -EBADF;
+	if (!file->f_op || !file->f_op->read)
+		return -EINVAL;
+	if (pos < 0)
+		return -EINVAL;
+
+	ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, *pos, count);
+	if (!ret) {
+		ret = file->f_op->read(file, buf, count, pos);
 		if (ret > 0)
 			dnotify_parent(file->f_dentry, DN_ACCESS);
+	}
+
+	return ret;
+}
+
+ssize_t vfs_write(struct file *file, const char *buf, size_t count, loff_t *pos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	ssize_t ret;
+
+	if (!(file->f_mode & FMODE_WRITE))
+		return -EBADF;
+	if (!file->f_op || !file->f_op->write)
+		return -EINVAL;
+	if (pos < 0)
+		return -EINVAL;
+
+	ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, *pos, count);
+	if (!ret) {
+		ret = file->f_op->write(file, buf, count, pos);
+		if (ret > 0)
+			dnotify_parent(file->f_dentry, DN_MODIFY);
+	}
+
+	return ret;
+}
+
+asmlinkage ssize_t sys_read(unsigned int fd, char * buf, size_t count)
+{
+	struct file *file;
+	ssize_t ret = -EBADF;
+
+	file = fget(fd);
+	if (file) {
+		ret = vfs_read(file, buf, count, &file->f_pos);
 		fput(file);
 	}
+
 	return ret;
 }
 
 asmlinkage ssize_t sys_write(unsigned int fd, const char * buf, size_t count)
 {
-	ssize_t ret;
-	struct file * file;
+	struct file *file;
+	ssize_t ret = -EBADF;
 
-	ret = -EBADF;
 	file = fget(fd);
 	if (file) {
-		if (file->f_mode & FMODE_WRITE) {
-			struct inode *inode = file->f_dentry->d_inode;
-			ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file,
-				file->f_pos, count);
-			if (!ret) {
-				ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
-				ret = -EINVAL;
-				if (file->f_op && (write = file->f_op->write) != NULL)
-					ret = write(file, buf, count, &file->f_pos);
-			}
-		}
-		if (ret > 0)
-			dnotify_parent(file->f_dentry, DN_MODIFY);
+		ret = vfs_write(file, buf, count, &file->f_pos);
 		fput(file);
 	}
+
 	return ret;
 }
 
+asmlinkage ssize_t sys_pread(unsigned int fd, char *buf,
+			     size_t count, loff_t pos)
+{
+	struct file *file;
+	ssize_t ret = -EBADF;
+
+	file = fget(fd);
+	if (file) {
+		ret = vfs_read(file, buf, count, &pos);
+		fput(file);
+	}
+
+	return ret;
+}
+
+asmlinkage ssize_t sys_pwrite(unsigned int fd, const char *buf,
+			      size_t count, loff_t pos)
+{
+	struct file *file;
+	ssize_t ret = -EBADF;
+
+	file = fget(fd);
+	if (file) {
+		ret = vfs_write(file, buf, count, &pos);
+		fput(file);
+	}
+
+	return ret;
+}
 
 static ssize_t do_readv_writev(int type, struct file *file,
 			       const struct iovec * vector,
@@ -337,70 +387,3 @@
 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 sys_pread(unsigned int fd, char * buf,
-			     size_t count, 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)
-		dnotify_parent(file->f_dentry, DN_ACCESS);
-out:
-	fput(file);
-bad_file:
-	return ret;
-}
-
-asmlinkage ssize_t sys_pwrite(unsigned int fd, const char * buf,
-			      size_t count, 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)
-		dnotify_parent(file->f_dentry, DN_MODIFY);
-out:
-	fput(file);
-bad_file:
-	return ret;
-}
--- linux-2.4.19-pre8-ac3/kernel/ksyms.c	Tue May 14 16:52:11 2002
+++ linux/kernel/ksyms.c	Wed May 15 17:31:10 2002
@@ -242,6 +242,8 @@
 EXPORT_SYMBOL(find_inode_number);
 EXPORT_SYMBOL(is_subdir);
 EXPORT_SYMBOL(get_unused_fd);
+EXPORT_SYMBOL(vfs_read);
+EXPORT_SYMBOL(vfs_write);
 EXPORT_SYMBOL(vfs_create);
 EXPORT_SYMBOL(vfs_mkdir);
 EXPORT_SYMBOL(vfs_mknod);
--- linux-2.4.19-pre8-ac3/include/linux/fs.h	Tue May 14 16:52:10 2002
+++ linux/include/linux/fs.h	Wed May 15 17:27:52 2002
@@ -821,6 +821,9 @@
 extern int vfs_unlink(struct inode *, struct dentry *);
 extern int vfs_rename(struct inode *, struct dentry *, struct inode *, struct dentry *);
 
+extern ssize_t vfs_read(struct file *, char *, size_t, loff_t *);
+extern ssize_t vfs_write(struct file *, const char *, size_t, loff_t *);
+
 /*
  * File types
  */

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2002-05-15 14:40 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-05-15 14:38 [PATCH] cleanup read/write Christoph Hellwig

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).