All of lore.kernel.org
 help / color / mirror / Atom feed
From: Dan Carpenter <dan.carpenter@oracle.com>
To: wqu@suse.com
Cc: linux-btrfs@vger.kernel.org
Subject: [bug report] btrfs: subpage: only call btrfs_alloc_subpage() when sectorsize is smaller than PAGE_SIZE
Date: Wed, 25 Aug 2021 13:21:24 +0300	[thread overview]
Message-ID: <20210825102124.GA1822@kili> (raw)

Hello Qu Wenruo,

The patch 4c1e934ee490: "btrfs: subpage: only call
btrfs_alloc_subpage() when sectorsize is smaller than PAGE_SIZE" from
Aug 17, 2021, leads to the following
Smatch static checker warning:

	fs/btrfs/subpage.c:110 btrfs_attach_subpage()
	warn: sleeping in atomic context

fs/btrfs/subpage.c
    94 int btrfs_attach_subpage(const struct btrfs_fs_info *fs_info,
    95                          struct page *page, enum btrfs_subpage_type type)
    96 {
    97         struct btrfs_subpage *subpage;
    98 
    99         /*
    100          * We have cases like a dummy extent buffer page, which is not mappped
    101          * and doesn't need to be locked.
    102          */
    103         if (page->mapping)
    104                 ASSERT(PageLocked(page));
    105 
    106         /* Either not subpage, or the page already has private attached */
    107         if (fs_info->sectorsize == PAGE_SIZE || PagePrivate(page))
    108                 return 0;
    109 
--> 110         subpage = btrfs_alloc_subpage(fs_info, type);
    111         if (IS_ERR(subpage))
    112                 return  PTR_ERR(subpage);
    113 
    114         attach_page_private(page, subpage);
    115         return 0;
    116 }

The call tree is:

alloc_extent_buffer() <- disables preempt
-> attach_extent_buffer_page()
   -> btrfs_attach_subpage()

fs/btrfs/extent_io.c
  6132          for (i = 0; i < num_pages; i++, index++) {
  6133                  struct btrfs_subpage *prealloc = NULL;
  6134  
  6135                  p = find_or_create_page(mapping, index, GFP_NOFS|__GFP_NOFAIL);
  6136                  if (!p) {
  6137                          exists = ERR_PTR(-ENOMEM);
  6138                          goto free_eb;
  6139                  }
  6140  
  6141                  /*
  6142                   * Preallocate page->private for subpage case, so that we won't
  6143                   * allocate memory with private_lock hold.  The memory will be
  6144                   * freed by attach_extent_buffer_page() or freed manually if
  6145                   * we exit earlier.
  6146                   *
  6147                   * Although we have ensured one subpage eb can only have one
  6148                   * page, but it may change in the future for 16K page size
  6149                   * support, so we still preallocate the memory in the loop.
  6150                   */
  6151                  if (fs_info->sectorsize < PAGE_SIZE) {

The patch adds this check which means we only preallocate it when it's
small.

  6152                          prealloc = btrfs_alloc_subpage(fs_info, BTRFS_SUBPAGE_METADATA);
  6153                          if (IS_ERR(prealloc)) {
  6154                                  ret = PTR_ERR(prealloc);
  6155                                  unlock_page(p);
  6156                                  put_page(p);
  6157                                  exists = ERR_PTR(ret);
  6158                                  goto free_eb;
  6159                          }
  6160                  }
  6161  
  6162                  spin_lock(&mapping->private_lock);
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Take a spinlock.

  6163                  exists = grab_extent_buffer(fs_info, p);
  6164                  if (exists) {
  6165                          spin_unlock(&mapping->private_lock);
  6166                          unlock_page(p);
  6167                          put_page(p);
  6168                          mark_extent_buffer_accessed(exists, p);
  6169                          btrfs_free_subpage(prealloc);
  6170                          goto free_eb;
  6171                  }
  6172                  /* Should not fail, as we have preallocated the memory */
                           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
This comment is out of date.


  6173                  ret = attach_extent_buffer_page(eb, p, prealloc);
                                                               ^^^^^^^^
If we don't preallocate it, then it leads to a sleeping while holding
a spinlock bug.

  6174                  ASSERT(!ret);
  6175                  /*
  6176                   * To inform we have extra eb under allocation, so that

regards,
dan carpenter

             reply	other threads:[~2021-08-25 10:21 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-25 10:21 Dan Carpenter [this message]
2021-08-25 10:43 ` [bug report] btrfs: subpage: only call btrfs_alloc_subpage() when sectorsize is smaller than PAGE_SIZE Qu Wenruo

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210825102124.GA1822@kili \
    --to=dan.carpenter@oracle.com \
    --cc=linux-btrfs@vger.kernel.org \
    --cc=wqu@suse.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.