1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* Cache data I/O routines |
3 | * |
4 | * Copyright (C) 2021 Red Hat, Inc. All Rights Reserved. |
5 | * Written by David Howells (dhowells@redhat.com) |
6 | */ |
7 | #define FSCACHE_DEBUG_LEVEL OPERATION |
8 | #include <linux/fscache-cache.h> |
9 | #include <linux/uio.h> |
10 | #include <linux/bvec.h> |
11 | #include <linux/slab.h> |
12 | #include <linux/uio.h> |
13 | #include "internal.h" |
14 | |
15 | /** |
16 | * fscache_wait_for_operation - Wait for an object become accessible |
17 | * @cres: The cache resources for the operation being performed |
18 | * @want_state: The minimum state the object must be at |
19 | * |
20 | * See if the target cache object is at the specified minimum state of |
21 | * accessibility yet, and if not, wait for it. |
22 | */ |
23 | bool fscache_wait_for_operation(struct netfs_cache_resources *cres, |
24 | enum fscache_want_state want_state) |
25 | { |
26 | struct fscache_cookie *cookie = fscache_cres_cookie(cres); |
27 | enum fscache_cookie_state state; |
28 | |
29 | again: |
30 | if (!fscache_cache_is_live(cache: cookie->volume->cache)) { |
31 | _leave(" [broken]" ); |
32 | return false; |
33 | } |
34 | |
35 | state = fscache_cookie_state(cookie); |
36 | _enter("c=%08x{%u},%x" , cookie->debug_id, state, want_state); |
37 | |
38 | switch (state) { |
39 | case FSCACHE_COOKIE_STATE_CREATING: |
40 | case FSCACHE_COOKIE_STATE_INVALIDATING: |
41 | if (want_state == FSCACHE_WANT_PARAMS) |
42 | goto ready; /* There can be no content */ |
43 | fallthrough; |
44 | case FSCACHE_COOKIE_STATE_LOOKING_UP: |
45 | case FSCACHE_COOKIE_STATE_LRU_DISCARDING: |
46 | wait_var_event(&cookie->state, |
47 | fscache_cookie_state(cookie) != state); |
48 | goto again; |
49 | |
50 | case FSCACHE_COOKIE_STATE_ACTIVE: |
51 | goto ready; |
52 | case FSCACHE_COOKIE_STATE_DROPPED: |
53 | case FSCACHE_COOKIE_STATE_RELINQUISHING: |
54 | default: |
55 | _leave(" [not live]" ); |
56 | return false; |
57 | } |
58 | |
59 | ready: |
60 | if (!cres->cache_priv2) |
61 | return cookie->volume->cache->ops->begin_operation(cres, want_state); |
62 | return true; |
63 | } |
64 | EXPORT_SYMBOL(fscache_wait_for_operation); |
65 | |
66 | /* |
67 | * Begin an I/O operation on the cache, waiting till we reach the right state. |
68 | * |
69 | * Attaches the resources required to the operation resources record. |
70 | */ |
71 | static int fscache_begin_operation(struct netfs_cache_resources *cres, |
72 | struct fscache_cookie *cookie, |
73 | enum fscache_want_state want_state, |
74 | enum fscache_access_trace why) |
75 | { |
76 | enum fscache_cookie_state state; |
77 | long timeo; |
78 | bool once_only = false; |
79 | |
80 | cres->ops = NULL; |
81 | cres->cache_priv = cookie; |
82 | cres->cache_priv2 = NULL; |
83 | cres->debug_id = cookie->debug_id; |
84 | cres->inval_counter = cookie->inval_counter; |
85 | |
86 | if (!fscache_begin_cookie_access(cookie, why)) { |
87 | cres->cache_priv = NULL; |
88 | return -ENOBUFS; |
89 | } |
90 | |
91 | again: |
92 | spin_lock(lock: &cookie->lock); |
93 | |
94 | state = fscache_cookie_state(cookie); |
95 | _enter("c=%08x{%u},%x" , cookie->debug_id, state, want_state); |
96 | |
97 | switch (state) { |
98 | case FSCACHE_COOKIE_STATE_LOOKING_UP: |
99 | case FSCACHE_COOKIE_STATE_LRU_DISCARDING: |
100 | case FSCACHE_COOKIE_STATE_INVALIDATING: |
101 | goto wait_for_file_wrangling; |
102 | case FSCACHE_COOKIE_STATE_CREATING: |
103 | if (want_state == FSCACHE_WANT_PARAMS) |
104 | goto ready; /* There can be no content */ |
105 | goto wait_for_file_wrangling; |
106 | case FSCACHE_COOKIE_STATE_ACTIVE: |
107 | goto ready; |
108 | case FSCACHE_COOKIE_STATE_DROPPED: |
109 | case FSCACHE_COOKIE_STATE_RELINQUISHING: |
110 | WARN(1, "Can't use cookie in state %u\n" , cookie->state); |
111 | goto not_live; |
112 | default: |
113 | goto not_live; |
114 | } |
115 | |
116 | ready: |
117 | spin_unlock(lock: &cookie->lock); |
118 | if (!cookie->volume->cache->ops->begin_operation(cres, want_state)) |
119 | goto failed; |
120 | return 0; |
121 | |
122 | wait_for_file_wrangling: |
123 | spin_unlock(lock: &cookie->lock); |
124 | trace_fscache_access(cookie_debug_id: cookie->debug_id, ref: refcount_read(r: &cookie->ref), |
125 | n_accesses: atomic_read(v: &cookie->n_accesses), |
126 | why: fscache_access_io_wait); |
127 | timeo = wait_var_event_timeout(&cookie->state, |
128 | fscache_cookie_state(cookie) != state, 20 * HZ); |
129 | if (timeo <= 1 && !once_only) { |
130 | pr_warn("%s: cookie state change wait timed out: cookie->state=%u state=%u" , |
131 | __func__, fscache_cookie_state(cookie), state); |
132 | fscache_print_cookie(cookie, prefix: 'O'); |
133 | once_only = true; |
134 | } |
135 | goto again; |
136 | |
137 | not_live: |
138 | spin_unlock(lock: &cookie->lock); |
139 | failed: |
140 | cres->cache_priv = NULL; |
141 | cres->ops = NULL; |
142 | fscache_end_cookie_access(cookie, why: fscache_access_io_not_live); |
143 | _leave(" = -ENOBUFS" ); |
144 | return -ENOBUFS; |
145 | } |
146 | |
147 | int __fscache_begin_read_operation(struct netfs_cache_resources *cres, |
148 | struct fscache_cookie *cookie) |
149 | { |
150 | return fscache_begin_operation(cres, cookie, want_state: FSCACHE_WANT_PARAMS, |
151 | why: fscache_access_io_read); |
152 | } |
153 | EXPORT_SYMBOL(__fscache_begin_read_operation); |
154 | |
155 | int __fscache_begin_write_operation(struct netfs_cache_resources *cres, |
156 | struct fscache_cookie *cookie) |
157 | { |
158 | return fscache_begin_operation(cres, cookie, want_state: FSCACHE_WANT_PARAMS, |
159 | why: fscache_access_io_write); |
160 | } |
161 | EXPORT_SYMBOL(__fscache_begin_write_operation); |
162 | |
163 | struct fscache_write_request { |
164 | struct netfs_cache_resources cache_resources; |
165 | struct address_space *mapping; |
166 | loff_t start; |
167 | size_t len; |
168 | bool set_bits; |
169 | netfs_io_terminated_t term_func; |
170 | void *term_func_priv; |
171 | }; |
172 | |
173 | void __fscache_clear_page_bits(struct address_space *mapping, |
174 | loff_t start, size_t len) |
175 | { |
176 | pgoff_t first = start / PAGE_SIZE; |
177 | pgoff_t last = (start + len - 1) / PAGE_SIZE; |
178 | struct page *page; |
179 | |
180 | if (len) { |
181 | XA_STATE(xas, &mapping->i_pages, first); |
182 | |
183 | rcu_read_lock(); |
184 | xas_for_each(&xas, page, last) { |
185 | end_page_fscache(page); |
186 | } |
187 | rcu_read_unlock(); |
188 | } |
189 | } |
190 | EXPORT_SYMBOL(__fscache_clear_page_bits); |
191 | |
192 | /* |
193 | * Deal with the completion of writing the data to the cache. |
194 | */ |
195 | static void fscache_wreq_done(void *priv, ssize_t transferred_or_error, |
196 | bool was_async) |
197 | { |
198 | struct fscache_write_request *wreq = priv; |
199 | |
200 | fscache_clear_page_bits(mapping: wreq->mapping, start: wreq->start, len: wreq->len, |
201 | caching: wreq->set_bits); |
202 | |
203 | if (wreq->term_func) |
204 | wreq->term_func(wreq->term_func_priv, transferred_or_error, |
205 | was_async); |
206 | fscache_end_operation(cres: &wreq->cache_resources); |
207 | kfree(objp: wreq); |
208 | } |
209 | |
210 | void __fscache_write_to_cache(struct fscache_cookie *cookie, |
211 | struct address_space *mapping, |
212 | loff_t start, size_t len, loff_t i_size, |
213 | netfs_io_terminated_t term_func, |
214 | void *term_func_priv, |
215 | bool cond) |
216 | { |
217 | struct fscache_write_request *wreq; |
218 | struct netfs_cache_resources *cres; |
219 | struct iov_iter iter; |
220 | int ret = -ENOBUFS; |
221 | |
222 | if (len == 0) |
223 | goto abandon; |
224 | |
225 | _enter("%llx,%zx" , start, len); |
226 | |
227 | wreq = kzalloc(size: sizeof(struct fscache_write_request), GFP_NOFS); |
228 | if (!wreq) |
229 | goto abandon; |
230 | wreq->mapping = mapping; |
231 | wreq->start = start; |
232 | wreq->len = len; |
233 | wreq->set_bits = cond; |
234 | wreq->term_func = term_func; |
235 | wreq->term_func_priv = term_func_priv; |
236 | |
237 | cres = &wreq->cache_resources; |
238 | if (fscache_begin_operation(cres, cookie, want_state: FSCACHE_WANT_WRITE, |
239 | why: fscache_access_io_write) < 0) |
240 | goto abandon_free; |
241 | |
242 | ret = cres->ops->prepare_write(cres, &start, &len, len, i_size, false); |
243 | if (ret < 0) |
244 | goto abandon_end; |
245 | |
246 | /* TODO: Consider clearing page bits now for space the write isn't |
247 | * covering. This is more complicated than it appears when THPs are |
248 | * taken into account. |
249 | */ |
250 | |
251 | iov_iter_xarray(i: &iter, ITER_SOURCE, xarray: &mapping->i_pages, start, count: len); |
252 | fscache_write(cres, start_pos: start, iter: &iter, term_func: fscache_wreq_done, term_func_priv: wreq); |
253 | return; |
254 | |
255 | abandon_end: |
256 | return fscache_wreq_done(priv: wreq, transferred_or_error: ret, was_async: false); |
257 | abandon_free: |
258 | kfree(objp: wreq); |
259 | abandon: |
260 | fscache_clear_page_bits(mapping, start, len, caching: cond); |
261 | if (term_func) |
262 | term_func(term_func_priv, ret, false); |
263 | } |
264 | EXPORT_SYMBOL(__fscache_write_to_cache); |
265 | |
266 | /* |
267 | * Change the size of a backing object. |
268 | */ |
269 | void __fscache_resize_cookie(struct fscache_cookie *cookie, loff_t new_size) |
270 | { |
271 | struct netfs_cache_resources cres; |
272 | |
273 | trace_fscache_resize(cookie, new_size); |
274 | if (fscache_begin_operation(cres: &cres, cookie, want_state: FSCACHE_WANT_WRITE, |
275 | why: fscache_access_io_resize) == 0) { |
276 | fscache_stat(stat: &fscache_n_resizes); |
277 | set_bit(FSCACHE_COOKIE_NEEDS_UPDATE, addr: &cookie->flags); |
278 | |
279 | /* We cannot defer a resize as we need to do it inside the |
280 | * netfs's inode lock so that we're serialised with respect to |
281 | * writes. |
282 | */ |
283 | cookie->volume->cache->ops->resize_cookie(&cres, new_size); |
284 | fscache_end_operation(cres: &cres); |
285 | } else { |
286 | fscache_stat(stat: &fscache_n_resizes_null); |
287 | } |
288 | } |
289 | EXPORT_SYMBOL(__fscache_resize_cookie); |
290 | |