]> git.ipfire.org Git - thirdparty/kernel/linux.git/blob - fs/fuse/iomode.c
fuse: introduce inode io modes
[thirdparty/kernel/linux.git] / fs / fuse / iomode.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * FUSE inode io modes.
4 *
5 * Copyright (c) 2024 CTERA Networks.
6 */
7
8 #include "fuse_i.h"
9
10 #include <linux/kernel.h>
11 #include <linux/sched.h>
12 #include <linux/file.h>
13 #include <linux/fs.h>
14
15 /*
16 * Start cached io mode, where parallel dio writes are not allowed.
17 */
18 int fuse_file_cached_io_start(struct inode *inode, struct fuse_file *ff)
19 {
20 struct fuse_inode *fi = get_fuse_inode(inode);
21 int err = 0;
22
23 /* There are no io modes if server does not implement open */
24 if (!ff->release_args)
25 return 0;
26
27 spin_lock(&fi->lock);
28 if (fi->iocachectr < 0) {
29 err = -ETXTBSY;
30 goto unlock;
31 }
32 WARN_ON(ff->iomode == IOM_UNCACHED);
33 if (ff->iomode == IOM_NONE) {
34 ff->iomode = IOM_CACHED;
35 if (fi->iocachectr == 0)
36 set_bit(FUSE_I_CACHE_IO_MODE, &fi->state);
37 fi->iocachectr++;
38 }
39 unlock:
40 spin_unlock(&fi->lock);
41 return err;
42 }
43
44 static void fuse_file_cached_io_end(struct inode *inode, struct fuse_file *ff)
45 {
46 struct fuse_inode *fi = get_fuse_inode(inode);
47
48 spin_lock(&fi->lock);
49 WARN_ON(fi->iocachectr <= 0);
50 WARN_ON(ff->iomode != IOM_CACHED);
51 ff->iomode = IOM_NONE;
52 fi->iocachectr--;
53 if (fi->iocachectr == 0)
54 clear_bit(FUSE_I_CACHE_IO_MODE, &fi->state);
55 spin_unlock(&fi->lock);
56 }
57
58 /* Start strictly uncached io mode where cache access is not allowed */
59 static int fuse_file_uncached_io_start(struct inode *inode, struct fuse_file *ff)
60 {
61 struct fuse_inode *fi = get_fuse_inode(inode);
62 int err = 0;
63
64 spin_lock(&fi->lock);
65 if (fi->iocachectr > 0) {
66 err = -ETXTBSY;
67 goto unlock;
68 }
69 WARN_ON(ff->iomode != IOM_NONE);
70 fi->iocachectr--;
71 ff->iomode = IOM_UNCACHED;
72 unlock:
73 spin_unlock(&fi->lock);
74 return err;
75 }
76
77 static void fuse_file_uncached_io_end(struct inode *inode, struct fuse_file *ff)
78 {
79 struct fuse_inode *fi = get_fuse_inode(inode);
80
81 spin_lock(&fi->lock);
82 WARN_ON(fi->iocachectr >= 0);
83 WARN_ON(ff->iomode != IOM_UNCACHED);
84 ff->iomode = IOM_NONE;
85 fi->iocachectr++;
86 spin_unlock(&fi->lock);
87 }
88
89 /* Request access to submit new io to inode via open file */
90 int fuse_file_io_open(struct file *file, struct inode *inode)
91 {
92 struct fuse_file *ff = file->private_data;
93 int err;
94
95 /*
96 * io modes are not relevant with DAX and with server that does not
97 * implement open.
98 */
99 if (FUSE_IS_DAX(inode) || !ff->release_args)
100 return 0;
101
102 /*
103 * FOPEN_PARALLEL_DIRECT_WRITES requires FOPEN_DIRECT_IO.
104 */
105 if (!(ff->open_flags & FOPEN_DIRECT_IO))
106 ff->open_flags &= ~FOPEN_PARALLEL_DIRECT_WRITES;
107
108 /*
109 * First parallel dio open denies caching inode io mode.
110 * First caching file open enters caching inode io mode.
111 *
112 * Note that if user opens a file open with O_DIRECT, but server did
113 * not specify FOPEN_DIRECT_IO, a later fcntl() could remove O_DIRECT,
114 * so we put the inode in caching mode to prevent parallel dio.
115 */
116 if (ff->open_flags & FOPEN_DIRECT_IO) {
117 if (ff->open_flags & FOPEN_PARALLEL_DIRECT_WRITES)
118 err = fuse_file_uncached_io_start(inode, ff);
119 else
120 return 0;
121 } else {
122 err = fuse_file_cached_io_start(inode, ff);
123 }
124 if (err)
125 goto fail;
126
127 return 0;
128
129 fail:
130 pr_debug("failed to open file in requested io mode (open_flags=0x%x, err=%i).\n",
131 ff->open_flags, err);
132 /*
133 * The file open mode determines the inode io mode.
134 * Using incorrect open mode is a server mistake, which results in
135 * user visible failure of open() with EIO error.
136 */
137 return -EIO;
138 }
139
140 /* No more pending io and no new io possible to inode via open/mmapped file */
141 void fuse_file_io_release(struct fuse_file *ff, struct inode *inode)
142 {
143 /*
144 * Last parallel dio close allows caching inode io mode.
145 * Last caching file close exits caching inode io mode.
146 */
147 switch (ff->iomode) {
148 case IOM_NONE:
149 /* Nothing to do */
150 break;
151 case IOM_UNCACHED:
152 fuse_file_uncached_io_end(inode, ff);
153 break;
154 case IOM_CACHED:
155 fuse_file_cached_io_end(inode, ff);
156 break;
157 }
158 }