patch-2.4.4 linux/fs/coda/file.c

Next file: linux/fs/coda/inode.c
Previous file: linux/fs/coda/dir.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.3/linux/fs/coda/file.c linux/fs/coda/file.c
@@ -10,6 +10,7 @@
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
+#include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
@@ -25,54 +26,213 @@
 #include <linux/coda_psdev.h>
 #include <linux/coda_proc.h>
 
+/* if CODA_STORE fails with EOPNOTSUPP, venus clearly doesn't support
+ * CODA_STORE/CODA_RELEASE and we fall back on using the CODA_CLOSE upcall */
+int use_coda_close;
+
 static ssize_t
 coda_file_write(struct file *file,const char *buf,size_t count,loff_t *ppos)
 {
-	struct inode *inode = file->f_dentry->d_inode;
-	struct inode *container = inode->i_mapping->host;
+	struct file *cfile;
+	struct inode *cinode, *inode = file->f_dentry->d_inode;
+	struct coda_inode_info *cii = ITOC(inode);
 	ssize_t n;
 
-        down(&container->i_sem);
+	cfile = cii->c_container;
+	if (!cfile) BUG();
+
+	if (!cfile->f_op || cfile->f_op->write != generic_file_write)
+		BUG();
+
+	cinode = cfile->f_dentry->d_inode;
+	down(&cinode->i_sem);
 
 	n = generic_file_write(file, buf, count, ppos);
-	inode->i_size = container->i_size;
+	inode->i_size = cinode->i_size;
 
-        up(&container->i_sem);
+	up(&cinode->i_sem);
 
 	return n;
 }
 
-/* exported from this file (used for dirs) */
-int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync)
+int coda_open(struct inode *i, struct file *f)
 {
-	struct inode *inode = coda_dentry->d_inode;
-	struct dentry cont_dentry;
-	int result = 0;
+	struct file *fh = NULL;
+	int error = 0;
+	unsigned short flags = f->f_flags & (~O_EXCL);
+	unsigned short coda_flags = coda_flags_to_cflags(flags);
+	struct coda_cred *cred;
+	struct coda_inode_info *cii;
+
+	lock_kernel();
+	ENTRY;
+	coda_vfs_stat.open++;
+
+	CDEBUG(D_SPECIAL, "OPEN inode number: %ld, count %d, flags %o.\n", 
+	       f->f_dentry->d_inode->i_ino, atomic_read(&f->f_dentry->d_count), flags);
+
+	error = venus_open(i->i_sb, coda_i2f(i), coda_flags, &fh); 
+	if (error || !fh) {
+	        CDEBUG(D_FILE, "coda_open: venus_open result %d\n", error);
+		unlock_kernel();
+		return error;
+	}
+
+	/* coda_upcall returns filehandle of container file object */
+	cii = ITOC(i);
+	if (cii->c_container)
+		fput(cii->c_container);
+
+	cii->c_contcount++;
+	cii->c_container = fh;
+	i->i_mapping = &cii->c_container->f_dentry->d_inode->i_data;
+
+	cred = kmalloc(sizeof(struct coda_cred), GFP_KERNEL);
+
+	/* If the allocation failed, we'll just muddle on. This actually works
+	 * fine for normal cases. (i.e. when open credentials are the same as
+	 * close credentials) */
+	if (cred) {
+		coda_load_creds(cred);
+		f->private_data = cred;
+	}
+
+	CDEBUG(D_FILE, "result %d, coda i->i_count is %d, cii->contcount is %d for ino %ld\n", 
+	       error, atomic_read(&i->i_count), cii->c_contcount, i->i_ino);
+	CDEBUG(D_FILE, "cache ino: %ld, count %d, ops %p\n", 
+	       fh->f_dentry->d_inode->i_ino,
+	       atomic_read(&fh->f_dentry->d_inode->i_count),
+               fh->f_dentry->d_inode->i_op);
+	EXIT;
+	unlock_kernel();
+	return 0;
+}
+
+
+int coda_flush(struct file *file)
+{
+	unsigned short flags = (file->f_flags) & (~O_EXCL);
+	unsigned short cflags;
+	struct coda_inode_info *cii;
+	struct file *cfile;
+	struct inode *cinode, *inode;
+	int err = 0, fcnt;
+
+	ENTRY;
+	coda_vfs_stat.flush++;
+
+	/* No need to make an upcall when we have not made any modifications
+	 * to the file */
+	if ((file->f_flags & O_ACCMODE) == O_RDONLY)
+		return 0;
+
+	if (use_coda_close)
+		return 0;
+
+	fcnt = file_count(file);
+	if (fcnt > 1) return 0;
+
+	cflags = coda_flags_to_cflags(flags);
+
+	inode = file->f_dentry->d_inode;
+	cii = ITOC(inode);
+	cfile = cii->c_container;
+	if (!cfile) BUG();
+
+	cinode = cfile->f_dentry->d_inode;
+
+	CDEBUG(D_FILE, "FLUSH coda (file %p ct %d)\n", file, fcnt);
+
+	err = venus_store(inode->i_sb, coda_i2f(inode), cflags,
+                          (struct coda_cred *)file->private_data);
+	if (err == -EOPNOTSUPP) {
+		use_coda_close = 1;
+		err = 0;
+	}
+
+	CDEBUG(D_FILE, "coda_flush: result: %d\n", err);
+	return err;
+}
+
+int coda_release(struct inode *i, struct file *f)
+{
+	unsigned short flags = (f->f_flags) & (~O_EXCL);
+	unsigned short cflags = coda_flags_to_cflags(flags);
+	struct coda_inode_info *cii;
+	struct file *cfile;
+	int err = 0;
+
+	lock_kernel();
+	ENTRY;
+	coda_vfs_stat.release++;
+ 
+	if (!use_coda_close) {
+		err = venus_release(i->i_sb, coda_i2f(i), cflags);
+		if (err == -EOPNOTSUPP) {
+			use_coda_close = 1;
+			err = 0;
+		}
+	}
+
+	if (use_coda_close)
+		err = venus_close(i->i_sb, coda_i2f(i), cflags,
+                                  (struct coda_cred *)f->private_data);
+
+	cii = ITOC(i);
+	cfile = cii->c_container;
+	if (!cfile) BUG();
+
+	if (--cii->c_contcount) {
+		unlock_kernel();
+		return err;
+	}
+
+	i->i_mapping = &i->i_data;
+	fput(cfile);
+	cii->c_container = NULL;
+
+	if (f->private_data) {
+		kfree(f->private_data);
+		f->private_data = NULL;
+	}
+
+	unlock_kernel();
+	return err;
+}
+
+int coda_fsync(struct file *file, struct dentry *dentry, int datasync)
+{
+	struct file *cfile;
+	struct dentry *cdentry;
+	struct inode *cinode, *inode = dentry->d_inode;
+	struct coda_inode_info *cii = ITOC(inode);
+	int err = 0;
 	ENTRY;
-	coda_vfs_stat.fsync++;
 
 	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
 	      S_ISLNK(inode->i_mode)))
 		return -EINVAL;
 
-	if ( inode->i_mapping == &inode->i_data ) {
-		printk("coda_fsync: no container inode!\n");
-                return -1; 
-        }
-
-	cont_dentry.d_inode = inode->i_mapping->host;
-  
-	down(&cont_dentry.d_inode->i_sem);
-	result = file_fsync(NULL, &cont_dentry, datasync);
-	up(&cont_dentry.d_inode->i_sem);
+	cfile = cii->c_container;
+	if (!cfile) BUG();
+
+	coda_vfs_stat.fsync++;
+
+	if (cfile->f_op && cfile->f_op->fsync) {
+		cdentry = cfile->f_dentry;
+		cinode = cdentry->d_inode;
+		down(&cinode->i_sem);
+		err = cfile->f_op->fsync(cfile, cdentry, datasync);
+		up(&cinode->i_sem);
+	}
 
-	if ( result == 0 && datasync == 0 ) {
+	if ( !err && !datasync ) {
 		lock_kernel();
-		result = venus_fsync(inode->i_sb, coda_i2f(inode));
+		err = venus_fsync(inode->i_sb, coda_i2f(inode));
 		unlock_kernel();
 	}
 
-	return result;
+	return err;
 }
 
 struct file_operations coda_file_operations = {
@@ -80,6 +240,7 @@
 	write:		coda_file_write,
 	mmap:		generic_file_mmap,
 	open:		coda_open,
+	flush:  	coda_flush,
 	release:	coda_release,
 	fsync:		coda_fsync,
 };

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)