summaryrefslogtreecommitdiffstats
path: root/fs/coda/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/coda/file.c')
-rw-r--r--fs/coda/file.c240
1 files changed, 240 insertions, 0 deletions
diff --git a/fs/coda/file.c b/fs/coda/file.c
new file mode 100644
index 000000000..225ca881a
--- /dev/null
+++ b/fs/coda/file.c
@@ -0,0 +1,240 @@
+/*
+ * File operations for Coda.
+ * Original version: (C) 1996 Peter Braam
+ * Rewritten for Linux 2.1: (C) 1997 Carnegie Mellon University
+ *
+ * Carnegie Mellon encourages users of this code to contribute improvements
+ * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>.
+ */
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/stat.h>
+#include <linux/errno.h>
+#include <linux/locks.h>
+#include <asm/segment.h>
+#include <linux/string.h>
+#include <asm/uaccess.h>
+
+#include <linux/coda_namecache.h>
+#include <linux/coda.h>
+#include <linux/coda_linux.h>
+#include <linux/coda_cnode.h>
+#include <linux/coda_psdev.h>
+
+/* file operations */
+static int coda_readpage(struct inode * inode, struct page * page);
+static ssize_t coda_file_read(struct file *f, char *buf, size_t count, loff_t *off);
+static ssize_t coda_file_write(struct file *f, const char *buf, size_t count, loff_t *off);
+static int coda_file_mmap(struct file * file, struct vm_area_struct * vma);
+
+/* exported from this file */
+struct inode_operations coda_file_inode_operations = {
+ &coda_file_operations, /* default file operations */
+ NULL, /* create */
+ NULL, /* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ coda_readpage, /* readpage */
+ NULL, /* writepage */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ coda_permission, /* permission */
+ NULL, /* smap */
+ NULL, /* update page */
+ NULL /* revalidate */
+};
+
+struct file_operations coda_file_operations = {
+ NULL, /* lseek - default should work for coda */
+ coda_file_read, /* read */
+ coda_file_write, /* write */
+ NULL, /* readdir */
+ NULL, /* select - default */
+ NULL, /* ioctl */
+ coda_file_mmap, /* mmap */
+ coda_open, /* open */
+ coda_release, /* release */
+ NULL, /* fsync */
+};
+
+/* File file operations */
+static int coda_readpage(struct inode * inode, struct page * page)
+{
+ struct inode *open_inode;
+ struct cnode *cnp;
+
+ ENTRY;
+
+ cnp = ITOC(inode);
+ CHECK_CNODE(cnp);
+
+ if ( ! cnp->c_ovp ) {
+ printk("coda_readpage: no open inode for ino %ld\n", inode->i_ino);
+ return -ENXIO;
+ }
+
+ open_inode = cnp->c_ovp;
+
+ CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", inode->i_ino, open_inode->i_ino, page->offset);
+
+ generic_readpage(open_inode, page);
+ EXIT;
+ return 0;
+}
+
+static int coda_file_mmap(struct file * file, struct vm_area_struct * vma)
+{
+ struct cnode *cnp;
+ cnp = ITOC(file->f_dentry->d_inode);
+ cnp->c_mmcount++;
+
+ return generic_file_mmap(file, vma);
+}
+
+static ssize_t coda_file_read(struct file *coda_file, char *buff,
+ size_t count, loff_t *ppos)
+{
+ struct cnode *cnp;
+ struct inode *coda_inode = coda_file->f_dentry->d_inode;
+ struct inode *cont_inode = NULL;
+ struct file cont_file;
+ struct dentry cont_dentry;
+ int result = 0;
+
+ ENTRY;
+
+ cnp = ITOC(coda_inode);
+ CHECK_CNODE(cnp);
+
+ cont_inode = cnp->c_ovp;
+ if ( cont_inode == NULL ) {
+ printk("coda_file_read: cached inode is 0!\n");
+ return -1;
+ }
+
+ coda_prepare_openfile(coda_inode, coda_file, cont_inode,
+ &cont_file, &cont_dentry);
+
+ if (!cont_file.f_op || ! cont_file.f_op->read) {
+ printk( "container file has no read in file operations.\n");
+ return -1;
+ }
+
+ result = cont_file.f_op->read(&cont_file , buff, count,
+ &(cont_file.f_pos));
+
+ CDEBUG(D_FILE, "ops at %x result %d, count %d, position: %d\n",
+ (int)cont_file.f_op, result, count, (int)cont_file.f_pos);
+
+ coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
+ return result;
+}
+
+
+static ssize_t coda_file_write(struct file *coda_file, const char *buff,
+ size_t count, loff_t *ppos)
+{
+ struct cnode *cnp;
+ struct inode *coda_inode = coda_file->f_dentry->d_inode;
+ struct inode *cont_inode = NULL;
+ struct file cont_file;
+ struct dentry cont_dentry;
+ int result = 0;
+
+ ENTRY;
+
+ cnp = ITOC(coda_inode);
+ CHECK_CNODE(cnp);
+
+ cont_inode = cnp->c_ovp;
+ if ( cont_inode == NULL ) {
+ printk("coda_file_write: cached inode is 0!\n");
+ return -1;
+ }
+
+ coda_prepare_openfile(coda_inode, coda_file, cont_inode,
+ &cont_file, &cont_dentry);
+
+ if (!cont_file.f_op || !cont_file.f_op->write) {
+ printk("coda_file_write: container file has no file ops.\n");
+ return -1;
+ }
+
+ cnp->c_flags &= ~C_VATTR;
+
+ down(&cont_inode->i_sem);
+ result = cont_file.f_op->write(&cont_file , buff, count,
+ &(cont_file.f_pos));
+ up(&cont_inode->i_sem);
+ coda_restore_codafile(coda_inode, coda_file, cont_inode, &cont_file);
+
+ return result;
+}
+
+
+
+/*
+ * support routines
+ */
+
+/* instantiate the container file and dentry object to do io */
+void coda_prepare_openfile(struct inode *i, struct file *coda_file,
+ struct inode *cont_inode, struct file *cont_file,
+ struct dentry *cont_dentry)
+{
+ cont_file->f_pos = coda_file->f_pos;
+ cont_file->f_mode = coda_file->f_mode;
+ cont_file->f_flags = coda_file->f_flags;
+ cont_file->f_count = coda_file->f_count;
+ cont_file->f_owner = coda_file->f_owner;
+ cont_file->f_op = cont_inode->i_op->default_file_ops;
+ cont_file->f_dentry = cont_dentry;
+ cont_file->f_dentry->d_inode = cont_inode;
+ return ;
+}
+
+/* update the Coda file & inode after I/O */
+void coda_restore_codafile(struct inode *coda_inode, struct file *coda_file,
+ struct inode *open_inode, struct file *open_file)
+{
+ coda_file->f_pos = open_file->f_pos;
+ /* XXX what about setting the mtime here too? */
+ coda_inode->i_mtime = open_inode->i_mtime;
+ coda_inode->i_size = open_inode->i_size;
+ return;
+}
+
+/* grab the ext2 inode of the container file */
+int coda_inode_grab(dev_t dev, ino_t ino, struct inode **ind)
+{
+ struct super_block *sbptr;
+
+ sbptr = get_super(dev);
+
+ if ( !sbptr ) {
+ printk("coda_inode_grab: coda_find_super returns NULL.\n");
+ return -ENXIO;
+ }
+
+ *ind = NULL;
+ *ind = iget(sbptr, ino);
+
+ if ( *ind == NULL ) {
+ printk("coda_inode_grab: iget(dev: %d, ino: %ld)
+ returns NULL.\n", dev, ino);
+ return -ENOENT;
+ }
+ CDEBUG(D_FILE, "ino: %ld, ops at %x\n", ino, (int)(*ind)->i_op);
+ return 0;
+}
+