Received: by 2002:a25:c205:0:0:0:0:0 with SMTP id s5csp259759ybf; Thu, 27 Feb 2020 20:39:33 -0800 (PST) X-Google-Smtp-Source: APXvYqwcgTYx5ewkF0KwoeHH4aol8NMMp52DPQeWHBXRBien8nKyDuGA3btHeZcAFh5UbYnKGEGg X-Received: by 2002:a05:6830:4a6:: with SMTP id l6mr347809otd.287.1582864773192; Thu, 27 Feb 2020 20:39:33 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1582864773; cv=none; d=google.com; s=arc-20160816; b=EUHd/RjNZNMTKsLrZyvFmw+qieze3YzpjzU68OPf/s/vSr2qA+mD9Zf8pm3qcqbeHU r/6qn3wSLhDIAYMWhAQl3bJiFjkrAAro/nfESiMb46CRn7F2ZSrIQlQB9de+Ps3OGQUA YpjJiGjPWwAKAIrY1ciM0rA88Gi6UYISi2MEXUksFAwVFHgFzXXowpqUdI3aRXLZgXoD FHrQhx+xNtPRrRVmDdOoVeLUM/2nx2nZWK6ipJ5391TBO3fbKlphoYNKFYqbzHFeOtuc 8z4OvSyBXRgr4owk38p6tPm532KLF5Auc/9np0TF+tqLQvhmIQxBIlB6LtR5QyudX+8E +iOA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=dA/5ebLbP7M8A7hFMbfrUAWRFwPNbUxzpRKqDac8Mtc=; b=p7mwWjyrScadVycUHYPnhGdYSKIGhTOt6kqPeCwk5h0Vix6TP3LIzoHsTCch0aAVzc A7E2v0hkSixXpGM5PgVqIZweYcWtZixgut3pU0zDkVcltoj+iIHxKWDzoYMZT1cIWWtV DszHhNSF0M9fu4EBk5GsVNAPTc2EymE58QEaWSfa8qfaA0zOQNYfO6+04cj8W0eO45zh YUoGD1tGqjw0i+REFqt9IDCilufC5DurOK+LtGWskCy0MvWTIl8ZckmvQJH1jhWvrxK7 YklUOD+WQsX8+kujUCvw3WuqS+iLoYaRW9hT9yZuY1rNbkq7mt7xwXjb1Uwgn2D6BcWW mVRw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=R1JdH66y; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id 8si1129582oix.109.2020.02.27.20.39.21; Thu, 27 Feb 2020 20:39:33 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@kernel.org header.s=default header.b=R1JdH66y; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=kernel.org Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1730951AbgB1EiZ (ORCPT + 99 others); Thu, 27 Feb 2020 23:38:25 -0500 Received: from mail.kernel.org ([198.145.29.99]:56048 "EHLO mail.kernel.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1730802AbgB1EiZ (ORCPT ); Thu, 27 Feb 2020 23:38:25 -0500 Received: from localhost (unknown [104.132.1.66]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPSA id EA19D2469D; Fri, 28 Feb 2020 04:38:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=default; t=1582864704; bh=HQ7hmvfvnb2OGkhjZtbAEIeMVAGbeP6z+iDoaV29xGg=; h=From:To:Cc:Subject:Date:From; b=R1JdH66yUYP82IgWNwYtnKp6TJ80AtmtFaMnGZ/ppt73Dd0sHeSZcyQZPOvif2NWz M61C7KNWhgVQXHzTz7HTskXmFQftQZOqgAI6oXDzHObSziAc4JpOPqh9tRwgd8kl5G 1MaKi+uZlnDK4is2WTFDpTdQf+02p7X4EdifKWd4= From: Jaegeuk Kim To: linux-kernel@vger.kernel.org, linux-f2fs-devel@lists.sourceforge.net Cc: Jaegeuk Kim , stable@vger.kernel.org, Jens Axboe , linux-block@vger.kernel.org, Bart Van Assche , Gwendal Grignou , grygorii tertychnyi Subject: [PATCH] loop: avoid EAGAIN, if offset or block_size are changed Date: Thu, 27 Feb 2020 20:38:20 -0800 Message-Id: <20200228043820.169288-1-jaegeuk@kernel.org> X-Mailer: git-send-email 2.25.1.481.gfbce0eb801-goog MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Previously, there was a bug where user could see stale buffer cache (e.g, 512B) attached in the 4KB-sized pager cache, when the block size was changed from 512B to 4KB. That was fixed by: commit 5db470e229e2 ("loop: drop caches if offset or block_size are changed") But, there were some regression reports saying the fix returns EAGAIN easily. So, this patch removes previously added EAGAIN condition, nrpages != 0. Instead, it changes the flow like this: - sync_blockdev() - blk_mq_freeze_queue() : change the loop configuration - blk_mq_unfreeze_queue() - sync_blockdev() - invalidate_bdev() After invalidating the buffer cache, we must see the full valid 4KB page. Additional concern came from Bart in which we can lose some data when changing the lo_offset. In that case, this patch adds: - sync_blockdev() - blk_set_queue_dying - blk_mq_freeze_queue() : change the loop configuration - blk_mq_unfreeze_queue() - blk_queue_flag_clear(QUEUE_FLAG_DYING); - sync_blockdev() - invalidate_bdev() Report: https://bugs.chromium.org/p/chromium/issues/detail?id=938958#c38 Cc: Cc: Jens Axboe Cc: linux-block@vger.kernel.org Cc: Bart Van Assche Fixes: 5db470e229e2 ("loop: drop caches if offset or block_size are changed") Reported-by: Gwendal Grignou Reported-by: grygorii tertychnyi Reviewed-by: Bart Van Assche Signed-off-by: Jaegeuk Kim --- drivers/block/loop.c | 65 ++++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/drivers/block/loop.c b/drivers/block/loop.c index 739b372a5112..8c9da7f9b1f6 100644 --- a/drivers/block/loop.c +++ b/drivers/block/loop.c @@ -1245,6 +1245,8 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) kuid_t uid = current_uid(); struct block_device *bdev; bool partscan = false; + bool drop_request = false; + bool drop_cache = false; err = mutex_lock_killable(&loop_ctl_mutex); if (err) @@ -1264,14 +1266,21 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) goto out_unlock; } + if (lo->lo_offset != info->lo_offset) + drop_request = true; if (lo->lo_offset != info->lo_offset || - lo->lo_sizelimit != info->lo_sizelimit) { - sync_blockdev(lo->lo_device); - kill_bdev(lo->lo_device); - } + lo->lo_sizelimit != info->lo_sizelimit) + drop_cache = true; - /* I/O need to be drained during transfer transition */ - blk_mq_freeze_queue(lo->lo_queue); + sync_blockdev(lo->lo_device); + + if (drop_request) { + blk_set_queue_dying(lo->lo_queue); + blk_mq_freeze_queue_wait(lo->lo_queue); + } else { + /* I/O need to be drained during transfer transition */ + blk_mq_freeze_queue(lo->lo_queue); + } err = loop_release_xfer(lo); if (err) @@ -1298,14 +1307,6 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) if (lo->lo_offset != info->lo_offset || lo->lo_sizelimit != info->lo_sizelimit) { - /* kill_bdev should have truncated all the pages */ - if (lo->lo_device->bd_inode->i_mapping->nrpages) { - err = -EAGAIN; - pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n", - __func__, lo->lo_number, lo->lo_file_name, - lo->lo_device->bd_inode->i_mapping->nrpages); - goto out_unfreeze; - } if (figure_loop_size(lo, info->lo_offset, info->lo_sizelimit)) { err = -EFBIG; goto out_unfreeze; @@ -1342,6 +1343,8 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) out_unfreeze: blk_mq_unfreeze_queue(lo->lo_queue); + if (drop_request) + blk_queue_flag_clear(QUEUE_FLAG_DYING, lo->lo_queue); if (!err && (info->lo_flags & LO_FLAGS_PARTSCAN) && !(lo->lo_flags & LO_FLAGS_PARTSCAN)) { @@ -1350,6 +1353,12 @@ loop_set_status(struct loop_device *lo, const struct loop_info64 *info) bdev = lo->lo_device; partscan = true; } + + /* truncate stale pages cached by previous operations */ + if (!err && drop_cache) { + sync_blockdev(lo->lo_device); + invalidate_bdev(lo->lo_device); + } out_unlock: mutex_unlock(&loop_ctl_mutex); if (partscan) @@ -1531,7 +1540,7 @@ static int loop_set_dio(struct loop_device *lo, unsigned long arg) static int loop_set_block_size(struct loop_device *lo, unsigned long arg) { - int err = 0; + bool drop_cache = false; if (lo->lo_state != Lo_bound) return -ENXIO; @@ -1539,31 +1548,23 @@ static int loop_set_block_size(struct loop_device *lo, unsigned long arg) if (arg < 512 || arg > PAGE_SIZE || !is_power_of_2(arg)) return -EINVAL; - if (lo->lo_queue->limits.logical_block_size != arg) { - sync_blockdev(lo->lo_device); - kill_bdev(lo->lo_device); - } + if (lo->lo_queue->limits.logical_block_size != arg) + drop_cache = true; + sync_blockdev(lo->lo_device); blk_mq_freeze_queue(lo->lo_queue); - - /* kill_bdev should have truncated all the pages */ - if (lo->lo_queue->limits.logical_block_size != arg && - lo->lo_device->bd_inode->i_mapping->nrpages) { - err = -EAGAIN; - pr_warn("%s: loop%d (%s) has still dirty pages (nrpages=%lu)\n", - __func__, lo->lo_number, lo->lo_file_name, - lo->lo_device->bd_inode->i_mapping->nrpages); - goto out_unfreeze; - } - blk_queue_logical_block_size(lo->lo_queue, arg); blk_queue_physical_block_size(lo->lo_queue, arg); blk_queue_io_min(lo->lo_queue, arg); loop_update_dio(lo); -out_unfreeze: blk_mq_unfreeze_queue(lo->lo_queue); - return err; + /* truncate stale pages cached by previous operations */ + if (drop_cache) { + sync_blockdev(lo->lo_device); + invalidate_bdev(lo->lo_device); + } + return 0; } static int lo_simple_ioctl(struct loop_device *lo, unsigned int cmd, -- 2.25.1.481.gfbce0eb801-goog