From nobody Thu Dec 26 16:06:10 2024 Received: from m16.mail.163.com (m16.mail.163.com [220.197.31.3]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E839F13C8E8 for ; Sat, 30 Nov 2024 06:37:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=220.197.31.3 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732948625; cv=none; b=AojEIJVI5KInxFcrQ0qP4U/eYPUn/5fVByZN2qeicLWvafJH07nwKZssUnGPmyI6rHBbsOAtO/UXn7eBG23+RREPjIw9JnvsYRLlX+hdDE8QcE98mNMmBRRAs/vnh2+jii5jRme9quZfuTnPZGRKHFDYUJIzMjc1VJRiiVNyJ4o= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1732948625; c=relaxed/simple; bh=nPzA4awnZioieH5/GUiWH6Q1g6NGKZF7/J7a0r9M+Co=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=Tm+nB9EbhiW2BmnVhos+EPu+COF8KWZVT9ECsLF0LJyFSEGm29/+eI3edQDuWShpPBLjEK8IDbIBxsE9Ywe0jlorpGL/3YYsMBbYcbkmPtwLXxx3/jrN9zRuJGtSZXpGrO2fxcsjJK29RHS6BEKdXfl9jVMR4DBWYQDDXM1RLhQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com; spf=pass smtp.mailfrom=163.com; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b=PGk47AwR; arc=none smtp.client-ip=220.197.31.3 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=163.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=163.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=163.com header.i=@163.com header.b="PGk47AwR" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=163.com; s=s110527; h=From:Subject:Date:Message-ID:MIME-Version; bh=OsyGn ki5o6g212ZSCtqYRDaMbguZhKpJrnZFCLHi8p8=; b=PGk47AwRMa49yxRANqMmh 6vzzaG4Es0ce+CamUJ+gGxG9XIq/DeqMVk/smiG/tcAlC/EtNCgt5yQQD+geowik FiAXtv78icHEH0RkVVLht54iMlvn7Ukdakn47Fvnw6nLzoQyJaeS8FRWWprYP61O G4ILcuZ9HBGo/o2AuKx1ak= Received: from Jerry-PC.. (unknown [115.204.198.71]) by gzga-smtp-mtada-g1-4 (Coremail) with SMTP id _____wD3H0_6sUpnQ0YgCA--.43253S2; Sat, 30 Nov 2024 14:34:38 +0800 (CST) From: Jerry To: akpm@linux-foundation.org Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org, Jerry Subject: [PATCH] Fix issue: Writing a block devices case dead loop. generic_perform_write()-> balance_dirty_pages_ratelimited()-> balance_dirty_pages() At this point, if the block device removed, the process may trapped in a dead loop. and the memory of the bdi device hass also been released. I found this issue through SCSI devices Date: Sat, 30 Nov 2024 14:34:31 +0800 Message-ID: <20241130063431.79079-1-jerrydeng079@163.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-CM-TRANSID: _____wD3H0_6sUpnQ0YgCA--.43253S2 X-Coremail-Antispam: 1Uf129KBjvJXoWxCw4fur1DZw4UJFy3GFW3Jrb_yoW7JF1kpF Wayw1FyrW8JFy7WrZ3CayUZF4a93yIkFW7Ary7Ga9IyrsxKF1jkFyavFy0yr10krZ8GrWa vr45trW7Gr48Cr7anT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07UndbbUUUUU= X-CM-SenderInfo: xmhu25pghqwiixz6il2tof0z/1tbiNgun22dKsMMXGwAAsT Content-Type: text/plain; charset="utf-8" Signed-off-by: Jerry --- mm/backing-dev.c | 1 + mm/filemap.c | 6 ++++- mm/page-writeback.c | 61 +++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 62 insertions(+), 6 deletions(-) diff --git a/mm/backing-dev.c b/mm/backing-dev.c index dd08ab928..0b86bd980 100755 --- a/mm/backing-dev.c +++ b/mm/backing-dev.c @@ -878,6 +878,7 @@ void bdi_unregister(struct backing_dev_info *bdi) /* make sure nobody finds us on the bdi_list anymore */ bdi_remove_from_list(bdi); wb_shutdown(&bdi->wb); + wake_up(&(bdi->wb_waitq)); cgwb_bdi_unregister(bdi); =20 /* diff --git a/mm/filemap.c b/mm/filemap.c index 3b0d8c6dd..3282840f0 100755 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -3300,6 +3300,7 @@ ssize_t generic_perform_write(struct file *file, long status =3D 0; ssize_t written =3D 0; unsigned int flags =3D 0; + errseq_t err =3D 0; =20 do { struct page *page; @@ -3368,8 +3369,11 @@ ssize_t generic_perform_write(struct file *file, } pos +=3D copied; written +=3D copied; - balance_dirty_pages_ratelimited(mapping); + err =3D errseq_check(&mapping->wb_err, 0); + if (err) + return err; + } while (iov_iter_count(i)); =20 return written ? written : status; diff --git a/mm/page-writeback.c b/mm/page-writeback.c index b2c916474..e013a6d01 100755 --- a/mm/page-writeback.c +++ b/mm/page-writeback.c @@ -146,6 +146,16 @@ struct dirty_throttle_control { unsigned long pos_ratio; }; =20 + + +struct bdi_wq_callback_entry { + + struct task_struct *tsk; + struct wait_queue_entry wq_entry; + int bdi_unregister; +}; + + /* * Length of period for aging writeout fractions of bdis. This is an * arbitrarily chosen number. The longer the period, the slower fractions = will @@ -1567,6 +1577,22 @@ static inline void wb_dirty_limits(struct dirty_thro= ttle_control *dtc) } } =20 + +static int wake_up_bdi_waitq(wait_queue_entry_t *wait, unsigned int mode, + int sync, void *key) +{ + + struct bdi_wq_callback_entry *bwce =3D + container_of(wait, struct bdi_wq_callback_entry, wq_entry); + + bwce->bdi_unregister =3D 1; + if (bwce->tsk) + wake_up_process(bwce->tsk); + + return 0; +} + + /* * balance_dirty_pages() must be called by processes which are generating = dirty * data. It looks at the number of dirty pages in the machine and will fo= rce @@ -1574,7 +1600,7 @@ static inline void wb_dirty_limits(struct dirty_throt= tle_control *dtc) * If we're over `background_thresh' then the writeback threads are woken = to * perform some writeout. */ -static void balance_dirty_pages(struct bdi_writeback *wb, +static int balance_dirty_pages(struct bdi_writeback *wb, unsigned long pages_dirtied) { struct dirty_throttle_control gdtc_stor =3D { GDTC_INIT(wb) }; @@ -1595,6 +1621,16 @@ static void balance_dirty_pages(struct bdi_writeback= *wb, struct backing_dev_info *bdi =3D wb->bdi; bool strictlimit =3D bdi->capabilities & BDI_CAP_STRICTLIMIT; unsigned long start_time =3D jiffies; + struct bdi_wq_callback_entry bwce =3D {NULL}; + int ret =3D 0; + + + if (!test_bit(WB_registered, &wb->state)) + return -EIO; + + init_waitqueue_func_entry(&(bwce.wq_entry), wake_up_bdi_waitq); + bwce.tsk =3D current; + add_wait_queue(&(bdi->wb_waitq), &(bwce.wq_entry)); =20 for (;;) { unsigned long now =3D jiffies; @@ -1816,6 +1852,12 @@ static void balance_dirty_pages(struct bdi_writeback= *wb, wb->dirty_sleep =3D now; io_schedule_timeout(pause); =20 + /* bid is unregister NULL, all bdi memory is illegal */ + if (bwce.bdi_unregister) { + ret =3D -EIO; + break; + } + current->dirty_paused_when =3D now + pause; current->nr_dirtied =3D 0; current->nr_dirtied_pause =3D nr_dirtied_pause; @@ -1843,12 +1885,15 @@ static void balance_dirty_pages(struct bdi_writebac= k *wb, if (fatal_signal_pending(current)) break; } + + if (bwce.bdi_unregister =3D=3D 0) + remove_wait_queue(&(bdi->wb_waitq), &(bwce.wq_entry)); =20 if (!dirty_exceeded && wb->dirty_exceeded) wb->dirty_exceeded =3D 0; =20 if (writeback_in_progress(wb)) - return; + return ret; =20 /* * In laptop mode, we wait until hitting the higher threshold before @@ -1859,10 +1904,12 @@ static void balance_dirty_pages(struct bdi_writebac= k *wb, * background_thresh, to keep the amount of dirty memory low. */ if (laptop_mode) - return; + return ret; =20 if (nr_reclaimable > gdtc->bg_thresh) wb_start_background_writeback(wb); + + return ret; } =20 static DEFINE_PER_CPU(int, bdp_ratelimits); @@ -1944,8 +1991,12 @@ void balance_dirty_pages_ratelimited(struct address_= space *mapping) } preempt_enable(); =20 - if (unlikely(current->nr_dirtied >=3D ratelimit)) - balance_dirty_pages(wb, current->nr_dirtied); + if (unlikely(current->nr_dirtied >=3D ratelimit)) { + + if (balance_dirty_pages(wb, current->nr_dirtied) < 0) + errseq_set(&(mapping->wb_err), -EIO); + + } =20 wb_put(wb); } --=20 2.43.0