lkml.org 
[lkml]   [2020]   [Nov]   [20]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Subject[RFC PATCH 65/76] afs: Prepare for use of THPs
    From
    Date
    As a prelude to supporting transparent huge pages, use thp_size() and
    similar rather than PAGE_SIZE/SHIFT.

    Further, try and frame everything in terms of file positions and lengths
    rather than page indices and numbers of pages.

    Signed-off-by: David Howells <dhowells@redhat.com>
    ---

    fs/afs/dir.c | 2
    fs/afs/file.c | 8 -
    fs/afs/internal.h | 2
    fs/afs/write.c | 436 +++++++++++++++++++++++++++++------------------------
    4 files changed, 245 insertions(+), 203 deletions(-)

    diff --git a/fs/afs/dir.c b/fs/afs/dir.c
    index 215f73121391..26ac5cfdf3af 100644
    --- a/fs/afs/dir.c
    +++ b/fs/afs/dir.c
    @@ -2078,6 +2078,6 @@ static void afs_dir_invalidatepage(struct page *page, unsigned int offset,
    afs_stat_v(dvnode, n_inval);

    /* we clean up only if the entire page is being invalidated */
    - if (offset == 0 && length == PAGE_SIZE)
    + if (offset == 0 && length == thp_size(page))
    detach_page_private(page);
    }
    diff --git a/fs/afs/file.c b/fs/afs/file.c
    index a6c6cc9b1d1c..b4a78afad643 100644
    --- a/fs/afs/file.c
    +++ b/fs/afs/file.c
    @@ -343,8 +343,8 @@ static int afs_page_filler(struct key *key, struct page *page)
    req->vnode = vnode;
    req->key = key_get(key);
    req->pos = (loff_t)page->index << PAGE_SHIFT;
    - req->len = PAGE_SIZE;
    - req->nr_pages = 1;
    + req->len = thp_size(page);
    + req->nr_pages = thp_nr_pages(page);
    req->done = afs_file_read_done;
    req->cleanup = afs_file_read_cleanup;

    @@ -588,8 +588,8 @@ static void afs_invalidate_dirty(struct page *page, unsigned int offset,
    trace_afs_page_dirty(vnode, tracepoint_string("undirty"), page);
    clear_page_dirty_for_io(page);
    full_invalidate:
    - detach_page_private(page);
    trace_afs_page_dirty(vnode, tracepoint_string("inval"), page);
    + detach_page_private(page);
    }

    /*
    @@ -634,8 +634,8 @@ static int afs_releasepage(struct page *page, gfp_t gfp_flags)
    #endif

    if (PagePrivate(page)) {
    - detach_page_private(page);
    trace_afs_page_dirty(vnode, tracepoint_string("rel"), page);
    + detach_page_private(page);
    }

    /* indicate that the page can be released */
    diff --git a/fs/afs/internal.h b/fs/afs/internal.h
    index 3556500a1247..ce1f05d5c94b 100644
    --- a/fs/afs/internal.h
    +++ b/fs/afs/internal.h
    @@ -814,8 +814,6 @@ struct afs_operation {
    loff_t pos;
    loff_t size;
    loff_t i_size;
    - pgoff_t first; /* first page in mapping to deal with */
    - pgoff_t last; /* last page in mapping to deal with */
    bool laundering; /* Laundering page, PG_writeback not set */
    } store;
    struct {
    diff --git a/fs/afs/write.c b/fs/afs/write.c
    index 89c804bfe253..e672833c99bc 100644
    --- a/fs/afs/write.c
    +++ b/fs/afs/write.c
    @@ -94,15 +94,15 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
    struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
    struct page *page;
    unsigned long priv;
    - unsigned f, from = pos & (PAGE_SIZE - 1);
    - unsigned t, to = from + len;
    - pgoff_t index = pos >> PAGE_SHIFT;
    + unsigned f, from;
    + unsigned t, to;
    + pgoff_t index;
    int ret;

    - _enter("{%llx:%llu},{%lx},%u,%u",
    - vnode->fid.vid, vnode->fid.vnode, index, from, to);
    + _enter("{%llx:%llu},%llx,%x",
    + vnode->fid.vid, vnode->fid.vnode, pos, len);

    - page = grab_cache_page_write_begin(mapping, index, flags);
    + page = grab_cache_page_write_begin(mapping, pos / PAGE_SIZE, flags);
    if (!page)
    return -ENOMEM;

    @@ -121,19 +121,20 @@ int afs_write_begin(struct file *file, struct address_space *mapping,
    wait_on_page_fscache(page);
    #endif

    + index = page->index;
    + from = pos - index * PAGE_SIZE;
    + to = from + len;
    +
    try_again:
    /* See if this page is already partially written in a way that we can
    * merge the new write with.
    */
    - t = f = 0;
    if (PagePrivate(page)) {
    priv = page_private(page);
    f = afs_page_dirty_from(page, priv);
    t = afs_page_dirty_to(page, priv);
    ASSERTCMP(f, <=, t);
    - }

    - if (f != t) {
    if (PageWriteback(page)) {
    trace_afs_page_dirty(vnode, tracepoint_string("alrdy"), page);
    goto flush_conflicting_write;
    @@ -180,7 +181,7 @@ int afs_write_end(struct file *file, struct address_space *mapping,
    {
    struct afs_vnode *vnode = AFS_FS_I(file_inode(file));
    unsigned long priv;
    - unsigned int f, from = pos & (PAGE_SIZE - 1);
    + unsigned int f, from = pos & (thp_size(page) - 1);
    unsigned int t, to = from + copied;
    loff_t i_size, maybe_i_size;
    int ret = 0;
    @@ -233,9 +234,8 @@ int afs_write_end(struct file *file, struct address_space *mapping,
    trace_afs_page_dirty(vnode, tracepoint_string("dirty"), page);
    }

    - set_page_dirty(page);
    - if (PageDirty(page))
    - _debug("dirtied");
    + if (set_page_dirty(page))
    + _debug("dirtied %lx", page->index);
    ret = copied;

    out:
    @@ -248,40 +248,43 @@ int afs_write_end(struct file *file, struct address_space *mapping,
    * kill all the pages in the given range
    */
    static void afs_kill_pages(struct address_space *mapping,
    - pgoff_t first, pgoff_t last)
    + loff_t start, loff_t len)
    {
    struct afs_vnode *vnode = AFS_FS_I(mapping->host);
    struct pagevec pv;
    - unsigned count, loop;
    + unsigned int loop, psize;

    - _enter("{%llx:%llu},%lx-%lx",
    - vnode->fid.vid, vnode->fid.vnode, first, last);
    + _enter("{%llx:%llu},%llx @%llx",
    + vnode->fid.vid, vnode->fid.vnode, len, start);

    pagevec_init(&pv);

    do {
    - _debug("kill %lx-%lx", first, last);
    + _debug("kill %llx @%llx", len, start);

    - count = last - first + 1;
    - if (count > PAGEVEC_SIZE)
    - count = PAGEVEC_SIZE;
    - pv.nr = find_get_pages_contig(mapping, first, count, pv.pages);
    - ASSERTCMP(pv.nr, ==, count);
    + pv.nr = find_get_pages_contig(mapping, start / PAGE_SIZE,
    + PAGEVEC_SIZE, pv.pages);
    + if (pv.nr == 0)
    + break;

    - for (loop = 0; loop < count; loop++) {
    + for (loop = 0; loop < pv.nr; loop++) {
    struct page *page = pv.pages[loop];
    +
    + if (page->index * PAGE_SIZE >= start + len)
    + break;
    +
    + psize = thp_size(page);
    + start += psize;
    + len -= psize;
    ClearPageUptodate(page);
    - SetPageError(page);
    end_page_writeback(page);
    - if (page->index >= first)
    - first = page->index + 1;
    lock_page(page);
    generic_error_remove_page(mapping, page);
    unlock_page(page);
    }

    __pagevec_release(&pv);
    - } while (first <= last);
    + } while (len > 0);

    _leave("");
    }
    @@ -291,37 +294,40 @@ static void afs_kill_pages(struct address_space *mapping,
    */
    static void afs_redirty_pages(struct writeback_control *wbc,
    struct address_space *mapping,
    - pgoff_t first, pgoff_t last)
    + loff_t start, loff_t len)
    {
    struct afs_vnode *vnode = AFS_FS_I(mapping->host);
    struct pagevec pv;
    - unsigned count, loop;
    + unsigned int loop, psize;

    - _enter("{%llx:%llu},%lx-%lx",
    - vnode->fid.vid, vnode->fid.vnode, first, last);
    + _enter("{%llx:%llu},%llx @%llx",
    + vnode->fid.vid, vnode->fid.vnode, len, start);

    pagevec_init(&pv);

    do {
    - _debug("redirty %lx-%lx", first, last);
    + _debug("redirty %llx @%llx", len, start);

    - count = last - first + 1;
    - if (count > PAGEVEC_SIZE)
    - count = PAGEVEC_SIZE;
    - pv.nr = find_get_pages_contig(mapping, first, count, pv.pages);
    - ASSERTCMP(pv.nr, ==, count);
    + pv.nr = find_get_pages_contig(mapping, start / PAGE_SIZE,
    + PAGEVEC_SIZE, pv.pages);
    + if (pv.nr == 0)
    + break;

    - for (loop = 0; loop < count; loop++) {
    + for (loop = 0; loop < pv.nr; loop++) {
    struct page *page = pv.pages[loop];

    + if (page->index * PAGE_SIZE >= start + len)
    + break;
    +
    + psize = thp_size(page);
    + start += psize;
    + len -= psize;
    redirty_page_for_writepage(wbc, page);
    end_page_writeback(page);
    - if (page->index >= first)
    - first = page->index + 1;
    }

    __pagevec_release(&pv);
    - } while (first <= last);
    + } while (len > 0);

    _leave("");
    }
    @@ -329,23 +335,28 @@ static void afs_redirty_pages(struct writeback_control *wbc,
    /*
    * completion of write to server
    */
    -static void afs_pages_written_back(struct afs_vnode *vnode, pgoff_t start, pgoff_t last)
    +static void afs_pages_written_back(struct afs_vnode *vnode, loff_t start, unsigned int len)
    {
    struct address_space *mapping = vnode->vfs_inode.i_mapping;
    struct page *page;
    + pgoff_t end;

    - XA_STATE(xas, &mapping->i_pages, start);
    + XA_STATE(xas, &mapping->i_pages, start / PAGE_SIZE);

    - _enter("{%llx:%llu},{%lx-%lx}",
    - vnode->fid.vid, vnode->fid.vnode, start, last);
    + _enter("{%llx:%llu},{%x @%llx}",
    + vnode->fid.vid, vnode->fid.vnode, len, start);

    rcu_read_lock();

    - xas_for_each(&xas, page, last) {
    - ASSERT(PageWriteback(page));
    + end = (start + len - 1) / PAGE_SIZE;
    + xas_for_each(&xas, page, end) {
    + if (!PageWriteback(page)) {
    + kdebug("bad %x @%llx page %lx %lx", len, start, page->index, end);
    + ASSERT(PageWriteback(page));
    + }

    - detach_page_private(page);
    trace_afs_page_dirty(vnode, tracepoint_string("clear"), page);
    + detach_page_private(page);
    page_endio(page, true, 0);
    }

    @@ -404,7 +415,7 @@ static void afs_store_data_success(struct afs_operation *op)
    afs_vnode_commit_status(op, &op->file[0]);
    if (op->error == 0) {
    if (!op->store.laundering)
    - afs_pages_written_back(vnode, op->store.first, op->store.last);
    + afs_pages_written_back(vnode, op->store.pos, op->store.size);
    afs_stat_v(vnode, n_stores);
    atomic_long_add(op->store.size, &afs_v2net(vnode)->n_store_bytes);
    }
    @@ -419,8 +430,7 @@ static const struct afs_operation_ops afs_store_data_operation = {
    /*
    * write to a file
    */
    -static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter,
    - loff_t pos, pgoff_t first, pgoff_t last,
    +static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter, loff_t pos,
    bool laundering)
    {
    struct afs_operation *op;
    @@ -453,8 +463,6 @@ static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter,
    op->file[0].dv_delta = 1;
    op->store.write_iter = iter;
    op->store.pos = pos;
    - op->store.first = first;
    - op->store.last = last;
    op->store.size = size;
    op->store.i_size = max(pos + size, i_size);
    op->store.laundering = laundering;
    @@ -499,40 +507,49 @@ static int afs_store_data(struct afs_vnode *vnode, struct iov_iter *iter,
    static void afs_extend_writeback(struct address_space *mapping,
    struct afs_vnode *vnode,
    long *_count,
    - pgoff_t start,
    - pgoff_t final_page,
    - unsigned *_offset,
    - unsigned *_to,
    - bool new_content)
    + loff_t start,
    + loff_t max_len,
    + bool new_content,
    + unsigned int *_len)
    {
    - struct page *pages[8], *page;
    - unsigned long count = *_count, priv;
    - unsigned offset = *_offset, to = *_to, n, f, t;
    - int loop;
    + struct pagevec pvec;
    + struct page *page;
    + unsigned long priv;
    + unsigned int psize, filler = 0;
    + unsigned int f, t;
    + loff_t len = *_len;
    + pgoff_t index = (start + len) / PAGE_SIZE;
    + bool stop = true;
    + unsigned int i;
    +
    + XA_STATE(xas, &mapping->i_pages, index);
    + pagevec_init(&pvec);

    - start++;
    do {
    - _debug("more %lx [%lx]", start, count);
    - n = final_page - start + 1;
    - if (n > ARRAY_SIZE(pages))
    - n = ARRAY_SIZE(pages);
    - n = find_get_pages_contig(mapping, start, ARRAY_SIZE(pages), pages);
    - _debug("fgpc %u", n);
    - if (n == 0)
    - goto no_more;
    - if (pages[0]->index != start) {
    - do {
    - put_page(pages[--n]);
    - } while (n > 0);
    - goto no_more;
    - }
    + /* Firstly, we gather up a batch of contiguous dirty pages
    + * under the RCU read lock - but we can't clear the dirty flags
    + * there if any of those pages are mapped.
    + */
    + rcu_read_lock();

    - for (loop = 0; loop < n; loop++) {
    - page = pages[loop];
    - if (to != PAGE_SIZE && !new_content)
    + xas_for_each(&xas, page, ULONG_MAX) {
    + stop = true;
    + if (xas_retry(&xas, page))
    + continue;
    + if (xa_is_value(page))
    + break;
    + if (page->index != index)
    break;
    - if (page->index > final_page)
    +
    + if (!page_cache_get_speculative(page)) {
    + xas_reset(&xas);
    + continue;
    + }
    +
    + /* Has the page moved or been split? */
    + if (unlikely(page != xas_reload(&xas)))
    break;
    +
    if (!trylock_page(page))
    break;
    if (!PageDirty(page) || PageWriteback(page)) {
    @@ -540,6 +557,7 @@ static void afs_extend_writeback(struct address_space *mapping,
    break;
    }

    + psize = thp_size(page);
    priv = page_private(page);
    f = afs_page_dirty_from(page, priv);
    t = afs_page_dirty_to(page, priv);
    @@ -547,110 +565,126 @@ static void afs_extend_writeback(struct address_space *mapping,
    unlock_page(page);
    break;
    }
    - to = t;

    + len += filler + t;
    + filler = psize - t;
    + if (len >= max_len || *_count <= 0)
    + stop = true;
    + else if (t == psize || new_content)
    + stop = false;
    +
    + index += thp_nr_pages(page);
    + if (!pagevec_add(&pvec, page))
    + break;
    + if (stop)
    + break;
    + }
    +
    + if (!stop)
    + xas_pause(&xas);
    + rcu_read_unlock();
    +
    + /* Now, if we obtained any pages, we can shift them to being
    + * writable and mark them for caching.
    + */
    + if (!pagevec_count(&pvec))
    + break;
    +
    + for (i = 0; i < pagevec_count(&pvec); i++) {
    + page = pvec.pages[i];
    trace_afs_page_dirty(vnode, tracepoint_string("store+"), page);

    if (!clear_page_dirty_for_io(page))
    BUG();
    if (test_set_page_writeback(page))
    BUG();
    +
    + *_count -= thp_nr_pages(page);
    unlock_page(page);
    - put_page(page);
    - }
    - count += loop;
    - if (loop < n) {
    - for (; loop < n; loop++)
    - put_page(pages[loop]);
    - goto no_more;
    }

    - start += loop;
    - } while (start <= final_page && count < 65536);
    + pagevec_release(&pvec);
    + cond_resched();
    + } while (!stop);

    -no_more:
    - *_count = count;
    - *_offset = offset;
    - *_to = to;
    + *_len = len;
    }

    /*
    * Synchronously write back the locked page and any subsequent non-locked dirty
    * pages.
    */
    -static int afs_write_back_from_locked_page(struct address_space *mapping,
    - struct writeback_control *wbc,
    - struct page *primary_page,
    - pgoff_t final_page)
    +static ssize_t afs_write_back_from_locked_page(struct address_space *mapping,
    + struct writeback_control *wbc,
    + struct page *page,
    + loff_t start, loff_t end)
    {
    struct afs_vnode *vnode = AFS_FS_I(mapping->host);
    struct iov_iter iter;
    - unsigned long count, priv;
    - unsigned offset, to;
    - pgoff_t start, first, last;
    - loff_t i_size, pos, end;
    + unsigned long priv;
    + unsigned int offset, to, len, max_len;
    + loff_t i_size = i_size_read(&vnode->vfs_inode);
    bool new_content = test_bit(AFS_VNODE_NEW_CONTENT, &vnode->flags);
    + long count = wbc->nr_to_write;
    int ret;

    - _enter(",%lx", primary_page->index);
    + _enter(",%lx,%llx-%llx", page->index, start, end);

    - count = 1;
    - if (test_set_page_writeback(primary_page))
    + if (test_set_page_writeback(page))
    BUG();

    + count -= thp_nr_pages(page);
    +
    /* Find all consecutive lockable dirty pages that have contiguous
    * written regions, stopping when we find a page that is not
    * immediately lockable, is not dirty or is missing, or we reach the
    * end of the range.
    */
    - start = primary_page->index;
    - priv = page_private(primary_page);
    - offset = afs_page_dirty_from(primary_page, priv);
    - to = afs_page_dirty_to(primary_page, priv);
    - trace_afs_page_dirty(vnode, tracepoint_string("store"), primary_page);
    -
    - WARN_ON(offset == to);
    - if (offset == to)
    - trace_afs_page_dirty(vnode, tracepoint_string("WARN"), primary_page);
    -
    - if (start < final_page &&
    - (to == PAGE_SIZE || new_content))
    - afs_extend_writeback(mapping, vnode, &count, start, final_page,
    - &offset, &to, new_content);
    + priv = page_private(page);
    + offset = afs_page_dirty_from(page, priv);
    + to = afs_page_dirty_to(page, priv);
    + trace_afs_page_dirty(vnode, tracepoint_string("store"), page);
    +
    + len = to - offset;
    + start += offset;
    + if (start < i_size) {
    + /* Trim the write to the EOF; the extra data is ignored. Also
    + * put an upper limit on the size of a single storedata op.
    + */
    + max_len = 65536 * 4096;
    + max_len = min_t(unsigned long long, max_len, end - start + 1);
    + max_len = min_t(unsigned long long, max_len, i_size - start);
    +
    + if (len < max_len &&
    + (to == thp_size(page) || new_content))
    + afs_extend_writeback(mapping, vnode, &count,
    + start, max_len, new_content, &len);
    + len = min_t(loff_t, len, max_len);
    + }

    /* We now have a contiguous set of dirty pages, each with writeback
    * set; the first page is still locked at this point, but all the rest
    * have been unlocked.
    */
    - unlock_page(primary_page);
    -
    - first = primary_page->index;
    - last = first + count - 1;
    - _debug("write back %lx[%u..] to %lx[..%u]", first, offset, last, to);
    -
    - pos = first;
    - pos <<= PAGE_SHIFT;
    - pos += offset;
    - end = last;
    - end <<= PAGE_SHIFT;
    - end += to;
    + unlock_page(page);

    - /* Trim the actual write down to the EOF */
    - i_size = i_size_read(&vnode->vfs_inode);
    - if (end > i_size)
    - end = i_size;
    + if (start < i_size) {
    + _debug("write back %x @%llx [%llx]", len, start, i_size);

    - if (pos < i_size) {
    - iov_iter_xarray(&iter, WRITE, &mapping->i_pages, pos, end - pos);
    - ret = afs_store_data(vnode, &iter, pos, first, last, false);
    + iov_iter_xarray(&iter, WRITE, &mapping->i_pages, start, len);
    + ret = afs_store_data(vnode, &iter, start, false);
    } else {
    + _debug("write discard %x @%llx [%llx]", len, start, i_size);
    +
    /* The dirty region was entirely beyond the EOF. */
    + afs_pages_written_back(vnode, start, len);
    ret = 0;
    }

    switch (ret) {
    case 0:
    - ret = count;
    + wbc->nr_to_write = count;
    + ret = len;
    break;

    default:
    @@ -662,13 +696,13 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
    case -EKEYEXPIRED:
    case -EKEYREJECTED:
    case -EKEYREVOKED:
    - afs_redirty_pages(wbc, mapping, first, last);
    + afs_redirty_pages(wbc, mapping, start, len);
    mapping_set_error(mapping, ret);
    break;

    case -EDQUOT:
    case -ENOSPC:
    - afs_redirty_pages(wbc, mapping, first, last);
    + afs_redirty_pages(wbc, mapping, start, len);
    mapping_set_error(mapping, -ENOSPC);
    break;

    @@ -680,7 +714,7 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
    case -ENOMEDIUM:
    case -ENXIO:
    trace_afs_file_error(vnode, ret, afs_file_error_writeback_fail);
    - afs_kill_pages(mapping, first, last);
    + afs_kill_pages(mapping, start, len);
    mapping_set_error(mapping, ret);
    break;
    }
    @@ -695,19 +729,19 @@ static int afs_write_back_from_locked_page(struct address_space *mapping,
    */
    int afs_writepage(struct page *page, struct writeback_control *wbc)
    {
    - int ret;
    + ssize_t ret;
    + loff_t start;

    _enter("{%lx},", page->index);

    + start = page->index * PAGE_SIZE;
    ret = afs_write_back_from_locked_page(page->mapping, wbc, page,
    - wbc->range_end >> PAGE_SHIFT);
    + start, LLONG_MAX - start);
    if (ret < 0) {
    - _leave(" = %d", ret);
    - return 0;
    + _leave(" = %zd", ret);
    + return ret;
    }

    - wbc->nr_to_write -= ret;
    -
    _leave(" = 0");
    return 0;
    }
    @@ -717,35 +751,46 @@ int afs_writepage(struct page *page, struct writeback_control *wbc)
    */
    static int afs_writepages_region(struct address_space *mapping,
    struct writeback_control *wbc,
    - pgoff_t index, pgoff_t end, pgoff_t *_next)
    + loff_t start, loff_t end, loff_t *_next)
    {
    struct page *page;
    - int ret, n;
    + ssize_t ret;
    + int n;

    - _enter(",,%lx,%lx,", index, end);
    + _enter("%llx,%llx,", start, end);

    do {
    - n = find_get_pages_range_tag(mapping, &index, end,
    - PAGECACHE_TAG_DIRTY, 1, &page);
    + pgoff_t index = start / PAGE_SIZE;
    +
    + n = find_get_pages_range_tag(mapping, &index, end / PAGE_SIZE,
    + PAGECACHE_TAG_DIRTY, 1, &page);
    if (!n)
    break;

    + start = (loff_t)page->index * PAGE_SIZE; /* May regress with THPs */
    +
    _debug("wback %lx", page->index);

    - /*
    - * at this point we hold neither the i_pages lock nor the
    + /* At this point we hold neither the i_pages lock nor the
    * page lock: the page may be truncated or invalidated
    * (changing page->mapping to NULL), or even swizzled
    * back from swapper_space to tmpfs file mapping
    */
    - ret = lock_page_killable(page);
    - if (ret < 0) {
    - put_page(page);
    - _leave(" = %d", ret);
    - return ret;
    + if (wbc->sync_mode != WB_SYNC_NONE) {
    + ret = lock_page_killable(page);
    + if (ret < 0) {
    + put_page(page);
    + return ret;
    + }
    + } else {
    + if (!trylock_page(page)) {
    + put_page(page);
    + return 0;
    + }
    }

    if (page->mapping != mapping || !PageDirty(page)) {
    + start += thp_size(page);
    unlock_page(page);
    put_page(page);
    continue;
    @@ -761,20 +806,20 @@ static int afs_writepages_region(struct address_space *mapping,

    if (!clear_page_dirty_for_io(page))
    BUG();
    - ret = afs_write_back_from_locked_page(mapping, wbc, page, end);
    + ret = afs_write_back_from_locked_page(mapping, wbc, page, start, end);
    put_page(page);
    if (ret < 0) {
    - _leave(" = %d", ret);
    + _leave(" = %zd", ret);
    return ret;
    }

    - wbc->nr_to_write -= ret;
    + start += ret * PAGE_SIZE;

    cond_resched();
    - } while (index < end && wbc->nr_to_write > 0);
    + } while (wbc->nr_to_write > 0);

    - *_next = index;
    - _leave(" = 0 [%lx]", *_next);
    + *_next = start;
    + _leave(" = 0 [%llx]", *_next);
    return 0;
    }

    @@ -785,7 +830,7 @@ int afs_writepages(struct address_space *mapping,
    struct writeback_control *wbc)
    {
    struct afs_vnode *vnode = AFS_FS_I(mapping->host);
    - pgoff_t start, end, next;
    + loff_t start, next;
    int ret;

    _enter("");
    @@ -800,22 +845,19 @@ int afs_writepages(struct address_space *mapping,
    return 0;

    if (wbc->range_cyclic) {
    - start = mapping->writeback_index;
    - end = -1;
    - ret = afs_writepages_region(mapping, wbc, start, end, &next);
    + start = mapping->writeback_index * PAGE_SIZE;
    + ret = afs_writepages_region(mapping, wbc, start, LLONG_MAX, &next);
    if (start > 0 && wbc->nr_to_write > 0 && ret == 0)
    ret = afs_writepages_region(mapping, wbc, 0, start,
    &next);
    - mapping->writeback_index = next;
    + mapping->writeback_index = next / PAGE_SIZE;
    } else if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX) {
    - end = (pgoff_t)(LLONG_MAX >> PAGE_SHIFT);
    - ret = afs_writepages_region(mapping, wbc, 0, end, &next);
    + ret = afs_writepages_region(mapping, wbc, 0, LLONG_MAX, &next);
    if (wbc->nr_to_write > 0)
    mapping->writeback_index = next;
    } else {
    - start = wbc->range_start >> PAGE_SHIFT;
    - end = wbc->range_end >> PAGE_SHIFT;
    - ret = afs_writepages_region(mapping, wbc, start, end, &next);
    + ret = afs_writepages_region(mapping, wbc,
    + wbc->range_start, wbc->range_end, &next);
    }

    up_read(&vnode->validate_lock);
    @@ -873,13 +915,13 @@ int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
    */
    vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
    {
    + struct page *page = thp_head(vmf->page);
    struct file *file = vmf->vma->vm_file;
    struct inode *inode = file_inode(file);
    struct afs_vnode *vnode = AFS_FS_I(inode);
    unsigned long priv;

    - _enter("{{%llx:%llu}},{%lx}",
    - vnode->fid.vid, vnode->fid.vnode, vmf->page->index);
    + _enter("{{%llx:%llu}},{%lx}", vnode->fid.vid, vnode->fid.vnode, page->index);

    sb_start_pagefault(inode->i_sb);

    @@ -887,31 +929,33 @@ vm_fault_t afs_page_mkwrite(struct vm_fault *vmf)
    * be modified. We then assume the entire page will need writing back.
    */
    #ifdef CONFIG_AFS_FSCACHE
    - if (PageFsCache(vmf->page) &&
    - wait_on_page_bit_killable(vmf->page, PG_fscache) < 0)
    + if (PageFsCache(page) &&
    + wait_on_page_bit_killable(page, PG_fscache) < 0)
    return VM_FAULT_RETRY;
    #endif

    - if (PageWriteback(vmf->page) &&
    - wait_on_page_bit_killable(vmf->page, PG_writeback) < 0)
    + if (PageWriteback(page) &&
    + wait_on_page_bit_killable(page, PG_writeback) < 0)
    return VM_FAULT_RETRY;

    - if (lock_page_killable(vmf->page) < 0)
    + if (lock_page_killable(page) < 0)
    return VM_FAULT_RETRY;

    /* We mustn't change page->private until writeback is complete as that
    * details the portion of the page we need to write back and we might
    * need to redirty the page if there's a problem.
    */
    - wait_on_page_writeback(vmf->page);
    + wait_on_page_writeback(page);

    - priv = afs_page_dirty(vmf->page, 0, PAGE_SIZE);
    + priv = afs_page_dirty(page, 0, thp_size(page));
    priv = afs_page_dirty_mmapped(priv);
    - if (PagePrivate(vmf->page))
    - set_page_private(vmf->page, priv);
    - else
    - attach_page_private(vmf->page, (void *)priv);
    - trace_afs_page_dirty(vnode, tracepoint_string("mkwrite"), vmf->page);
    + if (PagePrivate(page)) {
    + set_page_private(page, priv);
    + trace_afs_page_dirty(vnode, tracepoint_string("mkwrite+"), page);
    + } else {
    + attach_page_private(page, (void *)priv);
    + trace_afs_page_dirty(vnode, tracepoint_string("mkwrite"), page);
    + }
    file_update_time(file);

    sb_end_pagefault(inode->i_sb);
    @@ -964,7 +1008,7 @@ int afs_launder_page(struct page *page)
    priv = page_private(page);
    if (clear_page_dirty_for_io(page)) {
    f = 0;
    - t = PAGE_SIZE;
    + t = thp_size(page);
    if (PagePrivate(page)) {
    f = afs_page_dirty_from(page, priv);
    t = afs_page_dirty_to(page, priv);
    @@ -976,12 +1020,12 @@ int afs_launder_page(struct page *page)
    iov_iter_bvec(&iter, WRITE, bv, 1, bv[0].bv_len);

    trace_afs_page_dirty(vnode, tracepoint_string("launder"), page);
    - ret = afs_store_data(vnode, &iter, (loff_t)page->index << PAGE_SHIFT,
    - page->index, page->index, true);
    + ret = afs_store_data(vnode, &iter, (loff_t)page->index * PAGE_SIZE,
    + true);
    }

    - detach_page_private(page);
    trace_afs_page_dirty(vnode, tracepoint_string("laundered"), page);
    + detach_page_private(page);
    wait_on_page_fscache(page);
    return ret;
    }

    \
     
     \ /
      Last update: 2020-11-20 16:20    [W:2.325 / U:0.060 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site