linux/fs/coda/file.c
<<
>>
Prefs
   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
  30static ssize_t
  31coda_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
  41static ssize_t
  42coda_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
  64static int
  65coda_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
 103int 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
 136int 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
 172int 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
 200const 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