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); 38 } 39 40 static ssize_t 41 coda_file_splice_read(struct file *coda_file, loff_t *ppos, 42 struct pipe_inode_info *pipe, size_t count, 43 unsigned int flags) 44 { 45 ssize_t (*splice_read)(struct file *, loff_t *, 46 struct pipe_inode_info *, size_t, unsigned int); 47 struct coda_file_info *cfi; 48 struct file *host_file; 49 50 cfi = CODA_FTOC(coda_file); 51 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 52 host_file = cfi->cfi_container; 53 54 splice_read = host_file->f_op->splice_read; 55 if (!splice_read) 56 splice_read = default_file_splice_read; 57 58 return splice_read(host_file, ppos, pipe, count, flags); 59 } 60 61 static ssize_t 62 coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to) 63 { 64 struct file *coda_file = iocb->ki_filp; 65 struct inode *coda_inode = file_inode(coda_file); 66 struct coda_file_info *cfi = CODA_FTOC(coda_file); 67 struct file *host_file; 68 ssize_t ret; 69 70 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 71 72 host_file = cfi->cfi_container; 73 file_start_write(host_file); 74 inode_lock(coda_inode); 75 ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos); 76 coda_inode->i_size = file_inode(host_file)->i_size; 77 coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9; 78 coda_inode->i_mtime = coda_inode->i_ctime = CURRENT_TIME_SEC; 79 inode_unlock(coda_inode); 80 file_end_write(host_file); 81 return ret; 82 } 83 84 static int 85 coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma) 86 { 87 struct coda_file_info *cfi; 88 struct coda_inode_info *cii; 89 struct file *host_file; 90 struct inode *coda_inode, *host_inode; 91 92 cfi = CODA_FTOC(coda_file); 93 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 94 host_file = cfi->cfi_container; 95 96 if (!host_file->f_op->mmap) 97 return -ENODEV; 98 99 coda_inode = file_inode(coda_file); 100 host_inode = file_inode(host_file); 101 102 cii = ITOC(coda_inode); 103 spin_lock(&cii->c_lock); 104 coda_file->f_mapping = host_file->f_mapping; 105 if (coda_inode->i_mapping == &coda_inode->i_data) 106 coda_inode->i_mapping = host_inode->i_mapping; 107 108 /* only allow additional mmaps as long as userspace isn't changing 109 * the container file on us! */ 110 else if (coda_inode->i_mapping != host_inode->i_mapping) { 111 spin_unlock(&cii->c_lock); 112 return -EBUSY; 113 } 114 115 /* keep track of how often the coda_inode/host_file has been mmapped */ 116 cii->c_mapcount++; 117 cfi->cfi_mapcount++; 118 spin_unlock(&cii->c_lock); 119 120 return host_file->f_op->mmap(host_file, vma); 121 } 122 123 int coda_open(struct inode *coda_inode, struct file *coda_file) 124 { 125 struct file *host_file = NULL; 126 int error; 127 unsigned short flags = coda_file->f_flags & (~O_EXCL); 128 unsigned short coda_flags = coda_flags_to_cflags(flags); 129 struct coda_file_info *cfi; 130 131 cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL); 132 if (!cfi) 133 return -ENOMEM; 134 135 error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags, 136 &host_file); 137 if (!host_file) 138 error = -EIO; 139 140 if (error) { 141 kfree(cfi); 142 return error; 143 } 144 145 host_file->f_flags |= coda_file->f_flags & (O_APPEND | O_SYNC); 146 147 cfi->cfi_magic = CODA_MAGIC; 148 cfi->cfi_mapcount = 0; 149 cfi->cfi_container = host_file; 150 151 BUG_ON(coda_file->private_data != NULL); 152 coda_file->private_data = cfi; 153 return 0; 154 } 155 156 int coda_release(struct inode *coda_inode, struct file *coda_file) 157 { 158 unsigned short flags = (coda_file->f_flags) & (~O_EXCL); 159 unsigned short coda_flags = coda_flags_to_cflags(flags); 160 struct coda_file_info *cfi; 161 struct coda_inode_info *cii; 162 struct inode *host_inode; 163 int err; 164 165 cfi = CODA_FTOC(coda_file); 166 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 167 168 err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode), 169 coda_flags, coda_file->f_cred->fsuid); 170 171 host_inode = file_inode(cfi->cfi_container); 172 cii = ITOC(coda_inode); 173 174 /* did we mmap this file? */ 175 spin_lock(&cii->c_lock); 176 if (coda_inode->i_mapping == &host_inode->i_data) { 177 cii->c_mapcount -= cfi->cfi_mapcount; 178 if (!cii->c_mapcount) 179 coda_inode->i_mapping = &coda_inode->i_data; 180 } 181 spin_unlock(&cii->c_lock); 182 183 fput(cfi->cfi_container); 184 kfree(coda_file->private_data); 185 coda_file->private_data = NULL; 186 187 /* VFS fput ignores the return value from file_operations->release, so 188 * there is no use returning an error here */ 189 return 0; 190 } 191 192 int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync) 193 { 194 struct file *host_file; 195 struct inode *coda_inode = file_inode(coda_file); 196 struct coda_file_info *cfi; 197 int err; 198 199 if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) || 200 S_ISLNK(coda_inode->i_mode))) 201 return -EINVAL; 202 203 err = filemap_write_and_wait_range(coda_inode->i_mapping, start, end); 204 if (err) 205 return err; 206 inode_lock(coda_inode); 207 208 cfi = CODA_FTOC(coda_file); 209 BUG_ON(!cfi || cfi->cfi_magic != CODA_MAGIC); 210 host_file = cfi->cfi_container; 211 212 err = vfs_fsync(host_file, datasync); 213 if (!err && !datasync) 214 err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode)); 215 inode_unlock(coda_inode); 216 217 return err; 218 } 219 220 const struct file_operations coda_file_operations = { 221 .llseek = generic_file_llseek, 222 .read_iter = coda_file_read_iter, 223 .write_iter = coda_file_write_iter, 224 .mmap = coda_file_mmap, 225 .open = coda_open, 226 .release = coda_release, 227 .fsync = coda_fsync, 228 .splice_read = coda_file_splice_read, 229 }; 230 231