Blame view

fs/coda/file.c 7.94 KB
b24413180   Greg Kroah-Hartman   License cleanup: ...
1
  // SPDX-License-Identifier: GPL-2.0
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  /*
   * 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   Randy Dunlap   coda: fix creds r...
17
  #include <linux/cred.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
18
  #include <linux/errno.h>
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
19
  #include <linux/spinlock.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20
  #include <linux/string.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
21
  #include <linux/slab.h>
834b46c37   Fabian Frederick   fs/coda: use linu...
22
  #include <linux/uaccess.h>
a9fba24c6   Pedro Cuadra   coda: add hinting...
23
  #include <linux/uio.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
24
25
  
  #include <linux/coda.h>
8fc8b9df8   David Howells   coda: move intern...
26
  #include "coda_psdev.h"
31a203df9   Al Viro   take coda-private...
27
  #include "coda_linux.h"
c98d8cfbc   Adrian Bunk   [PATCH] fs/coda/:...
28
  #include "coda_int.h"
7fa0a1da3   Jan Harkes   coda: pass the ho...
29
30
31
32
33
34
  struct coda_vm_ops {
  	atomic_t refcnt;
  	struct file *coda_file;
  	const struct vm_operations_struct *host_vm_ops;
  	struct vm_operations_struct vm_ops;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  static ssize_t
c12c49e70   Al Viro   coda: switch to -...
36
  coda_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
  {
c12c49e70   Al Viro   coda: switch to -...
38
  	struct file *coda_file = iocb->ki_filp;
a9fba24c6   Pedro Cuadra   coda: add hinting...
39
  	struct inode *coda_inode = file_inode(coda_file);
5bb44810f   Fabian Frederick   coda: ftoc validi...
40
  	struct coda_file_info *cfi = coda_ftoc(coda_file);
a9fba24c6   Pedro Cuadra   coda: add hinting...
41
42
43
44
45
46
47
48
49
50
51
  	loff_t ki_pos = iocb->ki_pos;
  	size_t count = iov_iter_count(to);
  	ssize_t ret;
  
  	ret = venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
  				  &cfi->cfi_access_intent,
  				  count, ki_pos, CODA_ACCESS_TYPE_READ);
  	if (ret)
  		goto finish_read;
  
  	ret = vfs_iter_read(cfi->cfi_container, to, &iocb->ki_pos, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52

a9fba24c6   Pedro Cuadra   coda: add hinting...
53
54
55
56
57
  finish_read:
  	venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
  			    &cfi->cfi_access_intent,
  			    count, ki_pos, CODA_ACCESS_TYPE_READ_FINISH);
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
58
59
60
  }
  
  static ssize_t
c12c49e70   Al Viro   coda: switch to -...
61
  coda_file_write_iter(struct kiocb *iocb, struct iov_iter *to)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
  {
c12c49e70   Al Viro   coda: switch to -...
63
64
  	struct file *coda_file = iocb->ki_filp;
  	struct inode *coda_inode = file_inode(coda_file);
5bb44810f   Fabian Frederick   coda: ftoc validi...
65
  	struct coda_file_info *cfi = coda_ftoc(coda_file);
a9fba24c6   Pedro Cuadra   coda: add hinting...
66
67
68
  	struct file *host_file = cfi->cfi_container;
  	loff_t ki_pos = iocb->ki_pos;
  	size_t count = iov_iter_count(to);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
  	ssize_t ret;
a9fba24c6   Pedro Cuadra   coda: add hinting...
70
71
72
73
74
  	ret = venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
  				  &cfi->cfi_access_intent,
  				  count, ki_pos, CODA_ACCESS_TYPE_WRITE);
  	if (ret)
  		goto finish_write;
03d95eb2f   Al Viro   lift sb_start_wri...
75
  	file_start_write(host_file);
5955102c9   Al Viro   wrappers for ->i_...
76
  	inode_lock(coda_inode);
abbb65899   Christoph Hellwig   fs: implement vfs...
77
  	ret = vfs_iter_write(cfi->cfi_container, to, &iocb->ki_pos, 0);
c12c49e70   Al Viro   coda: switch to -...
78
  	coda_inode->i_size = file_inode(host_file)->i_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
79
  	coda_inode->i_blocks = (coda_inode->i_size + 511) >> 9;
02027d42c   Deepa Dinamani   fs: Replace CURRE...
80
  	coda_inode->i_mtime = coda_inode->i_ctime = current_time(coda_inode);
5955102c9   Al Viro   wrappers for ->i_...
81
  	inode_unlock(coda_inode);
03d95eb2f   Al Viro   lift sb_start_wri...
82
  	file_end_write(host_file);
a9fba24c6   Pedro Cuadra   coda: add hinting...
83
84
85
86
87
  
  finish_write:
  	venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
  			    &cfi->cfi_access_intent,
  			    count, ki_pos, CODA_ACCESS_TYPE_WRITE_FINISH);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
  	return ret;
  }
7fa0a1da3   Jan Harkes   coda: pass the ho...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
  static void
  coda_vm_open(struct vm_area_struct *vma)
  {
  	struct coda_vm_ops *cvm_ops =
  		container_of(vma->vm_ops, struct coda_vm_ops, vm_ops);
  
  	atomic_inc(&cvm_ops->refcnt);
  
  	if (cvm_ops->host_vm_ops && cvm_ops->host_vm_ops->open)
  		cvm_ops->host_vm_ops->open(vma);
  }
  
  static void
  coda_vm_close(struct vm_area_struct *vma)
  {
  	struct coda_vm_ops *cvm_ops =
  		container_of(vma->vm_ops, struct coda_vm_ops, vm_ops);
  
  	if (cvm_ops->host_vm_ops && cvm_ops->host_vm_ops->close)
  		cvm_ops->host_vm_ops->close(vma);
  
  	if (atomic_dec_and_test(&cvm_ops->refcnt)) {
  		vma->vm_ops = cvm_ops->host_vm_ops;
  		fput(cvm_ops->coda_file);
  		kfree(cvm_ops);
  	}
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
117
118
119
  static int
  coda_file_mmap(struct file *coda_file, struct vm_area_struct *vma)
  {
a9fba24c6   Pedro Cuadra   coda: add hinting...
120
121
122
123
  	struct inode *coda_inode = file_inode(coda_file);
  	struct coda_file_info *cfi = coda_ftoc(coda_file);
  	struct file *host_file = cfi->cfi_container;
  	struct inode *host_inode = file_inode(host_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
124
  	struct coda_inode_info *cii;
7fa0a1da3   Jan Harkes   coda: pass the ho...
125
  	struct coda_vm_ops *cvm_ops;
a9fba24c6   Pedro Cuadra   coda: add hinting...
126
127
  	loff_t ppos;
  	size_t count;
7fa0a1da3   Jan Harkes   coda: pass the ho...
128
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129

72c2d5319   Al Viro   file->f_op is nev...
130
  	if (!host_file->f_op->mmap)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
  		return -ENODEV;
7fa0a1da3   Jan Harkes   coda: pass the ho...
132
133
  	if (WARN_ON(coda_file != vma->vm_file))
  		return -EIO;
a9fba24c6   Pedro Cuadra   coda: add hinting...
134
135
136
137
138
139
140
141
  	count = vma->vm_end - vma->vm_start;
  	ppos = vma->vm_pgoff * PAGE_SIZE;
  
  	ret = venus_access_intent(coda_inode->i_sb, coda_i2f(coda_inode),
  				  &cfi->cfi_access_intent,
  				  count, ppos, CODA_ACCESS_TYPE_MMAP);
  	if (ret)
  		return ret;
7fa0a1da3   Jan Harkes   coda: pass the ho...
142
143
144
  	cvm_ops = kmalloc(sizeof(struct coda_vm_ops), GFP_KERNEL);
  	if (!cvm_ops)
  		return -ENOMEM;
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
145
146
  	cii = ITOC(coda_inode);
  	spin_lock(&cii->c_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
  	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   Yoshihisa Abe   Coda: add spin lo...
153
154
  	else if (coda_inode->i_mapping != host_inode->i_mapping) {
  		spin_unlock(&cii->c_lock);
7fa0a1da3   Jan Harkes   coda: pass the ho...
155
  		kfree(cvm_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
  		return -EBUSY;
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
157
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
  
  	/* keep track of how often the coda_inode/host_file has been mmapped */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
  	cii->c_mapcount++;
  	cfi->cfi_mapcount++;
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
162
  	spin_unlock(&cii->c_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163

7fa0a1da3   Jan Harkes   coda: pass the ho...
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
  	vma->vm_file = get_file(host_file);
  	ret = call_mmap(vma->vm_file, vma);
  
  	if (ret) {
  		/* if call_mmap fails, our caller will put coda_file so we
  		 * should drop the reference to the host_file that we got.
  		 */
  		fput(host_file);
  		kfree(cvm_ops);
  	} else {
  		/* here we add redirects for the open/close vm_operations */
  		cvm_ops->host_vm_ops = vma->vm_ops;
  		if (vma->vm_ops)
  			cvm_ops->vm_ops = *vma->vm_ops;
  
  		cvm_ops->vm_ops.open = coda_vm_open;
  		cvm_ops->vm_ops.close = coda_vm_close;
  		cvm_ops->coda_file = coda_file;
  		atomic_set(&cvm_ops->refcnt, 1);
  
  		vma->vm_ops = &cvm_ops->vm_ops;
  	}
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
187
188
189
190
191
192
193
194
195
  }
  
  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   Linus Torvalds   Linux-2.6.12-rc2
196
  	cfi = kmalloc(sizeof(struct coda_file_info), GFP_KERNEL);
6ecbc4e1a   Josh Triplett   [PATCH] Remove in...
197
  	if (!cfi)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  		return -ENOMEM;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
199

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  	error = venus_open(coda_inode->i_sb, coda_i2f(coda_inode), coda_flags,
38c2e4370   Jan Harkes   coda: do not grab...
201
202
203
204
205
  			   &host_file);
  	if (!host_file)
  		error = -EIO;
  
  	if (error) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206
  		kfree(cfi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
209
210
211
212
213
214
  		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;
a9fba24c6   Pedro Cuadra   coda: add hinting...
215
216
  	/* assume access intents are supported unless we hear otherwise */
  	cfi->cfi_access_intent = true;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
217
218
219
  
  	BUG_ON(coda_file->private_data != NULL);
  	coda_file->private_data = cfi;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
220
221
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
224
225
226
227
228
  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   Yoshihisa Abe   Coda: push BKL re...
229
  	int err;
3cf01f28c   Jan Harkes   coda: remove stat...
230

5bb44810f   Fabian Frederick   coda: ftoc validi...
231
  	cfi = coda_ftoc(coda_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
232

d3fec424b   Jan Harkes   coda: remove CODA...
233
  	err = venus_close(coda_inode->i_sb, coda_i2f(coda_inode),
d76b0d9b2   David Howells   CRED: Use creds i...
234
  			  coda_flags, coda_file->f_cred->fsuid);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235

496ad9aa8   Al Viro   new helper: file_...
236
  	host_inode = file_inode(cfi->cfi_container);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
237
238
239
  	cii = ITOC(coda_inode);
  
  	/* did we mmap this file? */
b5ce1d83a   Yoshihisa Abe   Coda: add spin lo...
240
  	spin_lock(&cii->c_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
241
242
243
244
245
  	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   Yoshihisa Abe   Coda: add spin lo...
246
  	spin_unlock(&cii->c_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
250
  
  	fput(cfi->cfi_container);
  	kfree(coda_file->private_data);
  	coda_file->private_data = NULL;
d3fec424b   Jan Harkes   coda: remove CODA...
251
252
253
  	/* VFS fput ignores the return value from file_operations->release, so
  	 * there is no use returning an error here */
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
255
  int coda_fsync(struct file *coda_file, loff_t start, loff_t end, int datasync)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256
257
  {
  	struct file *host_file;
496ad9aa8   Al Viro   new helper: file_...
258
  	struct inode *coda_inode = file_inode(coda_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
  	struct coda_file_info *cfi;
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
260
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
  
  	if (!(S_ISREG(coda_inode->i_mode) || S_ISDIR(coda_inode->i_mode) ||
  	      S_ISLNK(coda_inode->i_mode)))
  		return -EINVAL;
02c24a821   Josef Bacik   fs: push i_mutex ...
265
266
267
  	err = filemap_write_and_wait_range(coda_inode->i_mapping, start, end);
  	if (err)
  		return err;
5955102c9   Al Viro   wrappers for ->i_...
268
  	inode_lock(coda_inode);
02c24a821   Josef Bacik   fs: push i_mutex ...
269

5bb44810f   Fabian Frederick   coda: ftoc validi...
270
  	cfi = coda_ftoc(coda_file);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
271
  	host_file = cfi->cfi_container;
8018ab057   Christoph Hellwig   sanitize vfs_fsyn...
272
  	err = vfs_fsync(host_file, datasync);
f7cc02b87   Yoshihisa Abe   Coda: push BKL re...
273
  	if (!err && !datasync)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
274
  		err = venus_fsync(coda_inode->i_sb, coda_i2f(coda_inode));
5955102c9   Al Viro   wrappers for ->i_...
275
  	inode_unlock(coda_inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
277
278
  
  	return err;
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
279
  const struct file_operations coda_file_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  	.llseek		= generic_file_llseek,
c12c49e70   Al Viro   coda: switch to -...
281
282
  	.read_iter	= coda_file_read_iter,
  	.write_iter	= coda_file_write_iter,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
284
  	.mmap		= coda_file_mmap,
  	.open		= coda_open,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
286
  	.release	= coda_release,
  	.fsync		= coda_fsync,
82c156f85   Al Viro   switch generic_fi...
287
  	.splice_read	= generic_file_splice_read,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
  };