[WIP] Re: [3.18rc1] btrfs triggering vm bug_on

It _looks_ like a hard out-of-ram event and not necessarily a filesystem
implementation problem.

One of the systems I work with has zero swap but still allows overcommit
in the VM. It would do things like this all the time back in development
(and I suspect it still does but the developers got rid of those pesky
logs). Not necessarily this exact error, but lots of them with the same
"feel".

You are actually triggering two bugs, only the second being in btrfs code.

The VM_BUG_ON_PAGE() in cleancache_get_page() (mm/cleancache.c) is going
off first. This is presumably the ram exhaustion event, which is an
outer problem taking place in your system (e.g. the real cause).

This floats back to the __do_readpage() which doesn't (and almost
cannot) figure out how the page validation failed

         if (!PageUptodate(page)) {
                 if (cleancache_get_page(page) == 0) {
                         BUG_ON(blocksize != PAGE_SIZE);
                         unlock_extent(tree, start, end);
                         goto out;
                 }
         }

Which (improperly) ends with this suspect bit from the out: in
__do_readpage() where the unlock_page() is called unconditionally.

out:
         if (!nr) {
                 if (!PageError(page))
                         SetPageUptodate(page);
                 unlock_page(page);
         }

I _think_ the call to unlock_page() _should_ have an if
(PageLocked(page)) in front of it.
[PATCH] Btrfs: fix race that makes btrfs_lookup_extent_info miss skinny extent items

We have a race that can lead us to miss skinny extent items in the function
btrfs_lookup_extent_info() when the skinny metadata feature is enabled.
So basically the sequence of steps is:

1) We search in the extent tree for the skinny extent, which returns > 0
   (not found);

2) We check the previous item in the returned leaf for a non-skinny extent,
   and we don't find it;

3) Because we didn't find the non-skinny extent in step 2), we release our
   path to search the extent tree again, but this time for a non-skinny
   extent key;

4) Right after we released our path in step 3), a skinny extent was inserted
   in the extent tree (delayed refs were run) - our second extent tree search
   will miss it, because it's not looking for a skinny extent;

5) After the second search returned (with ret > 0), we look for any delayed
   ref for our extent's bytenr (and we do it while holding a read lock on the
   leaf), but we won't find any, as such delayed ref had just run and completed
   after we released out path in step 3) before doing the second search.

Fix this by removing completely the path release and re-search logic. This is
safe, because if we seach for a metadata item and we don't find it, we have the
guarantee that the returned leaf is the one where the item would be inserted,
and so path->slots[0] > 0 and path->slots[0] - 1 must be the slot where the
non-skinny extent item is if it exists. The only case where path->slots[0] is
zero is when there are no smaller keys in the tree (i.e. no left siblings for
our leaf), in which case the re-search logic isn't needed as well.

This race has been present since the introduction of skinny metadata (change
3173a18f70554fe7880bb2d85c7da566e364eb3c).

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/extent-tree.c | 8 --------
 1 file changed, 8 deletions(-)
[PATCH] btrfs: Add show_path function for btrfs_super_ops

show_path() function in struct super_operations is used to output
subtree mount info for mountinfo.
Without the implement of show_path() function, user can not found where
each subvolume is mounted if using 'subvolid=' mount option.
(When mounted with 'subvol=' mount option, vfs is aware of subtree mount
and can to the path resolve by vfs itself)

With this patch, end users will be able to use findmnt(8) or other
programs reading mountinfo to find which btrfs subvolume is mounted.

Though we use fs_info->subvol_sem to protect show_path() from subvolume
destroying/creating, if user renames/moves the parent non-subvolume
dir of a subvolume, it is still possible that concurrency may happen and
cause btrfs_search_slot() fails to find the desired key.
In that case, we just return -EBUSY and info user to try again since
extra locking like locking the whole subvolume tree is too expensive for
such usage.

Reported-by: Stefan G.Weichinger <lists@xunil.at>
Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
---
 fs/btrfs/ctree.h |   2 +
 fs/btrfs/ioctl.c |   4 +-
 fs/btrfs/super.c | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 116 insertions(+), 2 deletions(-)
[PATCH] btrfs: SSD related mount option dependency rework

According to Documentations/filesystem/btrfs.txt, ssd/ssd_spread/nossd
has their own dependency(See below), but only ssd_spread implying ssd is
implemented.

ssd_spread implies ssd, conflicts nossd.
ssd conflicts nossd.
nossd conflicts ssd and ssd_spread.

This patch adds ssd{,_spread} confliction with nossd.

Signed-off-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
---
 fs/btrfs/super.c | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)
[PATCH v2] Btrfs: fix invalid leaf slot access in btrfs_lookup_extent()

If we couldn't find our extent item, we accessed the current slot
(path->slots[0]) to check if it corresponds to an equivalent skinny
metadata item. However this slot could be beyond our last item in the
leaf (i.e. path->slots[0] >= btrfs_header_nritems(leaf)), in which case
we shouldn't process it.

Since btrfs_lookup_extent() is only used to find extent items for data
extents, fix this by removing completely the logic that looks up for an
equivalent skinny metadata item, since it can not exist.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---

V2: Renamed btrfs_lookup_extent() to btrfs_lookup_data_extent().

 fs/btrfs/ctree.h       |  2 +-
 fs/btrfs/extent-tree.c | 10 ++--------
 fs/btrfs/tree-log.c    |  2 +-
 3 files changed, 4 insertions(+), 10 deletions(-)
[PATCH] btrfs: get the accurate value of used_bytes in btrfs_get_block_group_info()

Reproducer:
	# mkfs.btrfs -f -b 20G /dev/sdb
	# mount /dev/sdb /mnt/test
	# fallocate  -l 17G /mnt/test/largefile
	# btrfs fi df /mnt/test
	Data, single: total=17.49GiB, used=6.00GiB <- only 6G, but actually it should be 17G.
	System, DUP: total=8.00MiB, used=16.00KiB
	System, single: total=4.00MiB, used=0.00B
	Metadata, DUP: total=1.00GiB, used=112.00KiB
	Metadata, single: total=8.00MiB, used=0.00B
	GlobalReserve, single: total=16.00MiB, used=0.00B
	# sync
	# btrfs fi df /mnt/test
	Data, single: total=17.49GiB, used=17.00GiB <- After sync, it is expected.
	System, DUP: total=8.00MiB, used=16.00KiB
	System, single: total=4.00MiB, used=0.00B
	Metadata, DUP: total=1.00GiB, used=112.00KiB
	Metadata, single: total=8.00MiB, used=0.00B
	GlobalReserve, single: total=16.00MiB, used=0.00B

The value of 6.00GiB is actually calculated in btrfs_get_block_group_info()
by adding the @block_group->item->used for each group together. In this way,
it did not consider the bytes in cache.

This patch adds the value of @pinned, @reserved and @bytes_super in
struct btrfs_block_group_cache to make sure we can get the accurate @used_bytes.

Reported-by: Qu Wenruo <quwenruo@cn.fujitsu.com>
Signed-off-by: Dongsheng Yang <yangds.fnst@cn.fujitsu.com>
---
 fs/btrfs/ioctl.c | 4 ++++
 1 file changed, 4 insertions(+)