lkml.org 
[lkml]   [2020]   [Jun]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH] fuse_writepages_fill() optimization to avoid WARN_ON in tree_insert
    Date
    In current implementation fuse_writepages_fill() tries to share the code:
    for new wpa it calls tree_insert() with num_pages = 0
    then switches to common code used non-modified num_pages
    and increments it at the very end.

    Though it triggers WARN_ON(!wpa->ia.ap.num_pages) in tree_insert()
    WARNING: CPU: 1 PID: 17211 at fs/fuse/file.c:1728 tree_insert+0xab/0xc0 [fuse]
    RIP: 0010:tree_insert+0xab/0xc0 [fuse]
    Call Trace:
    fuse_writepages_fill+0x5da/0x6a0 [fuse]
    write_cache_pages+0x171/0x470
    fuse_writepages+0x8a/0x100 [fuse]
    do_writepages+0x43/0xe0

    This patch re-works fuse_writepages_fill() to call tree_insert()
    with num_pages = 1 and avoids its subsequent increment and
    an extra spin_lock(&fi->lock) for newly added wpa.

    Fixes: 6b2fb79963fb ("fuse: optimize writepages search")
    Reported-by: kernel test robot <rong.a.chen@intel.com>
    Signed-off-by: Vasily Averin <vvs@virtuozzo.com>
    ---
    fs/fuse/file.c | 56 +++++++++++++++++++++++++++++---------------------------
    1 file changed, 29 insertions(+), 27 deletions(-)

    diff --git a/fs/fuse/file.c b/fs/fuse/file.c
    index e573b0c..cf267bd 100644
    --- a/fs/fuse/file.c
    +++ b/fs/fuse/file.c
    @@ -1966,10 +1966,9 @@ static bool fuse_writepage_in_flight(struct fuse_writepage_args *new_wpa,
    struct fuse_writepage_args *old_wpa;
    struct fuse_args_pages *new_ap = &new_wpa->ia.ap;

    - WARN_ON(new_ap->num_pages != 0);
    + WARN_ON(new_ap->num_pages != 1);

    spin_lock(&fi->lock);
    - rb_erase(&new_wpa->writepages_entry, &fi->writepages);
    old_wpa = fuse_find_writeback(fi, page->index, page->index);
    if (!old_wpa) {
    tree_insert(&fi->writepages, new_wpa);
    @@ -1977,7 +1976,6 @@ static bool fuse_writepage_in_flight(struct fuse_writepage_args *new_wpa,
    return false;
    }

    - new_ap->num_pages = 1;
    for (tmp = old_wpa->next; tmp; tmp = tmp->next) {
    pgoff_t curr_index;

    @@ -2020,7 +2018,7 @@ static int fuse_writepages_fill(struct page *page,
    struct fuse_conn *fc = get_fuse_conn(inode);
    struct page *tmp_page;
    bool is_writeback;
    - int err;
    + int index, err;

    if (!data->ff) {
    err = -EIO;
    @@ -2083,44 +2081,48 @@ static int fuse_writepages_fill(struct page *page,
    wpa->next = NULL;
    ap->args.in_pages = true;
    ap->args.end = fuse_writepage_end;
    - ap->num_pages = 0;
    + ap->num_pages = 1;
    wpa->inode = inode;
    -
    - spin_lock(&fi->lock);
    - tree_insert(&fi->writepages, wpa);
    - spin_unlock(&fi->lock);
    -
    + index = 0;
    data->wpa = wpa;
    + } else {
    + index = ap->num_pages;
    }
    set_page_writeback(page);

    copy_highpage(tmp_page, page);
    - ap->pages[ap->num_pages] = tmp_page;
    - ap->descs[ap->num_pages].offset = 0;
    - ap->descs[ap->num_pages].length = PAGE_SIZE;
    + ap->pages[index] = tmp_page;
    + ap->descs[index].offset = 0;
    + ap->descs[index].length = PAGE_SIZE;

    inc_wb_stat(&inode_to_bdi(inode)->wb, WB_WRITEBACK);
    inc_node_page_state(tmp_page, NR_WRITEBACK_TEMP);

    err = 0;
    - if (is_writeback && fuse_writepage_in_flight(wpa, page)) {
    - end_page_writeback(page);
    - data->wpa = NULL;
    - goto out_unlock;
    + if (is_writeback) {
    + if (fuse_writepage_in_flight(wpa, page)) {
    + end_page_writeback(page);
    + data->wpa = NULL;
    + goto out_unlock;
    + }
    + } else if (!index) {
    + spin_lock(&fi->lock);
    + tree_insert(&fi->writepages, wpa);
    + spin_unlock(&fi->lock);
    }
    - data->orig_pages[ap->num_pages] = page;
    -
    - /*
    - * Protected by fi->lock against concurrent access by
    - * fuse_page_is_writeback().
    - */
    - spin_lock(&fi->lock);
    - ap->num_pages++;
    - spin_unlock(&fi->lock);
    + data->orig_pages[index] = page;

    + if (index) {
    + /*
    + * Protected by fi->lock against concurrent access by
    + * fuse_page_is_writeback().
    + */
    + spin_lock(&fi->lock);
    + ap->num_pages++;
    + spin_unlock(&fi->lock);
    + }
    out_unlock:
    unlock_page(page);
    -
    return err;
    }

    --
    1.8.3.1
    \
     
     \ /
      Last update: 2020-06-25 11:03    [W:2.900 / U:0.016 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site