From patchwork Tue Mar 30 10:43:45 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sascha Hauer X-Patchwork-Id: 1459991 X-Patchwork-Delegate: richard@nod.at Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=Op6A/4Ag; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (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 4F8mLG292vz9sWF for ; Tue, 30 Mar 2021 21:45:10 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=bKHOG6JDP62c3sjxRFoB7c6q61gfFHW3+eam3E+VvS0=; b=Op6A/4AgRIUP4SULTv3FTy2W1 WS38c4GRvkmJA4I3MGiY0yCXTAjHQmPPfubwsoI69BXB8dGE/4x5eTVL12vPUbjB7b9e2XxhOJr4O AVoue6sybNViKz/80murEvNy1XBoSbsUM1rsXLUwORmrNnNrt0KSRQDQyEA+3mqb8NNK0GzLM/+lX D6fgmYn/2dAM/8Fm3bAltebqDlPXGCQYQeeCRcBnhBaAiCZNVluekzKovT9iArdqICIq25ACoLxGb vO8o4y0gd1MCAgT3SmXYS7scwNh8PZD43T0D1TncFKZzivyJYzOxIix3rKP8v7owUUO7CeLNPnJDM 9IKbuWl7g==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRBrN-003RJ4-QE; Tue, 30 Mar 2021 10:44:33 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lRBr3-003REo-DJ for linux-mtd@lists.infradead.org; Tue, 30 Mar 2021 10:44:15 +0000 Received: from dude02.hi.pengutronix.de ([2001:67c:670:100:1d::28]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lRBqu-0006SI-NQ; Tue, 30 Mar 2021 12:44:04 +0200 Received: from sha by dude02.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1lRBqt-0006OZ-QX; Tue, 30 Mar 2021 12:44:03 +0200 From: Sascha Hauer To: linux-mtd@lists.infradead.org Cc: kernel@pengutronix.de, Jan Kara , Richard Weinberger , Sascha Hauer Subject: [PATCH 1/7] ubifs: move checks and preparation into setflags() Date: Tue, 30 Mar 2021 12:43:45 +0200 Message-Id: <20210330104351.21328-2-s.hauer@pengutronix.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210330104351.21328-1-s.hauer@pengutronix.de> References: <20210330104351.21328-1-s.hauer@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::28 X-SA-Exim-Mail-From: sha@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-mtd@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_114413_746887_333F18F5 X-CRM114-Status: GOOD ( 17.36 ) X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: setflags() can be reused for upcoming FS_IOC_FS[SG]ETXATTR ioctl support. In preparation for that move the checks and preparation into that function so we can reuse them as well. Signed-off-by: Sascha Hauer --- fs/ubifs/ioctl.c | 46 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+), 19 deletions(-) Content analysis details: (0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org setflags() can be reused for upcoming FS_IOC_FS[SG]ETXATTR ioctl support. In preparation for that move the checks and preparation into that function so we can reuse them as well. Signed-off-by: Sascha Hauer --- fs/ubifs/ioctl.c | 46 +++++++++++++++++++++++++++------------------- 1 file changed, 27 insertions(+), 19 deletions(-) diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index 2326d5122beb..89533f92b356 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c @@ -101,18 +101,35 @@ static int ubifs2ioctl(int ubifs_flags) return ioctl_flags; } -static int setflags(struct inode *inode, int flags) +static int setflags(struct file *file, int flags) { int oldflags, err, release; + struct inode *inode = file_inode(file); struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_budget_req req = { .dirtied_ino = 1, .dirtied_ino_d = ui->data_len }; - err = ubifs_budget_space(c, &req); + if (IS_RDONLY(inode)) + return -EROFS; + + if (!inode_owner_or_capable(&init_user_ns, inode)) + return -EACCES; + + /* + * Make sure the file-system is read-write and make sure it + * will not become read-only while we are changing the flags. + */ + err = mnt_want_write_file(file); if (err) return err; + dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags); + + err = ubifs_budget_space(c, &req); + if (err) + goto out_drop; + mutex_lock(&ui->ui_mutex); oldflags = ubifs2ioctl(ui->flags); err = vfs_ioc_setflags_prepare(inode, oldflags, flags); @@ -131,11 +148,17 @@ static int setflags(struct inode *inode, int flags) ubifs_release_budget(c, &req); if (IS_SYNC(inode)) err = write_inode_now(inode, 1); + + mnt_drop_write_file(file); + return err; out_unlock: mutex_unlock(&ui->ui_mutex); ubifs_release_budget(c, &req); +out_drop: + mnt_drop_write_file(file); + return err; } @@ -152,12 +175,6 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return put_user(flags, (int __user *) arg); case FS_IOC_SETFLAGS: { - if (IS_RDONLY(inode)) - return -EROFS; - - if (!inode_owner_or_capable(&init_user_ns, inode)) - return -EACCES; - if (get_user(flags, (int __user *) arg)) return -EFAULT; @@ -168,17 +185,8 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) if (!S_ISDIR(inode->i_mode)) flags &= ~FS_DIRSYNC_FL; - /* - * Make sure the file-system is read-write and make sure it - * will not become read-only while we are changing the flags. - */ - err = mnt_want_write_file(file); - if (err) - return err; - dbg_gen("set flags: %#x, i_flags %#x", flags, inode->i_flags); - err = setflags(inode, flags); - mnt_drop_write_file(file); - return err; + + return setflags(file, flags); } case FS_IOC_SET_ENCRYPTION_POLICY: { struct ubifs_info *c = inode->i_sb->s_fs_info; From patchwork Tue Mar 30 10:43:46 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sascha Hauer X-Patchwork-Id: 1459989 X-Patchwork-Delegate: richard@nod.at Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=XzB18yjO; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (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 4F8mLD604Xz9sRK for ; Tue, 30 Mar 2021 21:45:08 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=QNkRdAM+JSw5O0trRB912MwTyyVnTpYsNZgzcIlxYL0=; b=XzB18yjO6yfgJI/XNkL3XG3vb c2ijOTId1ZC7U2ZEFQiaLmELkrO5ciX4F/auG37JTKP3OK0K7qWwk+0fpr33QqSeSF+Fhnm0OZVng Dczy6k5lLkqAaS+3ZGwf2QIKAkaKOUT4ggnK9if70U0NPKf4EatEogOvgZU/tHEJGR8ww2T+s+jF0 46dVmoTDeYwzIFwYha6Mv04zZrtBUiDqU1gZcNkwXbj20Wu7JBErQ6n4gpJvNIOZ21VjvM4IQ44av Da7WQ71tiFIlozYAg0kKzcBZEzpeg38+0468nMSHbceORw5tyOGmHpvgLlv/MdMSdMPViAeAzbRJ7 PJERuTr4w==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRBr1-003REg-Bv; Tue, 30 Mar 2021 10:44:11 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lRBqv-003RCM-Mi for linux-mtd@lists.infradead.org; Tue, 30 Mar 2021 10:44:07 +0000 Received: from dude02.hi.pengutronix.de ([2001:67c:670:100:1d::28]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lRBqu-0006SJ-NO; Tue, 30 Mar 2021 12:44:04 +0200 Received: from sha by dude02.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1lRBqt-0006Oc-Qy; Tue, 30 Mar 2021 12:44:03 +0200 From: Sascha Hauer To: linux-mtd@lists.infradead.org Cc: kernel@pengutronix.de, Jan Kara , Richard Weinberger , Sascha Hauer Subject: [PATCH 2/7] ubifs: Add support for FS_IOC_FS[SG]ETXATTR ioctls Date: Tue, 30 Mar 2021 12:43:46 +0200 Message-Id: <20210330104351.21328-3-s.hauer@pengutronix.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210330104351.21328-1-s.hauer@pengutronix.de> References: <20210330104351.21328-1-s.hauer@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::28 X-SA-Exim-Mail-From: sha@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-mtd@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_114405_826470_23CEBFDA X-CRM114-Status: GOOD ( 19.22 ) X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: The FS_IOC_FS[SG]ETXATTR ioctls are an alternative to FS_IOC_[GS]ETFLAGS with additional features. This patch adds support for these ioctls. Signed-off-by: Sascha Hauer --- fs/ubifs/ioctl.c | 107 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 5 deletions(-) Content analysis details: (0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org The FS_IOC_FS[SG]ETXATTR ioctls are an alternative to FS_IOC_[GS]ETFLAGS with additional features. This patch adds support for these ioctls. Signed-off-by: Sascha Hauer --- fs/ubifs/ioctl.c | 107 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 102 insertions(+), 5 deletions(-) diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index 89533f92b356..34bcd47083e4 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c @@ -101,9 +101,46 @@ static int ubifs2ioctl(int ubifs_flags) return ioctl_flags; } -static int setflags(struct file *file, int flags) +/* Transfer xflags flags to internal */ +static unsigned long ubifs_xflags_to_iflags(__u32 xflags) { - int oldflags, err, release; + unsigned long iflags = 0; + + if (xflags & FS_XFLAG_SYNC) + iflags |= UBIFS_SYNC_FL; + if (xflags & FS_XFLAG_IMMUTABLE) + iflags |= UBIFS_IMMUTABLE_FL; + if (xflags & FS_XFLAG_APPEND) + iflags |= UBIFS_APPEND_FL; + + return iflags; +} + +/* Transfer internal flags to xflags */ +static __u32 ubifs_iflags_to_xflags(unsigned long flags) +{ + __u32 xflags = 0; + + if (flags & UBIFS_SYNC_FL) + xflags |= FS_XFLAG_SYNC; + if (flags & UBIFS_IMMUTABLE_FL) + xflags |= FS_XFLAG_IMMUTABLE; + if (flags & UBIFS_APPEND_FL) + xflags |= FS_XFLAG_APPEND; + + return xflags; +} + +static void ubifs_fill_fsxattr(struct inode *inode, struct fsxattr *fa) +{ + struct ubifs_inode *ui = ubifs_inode(inode); + + simple_fill_fsxattr(fa, ubifs_iflags_to_xflags(ui->flags)); +} + +static int setflags(struct file *file, int flags, struct fsxattr *fa) +{ + int ubi_flags, oldflags, err, release; struct inode *inode = file_inode(file); struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_info *c = inode->i_sb->s_fs_info; @@ -116,6 +153,13 @@ static int setflags(struct file *file, int flags) if (!inode_owner_or_capable(&init_user_ns, inode)) return -EACCES; + ubifs_assert(c, !(flags && fa)); + + if (fa) + ubi_flags = ubifs_xflags_to_iflags(fa->fsx_xflags); + else + ubi_flags = ioctl2ubifs(flags); + /* * Make sure the file-system is read-write and make sure it * will not become read-only while we are changing the flags. @@ -132,12 +176,24 @@ static int setflags(struct file *file, int flags) mutex_lock(&ui->ui_mutex); oldflags = ubifs2ioctl(ui->flags); - err = vfs_ioc_setflags_prepare(inode, oldflags, flags); + err = vfs_ioc_setflags_prepare(inode, oldflags, ubifs2ioctl(ubi_flags)); if (err) goto out_unlock; ui->flags &= ~ioctl2ubifs(UBIFS_SETTABLE_IOCTL_FLAGS); - ui->flags |= ioctl2ubifs(flags); + + if (fa) { + struct fsxattr old_fa; + + ubifs_fill_fsxattr(inode, &old_fa); + + err = vfs_ioc_fssetxattr_check(inode, &old_fa, fa); + if (err) + goto out_unlock; + } + + ui->flags |= ubi_flags; + ubifs_set_inode_flags(inode); inode->i_ctime = current_time(inode); release = ui->dirty; @@ -162,6 +218,41 @@ static int setflags(struct file *file, int flags) return err; } +static int ubifs_ioc_fsgetxattr(struct file *file, void __user *arg) +{ + struct inode *inode = file_inode(file); + struct fsxattr fa; + + ubifs_fill_fsxattr(inode, &fa); + + if (copy_to_user(arg, &fa, sizeof(fa))) + return -EFAULT; + + return 0; +} + +static int check_xflags(unsigned int flags) +{ + if (flags & ~(FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND)) + return -EOPNOTSUPP; + return 0; +} + +static int ubifs_ioc_fssetxattr(struct file *file, const void __user *arg) +{ + struct fsxattr fa; + int err; + + if (copy_from_user(&fa, (struct fsxattr __user *)arg, sizeof(fa))) + return -EFAULT; + + err = check_xflags(fa.fsx_xflags); + if (err) + return err; + + return setflags(file, 0, &fa); +} + long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { int flags, err; @@ -186,7 +277,7 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) flags &= ~FS_DIRSYNC_FL; - return setflags(file, flags); + return setflags(file, flags, NULL); } case FS_IOC_SET_ENCRYPTION_POLICY: { struct ubifs_info *c = inode->i_sb->s_fs_info; @@ -218,6 +309,12 @@ long ubifs_ioctl(struct file *file, unsigned int cmd, unsigned long arg) case FS_IOC_GET_ENCRYPTION_NONCE: return fscrypt_ioctl_get_nonce(file, (void __user *)arg); + case FS_IOC_FSGETXATTR: + return ubifs_ioc_fsgetxattr(file, (void __user *)arg); + + case FS_IOC_FSSETXATTR: + return ubifs_ioc_fssetxattr(file, (const void __user *)arg); + default: return -ENOTTY; } From patchwork Tue Mar 30 10:43:47 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sascha Hauer X-Patchwork-Id: 1459995 X-Patchwork-Delegate: richard@nod.at Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=cmBN90Vk; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (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 4F8mNv1jb1z9sRK for ; Tue, 30 Mar 2021 21:47:27 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=H0+H//+fpF5tMhRbqVF5W4tiBr4xd3AkjDGV/scTXs0=; b=cmBN90VkkaksphH6M3Z0mVcKr B+0JKqJ1ndUUmw0ic+MyUTDYHWcV+bADmdX8T9+z3KHxvNZ/BnVuezKwAT3Kg/lk4XOS47o0x5eUs H4qndy2NpqSfe9dM1tDEzJMPTWub3prL22QyZXcH4jwmTav/tiIhNxfMBxlJjsh8Ii9++tsqLoAR0 xDzgPXI+d0KFYtSM5A5tUPTOMabv4OqJoF/GjpTeV8esvdDyuKDNjGN7W+4/B1KyZRNjah4vV1A87 xeZHe2zsY28JGRMdlqyIHy1liXZwrJuvqzu6wgfw3g6e/OvoLixnIDRTsglok26OL5xOMI5Hkqjug Td2u6sPUA==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRBtZ-003S0L-AF; Tue, 30 Mar 2021 10:46:49 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lRBr3-003REn-Cu for linux-mtd@lists.infradead.org; Tue, 30 Mar 2021 10:45:04 +0000 Received: from dude02.hi.pengutronix.de ([2001:67c:670:100:1d::28]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lRBqu-0006SK-NT; Tue, 30 Mar 2021 12:44:04 +0200 Received: from sha by dude02.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1lRBqt-0006Of-RQ; Tue, 30 Mar 2021 12:44:03 +0200 From: Sascha Hauer To: linux-mtd@lists.infradead.org Cc: kernel@pengutronix.de, Jan Kara , Richard Weinberger , Sascha Hauer Subject: [PATCH 3/7] ubifs: do not call ubifs_inode() on unchecked pointer Date: Tue, 30 Mar 2021 12:43:47 +0200 Message-Id: <20210330104351.21328-4-s.hauer@pengutronix.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210330104351.21328-1-s.hauer@pengutronix.de> References: <20210330104351.21328-1-s.hauer@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::28 X-SA-Exim-Mail-From: sha@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-mtd@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_114413_857780_BC314A49 X-CRM114-Status: GOOD ( 13.56 ) X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: new_inode() may return NULL, so only derefence the return inode when it's non NULL. This is merely a cleanup as calling ubifs_inode() on a NULL pointer doesn't do any harm, only using the result would [...] Content analysis details: (0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org new_inode() may return NULL, so only derefence the return inode when it's non NULL. This is merely a cleanup as calling ubifs_inode() on a NULL pointer doesn't do any harm, only using the result would. Nevertheless using inode only after it has been checked for validity looks much cleaner. Signed-off-by: Sascha Hauer --- fs/ubifs/dir.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index d9d8d7794eff..ba4944c87a2c 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -82,10 +82,10 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, bool encrypted = false; inode = new_inode(c->vfs_sb); - ui = ubifs_inode(inode); if (!inode) return ERR_PTR(-ENOMEM); + ui = ubifs_inode(inode); /* * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and * marking them dirty in file write path (see 'file_update_time()'). From patchwork Tue Mar 30 10:43:48 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sascha Hauer X-Patchwork-Id: 1459996 X-Patchwork-Delegate: richard@nod.at Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=DFzPmyVf; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (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 4F8mQ10b6Nz9sRK for ; Tue, 30 Mar 2021 21:48:25 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=lVcpM/mxWD/S3Gl3EApaLxaJRYvyCjgmJjaKjksYO3Y=; b=DFzPmyVfAqhKepmlniIR1XvmQ udI5j07+TqeE7n//OdNn/UAQX49ezmT1Bs0IZpD/A3zbpAPab0cBesI3CDcgxrwxvdiORHTz1qkoS gIn+jSVccUnU/lj9pDtkXwkmvLnGRdnFg+1W4M41JgVHtBBZFenco03RdIbeo3cyw1vgS6mn7Hznb CaBF4RF+4b5a6u5CtXJoev/EeQHOArsi64J5MrSK1pFtw7EJNOLoNql4+/I9zg1D9W66/73527Qbq LfahqHS9USEyuGIH2iEdgTu0+hkSJAWRklgEyg3w202kkVftpy4Y+xW1WEDgtoIS38Sn89UlQo3X4 0YxfSoxcQ==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRBuU-003SFI-My; Tue, 30 Mar 2021 10:47:46 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lRBrB-003RGd-Bo for linux-mtd@lists.infradead.org; Tue, 30 Mar 2021 10:45:04 +0000 Received: from dude02.hi.pengutronix.de ([2001:67c:670:100:1d::28]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lRBqu-0006SL-NU; Tue, 30 Mar 2021 12:44:04 +0200 Received: from sha by dude02.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1lRBqt-0006On-Rr; Tue, 30 Mar 2021 12:44:03 +0200 From: Sascha Hauer To: linux-mtd@lists.infradead.org Cc: kernel@pengutronix.de, Jan Kara , Richard Weinberger , Sascha Hauer Subject: [PATCH 4/7] ubifs: Factor out ubifs_set_feature_flag() Date: Tue, 30 Mar 2021 12:43:48 +0200 Message-Id: <20210330104351.21328-5-s.hauer@pengutronix.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210330104351.21328-1-s.hauer@pengutronix.de> References: <20210330104351.21328-1-s.hauer@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::28 X-SA-Exim-Mail-From: sha@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-mtd@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_114421_704854_0B72B1DF X-CRM114-Status: GOOD ( 13.26 ) X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: The code setting a feature flag can be reused for upcoming projid support. Factor out a function to share the code. Signed-off-by: Sascha Hauer --- fs/ubifs/sb.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) Content analysis details: (0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org The code setting a feature flag can be reused for upcoming projid support. Factor out a function to share the code. Signed-off-by: Sascha Hauer --- fs/ubifs/sb.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c index c160f718c288..87466836fcfc 100644 --- a/fs/ubifs/sb.c +++ b/fs/ubifs/sb.c @@ -924,28 +924,34 @@ int ubifs_fixup_free_space(struct ubifs_info *c) return err; } -int ubifs_enable_encryption(struct ubifs_info *c) +static int ubifs_set_feature_flag(struct ubifs_info *c, unsigned int flag) { - int err; struct ubifs_sb_node *sup = c->sup_node; - if (!IS_ENABLED(CONFIG_FS_ENCRYPTION)) - return -EOPNOTSUPP; - - if (c->encrypted) + if ((sup->flags & cpu_to_le32(flag)) == cpu_to_le32(flag)) return 0; if (c->ro_mount || c->ro_media) return -EROFS; if (c->fmt_version < 5) { - ubifs_err(c, "on-flash format version 5 is needed for encryption"); + ubifs_err(c, "on-flash format version 5 is needed for feature flags"); return -EINVAL; } - sup->flags |= cpu_to_le32(UBIFS_FLG_ENCRYPTION); + sup->flags |= cpu_to_le32(flag); + + return ubifs_write_sb_node(c, sup); +} + +int ubifs_enable_encryption(struct ubifs_info *c) +{ + int err; + + if (!IS_ENABLED(CONFIG_FS_ENCRYPTION)) + return -EOPNOTSUPP; - err = ubifs_write_sb_node(c, sup); + err = ubifs_set_feature_flag(c, UBIFS_FLG_ENCRYPTION); if (!err) c->encrypted = 1; From patchwork Tue Mar 30 10:43:49 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sascha Hauer X-Patchwork-Id: 1459992 X-Patchwork-Delegate: richard@nod.at Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=G1MoQtye; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (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 4F8mLk4bV9z9sRK for ; Tue, 30 Mar 2021 21:45:34 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=5NFyFt1oJp+X23DBcCMUVM8tGwlpZkzBaOcexJsnmNw=; b=G1MoQtyek8KklqBtls1/LScxR TBVVKNfZn6dA1fs2vZ6JFHuNQLpRIwPa6fv5/gy/TDQOwlY1flw0cTxh4yIvzkOqz2P56uND4vwD6 oS+DKE7vvSQJ68iTJsxN5OX/AeFqRufmei0FwQ9Dl0h3bvzGvDp5z9SBNs789RMRm3bFnNnqau5Py fz09J9vB5+8G0D/FcsBPJXa51mPZ+tRpWvnGBacBw4e14JEiRujduAAUqkz6QRZHB66CVcRcF3NU2 G0zhm8pj7181z9/Y4TfFmC4i0/h2zD5ovTgxqa4kUhSBiAjNM2QtLgd0BQsmPUghvyz1VpQUJWpkk xhwjPqfgw==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRBrh-003RNG-2i; Tue, 30 Mar 2021 10:44:53 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lRBrB-003RGe-Bo for linux-mtd@lists.infradead.org; Tue, 30 Mar 2021 10:44:25 +0000 Received: from dude02.hi.pengutronix.de ([2001:67c:670:100:1d::28]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lRBqu-0006SM-NX; Tue, 30 Mar 2021 12:44:04 +0200 Received: from sha by dude02.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1lRBqt-0006Or-SM; Tue, 30 Mar 2021 12:44:03 +0200 From: Sascha Hauer To: linux-mtd@lists.infradead.org Cc: kernel@pengutronix.de, Jan Kara , Richard Weinberger , Sascha Hauer Subject: [PATCH 5/7] ubifs: Add support for project id Date: Tue, 30 Mar 2021 12:43:49 +0200 Message-Id: <20210330104351.21328-6-s.hauer@pengutronix.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210330104351.21328-1-s.hauer@pengutronix.de> References: <20210330104351.21328-1-s.hauer@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::28 X-SA-Exim-Mail-From: sha@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-mtd@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_114421_642987_06991E1C X-CRM114-Status: GOOD ( 27.88 ) X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: The project id is necessary for quota project id support. This adds support for the project id to UBIFS as well as support for the FS_PROJINHERIT_FL flag. This includes a change for the UBIFS on-disk format. struct ubifs_ino_node gains a project id number and a UBIFS_PROJINHERIT_FL flag. A feature flag is added to prevent older UBIFS implementations fro [...] Content analysis details: (0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org The project id is necessary for quota project id support. This adds support for the project id to UBIFS as well as support for the FS_PROJINHERIT_FL flag. This includes a change for the UBIFS on-disk format. struct ubifs_ino_node gains a project id number and a UBIFS_PROJINHERIT_FL flag. A feature flag is added to prevent older UBIFS implementations from mounting images with project ids. The feature flag is set when a projid is set for the first time. Signed-off-by: Sascha Hauer --- fs/ubifs/dir.c | 36 ++++++++++++++++++++++++++++++++++-- fs/ubifs/ioctl.c | 42 ++++++++++++++++++++++++++++++++++++++++-- fs/ubifs/journal.c | 2 +- fs/ubifs/sb.c | 5 +++++ fs/ubifs/super.c | 1 + fs/ubifs/ubifs-media.h | 10 +++++++--- fs/ubifs/ubifs.h | 5 +++++ 7 files changed, 93 insertions(+), 8 deletions(-) diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index ba4944c87a2c..29ff0f8b038e 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -56,7 +56,8 @@ static int inherit_flags(const struct inode *dir, umode_t mode) */ return 0; - flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL); + flags = ui->flags & (UBIFS_COMPR_FL | UBIFS_SYNC_FL | UBIFS_DIRSYNC_FL | + UBIFS_PROJINHERIT_FL); if (!S_ISDIR(mode)) /* The "DIRSYNC" flag only applies to directories */ flags &= ~UBIFS_DIRSYNC_FL; @@ -105,6 +106,11 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, goto out_iput; } + if (ubifs_inode(dir)->flags & UBIFS_PROJINHERIT_FL) + ui->projid = ubifs_inode(dir)->projid; + else + ui->projid = make_kprojid(&init_user_ns, UBIFS_DEF_PROJID); + switch (mode & S_IFMT) { case S_IFREG: inode->i_mapping->a_ops = &ubifs_file_address_operations; @@ -709,6 +715,9 @@ static int ubifs_link(struct dentry *old_dentry, struct inode *dir, ubifs_assert(c, inode_is_locked(dir)); ubifs_assert(c, inode_is_locked(inode)); + if (!projid_eq(dir_ui->projid, ui->projid)) + return -EXDEV; + err = fscrypt_prepare_link(old_dentry, dir, dentry); if (err) return err; @@ -1543,6 +1552,20 @@ static int ubifs_xrename(struct inode *old_dir, struct dentry *old_dentry, return err; } +static int ubifs_rename_check_projid(struct inode *dir, struct inode *inode) +{ + struct ubifs_inode *ud = ubifs_inode(dir); + struct ubifs_inode *ui = ubifs_inode(inode); + + if (!(ud->flags & UBIFS_PROJINHERIT_FL)) + return 0; + + if (projid_eq(ud->projid, ui->projid)) + return 0; + + return -EXDEV; +} + static int ubifs_rename(struct user_namespace *mnt_userns, struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry, @@ -1562,8 +1585,17 @@ static int ubifs_rename(struct user_namespace *mnt_userns, if (err) return err; - if (flags & RENAME_EXCHANGE) + err = ubifs_rename_check_projid(new_dir, old_dentry->d_inode); + if (err) + return err; + + if (flags & RENAME_EXCHANGE) { + err = ubifs_rename_check_projid(old_dir, new_dentry->d_inode); + if (err) + return err; + return ubifs_xrename(old_dir, old_dentry, new_dir, new_dentry); + } return do_rename(old_dir, old_dentry, new_dir, new_dentry, flags); } diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index 34bcd47083e4..34e3a80b6aea 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c @@ -19,7 +19,7 @@ /* Need to be kept consistent with checked flags in ioctl2ubifs() */ #define UBIFS_SETTABLE_IOCTL_FLAGS \ (FS_COMPR_FL | FS_SYNC_FL | FS_APPEND_FL | \ - FS_IMMUTABLE_FL | FS_DIRSYNC_FL) + FS_IMMUTABLE_FL | FS_DIRSYNC_FL | FS_PROJINHERIT_FL) /* Need to be kept consistent with checked flags in ubifs2ioctl() */ #define UBIFS_GETTABLE_IOCTL_FLAGS \ @@ -70,6 +70,8 @@ static int ioctl2ubifs(int ioctl_flags) ubifs_flags |= UBIFS_IMMUTABLE_FL; if (ioctl_flags & FS_DIRSYNC_FL) ubifs_flags |= UBIFS_DIRSYNC_FL; + if (ioctl_flags & FS_PROJINHERIT_FL) + ubifs_flags |= UBIFS_PROJINHERIT_FL; return ubifs_flags; } @@ -97,6 +99,8 @@ static int ubifs2ioctl(int ubifs_flags) ioctl_flags |= FS_DIRSYNC_FL; if (ubifs_flags & UBIFS_CRYPT_FL) ioctl_flags |= FS_ENCRYPT_FL; + if (ubifs_flags & UBIFS_PROJINHERIT_FL) + ioctl_flags |= FS_PROJINHERIT_FL; return ioctl_flags; } @@ -112,6 +116,8 @@ static unsigned long ubifs_xflags_to_iflags(__u32 xflags) iflags |= UBIFS_IMMUTABLE_FL; if (xflags & FS_XFLAG_APPEND) iflags |= UBIFS_APPEND_FL; + if (xflags & FS_XFLAG_PROJINHERIT) + iflags |= UBIFS_PROJINHERIT_FL; return iflags; } @@ -127,15 +133,34 @@ static __u32 ubifs_iflags_to_xflags(unsigned long flags) xflags |= FS_XFLAG_IMMUTABLE; if (flags & UBIFS_APPEND_FL) xflags |= FS_XFLAG_APPEND; + if (flags & UBIFS_PROJINHERIT_FL) + xflags |= FS_XFLAG_PROJINHERIT; return xflags; } +static int ubifs_ioc_setproject(struct file *file, __u32 projid) +{ + struct inode *inode = file_inode(file); + struct ubifs_inode *ui = ubifs_inode(inode); + kprojid_t kprojid; + + kprojid = make_kprojid(&init_user_ns, (projid_t)projid); + if (projid_eq(kprojid, ui->projid)) + return 0; + + ui->projid = kprojid; + + return 0; +} + static void ubifs_fill_fsxattr(struct inode *inode, struct fsxattr *fa) { struct ubifs_inode *ui = ubifs_inode(inode); simple_fill_fsxattr(fa, ubifs_iflags_to_xflags(ui->flags)); + + fa->fsx_projid = (__u32)from_kprojid(&init_user_ns, ui->projid); } static int setflags(struct file *file, int flags, struct fsxattr *fa) @@ -146,6 +171,7 @@ static int setflags(struct file *file, int flags, struct fsxattr *fa) struct ubifs_info *c = inode->i_sb->s_fs_info; struct ubifs_budget_req req = { .dirtied_ino = 1, .dirtied_ino_d = ui->data_len }; + __u32 projid = UBIFS_DEF_PROJID; if (IS_RDONLY(inode)) return -EROFS; @@ -190,9 +216,20 @@ static int setflags(struct file *file, int flags, struct fsxattr *fa) err = vfs_ioc_fssetxattr_check(inode, &old_fa, fa); if (err) goto out_unlock; + + projid = fa->fsx_projid; + + err = ubifs_ioc_setproject(file, projid); + if (err) + goto out_unlock; } ui->flags |= ubi_flags; + if (ui->flags & UBIFS_FLG_PROJID || projid != UBIFS_DEF_PROJID) { + err = ubifs_enable_projid(c); + if (err) + goto out_unlock; + } ubifs_set_inode_flags(inode); inode->i_ctime = current_time(inode); @@ -233,7 +270,8 @@ static int ubifs_ioc_fsgetxattr(struct file *file, void __user *arg) static int check_xflags(unsigned int flags) { - if (flags & ~(FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND)) + if (flags & ~(FS_XFLAG_SYNC | FS_XFLAG_IMMUTABLE | FS_XFLAG_APPEND | + FS_XFLAG_PROJINHERIT)) return -EOPNOTSUPP; return 0; } diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 2857e64d673d..6c772c4d8053 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -54,7 +54,6 @@ */ static inline void zero_ino_node_unused(struct ubifs_ino_node *ino) { - memset(ino->padding1, 0, 4); memset(ino->padding2, 0, 26); } @@ -469,6 +468,7 @@ static void pack_inode(struct ubifs_info *c, struct ubifs_ino_node *ino, ino->xattr_cnt = cpu_to_le32(ui->xattr_cnt); ino->xattr_size = cpu_to_le32(ui->xattr_size); ino->xattr_names = cpu_to_le32(ui->xattr_names); + ino->projid = cpu_to_le32(from_kprojid(&init_user_ns, ui->projid)); zero_ino_node_unused(ino); /* diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c index 87466836fcfc..6b673db23fd4 100644 --- a/fs/ubifs/sb.c +++ b/fs/ubifs/sb.c @@ -957,3 +957,8 @@ int ubifs_enable_encryption(struct ubifs_info *c) return err; } + +int ubifs_enable_projid(struct ubifs_info *c) +{ + return ubifs_set_feature_flag(c, UBIFS_FLG_PROJID); +} diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index ddb2ca636c93..38322b2df548 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -159,6 +159,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) ui->xattr_size = le32_to_cpu(ino->xattr_size); ui->xattr_names = le32_to_cpu(ino->xattr_names); ui->synced_i_size = ui->ui_size = inode->i_size; + ui->projid = make_kprojid(&init_user_ns, le32_to_cpu(ino->projid)); ui->xattr = (ui->flags & UBIFS_XATTR_FL) ? 1 : 0; diff --git a/fs/ubifs/ubifs-media.h b/fs/ubifs/ubifs-media.h index 3c9792cbb6ff..59077e7fddbc 100644 --- a/fs/ubifs/ubifs-media.h +++ b/fs/ubifs/ubifs-media.h @@ -316,6 +316,7 @@ enum { * UBIFS_DIRSYNC_FL: I/O on this directory inode has to be synchronous * UBIFS_XATTR_FL: this inode is the inode for an extended attribute value * UBIFS_CRYPT_FL: use encryption for this inode + * UBIFS_PROJINHERIT_FL: Create with parents projid * * Note, these are on-flash flags which correspond to ioctl flags * (@FS_COMPR_FL, etc). They have the same values now, but generally, do not @@ -329,6 +330,7 @@ enum { UBIFS_DIRSYNC_FL = 0x10, UBIFS_XATTR_FL = 0x20, UBIFS_CRYPT_FL = 0x40, + UBIFS_PROJINHERIT_FL = 0x80, }; /* Inode flag bits used by UBIFS */ @@ -427,6 +429,7 @@ enum { * support 64bit cookies for lookups by hash * UBIFS_FLG_ENCRYPTION: this filesystem contains encrypted files * UBIFS_FLG_AUTHENTICATION: this filesystem contains hashes for authentication + * UBIFS_FLG_PROJID: this filesystem has project id support enabled */ enum { UBIFS_FLG_BIGLPT = 0x02, @@ -434,11 +437,12 @@ enum { UBIFS_FLG_DOUBLE_HASH = 0x08, UBIFS_FLG_ENCRYPTION = 0x10, UBIFS_FLG_AUTHENTICATION = 0x20, + UBIFS_FLG_PROJID = 0x40, }; #define UBIFS_FLG_MASK (UBIFS_FLG_BIGLPT | UBIFS_FLG_SPACE_FIXUP | \ UBIFS_FLG_DOUBLE_HASH | UBIFS_FLG_ENCRYPTION | \ - UBIFS_FLG_AUTHENTICATION) + UBIFS_FLG_AUTHENTICATION | UBIFS_FLG_PROJID) /** * struct ubifs_ch - common header node. @@ -497,7 +501,7 @@ union ubifs_dev_desc { * @data_len: inode data length * @xattr_cnt: count of extended attributes this inode has * @xattr_size: summarized size of all extended attributes in bytes - * @padding1: reserved for future, zeroes + * @projid: Quota project id * @xattr_names: sum of lengths of all extended attribute names belonging to * this inode * @compr_type: compression type used for this inode @@ -531,7 +535,7 @@ struct ubifs_ino_node { __le32 data_len; __le32 xattr_cnt; __le32 xattr_size; - __u8 padding1[4]; /* Watch 'zero_ino_node_unused()' if changing! */ + __le32 projid; __le32 xattr_names; __le16 compr_type; __u8 padding2[26]; /* Watch 'zero_ino_node_unused()' if changing! */ diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 7fdfdbda4b8a..534dedf0b23a 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -155,6 +155,8 @@ #define UBIFS_HMAC_ARR_SZ 0 #endif +#define UBIFS_DEF_PROJID 0 + /* * Lockdep classes for UBIFS inode @ui_mutex. */ @@ -362,6 +364,7 @@ struct ubifs_gced_idx_leb { * inodes * @ui_size: inode size used by UBIFS when writing to flash * @flags: inode flags (@UBIFS_COMPR_FL, etc) + * @projid: The project id of this inode * @compr_type: default compression type used for this inode * @last_page_read: page number of last page read (for bulk read) * @read_in_a_row: number of consecutive pages read in a row (for bulk read) @@ -413,6 +416,7 @@ struct ubifs_inode { loff_t synced_i_size; loff_t ui_size; int flags; + kprojid_t projid; pgoff_t last_page_read; pgoff_t read_in_a_row; int data_len; @@ -1902,6 +1906,7 @@ int ubifs_read_superblock(struct ubifs_info *c); int ubifs_write_sb_node(struct ubifs_info *c, struct ubifs_sb_node *sup); int ubifs_fixup_free_space(struct ubifs_info *c); int ubifs_enable_encryption(struct ubifs_info *c); +int ubifs_enable_projid(struct ubifs_info *c); /* replay.c */ int ubifs_validate_entry(struct ubifs_info *c, From patchwork Tue Mar 30 10:43:50 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sascha Hauer X-Patchwork-Id: 1459993 X-Patchwork-Delegate: richard@nod.at Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=fvZVSz5e; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (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 4F8mMC0rl3z9sRK for ; Tue, 30 Mar 2021 21:45:59 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=IY9NQ+PhzmOF+TR4v/XyoIaWNPfnfjBH0fb1FMDKTX8=; b=fvZVSz5egyWtgD3WMWfBl2Kpo RPgLF2qh1Xwt9E1qpd74Mc4aXGjWnpMXThi1JX8unt/vn7oAuhllNQoyr9W8os0VYunh5U0IPfhzs xWqmEyVQXkwCxpg5obt8pYWuv09Xl+bRt6r99Z1Qe1mIJq4Bw3WqIincOVheM5sVkFdfI809RklD0 3KZQwMA4axFhaWOP8dPQUQv2/+ZLJuwWTO30EC0AO5jyUEaHw1bH0JE9IPecAlp75OW4TezqjZH0A YJgAL+N7dUQWZIJLQTvRCBUymTl4qqfXk+KQyH9BT2jwWtAhZCju7x4z9MKn/zKmlJPucwfr6l9JF vnQ1H/M6Q==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRBs2-003RUT-3I; Tue, 30 Mar 2021 10:45:14 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lRBrJ-003RHk-CW for linux-mtd@lists.infradead.org; Tue, 30 Mar 2021 10:44:31 +0000 Received: from dude02.hi.pengutronix.de ([2001:67c:670:100:1d::28]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lRBqu-0006SN-NU; Tue, 30 Mar 2021 12:44:04 +0200 Received: from sha by dude02.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1lRBqt-0006Ou-So; Tue, 30 Mar 2021 12:44:03 +0200 From: Sascha Hauer To: linux-mtd@lists.infradead.org Cc: kernel@pengutronix.de, Jan Kara , Richard Weinberger , Sascha Hauer Subject: [PATCH 6/7] ubifs: move get_znode() to global scope Date: Tue, 30 Mar 2021 12:43:50 +0200 Message-Id: <20210330104351.21328-7-s.hauer@pengutronix.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210330104351.21328-1-s.hauer@pengutronix.de> References: <20210330104351.21328-1-s.hauer@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::28 X-SA-Exim-Mail-From: sha@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-mtd@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_114429_605802_5E34F13A X-CRM114-Status: GOOD ( 16.10 ) X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: get_znode will be needed by upcoming UBIFS quota support. Rename it to ubifs_get_znode and export it. Signed-off-by: Sascha Hauer --- fs/ubifs/tnc.c | 32 ++++++++++++++++ fs/ubifs/ubifs.h | 2 ++ 2 files changed, 18 insertions(+), 16 deletions(-) Content analysis details: (0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org get_znode will be needed by upcoming UBIFS quota support. Rename it to ubifs_get_znode and export it. Signed-off-by: Sascha Hauer --- fs/ubifs/tnc.c | 32 ++++++++++++++++---------------- fs/ubifs/ubifs.h | 2 ++ 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/fs/ubifs/tnc.c b/fs/ubifs/tnc.c index 488f3da7a6c6..b30cd47a7e4c 100644 --- a/fs/ubifs/tnc.c +++ b/fs/ubifs/tnc.c @@ -570,15 +570,15 @@ static int matches_name(struct ubifs_info *c, struct ubifs_zbranch *zbr, } /** - * get_znode - get a TNC znode that may not be loaded yet. + * ubifs_get_znode - get a TNC znode that may not be loaded yet. * @c: UBIFS file-system description object * @znode: parent znode * @n: znode branch slot number * * This function returns the znode or a negative error code. */ -static struct ubifs_znode *get_znode(struct ubifs_info *c, - struct ubifs_znode *znode, int n) +struct ubifs_znode *ubifs_get_znode(struct ubifs_info *c, + struct ubifs_znode *znode, int n) { struct ubifs_zbranch *zbr; @@ -618,11 +618,11 @@ static int tnc_next(struct ubifs_info *c, struct ubifs_znode **zn, int *n) nn = znode->iip + 1; znode = zp; if (nn < znode->child_cnt) { - znode = get_znode(c, znode, nn); + znode = ubifs_get_znode(c, znode, nn); if (IS_ERR(znode)) return PTR_ERR(znode); while (znode->level != 0) { - znode = get_znode(c, znode, 0); + znode = ubifs_get_znode(c, znode, 0); if (IS_ERR(znode)) return PTR_ERR(znode); } @@ -662,12 +662,12 @@ static int tnc_prev(struct ubifs_info *c, struct ubifs_znode **zn, int *n) nn = znode->iip - 1; znode = zp; if (nn >= 0) { - znode = get_znode(c, znode, nn); + znode = ubifs_get_znode(c, znode, nn); if (IS_ERR(znode)) return PTR_ERR(znode); while (znode->level != 0) { nn = znode->child_cnt - 1; - znode = get_znode(c, znode, nn); + znode = ubifs_get_znode(c, znode, nn); if (IS_ERR(znode)) return PTR_ERR(znode); } @@ -2571,7 +2571,7 @@ static int tnc_delete(struct ubifs_info *c, struct ubifs_znode *znode, int n) while (znode->child_cnt == 1 && znode->level != 0) { zp = znode; zbr = &znode->zbranch[0]; - znode = get_znode(c, znode, 0); + znode = ubifs_get_znode(c, znode, 0); if (IS_ERR(znode)) return PTR_ERR(znode); znode = dirty_cow_znode(c, zbr); @@ -3098,12 +3098,12 @@ static struct ubifs_znode *left_znode(struct ubifs_info *c, return NULL; if (n >= 0) { /* Now go down the rightmost branch to 'level' */ - znode = get_znode(c, znode, n); + znode = ubifs_get_znode(c, znode, n); if (IS_ERR(znode)) return znode; while (znode->level != level) { n = znode->child_cnt - 1; - znode = get_znode(c, znode, n); + znode = ubifs_get_znode(c, znode, n); if (IS_ERR(znode)) return znode; } @@ -3135,11 +3135,11 @@ static struct ubifs_znode *right_znode(struct ubifs_info *c, return NULL; if (n < znode->child_cnt) { /* Now go down the leftmost branch to 'level' */ - znode = get_znode(c, znode, n); + znode = ubifs_get_znode(c, znode, n); if (IS_ERR(znode)) return znode; while (znode->level != level) { - znode = get_znode(c, znode, 0); + znode = ubifs_get_znode(c, znode, 0); if (IS_ERR(znode)) return znode; } @@ -3224,13 +3224,13 @@ static struct ubifs_znode *lookup_znode(struct ubifs_info *c, } if (znode->level == level + 1) break; - znode = get_znode(c, znode, n); + znode = ubifs_get_znode(c, znode, n); if (IS_ERR(znode)) return znode; } /* Check if the child is the one we are looking for */ if (znode->zbranch[n].lnum == lnum && znode->zbranch[n].offs == offs) - return get_znode(c, znode, n); + return ubifs_get_znode(c, znode, n); /* If the key is unique, there is nowhere else to look */ if (!is_hash_key(c, key)) return NULL; @@ -3256,7 +3256,7 @@ static struct ubifs_znode *lookup_znode(struct ubifs_info *c, /* Check it */ if (znode->zbranch[n].lnum == lnum && znode->zbranch[n].offs == offs) - return get_znode(c, znode, n); + return ubifs_get_znode(c, znode, n); /* Stop if the key is less than the one we are looking for */ if (keys_cmp(c, &znode->zbranch[n].key, key) < 0) break; @@ -3278,7 +3278,7 @@ static struct ubifs_znode *lookup_znode(struct ubifs_info *c, /* Check it */ if (znode->zbranch[n].lnum == lnum && znode->zbranch[n].offs == offs) - return get_znode(c, znode, n); + return ubifs_get_znode(c, znode, n); /* Stop if the key is greater than the one we are looking for */ if (keys_cmp(c, &znode->zbranch[n].key, key) > 0) break; diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 534dedf0b23a..1f03f88017ed 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -1820,6 +1820,8 @@ int ubifs_find_dirty_idx_leb(struct ubifs_info *c); int ubifs_save_dirty_idx_lnums(struct ubifs_info *c); /* tnc.c */ +struct ubifs_znode *ubifs_get_znode(struct ubifs_info *c, + struct ubifs_znode *znode, int n); int ubifs_lookup_level0(struct ubifs_info *c, const union ubifs_key *key, struct ubifs_znode **zn, int *n); int ubifs_tnc_lookup_nm(struct ubifs_info *c, const union ubifs_key *key, From patchwork Tue Mar 30 10:43:51 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sascha Hauer X-Patchwork-Id: 1459994 X-Patchwork-Delegate: richard@nod.at Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=none (no SPF record) smtp.mailfrom=lists.infradead.org (client-ip=2001:8b0:10b:1:d65d:64ff:fe57:4e05; helo=desiato.infradead.org; envelope-from=linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (2048-bit key; secure) header.d=lists.infradead.org header.i=@lists.infradead.org header.a=rsa-sha256 header.s=desiato.20200630 header.b=BIFzKT4r; dkim-atps=neutral Received: from desiato.infradead.org (desiato.infradead.org [IPv6:2001:8b0:10b:1:d65d:64ff:fe57:4e05]) (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 4F8mNp5tynz9sRK for ; Tue, 30 Mar 2021 21:47:22 +1100 (AEDT) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=desiato.20200630; h=Sender:Content-Transfer-Encoding :Content-Type:List-Subscribe:List-Help:List-Post:List-Archive: List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=9jvLcCCr4PSmcfoIuDAENBahVBA7vPCAlMTSf742Vzo=; b=BIFzKT4r+4aFIosOaqDISirBv agGmCIx3hpc7ggXuEKcm0bsiYJ8Brt/irfG/5U/1h/xDZtPkWFsYtUOsp2L+nTBtrkTPD8wcdvChN J0R8ppw/+Rvx/pqTKf8kNYDDZCuuWvdCTGvFt/s1j9pgUco0PG6kLiqPSWZBFGCVRlka4GClHla1y 9CjEk2PHFcKYTIEKLNruvTobXpYaTi8wbghMX8EFMZOV7F9zWJ42OpMrJMK872DroMl0KRu5HlIJh 7glGU+XK64i9FgiK08SfPLbXtaNSJWsZPmvsSK32KX9UO7H91EzREUpgiihV1vZ8YqsraHAcwEoKE mvCkOiJrQ==; Received: from localhost ([::1] helo=desiato.infradead.org) by desiato.infradead.org with esmtp (Exim 4.94 #2 (Red Hat Linux)) id 1lRBsv-003Ro2-Lh; Tue, 30 Mar 2021 10:46:09 +0000 Received: from metis.ext.pengutronix.de ([2001:67c:670:201:290:27ff:fe1d:cc33]) by desiato.infradead.org with esmtps (Exim 4.94 #2 (Red Hat Linux)) id 1lRBqv-003RCO-Mk for linux-mtd@lists.infradead.org; Tue, 30 Mar 2021 10:45:04 +0000 Received: from dude02.hi.pengutronix.de ([2001:67c:670:100:1d::28]) by metis.ext.pengutronix.de with esmtps (TLS1.3:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1lRBqu-0006SO-Ul; Tue, 30 Mar 2021 12:44:04 +0200 Received: from sha by dude02.hi.pengutronix.de with local (Exim 4.92) (envelope-from ) id 1lRBqt-0006Ox-TX; Tue, 30 Mar 2021 12:44:03 +0200 From: Sascha Hauer To: linux-mtd@lists.infradead.org Cc: kernel@pengutronix.de, Jan Kara , Richard Weinberger , Sascha Hauer , Dongsheng Yang Subject: [PATCH 7/7] ubifs: Add quota support Date: Tue, 30 Mar 2021 12:43:51 +0200 Message-Id: <20210330104351.21328-8-s.hauer@pengutronix.de> X-Mailer: git-send-email 2.29.2 In-Reply-To: <20210330104351.21328-1-s.hauer@pengutronix.de> References: <20210330104351.21328-1-s.hauer@pengutronix.de> MIME-Version: 1.0 X-SA-Exim-Connect-IP: 2001:67c:670:100:1d::28 X-SA-Exim-Mail-From: sha@pengutronix.de X-SA-Exim-Scanned: No (on metis.ext.pengutronix.de); SAEximRunCond expanded to false X-PTX-Original-Recipient: linux-mtd@lists.infradead.org X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20210330_114406_058727_45E5572F X-CRM114-Status: GOOD ( 37.48 ) X-Spam-Score: 0.0 (/) X-Spam-Report: Spam detection software, running on the system "desiato.infradead.org", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: This introduces poor man's quota support for UBIFS. Unlike other implementations we never store anything on the flash. This has two big advantages: - No possible regressions with a changed on-disk format - no quota files can get out of sync. Content analysis details: (0.0 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- 0.0 SPF_HELO_NONE SPF: HELO does not publish an SPF Record -0.0 SPF_PASS SPF: sender matches SPF record X-BeenThere: linux-mtd@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Linux MTD discussion mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: "linux-mtd" Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org This introduces poor man's quota support for UBIFS. Unlike other implementations we never store anything on the flash. This has two big advantages: - No possible regressions with a changed on-disk format - no quota files can get out of sync. There are downsides as well: - During mount the whole index must be scanned which takes some time - The quota limits must be set manually each time a filesystem is mounted. UBIFS is targetted for embedded systems and quota limits are likely not changed interactively, so having to restore the quota limits with a script shouldn't be a big deal. The mount time penalty is a price we must pay, but for that we get a simple and straight forward implementation for this rather rarely used feature. The quota data itself is stored in a red-black tree in memory. It is implemented as a quota format. When enabled with the "quota" mount option all three quota types (user, group, project) are enabled. The quota integration into UBIFS is taken from a series posted earlier by Dongsheng Yang. Like the earlier series we only account regular files for quota. All others are counted in the number of files, but do not require any quota space. Signed-off-by: Dongsheng Yang Signed-off-by: Sascha Hauer --- Documentation/filesystems/ubifs.rst | 6 + fs/ubifs/Makefile | 1 + fs/ubifs/dir.c | 103 +++-- fs/ubifs/file.c | 43 ++ fs/ubifs/ioctl.c | 32 ++ fs/ubifs/journal.c | 2 + fs/ubifs/quota.c | 606 ++++++++++++++++++++++++++++ fs/ubifs/super.c | 86 +++- fs/ubifs/ubifs.h | 37 ++ fs/ubifs/xattr.c | 5 +- include/uapi/linux/quota.h | 1 + 11 files changed, 896 insertions(+), 26 deletions(-) create mode 100644 fs/ubifs/quota.c diff --git a/Documentation/filesystems/ubifs.rst b/Documentation/filesystems/ubifs.rst index e6ee99762534..999b815afb38 100644 --- a/Documentation/filesystems/ubifs.rst +++ b/Documentation/filesystems/ubifs.rst @@ -105,6 +105,12 @@ auth_key= specify the key used for authenticating the filesystem. auth_hash_name= The hash algorithm used for authentication. Used for both hashing and for creating HMACs. Typical values include "sha256" or "sha512" +usrquota Enable user disk quota support + (requires CONFIG_QUOTA). +grpquota Enable group disk quota support + (requires CONFIG_QUOTA). +prjquota Enable project disk quota support + (requires CONFIG_QUOTA). ==================== ======================================================= diff --git a/fs/ubifs/Makefile b/fs/ubifs/Makefile index 5c4b845754a7..07f657f5ea8f 100644 --- a/fs/ubifs/Makefile +++ b/fs/ubifs/Makefile @@ -9,3 +9,4 @@ ubifs-y += misc.o ubifs-$(CONFIG_FS_ENCRYPTION) += crypto.o ubifs-$(CONFIG_UBIFS_FS_XATTR) += xattr.o ubifs-$(CONFIG_UBIFS_FS_AUTHENTICATION) += auth.o +ubifs-$(CONFIG_QUOTA) += quota.o diff --git a/fs/ubifs/dir.c b/fs/ubifs/dir.c index 29ff0f8b038e..92cb6e9a978a 100644 --- a/fs/ubifs/dir.c +++ b/fs/ubifs/dir.c @@ -64,28 +64,13 @@ static int inherit_flags(const struct inode *dir, umode_t mode) return flags; } -/** - * ubifs_new_inode - allocate new UBIFS inode object. - * @c: UBIFS file-system description object - * @dir: parent directory inode - * @mode: inode mode flags - * - * This function finds an unused inode number, allocates new inode and - * initializes it. Returns new inode in case of success and an error code in - * case of failure. - */ -struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, - umode_t mode) +static int ubifs_init_inode(struct ubifs_info *c, struct inode *inode, + struct inode *dir, umode_t mode) { int err; - struct inode *inode; struct ubifs_inode *ui; bool encrypted = false; - inode = new_inode(c->vfs_sb); - if (!inode) - return ERR_PTR(-ENOMEM); - ui = ubifs_inode(inode); /* * Set 'S_NOCMTIME' to prevent VFS form updating [mc]time of inodes and @@ -103,7 +88,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, err = fscrypt_prepare_new_inode(dir, inode, &encrypted); if (err) { ubifs_err(c, "fscrypt_prepare_new_inode failed: %i", err); - goto out_iput; + return err; } if (ubifs_inode(dir)->flags & UBIFS_PROJINHERIT_FL) @@ -111,6 +96,11 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, else ui->projid = make_kprojid(&init_user_ns, UBIFS_DEF_PROJID); + dquot_initialize(inode); + err = dquot_alloc_inode(inode); + if (err) + return err; + switch (mode & S_IFMT) { case S_IFREG: inode->i_mapping->a_ops = &ubifs_file_address_operations; @@ -150,7 +140,7 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, spin_unlock(&c->cnt_lock); ubifs_err(c, "out of inode numbers"); err = -EINVAL; - goto out_iput; + goto out_drop; } ubifs_warn(c, "running out of inode numbers (current %lu, max %u)", (unsigned long)c->highest_inum, INUM_WATERMARK); @@ -171,16 +161,79 @@ struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, err = fscrypt_set_context(inode, NULL); if (err) { ubifs_err(c, "fscrypt_set_context failed: %i", err); - goto out_iput; + goto out_bad; } } - return inode; + return 0; -out_iput: +out_bad: make_bad_inode(inode); - iput(inode); - return ERR_PTR(err); + + dquot_free_inode(inode); +out_drop: + dquot_drop(inode); + + return err; +} + +/** + * ubifs_new_inode - allocate new UBIFS inode object. + * @c: UBIFS file-system description object + * @dir: parent directory inode + * @mode: inode mode flags + * + * This function finds an unused inode number, allocates new inode and + * initializes it. Returns new inode in case of success and an error code in + * case of failure. + */ +struct inode *ubifs_new_inode(struct ubifs_info *c, struct inode *dir, + umode_t mode) +{ + struct inode *inode; + int err; + + inode = new_inode(c->vfs_sb); + if (!inode) + return ERR_PTR(-ENOMEM); + + err = ubifs_init_inode(c, inode, dir, mode); + if (err) { + iput(inode); + return ERR_PTR(err); + } + + return inode; +} + +/** + * ubifs_new_xattr_inode - allocate new UBIFS inode object to be used as xattr + * @c: UBIFS file-system description object + * @dir: parent directory inode + * @mode: inode mode flags + * + * like ubifs_new_inode, but allocates an inode without quota accounting to be + * used for xattrs. + */ +struct inode *ubifs_new_xattr_inode(struct ubifs_info *c, struct inode *dir, + umode_t mode) +{ + struct inode *inode; + int err; + + inode = new_inode(c->vfs_sb); + if (!inode) + return ERR_PTR(-ENOMEM); + + inode->i_flags |= S_NOQUOTA; + + err = ubifs_init_inode(c, inode, dir, mode); + if (err) { + iput(inode); + return ERR_PTR(err); + } + + return inode; } static int dbg_check_name(const struct ubifs_info *c, @@ -780,6 +833,8 @@ static int ubifs_unlink(struct inode *dir, struct dentry *dentry) unsigned int saved_nlink = inode->i_nlink; struct fscrypt_name nm; + dquot_initialize(inode); + /* * Budget request settings: deletion direntry, deletion inode (+1 for * @dirtied_ino), changing the parent directory inode. If budgeting diff --git a/fs/ubifs/file.c b/fs/ubifs/file.c index 0e4b4be3aa26..62d8fe34aa8a 100644 --- a/fs/ubifs/file.c +++ b/fs/ubifs/file.c @@ -427,8 +427,10 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping, struct ubifs_inode *ui = ubifs_inode(inode); pgoff_t index = pos >> PAGE_SHIFT; int err, appending = !!(pos + len > inode->i_size); + int quota_size = 0; int skipped_read = 0; struct page *page; + int ret = 0; ubifs_assert(c, ubifs_inode(inode)->ui_size == inode->i_size); ubifs_assert(c, !c->ro_media && !c->ro_mount); @@ -436,6 +438,16 @@ static int ubifs_write_begin(struct file *file, struct address_space *mapping, if (unlikely(c->ro_error)) return -EROFS; + quota_size = ((pos + len) - inode->i_size); + if (quota_size < 0) + quota_size = 0; + if (S_ISREG(inode->i_mode)) { + dquot_initialize(inode); + ret = dquot_alloc_space_nodirty(inode, quota_size); + if (unlikely(ret)) + return ret; + } + /* Try out the fast-path part first */ page = grab_cache_page_write_begin(mapping, index, flags); if (unlikely(!page)) @@ -541,6 +553,7 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping, struct ubifs_inode *ui = ubifs_inode(inode); struct ubifs_info *c = inode->i_sb->s_fs_info; loff_t end_pos = pos + len; + int quota_size = 0; int appending = !!(end_pos > inode->i_size); dbg_gen("ino %lu, pos %llu, pg %lu, len %u, copied %d, i_size %lld", @@ -559,6 +572,11 @@ static int ubifs_write_end(struct file *file, struct address_space *mapping, dbg_gen("copied %d instead of %d, read page and repeat", copied, len); cancel_budget(c, page, ui, appending); + quota_size = ((pos + len) - inode->i_size); + if (quota_size < 0) + quota_size = 0; + if (S_ISREG(inode->i_mode)) + dquot_free_space_nodirty(inode, quota_size); ClearPageChecked(page); /* @@ -1111,6 +1129,7 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode, int err; struct ubifs_budget_req req; loff_t old_size = inode->i_size, new_size = attr->ia_size; + loff_t quota_size = (old_size - new_size); int offset = new_size & (UBIFS_BLOCK_SIZE - 1), budgeted = 1; struct ubifs_inode *ui = ubifs_inode(inode); @@ -1190,6 +1209,10 @@ static int do_truncation(struct ubifs_info *c, struct inode *inode, do_attr_changes(inode, attr); err = ubifs_jnl_truncate(c, inode, old_size, new_size); mutex_unlock(&ui->ui_mutex); + if (quota_size < 0) + quota_size = 0; + if (S_ISREG(inode->i_mode)) + dquot_free_space_nodirty(inode, quota_size); out_budg: if (budgeted) @@ -1226,6 +1249,17 @@ static int do_setattr(struct ubifs_info *c, struct inode *inode, if (attr->ia_valid & ATTR_SIZE) { dbg_gen("size %lld -> %lld", inode->i_size, new_size); + if (S_ISREG(inode->i_mode)) { + if (new_size > inode->i_size) { + err = dquot_alloc_space_nodirty(inode, new_size - inode->i_size); + if (err) { + ubifs_release_budget(c, &req); + return err; + } + } else { + dquot_free_space_nodirty(inode, inode->i_size - new_size); + } + } truncate_setsize(inode, new_size); } @@ -1278,6 +1312,15 @@ int ubifs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry, if (err) return err; + if (is_quota_modification(inode, attr)) + dquot_initialize(inode); + if ((attr->ia_valid & ATTR_UID && !uid_eq(attr->ia_uid, inode->i_uid)) || + (attr->ia_valid & ATTR_GID && !gid_eq(attr->ia_gid, inode->i_gid))) { + err = dquot_transfer(inode, attr); + if (err) + return err; + } + if ((attr->ia_valid & ATTR_SIZE) && attr->ia_size < inode->i_size) /* Truncation to a smaller size */ err = do_truncation(c, inode, attr); diff --git a/fs/ubifs/ioctl.c b/fs/ubifs/ioctl.c index 34e3a80b6aea..9de8d0f86a31 100644 --- a/fs/ubifs/ioctl.c +++ b/fs/ubifs/ioctl.c @@ -139,16 +139,48 @@ static __u32 ubifs_iflags_to_xflags(unsigned long flags) return xflags; } +#ifdef CONFIG_QUOTA +static int ubifs_transfer_project_quota(struct inode *inode, kprojid_t kprojid) +{ + struct dquot *transfer_to[MAXQUOTAS] = {}; + struct ubifs_info *c = inode->i_sb->s_fs_info; + struct super_block *sb = c->vfs_sb; + int err = 0; + + err = dquot_initialize(inode); + if (err) + return err; + + transfer_to[PRJQUOTA] = dqget(sb, make_kqid_projid(kprojid)); + if (!IS_ERR(transfer_to[PRJQUOTA])) { + err = __dquot_transfer(inode, transfer_to); + dqput(transfer_to[PRJQUOTA]); + } + + return err; +} +#else +static int ubifs_transfer_project_quota(struct inode *inode, kprojid_t kprojid) +{ + return 0; +} +#endif + static int ubifs_ioc_setproject(struct file *file, __u32 projid) { struct inode *inode = file_inode(file); struct ubifs_inode *ui = ubifs_inode(inode); kprojid_t kprojid; + int err; kprojid = make_kprojid(&init_user_ns, (projid_t)projid); if (projid_eq(kprojid, ui->projid)) return 0; + err = ubifs_transfer_project_quota(inode, kprojid); + if (err) + return err; + ui->projid = kprojid; return 0; diff --git a/fs/ubifs/journal.c b/fs/ubifs/journal.c index 6c772c4d8053..3cc888635d19 100644 --- a/fs/ubifs/journal.c +++ b/fs/ubifs/journal.c @@ -631,6 +631,8 @@ int ubifs_jnl_update(struct ubifs_info *c, const struct inode *dir, } ui->del_cmtno = c->cmt_no; orphan_added = 1; + if (S_ISREG(inode->i_mode)) + dquot_free_space_nodirty((struct inode *)inode, inode->i_size); } err = write_head(c, BASEHD, dent, len, &lnum, &dent_offs, sync); diff --git a/fs/ubifs/quota.c b/fs/ubifs/quota.c new file mode 100644 index 000000000000..bebefb846b1b --- /dev/null +++ b/fs/ubifs/quota.c @@ -0,0 +1,606 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * This file is part of UBIFS. + * + * Copyright (C) 2019 Pengutronix, Sascha Hauer + */ +#include "ubifs.h" + +struct ubifs_dqblk { + struct mem_dqblk dqblk; + struct rb_node rb; + struct kqid kqid; +}; + +/** + * ubifs_dqblk_insert - find qid in tree + * @c: UBIFS file-system description object + * @new: The new entry to insert + * + * This inserts a new entry to the dqblk tree which is sorted by qids. Caller + * must make sure this entry doesn't exist already. + */ +static void ubifs_dqblk_insert(struct ubifs_info *c, struct ubifs_dqblk *new) +{ + struct rb_root *root = &c->dqblk_tree[new->kqid.type]; + struct rb_node **link = &root->rb_node, *parent = NULL; + struct ubifs_dqblk *ud; + + /* Go to the bottom of the tree */ + while (*link) { + parent = *link; + + ud = rb_entry(parent, struct ubifs_dqblk, rb); + + if (qid_lt(new->kqid, ud->kqid)) + link = &(*link)->rb_left; + else + link = &(*link)->rb_right; + } + + /* Put the new node there */ + rb_link_node(&new->rb, parent, link); + rb_insert_color(&new->rb, root); +} + +/** + * ubifs_dqblk_find_next - find the next qid + * @c: UBIFS file-system description object + * @qid: The qid to look for + * + * Find the next dqblk entry with a qid that is bigger or equally big than the + * given qid. Returns the next dqblk entry if found or NULL if no dqblk exists + * with a qid that is at least equally big. + */ +static struct ubifs_dqblk *ubifs_dqblk_find_next(struct ubifs_info *c, + struct kqid qid) +{ + struct rb_node *node = c->dqblk_tree[qid.type].rb_node; + struct ubifs_dqblk *next = NULL; + + while (node) { + struct ubifs_dqblk *ud = rb_entry(node, struct ubifs_dqblk, rb); + + if (qid_eq(qid, ud->kqid)) + return ud; + + if (qid_lt(qid, ud->kqid)) { + next = ud; + node = node->rb_left; + } else { + node = node->rb_right; + } + } + + return next; +} + +/** + * ubifs_dqblk_find - find qid in tree + * @c: UBIFS file-system description object + * @qid: The qid to look for + * + * This walks the dqblk tree and searches a given qid. Returns the dqblk entry + * when found or NULL otherwise. + */ +static struct ubifs_dqblk *ubifs_dqblk_find(struct ubifs_info *c, + struct kqid qid) +{ + struct ubifs_dqblk *next; + + next = ubifs_dqblk_find_next(c, qid); + + if (next && qid_eq(qid, next->kqid)) + return next; + + return NULL; +} + +/** + * ubifs_dqblk_get - get dqblk entry for given qid + * @c: UBIFS file-system description object + * @qid: The qid to look for + * + * This searches the given qid in the dqblk tree and returns it if found. If not, + * a new dqblk entry is created, inserted into the dqblk tree and returned. + */ +static struct ubifs_dqblk *ubifs_dqblk_get(struct ubifs_info *c, + struct kqid qid) +{ + struct ubifs_dqblk *ud; + + ud = ubifs_dqblk_find(c, qid); + if (ud) + return ud; + + ud = kzalloc(sizeof(*ud), GFP_KERNEL); + if (!ud) + return NULL; + + ud->kqid = qid; + + ubifs_dqblk_insert(c, ud); + + return ud; +} + +/** + * ubifs_check_quota_file - check if quota file is valid for this format + * @sb: The superblock + * @type: Quota type + * + * We currently do not store any quota file on flash. It's completely in RAM and + * thus always valid. + */ +static int ubifs_check_quota_file(struct super_block *sb, int type) +{ + return 1; +} + +/** + * ubifs_read_file_info - read quota file info + * @sb: The superblock + * @type: Quota type + * + * We currently do not store any quota info on flash. Just fill in default + * values. + */ +static int ubifs_read_file_info(struct super_block *sb, int type) +{ + struct quota_info *dqopt = sb_dqopt(sb); + struct mem_dqinfo *info = &dqopt->info[type]; + + down_read(&dqopt->dqio_sem); + + /* + * Used space is stored as unsigned 64-bit value in bytes but + * quota core supports only signed 64-bit values so use that + * as a limit + */ + info->dqi_max_spc_limit = 0x7fffffffffffffffLL; /* 2^63-1 */ + info->dqi_max_ino_limit = 0x7fffffffffffffffLL; + info->dqi_bgrace = 0; + info->dqi_igrace = 0; + info->dqi_flags = 0; + + up_read(&dqopt->dqio_sem); + + return 0; +} + +/** + * ubifs_write_file_info - write quota file to device + * @sb: The superblock + * @type: Quota type + * + * We currently do not store any quota file on flash. Nothing to do here. + */ +static int ubifs_write_file_info(struct super_block *sb, int type) +{ + return 0; +} + +/** + * ubifs_read_dquot - read dquot from device + * @dquot: The dquot entry to read + * + * For us this means finding the entry in the dquot tree. + */ +static int ubifs_read_dquot(struct dquot *dquot) +{ + struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + struct ubifs_info *c = dquot->dq_sb->s_fs_info; + struct ubifs_dqblk *ud; + int ret = 0; + + down_read(&dqopt->dqio_sem); + + ud = ubifs_dqblk_find(c, dquot->dq_id); + if (ud) + dquot->dq_dqb = ud->dqblk; + else + ret = -ENOENT; + + up_read(&dqopt->dqio_sem); + + return 0; +} + +/** + * ubifs_write_dquot - write dquot to device + * @dquot: The dquot entry to read + * + * For us this means finding or creating the entry in the dquot tree and setting + * it to the dquots contents. + */ +static int ubifs_write_dquot(struct dquot *dquot) +{ + struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + struct ubifs_info *c = dquot->dq_sb->s_fs_info; + int ret = 0; + struct ubifs_dqblk *ud; + + down_write(&dqopt->dqio_sem); + + ud = ubifs_dqblk_get(c, dquot->dq_id); + if (!ud) { + ret = -ENOMEM; + goto out; + } + + ud->dqblk = dquot->dq_dqb; + +out: + up_write(&dqopt->dqio_sem); + + return ret; +} + +/** + * ubifs_release_dquot - release memory associated to a dquot entry + * @dquot: The dquot entry + * + * Nothing to do here, we didn't allocate anything. Our data is freed at unmount + * time. + */ +static int ubifs_release_dquot(struct dquot *dquot) +{ + return 0; +} + +/** + * ubifs_free_file_info - free memory allocated during reading the file info + * @sb: The superblock + * @type: Quota type + * + * Nothing to do here. + */ +static int ubifs_free_file_info(struct super_block *sb, int type) +{ + return 0; +} + +static int ubifs_get_next_id(struct super_block *sb, struct kqid *qid) +{ + struct quota_info *dqopt = sb_dqopt(sb); + struct ubifs_info *c = sb->s_fs_info; + struct ubifs_dqblk *ud; + int ret = 0; + + down_read(&dqopt->dqio_sem); + + ud = ubifs_dqblk_find_next(c, *qid); + if (!ud) { + ret = -ENOENT; + goto out; + } + + *qid = ud->kqid; +out: + up_read(&dqopt->dqio_sem); + + return ret; +} + +static const struct quota_format_ops ubifs_format_ops = { + .check_quota_file = ubifs_check_quota_file, + .read_file_info = ubifs_read_file_info, + .write_file_info = ubifs_write_file_info, + .free_file_info = ubifs_free_file_info, + .read_dqblk = ubifs_read_dquot, + .commit_dqblk = ubifs_write_dquot, + .release_dqblk = ubifs_release_dquot, + .get_next_id = ubifs_get_next_id, +}; + +/** + * add_inode_quota - read quota informations for an inode + * @c: UBIFS file-system description object + * @zbr: The zbranch to read the inode from + * + * This reads the inode as referred to by @zbr from the medium and + * extracts the quota relevant informations. Returns 0 for success + * or a negative error code otherwise. + */ +static int add_inode_quota(struct ubifs_info *c, struct ubifs_zbranch *zbr) +{ + struct ubifs_ino_node *ino; + int err, type = key_type(c, &zbr->key); + struct kqid qid[MAXQUOTAS]; + kprojid_t kprojid; + kgid_t kgid; + kuid_t kuid; + int i; + + if (type != UBIFS_INO_KEY) { + ubifs_err(c, "%s called on non INO node %d", __func__, type); + return 0; + } + + if (zbr->len < UBIFS_CH_SZ) { + ubifs_err(c, "bad leaf length %d (LEB %d:%d)", + zbr->len, zbr->lnum, zbr->offs); + return -EINVAL; + } + + ino = kmalloc(zbr->len, GFP_NOFS); + if (!ino) + return -ENOMEM; + + err = ubifs_tnc_read_node(c, zbr, ino); + if (err) { + ubifs_err(c, "cannot read leaf node at LEB %d:%d, error %d", + zbr->lnum, zbr->offs, err); + goto out_free; + } + + if (ino->flags & UBIFS_XATTR_FL) + goto out_free; + + kuid = make_kuid(&init_user_ns, le32_to_cpu(ino->uid)); + qid[USRQUOTA] = make_kqid_uid(kuid); + + kgid = make_kgid(&init_user_ns, le32_to_cpu(ino->gid)); + qid[GRPQUOTA] = make_kqid_gid(kgid); + + kprojid = make_kprojid(&init_user_ns, le32_to_cpu(ino->projid)); + qid[PRJQUOTA] = make_kqid_projid(kprojid); + + for (i = 0; i < UBIFS_MAXQUOTAS; i++) { + struct ubifs_dqblk *ud; + + if (!(c->quota_enable & (1 << type))) + continue; + + ud = ubifs_dqblk_get(c, qid[i]); + if (!ud) { + err = -ENOMEM; + goto out_free; + } + + if (S_ISREG(le32_to_cpu(ino->mode))) + ud->dqblk.dqb_curspace += le64_to_cpu(ino->size); + ud->dqblk.dqb_curinodes++; + } + + err = 0; + +out_free: + kfree(ino); + + return err; +} + +/** + * get_next_parent_inum - get the next inum + * @c: UBIFS file-system description object + * @znode: The znode to start searching from + * @inum: The next inum returned here + * + * Helper function for ubifs_quota_walk_index(). If we know the next inum we + * find up the tree is still the same as we just handled we do not have to walk + * down the tree but can skip these branches. Returns 0 for success or -ENOENT + * when we can't go further to the upper-right but hit the root node instead. + */ +static int get_next_parent_inum(struct ubifs_info *c, struct ubifs_znode *znode, + ino_t *inum) +{ + struct ubifs_znode *zp; + + while (1) { + int nn; + + zp = znode->parent; + if (!zp) + return -ENOENT; + + nn = znode->iip + 1; + znode = zp; + + if (nn < znode->child_cnt) { + *inum = key_inum(c, &znode->zbranch[nn].key); + return 0; + } + } +} + +/** + * ubifs_quota_walk_index - Collect quota info + * @c: UBIFS file-system description object + * + * This function walks the whole index and collects the quota usage information + * for all inodes. Returns 0 for success or a negative error code otherwise. + */ +static int ubifs_quota_walk_index(struct ubifs_info *c) +{ + int err; + struct ubifs_znode *znode; + int i, nn = 0; + ino_t inum = 0, pinum; + + if (!c->zroot.znode) { + c->zroot.znode = ubifs_load_znode(c, &c->zroot, NULL, 0); + if (IS_ERR(c->zroot.znode)) { + err = PTR_ERR(c->zroot.znode); + c->zroot.znode = NULL; + return err; + } + } + + znode = c->zroot.znode; + + while (1) { + while (znode->level != 0) { + znode = ubifs_get_znode(c, znode, nn); + if (IS_ERR(znode)) + return PTR_ERR(znode); + nn = 0; + } + + for (i = 0; i < znode->child_cnt; i++) { + if (inum == key_inum(c, &znode->zbranch[i].key)) + continue; + + add_inode_quota(c, &znode->zbranch[i]); + inum = key_inum(c, &znode->zbranch[i].key); + } + + while (1) { + struct ubifs_znode *zp; + + zp = znode->parent; + if (!zp) + return 0; + + nn = znode->iip + 1; + znode = zp; + + err = get_next_parent_inum(c, znode, &pinum); + + /* + * Optimization: When the next parent node is still for + * the inode we just handled we can skip parsing our + * children. + */ + if (!err && pinum == inum) + continue; + + /* + * Optimization: We can skip scanning all child nodes + * which are for the same inode as we already looked at. + */ + while (nn < znode->child_cnt - 1 && + inum == key_inum(c, &znode->zbranch[nn + 1].key)) + nn++; + + if (nn < znode->child_cnt) + break; + } + } +} + +/** + * ubifs_enable_quotas - enable quota + * @c: UBIFS file-system description object + * + * Enable usage tracking for all quota types. + */ +int ubifs_enable_quotas(struct ubifs_info *c) +{ + struct super_block *sb = c->vfs_sb; + struct quota_info *dqopt = sb_dqopt(sb); + int type, ret; + + if (!c->quota_enable) + return 0; + + dqopt->flags |= DQUOT_QUOTA_SYS_FILE | DQUOT_NOLIST_DIRTY; + + for (type = 0; type < UBIFS_MAXQUOTAS; type++) { + if (!(c->quota_enable & (1 << type))) + continue; + + ret = dquot_load_quota_sb(sb, type, QFMT_UBIFS, + DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); + if (ret) + goto out_quota_off; + + c->dqblk_tree[type] = RB_ROOT; + } + + return ubifs_quota_walk_index(c); + +out_quota_off: + ubifs_disable_quotas(c); + + return ret; +} + +/** + * ubifs_disable_quotas - disable quota + * @c: UBIFS file-system description object + * + * Disable quota for UBFIS. + */ +void ubifs_disable_quotas(struct ubifs_info *c) +{ + struct rb_node *n; + struct ubifs_dqblk *ud; + int type; + + if (!c->quota_enable) + return; + + dquot_disable(c->vfs_sb, -1, DQUOT_USAGE_ENABLED | DQUOT_LIMITS_ENABLED); + + for (type = 0; type < UBIFS_MAXQUOTAS; type++) { + while ((n = rb_first(&c->dqblk_tree[type]))) { + ud = rb_entry(n, struct ubifs_dqblk, rb); + rb_erase(n, &c->dqblk_tree[type]); + kfree(ud); + } + } +} + +static int ubifs_get_projid(struct inode *inode, kprojid_t *projid) +{ + struct ubifs_inode *ui = ubifs_inode(inode); + + *projid = ui->projid; + + return 0; +} + +static const struct dquot_operations ubifs_dquot_operations = { + .write_dquot = dquot_commit, + .acquire_dquot = dquot_acquire, + .release_dquot = dquot_release, + .mark_dirty = dquot_mark_dquot_dirty, + .write_info = dquot_commit_info, + .alloc_dquot = dquot_alloc, + .destroy_dquot = dquot_destroy, + .get_next_id = dquot_get_next_id, + .get_projid = ubifs_get_projid, +}; + +static const struct quotactl_ops ubifs_quotactl_ops = { + .get_state = dquot_get_state, + .set_info = dquot_set_dqinfo, + .get_dqblk = dquot_get_dqblk, + .set_dqblk = dquot_set_dqblk, + .get_nextdqblk = dquot_get_next_dqblk, +}; + +static struct quota_format_type ubifs_quota_format = { + .qf_fmt_id = QFMT_UBIFS, + .qf_ops = &ubifs_format_ops, + .qf_owner = THIS_MODULE +}; + +int ubifs_register_quota_format(void) +{ + return register_quota_format(&ubifs_quota_format); +} + +void ubifs_unregister_quota_format(void) +{ + return unregister_quota_format(&ubifs_quota_format); +} + +/** + * ubifs_init_quota - init quota ops for UBIFS + * @c: UBIFS file-system description object + * + * This inits the quota operations for UBIFS + */ +void ubifs_init_quota(struct ubifs_info *c) +{ + struct super_block *sb = c->vfs_sb; + + if (!c->quota_enable) + return; + + sb->dq_op = &ubifs_dquot_operations; + sb->s_qcop = &ubifs_quotactl_ops; + sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ; +} diff --git a/fs/ubifs/super.c b/fs/ubifs/super.c index 38322b2df548..4106ab9ba713 100644 --- a/fs/ubifs/super.c +++ b/fs/ubifs/super.c @@ -169,6 +169,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum) switch (inode->i_mode & S_IFMT) { case S_IFREG: + inode_set_bytes(inode, ino->size); inode->i_mapping->a_ops = &ubifs_file_address_operations; inode->i_op = &ubifs_file_inode_operations; inode->i_fop = &ubifs_file_operations; @@ -372,6 +373,7 @@ static void ubifs_evict_inode(struct inode *inode) if (is_bad_inode(inode)) goto out; + dquot_initialize(inode); ui->ui_size = inode->i_size = 0; err = ubifs_jnl_delete_inode(c, inode); if (err) @@ -381,7 +383,7 @@ static void ubifs_evict_inode(struct inode *inode) */ ubifs_err(c, "can't delete inode %lu, error %d", inode->i_ino, err); - + dquot_free_inode(inode); out: if (ui->dirty) ubifs_release_dirty_inode_budget(c, ui); @@ -391,6 +393,7 @@ static void ubifs_evict_inode(struct inode *inode) smp_wmb(); } done: + dquot_drop(inode); clear_inode(inode); fscrypt_put_encryption_info(inode); } @@ -453,6 +456,13 @@ static int ubifs_show_options(struct seq_file *s, struct dentry *root) else if (c->mount_opts.chk_data_crc == 1) seq_puts(s, ",no_chk_data_crc"); + if (c->quota_enable & (1 << USRQUOTA)) + seq_puts(s, ",usrquota"); + if (c->quota_enable & (1 << GRPQUOTA)) + seq_puts(s, ",grpquota"); + if (c->quota_enable & (1 << PRJQUOTA)) + seq_puts(s, ",prjquota"); + if (c->mount_opts.override_compr) { seq_printf(s, ",compr=%s", ubifs_compr_name(c, c->mount_opts.compr_type)); @@ -947,6 +957,29 @@ static int check_volume_empty(struct ubifs_info *c) return 0; } +#ifdef CONFIG_QUOTA +static struct dquot **ubifs_get_dquots(struct inode *inode) +{ + return ubifs_inode(inode)->i_dquot; +} + +static ssize_t ubifs_quota_read(struct super_block *sb, int type, char *data, + size_t len, loff_t off) +{ + BUG(); + + return 0; +} + +static ssize_t ubifs_quota_write(struct super_block *sb, int type, const char *data, + size_t len, loff_t off) +{ + BUG(); + + return 0; +} +#endif + /* * UBIFS mount options. * @@ -970,6 +1003,9 @@ enum { Opt_chk_data_crc, Opt_no_chk_data_crc, Opt_override_compr, + Opt_usrquota, + Opt_grpquota, + Opt_prjquota, Opt_assert, Opt_auth_key, Opt_auth_hash_name, @@ -985,6 +1021,9 @@ static const match_table_t tokens = { {Opt_chk_data_crc, "chk_data_crc"}, {Opt_no_chk_data_crc, "no_chk_data_crc"}, {Opt_override_compr, "compr=%s"}, + {Opt_usrquota, "usrquota"}, + {Opt_grpquota, "grpquota"}, + {Opt_prjquota, "prjquota"}, {Opt_auth_key, "auth_key=%s"}, {Opt_auth_hash_name, "auth_hash_name=%s"}, {Opt_ignore, "ubi=%s"}, @@ -1112,6 +1151,23 @@ static int ubifs_parse_options(struct ubifs_info *c, char *options, kfree(act); break; } +#ifdef CONFIG_QUOTA + case Opt_usrquota: + c->quota_enable |= 1 << USRQUOTA; + break; + case Opt_grpquota: + c->quota_enable |= 1 << GRPQUOTA; + break; + case Opt_prjquota: + c->quota_enable |= 1 << PRJQUOTA; + break; +#else + case Opt_usrquota: + case Opt_grpquota: + case Opt_prjquota: + ubifs_err(c, "quota operations not supported"); + break; +#endif case Opt_auth_key: if (!is_remount) { c->auth_key_name = kstrdup(args[0].from, @@ -1841,6 +1897,7 @@ static int ubifs_remount_rw(struct ubifs_info *c) */ err = dbg_check_space_info(c); } + c->vfs_sb->s_flags &= ~SB_RDONLY; mutex_unlock(&c->umount_mutex); return err; @@ -1910,6 +1967,7 @@ static void ubifs_remount_ro(struct ubifs_info *c) err = dbg_check_space_info(c); if (err) ubifs_ro_mode(c, err); + c->vfs_sb->s_flags |= SB_RDONLY; mutex_unlock(&c->umount_mutex); } @@ -1920,6 +1978,8 @@ static void ubifs_put_super(struct super_block *sb) ubifs_msg(c, "un-mount UBI device %d", c->vi.ubi_num); + ubifs_disable_quotas(c); + /* * The following asserts are only valid if there has not been a failure * of the media. For example, there will be dirty inodes if we failed @@ -2017,11 +2077,17 @@ static int ubifs_remount_fs(struct super_block *sb, int *flags, char *data) err = ubifs_remount_rw(c); if (err) return err; + err = dquot_resume(sb, -1); + if (err) + return err; } else if (!c->ro_mount && (*flags & SB_RDONLY)) { if (c->ro_error) { ubifs_msg(c, "cannot re-mount R/O due to prior errors"); return -EROFS; } + err = dquot_suspend(sb, -1); + if (err) + return err; ubifs_remount_ro(c); } @@ -2053,6 +2119,11 @@ const struct super_operations ubifs_super_operations = { .remount_fs = ubifs_remount_fs, .show_options = ubifs_show_options, .sync_fs = ubifs_sync_fs, +#ifdef CONFIG_QUOTA + .get_dquots = ubifs_get_dquots, + .quota_read = ubifs_quota_read, + .quota_write = ubifs_quota_write, +#endif }; /** @@ -2213,6 +2284,8 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) sb->s_xattr = ubifs_xattr_handlers; fscrypt_set_ops(sb, &ubifs_crypt_operations); + ubifs_init_quota(c); + mutex_lock(&c->umount_mutex); err = mount_ubifs(c); if (err) { @@ -2227,6 +2300,10 @@ static int ubifs_fill_super(struct super_block *sb, void *data, int silent) goto out_umount; } + err = ubifs_enable_quotas(c); + if (err) + goto out_umount; + sb->s_root = d_make_root(root); if (!sb->s_root) { err = -ENOMEM; @@ -2434,6 +2511,10 @@ static int __init ubifs_init(void) dbg_debugfs_init(); + err = ubifs_register_quota_format(); + if (err) + goto out_compressors; + err = register_filesystem(&ubifs_fs_type); if (err) { pr_err("UBIFS error (pid %d): cannot register file system, error %d", @@ -2444,6 +2525,8 @@ static int __init ubifs_init(void) out_dbg: dbg_debugfs_exit(); + ubifs_unregister_quota_format(); +out_compressors: ubifs_compressors_exit(); out_shrinker: unregister_shrinker(&ubifs_shrinker_info); @@ -2469,6 +2552,7 @@ static void __exit ubifs_exit(void) */ rcu_barrier(); kmem_cache_destroy(ubifs_inode_slab); + ubifs_unregister_quota_format(); unregister_filesystem(&ubifs_fs_type); } module_exit(ubifs_exit); diff --git a/fs/ubifs/ubifs.h b/fs/ubifs/ubifs.h index 1f03f88017ed..6d91427daad7 100644 --- a/fs/ubifs/ubifs.h +++ b/fs/ubifs/ubifs.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -157,6 +158,8 @@ #define UBIFS_DEF_PROJID 0 +#define UBIFS_MAXQUOTAS 3 + /* * Lockdep classes for UBIFS inode @ui_mutex. */ @@ -416,6 +419,9 @@ struct ubifs_inode { loff_t synced_i_size; loff_t ui_size; int flags; +#ifdef CONFIG_QUOTA + struct dquot *i_dquot[UBIFS_MAXQUOTAS]; +#endif kprojid_t projid; pgoff_t last_page_read; pgoff_t read_in_a_row; @@ -1045,6 +1051,7 @@ struct ubifs_debug_info; * @rw_incompat: the media is not R/W compatible * @assert_action: action to take when a ubifs_assert() fails * @authenticated: flag indigating the FS is mounted in authenticated mode + * @quota_enable: If true, quota is enabled on this filesystem * * @tnc_mutex: protects the Tree Node Cache (TNC), @zroot, @cnext, @enext, and * @calc_idx_sz @@ -1386,6 +1393,9 @@ struct ubifs_info { struct ubi_device_info di; struct ubi_volume_info vi; + unsigned int quota_enable; + struct rb_root dqblk_tree[UBIFS_MAXQUOTAS]; + struct rb_root orph_tree; struct list_head orph_list; struct list_head orph_new; @@ -2106,6 +2116,33 @@ int ubifs_decrypt(const struct inode *inode, struct ubifs_data_node *dn, extern const struct fscrypt_operations ubifs_crypt_operations; +/* quota.c */ +#ifdef CONFIG_QUOTA +int ubifs_register_quota_format(void); +void ubifs_unregister_quota_format(void); +void ubifs_init_quota(struct ubifs_info *c); +int ubifs_enable_quotas(struct ubifs_info *c); +void ubifs_disable_quotas(struct ubifs_info *c); +#else +static inline int ubifs_register_quota_format(void) +{ + return 0; +} +static inline void ubifs_unregister_quota_format(void) +{ +} +static inline void ubifs_init_quota(struct ubifs_info *c) +{ +} +static inline int ubifs_enable_quotas(struct ubifs_info *c) +{ + return 0; +} +static inline void ubifs_disable_quotas(struct ubifs_info *c) +{ +} +#endif + /* Normal UBIFS messages */ __printf(2, 3) void ubifs_msg(const struct ubifs_info *c, const char *fmt, ...); diff --git a/fs/ubifs/xattr.c b/fs/ubifs/xattr.c index 6b1e9830b274..7fdfc485e593 100644 --- a/fs/ubifs/xattr.c +++ b/fs/ubifs/xattr.c @@ -64,6 +64,9 @@ enum { static const struct inode_operations empty_iops; static const struct file_operations empty_fops; +struct inode *ubifs_new_xattr_inode(struct ubifs_info *c, struct inode *dir, + umode_t mode); + /** * create_xattr - create an extended attribute. * @c: UBIFS file-system description object @@ -110,7 +113,7 @@ static int create_xattr(struct ubifs_info *c, struct inode *host, if (err) return err; - inode = ubifs_new_inode(c, host, S_IFREG | S_IRWXUGO); + inode = ubifs_new_xattr_inode(c, host, S_IFREG | S_IRWXUGO); if (IS_ERR(inode)) { err = PTR_ERR(inode); goto out_budg; diff --git a/include/uapi/linux/quota.h b/include/uapi/linux/quota.h index f17c9636a859..0ddd5f7326a6 100644 --- a/include/uapi/linux/quota.h +++ b/include/uapi/linux/quota.h @@ -77,6 +77,7 @@ #define QFMT_VFS_V0 2 #define QFMT_OCFS2 3 #define QFMT_VFS_V1 4 +#define QFMT_UBIFS 5 /* Size of block in which space limits are passed through the quota * interface */