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