]>
Commit | Line | Data |
---|---|---|
e69e7fe5 EVH |
1 | /* |
2 | * linux/fs/9p/vfs_file.c | |
3 | * | |
4 | * This file contians vfs file ops for 9P2000. | |
5 | * | |
6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | |
7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
42e8c509 EVH |
10 | * it under the terms of the GNU General Public License version 2 |
11 | * as published by the Free Software Foundation. | |
e69e7fe5 EVH |
12 | * |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to: | |
20 | * Free Software Foundation | |
21 | * 51 Franklin Street, Fifth Floor | |
22 | * Boston, MA 02111-1301 USA | |
23 | * | |
24 | */ | |
25 | ||
26 | #include <linux/module.h> | |
27 | #include <linux/errno.h> | |
28 | #include <linux/fs.h> | |
914e2637 | 29 | #include <linux/sched.h> |
e69e7fe5 EVH |
30 | #include <linux/file.h> |
31 | #include <linux/stat.h> | |
32 | #include <linux/string.h> | |
e69e7fe5 | 33 | #include <linux/inet.h> |
e69e7fe5 | 34 | #include <linux/list.h> |
637d020a | 35 | #include <linux/pagemap.h> |
a099027c | 36 | #include <linux/utsname.h> |
e69e7fe5 EVH |
37 | #include <asm/uaccess.h> |
38 | #include <linux/idr.h> | |
070b3656 | 39 | #include <linux/uio.h> |
ce85dd58 | 40 | #include <linux/slab.h> |
bd238fb4 LI |
41 | #include <net/9p/9p.h> |
42 | #include <net/9p/client.h> | |
e69e7fe5 | 43 | |
e69e7fe5 | 44 | #include "v9fs.h" |
e69e7fe5 EVH |
45 | #include "v9fs_vfs.h" |
46 | #include "fid.h" | |
60e78d2c | 47 | #include "cache.h" |
e69e7fe5 | 48 | |
7263cebe | 49 | static const struct vm_operations_struct v9fs_file_vm_ops; |
fb89b45c | 50 | static const struct vm_operations_struct v9fs_mmap_file_vm_ops; |
7263cebe | 51 | |
e69e7fe5 EVH |
52 | /** |
53 | * v9fs_file_open - open a file (or directory) | |
54 | * @inode: inode to be opened | |
55 | * @file: file being opened | |
56 | * | |
57 | */ | |
58 | ||
59 | int v9fs_file_open(struct inode *inode, struct file *file) | |
60 | { | |
6a3124a3 | 61 | int err; |
6b39f6d2 | 62 | struct v9fs_inode *v9inode; |
bd238fb4 LI |
63 | struct v9fs_session_info *v9ses; |
64 | struct p9_fid *fid; | |
65 | int omode; | |
e69e7fe5 | 66 | |
5d385153 | 67 | p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file); |
6b39f6d2 | 68 | v9inode = V9FS_I(inode); |
bd238fb4 | 69 | v9ses = v9fs_inode2v9ses(inode); |
ef56547e | 70 | if (v9fs_proto_dotl(v9ses)) |
f88657ce | 71 | omode = v9fs_open_to_dotl_flags(file->f_flags); |
ef56547e MK |
72 | else |
73 | omode = v9fs_uflags2omode(file->f_flags, | |
74 | v9fs_proto_dotu(v9ses)); | |
bd238fb4 LI |
75 | fid = file->private_data; |
76 | if (!fid) { | |
77 | fid = v9fs_fid_clone(file->f_path.dentry); | |
78 | if (IS_ERR(fid)) | |
79 | return PTR_ERR(fid); | |
80 | ||
81 | err = p9_client_open(fid, omode); | |
9523a841 | 82 | if (err < 0) { |
bd238fb4 LI |
83 | p9_client_clunk(fid); |
84 | return err; | |
85 | } | |
ef56547e MK |
86 | if ((file->f_flags & O_APPEND) && |
87 | (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses))) | |
2e4bef41 | 88 | generic_file_llseek(file, 0, SEEK_END); |
6a3124a3 | 89 | } |
e69e7fe5 | 90 | |
bd238fb4 | 91 | file->private_data = fid; |
5a7e0a8c | 92 | mutex_lock(&v9inode->v_mutex); |
fb89b45c DM |
93 | if ((v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) && |
94 | !v9inode->writeback_fid && | |
7add697a | 95 | ((file->f_flags & O_ACCMODE) != O_RDONLY)) { |
3cf387d7 | 96 | /* |
6b39f6d2 | 97 | * clone a fid and add it to writeback_fid |
3cf387d7 AK |
98 | * we do it during open time instead of |
99 | * page dirty time via write_begin/page_mkwrite | |
100 | * because we want write after unlink usecase | |
101 | * to work. | |
102 | */ | |
103 | fid = v9fs_writeback_fid(file->f_path.dentry); | |
104 | if (IS_ERR(fid)) { | |
105 | err = PTR_ERR(fid); | |
5a7e0a8c | 106 | mutex_unlock(&v9inode->v_mutex); |
3cf387d7 AK |
107 | goto out_error; |
108 | } | |
6b39f6d2 | 109 | v9inode->writeback_fid = (void *) fid; |
3cf387d7 | 110 | } |
5a7e0a8c | 111 | mutex_unlock(&v9inode->v_mutex); |
fb89b45c | 112 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) |
60e78d2c | 113 | v9fs_cache_inode_set_cookie(inode, file); |
6a3124a3 | 114 | return 0; |
3cf387d7 AK |
115 | out_error: |
116 | p9_client_clunk(file->private_data); | |
117 | file->private_data = NULL; | |
118 | return err; | |
e69e7fe5 EVH |
119 | } |
120 | ||
121 | /** | |
122 | * v9fs_file_lock - lock a file (or directory) | |
ee443996 EVH |
123 | * @filp: file to be locked |
124 | * @cmd: lock command | |
125 | * @fl: file lock structure | |
e69e7fe5 | 126 | * |
ee443996 | 127 | * Bugs: this looks like a local only lock, we should extend into 9P |
e69e7fe5 EVH |
128 | * by using open exclusive |
129 | */ | |
130 | ||
131 | static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) | |
132 | { | |
133 | int res = 0; | |
496ad9aa | 134 | struct inode *inode = file_inode(filp); |
e69e7fe5 | 135 | |
5d385153 | 136 | p9_debug(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); |
e69e7fe5 EVH |
137 | |
138 | /* No mandatory locks */ | |
f78233dd | 139 | if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) |
e69e7fe5 EVH |
140 | return -ENOLCK; |
141 | ||
142 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { | |
28fd1298 | 143 | filemap_write_and_wait(inode->i_mapping); |
fc0ecff6 | 144 | invalidate_mapping_pages(&inode->i_data, 0, -1); |
e69e7fe5 EVH |
145 | } |
146 | ||
147 | return res; | |
148 | } | |
149 | ||
a099027c MK |
150 | static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl) |
151 | { | |
152 | struct p9_flock flock; | |
153 | struct p9_fid *fid; | |
154 | uint8_t status; | |
155 | int res = 0; | |
156 | unsigned char fl_type; | |
157 | ||
158 | fid = filp->private_data; | |
159 | BUG_ON(fid == NULL); | |
160 | ||
161 | if ((fl->fl_flags & FL_POSIX) != FL_POSIX) | |
162 | BUG(); | |
163 | ||
164 | res = posix_lock_file_wait(filp, fl); | |
165 | if (res < 0) | |
166 | goto out; | |
167 | ||
168 | /* convert posix lock to p9 tlock args */ | |
169 | memset(&flock, 0, sizeof(flock)); | |
51b8b4fb JG |
170 | /* map the lock type */ |
171 | switch (fl->fl_type) { | |
172 | case F_RDLCK: | |
173 | flock.type = P9_LOCK_TYPE_RDLCK; | |
174 | break; | |
175 | case F_WRLCK: | |
176 | flock.type = P9_LOCK_TYPE_WRLCK; | |
177 | break; | |
178 | case F_UNLCK: | |
179 | flock.type = P9_LOCK_TYPE_UNLCK; | |
180 | break; | |
181 | } | |
a099027c MK |
182 | flock.start = fl->fl_start; |
183 | if (fl->fl_end == OFFSET_MAX) | |
184 | flock.length = 0; | |
185 | else | |
186 | flock.length = fl->fl_end - fl->fl_start + 1; | |
187 | flock.proc_id = fl->fl_pid; | |
50192abe | 188 | flock.client_id = fid->clnt->name; |
a099027c MK |
189 | if (IS_SETLKW(cmd)) |
190 | flock.flags = P9_LOCK_FLAGS_BLOCK; | |
191 | ||
192 | /* | |
193 | * if its a blocked request and we get P9_LOCK_BLOCKED as the status | |
194 | * for lock request, keep on trying | |
195 | */ | |
196 | for (;;) { | |
197 | res = p9_client_lock_dotl(fid, &flock, &status); | |
198 | if (res < 0) | |
199 | break; | |
200 | ||
201 | if (status != P9_LOCK_BLOCKED) | |
202 | break; | |
203 | if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd)) | |
204 | break; | |
a0ea787b JG |
205 | if (schedule_timeout_interruptible(P9_LOCK_TIMEOUT) != 0) |
206 | break; | |
a099027c MK |
207 | } |
208 | ||
209 | /* map 9p status to VFS status */ | |
210 | switch (status) { | |
211 | case P9_LOCK_SUCCESS: | |
212 | res = 0; | |
213 | break; | |
214 | case P9_LOCK_BLOCKED: | |
215 | res = -EAGAIN; | |
216 | break; | |
217 | case P9_LOCK_ERROR: | |
218 | case P9_LOCK_GRACE: | |
219 | res = -ENOLCK; | |
220 | break; | |
221 | default: | |
222 | BUG(); | |
223 | } | |
224 | ||
225 | /* | |
226 | * incase server returned error for lock request, revert | |
227 | * it locally | |
228 | */ | |
229 | if (res < 0 && fl->fl_type != F_UNLCK) { | |
230 | fl_type = fl->fl_type; | |
231 | fl->fl_type = F_UNLCK; | |
232 | res = posix_lock_file_wait(filp, fl); | |
233 | fl->fl_type = fl_type; | |
234 | } | |
235 | out: | |
236 | return res; | |
237 | } | |
238 | ||
1d769cd1 MK |
239 | static int v9fs_file_getlock(struct file *filp, struct file_lock *fl) |
240 | { | |
241 | struct p9_getlock glock; | |
242 | struct p9_fid *fid; | |
243 | int res = 0; | |
244 | ||
245 | fid = filp->private_data; | |
246 | BUG_ON(fid == NULL); | |
247 | ||
248 | posix_test_lock(filp, fl); | |
249 | /* | |
250 | * if we have a conflicting lock locally, no need to validate | |
251 | * with server | |
252 | */ | |
253 | if (fl->fl_type != F_UNLCK) | |
254 | return res; | |
255 | ||
256 | /* convert posix lock to p9 tgetlock args */ | |
257 | memset(&glock, 0, sizeof(glock)); | |
51b8b4fb | 258 | glock.type = P9_LOCK_TYPE_UNLCK; |
1d769cd1 MK |
259 | glock.start = fl->fl_start; |
260 | if (fl->fl_end == OFFSET_MAX) | |
261 | glock.length = 0; | |
262 | else | |
263 | glock.length = fl->fl_end - fl->fl_start + 1; | |
264 | glock.proc_id = fl->fl_pid; | |
50192abe | 265 | glock.client_id = fid->clnt->name; |
1d769cd1 MK |
266 | |
267 | res = p9_client_getlock_dotl(fid, &glock); | |
268 | if (res < 0) | |
269 | return res; | |
51b8b4fb JG |
270 | /* map 9p lock type to os lock type */ |
271 | switch (glock.type) { | |
272 | case P9_LOCK_TYPE_RDLCK: | |
273 | fl->fl_type = F_RDLCK; | |
274 | break; | |
275 | case P9_LOCK_TYPE_WRLCK: | |
276 | fl->fl_type = F_WRLCK; | |
277 | break; | |
278 | case P9_LOCK_TYPE_UNLCK: | |
279 | fl->fl_type = F_UNLCK; | |
280 | break; | |
281 | } | |
282 | if (glock.type != P9_LOCK_TYPE_UNLCK) { | |
1d769cd1 MK |
283 | fl->fl_start = glock.start; |
284 | if (glock.length == 0) | |
285 | fl->fl_end = OFFSET_MAX; | |
286 | else | |
287 | fl->fl_end = glock.start + glock.length - 1; | |
288 | fl->fl_pid = glock.proc_id; | |
51b8b4fb | 289 | } |
ce85dd58 | 290 | kfree(glock.client_id); |
1d769cd1 MK |
291 | return res; |
292 | } | |
293 | ||
a099027c MK |
294 | /** |
295 | * v9fs_file_lock_dotl - lock a file (or directory) | |
296 | * @filp: file to be locked | |
297 | * @cmd: lock command | |
298 | * @fl: file lock structure | |
299 | * | |
300 | */ | |
301 | ||
302 | static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl) | |
303 | { | |
496ad9aa | 304 | struct inode *inode = file_inode(filp); |
a099027c MK |
305 | int ret = -ENOLCK; |
306 | ||
4b8e9923 AV |
307 | p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %pD\n", |
308 | filp, cmd, fl, filp); | |
a099027c MK |
309 | |
310 | /* No mandatory locks */ | |
311 | if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) | |
312 | goto out_err; | |
313 | ||
314 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { | |
315 | filemap_write_and_wait(inode->i_mapping); | |
316 | invalidate_mapping_pages(&inode->i_data, 0, -1); | |
317 | } | |
318 | ||
319 | if (IS_SETLK(cmd) || IS_SETLKW(cmd)) | |
320 | ret = v9fs_file_do_lock(filp, cmd, fl); | |
1d769cd1 MK |
321 | else if (IS_GETLK(cmd)) |
322 | ret = v9fs_file_getlock(filp, fl); | |
a099027c MK |
323 | else |
324 | ret = -EINVAL; | |
325 | out_err: | |
326 | return ret; | |
327 | } | |
328 | ||
329 | /** | |
330 | * v9fs_file_flock_dotl - lock a file | |
331 | * @filp: file to be locked | |
332 | * @cmd: lock command | |
333 | * @fl: file lock structure | |
334 | * | |
335 | */ | |
336 | ||
337 | static int v9fs_file_flock_dotl(struct file *filp, int cmd, | |
338 | struct file_lock *fl) | |
339 | { | |
496ad9aa | 340 | struct inode *inode = file_inode(filp); |
a099027c MK |
341 | int ret = -ENOLCK; |
342 | ||
4b8e9923 AV |
343 | p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %pD\n", |
344 | filp, cmd, fl, filp); | |
a099027c MK |
345 | |
346 | /* No mandatory locks */ | |
347 | if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK) | |
348 | goto out_err; | |
349 | ||
350 | if (!(fl->fl_flags & FL_FLOCK)) | |
351 | goto out_err; | |
352 | ||
353 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { | |
354 | filemap_write_and_wait(inode->i_mapping); | |
355 | invalidate_mapping_pages(&inode->i_data, 0, -1); | |
356 | } | |
357 | /* Convert flock to posix lock */ | |
a099027c MK |
358 | fl->fl_flags |= FL_POSIX; |
359 | fl->fl_flags ^= FL_FLOCK; | |
360 | ||
361 | if (IS_SETLK(cmd) | IS_SETLKW(cmd)) | |
362 | ret = v9fs_file_do_lock(filp, cmd, fl); | |
363 | else | |
364 | ret = -EINVAL; | |
365 | out_err: | |
366 | return ret; | |
367 | } | |
368 | ||
fbedadc1 EVH |
369 | /** |
370 | * v9fs_file_read - read from a file | |
371 | * @filp: file pointer to read | |
372 | * @udata: user data buffer to read data into | |
373 | * @count: size of buffer | |
374 | * @offset: offset at which to read data | |
375 | * | |
376 | */ | |
377 | ||
e69e7fe5 | 378 | static ssize_t |
e494b6b5 | 379 | v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to) |
e69e7fe5 | 380 | { |
e494b6b5 | 381 | struct p9_fid *fid = iocb->ki_filp->private_data; |
e1200fe6 | 382 | int ret, err; |
e69e7fe5 | 383 | |
e494b6b5 AV |
384 | p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", |
385 | iov_iter_count(to), iocb->ki_pos); | |
fbedadc1 | 386 | |
e494b6b5 | 387 | ret = p9_client_read(fid, iocb->ki_pos, to, &err); |
e1200fe6 AV |
388 | if (!ret) |
389 | return err; | |
e69e7fe5 | 390 | |
e494b6b5 | 391 | iocb->ki_pos += ret; |
bd238fb4 | 392 | return ret; |
e69e7fe5 EVH |
393 | } |
394 | ||
17311779 AK |
395 | /** |
396 | * v9fs_file_write - write to a file | |
397 | * @filp: file pointer to write | |
398 | * @data: data buffer to write data from | |
399 | * @count: size of buffer | |
400 | * @offset: offset at which to write data | |
401 | * | |
402 | */ | |
403 | static ssize_t | |
e494b6b5 | 404 | v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from) |
17311779 | 405 | { |
e494b6b5 | 406 | struct file *file = iocb->ki_filp; |
17311779 | 407 | ssize_t retval = 0; |
e494b6b5 AV |
408 | loff_t origin = iocb->ki_pos; |
409 | size_t count = iov_iter_count(from); | |
c711a6b1 | 410 | int err = 0; |
17311779 | 411 | |
0fa6b005 | 412 | retval = generic_write_checks(file, &origin, &count); |
17311779 | 413 | if (retval) |
c711a6b1 AV |
414 | return retval; |
415 | ||
e494b6b5 | 416 | iov_iter_truncate(from, count); |
17311779 | 417 | |
17311779 | 418 | if (!count) |
c711a6b1 | 419 | return 0; |
17311779 | 420 | |
e494b6b5 | 421 | retval = p9_client_write(file->private_data, origin, from, &err); |
c711a6b1 | 422 | if (retval > 0) { |
e494b6b5 | 423 | struct inode *inode = file_inode(file); |
c711a6b1 AV |
424 | loff_t i_size; |
425 | unsigned long pg_start, pg_end; | |
426 | pg_start = origin >> PAGE_CACHE_SHIFT; | |
427 | pg_end = (origin + retval - 1) >> PAGE_CACHE_SHIFT; | |
428 | if (inode->i_mapping && inode->i_mapping->nrpages) | |
429 | invalidate_inode_pages2_range(inode->i_mapping, | |
430 | pg_start, pg_end); | |
e494b6b5 | 431 | origin += retval; |
c711a6b1 | 432 | i_size = i_size_read(inode); |
e494b6b5 AV |
433 | iocb->ki_pos = origin; |
434 | if (origin > i_size) { | |
435 | inode_add_bytes(inode, origin - i_size); | |
436 | i_size_write(inode, origin); | |
c711a6b1 AV |
437 | } |
438 | return retval; | |
439 | } | |
440 | return err; | |
e69e7fe5 EVH |
441 | } |
442 | ||
02c24a82 JB |
443 | static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end, |
444 | int datasync) | |
7a4439c4 MK |
445 | { |
446 | struct p9_fid *fid; | |
02c24a82 | 447 | struct inode *inode = filp->f_mapping->host; |
7a4439c4 MK |
448 | struct p9_wstat wstat; |
449 | int retval; | |
450 | ||
02c24a82 JB |
451 | retval = filemap_write_and_wait_range(inode->i_mapping, start, end); |
452 | if (retval) | |
453 | return retval; | |
454 | ||
455 | mutex_lock(&inode->i_mutex); | |
5d385153 | 456 | p9_debug(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync); |
7a4439c4 MK |
457 | |
458 | fid = filp->private_data; | |
459 | v9fs_blank_wstat(&wstat); | |
460 | ||
461 | retval = p9_client_wstat(fid, &wstat); | |
02c24a82 JB |
462 | mutex_unlock(&inode->i_mutex); |
463 | ||
7a4439c4 MK |
464 | return retval; |
465 | } | |
466 | ||
02c24a82 JB |
467 | int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end, |
468 | int datasync) | |
920e65dc VJJ |
469 | { |
470 | struct p9_fid *fid; | |
02c24a82 | 471 | struct inode *inode = filp->f_mapping->host; |
920e65dc VJJ |
472 | int retval; |
473 | ||
02c24a82 JB |
474 | retval = filemap_write_and_wait_range(inode->i_mapping, start, end); |
475 | if (retval) | |
476 | return retval; | |
477 | ||
478 | mutex_lock(&inode->i_mutex); | |
5d385153 | 479 | p9_debug(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync); |
920e65dc VJJ |
480 | |
481 | fid = filp->private_data; | |
482 | ||
b165d601 | 483 | retval = p9_client_fsync(fid, datasync); |
02c24a82 JB |
484 | mutex_unlock(&inode->i_mutex); |
485 | ||
920e65dc VJJ |
486 | return retval; |
487 | } | |
488 | ||
7263cebe | 489 | static int |
fb89b45c | 490 | v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma) |
7263cebe AK |
491 | { |
492 | int retval; | |
493 | ||
fb89b45c DM |
494 | |
495 | retval = generic_file_mmap(filp, vma); | |
7263cebe AK |
496 | if (!retval) |
497 | vma->vm_ops = &v9fs_file_vm_ops; | |
498 | ||
499 | return retval; | |
500 | } | |
501 | ||
fb89b45c DM |
502 | static int |
503 | v9fs_mmap_file_mmap(struct file *filp, struct vm_area_struct *vma) | |
504 | { | |
505 | int retval; | |
506 | struct inode *inode; | |
507 | struct v9fs_inode *v9inode; | |
508 | struct p9_fid *fid; | |
509 | ||
510 | inode = file_inode(filp); | |
511 | v9inode = V9FS_I(inode); | |
512 | mutex_lock(&v9inode->v_mutex); | |
513 | if (!v9inode->writeback_fid && | |
514 | (vma->vm_flags & VM_WRITE)) { | |
515 | /* | |
516 | * clone a fid and add it to writeback_fid | |
517 | * we do it during mmap instead of | |
518 | * page dirty time via write_begin/page_mkwrite | |
519 | * because we want write after unlink usecase | |
520 | * to work. | |
521 | */ | |
522 | fid = v9fs_writeback_fid(filp->f_path.dentry); | |
523 | if (IS_ERR(fid)) { | |
524 | retval = PTR_ERR(fid); | |
525 | mutex_unlock(&v9inode->v_mutex); | |
526 | return retval; | |
527 | } | |
528 | v9inode->writeback_fid = (void *) fid; | |
529 | } | |
530 | mutex_unlock(&v9inode->v_mutex); | |
531 | ||
532 | retval = generic_file_mmap(filp, vma); | |
533 | if (!retval) | |
534 | vma->vm_ops = &v9fs_mmap_file_vm_ops; | |
535 | ||
536 | return retval; | |
537 | } | |
538 | ||
7263cebe AK |
539 | static int |
540 | v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) | |
541 | { | |
6b39f6d2 | 542 | struct v9fs_inode *v9inode; |
7263cebe AK |
543 | struct page *page = vmf->page; |
544 | struct file *filp = vma->vm_file; | |
496ad9aa | 545 | struct inode *inode = file_inode(filp); |
7263cebe AK |
546 | |
547 | ||
5d385153 JP |
548 | p9_debug(P9_DEBUG_VFS, "page %p fid %lx\n", |
549 | page, (unsigned long)filp->private_data); | |
7263cebe | 550 | |
120c2bca JK |
551 | /* Update file times before taking page lock */ |
552 | file_update_time(filp); | |
553 | ||
6b39f6d2 | 554 | v9inode = V9FS_I(inode); |
7263cebe AK |
555 | /* make sure the cache has finished storing the page */ |
556 | v9fs_fscache_wait_on_page_write(inode, page); | |
6b39f6d2 | 557 | BUG_ON(!v9inode->writeback_fid); |
7263cebe AK |
558 | lock_page(page); |
559 | if (page->mapping != inode->i_mapping) | |
560 | goto out_unlock; | |
13575ca1 | 561 | wait_for_stable_page(page); |
7263cebe AK |
562 | |
563 | return VM_FAULT_LOCKED; | |
564 | out_unlock: | |
565 | unlock_page(page); | |
566 | return VM_FAULT_NOPAGE; | |
567 | } | |
568 | ||
fb89b45c DM |
569 | /** |
570 | * v9fs_mmap_file_read - read from a file | |
571 | * @filp: file pointer to read | |
fd2916bd | 572 | * @data: user data buffer to read data into |
fb89b45c DM |
573 | * @count: size of buffer |
574 | * @offset: offset at which to read data | |
575 | * | |
576 | */ | |
577 | static ssize_t | |
e494b6b5 | 578 | v9fs_mmap_file_read_iter(struct kiocb *iocb, struct iov_iter *to) |
fb89b45c DM |
579 | { |
580 | /* TODO: Check if there are dirty pages */ | |
e494b6b5 | 581 | return v9fs_file_read_iter(iocb, to); |
fb89b45c DM |
582 | } |
583 | ||
fb89b45c DM |
584 | /** |
585 | * v9fs_mmap_file_write - write to a file | |
586 | * @filp: file pointer to write | |
587 | * @data: data buffer to write data from | |
588 | * @count: size of buffer | |
589 | * @offset: offset at which to write data | |
590 | * | |
591 | */ | |
592 | static ssize_t | |
e494b6b5 | 593 | v9fs_mmap_file_write_iter(struct kiocb *iocb, struct iov_iter *from) |
fb89b45c DM |
594 | { |
595 | /* | |
596 | * TODO: invalidate mmaps on filp's inode between | |
597 | * offset and offset+count | |
598 | */ | |
e494b6b5 | 599 | return v9fs_file_write_iter(iocb, from); |
fb89b45c DM |
600 | } |
601 | ||
602 | static void v9fs_mmap_vm_close(struct vm_area_struct *vma) | |
603 | { | |
604 | struct inode *inode; | |
605 | ||
606 | struct writeback_control wbc = { | |
607 | .nr_to_write = LONG_MAX, | |
608 | .sync_mode = WB_SYNC_ALL, | |
609 | .range_start = vma->vm_pgoff * PAGE_SIZE, | |
610 | /* absolute end, byte at end included */ | |
611 | .range_end = vma->vm_pgoff * PAGE_SIZE + | |
612 | (vma->vm_end - vma->vm_start - 1), | |
613 | }; | |
614 | ||
615 | ||
616 | p9_debug(P9_DEBUG_VFS, "9p VMA close, %p, flushing", vma); | |
617 | ||
618 | inode = file_inode(vma->vm_file); | |
619 | ||
620 | if (!mapping_cap_writeback_dirty(inode->i_mapping)) | |
621 | wbc.nr_to_write = 0; | |
622 | ||
623 | might_sleep(); | |
624 | sync_inode(inode, &wbc); | |
625 | } | |
626 | ||
627 | ||
7263cebe AK |
628 | static const struct vm_operations_struct v9fs_file_vm_ops = { |
629 | .fault = filemap_fault, | |
f1820361 | 630 | .map_pages = filemap_map_pages, |
7263cebe AK |
631 | .page_mkwrite = v9fs_vm_page_mkwrite, |
632 | }; | |
633 | ||
fb89b45c DM |
634 | static const struct vm_operations_struct v9fs_mmap_file_vm_ops = { |
635 | .close = v9fs_mmap_vm_close, | |
636 | .fault = filemap_fault, | |
f1820361 | 637 | .map_pages = filemap_map_pages, |
fb89b45c | 638 | .page_mkwrite = v9fs_vm_page_mkwrite, |
fb89b45c DM |
639 | }; |
640 | ||
e959b549 | 641 | |
29236f4e | 642 | const struct file_operations v9fs_cached_file_operations = { |
e03abc0c | 643 | .llseek = generic_file_llseek, |
aad4f8bb | 644 | .read_iter = generic_file_read_iter, |
8174202b | 645 | .write_iter = generic_file_write_iter, |
e03abc0c EVH |
646 | .open = v9fs_file_open, |
647 | .release = v9fs_dir_release, | |
648 | .lock = v9fs_file_lock, | |
7263cebe | 649 | .mmap = v9fs_file_mmap, |
7a4439c4 | 650 | .fsync = v9fs_file_fsync, |
e03abc0c EVH |
651 | }; |
652 | ||
29236f4e | 653 | const struct file_operations v9fs_cached_file_operations_dotl = { |
b04faaf3 | 654 | .llseek = generic_file_llseek, |
aad4f8bb | 655 | .read_iter = generic_file_read_iter, |
8174202b | 656 | .write_iter = generic_file_write_iter, |
b04faaf3 VJJ |
657 | .open = v9fs_file_open, |
658 | .release = v9fs_dir_release, | |
a099027c MK |
659 | .lock = v9fs_file_lock_dotl, |
660 | .flock = v9fs_file_flock_dotl, | |
7263cebe | 661 | .mmap = v9fs_file_mmap, |
920e65dc | 662 | .fsync = v9fs_file_fsync_dotl, |
b04faaf3 VJJ |
663 | }; |
664 | ||
4b6f5d20 | 665 | const struct file_operations v9fs_file_operations = { |
e69e7fe5 | 666 | .llseek = generic_file_llseek, |
e494b6b5 AV |
667 | .read_iter = v9fs_file_read_iter, |
668 | .write_iter = v9fs_file_write_iter, | |
e69e7fe5 EVH |
669 | .open = v9fs_file_open, |
670 | .release = v9fs_dir_release, | |
671 | .lock = v9fs_file_lock, | |
14b8869f | 672 | .mmap = generic_file_readonly_mmap, |
7a4439c4 | 673 | .fsync = v9fs_file_fsync, |
e69e7fe5 | 674 | }; |
9b6533c9 SK |
675 | |
676 | const struct file_operations v9fs_file_operations_dotl = { | |
677 | .llseek = generic_file_llseek, | |
e494b6b5 AV |
678 | .read_iter = v9fs_file_read_iter, |
679 | .write_iter = v9fs_file_write_iter, | |
9b6533c9 SK |
680 | .open = v9fs_file_open, |
681 | .release = v9fs_dir_release, | |
a099027c MK |
682 | .lock = v9fs_file_lock_dotl, |
683 | .flock = v9fs_file_flock_dotl, | |
9b6533c9 | 684 | .mmap = generic_file_readonly_mmap, |
920e65dc | 685 | .fsync = v9fs_file_fsync_dotl, |
9b6533c9 | 686 | }; |
fb89b45c DM |
687 | |
688 | const struct file_operations v9fs_mmap_file_operations = { | |
689 | .llseek = generic_file_llseek, | |
e494b6b5 AV |
690 | .read_iter = v9fs_mmap_file_read_iter, |
691 | .write_iter = v9fs_mmap_file_write_iter, | |
fb89b45c DM |
692 | .open = v9fs_file_open, |
693 | .release = v9fs_dir_release, | |
694 | .lock = v9fs_file_lock, | |
695 | .mmap = v9fs_mmap_file_mmap, | |
696 | .fsync = v9fs_file_fsync, | |
697 | }; | |
698 | ||
699 | const struct file_operations v9fs_mmap_file_operations_dotl = { | |
700 | .llseek = generic_file_llseek, | |
e494b6b5 AV |
701 | .read_iter = v9fs_mmap_file_read_iter, |
702 | .write_iter = v9fs_mmap_file_write_iter, | |
fb89b45c DM |
703 | .open = v9fs_file_open, |
704 | .release = v9fs_dir_release, | |
705 | .lock = v9fs_file_lock_dotl, | |
706 | .flock = v9fs_file_flock_dotl, | |
707 | .mmap = v9fs_mmap_file_mmap, | |
708 | .fsync = v9fs_file_fsync_dotl, | |
709 | }; |