1 // SPDX-License-Identifier: GPL-2.0-only
3 * This file contians vfs file ops for 9P2000.
5 * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
6 * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
9 #include <linux/module.h>
10 #include <linux/errno.h>
12 #include <linux/filelock.h>
13 #include <linux/sched.h>
14 #include <linux/file.h>
15 #include <linux/stat.h>
16 #include <linux/string.h>
17 #include <linux/list.h>
18 #include <linux/pagemap.h>
19 #include <linux/utsname.h>
20 #include <linux/uaccess.h>
21 #include <linux/uio.h>
22 #include <linux/slab.h>
23 #include <net/9p/9p.h>
24 #include <net/9p/client.h>
31 static const struct vm_operations_struct v9fs_mmap_file_vm_ops
;
34 * v9fs_file_open - open a file (or directory)
35 * @inode: inode to be opened
36 * @file: file being opened
40 int v9fs_file_open(struct inode
*inode
, struct file
*file
)
43 struct v9fs_session_info
*v9ses
;
47 p9_debug(P9_DEBUG_VFS
, "inode: %p file: %p\n", inode
, file
);
48 v9ses
= v9fs_inode2v9ses(inode
);
49 if (v9fs_proto_dotl(v9ses
))
50 omode
= v9fs_open_to_dotl_flags(file
->f_flags
);
52 omode
= v9fs_uflags2omode(file
->f_flags
,
53 v9fs_proto_dotu(v9ses
));
54 fid
= file
->private_data
;
56 fid
= v9fs_fid_clone(file_dentry(file
));
60 if ((v9ses
->cache
& CACHE_WRITEBACK
) && (omode
& P9_OWRITE
)) {
61 int writeback_omode
= (omode
& ~P9_OWRITE
) | P9_ORDWR
;
63 p9_debug(P9_DEBUG_CACHE
, "write-only file with writeback enabled, try opening O_RDWR\n");
64 err
= p9_client_open(fid
, writeback_omode
);
66 p9_debug(P9_DEBUG_CACHE
, "could not open O_RDWR, disabling caches\n");
67 err
= p9_client_open(fid
, omode
);
68 fid
->mode
|= P9L_DIRECT
;
71 err
= p9_client_open(fid
, omode
);
77 if ((file
->f_flags
& O_APPEND
) &&
78 (!v9fs_proto_dotu(v9ses
) && !v9fs_proto_dotl(v9ses
)))
79 generic_file_llseek(file
, 0, SEEK_END
);
81 file
->private_data
= fid
;
84 #ifdef CONFIG_9P_FSCACHE
85 if (v9ses
->cache
& CACHE_FSCACHE
)
86 fscache_use_cookie(v9fs_inode_cookie(V9FS_I(inode
)),
87 file
->f_mode
& FMODE_WRITE
);
89 v9fs_fid_add_modes(fid
, v9ses
->flags
, v9ses
->cache
, file
->f_flags
);
90 v9fs_open_fid_add(inode
, &fid
);
95 * v9fs_file_lock - lock a file (or directory)
96 * @filp: file to be locked
98 * @fl: file lock structure
100 * Bugs: this looks like a local only lock, we should extend into 9P
101 * by using open exclusive
104 static int v9fs_file_lock(struct file
*filp
, int cmd
, struct file_lock
*fl
)
106 struct inode
*inode
= file_inode(filp
);
108 p9_debug(P9_DEBUG_VFS
, "filp: %p lock: %p\n", filp
, fl
);
110 if ((IS_SETLK(cmd
) || IS_SETLKW(cmd
)) && fl
->c
.flc_type
!= F_UNLCK
) {
111 filemap_write_and_wait(inode
->i_mapping
);
112 invalidate_mapping_pages(&inode
->i_data
, 0, -1);
118 static int v9fs_file_do_lock(struct file
*filp
, int cmd
, struct file_lock
*fl
)
120 struct p9_flock flock
;
122 uint8_t status
= P9_LOCK_ERROR
;
124 struct v9fs_session_info
*v9ses
;
126 fid
= filp
->private_data
;
129 BUG_ON((fl
->c
.flc_flags
& FL_POSIX
) != FL_POSIX
);
131 res
= locks_lock_file_wait(filp
, fl
);
135 /* convert posix lock to p9 tlock args */
136 memset(&flock
, 0, sizeof(flock
));
137 /* map the lock type */
138 switch (fl
->c
.flc_type
) {
140 flock
.type
= P9_LOCK_TYPE_RDLCK
;
143 flock
.type
= P9_LOCK_TYPE_WRLCK
;
146 flock
.type
= P9_LOCK_TYPE_UNLCK
;
149 flock
.start
= fl
->fl_start
;
150 if (fl
->fl_end
== OFFSET_MAX
)
153 flock
.length
= fl
->fl_end
- fl
->fl_start
+ 1;
154 flock
.proc_id
= fl
->c
.flc_pid
;
155 flock
.client_id
= fid
->clnt
->name
;
157 flock
.flags
= P9_LOCK_FLAGS_BLOCK
;
159 v9ses
= v9fs_inode2v9ses(file_inode(filp
));
162 * if its a blocked request and we get P9_LOCK_BLOCKED as the status
163 * for lock request, keep on trying
166 res
= p9_client_lock_dotl(fid
, &flock
, &status
);
170 if (status
!= P9_LOCK_BLOCKED
)
172 if (status
== P9_LOCK_BLOCKED
&& !IS_SETLKW(cmd
))
174 if (schedule_timeout_interruptible(v9ses
->session_lock_timeout
)
178 * p9_client_lock_dotl overwrites flock.client_id with the
179 * server message, free and reuse the client name
181 if (flock
.client_id
!= fid
->clnt
->name
) {
182 kfree(flock
.client_id
);
183 flock
.client_id
= fid
->clnt
->name
;
187 /* map 9p status to VFS status */
189 case P9_LOCK_SUCCESS
:
192 case P9_LOCK_BLOCKED
:
196 WARN_ONCE(1, "unknown lock status code: %d\n", status
);
206 * incase server returned error for lock request, revert
209 if (res
< 0 && fl
->c
.flc_type
!= F_UNLCK
) {
210 unsigned char type
= fl
->c
.flc_type
;
212 fl
->c
.flc_type
= F_UNLCK
;
213 /* Even if this fails we want to return the remote error */
214 locks_lock_file_wait(filp
, fl
);
215 fl
->c
.flc_type
= type
;
217 if (flock
.client_id
!= fid
->clnt
->name
)
218 kfree(flock
.client_id
);
223 static int v9fs_file_getlock(struct file
*filp
, struct file_lock
*fl
)
225 struct p9_getlock glock
;
229 fid
= filp
->private_data
;
232 posix_test_lock(filp
, fl
);
234 * if we have a conflicting lock locally, no need to validate
237 if (fl
->c
.flc_type
!= F_UNLCK
)
240 /* convert posix lock to p9 tgetlock args */
241 memset(&glock
, 0, sizeof(glock
));
242 glock
.type
= P9_LOCK_TYPE_UNLCK
;
243 glock
.start
= fl
->fl_start
;
244 if (fl
->fl_end
== OFFSET_MAX
)
247 glock
.length
= fl
->fl_end
- fl
->fl_start
+ 1;
248 glock
.proc_id
= fl
->c
.flc_pid
;
249 glock
.client_id
= fid
->clnt
->name
;
251 res
= p9_client_getlock_dotl(fid
, &glock
);
254 /* map 9p lock type to os lock type */
255 switch (glock
.type
) {
256 case P9_LOCK_TYPE_RDLCK
:
257 fl
->c
.flc_type
= F_RDLCK
;
259 case P9_LOCK_TYPE_WRLCK
:
260 fl
->c
.flc_type
= F_WRLCK
;
262 case P9_LOCK_TYPE_UNLCK
:
263 fl
->c
.flc_type
= F_UNLCK
;
266 if (glock
.type
!= P9_LOCK_TYPE_UNLCK
) {
267 fl
->fl_start
= glock
.start
;
268 if (glock
.length
== 0)
269 fl
->fl_end
= OFFSET_MAX
;
271 fl
->fl_end
= glock
.start
+ glock
.length
- 1;
272 fl
->c
.flc_pid
= -glock
.proc_id
;
275 if (glock
.client_id
!= fid
->clnt
->name
)
276 kfree(glock
.client_id
);
281 * v9fs_file_lock_dotl - lock a file (or directory)
282 * @filp: file to be locked
284 * @fl: file lock structure
288 static int v9fs_file_lock_dotl(struct file
*filp
, int cmd
, struct file_lock
*fl
)
290 struct inode
*inode
= file_inode(filp
);
293 p9_debug(P9_DEBUG_VFS
, "filp: %p cmd:%d lock: %p name: %pD\n",
294 filp
, cmd
, fl
, filp
);
296 if ((IS_SETLK(cmd
) || IS_SETLKW(cmd
)) && fl
->c
.flc_type
!= F_UNLCK
) {
297 filemap_write_and_wait(inode
->i_mapping
);
298 invalidate_mapping_pages(&inode
->i_data
, 0, -1);
301 if (IS_SETLK(cmd
) || IS_SETLKW(cmd
))
302 ret
= v9fs_file_do_lock(filp
, cmd
, fl
);
303 else if (IS_GETLK(cmd
))
304 ret
= v9fs_file_getlock(filp
, fl
);
311 * v9fs_file_flock_dotl - lock a file
312 * @filp: file to be locked
314 * @fl: file lock structure
318 static int v9fs_file_flock_dotl(struct file
*filp
, int cmd
,
319 struct file_lock
*fl
)
321 struct inode
*inode
= file_inode(filp
);
324 p9_debug(P9_DEBUG_VFS
, "filp: %p cmd:%d lock: %p name: %pD\n",
325 filp
, cmd
, fl
, filp
);
327 if (!(fl
->c
.flc_flags
& FL_FLOCK
))
330 if ((IS_SETLK(cmd
) || IS_SETLKW(cmd
)) && fl
->c
.flc_type
!= F_UNLCK
) {
331 filemap_write_and_wait(inode
->i_mapping
);
332 invalidate_mapping_pages(&inode
->i_data
, 0, -1);
334 /* Convert flock to posix lock */
335 fl
->c
.flc_flags
|= FL_POSIX
;
336 fl
->c
.flc_flags
^= FL_FLOCK
;
338 if (IS_SETLK(cmd
) | IS_SETLKW(cmd
))
339 ret
= v9fs_file_do_lock(filp
, cmd
, fl
);
347 * v9fs_file_read_iter - read from a file
348 * @iocb: The operation parameters
349 * @to: The buffer to read into
353 v9fs_file_read_iter(struct kiocb
*iocb
, struct iov_iter
*to
)
355 struct p9_fid
*fid
= iocb
->ki_filp
->private_data
;
357 p9_debug(P9_DEBUG_VFS
, "fid %d count %zu offset %lld\n",
358 fid
->fid
, iov_iter_count(to
), iocb
->ki_pos
);
360 if (fid
->mode
& P9L_DIRECT
)
361 return netfs_unbuffered_read_iter(iocb
, to
);
363 p9_debug(P9_DEBUG_VFS
, "(cached)\n");
364 return netfs_file_read_iter(iocb
, to
);
368 * v9fs_file_splice_read - splice-read from a file
369 * @in: The 9p file to read from
370 * @ppos: Where to find/update the file position
371 * @pipe: The pipe to splice into
372 * @len: The maximum amount of data to splice
373 * @flags: SPLICE_F_* flags
375 static ssize_t
v9fs_file_splice_read(struct file
*in
, loff_t
*ppos
,
376 struct pipe_inode_info
*pipe
,
377 size_t len
, unsigned int flags
)
379 struct p9_fid
*fid
= in
->private_data
;
381 p9_debug(P9_DEBUG_VFS
, "fid %d count %zu offset %lld\n",
382 fid
->fid
, len
, *ppos
);
384 if (fid
->mode
& P9L_DIRECT
)
385 return copy_splice_read(in
, ppos
, pipe
, len
, flags
);
386 return filemap_splice_read(in
, ppos
, pipe
, len
, flags
);
390 * v9fs_file_write_iter - write to a file
391 * @iocb: The operation parameters
392 * @from: The data to write
396 v9fs_file_write_iter(struct kiocb
*iocb
, struct iov_iter
*from
)
398 struct file
*file
= iocb
->ki_filp
;
399 struct p9_fid
*fid
= file
->private_data
;
401 p9_debug(P9_DEBUG_VFS
, "fid %d\n", fid
->fid
);
403 if (fid
->mode
& (P9L_DIRECT
| P9L_NOWRITECACHE
))
404 return netfs_unbuffered_write_iter(iocb
, from
);
406 p9_debug(P9_DEBUG_CACHE
, "(cached)\n");
407 return netfs_file_write_iter(iocb
, from
);
410 static int v9fs_file_fsync(struct file
*filp
, loff_t start
, loff_t end
,
414 struct inode
*inode
= filp
->f_mapping
->host
;
415 struct p9_wstat wstat
;
418 retval
= file_write_and_wait_range(filp
, start
, end
);
423 p9_debug(P9_DEBUG_VFS
, "filp %p datasync %x\n", filp
, datasync
);
425 fid
= filp
->private_data
;
426 v9fs_blank_wstat(&wstat
);
428 retval
= p9_client_wstat(fid
, &wstat
);
434 int v9fs_file_fsync_dotl(struct file
*filp
, loff_t start
, loff_t end
,
438 struct inode
*inode
= filp
->f_mapping
->host
;
441 retval
= file_write_and_wait_range(filp
, start
, end
);
446 p9_debug(P9_DEBUG_VFS
, "filp %p datasync %x\n", filp
, datasync
);
448 fid
= filp
->private_data
;
450 retval
= p9_client_fsync(fid
, datasync
);
457 v9fs_file_mmap(struct file
*filp
, struct vm_area_struct
*vma
)
460 struct inode
*inode
= file_inode(filp
);
461 struct v9fs_session_info
*v9ses
= v9fs_inode2v9ses(inode
);
463 p9_debug(P9_DEBUG_MMAP
, "filp :%p\n", filp
);
465 if (!(v9ses
->cache
& CACHE_WRITEBACK
)) {
466 p9_debug(P9_DEBUG_CACHE
, "(read-only mmap mode)");
467 return generic_file_readonly_mmap(filp
, vma
);
470 retval
= generic_file_mmap(filp
, vma
);
472 vma
->vm_ops
= &v9fs_mmap_file_vm_ops
;
478 v9fs_vm_page_mkwrite(struct vm_fault
*vmf
)
480 return netfs_page_mkwrite(vmf
, NULL
);
483 static void v9fs_mmap_vm_close(struct vm_area_struct
*vma
)
487 struct writeback_control wbc
= {
488 .nr_to_write
= LONG_MAX
,
489 .sync_mode
= WB_SYNC_ALL
,
490 .range_start
= (loff_t
)vma
->vm_pgoff
* PAGE_SIZE
,
491 /* absolute end, byte at end included */
492 .range_end
= (loff_t
)vma
->vm_pgoff
* PAGE_SIZE
+
493 (vma
->vm_end
- vma
->vm_start
- 1),
496 if (!(vma
->vm_flags
& VM_SHARED
))
499 p9_debug(P9_DEBUG_VFS
, "9p VMA close, %p, flushing", vma
);
501 inode
= file_inode(vma
->vm_file
);
502 filemap_fdatawrite_wbc(inode
->i_mapping
, &wbc
);
505 static const struct vm_operations_struct v9fs_mmap_file_vm_ops
= {
506 .close
= v9fs_mmap_vm_close
,
507 .fault
= filemap_fault
,
508 .map_pages
= filemap_map_pages
,
509 .page_mkwrite
= v9fs_vm_page_mkwrite
,
512 const struct file_operations v9fs_file_operations
= {
513 .llseek
= generic_file_llseek
,
514 .read_iter
= v9fs_file_read_iter
,
515 .write_iter
= v9fs_file_write_iter
,
516 .open
= v9fs_file_open
,
517 .release
= v9fs_dir_release
,
518 .lock
= v9fs_file_lock
,
519 .mmap
= generic_file_readonly_mmap
,
520 .splice_read
= v9fs_file_splice_read
,
521 .splice_write
= iter_file_splice_write
,
522 .fsync
= v9fs_file_fsync
,
523 .setlease
= simple_nosetlease
,
526 const struct file_operations v9fs_file_operations_dotl
= {
527 .llseek
= generic_file_llseek
,
528 .read_iter
= v9fs_file_read_iter
,
529 .write_iter
= v9fs_file_write_iter
,
530 .open
= v9fs_file_open
,
531 .release
= v9fs_dir_release
,
532 .lock
= v9fs_file_lock_dotl
,
533 .flock
= v9fs_file_flock_dotl
,
534 .mmap
= v9fs_file_mmap
,
535 .splice_read
= v9fs_file_splice_read
,
536 .splice_write
= iter_file_splice_write
,
537 .fsync
= v9fs_file_fsync_dotl
,
538 .setlease
= simple_nosetlease
,