From 6e573423507ecfd1a67a13714915dd69f063b959 Mon Sep 17 00:00:00 2001
From: Guy Zana <guy@cloudius-systems.com>
Date: Tue, 12 Mar 2013 11:24:38 +0200
Subject: [PATCH] Initial fileops abstraction

---
 fs/build.mak          |   3 +-
 fs/vfs/vfs_fops.c     | 108 ++++++++++++++++++++++++++++++++++++++
 fs/vfs/vfs_syscalls.c |  72 +++++++------------------
 include/osv/file.h    | 119 ++++++++++++++++++++++++++++++++++++++++--
 4 files changed, 245 insertions(+), 57 deletions(-)
 create mode 100644 fs/vfs/vfs_fops.c

diff --git a/fs/build.mak b/fs/build.mak
index dec9818fe..47d1abf23 100644
--- a/fs/build.mak
+++ b/fs/build.mak
@@ -13,7 +13,8 @@ fs +=	vfs/main.o \
 	vfs/vfs_mount.o \
 	vfs/vfs_vnode.o \
 	vfs/vfs_task.o \
-	vfs/vfs_syscalls.o
+	vfs/vfs_syscalls.o \
+	vfs/vfs_fops.o
 
 fs +=	ramfs/ramfs_vfsops.o \
 	ramfs/ramfs_vnops.o
diff --git a/fs/vfs/vfs_fops.c b/fs/vfs/vfs_fops.c
new file mode 100644
index 000000000..40d094918
--- /dev/null
+++ b/fs/vfs/vfs_fops.c
@@ -0,0 +1,108 @@
+
+#include <sys/fcntl.h>
+#include <sys/stat.h>
+#include <osv/file.h>
+#include <fs/vfs/vfs.h>
+
+static int vfs_fo_init(struct file *fp)
+{
+	return 0;
+}
+
+static int vfs_close(struct file *fp)
+{
+	struct vnode *vp = fp->f_vnode;
+	int error;
+
+	vn_lock(vp);
+	error = VOP_CLOSE(vp, fp);
+	if (error) {
+		vn_unlock(vp);
+		return error;
+	}
+	vput(vp);
+	return 0;
+}
+
+static int vfs_read(struct file *fp, struct uio *uio, int flags)
+{
+	struct vnode *vp = fp->f_vnode;
+	int error;
+	size_t count;
+	ssize_t bytes;
+
+	bytes = uio->uio_resid;
+
+	vn_lock(vp);
+	if ((flags & FOF_OFFSET) == 0)
+		uio->uio_offset = fp->f_offset;
+
+	error = VOP_READ(vp, uio, 0);
+	if (!error) {
+		count = bytes - uio->uio_resid;
+		if ((flags & FOF_OFFSET) == 0)
+			fp->f_offset += count;
+	}
+	vn_unlock(vp);
+
+	return error;
+}
+
+
+static int vfs_write(struct file *fp, struct uio *uio, int flags)
+{
+	struct vnode *vp = fp->f_vnode;
+	int ioflags = 0;
+	int error;
+	size_t count;
+	ssize_t bytes;
+
+	bytes = uio->uio_resid;
+
+	vn_lock(vp);
+	if ((flags & FOF_OFFSET) == 0)
+	        uio->uio_offset = fp->f_offset;
+
+	error = VOP_WRITE(vp, uio, ioflags);
+	if (!error) {
+		count = bytes - uio->uio_resid;
+		if ((flags & FOF_OFFSET) == 0)
+			fp->f_offset += count;
+	}
+
+	vn_unlock(vp);
+	return error;
+}
+
+static int vfs_ioctl(struct file *fp, u_long com, void *data)
+{
+	struct vnode *vp = fp->f_vnode;
+	int error;
+
+	vn_lock(vp);
+	error = VOP_IOCTL(vp, fp, com, data);
+	vn_unlock(vp);
+
+	return error;
+}
+
+static int vfs_stat(struct file *fp, struct stat *st)
+{
+	struct vnode *vp = fp->f_vnode;
+	int error;
+
+	vn_lock(vp);
+	error = vn_stat(vp, st);
+	vn_unlock(vp);
+
+	return error;
+}
+
+struct fileops vfs_ops = {
+	.fo_init	= vfs_fo_init,
+	.fo_close	= vfs_close,
+	.fo_read	= vfs_read,
+	.fo_write	= vfs_write,
+	.fo_ioctl	= vfs_ioctl,
+	.fo_stat	= vfs_stat,
+};
diff --git a/fs/vfs/vfs_syscalls.c b/fs/vfs/vfs_syscalls.c
index 50c1731dc..242be8968 100755
--- a/fs/vfs/vfs_syscalls.c
+++ b/fs/vfs/vfs_syscalls.c
@@ -131,10 +131,12 @@ sys_open(char *path, int flags, mode_t mode, file_t *pfp)
 		return error;
 	}
 	memset(fp, 0, sizeof(struct file));
-	fp->f_vnode = vp;
 	fp->f_flags = flags;
-	fp->f_offset = 0;
 	fp->f_count = 1;
+	fp->f_offset = 0;
+	fp->f_vnode = vp;
+	fp->f_ops = &vfs_ops;
+	fp->f_type = DTYPE_VNODE;
 	*pfp = fp;
 	vn_unlock(vp);
 	return 0;
@@ -143,9 +145,6 @@ sys_open(char *path, int flags, mode_t mode, file_t *pfp)
 int
 sys_close(file_t fp)
 {
-	vnode_t vp;
-	int error;
-
 	DPRINTF(VFSDB_SYSCALL, ("sys_close: fp=%x count=%d\n",
 				(u_int)fp, fp->f_count));
 
@@ -155,13 +154,7 @@ sys_close(file_t fp)
 	if (--fp->f_count > 0)
 		return 0;
 
-	vp = fp->f_vnode;
-	vn_lock(vp);
-	if ((error = VOP_CLOSE(vp, fp)) != 0) {
-		vn_unlock(vp);
-		return error;
-	}
-	vput(vp);
+	fo_close(fp);
 	free(fp);
 	return 0;
 }
@@ -170,7 +163,6 @@ int
 sys_read(file_t fp, struct iovec *iov, size_t niov,
 		off_t offset, size_t *count)
 {
-	struct vnode *vp = fp->f_vnode;
 	struct uio *uio = NULL;
 	ssize_t bytes;
 	int error;
@@ -185,25 +177,18 @@ sys_read(file_t fp, struct iovec *iov, size_t niov,
 	if (error)
 		return error;
 
+	bytes = uio->uio_resid;
+
 	if (uio->uio_resid == 0) {
 		*count = 0;
 		return 0;
 	}
-	bytes = uio->uio_resid;
 
-	vn_lock(vp);
 	uio->uio_rw = UIO_READ;
-	if (offset == -1)
-		uio->uio_offset = fp->f_offset;
-	else
-		uio->uio_offset = offset;
-	error = VOP_READ(vp, uio, 0);
-	if (!error) {
-		*count = bytes - uio->uio_resid;
-		if (offset == -1)
-			fp->f_offset += *count;
-	}
-	vn_unlock(vp);
+	uio->uio_offset = offset;
+	fo_read(fp, uio, (offset == -1) ? 0 : FOF_OFFSET);
+	*count = bytes - uio->uio_resid;
+
 	return error;
 }
 
@@ -211,10 +196,8 @@ int
 sys_write(file_t fp, struct iovec *iov, size_t niov,
 		off_t offset, size_t *count)
 {
-	struct vnode *vp = fp->f_vnode;
 	struct uio *uio = NULL;
 	ssize_t bytes;
-	int ioflags = 0;
 	int error;
 
 	DPRINTF(VFSDB_SYSCALL, ("sys_write: fp=%x uio=%x niv=%zu\n",
@@ -222,8 +205,6 @@ sys_write(file_t fp, struct iovec *iov, size_t niov,
 
 	if ((fp->f_flags & FWRITE) == 0)
 		return EBADF;
-	if (fp->f_flags & O_APPEND)
-		ioflags |= IO_APPEND;
 
 	error = copyinuio(iov, niov, &uio);
 	if (error)
@@ -233,21 +214,14 @@ sys_write(file_t fp, struct iovec *iov, size_t niov,
 		*count = 0;
 		return 0;
 	}
+
 	bytes = uio->uio_resid;
 
-	vn_lock(vp);
 	uio->uio_rw = UIO_WRITE;
-	if (offset == -1)
-		uio->uio_offset = fp->f_offset;
-	else
-		uio->uio_offset = offset;
-	error = VOP_WRITE(vp, uio, ioflags);
-	if (!error) {
-		*count = bytes - uio->uio_resid;
-		if (offset == -1)
-			fp->f_offset += *count;
-	}
-	vn_unlock(vp);
+	uio->uio_offset = offset;
+	fo_write(fp, uio, (offset == -1) ? 0 : FOF_OFFSET);
+	*count = bytes - uio->uio_resid;
+
 	return error;
 }
 
@@ -302,7 +276,6 @@ sys_lseek(file_t fp, off_t off, int type, off_t *origin)
 int
 sys_ioctl(file_t fp, u_long request, void *buf)
 {
-	vnode_t vp;
 	int error;
 
 	DPRINTF(VFSDB_SYSCALL, ("sys_ioctl: fp=%x request=%x\n", fp, request));
@@ -310,10 +283,8 @@ sys_ioctl(file_t fp, u_long request, void *buf)
 	if ((fp->f_flags & (FREAD | FWRITE)) == 0)
 		return EBADF;
 
-	vp = fp->f_vnode;
-	vn_lock(vp);
-	error = VOP_IOCTL(vp, fp, request, buf);
-	vn_unlock(vp);
+	error = fo_ioctl(fp, request, buf);
+
 	DPRINTF(VFSDB_SYSCALL, ("sys_ioctl: comp error=%d\n", error));
 	return error;
 }
@@ -339,15 +310,12 @@ sys_fsync(file_t fp)
 int
 sys_fstat(file_t fp, struct stat *st)
 {
-	vnode_t vp;
 	int error = 0;
 
 	DPRINTF(VFSDB_SYSCALL, ("sys_fstat: fp=%x\n", fp));
 
-	vp = fp->f_vnode;
-	vn_lock(vp);
-	error = vn_stat(vp, st);
-	vn_unlock(vp);
+	error = fo_stat(fp, st);
+
 	return error;
 }
 
diff --git a/include/osv/file.h b/include/osv/file.h
index eecdaa353..69bcf6800 100755
--- a/include/osv/file.h
+++ b/include/osv/file.h
@@ -27,27 +27,138 @@
  * SUCH DAMAGE.
  */
 
-#ifndef _SYS_FILE_H_
-#define _SYS_FILE_H_
+#ifndef _OSV_FILE_H_
+#define _OSV_FILE_H_
 
 #include <sys/cdefs.h>
 #include <sys/types.h>
+#include <sys/stat.h>
+
+#include <osv/uio.h>
 
 __BEGIN_DECLS
 
+/*
+ * File type
+ */
+typedef enum {
+	DTYPE_UNSPEC,
+	DTYPE_VNODE,
+	DTYPE_SOCKET
+} filetype_t;
+
 struct vnode;
+struct fileops;
 
 /*
  * File structure
  */
 struct file {
-	int		f_flags;	/* open flag */
+	int		f_flags;	/* open flags */
 	int		f_count;	/* reference count */
 	off_t		f_offset;	/* current position in file */
 	struct vnode	*f_vnode;	/* vnode */
+	struct fileops	*f_ops;		/* file ops abstraction */
+	void		*f_data;	/* file descriptor specific data */
+	filetype_t	f_type;		/* descriptor type */
 };
+
 typedef struct file *file_t;
 
+#define FOF_OFFSET  0x0800    /* Use the offset in uio argument */
+
+typedef int fo_init_t(struct file *fp);
+typedef int fo_rdwr_t(struct file *fp, struct uio *uio, int flags);
+typedef int fo_truncate_t(struct file *fp, off_t length);
+typedef int fo_ioctl_t(struct file *fp, u_long com, void *data);
+typedef int fo_poll_t(struct file *fp, int events);
+typedef int fo_stat_t(struct file *fp, struct stat *sb);
+typedef int fo_close_t(struct file *fp);
+typedef int fo_chmod_t(struct file *fp, mode_t mode);
+
+
+struct fileops {
+	fo_init_t   *fo_init;
+	fo_rdwr_t   *fo_read;
+	fo_rdwr_t   *fo_write;
+	fo_truncate_t   *fo_truncate;
+	fo_ioctl_t  *fo_ioctl;
+	fo_poll_t   *fo_poll;
+	fo_stat_t   *fo_stat;
+	fo_close_t  *fo_close;
+	fo_chmod_t  *fo_chmod;
+};
+
+extern struct fileops vfs_ops;
+
+
+/*
+ * Easy inline functions for invoking the file operations
+ */
+static __inline fo_init_t   fo_init;
+static __inline fo_rdwr_t   fo_read;
+static __inline fo_rdwr_t   fo_write;
+static __inline fo_truncate_t   fo_truncate;
+static __inline fo_ioctl_t  fo_ioctl;
+static __inline fo_poll_t   fo_poll;
+static __inline fo_stat_t   fo_stat;
+static __inline fo_close_t  fo_close;
+static __inline fo_chmod_t  fo_chmod;
+
+static __inline int
+fo_init(struct file *fp)
+{
+	return fp->f_ops->fo_init(fp);
+}
+
+static __inline int
+fo_read(struct file *fp, struct uio *uio, int flags)
+{
+	return fp->f_ops->fo_read(fp, uio, flags);
+}
+
+static __inline int
+fo_write(struct file *fp, struct uio *uio, int flags)
+{
+	return fp->f_ops->fo_write(fp, uio, flags);
+}
+
+static __inline int
+fo_truncate(struct file *fp, off_t length)
+{
+	return fp->f_ops->fo_truncate(fp, length);
+}
+
+static __inline int
+fo_ioctl(struct file *fp, u_long com, void *data)
+{
+	return fp->f_ops->fo_ioctl(fp, com, data);
+}
+
+static __inline int
+fo_poll(struct file *fp, int events)
+{
+	return fp->f_ops->fo_poll(fp, events);
+}
+
+static __inline int
+fo_stat(struct file *fp, struct stat *sb)
+{
+	return fp->f_ops->fo_stat(fp, sb);
+}
+
+static __inline int
+fo_close(struct file *fp)
+{
+	return fp->f_ops->fo_close(fp);
+}
+
+static __inline int
+fo_chmod(struct file *fp, mode_t mode)
+{
+	return fp->f_ops->fo_chmod(fp, mode);
+}
+
 __END_DECLS
 
-#endif /* !_SYS_FILE_H_ */
+#endif /* !_OSV_FILE_H_ */
-- 
GitLab