fs/9p: Rework cache modes and add new options to Documentation
[linux-2.6-microblaze.git] / fs / 9p / vfs_file.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * This file contians vfs file ops for 9P2000.
4  *
5  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
6  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
7  */
8
9 #include <linux/module.h>
10 #include <linux/errno.h>
11 #include <linux/fs.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/inet.h>
18 #include <linux/list.h>
19 #include <linux/pagemap.h>
20 #include <linux/utsname.h>
21 #include <linux/uaccess.h>
22 #include <linux/uio.h>
23 #include <linux/slab.h>
24 #include <net/9p/9p.h>
25 #include <net/9p/client.h>
26
27 #include "v9fs.h"
28 #include "v9fs_vfs.h"
29 #include "fid.h"
30 #include "cache.h"
31
32 static const struct vm_operations_struct v9fs_mmap_file_vm_ops;
33
34 /**
35  * v9fs_file_open - open a file (or directory)
36  * @inode: inode to be opened
37  * @file: file being opened
38  *
39  */
40
41 int v9fs_file_open(struct inode *inode, struct file *file)
42 {
43         int err;
44         struct v9fs_session_info *v9ses;
45         struct p9_fid *fid;
46         int omode;
47
48         p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
49         v9ses = v9fs_inode2v9ses(inode);
50         if (v9fs_proto_dotl(v9ses))
51                 omode = v9fs_open_to_dotl_flags(file->f_flags);
52         else
53                 omode = v9fs_uflags2omode(file->f_flags,
54                                         v9fs_proto_dotu(v9ses));
55         fid = file->private_data;
56         if (!fid) {
57                 fid = v9fs_fid_clone(file_dentry(file));
58                 if (IS_ERR(fid))
59                         return PTR_ERR(fid);
60
61                 if ((v9ses->cache & CACHE_WRITEBACK) && (omode & P9_OWRITE)) {
62                         int writeback_omode = (omode & ~P9_OWRITE) | P9_ORDWR;
63
64                         p9_debug(P9_DEBUG_CACHE, "write-only file with writeback enabled, try opening O_RDWR\n");
65                         err = p9_client_open(fid, writeback_omode);
66                         if (err < 0) {
67                                 p9_debug(P9_DEBUG_CACHE, "could not open O_RDWR, disabling caches\n");
68                                 err = p9_client_open(fid, omode);
69                                 fid->mode |= P9L_DIRECT;
70                         }
71                 } else {
72                         err = p9_client_open(fid, omode);
73                 }
74                 if (err < 0) {
75                         p9_fid_put(fid);
76                         return err;
77                 }
78                 if ((file->f_flags & O_APPEND) &&
79                         (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
80                         generic_file_llseek(file, 0, SEEK_END);
81
82                 file->private_data = fid;
83         }
84
85 #ifdef CONFIG_9P_FSCACHE
86         if (v9ses->cache & CACHE_FSCACHE)
87                 fscache_use_cookie(v9fs_inode_cookie(V9FS_I(inode)),
88                                    file->f_mode & FMODE_WRITE);
89 #endif
90         v9fs_fid_add_modes(fid, v9ses->flags, v9ses->cache, file->f_flags);
91         v9fs_open_fid_add(inode, &fid);
92         return 0;
93 }
94
95 /**
96  * v9fs_file_lock - lock a file (or directory)
97  * @filp: file to be locked
98  * @cmd: lock command
99  * @fl: file lock structure
100  *
101  * Bugs: this looks like a local only lock, we should extend into 9P
102  *       by using open exclusive
103  */
104
105 static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
106 {
107         struct inode *inode = file_inode(filp);
108
109         p9_debug(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
110
111         if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
112                 filemap_write_and_wait(inode->i_mapping);
113                 invalidate_mapping_pages(&inode->i_data, 0, -1);
114         }
115
116         return 0;
117 }
118
119 static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
120 {
121         struct p9_flock flock;
122         struct p9_fid *fid;
123         uint8_t status = P9_LOCK_ERROR;
124         int res = 0;
125         unsigned char fl_type;
126         struct v9fs_session_info *v9ses;
127
128         fid = filp->private_data;
129         BUG_ON(fid == NULL);
130
131         BUG_ON((fl->fl_flags & FL_POSIX) != FL_POSIX);
132
133         res = locks_lock_file_wait(filp, fl);
134         if (res < 0)
135                 goto out;
136
137         /* convert posix lock to p9 tlock args */
138         memset(&flock, 0, sizeof(flock));
139         /* map the lock type */
140         switch (fl->fl_type) {
141         case F_RDLCK:
142                 flock.type = P9_LOCK_TYPE_RDLCK;
143                 break;
144         case F_WRLCK:
145                 flock.type = P9_LOCK_TYPE_WRLCK;
146                 break;
147         case F_UNLCK:
148                 flock.type = P9_LOCK_TYPE_UNLCK;
149                 break;
150         }
151         flock.start = fl->fl_start;
152         if (fl->fl_end == OFFSET_MAX)
153                 flock.length = 0;
154         else
155                 flock.length = fl->fl_end - fl->fl_start + 1;
156         flock.proc_id = fl->fl_pid;
157         flock.client_id = fid->clnt->name;
158         if (IS_SETLKW(cmd))
159                 flock.flags = P9_LOCK_FLAGS_BLOCK;
160
161         v9ses = v9fs_inode2v9ses(file_inode(filp));
162
163         /*
164          * if its a blocked request and we get P9_LOCK_BLOCKED as the status
165          * for lock request, keep on trying
166          */
167         for (;;) {
168                 res = p9_client_lock_dotl(fid, &flock, &status);
169                 if (res < 0)
170                         goto out_unlock;
171
172                 if (status != P9_LOCK_BLOCKED)
173                         break;
174                 if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
175                         break;
176                 if (schedule_timeout_interruptible(v9ses->session_lock_timeout)
177                                 != 0)
178                         break;
179                 /*
180                  * p9_client_lock_dotl overwrites flock.client_id with the
181                  * server message, free and reuse the client name
182                  */
183                 if (flock.client_id != fid->clnt->name) {
184                         kfree(flock.client_id);
185                         flock.client_id = fid->clnt->name;
186                 }
187         }
188
189         /* map 9p status to VFS status */
190         switch (status) {
191         case P9_LOCK_SUCCESS:
192                 res = 0;
193                 break;
194         case P9_LOCK_BLOCKED:
195                 res = -EAGAIN;
196                 break;
197         default:
198                 WARN_ONCE(1, "unknown lock status code: %d\n", status);
199                 fallthrough;
200         case P9_LOCK_ERROR:
201         case P9_LOCK_GRACE:
202                 res = -ENOLCK;
203                 break;
204         }
205
206 out_unlock:
207         /*
208          * incase server returned error for lock request, revert
209          * it locally
210          */
211         if (res < 0 && fl->fl_type != F_UNLCK) {
212                 fl_type = fl->fl_type;
213                 fl->fl_type = F_UNLCK;
214                 /* Even if this fails we want to return the remote error */
215                 locks_lock_file_wait(filp, fl);
216                 fl->fl_type = fl_type;
217         }
218         if (flock.client_id != fid->clnt->name)
219                 kfree(flock.client_id);
220 out:
221         return res;
222 }
223
224 static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
225 {
226         struct p9_getlock glock;
227         struct p9_fid *fid;
228         int res = 0;
229
230         fid = filp->private_data;
231         BUG_ON(fid == NULL);
232
233         posix_test_lock(filp, fl);
234         /*
235          * if we have a conflicting lock locally, no need to validate
236          * with server
237          */
238         if (fl->fl_type != F_UNLCK)
239                 return res;
240
241         /* convert posix lock to p9 tgetlock args */
242         memset(&glock, 0, sizeof(glock));
243         glock.type  = P9_LOCK_TYPE_UNLCK;
244         glock.start = fl->fl_start;
245         if (fl->fl_end == OFFSET_MAX)
246                 glock.length = 0;
247         else
248                 glock.length = fl->fl_end - fl->fl_start + 1;
249         glock.proc_id = fl->fl_pid;
250         glock.client_id = fid->clnt->name;
251
252         res = p9_client_getlock_dotl(fid, &glock);
253         if (res < 0)
254                 goto out;
255         /* map 9p lock type to os lock type */
256         switch (glock.type) {
257         case P9_LOCK_TYPE_RDLCK:
258                 fl->fl_type = F_RDLCK;
259                 break;
260         case P9_LOCK_TYPE_WRLCK:
261                 fl->fl_type = F_WRLCK;
262                 break;
263         case P9_LOCK_TYPE_UNLCK:
264                 fl->fl_type = F_UNLCK;
265                 break;
266         }
267         if (glock.type != P9_LOCK_TYPE_UNLCK) {
268                 fl->fl_start = glock.start;
269                 if (glock.length == 0)
270                         fl->fl_end = OFFSET_MAX;
271                 else
272                         fl->fl_end = glock.start + glock.length - 1;
273                 fl->fl_pid = -glock.proc_id;
274         }
275 out:
276         if (glock.client_id != fid->clnt->name)
277                 kfree(glock.client_id);
278         return res;
279 }
280
281 /**
282  * v9fs_file_lock_dotl - lock a file (or directory)
283  * @filp: file to be locked
284  * @cmd: lock command
285  * @fl: file lock structure
286  *
287  */
288
289 static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
290 {
291         struct inode *inode = file_inode(filp);
292         int ret = -ENOLCK;
293
294         p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %pD\n",
295                  filp, cmd, fl, filp);
296
297         if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
298                 filemap_write_and_wait(inode->i_mapping);
299                 invalidate_mapping_pages(&inode->i_data, 0, -1);
300         }
301
302         if (IS_SETLK(cmd) || IS_SETLKW(cmd))
303                 ret = v9fs_file_do_lock(filp, cmd, fl);
304         else if (IS_GETLK(cmd))
305                 ret = v9fs_file_getlock(filp, fl);
306         else
307                 ret = -EINVAL;
308         return ret;
309 }
310
311 /**
312  * v9fs_file_flock_dotl - lock a file
313  * @filp: file to be locked
314  * @cmd: lock command
315  * @fl: file lock structure
316  *
317  */
318
319 static int v9fs_file_flock_dotl(struct file *filp, int cmd,
320         struct file_lock *fl)
321 {
322         struct inode *inode = file_inode(filp);
323         int ret = -ENOLCK;
324
325         p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %pD\n",
326                  filp, cmd, fl, filp);
327
328         if (!(fl->fl_flags & FL_FLOCK))
329                 goto out_err;
330
331         if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
332                 filemap_write_and_wait(inode->i_mapping);
333                 invalidate_mapping_pages(&inode->i_data, 0, -1);
334         }
335         /* Convert flock to posix lock */
336         fl->fl_flags |= FL_POSIX;
337         fl->fl_flags ^= FL_FLOCK;
338
339         if (IS_SETLK(cmd) | IS_SETLKW(cmd))
340                 ret = v9fs_file_do_lock(filp, cmd, fl);
341         else
342                 ret = -EINVAL;
343 out_err:
344         return ret;
345 }
346
347 /**
348  * v9fs_file_read_iter - read from a file
349  * @iocb: The operation parameters
350  * @to: The buffer to read into
351  *
352  */
353 static ssize_t
354 v9fs_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
355 {
356         struct p9_fid *fid = iocb->ki_filp->private_data;
357         int ret, err = 0;
358
359         p9_debug(P9_DEBUG_VFS, "fid %d count %zu offset %lld\n",
360                  fid->fid, iov_iter_count(to), iocb->ki_pos);
361
362         if (!(fid->mode & P9L_DIRECT)) {
363                 p9_debug(P9_DEBUG_VFS, "(cached)\n");
364                 return generic_file_read_iter(iocb, to);
365         }
366
367         if (iocb->ki_filp->f_flags & O_NONBLOCK)
368                 ret = p9_client_read_once(fid, iocb->ki_pos, to, &err);
369         else
370                 ret = p9_client_read(fid, iocb->ki_pos, to, &err);
371         if (!ret)
372                 return err;
373
374         iocb->ki_pos += ret;
375         return ret;
376 }
377
378 /**
379  * v9fs_file_write_iter - write to a file
380  * @iocb: The operation parameters
381  * @from: The data to write
382  *
383  */
384 static ssize_t
385 v9fs_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
386 {
387         struct file *file = iocb->ki_filp;
388         struct p9_fid *fid = file->private_data;
389         ssize_t retval;
390         loff_t origin;
391         int err = 0;
392
393         p9_debug(P9_DEBUG_VFS, "fid %d\n", fid->fid);
394
395         if (!(fid->mode & (P9L_DIRECT | P9L_NOWRITECACHE))) {
396                 p9_debug(P9_DEBUG_CACHE, "(cached)\n");
397                 return generic_file_write_iter(iocb, from);
398         }
399
400         retval = generic_write_checks(iocb, from);
401         if (retval <= 0)
402                 return retval;
403
404         origin = iocb->ki_pos;
405         retval = p9_client_write(file->private_data, iocb->ki_pos, from, &err);
406         if (retval > 0) {
407                 struct inode *inode = file_inode(file);
408                 loff_t i_size;
409                 unsigned long pg_start, pg_end;
410
411                 pg_start = origin >> PAGE_SHIFT;
412                 pg_end = (origin + retval - 1) >> PAGE_SHIFT;
413                 if (inode->i_mapping && inode->i_mapping->nrpages)
414                         invalidate_inode_pages2_range(inode->i_mapping,
415                                                       pg_start, pg_end);
416                 iocb->ki_pos += retval;
417                 i_size = i_size_read(inode);
418                 if (iocb->ki_pos > i_size) {
419                         inode_add_bytes(inode, iocb->ki_pos - i_size);
420                         /*
421                          * Need to serialize against i_size_write() in
422                          * v9fs_stat2inode()
423                          */
424                         v9fs_i_size_write(inode, iocb->ki_pos);
425                 }
426                 return retval;
427         }
428         return err;
429 }
430
431 static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end,
432                            int datasync)
433 {
434         struct p9_fid *fid;
435         struct inode *inode = filp->f_mapping->host;
436         struct p9_wstat wstat;
437         int retval;
438
439         retval = file_write_and_wait_range(filp, start, end);
440         if (retval)
441                 return retval;
442
443         inode_lock(inode);
444         p9_debug(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
445
446         fid = filp->private_data;
447         v9fs_blank_wstat(&wstat);
448
449         retval = p9_client_wstat(fid, &wstat);
450         inode_unlock(inode);
451
452         return retval;
453 }
454
455 int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
456                          int datasync)
457 {
458         struct p9_fid *fid;
459         struct inode *inode = filp->f_mapping->host;
460         int retval;
461
462         retval = file_write_and_wait_range(filp, start, end);
463         if (retval)
464                 return retval;
465
466         inode_lock(inode);
467         p9_debug(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
468
469         fid = filp->private_data;
470
471         retval = p9_client_fsync(fid, datasync);
472         inode_unlock(inode);
473
474         return retval;
475 }
476
477 static int
478 v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma)
479 {
480         int retval;
481         struct inode *inode = file_inode(filp);
482         struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);
483
484         p9_debug(P9_DEBUG_MMAP, "filp :%p\n", filp);
485
486         if (!(v9ses->cache & CACHE_WRITEBACK)) {
487                 p9_debug(P9_DEBUG_CACHE, "(no mmap mode)");
488                 if (vma->vm_flags & VM_MAYSHARE)
489                         return -ENODEV;
490                 invalidate_inode_pages2(filp->f_mapping);
491                 return generic_file_readonly_mmap(filp, vma);
492         }
493
494         retval = generic_file_mmap(filp, vma);
495         if (!retval)
496                 vma->vm_ops = &v9fs_mmap_file_vm_ops;
497
498         return retval;
499 }
500
501 static vm_fault_t
502 v9fs_vm_page_mkwrite(struct vm_fault *vmf)
503 {
504         struct folio *folio = page_folio(vmf->page);
505         struct file *filp = vmf->vma->vm_file;
506         struct inode *inode = file_inode(filp);
507
508
509         p9_debug(P9_DEBUG_VFS, "folio %p fid %lx\n",
510                  folio, (unsigned long)filp->private_data);
511
512         /* Wait for the page to be written to the cache before we allow it to
513          * be modified.  We then assume the entire page will need writing back.
514          */
515 #ifdef CONFIG_9P_FSCACHE
516         if (folio_test_fscache(folio) &&
517             folio_wait_fscache_killable(folio) < 0)
518                 return VM_FAULT_NOPAGE;
519 #endif
520
521         /* Update file times before taking page lock */
522         file_update_time(filp);
523
524         if (folio_lock_killable(folio) < 0)
525                 return VM_FAULT_RETRY;
526         if (folio_mapping(folio) != inode->i_mapping)
527                 goto out_unlock;
528         folio_wait_stable(folio);
529
530         return VM_FAULT_LOCKED;
531 out_unlock:
532         folio_unlock(folio);
533         return VM_FAULT_NOPAGE;
534 }
535
536 static void v9fs_mmap_vm_close(struct vm_area_struct *vma)
537 {
538         struct inode *inode;
539
540         struct writeback_control wbc = {
541                 .nr_to_write = LONG_MAX,
542                 .sync_mode = WB_SYNC_ALL,
543                 .range_start = (loff_t)vma->vm_pgoff * PAGE_SIZE,
544                  /* absolute end, byte at end included */
545                 .range_end = (loff_t)vma->vm_pgoff * PAGE_SIZE +
546                         (vma->vm_end - vma->vm_start - 1),
547         };
548
549         if (!(vma->vm_flags & VM_SHARED))
550                 return;
551
552         p9_debug(P9_DEBUG_VFS, "9p VMA close, %p, flushing", vma);
553
554         inode = file_inode(vma->vm_file);
555         filemap_fdatawrite_wbc(inode->i_mapping, &wbc);
556 }
557
558 static const struct vm_operations_struct v9fs_mmap_file_vm_ops = {
559         .close = v9fs_mmap_vm_close,
560         .fault = filemap_fault,
561         .map_pages = filemap_map_pages,
562         .page_mkwrite = v9fs_vm_page_mkwrite,
563 };
564
565 const struct file_operations v9fs_file_operations = {
566         .llseek = generic_file_llseek,
567         .read_iter = v9fs_file_read_iter,
568         .write_iter = v9fs_file_write_iter,
569         .open = v9fs_file_open,
570         .release = v9fs_dir_release,
571         .lock = v9fs_file_lock,
572         .mmap = generic_file_readonly_mmap,
573         .splice_read = generic_file_splice_read,
574         .splice_write = iter_file_splice_write,
575         .fsync = v9fs_file_fsync,
576 };
577
578 const struct file_operations v9fs_file_operations_dotl = {
579         .llseek = generic_file_llseek,
580         .read_iter = v9fs_file_read_iter,
581         .write_iter = v9fs_file_write_iter,
582         .open = v9fs_file_open,
583         .release = v9fs_dir_release,
584         .lock = v9fs_file_lock_dotl,
585         .flock = v9fs_file_flock_dotl,
586         .mmap = v9fs_file_mmap,
587         .splice_read = generic_file_splice_read,
588         .splice_write = iter_file_splice_write,
589         .fsync = v9fs_file_fsync_dotl,
590 };