fscache: Provide a function to resize a cookie
[linux-block.git] / fs / fscache / io.c
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(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                 return -ENOBUFS;
88
89 again:
90         spin_lock(&cookie->lock);
91
92         state = fscache_cookie_state(cookie);
93         _enter("c=%08x{%u},%x", cookie->debug_id, state, want_state);
94
95         switch (state) {
96         case FSCACHE_COOKIE_STATE_LOOKING_UP:
97         case FSCACHE_COOKIE_STATE_LRU_DISCARDING:
98         case FSCACHE_COOKIE_STATE_INVALIDATING:
99                 goto wait_for_file_wrangling;
100         case FSCACHE_COOKIE_STATE_CREATING:
101                 if (want_state == FSCACHE_WANT_PARAMS)
102                         goto ready; /* There can be no content */
103                 goto wait_for_file_wrangling;
104         case FSCACHE_COOKIE_STATE_ACTIVE:
105                 goto ready;
106         case FSCACHE_COOKIE_STATE_DROPPED:
107         case FSCACHE_COOKIE_STATE_RELINQUISHING:
108                 WARN(1, "Can't use cookie in state %u\n", cookie->state);
109                 goto not_live;
110         default:
111                 goto not_live;
112         }
113
114 ready:
115         spin_unlock(&cookie->lock);
116         if (!cookie->volume->cache->ops->begin_operation(cres, want_state))
117                 goto failed;
118         return 0;
119
120 wait_for_file_wrangling:
121         spin_unlock(&cookie->lock);
122         trace_fscache_access(cookie->debug_id, refcount_read(&cookie->ref),
123                              atomic_read(&cookie->n_accesses),
124                              fscache_access_io_wait);
125         timeo = wait_var_event_timeout(&cookie->state,
126                                        fscache_cookie_state(cookie) != state, 20 * HZ);
127         if (timeo <= 1 && !once_only) {
128                 pr_warn("%s: cookie state change wait timed out: cookie->state=%u state=%u",
129                         __func__, fscache_cookie_state(cookie), state);
130                 fscache_print_cookie(cookie, 'O');
131                 once_only = true;
132         }
133         goto again;
134
135 not_live:
136         spin_unlock(&cookie->lock);
137 failed:
138         cres->cache_priv = NULL;
139         cres->ops = NULL;
140         fscache_end_cookie_access(cookie, fscache_access_io_not_live);
141         _leave(" = -ENOBUFS");
142         return -ENOBUFS;
143 }
144
145 int __fscache_begin_read_operation(struct netfs_cache_resources *cres,
146                                    struct fscache_cookie *cookie)
147 {
148         return fscache_begin_operation(cres, cookie, FSCACHE_WANT_PARAMS,
149                                        fscache_access_io_read);
150 }
151 EXPORT_SYMBOL(__fscache_begin_read_operation);
152
153 /**
154  * fscache_set_page_dirty - Mark page dirty and pin a cache object for writeback
155  * @page: The page being dirtied
156  * @cookie: The cookie referring to the cache object
157  *
158  * Set the dirty flag on a page and pin an in-use cache object in memory when
159  * dirtying a page so that writeback can later write to it.  This is intended
160  * to be called from the filesystem's ->set_page_dirty() method.
161  *
162  *  Returns 1 if PG_dirty was set on the page, 0 otherwise.
163  */
164 int fscache_set_page_dirty(struct page *page, struct fscache_cookie *cookie)
165 {
166         struct inode *inode = page->mapping->host;
167         bool need_use = false;
168
169         _enter("");
170
171         if (!__set_page_dirty_nobuffers(page))
172                 return 0;
173         if (!fscache_cookie_valid(cookie))
174                 return 1;
175
176         if (!(inode->i_state & I_PINNING_FSCACHE_WB)) {
177                 spin_lock(&inode->i_lock);
178                 if (!(inode->i_state & I_PINNING_FSCACHE_WB)) {
179                         inode->i_state |= I_PINNING_FSCACHE_WB;
180                         need_use = true;
181                 }
182                 spin_unlock(&inode->i_lock);
183
184                 if (need_use)
185                         fscache_use_cookie(cookie, true);
186         }
187         return 1;
188 }
189 EXPORT_SYMBOL(fscache_set_page_dirty);
190
191 struct fscache_write_request {
192         struct netfs_cache_resources cache_resources;
193         struct address_space    *mapping;
194         loff_t                  start;
195         size_t                  len;
196         bool                    set_bits;
197         netfs_io_terminated_t   term_func;
198         void                    *term_func_priv;
199 };
200
201 void __fscache_clear_page_bits(struct address_space *mapping,
202                                loff_t start, size_t len)
203 {
204         pgoff_t first = start / PAGE_SIZE;
205         pgoff_t last = (start + len - 1) / PAGE_SIZE;
206         struct page *page;
207
208         if (len) {
209                 XA_STATE(xas, &mapping->i_pages, first);
210
211                 rcu_read_lock();
212                 xas_for_each(&xas, page, last) {
213                         end_page_fscache(page);
214                 }
215                 rcu_read_unlock();
216         }
217 }
218 EXPORT_SYMBOL(__fscache_clear_page_bits);
219
220 /*
221  * Deal with the completion of writing the data to the cache.
222  */
223 static void fscache_wreq_done(void *priv, ssize_t transferred_or_error,
224                               bool was_async)
225 {
226         struct fscache_write_request *wreq = priv;
227
228         fscache_clear_page_bits(fscache_cres_cookie(&wreq->cache_resources),
229                                 wreq->mapping, wreq->start, wreq->len,
230                                 wreq->set_bits);
231
232         if (wreq->term_func)
233                 wreq->term_func(wreq->term_func_priv, transferred_or_error,
234                                 was_async);
235         fscache_end_operation(&wreq->cache_resources);
236         kfree(wreq);
237 }
238
239 void __fscache_write_to_cache(struct fscache_cookie *cookie,
240                               struct address_space *mapping,
241                               loff_t start, size_t len, loff_t i_size,
242                               netfs_io_terminated_t term_func,
243                               void *term_func_priv,
244                               bool cond)
245 {
246         struct fscache_write_request *wreq;
247         struct netfs_cache_resources *cres;
248         struct iov_iter iter;
249         int ret = -ENOBUFS;
250
251         if (len == 0)
252                 goto abandon;
253
254         _enter("%llx,%zx", start, len);
255
256         wreq = kzalloc(sizeof(struct fscache_write_request), GFP_NOFS);
257         if (!wreq)
258                 goto abandon;
259         wreq->mapping           = mapping;
260         wreq->start             = start;
261         wreq->len               = len;
262         wreq->set_bits          = cond;
263         wreq->term_func         = term_func;
264         wreq->term_func_priv    = term_func_priv;
265
266         cres = &wreq->cache_resources;
267         if (fscache_begin_operation(cres, cookie, FSCACHE_WANT_WRITE,
268                                     fscache_access_io_write) < 0)
269                 goto abandon_free;
270
271         ret = cres->ops->prepare_write(cres, &start, &len, i_size, false);
272         if (ret < 0)
273                 goto abandon_end;
274
275         /* TODO: Consider clearing page bits now for space the write isn't
276          * covering.  This is more complicated than it appears when THPs are
277          * taken into account.
278          */
279
280         iov_iter_xarray(&iter, WRITE, &mapping->i_pages, start, len);
281         fscache_write(cres, start, &iter, fscache_wreq_done, wreq);
282         return;
283
284 abandon_end:
285         return fscache_wreq_done(wreq, ret, false);
286 abandon_free:
287         kfree(wreq);
288 abandon:
289         fscache_clear_page_bits(cookie, mapping, start, len, cond);
290         if (term_func)
291                 term_func(term_func_priv, ret, false);
292 }
293 EXPORT_SYMBOL(__fscache_write_to_cache);
294
295 /*
296  * Change the size of a backing object.
297  */
298 void __fscache_resize_cookie(struct fscache_cookie *cookie, loff_t new_size)
299 {
300         struct netfs_cache_resources cres;
301
302         trace_fscache_resize(cookie, new_size);
303         if (fscache_begin_operation(&cres, cookie, FSCACHE_WANT_WRITE,
304                                     fscache_access_io_resize) == 0) {
305                 fscache_stat(&fscache_n_resizes);
306                 set_bit(FSCACHE_COOKIE_NEEDS_UPDATE, &cookie->flags);
307
308                 /* We cannot defer a resize as we need to do it inside the
309                  * netfs's inode lock so that we're serialised with respect to
310                  * writes.
311                  */
312                 cookie->volume->cache->ops->resize_cookie(&cres, new_size);
313                 fscache_end_operation(&cres);
314         } else {
315                 fscache_stat(&fscache_n_resizes_null);
316         }
317 }
318 EXPORT_SYMBOL(__fscache_resize_cookie);