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