.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* AFS filesystem file handling |
---|
2 | 3 | * |
---|
3 | 4 | * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved. |
---|
4 | 5 | * Written by David Howells (dhowells@redhat.com) |
---|
5 | | - * |
---|
6 | | - * This program is free software; you can redistribute it and/or |
---|
7 | | - * modify it under the terms of the GNU General Public License |
---|
8 | | - * as published by the Free Software Foundation; either version |
---|
9 | | - * 2 of the License, or (at your option) any later version. |
---|
10 | 6 | */ |
---|
11 | 7 | |
---|
12 | 8 | #include <linux/kernel.h> |
---|
.. | .. |
---|
17 | 13 | #include <linux/writeback.h> |
---|
18 | 14 | #include <linux/gfp.h> |
---|
19 | 15 | #include <linux/task_io_accounting_ops.h> |
---|
| 16 | +#include <linux/mm.h> |
---|
20 | 17 | #include "internal.h" |
---|
21 | 18 | |
---|
22 | 19 | static int afs_file_mmap(struct file *file, struct vm_area_struct *vma); |
---|
.. | .. |
---|
36 | 33 | .write_iter = afs_file_write, |
---|
37 | 34 | .mmap = afs_file_mmap, |
---|
38 | 35 | .splice_read = generic_file_splice_read, |
---|
| 36 | + .splice_write = iter_file_splice_write, |
---|
39 | 37 | .fsync = afs_fsync, |
---|
40 | 38 | .lock = afs_lock, |
---|
41 | 39 | .flock = afs_flock, |
---|
.. | .. |
---|
45 | 43 | .getattr = afs_getattr, |
---|
46 | 44 | .setattr = afs_setattr, |
---|
47 | 45 | .permission = afs_permission, |
---|
48 | | - .listxattr = afs_listxattr, |
---|
49 | 46 | }; |
---|
50 | 47 | |
---|
51 | 48 | const struct address_space_operations afs_fs_aops = { |
---|
.. | .. |
---|
72 | 69 | */ |
---|
73 | 70 | void afs_put_wb_key(struct afs_wb_key *wbk) |
---|
74 | 71 | { |
---|
75 | | - if (refcount_dec_and_test(&wbk->usage)) { |
---|
| 72 | + if (wbk && refcount_dec_and_test(&wbk->usage)) { |
---|
76 | 73 | key_put(wbk->key); |
---|
77 | 74 | kfree(wbk); |
---|
78 | 75 | } |
---|
.. | .. |
---|
121 | 118 | struct key *key; |
---|
122 | 119 | int ret; |
---|
123 | 120 | |
---|
124 | | - _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); |
---|
| 121 | + _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode); |
---|
125 | 122 | |
---|
126 | 123 | key = afs_request_key(vnode->volume->cell); |
---|
127 | 124 | if (IS_ERR(key)) { |
---|
.. | .. |
---|
171 | 168 | struct afs_file *af = file->private_data; |
---|
172 | 169 | int ret = 0; |
---|
173 | 170 | |
---|
174 | | - _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode); |
---|
| 171 | + _enter("{%llx:%llu},", vnode->fid.vid, vnode->fid.vnode); |
---|
175 | 172 | |
---|
176 | 173 | if ((file->f_mode & FMODE_WRITE)) |
---|
177 | 174 | ret = vfs_fsync(file, 0); |
---|
.. | .. |
---|
223 | 220 | } |
---|
224 | 221 | #endif |
---|
225 | 222 | |
---|
| 223 | +static void afs_fetch_data_success(struct afs_operation *op) |
---|
| 224 | +{ |
---|
| 225 | + struct afs_vnode *vnode = op->file[0].vnode; |
---|
| 226 | + |
---|
| 227 | + _enter("op=%08x", op->debug_id); |
---|
| 228 | + afs_vnode_commit_status(op, &op->file[0]); |
---|
| 229 | + afs_stat_v(vnode, n_fetches); |
---|
| 230 | + atomic_long_add(op->fetch.req->actual_len, &op->net->n_fetch_bytes); |
---|
| 231 | +} |
---|
| 232 | + |
---|
| 233 | +static void afs_fetch_data_put(struct afs_operation *op) |
---|
| 234 | +{ |
---|
| 235 | + afs_put_read(op->fetch.req); |
---|
| 236 | +} |
---|
| 237 | + |
---|
| 238 | +static const struct afs_operation_ops afs_fetch_data_operation = { |
---|
| 239 | + .issue_afs_rpc = afs_fs_fetch_data, |
---|
| 240 | + .issue_yfs_rpc = yfs_fs_fetch_data, |
---|
| 241 | + .success = afs_fetch_data_success, |
---|
| 242 | + .aborted = afs_check_for_remote_deletion, |
---|
| 243 | + .put = afs_fetch_data_put, |
---|
| 244 | +}; |
---|
| 245 | + |
---|
226 | 246 | /* |
---|
227 | 247 | * Fetch file data from the volume. |
---|
228 | 248 | */ |
---|
229 | | -int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *desc) |
---|
| 249 | +int afs_fetch_data(struct afs_vnode *vnode, struct key *key, struct afs_read *req) |
---|
230 | 250 | { |
---|
231 | | - struct afs_fs_cursor fc; |
---|
232 | | - int ret; |
---|
| 251 | + struct afs_operation *op; |
---|
233 | 252 | |
---|
234 | | - _enter("%s{%x:%u.%u},%x,,,", |
---|
| 253 | + _enter("%s{%llx:%llu.%u},%x,,,", |
---|
235 | 254 | vnode->volume->name, |
---|
236 | 255 | vnode->fid.vid, |
---|
237 | 256 | vnode->fid.vnode, |
---|
238 | 257 | vnode->fid.unique, |
---|
239 | 258 | key_serial(key)); |
---|
240 | 259 | |
---|
241 | | - ret = -ERESTARTSYS; |
---|
242 | | - if (afs_begin_vnode_operation(&fc, vnode, key)) { |
---|
243 | | - while (afs_select_fileserver(&fc)) { |
---|
244 | | - fc.cb_break = afs_calc_vnode_cb_break(vnode); |
---|
245 | | - afs_fs_fetch_data(&fc, desc); |
---|
246 | | - } |
---|
| 260 | + op = afs_alloc_operation(key, vnode->volume); |
---|
| 261 | + if (IS_ERR(op)) |
---|
| 262 | + return PTR_ERR(op); |
---|
247 | 263 | |
---|
248 | | - afs_check_for_remote_deletion(&fc, fc.vnode); |
---|
249 | | - afs_vnode_commit_status(&fc, vnode, fc.cb_break); |
---|
250 | | - ret = afs_end_vnode_operation(&fc); |
---|
251 | | - } |
---|
| 264 | + afs_op_set_vnode(op, 0, vnode); |
---|
252 | 265 | |
---|
253 | | - if (ret == 0) { |
---|
254 | | - afs_stat_v(vnode, n_fetches); |
---|
255 | | - atomic_long_add(desc->actual_len, |
---|
256 | | - &afs_v2net(vnode)->n_fetch_bytes); |
---|
257 | | - } |
---|
258 | | - |
---|
259 | | - _leave(" = %d", ret); |
---|
260 | | - return ret; |
---|
| 266 | + op->fetch.req = afs_get_read(req); |
---|
| 267 | + op->ops = &afs_fetch_data_operation; |
---|
| 268 | + return afs_do_sync_operation(op); |
---|
261 | 269 | } |
---|
262 | 270 | |
---|
263 | 271 | /* |
---|
.. | .. |
---|
302 | 310 | /* page will not be cached */ |
---|
303 | 311 | case -ENOBUFS: |
---|
304 | 312 | _debug("cache said ENOBUFS"); |
---|
| 313 | + |
---|
| 314 | + fallthrough; |
---|
305 | 315 | default: |
---|
306 | 316 | go_on: |
---|
307 | | - req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *), |
---|
308 | | - GFP_KERNEL); |
---|
| 317 | + req = kzalloc(struct_size(req, array, 1), GFP_KERNEL); |
---|
309 | 318 | if (!req) |
---|
310 | 319 | goto enomem; |
---|
311 | 320 | |
---|
.. | .. |
---|
404 | 413 | /* |
---|
405 | 414 | * Make pages available as they're filled. |
---|
406 | 415 | */ |
---|
407 | | -static void afs_readpages_page_done(struct afs_call *call, struct afs_read *req) |
---|
| 416 | +static void afs_readpages_page_done(struct afs_read *req) |
---|
408 | 417 | { |
---|
409 | 418 | #ifdef CONFIG_AFS_FSCACHE |
---|
410 | | - struct afs_vnode *vnode = call->reply[0]; |
---|
| 419 | + struct afs_vnode *vnode = req->vnode; |
---|
411 | 420 | #endif |
---|
412 | 421 | struct page *page = req->pages[req->index]; |
---|
413 | 422 | |
---|
.. | .. |
---|
444 | 453 | /* Count the number of contiguous pages at the front of the list. Note |
---|
445 | 454 | * that the list goes prev-wards rather than next-wards. |
---|
446 | 455 | */ |
---|
447 | | - first = list_entry(pages->prev, struct page, lru); |
---|
| 456 | + first = lru_to_page(pages); |
---|
448 | 457 | index = first->index + 1; |
---|
449 | 458 | n = 1; |
---|
450 | 459 | for (p = first->lru.prev; p != pages; p = p->prev) { |
---|
.. | .. |
---|
455 | 464 | n++; |
---|
456 | 465 | } |
---|
457 | 466 | |
---|
458 | | - req = kzalloc(sizeof(struct afs_read) + sizeof(struct page *) * n, |
---|
459 | | - GFP_NOFS); |
---|
| 467 | + req = kzalloc(struct_size(req, array, n), GFP_NOFS); |
---|
460 | 468 | if (!req) |
---|
461 | 469 | return -ENOMEM; |
---|
462 | 470 | |
---|
463 | 471 | refcount_set(&req->usage, 1); |
---|
| 472 | + req->vnode = vnode; |
---|
464 | 473 | req->page_done = afs_readpages_page_done; |
---|
465 | 474 | req->pos = first->index; |
---|
466 | 475 | req->pos <<= PAGE_SHIFT; |
---|
.. | .. |
---|
476 | 485 | * page at the end of the file. |
---|
477 | 486 | */ |
---|
478 | 487 | do { |
---|
479 | | - page = list_entry(pages->prev, struct page, lru); |
---|
| 488 | + page = lru_to_page(pages); |
---|
480 | 489 | list_del(&page->lru); |
---|
481 | 490 | index = page->index; |
---|
482 | 491 | if (add_to_page_cache_lru(page, mapping, index, |
---|
.. | .. |
---|
592 | 601 | } |
---|
593 | 602 | |
---|
594 | 603 | /* |
---|
| 604 | + * Adjust the dirty region of the page on truncation or full invalidation, |
---|
| 605 | + * getting rid of the markers altogether if the region is entirely invalidated. |
---|
| 606 | + */ |
---|
| 607 | +static void afs_invalidate_dirty(struct page *page, unsigned int offset, |
---|
| 608 | + unsigned int length) |
---|
| 609 | +{ |
---|
| 610 | + struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); |
---|
| 611 | + unsigned long priv; |
---|
| 612 | + unsigned int f, t, end = offset + length; |
---|
| 613 | + |
---|
| 614 | + priv = page_private(page); |
---|
| 615 | + |
---|
| 616 | + /* we clean up only if the entire page is being invalidated */ |
---|
| 617 | + if (offset == 0 && length == thp_size(page)) |
---|
| 618 | + goto full_invalidate; |
---|
| 619 | + |
---|
| 620 | + /* If the page was dirtied by page_mkwrite(), the PTE stays writable |
---|
| 621 | + * and we don't get another notification to tell us to expand it |
---|
| 622 | + * again. |
---|
| 623 | + */ |
---|
| 624 | + if (afs_is_page_dirty_mmapped(priv)) |
---|
| 625 | + return; |
---|
| 626 | + |
---|
| 627 | + /* We may need to shorten the dirty region */ |
---|
| 628 | + f = afs_page_dirty_from(priv); |
---|
| 629 | + t = afs_page_dirty_to(priv); |
---|
| 630 | + |
---|
| 631 | + if (t <= offset || f >= end) |
---|
| 632 | + return; /* Doesn't overlap */ |
---|
| 633 | + |
---|
| 634 | + if (f < offset && t > end) |
---|
| 635 | + return; /* Splits the dirty region - just absorb it */ |
---|
| 636 | + |
---|
| 637 | + if (f >= offset && t <= end) |
---|
| 638 | + goto undirty; |
---|
| 639 | + |
---|
| 640 | + if (f < offset) |
---|
| 641 | + t = offset; |
---|
| 642 | + else |
---|
| 643 | + f = end; |
---|
| 644 | + if (f == t) |
---|
| 645 | + goto undirty; |
---|
| 646 | + |
---|
| 647 | + priv = afs_page_dirty(f, t); |
---|
| 648 | + set_page_private(page, priv); |
---|
| 649 | + trace_afs_page_dirty(vnode, tracepoint_string("trunc"), page->index, priv); |
---|
| 650 | + return; |
---|
| 651 | + |
---|
| 652 | +undirty: |
---|
| 653 | + trace_afs_page_dirty(vnode, tracepoint_string("undirty"), page->index, priv); |
---|
| 654 | + clear_page_dirty_for_io(page); |
---|
| 655 | +full_invalidate: |
---|
| 656 | + priv = (unsigned long)detach_page_private(page); |
---|
| 657 | + trace_afs_page_dirty(vnode, tracepoint_string("inval"), page->index, priv); |
---|
| 658 | +} |
---|
| 659 | + |
---|
| 660 | +/* |
---|
595 | 661 | * invalidate part or all of a page |
---|
596 | 662 | * - release a page and clean up its private data if offset is 0 (indicating |
---|
597 | 663 | * the entire page) |
---|
.. | .. |
---|
599 | 665 | static void afs_invalidatepage(struct page *page, unsigned int offset, |
---|
600 | 666 | unsigned int length) |
---|
601 | 667 | { |
---|
602 | | - struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); |
---|
603 | | - unsigned long priv; |
---|
604 | | - |
---|
605 | 668 | _enter("{%lu},%u,%u", page->index, offset, length); |
---|
606 | 669 | |
---|
607 | 670 | BUG_ON(!PageLocked(page)); |
---|
608 | 671 | |
---|
| 672 | +#ifdef CONFIG_AFS_FSCACHE |
---|
609 | 673 | /* we clean up only if the entire page is being invalidated */ |
---|
610 | 674 | if (offset == 0 && length == PAGE_SIZE) { |
---|
611 | | -#ifdef CONFIG_AFS_FSCACHE |
---|
612 | 675 | if (PageFsCache(page)) { |
---|
613 | 676 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); |
---|
614 | 677 | fscache_wait_on_page_write(vnode->cache, page); |
---|
615 | 678 | fscache_uncache_page(vnode->cache, page); |
---|
616 | 679 | } |
---|
| 680 | + } |
---|
617 | 681 | #endif |
---|
618 | 682 | |
---|
619 | | - if (PagePrivate(page)) { |
---|
620 | | - priv = page_private(page); |
---|
621 | | - trace_afs_page_dirty(vnode, tracepoint_string("inval"), |
---|
622 | | - page->index, priv); |
---|
623 | | - set_page_private(page, 0); |
---|
624 | | - ClearPagePrivate(page); |
---|
625 | | - } |
---|
626 | | - } |
---|
| 683 | + if (PagePrivate(page)) |
---|
| 684 | + afs_invalidate_dirty(page, offset, length); |
---|
627 | 685 | |
---|
628 | 686 | _leave(""); |
---|
629 | 687 | } |
---|
.. | .. |
---|
637 | 695 | struct afs_vnode *vnode = AFS_FS_I(page->mapping->host); |
---|
638 | 696 | unsigned long priv; |
---|
639 | 697 | |
---|
640 | | - _enter("{{%x:%u}[%lu],%lx},%x", |
---|
| 698 | + _enter("{{%llx:%llu}[%lu],%lx},%x", |
---|
641 | 699 | vnode->fid.vid, vnode->fid.vnode, page->index, page->flags, |
---|
642 | 700 | gfp_flags); |
---|
643 | 701 | |
---|
.. | .. |
---|
651 | 709 | #endif |
---|
652 | 710 | |
---|
653 | 711 | if (PagePrivate(page)) { |
---|
654 | | - priv = page_private(page); |
---|
| 712 | + priv = (unsigned long)detach_page_private(page); |
---|
655 | 713 | trace_afs_page_dirty(vnode, tracepoint_string("rel"), |
---|
656 | 714 | page->index, priv); |
---|
657 | | - set_page_private(page, 0); |
---|
658 | | - ClearPagePrivate(page); |
---|
659 | 715 | } |
---|
660 | 716 | |
---|
661 | 717 | /* indicate that the page can be released */ |
---|