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