]>
Commit | Line | Data |
---|---|---|
2874c5fd | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
31143d5d DH |
2 | /* handling of writes to regular files and writing back to the server |
3 | * | |
4 | * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved. | |
5 | * Written by David Howells (dhowells@redhat.com) | |
31143d5d | 6 | */ |
4343d008 | 7 | |
4af3c9cc | 8 | #include <linux/backing-dev.h> |
31143d5d DH |
9 | #include <linux/slab.h> |
10 | #include <linux/fs.h> | |
11 | #include <linux/pagemap.h> | |
12 | #include <linux/writeback.h> | |
13 | #include <linux/pagevec.h> | |
3003bbd0 | 14 | #include <linux/netfs.h> |
31143d5d DH |
15 | #include "internal.h" |
16 | ||
a9eb558a DH |
17 | static int afs_writepages_region(struct address_space *mapping, |
18 | struct writeback_control *wbc, | |
19 | loff_t start, loff_t end, loff_t *_next, | |
20 | bool max_one_loop); | |
21 | ||
c7f75ef3 DH |
22 | static void afs_write_to_cache(struct afs_vnode *vnode, loff_t start, size_t len, |
23 | loff_t i_size, bool caching); | |
24 | ||
25 | #ifdef CONFIG_AFS_FSCACHE | |
c7f75ef3 DH |
26 | static void afs_folio_start_fscache(bool caching, struct folio *folio) |
27 | { | |
28 | if (caching) | |
29 | folio_start_fscache(folio); | |
30 | } | |
31 | #else | |
32 | static void afs_folio_start_fscache(bool caching, struct folio *folio) | |
33 | { | |
31143d5d | 34 | } |
c7f75ef3 | 35 | #endif |
31143d5d | 36 | |
a9eb558a DH |
37 | /* |
38 | * Flush out a conflicting write. This may extend the write to the surrounding | |
39 | * pages if also dirty and contiguous to the conflicting region.. | |
40 | */ | |
41 | static int afs_flush_conflicting_write(struct address_space *mapping, | |
42 | struct folio *folio) | |
43 | { | |
44 | struct writeback_control wbc = { | |
45 | .sync_mode = WB_SYNC_ALL, | |
46 | .nr_to_write = LONG_MAX, | |
47 | .range_start = folio_pos(folio), | |
48 | .range_end = LLONG_MAX, | |
49 | }; | |
50 | loff_t next; | |
51 | ||
52 | return afs_writepages_region(mapping, &wbc, folio_pos(folio), LLONG_MAX, | |
53 | &next, true); | |
54 | } | |
55 | ||
31143d5d DH |
56 | /* |
57 | * prepare to perform part of a write to a page | |
31143d5d | 58 | */ |
15b4650e | 59 | int afs_write_begin(struct file *file, struct address_space *mapping, |
9d6b0cd7 | 60 | loff_t pos, unsigned len, |
21db2cdc | 61 | struct page **_page, void **fsdata) |
31143d5d | 62 | { |
496ad9aa | 63 | struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); |
78525c74 | 64 | struct folio *folio; |
4343d008 | 65 | unsigned long priv; |
e87b03f5 DH |
66 | unsigned f, from; |
67 | unsigned t, to; | |
68 | pgoff_t index; | |
31143d5d DH |
69 | int ret; |
70 | ||
e87b03f5 DH |
71 | _enter("{%llx:%llu},%llx,%x", |
72 | vnode->fid.vid, vnode->fid.vnode, pos, len); | |
31143d5d | 73 | |
3003bbd0 DH |
74 | /* Prefetch area to be written into the cache if we're caching this |
75 | * file. We need to do this before we get a lock on the page in case | |
76 | * there's more than one writer competing for the same cache block. | |
77 | */ | |
e81fb419 | 78 | ret = netfs_write_begin(&vnode->netfs, file, mapping, pos, len, &folio, fsdata); |
3003bbd0 DH |
79 | if (ret < 0) |
80 | return ret; | |
630f5dda | 81 | |
78525c74 | 82 | index = folio_index(folio); |
e87b03f5 DH |
83 | from = pos - index * PAGE_SIZE; |
84 | to = from + len; | |
85 | ||
31143d5d | 86 | try_again: |
4343d008 DH |
87 | /* See if this page is already partially written in a way that we can |
88 | * merge the new write with. | |
89 | */ | |
78525c74 DH |
90 | if (folio_test_private(folio)) { |
91 | priv = (unsigned long)folio_get_private(folio); | |
92 | f = afs_folio_dirty_from(folio, priv); | |
93 | t = afs_folio_dirty_to(folio, priv); | |
4343d008 | 94 | ASSERTCMP(f, <=, t); |
31143d5d | 95 | |
78525c74 DH |
96 | if (folio_test_writeback(folio)) { |
97 | trace_afs_folio_dirty(vnode, tracepoint_string("alrdy"), folio); | |
a9eb558a DH |
98 | folio_unlock(folio); |
99 | goto wait_for_writeback; | |
5a039c32 | 100 | } |
5a813276 DH |
101 | /* If the file is being filled locally, allow inter-write |
102 | * spaces to be merged into writes. If it's not, only write | |
103 | * back what the user gives us. | |
104 | */ | |
105 | if (!test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags) && | |
106 | (to < f || from > t)) | |
4343d008 | 107 | goto flush_conflicting_write; |
31143d5d DH |
108 | } |
109 | ||
8549a263 | 110 | *_page = folio_file_page(folio, pos / PAGE_SIZE); |
4343d008 | 111 | _leave(" = 0"); |
31143d5d DH |
112 | return 0; |
113 | ||
4343d008 DH |
114 | /* The previous write and this write aren't adjacent or overlapping, so |
115 | * flush the page out. | |
116 | */ | |
117 | flush_conflicting_write: | |
a9eb558a DH |
118 | trace_afs_folio_dirty(vnode, tracepoint_string("confl"), folio); |
119 | folio_unlock(folio); | |
120 | ||
121 | ret = afs_flush_conflicting_write(mapping, folio); | |
122 | if (ret < 0) | |
123 | goto error; | |
124 | ||
125 | wait_for_writeback: | |
126 | ret = folio_wait_writeback_killable(folio); | |
21db2cdc DH |
127 | if (ret < 0) |
128 | goto error; | |
31143d5d | 129 | |
78525c74 | 130 | ret = folio_lock_killable(folio); |
21db2cdc DH |
131 | if (ret < 0) |
132 | goto error; | |
31143d5d | 133 | goto try_again; |
21db2cdc DH |
134 | |
135 | error: | |
78525c74 | 136 | folio_put(folio); |
21db2cdc DH |
137 | _leave(" = %d", ret); |
138 | return ret; | |
31143d5d DH |
139 | } |
140 | ||
141 | /* | |
142 | * finalise part of a write to a page | |
143 | */ | |
15b4650e NP |
144 | int afs_write_end(struct file *file, struct address_space *mapping, |
145 | loff_t pos, unsigned len, unsigned copied, | |
78525c74 | 146 | struct page *subpage, void *fsdata) |
31143d5d | 147 | { |
78525c74 | 148 | struct folio *folio = page_folio(subpage); |
496ad9aa | 149 | struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); |
f792e3ac | 150 | unsigned long priv; |
78525c74 | 151 | unsigned int f, from = offset_in_folio(folio, pos); |
f792e3ac | 152 | unsigned int t, to = from + copied; |
c7f75ef3 | 153 | loff_t i_size, write_end_pos; |
31143d5d | 154 | |
3b6492df | 155 | _enter("{%llx:%llu},{%lx}", |
78525c74 | 156 | vnode->fid.vid, vnode->fid.vnode, folio_index(folio)); |
31143d5d | 157 | |
78525c74 | 158 | if (!folio_test_uptodate(folio)) { |
66e9c6a8 DH |
159 | if (copied < len) { |
160 | copied = 0; | |
161 | goto out; | |
162 | } | |
163 | ||
78525c74 | 164 | folio_mark_uptodate(folio); |
66e9c6a8 DH |
165 | } |
166 | ||
3ad216ee DH |
167 | if (copied == 0) |
168 | goto out; | |
169 | ||
c7f75ef3 | 170 | write_end_pos = pos + copied; |
31143d5d | 171 | |
874c8ca1 | 172 | i_size = i_size_read(&vnode->netfs.inode); |
c7f75ef3 | 173 | if (write_end_pos > i_size) { |
1f32ef79 | 174 | write_seqlock(&vnode->cb_lock); |
874c8ca1 | 175 | i_size = i_size_read(&vnode->netfs.inode); |
c7f75ef3 DH |
176 | if (write_end_pos > i_size) |
177 | afs_set_i_size(vnode, write_end_pos); | |
1f32ef79 | 178 | write_sequnlock(&vnode->cb_lock); |
c7f75ef3 | 179 | fscache_update_cookie(afs_vnode_cache(vnode), NULL, &write_end_pos); |
31143d5d DH |
180 | } |
181 | ||
78525c74 DH |
182 | if (folio_test_private(folio)) { |
183 | priv = (unsigned long)folio_get_private(folio); | |
184 | f = afs_folio_dirty_from(folio, priv); | |
185 | t = afs_folio_dirty_to(folio, priv); | |
f792e3ac DH |
186 | if (from < f) |
187 | f = from; | |
188 | if (to > t) | |
189 | t = to; | |
78525c74 DH |
190 | priv = afs_folio_dirty(folio, f, t); |
191 | folio_change_private(folio, (void *)priv); | |
192 | trace_afs_folio_dirty(vnode, tracepoint_string("dirty+"), folio); | |
f792e3ac | 193 | } else { |
78525c74 DH |
194 | priv = afs_folio_dirty(folio, from, to); |
195 | folio_attach_private(folio, (void *)priv); | |
196 | trace_afs_folio_dirty(vnode, tracepoint_string("dirty"), folio); | |
f792e3ac DH |
197 | } |
198 | ||
78525c74 DH |
199 | if (folio_mark_dirty(folio)) |
200 | _debug("dirtied %lx", folio_index(folio)); | |
afae457d DH |
201 | |
202 | out: | |
78525c74 DH |
203 | folio_unlock(folio); |
204 | folio_put(folio); | |
3003bbd0 | 205 | return copied; |
31143d5d DH |
206 | } |
207 | ||
208 | /* | |
209 | * kill all the pages in the given range | |
210 | */ | |
4343d008 | 211 | static void afs_kill_pages(struct address_space *mapping, |
e87b03f5 | 212 | loff_t start, loff_t len) |
31143d5d | 213 | { |
4343d008 | 214 | struct afs_vnode *vnode = AFS_FS_I(mapping->host); |
78525c74 DH |
215 | struct folio *folio; |
216 | pgoff_t index = start / PAGE_SIZE; | |
217 | pgoff_t last = (start + len - 1) / PAGE_SIZE, next; | |
31143d5d | 218 | |
e87b03f5 DH |
219 | _enter("{%llx:%llu},%llx @%llx", |
220 | vnode->fid.vid, vnode->fid.vnode, len, start); | |
31143d5d | 221 | |
31143d5d | 222 | do { |
78525c74 | 223 | _debug("kill %lx (to %lx)", index, last); |
31143d5d | 224 | |
78525c74 | 225 | folio = filemap_get_folio(mapping, index); |
66dabbb6 | 226 | if (IS_ERR(folio)) { |
78525c74 DH |
227 | next = index + 1; |
228 | continue; | |
229 | } | |
e87b03f5 | 230 | |
78525c74 | 231 | next = folio_next_index(folio); |
e87b03f5 | 232 | |
78525c74 DH |
233 | folio_clear_uptodate(folio); |
234 | folio_end_writeback(folio); | |
235 | folio_lock(folio); | |
236 | generic_error_remove_page(mapping, &folio->page); | |
237 | folio_unlock(folio); | |
238 | folio_put(folio); | |
31143d5d | 239 | |
78525c74 | 240 | } while (index = next, index <= last); |
31143d5d DH |
241 | |
242 | _leave(""); | |
243 | } | |
244 | ||
245 | /* | |
4343d008 DH |
246 | * Redirty all the pages in a given range. |
247 | */ | |
248 | static void afs_redirty_pages(struct writeback_control *wbc, | |
249 | struct address_space *mapping, | |
e87b03f5 | 250 | loff_t start, loff_t len) |
4343d008 DH |
251 | { |
252 | struct afs_vnode *vnode = AFS_FS_I(mapping->host); | |
78525c74 DH |
253 | struct folio *folio; |
254 | pgoff_t index = start / PAGE_SIZE; | |
255 | pgoff_t last = (start + len - 1) / PAGE_SIZE, next; | |
4343d008 | 256 | |
e87b03f5 DH |
257 | _enter("{%llx:%llu},%llx @%llx", |
258 | vnode->fid.vid, vnode->fid.vnode, len, start); | |
4343d008 | 259 | |
4343d008 | 260 | do { |
e87b03f5 | 261 | _debug("redirty %llx @%llx", len, start); |
4343d008 | 262 | |
78525c74 | 263 | folio = filemap_get_folio(mapping, index); |
66dabbb6 | 264 | if (IS_ERR(folio)) { |
78525c74 DH |
265 | next = index + 1; |
266 | continue; | |
4343d008 DH |
267 | } |
268 | ||
78525c74 DH |
269 | next = index + folio_nr_pages(folio); |
270 | folio_redirty_for_writepage(wbc, folio); | |
271 | folio_end_writeback(folio); | |
272 | folio_put(folio); | |
273 | } while (index = next, index <= last); | |
31143d5d DH |
274 | |
275 | _leave(""); | |
276 | } | |
277 | ||
a58823ac DH |
278 | /* |
279 | * completion of write to server | |
280 | */ | |
e87b03f5 | 281 | static void afs_pages_written_back(struct afs_vnode *vnode, loff_t start, unsigned int len) |
a58823ac | 282 | { |
874c8ca1 | 283 | struct address_space *mapping = vnode->netfs.inode.i_mapping; |
78525c74 | 284 | struct folio *folio; |
e87b03f5 | 285 | pgoff_t end; |
bd80d8a8 | 286 | |
e87b03f5 | 287 | XA_STATE(xas, &mapping->i_pages, start / PAGE_SIZE); |
a58823ac | 288 | |
e87b03f5 DH |
289 | _enter("{%llx:%llu},{%x @%llx}", |
290 | vnode->fid.vid, vnode->fid.vnode, len, start); | |
a58823ac | 291 | |
bd80d8a8 | 292 | rcu_read_lock(); |
a58823ac | 293 | |
e87b03f5 | 294 | end = (start + len - 1) / PAGE_SIZE; |
78525c74 DH |
295 | xas_for_each(&xas, folio, end) { |
296 | if (!folio_test_writeback(folio)) { | |
297 | kdebug("bad %x @%llx page %lx %lx", | |
298 | len, start, folio_index(folio), end); | |
299 | ASSERT(folio_test_writeback(folio)); | |
e87b03f5 | 300 | } |
a58823ac | 301 | |
78525c74 DH |
302 | trace_afs_folio_dirty(vnode, tracepoint_string("clear"), folio); |
303 | folio_detach_private(folio); | |
304 | folio_end_writeback(folio); | |
bd80d8a8 | 305 | } |
a58823ac | 306 | |
bd80d8a8 | 307 | rcu_read_unlock(); |
a58823ac DH |
308 | |
309 | afs_prune_wb_keys(vnode); | |
310 | _leave(""); | |
311 | } | |
312 | ||
d2ddc776 | 313 | /* |
e49c7b2f DH |
314 | * Find a key to use for the writeback. We cached the keys used to author the |
315 | * writes on the vnode. *_wbk will contain the last writeback key used or NULL | |
316 | * and we need to start from there if it's set. | |
d2ddc776 | 317 | */ |
e49c7b2f DH |
318 | static int afs_get_writeback_key(struct afs_vnode *vnode, |
319 | struct afs_wb_key **_wbk) | |
d2ddc776 | 320 | { |
4343d008 DH |
321 | struct afs_wb_key *wbk = NULL; |
322 | struct list_head *p; | |
323 | int ret = -ENOKEY, ret2; | |
d2ddc776 | 324 | |
4343d008 | 325 | spin_lock(&vnode->wb_lock); |
e49c7b2f DH |
326 | if (*_wbk) |
327 | p = (*_wbk)->vnode_link.next; | |
328 | else | |
329 | p = vnode->wb_keys.next; | |
4343d008 | 330 | |
4343d008 DH |
331 | while (p != &vnode->wb_keys) { |
332 | wbk = list_entry(p, struct afs_wb_key, vnode_link); | |
333 | _debug("wbk %u", key_serial(wbk->key)); | |
334 | ret2 = key_validate(wbk->key); | |
e49c7b2f DH |
335 | if (ret2 == 0) { |
336 | refcount_inc(&wbk->usage); | |
337 | _debug("USE WB KEY %u", key_serial(wbk->key)); | |
338 | break; | |
339 | } | |
340 | ||
341 | wbk = NULL; | |
4343d008 DH |
342 | if (ret == -ENOKEY) |
343 | ret = ret2; | |
344 | p = p->next; | |
345 | } | |
346 | ||
347 | spin_unlock(&vnode->wb_lock); | |
e49c7b2f DH |
348 | if (*_wbk) |
349 | afs_put_wb_key(*_wbk); | |
350 | *_wbk = wbk; | |
351 | return 0; | |
352 | } | |
4343d008 | 353 | |
e49c7b2f DH |
354 | static void afs_store_data_success(struct afs_operation *op) |
355 | { | |
356 | struct afs_vnode *vnode = op->file[0].vnode; | |
4343d008 | 357 | |
da8d0755 | 358 | op->ctime = op->file[0].scb.status.mtime_client; |
e49c7b2f DH |
359 | afs_vnode_commit_status(op, &op->file[0]); |
360 | if (op->error == 0) { | |
d383e346 | 361 | if (!op->store.laundering) |
e87b03f5 | 362 | afs_pages_written_back(vnode, op->store.pos, op->store.size); |
e49c7b2f | 363 | afs_stat_v(vnode, n_stores); |
bd80d8a8 | 364 | atomic_long_add(op->store.size, &afs_v2net(vnode)->n_store_bytes); |
e49c7b2f DH |
365 | } |
366 | } | |
4343d008 | 367 | |
e49c7b2f DH |
368 | static const struct afs_operation_ops afs_store_data_operation = { |
369 | .issue_afs_rpc = afs_fs_store_data, | |
370 | .issue_yfs_rpc = yfs_fs_store_data, | |
371 | .success = afs_store_data_success, | |
372 | }; | |
a58823ac | 373 | |
e49c7b2f DH |
374 | /* |
375 | * write to a file | |
376 | */ | |
e87b03f5 | 377 | static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter, loff_t pos, |
bd80d8a8 | 378 | bool laundering) |
e49c7b2f | 379 | { |
e49c7b2f DH |
380 | struct afs_operation *op; |
381 | struct afs_wb_key *wbk = NULL; | |
ab487a4c | 382 | loff_t size = iov_iter_count(iter); |
bd80d8a8 | 383 | int ret = -ENOKEY; |
e49c7b2f | 384 | |
bd80d8a8 | 385 | _enter("%s{%llx:%llu.%u},%llx,%llx", |
e49c7b2f DH |
386 | vnode->volume->name, |
387 | vnode->fid.vid, | |
388 | vnode->fid.vnode, | |
389 | vnode->fid.unique, | |
bd80d8a8 | 390 | size, pos); |
d2ddc776 | 391 | |
e49c7b2f DH |
392 | ret = afs_get_writeback_key(vnode, &wbk); |
393 | if (ret) { | |
394 | _leave(" = %d [no keys]", ret); | |
395 | return ret; | |
d2ddc776 DH |
396 | } |
397 | ||
e49c7b2f DH |
398 | op = afs_alloc_operation(wbk->key, vnode->volume); |
399 | if (IS_ERR(op)) { | |
400 | afs_put_wb_key(wbk); | |
401 | return -ENOMEM; | |
402 | } | |
403 | ||
404 | afs_op_set_vnode(op, 0, vnode); | |
405 | op->file[0].dv_delta = 1; | |
22650f14 | 406 | op->file[0].modification = true; |
bd80d8a8 | 407 | op->store.pos = pos; |
bd80d8a8 | 408 | op->store.size = size; |
d383e346 | 409 | op->store.laundering = laundering; |
811f04ba | 410 | op->flags |= AFS_OPERATION_UNINTR; |
e49c7b2f DH |
411 | op->ops = &afs_store_data_operation; |
412 | ||
413 | try_next_key: | |
414 | afs_begin_vnode_operation(op); | |
03275585 DH |
415 | |
416 | op->store.write_iter = iter; | |
417 | op->store.i_size = max(pos + size, vnode->netfs.remote_i_size); | |
562ce1f7 | 418 | op->mtime = inode_get_mtime(&vnode->netfs.inode); |
03275585 | 419 | |
e49c7b2f DH |
420 | afs_wait_for_operation(op); |
421 | ||
422 | switch (op->error) { | |
4343d008 DH |
423 | case -EACCES: |
424 | case -EPERM: | |
425 | case -ENOKEY: | |
426 | case -EKEYEXPIRED: | |
427 | case -EKEYREJECTED: | |
428 | case -EKEYREVOKED: | |
429 | _debug("next"); | |
e49c7b2f DH |
430 | |
431 | ret = afs_get_writeback_key(vnode, &wbk); | |
432 | if (ret == 0) { | |
433 | key_put(op->key); | |
434 | op->key = key_get(wbk->key); | |
435 | goto try_next_key; | |
436 | } | |
437 | break; | |
4343d008 DH |
438 | } |
439 | ||
440 | afs_put_wb_key(wbk); | |
e49c7b2f DH |
441 | _leave(" = %d", op->error); |
442 | return afs_put_operation(op); | |
d2ddc776 DH |
443 | } |
444 | ||
31143d5d | 445 | /* |
810caa3e DH |
446 | * Extend the region to be written back to include subsequent contiguously |
447 | * dirty pages if possible, but don't sleep while doing so. | |
448 | * | |
449 | * If this page holds new content, then we can include filler zeros in the | |
450 | * writeback. | |
31143d5d | 451 | */ |
810caa3e DH |
452 | static void afs_extend_writeback(struct address_space *mapping, |
453 | struct afs_vnode *vnode, | |
454 | long *_count, | |
e87b03f5 DH |
455 | loff_t start, |
456 | loff_t max_len, | |
457 | bool new_content, | |
c7f75ef3 | 458 | bool caching, |
e87b03f5 | 459 | unsigned int *_len) |
31143d5d | 460 | { |
f5f288a0 | 461 | struct folio_batch fbatch; |
78525c74 | 462 | struct folio *folio; |
e87b03f5 DH |
463 | unsigned long priv; |
464 | unsigned int psize, filler = 0; | |
465 | unsigned int f, t; | |
466 | loff_t len = *_len; | |
467 | pgoff_t index = (start + len) / PAGE_SIZE; | |
468 | bool stop = true; | |
469 | unsigned int i; | |
470 | ||
471 | XA_STATE(xas, &mapping->i_pages, index); | |
f5f288a0 | 472 | folio_batch_init(&fbatch); |
4343d008 | 473 | |
31143d5d | 474 | do { |
e87b03f5 DH |
475 | /* Firstly, we gather up a batch of contiguous dirty pages |
476 | * under the RCU read lock - but we can't clear the dirty flags | |
477 | * there if any of those pages are mapped. | |
478 | */ | |
479 | rcu_read_lock(); | |
31143d5d | 480 | |
78525c74 | 481 | xas_for_each(&xas, folio, ULONG_MAX) { |
e87b03f5 | 482 | stop = true; |
78525c74 | 483 | if (xas_retry(&xas, folio)) |
e87b03f5 | 484 | continue; |
78525c74 | 485 | if (xa_is_value(folio)) |
e87b03f5 | 486 | break; |
78525c74 | 487 | if (folio_index(folio) != index) |
5a813276 | 488 | break; |
e87b03f5 | 489 | |
78525c74 | 490 | if (!folio_try_get_rcu(folio)) { |
e87b03f5 DH |
491 | xas_reset(&xas); |
492 | continue; | |
493 | } | |
494 | ||
495 | /* Has the page moved or been split? */ | |
78525c74 DH |
496 | if (unlikely(folio != xas_reload(&xas))) { |
497 | folio_put(folio); | |
31143d5d | 498 | break; |
581b2027 | 499 | } |
e87b03f5 | 500 | |
78525c74 DH |
501 | if (!folio_trylock(folio)) { |
502 | folio_put(folio); | |
31143d5d | 503 | break; |
581b2027 | 504 | } |
c7f75ef3 DH |
505 | if (!folio_test_dirty(folio) || |
506 | folio_test_writeback(folio) || | |
507 | folio_test_fscache(folio)) { | |
78525c74 DH |
508 | folio_unlock(folio); |
509 | folio_put(folio); | |
31143d5d DH |
510 | break; |
511 | } | |
4343d008 | 512 | |
78525c74 DH |
513 | psize = folio_size(folio); |
514 | priv = (unsigned long)folio_get_private(folio); | |
515 | f = afs_folio_dirty_from(folio, priv); | |
516 | t = afs_folio_dirty_to(folio, priv); | |
810caa3e | 517 | if (f != 0 && !new_content) { |
78525c74 DH |
518 | folio_unlock(folio); |
519 | folio_put(folio); | |
31143d5d DH |
520 | break; |
521 | } | |
4343d008 | 522 | |
e87b03f5 DH |
523 | len += filler + t; |
524 | filler = psize - t; | |
525 | if (len >= max_len || *_count <= 0) | |
526 | stop = true; | |
527 | else if (t == psize || new_content) | |
528 | stop = false; | |
529 | ||
78525c74 | 530 | index += folio_nr_pages(folio); |
f5f288a0 | 531 | if (!folio_batch_add(&fbatch, folio)) |
e87b03f5 DH |
532 | break; |
533 | if (stop) | |
534 | break; | |
535 | } | |
536 | ||
537 | if (!stop) | |
538 | xas_pause(&xas); | |
539 | rcu_read_unlock(); | |
540 | ||
f5f288a0 | 541 | /* Now, if we obtained any folios, we can shift them to being |
e87b03f5 DH |
542 | * writable and mark them for caching. |
543 | */ | |
f5f288a0 | 544 | if (!folio_batch_count(&fbatch)) |
e87b03f5 DH |
545 | break; |
546 | ||
f5f288a0 MWO |
547 | for (i = 0; i < folio_batch_count(&fbatch); i++) { |
548 | folio = fbatch.folios[i]; | |
78525c74 | 549 | trace_afs_folio_dirty(vnode, tracepoint_string("store+"), folio); |
13524ab3 | 550 | |
78525c74 | 551 | if (!folio_clear_dirty_for_io(folio)) |
31143d5d | 552 | BUG(); |
78525c74 | 553 | if (folio_start_writeback(folio)) |
31143d5d | 554 | BUG(); |
c7f75ef3 | 555 | afs_folio_start_fscache(caching, folio); |
e87b03f5 | 556 | |
78525c74 DH |
557 | *_count -= folio_nr_pages(folio); |
558 | folio_unlock(folio); | |
31143d5d DH |
559 | } |
560 | ||
f5f288a0 | 561 | folio_batch_release(&fbatch); |
e87b03f5 DH |
562 | cond_resched(); |
563 | } while (!stop); | |
31143d5d | 564 | |
e87b03f5 | 565 | *_len = len; |
810caa3e DH |
566 | } |
567 | ||
568 | /* | |
569 | * Synchronously write back the locked page and any subsequent non-locked dirty | |
570 | * pages. | |
571 | */ | |
78525c74 DH |
572 | static ssize_t afs_write_back_from_locked_folio(struct address_space *mapping, |
573 | struct writeback_control *wbc, | |
574 | struct folio *folio, | |
575 | loff_t start, loff_t end) | |
810caa3e DH |
576 | { |
577 | struct afs_vnode *vnode = AFS_FS_I(mapping->host); | |
578 | struct iov_iter iter; | |
e87b03f5 DH |
579 | unsigned long priv; |
580 | unsigned int offset, to, len, max_len; | |
874c8ca1 | 581 | loff_t i_size = i_size_read(&vnode->netfs.inode); |
810caa3e | 582 | bool new_content = test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags); |
c7f75ef3 | 583 | bool caching = fscache_cookie_enabled(afs_vnode_cache(vnode)); |
e87b03f5 | 584 | long count = wbc->nr_to_write; |
810caa3e DH |
585 | int ret; |
586 | ||
78525c74 | 587 | _enter(",%lx,%llx-%llx", folio_index(folio), start, end); |
810caa3e | 588 | |
78525c74 | 589 | if (folio_start_writeback(folio)) |
810caa3e | 590 | BUG(); |
c7f75ef3 | 591 | afs_folio_start_fscache(caching, folio); |
810caa3e | 592 | |
78525c74 | 593 | count -= folio_nr_pages(folio); |
e87b03f5 | 594 | |
810caa3e DH |
595 | /* Find all consecutive lockable dirty pages that have contiguous |
596 | * written regions, stopping when we find a page that is not | |
597 | * immediately lockable, is not dirty or is missing, or we reach the | |
598 | * end of the range. | |
599 | */ | |
78525c74 DH |
600 | priv = (unsigned long)folio_get_private(folio); |
601 | offset = afs_folio_dirty_from(folio, priv); | |
602 | to = afs_folio_dirty_to(folio, priv); | |
603 | trace_afs_folio_dirty(vnode, tracepoint_string("store"), folio); | |
e87b03f5 DH |
604 | |
605 | len = to - offset; | |
606 | start += offset; | |
607 | if (start < i_size) { | |
608 | /* Trim the write to the EOF; the extra data is ignored. Also | |
609 | * put an upper limit on the size of a single storedata op. | |
610 | */ | |
611 | max_len = 65536 * 4096; | |
612 | max_len = min_t(unsigned long long, max_len, end - start + 1); | |
613 | max_len = min_t(unsigned long long, max_len, i_size - start); | |
614 | ||
615 | if (len < max_len && | |
78525c74 | 616 | (to == folio_size(folio) || new_content)) |
e87b03f5 | 617 | afs_extend_writeback(mapping, vnode, &count, |
c7f75ef3 DH |
618 | start, max_len, new_content, |
619 | caching, &len); | |
e87b03f5 DH |
620 | len = min_t(loff_t, len, max_len); |
621 | } | |
810caa3e | 622 | |
4343d008 DH |
623 | /* We now have a contiguous set of dirty pages, each with writeback |
624 | * set; the first page is still locked at this point, but all the rest | |
625 | * have been unlocked. | |
626 | */ | |
78525c74 | 627 | folio_unlock(folio); |
793fe82e | 628 | |
e87b03f5 DH |
629 | if (start < i_size) { |
630 | _debug("write back %x @%llx [%llx]", len, start, i_size); | |
bd80d8a8 | 631 | |
c7f75ef3 DH |
632 | /* Speculatively write to the cache. We have to fix this up |
633 | * later if the store fails. | |
634 | */ | |
635 | afs_write_to_cache(vnode, start, len, i_size, caching); | |
636 | ||
de4eda9d | 637 | iov_iter_xarray(&iter, ITER_SOURCE, &mapping->i_pages, start, len); |
e87b03f5 | 638 | ret = afs_store_data(vnode, &iter, start, false); |
bd80d8a8 | 639 | } else { |
e87b03f5 DH |
640 | _debug("write discard %x @%llx [%llx]", len, start, i_size); |
641 | ||
bd80d8a8 | 642 | /* The dirty region was entirely beyond the EOF. */ |
2c547f29 | 643 | fscache_clear_page_bits(mapping, start, len, caching); |
e87b03f5 | 644 | afs_pages_written_back(vnode, start, len); |
bd80d8a8 DH |
645 | ret = 0; |
646 | } | |
31143d5d | 647 | |
4343d008 DH |
648 | switch (ret) { |
649 | case 0: | |
e87b03f5 DH |
650 | wbc->nr_to_write = count; |
651 | ret = len; | |
4343d008 DH |
652 | break; |
653 | ||
654 | default: | |
655 | pr_notice("kAFS: Unexpected error from FS.StoreData %d\n", ret); | |
df561f66 | 656 | fallthrough; |
4343d008 DH |
657 | case -EACCES: |
658 | case -EPERM: | |
659 | case -ENOKEY: | |
660 | case -EKEYEXPIRED: | |
661 | case -EKEYREJECTED: | |
662 | case -EKEYREVOKED: | |
adc9613f | 663 | case -ENETRESET: |
e87b03f5 | 664 | afs_redirty_pages(wbc, mapping, start, len); |
4343d008 DH |
665 | mapping_set_error(mapping, ret); |
666 | break; | |
667 | ||
668 | case -EDQUOT: | |
669 | case -ENOSPC: | |
e87b03f5 | 670 | afs_redirty_pages(wbc, mapping, start, len); |
4343d008 DH |
671 | mapping_set_error(mapping, -ENOSPC); |
672 | break; | |
673 | ||
674 | case -EROFS: | |
675 | case -EIO: | |
676 | case -EREMOTEIO: | |
677 | case -EFBIG: | |
678 | case -ENOENT: | |
679 | case -ENOMEDIUM: | |
680 | case -ENXIO: | |
f51375cd | 681 | trace_afs_file_error(vnode, ret, afs_file_error_writeback_fail); |
e87b03f5 | 682 | afs_kill_pages(mapping, start, len); |
4343d008 DH |
683 | mapping_set_error(mapping, ret); |
684 | break; | |
31143d5d DH |
685 | } |
686 | ||
687 | _leave(" = %d", ret); | |
688 | return ret; | |
689 | } | |
690 | ||
31143d5d DH |
691 | /* |
692 | * write a region of pages back to the server | |
693 | */ | |
c1206a2c AB |
694 | static int afs_writepages_region(struct address_space *mapping, |
695 | struct writeback_control *wbc, | |
a9eb558a DH |
696 | loff_t start, loff_t end, loff_t *_next, |
697 | bool max_one_loop) | |
31143d5d | 698 | { |
78525c74 | 699 | struct folio *folio; |
acc8d858 | 700 | struct folio_batch fbatch; |
e87b03f5 | 701 | ssize_t ret; |
acc8d858 | 702 | unsigned int i; |
173ce1ca | 703 | int n, skips = 0; |
31143d5d | 704 | |
e87b03f5 | 705 | _enter("%llx,%llx,", start, end); |
acc8d858 | 706 | folio_batch_init(&fbatch); |
31143d5d DH |
707 | |
708 | do { | |
e87b03f5 DH |
709 | pgoff_t index = start / PAGE_SIZE; |
710 | ||
acc8d858 VMO |
711 | n = filemap_get_folios_tag(mapping, &index, end / PAGE_SIZE, |
712 | PAGECACHE_TAG_DIRTY, &fbatch); | |
713 | ||
31143d5d DH |
714 | if (!n) |
715 | break; | |
acc8d858 VMO |
716 | for (i = 0; i < n; i++) { |
717 | folio = fbatch.folios[i]; | |
718 | start = folio_pos(folio); /* May regress with THPs */ | |
31143d5d | 719 | |
acc8d858 | 720 | _debug("wback %lx", folio_index(folio)); |
31143d5d | 721 | |
acc8d858 VMO |
722 | /* At this point we hold neither the i_pages lock nor the |
723 | * page lock: the page may be truncated or invalidated | |
724 | * (changing page->mapping to NULL), or even swizzled | |
725 | * back from swapper_space to tmpfs file mapping | |
726 | */ | |
819da022 | 727 | try_again: |
acc8d858 VMO |
728 | if (wbc->sync_mode != WB_SYNC_NONE) { |
729 | ret = folio_lock_killable(folio); | |
730 | if (ret < 0) { | |
731 | folio_batch_release(&fbatch); | |
732 | return ret; | |
733 | } | |
734 | } else { | |
735 | if (!folio_trylock(folio)) | |
736 | continue; | |
e87b03f5 | 737 | } |
31143d5d | 738 | |
acc8d858 VMO |
739 | if (folio->mapping != mapping || |
740 | !folio_test_dirty(folio)) { | |
741 | start += folio_size(folio); | |
742 | folio_unlock(folio); | |
743 | continue; | |
744 | } | |
31143d5d | 745 | |
acc8d858 VMO |
746 | if (folio_test_writeback(folio) || |
747 | folio_test_fscache(folio)) { | |
748 | folio_unlock(folio); | |
749 | if (wbc->sync_mode != WB_SYNC_NONE) { | |
750 | folio_wait_writeback(folio); | |
c7f75ef3 | 751 | #ifdef CONFIG_AFS_FSCACHE |
acc8d858 | 752 | folio_wait_fscache(folio); |
c7f75ef3 | 753 | #endif |
819da022 | 754 | goto try_again; |
acc8d858 | 755 | } |
819da022 VMO |
756 | |
757 | start += folio_size(folio); | |
acc8d858 VMO |
758 | if (wbc->sync_mode == WB_SYNC_NONE) { |
759 | if (skips >= 5 || need_resched()) { | |
760 | *_next = start; | |
a2b6f2ab | 761 | folio_batch_release(&fbatch); |
acc8d858 VMO |
762 | _leave(" = 0 [%llx]", *_next); |
763 | return 0; | |
764 | } | |
765 | skips++; | |
766 | } | |
767 | continue; | |
c7f75ef3 | 768 | } |
acc8d858 VMO |
769 | |
770 | if (!folio_clear_dirty_for_io(folio)) | |
771 | BUG(); | |
772 | ret = afs_write_back_from_locked_folio(mapping, wbc, | |
773 | folio, start, end); | |
774 | if (ret < 0) { | |
775 | _leave(" = %zd", ret); | |
776 | folio_batch_release(&fbatch); | |
777 | return ret; | |
173ce1ca | 778 | } |
31143d5d | 779 | |
acc8d858 | 780 | start += ret; |
31143d5d DH |
781 | } |
782 | ||
acc8d858 | 783 | folio_batch_release(&fbatch); |
31143d5d | 784 | cond_resched(); |
e87b03f5 | 785 | } while (wbc->nr_to_write > 0); |
31143d5d | 786 | |
e87b03f5 DH |
787 | *_next = start; |
788 | _leave(" = 0 [%llx]", *_next); | |
31143d5d DH |
789 | return 0; |
790 | } | |
791 | ||
792 | /* | |
793 | * write some of the pending data back to the server | |
794 | */ | |
795 | int afs_writepages(struct address_space *mapping, | |
796 | struct writeback_control *wbc) | |
797 | { | |
ec0fa0b6 | 798 | struct afs_vnode *vnode = AFS_FS_I(mapping->host); |
e87b03f5 | 799 | loff_t start, next; |
31143d5d DH |
800 | int ret; |
801 | ||
802 | _enter(""); | |
803 | ||
ec0fa0b6 DH |
804 | /* We have to be careful as we can end up racing with setattr() |
805 | * truncating the pagecache since the caller doesn't take a lock here | |
806 | * to prevent it. | |
807 | */ | |
808 | if (wbc->sync_mode == WB_SYNC_ALL) | |
809 | down_read(&vnode->validate_lock); | |
810 | else if (!down_read_trylock(&vnode->validate_lock)) | |
811 | return 0; | |
812 | ||
31143d5d | 813 | if (wbc->range_cyclic) { |
e87b03f5 | 814 | start = mapping->writeback_index * PAGE_SIZE; |
a9eb558a DH |
815 | ret = afs_writepages_region(mapping, wbc, start, LLONG_MAX, |
816 | &next, false); | |
afe69498 TR |
817 | if (ret == 0) { |
818 | mapping->writeback_index = next / PAGE_SIZE; | |
819 | if (start > 0 && wbc->nr_to_write > 0) { | |
820 | ret = afs_writepages_region(mapping, wbc, 0, | |
a9eb558a | 821 | start, &next, false); |
afe69498 TR |
822 | if (ret == 0) |
823 | mapping->writeback_index = | |
824 | next / PAGE_SIZE; | |
825 | } | |
826 | } | |
31143d5d | 827 | } else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) { |
a9eb558a DH |
828 | ret = afs_writepages_region(mapping, wbc, 0, LLONG_MAX, |
829 | &next, false); | |
afe69498 | 830 | if (wbc->nr_to_write > 0 && ret == 0) |
5a972474 | 831 | mapping->writeback_index = next / PAGE_SIZE; |
31143d5d | 832 | } else { |
e87b03f5 | 833 | ret = afs_writepages_region(mapping, wbc, |
a9eb558a DH |
834 | wbc->range_start, wbc->range_end, |
835 | &next, false); | |
31143d5d DH |
836 | } |
837 | ||
ec0fa0b6 | 838 | up_read(&vnode->validate_lock); |
31143d5d DH |
839 | _leave(" = %d", ret); |
840 | return ret; | |
841 | } | |
842 | ||
31143d5d DH |
843 | /* |
844 | * write to an AFS file | |
845 | */ | |
50b5551d | 846 | ssize_t afs_file_write(struct kiocb *iocb, struct iov_iter *from) |
31143d5d | 847 | { |
496ad9aa | 848 | struct afs_vnode *vnode = AFS_FS_I(file_inode(iocb->ki_filp)); |
3978d816 | 849 | struct afs_file *af = iocb->ki_filp->private_data; |
31143d5d | 850 | ssize_t result; |
50b5551d | 851 | size_t count = iov_iter_count(from); |
31143d5d | 852 | |
3b6492df | 853 | _enter("{%llx:%llu},{%zu},", |
50b5551d | 854 | vnode->fid.vid, vnode->fid.vnode, count); |
31143d5d | 855 | |
874c8ca1 | 856 | if (IS_SWAPFILE(&vnode->netfs.inode)) { |
31143d5d DH |
857 | printk(KERN_INFO |
858 | "AFS: Attempt to write to active swap file!\n"); | |
859 | return -EBUSY; | |
860 | } | |
861 | ||
862 | if (!count) | |
863 | return 0; | |
864 | ||
3978d816 DH |
865 | result = afs_validate(vnode, af->key); |
866 | if (result < 0) | |
867 | return result; | |
868 | ||
50b5551d | 869 | result = generic_file_write_iter(iocb, from); |
31143d5d | 870 | |
31143d5d DH |
871 | _leave(" = %zd", result); |
872 | return result; | |
873 | } | |
874 | ||
31143d5d DH |
875 | /* |
876 | * flush any dirty pages for this process, and check for write errors. | |
877 | * - the return status from this call provides a reliable indication of | |
878 | * whether any write errors occurred for this process. | |
879 | */ | |
02c24a82 | 880 | int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
31143d5d | 881 | { |
3978d816 DH |
882 | struct afs_vnode *vnode = AFS_FS_I(file_inode(file)); |
883 | struct afs_file *af = file->private_data; | |
884 | int ret; | |
31143d5d | 885 | |
3b6492df | 886 | _enter("{%llx:%llu},{n=%pD},%d", |
3c981bfc | 887 | vnode->fid.vid, vnode->fid.vnode, file, |
31143d5d DH |
888 | datasync); |
889 | ||
3978d816 DH |
890 | ret = afs_validate(vnode, af->key); |
891 | if (ret < 0) | |
892 | return ret; | |
893 | ||
4343d008 | 894 | return file_write_and_wait_range(file, start, end); |
31143d5d | 895 | } |
9b3f26c9 DH |
896 | |
897 | /* | |
898 | * notification that a previously read-only page is about to become writable | |
899 | * - if it returns an error, the caller will deliver a bus error signal | |
900 | */ | |
0722f186 | 901 | vm_fault_t afs_page_mkwrite(struct vm_fault *vmf) |
9b3f26c9 | 902 | { |
490e016f | 903 | struct folio *folio = page_folio(vmf->page); |
1cf7a151 DH |
904 | struct file *file = vmf->vma->vm_file; |
905 | struct inode *inode = file_inode(file); | |
906 | struct afs_vnode *vnode = AFS_FS_I(inode); | |
3978d816 | 907 | struct afs_file *af = file->private_data; |
1cf7a151 | 908 | unsigned long priv; |
9620ad86 | 909 | vm_fault_t ret = VM_FAULT_RETRY; |
9b3f26c9 | 910 | |
78525c74 | 911 | _enter("{{%llx:%llu}},{%lx}", vnode->fid.vid, vnode->fid.vnode, folio_index(folio)); |
9b3f26c9 | 912 | |
3978d816 DH |
913 | afs_validate(vnode, af->key); |
914 | ||
1cf7a151 | 915 | sb_start_pagefault(inode->i_sb); |
9b3f26c9 | 916 | |
1cf7a151 DH |
917 | /* Wait for the page to be written to the cache before we allow it to |
918 | * be modified. We then assume the entire page will need writing back. | |
919 | */ | |
630f5dda | 920 | #ifdef CONFIG_AFS_FSCACHE |
78525c74 DH |
921 | if (folio_test_fscache(folio) && |
922 | folio_wait_fscache_killable(folio) < 0) | |
9620ad86 | 923 | goto out; |
630f5dda | 924 | #endif |
9b3f26c9 | 925 | |
490e016f | 926 | if (folio_wait_writeback_killable(folio)) |
9620ad86 | 927 | goto out; |
1cf7a151 | 928 | |
78525c74 | 929 | if (folio_lock_killable(folio) < 0) |
9620ad86 | 930 | goto out; |
1cf7a151 | 931 | |
78525c74 | 932 | /* We mustn't change folio->private until writeback is complete as that |
1cf7a151 DH |
933 | * details the portion of the page we need to write back and we might |
934 | * need to redirty the page if there's a problem. | |
935 | */ | |
490e016f MWO |
936 | if (folio_wait_writeback_killable(folio) < 0) { |
937 | folio_unlock(folio); | |
9620ad86 | 938 | goto out; |
5cbf0398 | 939 | } |
1cf7a151 | 940 | |
78525c74 DH |
941 | priv = afs_folio_dirty(folio, 0, folio_size(folio)); |
942 | priv = afs_folio_dirty_mmapped(priv); | |
943 | if (folio_test_private(folio)) { | |
944 | folio_change_private(folio, (void *)priv); | |
945 | trace_afs_folio_dirty(vnode, tracepoint_string("mkwrite+"), folio); | |
e87b03f5 | 946 | } else { |
78525c74 DH |
947 | folio_attach_private(folio, (void *)priv); |
948 | trace_afs_folio_dirty(vnode, tracepoint_string("mkwrite"), folio); | |
e87b03f5 | 949 | } |
bb413489 | 950 | file_update_time(file); |
1cf7a151 | 951 | |
9620ad86 MWO |
952 | ret = VM_FAULT_LOCKED; |
953 | out: | |
1cf7a151 | 954 | sb_end_pagefault(inode->i_sb); |
9620ad86 | 955 | return ret; |
9b3f26c9 | 956 | } |
4343d008 DH |
957 | |
958 | /* | |
959 | * Prune the keys cached for writeback. The caller must hold vnode->wb_lock. | |
960 | */ | |
961 | void afs_prune_wb_keys(struct afs_vnode *vnode) | |
962 | { | |
963 | LIST_HEAD(graveyard); | |
964 | struct afs_wb_key *wbk, *tmp; | |
965 | ||
966 | /* Discard unused keys */ | |
967 | spin_lock(&vnode->wb_lock); | |
968 | ||
874c8ca1 DH |
969 | if (!mapping_tagged(&vnode->netfs.inode.i_data, PAGECACHE_TAG_WRITEBACK) && |
970 | !mapping_tagged(&vnode->netfs.inode.i_data, PAGECACHE_TAG_DIRTY)) { | |
4343d008 DH |
971 | list_for_each_entry_safe(wbk, tmp, &vnode->wb_keys, vnode_link) { |
972 | if (refcount_read(&wbk->usage) == 1) | |
973 | list_move(&wbk->vnode_link, &graveyard); | |
974 | } | |
975 | } | |
976 | ||
977 | spin_unlock(&vnode->wb_lock); | |
978 | ||
979 | while (!list_empty(&graveyard)) { | |
980 | wbk = list_entry(graveyard.next, struct afs_wb_key, vnode_link); | |
981 | list_del(&wbk->vnode_link); | |
982 | afs_put_wb_key(wbk); | |
983 | } | |
984 | } | |
985 | ||
986 | /* | |
987 | * Clean up a page during invalidation. | |
988 | */ | |
a42442dd | 989 | int afs_launder_folio(struct folio *folio) |
4343d008 | 990 | { |
78525c74 | 991 | struct afs_vnode *vnode = AFS_FS_I(folio_inode(folio)); |
bd80d8a8 | 992 | struct iov_iter iter; |
a8173be1 | 993 | struct bio_vec bv; |
4343d008 DH |
994 | unsigned long priv; |
995 | unsigned int f, t; | |
996 | int ret = 0; | |
997 | ||
a42442dd | 998 | _enter("{%lx}", folio->index); |
4343d008 | 999 | |
78525c74 DH |
1000 | priv = (unsigned long)folio_get_private(folio); |
1001 | if (folio_clear_dirty_for_io(folio)) { | |
4343d008 | 1002 | f = 0; |
78525c74 DH |
1003 | t = folio_size(folio); |
1004 | if (folio_test_private(folio)) { | |
1005 | f = afs_folio_dirty_from(folio, priv); | |
1006 | t = afs_folio_dirty_to(folio, priv); | |
4343d008 DH |
1007 | } |
1008 | ||
a8173be1 CH |
1009 | bvec_set_folio(&bv, folio, t - f, f); |
1010 | iov_iter_bvec(&iter, ITER_SOURCE, &bv, 1, bv.bv_len); | |
bd80d8a8 | 1011 | |
78525c74 DH |
1012 | trace_afs_folio_dirty(vnode, tracepoint_string("launder"), folio); |
1013 | ret = afs_store_data(vnode, &iter, folio_pos(folio) + f, true); | |
4343d008 DH |
1014 | } |
1015 | ||
78525c74 DH |
1016 | trace_afs_folio_dirty(vnode, tracepoint_string("laundered"), folio); |
1017 | folio_detach_private(folio); | |
1018 | folio_wait_fscache(folio); | |
4343d008 | 1019 | return ret; |
9b3f26c9 | 1020 | } |
c7f75ef3 DH |
1021 | |
1022 | /* | |
1023 | * Deal with the completion of writing the data to the cache. | |
1024 | */ | |
1025 | static void afs_write_to_cache_done(void *priv, ssize_t transferred_or_error, | |
1026 | bool was_async) | |
1027 | { | |
1028 | struct afs_vnode *vnode = priv; | |
1029 | ||
1030 | if (IS_ERR_VALUE(transferred_or_error) && | |
1031 | transferred_or_error != -ENOBUFS) | |
1032 | afs_invalidate_cache(vnode, 0); | |
1033 | } | |
1034 | ||
1035 | /* | |
1036 | * Save the write to the cache also. | |
1037 | */ | |
1038 | static void afs_write_to_cache(struct afs_vnode *vnode, | |
1039 | loff_t start, size_t len, loff_t i_size, | |
1040 | bool caching) | |
1041 | { | |
1042 | fscache_write_to_cache(afs_vnode_cache(vnode), | |
874c8ca1 | 1043 | vnode->netfs.inode.i_mapping, start, len, i_size, |
c7f75ef3 DH |
1044 | afs_write_to_cache_done, vnode, caching); |
1045 | } |