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
- Lines: 254
- Date:
Wed Apr 25 16:18:54 2001
- Orig file:
v2.4.3/linux/fs/coda/file.c
- Orig date:
Fri Dec 29 14:07:57 2000
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)