/* * file.c */ #define DEBUG_SUBSYSTEM S_SM #include #include #include #include #include #include #include #include "smfs_internal.h" static int smfs_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; struct inode *cache_inode; int rc; ENTRY; cache_inode = I2CI(inode); if (!cache_inode) RETURN(-ENOENT); if (cache_inode->i_mapping->a_ops->readpage) rc = cache_inode->i_mapping->a_ops->readpage(file, page); RETURN(rc); } static int smfs_writepage(struct page *page) { struct inode *inode = page->mapping->host; struct inode *cache_inode; int rc; ENTRY; cache_inode = I2CI(inode); if (!cache_inode) RETURN(-ENOENT); if (cache_inode->i_mapping->a_ops->writepage) rc = cache_inode->i_mapping->a_ops->writepage(page); RETURN(rc); } struct address_space_operations smfs_file_aops = { readpage: smfs_readpage, writepage: smfs_writepage, }; /* instantiate a file handle to the cache file */ void smfs_prepare_cachefile(struct inode *inode, struct file *file, struct inode *cache_inode, struct file *cache_file, struct dentry *cache_dentry) { ENTRY; cache_file->f_pos = file->f_pos; cache_file->f_mode = file->f_mode; cache_file->f_flags = file->f_flags; cache_file->f_count = file->f_count; cache_file->f_owner = file->f_owner; cache_file->f_op = inode->i_fop; cache_file->f_dentry = cache_dentry; cache_file->f_dentry->d_inode = cache_inode; EXIT; } /* update file structs*/ void smfs_update_file(struct file *file, struct file *cache_file) { ENTRY; file->f_pos = cache_file->f_pos; file->f_mode = cache_file->f_mode; file->f_flags = cache_file->f_flags; file->f_count = cache_file->f_count; file->f_owner = cache_file->f_owner; EXIT; } static ssize_t smfs_write (struct file *filp, const char *buf, size_t count, loff_t *ppos) { struct inode *cache_inode; struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; struct file open_file; struct dentry open_dentry; int rc; ENTRY; cache_inode = I2CI(inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cachefile(inode, filp, cache_inode, &open_file, &open_dentry); if (cache_inode->i_fop->write) cache_inode->i_fop->write(&open_file, buf, count, ppos); smfs_update_file(filp, &open_file); RETURN(rc); } int smfs_ioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long arg) { struct inode *cache_inode; struct dentry *dentry = filp->f_dentry; struct file open_file; struct dentry open_dentry; ssize_t rc; ENTRY; cache_inode = I2CI(dentry->d_inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cachefile(inode, filp, cache_inode, &open_file, &open_dentry); if (cache_inode->i_fop->ioctl) rc = cache_inode->i_fop->ioctl(cache_inode, &open_file, cmd, arg); smfs_update_file(filp, &open_file); RETURN(rc); } static ssize_t smfs_read (struct file *filp, char *buf, size_t count, loff_t *ppos) { struct inode *cache_inode; struct dentry *dentry = filp->f_dentry; struct file open_file; struct dentry open_dentry; ssize_t rc; ENTRY; cache_inode = I2CI(dentry->d_inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cachefile(dentry->d_inode, filp, cache_inode, &open_file, &open_dentry); if (cache_inode->i_fop->read) rc = cache_inode->i_fop->read(&open_file, buf, count, ppos); smfs_update_file(filp, &open_file); RETURN(rc); } static loff_t smfs_llseek(struct file *file, loff_t offset, int origin) { struct inode *cache_inode; struct dentry *dentry = file->f_dentry; struct file open_file; struct dentry open_dentry; ssize_t rc; ENTRY; cache_inode = I2CI(dentry->d_inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cachefile(dentry->d_inode, file, cache_inode, &open_file, &open_dentry); if (cache_inode->i_fop->llseek) rc = cache_inode->i_fop->llseek(&open_file, offset, origin); smfs_update_file(file, &open_file); RETURN(rc); } static int smfs_mmap(struct file * file, struct vm_area_struct * vma) { struct address_space *mapping = file->f_dentry->d_inode->i_mapping; struct inode *inode = mapping->host; struct inode *cache_inode = NULL; struct file open_file; struct dentry open_dentry; int rc = 0; cache_inode = I2CI(inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cachefile(inode, file, cache_inode, &open_file, &open_dentry); if (cache_inode->i_fop->mmap) rc = cache_inode->i_fop->mmap(&open_file, vma); smfs_update_file(file, &open_file); RETURN(rc); } static int smfs_open(struct inode * inode, struct file * filp) { struct inode *cache_inode = NULL; struct file open_file; struct dentry open_dentry; int rc = 0; cache_inode = I2CI(inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cachefile(inode, filp, cache_inode, &open_file, &open_dentry); if (cache_inode->i_fop->open) rc = cache_inode->i_fop->open(cache_inode, &open_file); smfs_update_file(filp, &open_file); RETURN(rc); } static int smfs_release(struct inode * inode, struct file * filp) { struct inode *cache_inode = NULL; struct file open_file; struct dentry open_dentry; int rc = 0; cache_inode = I2CI(inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cachefile(inode, filp, cache_inode, &open_file, &open_dentry); if (cache_inode->i_fop->release) rc = cache_inode->i_fop->release(cache_inode, &open_file); smfs_update_file(filp, &open_file); RETURN(rc); } int smfs_fsync(struct file * file, struct dentry *dentry, int datasync) { struct inode *inode = dentry->d_inode; struct inode *cache_inode; struct file open_file; struct dentry open_dentry; int rc = 0; cache_inode = I2CI(inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cachefile(inode, file, cache_inode, &open_file, &open_dentry); if (cache_inode->i_fop->fsync) rc = cache_inode->i_fop->fsync(&open_file, &open_dentry, datasync); smfs_update_file(file, &open_file); RETURN(rc); } struct file_operations smfs_file_fops = { llseek: smfs_llseek, read: smfs_read, write: smfs_write, ioctl: smfs_ioctl, mmap: smfs_mmap, open: smfs_open, release: smfs_release, fsync: smfs_fsync, }; static void smfs_prepare_cache_dentry(struct dentry *dentry, struct inode *inode) { atomic_set(&dentry->d_count, 1); dentry->d_vfs_flags = 0; dentry->d_flags = 0; dentry->d_inode = inode; dentry->d_op = NULL; dentry->d_fsdata = NULL; dentry->d_mounted = 0; INIT_LIST_HEAD(&dentry->d_hash); INIT_LIST_HEAD(&dentry->d_lru); INIT_LIST_HEAD(&dentry->d_subdirs); INIT_LIST_HEAD(&dentry->d_alias); } static void smfs_truncate(struct inode * inode) { struct inode *cache_inode; cache_inode = I2CI(inode); if (!cache_inode) return; if (cache_inode->i_op->truncate) cache_inode->i_op->truncate(cache_inode); duplicate_inode(inode, cache_inode); return; } int smfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *cache_inode; struct dentry open_dentry; int rc = 0; cache_inode = I2CI(dentry->d_inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cache_dentry(&open_dentry, cache_inode); if (cache_inode->i_op->setattr) rc = cache_inode->i_op->setattr(&open_dentry, attr); RETURN(rc); } int smfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { struct inode *cache_inode; struct dentry open_dentry; int rc = 0; cache_inode = I2CI(dentry->d_inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cache_dentry(&open_dentry, cache_inode); if (cache_inode->i_op->setattr) rc = cache_inode->i_op->setxattr(&open_dentry, name, value, size, flags); RETURN(rc); } int smfs_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size) { struct inode *cache_inode; struct dentry open_dentry; int rc = 0; cache_inode = I2CI(dentry->d_inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cache_dentry(&open_dentry, cache_inode); if (cache_inode->i_op->setattr) rc = cache_inode->i_op->getxattr(&open_dentry, name, buffer, size); RETURN(rc); } ssize_t smfs_listxattr(struct dentry *dentry, char *buffer, size_t size) { struct inode *cache_inode; struct dentry open_dentry; int rc = 0; cache_inode = I2CI(dentry->d_inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cache_dentry(&open_dentry, cache_inode); if (cache_inode->i_op->listxattr) rc = cache_inode->i_op->listxattr(&open_dentry, buffer, size); RETURN(rc); } int smfs_removexattr(struct dentry *dentry, const char *name) { struct inode *cache_inode; struct dentry open_dentry; int rc = 0; cache_inode = I2CI(dentry->d_inode); if (!cache_inode) RETURN(-ENOENT); smfs_prepare_cache_dentry(&open_dentry, cache_inode); if (cache_inode->i_op->removexattr) rc = cache_inode->i_op->removexattr(&open_dentry, name); RETURN(rc); } struct inode_operations smfs_file_iops = { truncate: smfs_truncate, /* BKL held */ setattr: smfs_setattr, /* BKL held */ setxattr: smfs_setxattr, /* BKL held */ getxattr: smfs_getxattr, /* BKL held */ listxattr: smfs_listxattr, /* BKL held */ removexattr: smfs_removexattr, /* BKL held */ };