1 /* 2 * File operations for Coda. 3 * Original version: (C) 1996 Peter Braam 4 * Rewritten for Linux 2.1: (C) 1997 Carnegie Mellon University 5 * 6 * Carnegie Mellon encourages users of this code to contribute improvements 7 * to the Coda project. Contact Peter Braam <coda@cs.cmu.edu>. 8 */ 9 10 #include <linux/types.h> 11 #include <linux/kernel.h> 12 #include <linux/time.h> 13 #include <linux/file.h> 14 #include <linux/fs.h> 15 #include <linux/stat.h> 16 #include <linux/cred.h> 17 #include <linux/errno.h> 18 #include <linux/spinlock.h> 19 #include <linux/string.h> 20 #include <linux/slab.h> 21 #include <linux/uaccess.h> 22 23 #include <linux/coda.h> 24 #include <linux/coda_psdev.h> 25 26 #include "coda_linux.h" 27 #include "coda_int.h" 28 29 static ssize_t 30 coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to) 31 { 32 struct file *coda_file = iocb->ki_filp; 33 struct coda_file_info *cfi = CODA_FTOC(coda_file); 34 35 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 36 37 return vfs_iter_read(cfi->cfi_container, to, &iocb->ki_pos, 0); 38 } 39 40 static ssize_t 41 coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to) 42 { 43 struct file *coda_file = iocb->ki_filp; 44 struct inode *coda_inode = file_inode(coda_file); 45 struct coda_file_info *cfi = CODA_FTOC(coda_file); 46 struct file *host_file; 47 ssize_t ret; 48 49 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 50 51 host_file = cfi->cfi_container; 52 file_start_write(host_file); 53 inode_lock(coda_inode); 54 ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos, 0); 55 coda_inode->i_size = file_inode(host_file)->i_size; 56 coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9; 57 coda_inode->i_mtime = coda_inode->i_ctime = current_time(coda_inode); 58 inode_unlock(coda_inode); 59 file_end_write(host_file); 60 return ret; 61 } 62 63 static int 64 coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma) 65 { 66 struct coda_file_info *cfi; 67 struct coda_inode_info *cii; 68 struct file *host_file; 69 struct inode *coda_inode, *host_inode; 70 71 cfi = CODA_FTOC(coda_file); 72 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 73 host_file = cfi->cfi_container; 74 75 if (!host_file->f_op->mmap) 76 return -ENODEV; 77 78 coda_inode = file_inode(coda_file); 79 host_inode = file_inode(host_file); 80 81 cii = ITOC(coda_inode); 82 spin_lock(&cii->c_lock); 83 coda_file->f_mapping = host_file->f_mapping; 84 if (coda_inode->i_mapping == &coda_inode->i_data) 85 coda_inode->i_mapping = host_inode->i_mapping; 86 87 /* only allow additional mmaps as long as userspace isn't changing 88 * the container file on us! */ 89 else if (coda_inode->i_mapping != host_inode->i_mapping) { 90 spin_unlock(&cii->c_lock); 91 return -EBUSY; 92 } 93 94 /* keep track of how often the coda_inode/host_file has been mmapped */ 95 cii->c_mapcount++; 96 cfi->cfi_mapcount++; 97 spin_unlock(&cii->c_lock); 98 99 return call_mmap(host_file, vma); 100 } 101 102 int coda_open(struct inode *coda_inode, struct file *coda_file) 103 { 104 struct file *host_file = NULL; 105 int error; 106 unsigned short flags = coda_file->f_flags & (~O_EXCL); 107 unsigned short coda_flags = coda_flags_to_cflags(flags); 108 struct coda_file_info *cfi; 109 110 cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL); 111 if (!cfi) 112 return -ENOMEM; 113 114 error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, 115 &host_file); 116 if (!host_file) 117 error = -EIO; 118 119 if (error) { 120 kfree(cfi); 121 return error; 122 } 123 124 host_file->f_flags |= coda_file->f_flags & (O_APPEND | O_SYNC); 125 126 cfi->cfi_magic = CODA_MAGIC; 127 cfi->cfi_mapcount = 0; 128 cfi->cfi_container = host_file; 129 130 BUG_ON(coda_file->private_data != NULL); 131 coda_file->private_data = cfi; 132 return 0; 133 } 134 135 int coda_release(struct inode *coda_inode, struct file *coda_file) 136 { 137 unsigned short flags = (coda_file->f_flags) & (~O_EXCL); 138 unsigned short coda_flags = coda_flags_to_cflags(flags); 139 struct coda_file_info *cfi; 140 struct coda_inode_info *cii; 141 struct inode *host_inode; 142 int err; 143 144 cfi = CODA_FTOC(coda_file); 145 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 146 147 err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode), 148 coda_flags, coda_file->f_cred->fsuid); 149 150 host_inode = file_inode(cfi->cfi_container); 151 cii = ITOC(coda_inode); 152 153 /* did we mmap this file? */ 154 spin_lock(&cii->c_lock); 155 if (coda_inode->i_mapping == &host_inode->i_data) { 156 cii->c_mapcount -= cfi->cfi_mapcount; 157 if (!cii->c_mapcount) 158 coda_inode->i_mapping = &coda_inode->i_data; 159 } 160 spin_unlock(&cii->c_lock); 161 162 fput(cfi->cfi_container); 163 kfree(coda_file->private_data); 164 coda_file->private_data = NULL; 165 166 /* VFS fput ignores the return value from file_operations->release, so 167 * there is no use returning an error here */ 168 return 0; 169 } 170 171 int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) 172 { 173 struct file *host_file; 174 struct inode *coda_inode = file_inode(coda_file); 175 struct coda_file_info *cfi; 176 int err; 177 178 if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) || 179 S_ISLNK(coda_inode->i_mode))) 180 return -EINVAL; 181 182 err = filemap_write_and_wait_range(coda_inode->i_mapping, start, end); 183 if (err) 184 return err; 185 inode_lock(coda_inode); 186 187 cfi = CODA_FTOC(coda_file); 188 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 189 host_file = cfi->cfi_container; 190 191 err = vfs_fsync(host_file, datasync); 192 if (!err && !datasync) 193 err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode)); 194 inode_unlock(coda_inode); 195 196 return err; 197 } 198 199 const struct file_operations coda_file_operations = { 200 .llseek = generic_file_llseek, 201 .read_iter = coda_file_read_iter, 202 .write_iter = coda_file_write_iter, 203 .mmap = coda_file_mmap, 204 .open = coda_open, 205 .release = coda_release, 206 .fsync = coda_fsync, 207 .splice_read = generic_file_splice_read, 208 }; 209 210