lkml.org 
[lkml]   [2022]   [Oct]   [24]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.14 067/210] nilfs2: fix lockdep warnings during disk space reclamation
    Date
    From: Ryusuke Konishi <konishi.ryusuke@gmail.com>

    commit 6e211930f79aa45d422009a5f2e5467d2369ffe5 upstream.

    During disk space reclamation, nilfs2 still emits the following lockdep
    warning due to page/folio operations on shadowed page caches that nilfs2
    uses to get a snapshot of DAT file in memory:

    WARNING: CPU: 0 PID: 2643 at include/linux/backing-dev.h:272 __folio_mark_dirty+0x645/0x670
    ...
    RIP: 0010:__folio_mark_dirty+0x645/0x670
    ...
    Call Trace:
    filemap_dirty_folio+0x74/0xd0
    __set_page_dirty_nobuffers+0x85/0xb0
    nilfs_copy_dirty_pages+0x288/0x510 [nilfs2]
    nilfs_mdt_save_to_shadow_map+0x50/0xe0 [nilfs2]
    nilfs_clean_segments+0xee/0x5d0 [nilfs2]
    nilfs_ioctl_clean_segments.isra.19+0xb08/0xf40 [nilfs2]
    nilfs_ioctl+0xc52/0xfb0 [nilfs2]
    __x64_sys_ioctl+0x11d/0x170

    This fixes the remaining warning by using inode objects to hold those
    page caches.

    Link: https://lkml.kernel.org/r/1647867427-30498-3-git-send-email-konishi.ryusuke@gmail.com
    Signed-off-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
    Tested-by: Ryusuke Konishi <konishi.ryusuke@gmail.com>
    Cc: Matthew Wilcox <willy@infradead.org>
    Cc: David Hildenbrand <david@redhat.com>
    Cc: Hao Sun <sunhao.th@gmail.com>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
    ---
    fs/nilfs2/dat.c | 4 ++-
    fs/nilfs2/inode.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++----
    fs/nilfs2/mdt.c | 38 ++++++++++++++++++++++----------
    fs/nilfs2/mdt.h | 6 +----
    fs/nilfs2/nilfs.h | 2 +
    5 files changed, 92 insertions(+), 21 deletions(-)

    --- a/fs/nilfs2/dat.c
    +++ b/fs/nilfs2/dat.c
    @@ -506,7 +506,9 @@ int nilfs_dat_read(struct super_block *s
    di = NILFS_DAT_I(dat);
    lockdep_set_class(&di->mi.mi_sem, &dat_lock_key);
    nilfs_palloc_setup_cache(dat, &di->palloc_cache);
    - nilfs_mdt_setup_shadow_map(dat, &di->shadow);
    + err = nilfs_mdt_setup_shadow_map(dat, &di->shadow);
    + if (err)
    + goto failed;

    err = nilfs_read_inode_common(dat, raw_inode);
    if (err)
    --- a/fs/nilfs2/inode.c
    +++ b/fs/nilfs2/inode.c
    @@ -38,6 +38,7 @@
    * @root: pointer on NILFS root object (mounted checkpoint)
    * @for_gc: inode for GC flag
    * @for_btnc: inode for B-tree node cache flag
    + * @for_shadow: inode for shadowed page cache flag
    */
    struct nilfs_iget_args {
    u64 ino;
    @@ -45,6 +46,7 @@ struct nilfs_iget_args {
    struct nilfs_root *root;
    bool for_gc;
    bool for_btnc;
    + bool for_shadow;
    };

    static int nilfs_iget_test(struct inode *inode, void *opaque);
    @@ -334,7 +336,7 @@ static int nilfs_insert_inode_locked(str
    {
    struct nilfs_iget_args args = {
    .ino = ino, .root = root, .cno = 0, .for_gc = false,
    - .for_btnc = false
    + .for_btnc = false, .for_shadow = false
    };

    return insert_inode_locked4(inode, ino, nilfs_iget_test, &args);
    @@ -570,6 +572,12 @@ static int nilfs_iget_test(struct inode
    } else if (args->for_btnc) {
    return 0;
    }
    + if (test_bit(NILFS_I_SHADOW, &ii->i_state)) {
    + if (!args->for_shadow)
    + return 0;
    + } else if (args->for_shadow) {
    + return 0;
    + }

    if (!test_bit(NILFS_I_GCINODE, &ii->i_state))
    return !args->for_gc;
    @@ -591,6 +599,8 @@ static int nilfs_iget_set(struct inode *
    NILFS_I(inode)->i_state = BIT(NILFS_I_GCINODE);
    if (args->for_btnc)
    NILFS_I(inode)->i_state |= BIT(NILFS_I_BTNC);
    + if (args->for_shadow)
    + NILFS_I(inode)->i_state |= BIT(NILFS_I_SHADOW);
    return 0;
    }

    @@ -599,7 +609,7 @@ struct inode *nilfs_ilookup(struct super
    {
    struct nilfs_iget_args args = {
    .ino = ino, .root = root, .cno = 0, .for_gc = false,
    - .for_btnc = false
    + .for_btnc = false, .for_shadow = false
    };

    return ilookup5(sb, ino, nilfs_iget_test, &args);
    @@ -610,7 +620,7 @@ struct inode *nilfs_iget_locked(struct s
    {
    struct nilfs_iget_args args = {
    .ino = ino, .root = root, .cno = 0, .for_gc = false,
    - .for_btnc = false
    + .for_btnc = false, .for_shadow = false
    };

    return iget5_locked(sb, ino, nilfs_iget_test, nilfs_iget_set, &args);
    @@ -642,7 +652,7 @@ struct inode *nilfs_iget_for_gc(struct s
    {
    struct nilfs_iget_args args = {
    .ino = ino, .root = NULL, .cno = cno, .for_gc = true,
    - .for_btnc = false
    + .for_btnc = false, .for_shadow = false
    };
    struct inode *inode;
    int err;
    @@ -689,6 +699,7 @@ int nilfs_attach_btree_node_cache(struct
    args.cno = ii->i_cno;
    args.for_gc = test_bit(NILFS_I_GCINODE, &ii->i_state) != 0;
    args.for_btnc = true;
    + args.for_shadow = test_bit(NILFS_I_SHADOW, &ii->i_state) != 0;

    btnc_inode = iget5_locked(inode->i_sb, inode->i_ino, nilfs_iget_test,
    nilfs_iget_set, &args);
    @@ -724,6 +735,50 @@ void nilfs_detach_btree_node_cache(struc
    }
    }

    +/**
    + * nilfs_iget_for_shadow - obtain inode for shadow mapping
    + * @inode: inode object that uses shadow mapping
    + *
    + * nilfs_iget_for_shadow() allocates a pair of inodes that holds page
    + * caches for shadow mapping. The page cache for data pages is set up
    + * in one inode and the one for b-tree node pages is set up in the
    + * other inode, which is attached to the former inode.
    + *
    + * Return Value: On success, a pointer to the inode for data pages is
    + * returned. On errors, one of the following negative error code is returned
    + * in a pointer type.
    + *
    + * %-ENOMEM - Insufficient memory available.
    + */
    +struct inode *nilfs_iget_for_shadow(struct inode *inode)
    +{
    + struct nilfs_iget_args args = {
    + .ino = inode->i_ino, .root = NULL, .cno = 0, .for_gc = false,
    + .for_btnc = false, .for_shadow = true
    + };
    + struct inode *s_inode;
    + int err;
    +
    + s_inode = iget5_locked(inode->i_sb, inode->i_ino, nilfs_iget_test,
    + nilfs_iget_set, &args);
    + if (unlikely(!s_inode))
    + return ERR_PTR(-ENOMEM);
    + if (!(s_inode->i_state & I_NEW))
    + return inode;
    +
    + NILFS_I(s_inode)->i_flags = 0;
    + memset(NILFS_I(s_inode)->i_bmap, 0, sizeof(struct nilfs_bmap));
    + mapping_set_gfp_mask(s_inode->i_mapping, GFP_NOFS);
    +
    + err = nilfs_attach_btree_node_cache(s_inode);
    + if (unlikely(err)) {
    + iget_failed(s_inode);
    + return ERR_PTR(err);
    + }
    + unlock_new_inode(s_inode);
    + return s_inode;
    +}
    +
    void nilfs_write_inode_common(struct inode *inode,
    struct nilfs_inode *raw_inode, int has_bmap)
    {
    --- a/fs/nilfs2/mdt.c
    +++ b/fs/nilfs2/mdt.c
    @@ -478,9 +478,18 @@ int nilfs_mdt_init(struct inode *inode,
    void nilfs_mdt_clear(struct inode *inode)
    {
    struct nilfs_mdt_info *mdi = NILFS_MDT(inode);
    + struct nilfs_shadow_map *shadow = mdi->mi_shadow;

    if (mdi->mi_palloc_cache)
    nilfs_palloc_destroy_cache(inode);
    +
    + if (shadow) {
    + struct inode *s_inode = shadow->inode;
    +
    + shadow->inode = NULL;
    + iput(s_inode);
    + mdi->mi_shadow = NULL;
    + }
    }

    /**
    @@ -514,12 +523,15 @@ int nilfs_mdt_setup_shadow_map(struct in
    struct nilfs_shadow_map *shadow)
    {
    struct nilfs_mdt_info *mi = NILFS_MDT(inode);
    + struct inode *s_inode;

    INIT_LIST_HEAD(&shadow->frozen_buffers);
    - address_space_init_once(&shadow->frozen_data);
    - nilfs_mapping_init(&shadow->frozen_data, inode);
    - address_space_init_once(&shadow->frozen_btnodes);
    - nilfs_mapping_init(&shadow->frozen_btnodes, inode);
    +
    + s_inode = nilfs_iget_for_shadow(inode);
    + if (IS_ERR(s_inode))
    + return PTR_ERR(s_inode);
    +
    + shadow->inode = s_inode;
    mi->mi_shadow = shadow;
    return 0;
    }
    @@ -533,13 +545,14 @@ int nilfs_mdt_save_to_shadow_map(struct
    struct nilfs_mdt_info *mi = NILFS_MDT(inode);
    struct nilfs_inode_info *ii = NILFS_I(inode);
    struct nilfs_shadow_map *shadow = mi->mi_shadow;
    + struct inode *s_inode = shadow->inode;
    int ret;

    - ret = nilfs_copy_dirty_pages(&shadow->frozen_data, inode->i_mapping);
    + ret = nilfs_copy_dirty_pages(s_inode->i_mapping, inode->i_mapping);
    if (ret)
    goto out;

    - ret = nilfs_copy_dirty_pages(&shadow->frozen_btnodes,
    + ret = nilfs_copy_dirty_pages(NILFS_I(s_inode)->i_assoc_inode->i_mapping,
    ii->i_assoc_inode->i_mapping);
    if (ret)
    goto out;
    @@ -556,7 +569,7 @@ int nilfs_mdt_freeze_buffer(struct inode
    struct page *page;
    int blkbits = inode->i_blkbits;

    - page = grab_cache_page(&shadow->frozen_data, bh->b_page->index);
    + page = grab_cache_page(shadow->inode->i_mapping, bh->b_page->index);
    if (!page)
    return -ENOMEM;

    @@ -588,7 +601,7 @@ nilfs_mdt_get_frozen_buffer(struct inode
    struct page *page;
    int n;

    - page = find_lock_page(&shadow->frozen_data, bh->b_page->index);
    + page = find_lock_page(shadow->inode->i_mapping, bh->b_page->index);
    if (page) {
    if (page_has_buffers(page)) {
    n = bh_offset(bh) >> inode->i_blkbits;
    @@ -629,11 +642,11 @@ void nilfs_mdt_restore_from_shadow_map(s
    nilfs_palloc_clear_cache(inode);

    nilfs_clear_dirty_pages(inode->i_mapping, true);
    - nilfs_copy_back_pages(inode->i_mapping, &shadow->frozen_data);
    + nilfs_copy_back_pages(inode->i_mapping, shadow->inode->i_mapping);

    nilfs_clear_dirty_pages(ii->i_assoc_inode->i_mapping, true);
    nilfs_copy_back_pages(ii->i_assoc_inode->i_mapping,
    - &shadow->frozen_btnodes);
    + NILFS_I(shadow->inode)->i_assoc_inode->i_mapping);

    nilfs_bmap_restore(ii->i_bmap, &shadow->bmap_store);

    @@ -648,10 +661,11 @@ void nilfs_mdt_clear_shadow_map(struct i
    {
    struct nilfs_mdt_info *mi = NILFS_MDT(inode);
    struct nilfs_shadow_map *shadow = mi->mi_shadow;
    + struct inode *shadow_btnc_inode = NILFS_I(shadow->inode)->i_assoc_inode;

    down_write(&mi->mi_sem);
    nilfs_release_frozen_buffers(shadow);
    - truncate_inode_pages(&shadow->frozen_data, 0);
    - truncate_inode_pages(&shadow->frozen_btnodes, 0);
    + truncate_inode_pages(shadow->inode->i_mapping, 0);
    + truncate_inode_pages(shadow_btnc_inode->i_mapping, 0);
    up_write(&mi->mi_sem);
    }
    --- a/fs/nilfs2/mdt.h
    +++ b/fs/nilfs2/mdt.h
    @@ -27,14 +27,12 @@
    /**
    * struct nilfs_shadow_map - shadow mapping of meta data file
    * @bmap_store: shadow copy of bmap state
    - * @frozen_data: shadowed dirty data pages
    - * @frozen_btnodes: shadowed dirty b-tree nodes' pages
    + * @inode: holder of page caches used in shadow mapping
    * @frozen_buffers: list of frozen buffers
    */
    struct nilfs_shadow_map {
    struct nilfs_bmap_store bmap_store;
    - struct address_space frozen_data;
    - struct address_space frozen_btnodes;
    + struct inode *inode;
    struct list_head frozen_buffers;
    };

    --- a/fs/nilfs2/nilfs.h
    +++ b/fs/nilfs2/nilfs.h
    @@ -101,6 +101,7 @@ enum {
    NILFS_I_BMAP, /* has bmap and btnode_cache */
    NILFS_I_GCINODE, /* inode for GC, on memory only */
    NILFS_I_BTNC, /* inode for btree node cache */
    + NILFS_I_SHADOW, /* inode for shadowed page cache */
    };

    /*
    @@ -273,6 +274,7 @@ extern struct inode *nilfs_iget_for_gc(s
    unsigned long ino, __u64 cno);
    int nilfs_attach_btree_node_cache(struct inode *inode);
    void nilfs_detach_btree_node_cache(struct inode *inode);
    +struct inode *nilfs_iget_for_shadow(struct inode *inode);
    extern void nilfs_update_inode(struct inode *, struct buffer_head *, int);
    extern void nilfs_truncate(struct inode *);
    extern void nilfs_evict_inode(struct inode *);

    \
     
     \ /
      Last update: 2022-10-24 21:46    [W:2.633 / U:0.160 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site