From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx2.suse.de ([195.135.220.15]:36392 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1030224AbcIVSrs (ORCPT ); Thu, 22 Sep 2016 14:47:48 -0400 Received: from relay2.suse.de (charybdis-ext.suse.de [195.135.220.254]) by mx2.suse.de (Postfix) with ESMTP id A3B3AABDB for ; Thu, 22 Sep 2016 18:47:47 +0000 (UTC) From: Goldwyn Rodrigues To: linux-btrfs@vger.kernel.org Cc: Goldwyn Rodrigues Subject: [PATCH] qgroup: Prevent qgroup->reserved from going subzero Date: Thu, 22 Sep 2016 13:47:30 -0500 Message-Id: <1474570050-4715-1-git-send-email-rgoldwyn@suse.de> Sender: linux-btrfs-owner@vger.kernel.org List-ID: From: Goldwyn Rodrigues While free'ing qgroup->reserved resources, we must check if the page is already commmitted to disk or still in memory. If not, the reserve free is doubly accounted, once while invalidating the page, and the next time while free'ing delalloc. This results is qgroup->reserved(u64) going subzero, thus very large value. So, no further I/O can be performed. This is also expressed in the comments, but not performed. Testcase: SCRATCH_DEV=/dev/vdb SCRATCH_MNT=/mnt mkfs.btrfs -f $SCRATCH_DEV mount -t btrfs $SCRATCH_DEV $SCRATCH_MNT cd $SCRATCH_MNT btrfs quota enable $SCRATCH_MNT btrfs subvolume create a btrfs qgroup limit 50m a $SCRATCH_MNT sync for c in {1..15}; do dd if=/dev/zero bs=1M count=40 of=$SCRATCH_MNT/a/file; done sleep 10 sync sleep 5 touch $SCRATCH_MNT/a/newfile echo "Removing file" rm $SCRATCH_MNT/a/file Fixes: b9d0b38928 ("btrfs: Add handler for invalidate page") Signed-off-by: Goldwyn Rodrigues --- fs/btrfs/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index e6811c4..2e2a026 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -8917,7 +8917,8 @@ again: * 2) Not written to disk * This means the reserved space should be freed here. */ - btrfs_qgroup_free_data(inode, page_start, PAGE_SIZE); + if (PageDirty(page)) + btrfs_qgroup_free_data(inode, page_start, PAGE_SIZE); if (!inode_evicting) { clear_extent_bit(tree, page_start, page_end, EXTENT_LOCKED | EXTENT_DIRTY | -- 2.6.6