URL
https://opencores.org/ocsvn/or1k/or1k/trunk
Subversion Repositories or1k
[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [coda/] [file.c] - Rev 1275
Go to most recent revision | Compare with Previous | Blame | View Log
/* * 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/file.h> #include <linux/fs.h> #include <linux/stat.h> #include <linux/errno.h> #include <linux/locks.h> #include <linux/smp_lock.h> #include <linux/string.h> #include <asm/uaccess.h> #include <linux/coda.h> #include <linux/coda_linux.h> #include <linux/coda_fs_i.h> #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_read(struct file *coda_file, char *buf, size_t count, loff_t *ppos) { struct coda_file_info *cfi; struct file *host_file; cfi = CODA_FTOC(coda_file); if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG(); host_file = cfi->cfi_container; if (!host_file->f_op || !host_file->f_op->read) return -EINVAL; return host_file->f_op->read(host_file, buf, count, ppos); } static ssize_t coda_file_write(struct file *coda_file, const char *buf, size_t count, loff_t *ppos) { struct inode *coda_inode = coda_file->f_dentry->d_inode; struct coda_file_info *cfi; struct file *host_file; ssize_t ret; cfi = CODA_FTOC(coda_file); if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG(); host_file = cfi->cfi_container; if (!host_file->f_op || !host_file->f_op->write) return -EINVAL; down(&coda_inode->i_sem); ret = host_file->f_op->write(host_file, buf, count, ppos); coda_inode->i_size = host_file->f_dentry->d_inode->i_size; coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9; coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME; up(&coda_inode->i_sem); return ret; } static int coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma) { struct coda_file_info *cfi; struct coda_inode_info *cii; struct file *host_file; struct inode *coda_inode, *host_inode; cfi = CODA_FTOC(coda_file); if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG(); host_file = cfi->cfi_container; if (!host_file->f_op || !host_file->f_op->mmap) return -ENODEV; coda_inode = coda_file->f_dentry->d_inode; host_inode = host_file->f_dentry->d_inode; if (coda_inode->i_mapping == &coda_inode->i_data) coda_inode->i_mapping = host_inode->i_mapping; /* only allow additional mmaps as long as userspace isn't changing * the container file on us! */ else if (coda_inode->i_mapping != host_inode->i_mapping) return -EBUSY; /* keep track of how often the coda_inode/host_file has been mmapped */ cii = ITOC(coda_inode); cii->c_mapcount++; cfi->cfi_mapcount++; return host_file->f_op->mmap(host_file, vma); } int coda_open(struct inode *coda_inode, struct file *coda_file) { struct file *host_file = NULL; int error; unsigned short flags = coda_file->f_flags & (~O_EXCL); unsigned short coda_flags = coda_flags_to_cflags(flags); struct coda_file_info *cfi; struct inode *host_inode; coda_vfs_stat.open++; cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL); if (!cfi) return -ENOMEM; lock_kernel(); error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, &host_file); if (!error && !host_file) error = EBADF; if (error) { kfree(cfi); unlock_kernel(); return error; } host_file->f_flags |= coda_file->f_flags & (O_APPEND | O_SYNC); cfi->cfi_magic = CODA_MAGIC; cfi->cfi_mapcount = 0; cfi->cfi_container = host_file; coda_load_creds(&cfi->cfi_cred); host_inode = host_file->f_dentry->d_inode; if (coda_inode->i_mapping == &coda_inode->i_data) coda_inode->i_mapping = host_inode->i_mapping; else if (coda_inode->i_mapping != host_inode->i_mapping) { /* This is not a good thing, it doesn't happen with 'venus' * Coda's own userspace daemon, but others might not provide * the same guarantees. Still looking for the real fix. */ printk("coda_open: changed mapping\n"); coda_inode->i_mapping = host_inode->i_mapping; } if (coda_file->private_data != NULL) BUG(); coda_file->private_data = cfi; unlock_kernel(); return 0; } int coda_flush(struct file *coda_file) { unsigned short flags = coda_file->f_flags & ~O_EXCL; unsigned short coda_flags = coda_flags_to_cflags(flags); struct coda_file_info *cfi; struct inode *coda_inode; int err = 0, fcnt; coda_vfs_stat.flush++; /* No need to make an upcall when we have not made any modifications * to the file */ if ((coda_file->f_flags & O_ACCMODE) == O_RDONLY) return 0; if (use_coda_close) return 0; fcnt = file_count(coda_file); if (fcnt > 1) return 0; coda_inode = coda_file->f_dentry->d_inode; cfi = CODA_FTOC(coda_file); if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG(); err = venus_store(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, &cfi->cfi_cred); if (err == -EOPNOTSUPP) { use_coda_close = 1; err = 0; } return err; } int coda_release(struct inode *coda_inode, struct file *coda_file) { unsigned short flags = (coda_file->f_flags) & (~O_EXCL); unsigned short coda_flags = coda_flags_to_cflags(flags); struct coda_file_info *cfi; struct coda_inode_info *cii; struct inode *host_inode; int err = 0; lock_kernel(); coda_vfs_stat.release++; if (!use_coda_close) { err = venus_release(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags); if (err == -EOPNOTSUPP) { use_coda_close = 1; err = 0; } } cfi = CODA_FTOC(coda_file); if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG(); if (use_coda_close) err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, &cfi->cfi_cred); host_inode = cfi->cfi_container->f_dentry->d_inode; cii = ITOC(coda_inode); /* did we mmap this file? */ if (coda_inode->i_mapping == &host_inode->i_data) { cii->c_mapcount -= cfi->cfi_mapcount; if (!cii->c_mapcount) coda_inode->i_mapping = &coda_inode->i_data; } fput(cfi->cfi_container); kfree(coda_file->private_data); coda_file->private_data = NULL; unlock_kernel(); return err; } int coda_fsync(struct file *coda_file, struct dentry *coda_dentry, int datasync) { struct file *host_file; struct dentry *host_dentry; struct inode *host_inode, *coda_inode = coda_dentry->d_inode; struct coda_file_info *cfi; int err = 0; if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) || S_ISLNK(coda_inode->i_mode))) return -EINVAL; cfi = CODA_FTOC(coda_file); if (!cfi || cfi->cfi_magic != CODA_MAGIC) BUG(); host_file = cfi->cfi_container; coda_vfs_stat.fsync++; if (host_file->f_op && host_file->f_op->fsync) { host_dentry = host_file->f_dentry; host_inode = host_dentry->d_inode; down(&host_inode->i_sem); err = host_file->f_op->fsync(host_file, host_dentry, datasync); up(&host_inode->i_sem); } if ( !err && !datasync ) { lock_kernel(); err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode)); unlock_kernel(); } return err; } struct file_operations coda_file_operations = { llseek: generic_file_llseek, read: coda_file_read, write: coda_file_write, mmap: coda_file_mmap, open: coda_open, flush: coda_flush, release: coda_release, fsync: coda_fsync, };
Go to most recent revision | Compare with Previous | Blame | View Log