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