| .. | .. |
|---|
| 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 */ |
|---|