From patchwork Mon Mar 12 15:21:55 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eryu Guan X-Patchwork-Id: 884548 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-ext4-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="mk4JYyIc"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 400MFP4wL5z9sRc for ; Tue, 13 Mar 2018 02:23:21 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752039AbeCLPXV (ORCPT ); Mon, 12 Mar 2018 11:23:21 -0400 Received: from mail-pg0-f65.google.com ([74.125.83.65]:41726 "EHLO mail-pg0-f65.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751944AbeCLPXT (ORCPT ); Mon, 12 Mar 2018 11:23:19 -0400 Received: by mail-pg0-f65.google.com with SMTP id w17so2555571pgq.8 for ; Mon, 12 Mar 2018 08:23:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id; bh=Cd9mBGXOoUP/f0oRUBWhLAKDCIKJzPT3QUhBtk6N9h4=; b=mk4JYyIcObFnicXLYIXMwgTPhkZYYZxQj8/ZO0Dwa+nKfGRNJBCTEdnUHJflY7jYQv Ust8pwn7F6uHe30ZxuaVn4u6OMy0EJxknitFli/UlwpYOYhdGY7S8b0+TXlOFP1hluLF 8LWTtxoMfhMphjfoRrXkuuI2zZyrFXzMW/B/AtXvyZ5JxBjd607QJlMaeIZy6GCp87Vn eyLy11Xi5NFovRvlqHt8NJZ+nvjQFcuJ/iavaGgn+HRjLZfk3GIqBJmr29bOXVbn2qsp 00z2VNsVHd9MGQY93celyEFujCqaEnRy4g1v9yTY4MkdDVmUqJelP36FBQDQm9QPo5VA bsKg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id; bh=Cd9mBGXOoUP/f0oRUBWhLAKDCIKJzPT3QUhBtk6N9h4=; b=ftqzMemOGDGpjA9EBEDN0m9hs94UL+bOT6Jjejen6qlTC873ACu5U9DqALopO4McVu 6GkQKbi6L+bmOc8+3x9ksH2qlgcjvYhFHABQNu+931GYPDmVglD66HbaT8xzdtvYpkkL RObqsIyMnZkFVvm3ibto/pST7VSkFJk/XdGAtikE2W5SfCE3DaiF+NqzntHGNqYoWh3A eJEfK3BTENN6KBQrIgpH9+IFnHEINjT5OF+L3Lnr5d6X4s6vs1hu40WigoZU+HUd6xul cK4Ee9w8hDHFoYY65cfg9y2XTOhxks3Q+5SoyR84q/fMAy60YOGvPkLksyM7rQ8LXUV7 99TQ== X-Gm-Message-State: AElRT7EGqqdijlYyVoV8BDEDWeDj4yz+DAnjIQtpAg4OScqgV1PmecFt pIsRG9KsQWAmj/WEyalaX73zzBOXiTs= X-Google-Smtp-Source: AG47ELuoTj1MBfouWG/NORdzSA2tZLMB+IZGm6NUNVEbS0e2H5IfckVw40DzwAFEFXE4VbtsIxFouw== X-Received: by 10.98.103.136 with SMTP id t8mr8391816pfj.177.1520868198426; Mon, 12 Mar 2018 08:23:18 -0700 (PDT) Received: from localhost ([128.199.137.77]) by smtp.gmail.com with ESMTPSA id r29sm17101496pfj.99.2018.03.12.08.23.16 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 12 Mar 2018 08:23:17 -0700 (PDT) From: Eryu Guan To: linux-ext4@vger.kernel.org Cc: Theodore Ts'o , Jan Kara , Eryu Guan Subject: [PATCH v2 1/2] ext4: protect i_disksize update by i_data_sem in direct write path Date: Mon, 12 Mar 2018 23:21:55 +0800 Message-Id: <20180312152156.14034-1-guaneryu@gmail.com> X-Mailer: git-send-email 2.14.3 Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org i_disksize update should be protected by i_data_sem, by either taking the lock explicitly or by using ext4_update_i_disksize() helper. But the i_disksize updates in ext4_direct_IO_write() are not protected at all, which may be racing with i_disksize updates in writeback path in delalloc buffer write path. This is found by code inspection, and I didn't hit any i_disksize corruption due to this bug. Thanks to Jan Kara for catching this bug and suggesting the fix! Reported-by: Jan Kara Suggested-by: Jan Kara Signed-off-by: Eryu Guan Reviewed-by: Jan Kara --- There's no v1 version of this patch. It's a bit unfortunate that I have to remove the "ei" definition in this patch and reintroduce it in patch 2/2, otherwise I got transient "defined but not used" build warning with only this patch applied. fs/ext4/inode.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index c94780075b04..bff44b4a0783 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3658,7 +3658,6 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; - struct ext4_inode_info *ei = EXT4_I(inode); ssize_t ret; loff_t offset = iocb->ki_pos; size_t count = iov_iter_count(iter); @@ -3682,7 +3681,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) goto out; } orphan = 1; - ei->i_disksize = inode->i_size; + ext4_update_i_disksize(inode, inode->i_size); ext4_journal_stop(handle); } @@ -3790,7 +3789,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) if (ret > 0) { loff_t end = offset + ret; if (end > inode->i_size) { - ei->i_disksize = end; + ext4_update_i_disksize(inode, end); i_size_write(inode, end); /* * We're going to return a positive `ret' From patchwork Mon Mar 12 15:21:56 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Eryu Guan X-Patchwork-Id: 884549 Return-Path: X-Original-To: patchwork-incoming@ozlabs.org Delivered-To: patchwork-incoming@ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=vger.kernel.org (client-ip=209.132.180.67; helo=vger.kernel.org; envelope-from=linux-ext4-owner@vger.kernel.org; receiver=) Authentication-Results: ozlabs.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=gmail.com header.i=@gmail.com header.b="YPtgrNXO"; dkim-atps=neutral Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 400MFY4S0Qz9sRX for ; Tue, 13 Mar 2018 02:23:29 +1100 (AEDT) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751892AbeCLPX3 (ORCPT ); Mon, 12 Mar 2018 11:23:29 -0400 Received: from mail-pl0-f48.google.com ([209.85.160.48]:45934 "EHLO mail-pl0-f48.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751415AbeCLPX2 (ORCPT ); Mon, 12 Mar 2018 11:23:28 -0400 Received: by mail-pl0-f48.google.com with SMTP id v9-v6so9488085plp.12 for ; Mon, 12 Mar 2018 08:23:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=Qw731vqdLNplesWuXTe2jUPz8/jabtpIjGy3ghoGtB8=; b=YPtgrNXOKB8xmoQRiQxd7/o7nfusZKSvlp+DvYCpeXfcFwq7469fDInHVh1S6pP5fV wdg5genG7Shv2h/7W+c/2rwqLyvroln5MsIDGeeJjAwRtu1a0PhUDTvPKlDgl4JtrBzj 0I+u6yS6wBNhmNwJ3sDgyDwuZWy3+4mLmMTX11roN3RiVLEp/NcLSoIqU4ZEO8FMT6zK LW99MST2Z0fpcRCSDm6+iu3NxnxJc4UhYTg/5mKMBAoS+vY7e98JxZXQBoLCS3HPPdIn YRmM0yzyv7ke6gu9sovUtefuqIxVTz9Ntodg8f7IVtOXpEtR+XwuW9ia76HoEw21AU5V X7Dg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=Qw731vqdLNplesWuXTe2jUPz8/jabtpIjGy3ghoGtB8=; b=gqFTUm14yB7+frP/z81GgABnS8ndPemRtPsf3X1YqEMzv4J+rpxCC2OnYovPPs6dX7 MV2IZ23jXrjCIJNArWNnibk+pFMj3mW97LhhY1Qaaeh1GARDSocOgOi5Ghu+WOvTCia7 2mZ527+vK88I3iBvHjeSGiq9R1BlatQZ2CcDEhw0KdpKOQ3WyxakvJ/Aba1Xw21WhYpx faJ4az6vNWREnQ2hhsWBteFuRLSWiBkdnK6t6e/mI8VKAbhC5tHgH9dRzLw/Yb7m+1ts uROzmpoPfBLa4io9CCQv1lrlSo67fhtNwwrPEdhWgfkRIkrWUoFxHIU5Jhtp867NomzI srTA== X-Gm-Message-State: AElRT7HhL03M8RiL+aVqsdc891P1gmfZu9WrB5ViLi9HSVYfOPL3290P y/Jv77jowCIVcz0zsDTcb39w8JhZwIY= X-Google-Smtp-Source: AG47ELtiEwsN5RiBKlGdc+RsiiaAdc8FfOFnbHxLkP6EWva+X5fcCW+qIZwOGMAXPPSZ6wvBNqPL8g== X-Received: by 2002:a17:902:24c1:: with SMTP id l1-v6mr8558749plg.281.1520868207467; Mon, 12 Mar 2018 08:23:27 -0700 (PDT) Received: from localhost ([128.199.137.77]) by smtp.gmail.com with ESMTPSA id m12sm13456649pgr.35.2018.03.12.08.23.24 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Mon, 12 Mar 2018 08:23:26 -0700 (PDT) From: Eryu Guan To: linux-ext4@vger.kernel.org Cc: Theodore Ts'o , Jan Kara , Eryu Guan Subject: [PATCH v2 2/2] ext4: update i_disksize if direct write past ondisk size Date: Mon, 12 Mar 2018 23:21:56 +0800 Message-Id: <20180312152156.14034-2-guaneryu@gmail.com> X-Mailer: git-send-email 2.14.3 In-Reply-To: <20180312152156.14034-1-guaneryu@gmail.com> References: <20180312152156.14034-1-guaneryu@gmail.com> Sender: linux-ext4-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-ext4@vger.kernel.org Currently in ext4 direct write path, we update i_disksize only when new eof is greater than i_size, and don't update it even when new eof is greater than i_disksize but less than i_size. This doesn't work well with delalloc buffer write, which updates i_size and i_disksize only when delalloc blocks are resolved (at writeback time), the i_disksize from direct write can be lost if a previous buffer write succeeded at write time but failed at writeback time, then results in corrupted ondisk inode size. Consider this case, first buffer write 4k data to a new file at offset 16k with delayed allocation, then direct write 4k data to the same file at offset 4k before delalloc blocks are resolved, which doesn't update i_disksize because it writes within i_size(20k), but the extent tree metadata has been committed in journal. Then writeback of the delalloc blocks fails (due to device error etc.), and i_size/i_disksize from buffer write can't be written to disk (still zero). A subsequent umount/mount cycle recovers journal and writes extent tree metadata from direct write to disk, but with i_disksize being zero. Fix it by updating i_disksize too in direct write path when new eof is greater than i_disksize but less than i_size, so i_disksize is always consistent with direct write. This fixes occasional i_size corruption in fstests generic/475. Signed-off-by: Eryu Guan Reviewed-by: Jan Kara --- v2: - basically no change since v1, just fix the locking issue first, and reintroduce the "ei" definition in this patch. I've tested this patchset by looping generic/475 200 times without hitting a corruption, usually it fails within 5 iterations for me. Also tested by full fstests runs on ext2_4k, ext3_2k, ext4_1k configurations and dio tests from LTP, all results looked good. fs/ext4/inode.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index bff44b4a0783..9acac476c15c 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -3658,6 +3658,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) { struct file *file = iocb->ki_filp; struct inode *inode = file->f_mapping->host; + struct ext4_inode_info *ei = EXT4_I(inode); ssize_t ret; loff_t offset = iocb->ki_pos; size_t count = iov_iter_count(iter); @@ -3668,7 +3669,7 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) int orphan = 0; handle_t *handle; - if (final_size > inode->i_size) { + if (final_size > inode->i_size || final_size > ei->i_disksize) { /* Credits for sb + inode write */ handle = ext4_journal_start(inode, EXT4_HT_INODE, 2); if (IS_ERR(handle)) { @@ -3788,9 +3789,10 @@ static ssize_t ext4_direct_IO_write(struct kiocb *iocb, struct iov_iter *iter) ext4_orphan_del(handle, inode); if (ret > 0) { loff_t end = offset + ret; - if (end > inode->i_size) { + if (end > inode->i_size || end > ei->i_disksize) { ext4_update_i_disksize(inode, end); - i_size_write(inode, end); + if (end > inode->i_size) + i_size_write(inode, end); /* * We're going to return a positive `ret' * here due to non-zero-length I/O, so there's