From patchwork Fri Jun 21 23:57:15 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Darrick Wong X-Patchwork-Id: 1120573 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (mailfrom) smtp.mailfrom=lists.infradead.org (client-ip=2607:7c80:54:e::133; helo=bombadil.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=oracle.com Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=lists.infradead.org header.i=@lists.infradead.org header.b="S+l9ISRq"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=oracle.com header.i=@oracle.com header.b="iop0iBLc"; dkim-atps=neutral Received: from bombadil.infradead.org (bombadil.infradead.org [IPv6:2607:7c80:54:e::133]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 45Vwd92nGSz9sN4 for ; Sat, 22 Jun 2019 09:58:53 +1000 (AEST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:Cc:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:To:From:Subject:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=Aa+D9QBkfqkDCdaqJgeHeosxl0dYLZJdsOLnfHzQ+a4=; b=S+l9ISRqFcUZw9 dOs0AhqVsldHWUEGVcvUwmwulApiVMjOxy6YA052AitmW15Ms5rnmlbnVrRtoNGvF3lthvMcr7NtK pevPRqk0Nui4SV7JYoU3spxsH7tbMsotji7mHfM0jezWziJNEe/dYicoIht/xLMXhyKba3k/v0JGs 5BPngwZGXWleFJrz2SaAJDAxJMGiLwDgk6OF5Y93SRnlOVfwoRg9nYVxhHvJ1GmsmJQ2M8rfkiilQ XGQiK1SvIfN0zrX5tJqeoPS0DjhAonU1uDezm1+NPNyk2zdnwcSC0Aq/C8+YCp1rvPJG9RLoesTd7 A30BpTfnB6+JAgV6S3qA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.92 #3 (Red Hat Linux)) id 1heTQg-0007Mg-09; Fri, 21 Jun 2019 23:58:50 +0000 Received: from userp2120.oracle.com ([156.151.31.85]) by bombadil.infradead.org with esmtps (Exim 4.92 #3 (Red Hat Linux)) id 1heTPL-0005yd-AF for linux-mtd@lists.infradead.org; Fri, 21 Jun 2019 23:57:32 +0000 Received: from pps.filterd (userp2120.oracle.com [127.0.0.1]) by userp2120.oracle.com (8.16.0.27/8.16.0.27) with SMTP id x5LNsqBD059305; Fri, 21 Jun 2019 23:57:20 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oracle.com; h=subject : from : to : cc : date : message-id : in-reply-to : references : mime-version : content-type : content-transfer-encoding; s=corp-2018-07-02; bh=bO+sN6Te54B7Gm32yC/95CPAosLiG+rfFvZuf1HgzMU=; b=iop0iBLcfymdJCKdAp5ye36YRtYmpLaZtzpeCNIekVvk8BHvE0TvsQwZPTRe3GvBvnHB POhg9g6OZky6l9+XmlonbM47GDVpeHCNptPw1f0SGTFD69qudz5qj2jFjltpAPUFyq13 w3KNWu+wVs7ezxklCQg9TRG/odCOQBt/cLogJMrLkTERZiJDfOXSZr31CkR+QhJH0+68 gjtvuKs3csVg+Tg8WtXM+Uv0cSBNM7/LjpN7quqI1LB93qlLu9XwdmKKwOJl6wy5h1U7 wT8duhrMKfSo1Tj8wa37VlB+1nB222jRZXy16Cni/dLFHtFij5jp8ZgfZ5xzfhH5L5KN WQ== Received: from userp3030.oracle.com (userp3030.oracle.com [156.151.31.80]) by userp2120.oracle.com with ESMTP id 2t7809rqv6-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 21 Jun 2019 23:57:20 +0000 Received: from pps.filterd (userp3030.oracle.com [127.0.0.1]) by userp3030.oracle.com (8.16.0.27/8.16.0.27) with SMTP id x5LNu9VH042326; Fri, 21 Jun 2019 23:57:19 GMT Received: from pps.reinject (localhost [127.0.0.1]) by userp3030.oracle.com with ESMTP id 2t77ypesfg-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=FAIL); Fri, 21 Jun 2019 23:57:19 +0000 Received: from userp3030.oracle.com (userp3030.oracle.com [127.0.0.1]) by pps.reinject (8.16.0.27/8.16.0.27) with SMTP id x5LNvJbZ044395; Fri, 21 Jun 2019 23:57:19 GMT Received: from aserv0121.oracle.com (aserv0121.oracle.com [141.146.126.235]) by userp3030.oracle.com with ESMTP id 2t77ypesfc-1 (version=TLSv1.2 cipher=ECDHE-RSA-AES256-GCM-SHA384 bits=256 verify=OK); Fri, 21 Jun 2019 23:57:19 +0000 Received: from abhmp0013.oracle.com (abhmp0013.oracle.com [141.146.116.19]) by aserv0121.oracle.com (8.14.4/8.13.8) with ESMTP id x5LNvIgI031562; Fri, 21 Jun 2019 23:57:18 GMT Received: from localhost (/10.159.131.214) by default (Oracle Beehive Gateway v4.0) with ESMTP ; Fri, 21 Jun 2019 23:57:17 +0000 Subject: [PATCH 3/7] vfs: flush and wait for io when setting the immutable flag via FSSETXATTR From: "Darrick J. Wong" To: matthew.garrett@nebula.com, yuchao0@huawei.com, tytso@mit.edu, darrick.wong@oracle.com, ard.biesheuvel@linaro.org, josef@toxicpanda.com, clm@fb.com, adilger.kernel@dilger.ca, viro@zeniv.linux.org.uk, jack@suse.com, dsterba@suse.com, jaegeuk@kernel.org, jk@ozlabs.org Date: Fri, 21 Jun 2019 16:57:15 -0700 Message-ID: <156116143526.1664939.6767366095685084430.stgit@magnolia> In-Reply-To: <156116141046.1664939.11424021489724835645.stgit@magnolia> References: <156116141046.1664939.11424021489724835645.stgit@magnolia> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Proofpoint-Virus-Version: vendor=nai engine=6000 definitions=9295 signatures=668687 X-Proofpoint-Spam-Details: rule=notspam policy=default score=0 priorityscore=1501 malwarescore=0 suspectscore=2 phishscore=0 bulkscore=0 spamscore=0 clxscore=1015 lowpriorityscore=0 mlxscore=0 impostorscore=0 mlxlogscore=999 adultscore=0 classifier=spam adjust=0 reason=mlx scancount=1 engine=8.0.1-1810050000 definitions=main-1906210182 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20190621_165727_476473_93BD35D4 X-CRM114-Status: GOOD ( 22.00 ) X-Spam-Score: -2.5 (--) X-Spam-Report: SpamAssassin version 3.4.2 on bombadil.infradead.org summary: Content analysis details: (-2.5 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at https://www.dnswl.org/, medium trust [156.151.31.85 listed in list.dnswl.org] -0.0 SPF_HELO_PASS SPF: HELO matches SPF record -0.0 SPF_PASS SPF: sender matches SPF record 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain 0.0 UNPARSEABLE_RELAY Informational: message has unparseable relay lines -0.0 DKIMWL_WL_HIGH DKIMwl.org - Whitelisted High sender X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-efi@vger.kernel.org, linux-btrfs@vger.kernel.org, linux-kernel@vger.kernel.org, reiserfs-devel@vger.kernel.org, linux-f2fs-devel@lists.sourceforge.net, linux-xfs@vger.kernel.org, linux-mm@kvack.org, linux-nilfs@vger.kernel.org, linux-mtd@lists.infradead.org, ocfs2-devel@oss.oracle.com, linux-fsdevel@vger.kernel.org, linux-ext4@vger.kernel.org, devel@lists.orangefs.org Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org From: Darrick J. Wong When we're using FS_IOC_FSSETXATTR to set the immutable flag on a file, we need to ensure that userspace can't continue to write the file after the file becomes immutable. To make that happen, we have to flush all the dirty pagecache pages to disk to ensure that we can fail a page fault on a mmap'd region, wait for pending directio to complete, and hope the caller locked out any new writes by holding the inode lock. Signed-off-by: Darrick J. Wong --- fs/btrfs/ioctl.c | 3 +++ fs/ext4/ioctl.c | 3 +++ fs/f2fs/file.c | 3 +++ fs/xfs/xfs_ioctl.c | 39 +++++++++++++++++++++++++++++++++------ include/linux/fs.h | 37 +++++++++++++++++++++++++++++++++++++ 5 files changed, 79 insertions(+), 6 deletions(-) diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index f431813b2454..63a9281e6ce0 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c @@ -432,6 +432,9 @@ static int btrfs_ioctl_fssetxattr(struct file *file, void __user *arg) __btrfs_ioctl_fsgetxattr(binode, &old_fa); ret = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa); + if (ret) + goto out_unlock; + ret = vfs_ioc_fssetxattr_flush_data(inode, &fa); if (ret) goto out_unlock; diff --git a/fs/ext4/ioctl.c b/fs/ext4/ioctl.c index a05341b94d98..6037585c1520 100644 --- a/fs/ext4/ioctl.c +++ b/fs/ext4/ioctl.c @@ -1115,6 +1115,9 @@ long ext4_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) inode_lock(inode); ext4_fsgetxattr(inode, &old_fa); err = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa); + if (err) + goto out; + err = vfs_ioc_fssetxattr_flush_data(inode, &fa); if (err) goto out; flags = (ei->i_flags & ~EXT4_FL_XFLAG_VISIBLE) | diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c index d3cf4bdb8738..97f4bb36540f 100644 --- a/fs/f2fs/file.c +++ b/fs/f2fs/file.c @@ -2832,6 +2832,9 @@ static int f2fs_ioc_fssetxattr(struct file *filp, unsigned long arg) __f2fs_ioc_fsgetxattr(inode, &old_fa); err = vfs_ioc_fssetxattr_check(inode, &old_fa, &fa); + if (err) + goto out; + err = vfs_ioc_fssetxattr_flush_data(inode, &fa); if (err) goto out; flags = (fi->i_flags & ~F2FS_FL_XFLAG_VISIBLE) | diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c index b494e7e881e3..88583b3e1e76 100644 --- a/fs/xfs/xfs_ioctl.c +++ b/fs/xfs/xfs_ioctl.c @@ -1014,6 +1014,28 @@ xfs_diflags_to_linux( #endif } +/* + * Lock the inode against file io and page faults, then flush all dirty pages + * and wait for writeback and direct IO operations to finish. Returns with + * the relevant inode lock flags set in @join_flags. Caller is responsible for + * unlocking even on error return. + */ +static int +xfs_ioctl_setattr_flush( + struct xfs_inode *ip, + int *join_flags) +{ + /* Already locked the inode from IO? Assume we're done. */ + if (((*join_flags) & (XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL)) == + (XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL)) + return 0; + + /* Lock and flush all mappings and IO in preparation for flag change */ + *join_flags = XFS_IOLOCK_EXCL | XFS_MMAPLOCK_EXCL; + xfs_ilock(ip, *join_flags); + return inode_flush_data(VFS_I(ip)); +} + static int xfs_ioctl_setattr_xflags( struct xfs_trans *tp, @@ -1099,23 +1121,22 @@ xfs_ioctl_setattr_dax_invalidate( if (!(fa->fsx_xflags & FS_XFLAG_DAX) && !IS_DAX(inode)) return 0; - if (S_ISDIR(inode->i_mode)) + if (!S_ISREG(inode->i_mode)) return 0; - /* lock, flush and invalidate mapping in preparation for flag change */ - xfs_ilock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL); - error = filemap_write_and_wait(inode->i_mapping); + error = xfs_ioctl_setattr_flush(ip, join_flags); if (error) goto out_unlock; error = invalidate_inode_pages2(inode->i_mapping); if (error) goto out_unlock; - *join_flags = XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL; return 0; out_unlock: - xfs_iunlock(ip, XFS_MMAPLOCK_EXCL | XFS_IOLOCK_EXCL); + if (*join_flags) + xfs_iunlock(ip, *join_flags); + *join_flags = 0; return error; } @@ -1337,6 +1358,12 @@ xfs_ioctl_setattr( if (code) goto error_free_dquots; + if (!join_flags && vfs_ioc_fssetxattr_need_flush(VFS_I(ip), fa)) { + code = xfs_ioctl_setattr_flush(ip, &join_flags); + if (code) + goto error_free_dquots; + } + tp = xfs_ioctl_setattr_get_trans(ip, join_flags); if (IS_ERR(tp)) { code = PTR_ERR(tp); diff --git a/include/linux/fs.h b/include/linux/fs.h index ed9a74cf5ef3..b4553d01e254 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -3607,5 +3607,42 @@ static inline int vfs_ioc_setflags_flush_data(struct inode *inode, int flags) int vfs_ioc_fssetxattr_check(struct inode *inode, const struct fsxattr *old_fa, struct fsxattr *fa); +/* + * Do we need to flush the file data before changing attributes? When we're + * setting the immutable flag we must stop all directio writes and flush the + * dirty pages so that we can fail the page fault on the next write attempt. + */ +static inline bool vfs_ioc_fssetxattr_need_flush(struct inode *inode, + struct fsxattr *fa) +{ + if (S_ISREG(inode->i_mode) && !IS_IMMUTABLE(inode) && + (fa->fsx_xflags & FS_XFLAG_IMMUTABLE)) + return true; + + return false; +} + +/* + * Flush all pending IO and dirty mappings before setting S_IMMUTABLE on an + * inode via FS_IOC_SETXATTR. If the flush fails we'll clear the flag before + * returning error. + * + * Note: the caller should be holding i_mutex, or else be sure that + * they have exclusive access to the inode structure. + */ +static inline int vfs_ioc_fssetxattr_flush_data(struct inode *inode, + struct fsxattr *fa) +{ + int ret; + + if (!vfs_ioc_fssetxattr_need_flush(inode, fa)) + return 0; + + inode_set_flags(inode, S_IMMUTABLE, S_IMMUTABLE); + ret = inode_flush_data(inode); + if (ret) + inode_set_flags(inode, 0, S_IMMUTABLE); + return ret; +} #endif /* _LINUX_FS_H */