From patchwork Tue Oct 31 19:31:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 160314 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b90f:0:b0:403:3b70:6f57 with SMTP id t15csp470752vqg; Tue, 31 Oct 2023 12:35:10 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFEfEH0dqVsFxl++G3jL0OYO147N/OYGeR6jhGs5pvbzJBvPTWMS5thptzikQXDSIuLQ9rq X-Received: by 2002:a17:90b:120a:b0:27d:9f6:47a3 with SMTP id gl10-20020a17090b120a00b0027d09f647a3mr12781013pjb.31.1698780910064; Tue, 31 Oct 2023 12:35:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1698780910; cv=none; d=google.com; s=arc-20160816; b=UV8W+sA5k8RlYR2vqEfv2/kOv8js4PG6UxRlwfGFGtaCEoHYGpZgA9A9lSzttKmVGq f0MnSiwBWsjf3pKynAQRDbmWx6CuYdkFPCxlR3nC+Icsp5Fvq7r5X9WKEEF4v0dl2ZPr OB2WOHVyKmTosxkm1E4nqqbEW36Y7k6sp+XHOD1RgLbWCs7igm9obs/Pgkvj7L/mfLrO mz1pmELf2m6IKelf5b2LWbQ0WvDH5AtcnXdtQVdbT9amuO5E+HLZMo60CwauHvqcYB/z c5/f987cgGuyV+B18jqUKKF4HhIIveLFsqmZ+bpF75rL2SzRzuAhTiOpd/bn8sNajHAl qzfw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:references:subject:cc:to:from:date :user-agent:message-id; bh=MQR5VwKw0NAhs0YrmKEIwaU1UlIUHe1DuSWIYpvy4ow=; fh=23HZD1H2eTFku4IoURxcqGy1ybiazb0E70TBt1XO3Qk=; b=zVDPkZ61TnUWnOiEhPD8Y7t+mH8HHPdA7/TSY2iMvjtUnrcUVR8ynIZmjUj5jc9VJ5 mE3TpJzrZYn72X6pqxkypHot01G/GZQIYzqW13J+U8D++Thfzu+FgleTznYMKtCFTgTq Fi8/bM8wdVqww38E3XlEwRd4T8DSItHmEuA1qOMXc4B/AFGDOwvYXWBfW0yVlJxJjg4J vtb8xM3fcoxldtWL9hZdjSJUrnrZ5Bs+SNzTRtQCdF/aG2Y+us6KhyH1fjOdp8c+pQ7l kQ+QfLz4faOng+m3HcjpkP3eRS9jbaokegu49UzVjvw4VQFsWIn5Z5ld47IEUN9KjyoS 2BHg== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:6 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from pete.vger.email (pete.vger.email. [2620:137:e000::3:6]) by mx.google.com with ESMTPS id y3-20020a17090a86c300b002801ffd08f8si1356713pjv.51.2023.10.31.12.35.09 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 12:35:10 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:6 as permitted sender) client-ip=2620:137:e000::3:6; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::3:6 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by pete.vger.email (Postfix) with ESMTP id B90358029304; Tue, 31 Oct 2023 12:35:06 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at pete.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234946AbjJaTeh (ORCPT + 33 others); Tue, 31 Oct 2023 15:34:37 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48540 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234415AbjJaTec (ORCPT ); Tue, 31 Oct 2023 15:34:32 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2A1D9F3 for ; Tue, 31 Oct 2023 12:34:30 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id A0DACC433CC; Tue, 31 Oct 2023 19:34:29 +0000 (UTC) Received: from rostedt by gandalf with local (Exim 4.96) (envelope-from ) id 1qxuVQ-00EK8x-1j; Tue, 31 Oct 2023 15:34:28 -0400 Message-ID: <20231031193428.347017769@goodmis.org> User-Agent: quilt/0.66 Date: Tue, 31 Oct 2023 15:31:11 -0400 From: Steven Rostedt To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org Cc: Masami Hiramatsu , Mark Rutland , Andrew Morton , "Arnd Bergmann" , "Ajay Kaher" , Linux Kernel Functional Testing , Naresh Kamboju , Beau Belgrave Subject: [PATCH v4 2/3] eventfs: Test for ei->is_freed when accessing ei->dentry References: <20231031193109.018322397@goodmis.org> MIME-Version: 1.0 X-Spam-Status: No, score=-0.8 required=5.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on pete.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (pete.vger.email [0.0.0.0]); Tue, 31 Oct 2023 12:35:06 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1781300891117612147 X-GMAIL-MSGID: 1781300891117612147 From: "Steven Rostedt (Google)" The eventfs_inode (ei) is protected by SRCU, but the ei->dentry is not. It is protected by the eventfs_mutex. Anytime the eventfs_mutex is released, and access to the ei->dentry needs to be done, it should first check if ei->is_freed is set under the eventfs_mutex. If it is, then the ei->dentry is invalid and must not be used. The ei->dentry must only be accessed under the eventfs_mutex and after checking if ei->is_freed is set. When the ei is being freed, it will (under the eventfs_mutex) set is_freed and at the same time move the dentry to a free list to be cleared after the eventfs_mutex is released. This means that any access to the ei->dentry must check first if ei->is_freed is set, because if it is, then the dentry is on its way to be freed. Also add comments to describe this better. Link: https://lore.kernel.org/all/CA+G9fYt6pY+tMZEOg=SoEywQOe19fGP3uR15SGowkdK+_X85Cg@mail.gmail.com/ Link: https://lore.kernel.org/all/CA+G9fYuDP3hVQ3t7FfrBAjd_WFVSurMgCepTxunSJf=MTe=6aA@mail.gmail.com/ Cc: Mark Rutland Cc: "Arnd Bergmann" Cc: "Ajay Kaher" Cc: Andrew Morton Fixes: 5790b1fb3d672 ("eventfs: Remove eventfs_file and just use eventfs_inode") Reported-by: Linux Kernel Functional Testing Reported-by: Naresh Kamboju Reported-by: Beau Belgrave Reviewed-by: Masami Hiramatsu (Google) Tested-by: Linux Kernel Functional Testing Tested-by: Naresh Kamboju Tested-by: Beau Belgrave Signed-off-by: Steven Rostedt (Google) --- Changes since v2: https://lore.kernel.org/linux-trace-kernel/20231028164650.4f5ea18a@rorschach.local.home/ - Separated out free_ei() into its own patch fs/tracefs/event_inode.c | 50 +++++++++++++++++++++++++++++++++++----- fs/tracefs/internal.h | 3 ++- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 76323f48d5f0..362a2dba82c2 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -24,7 +24,20 @@ #include #include "internal.h" +/* + * eventfs_mutex protects the eventfs_inode (ei) dentry. Any access + * to the ei->dentry must be done under this mutex and after checking + * if ei->is_freed is not set. The ei->dentry is released under the + * mutex at the same time ei->is_freed is set. If ei->is_freed is set + * then the ei->dentry is invalid. + */ static DEFINE_MUTEX(eventfs_mutex); + +/* + * The eventfs_inode (ei) itself is protected by SRCU. It is released from + * its parent's list and will have is_freed set (under eventfs_mutex). + * After the SRCU grace period is over, the ei may be freed. + */ DEFINE_STATIC_SRCU(eventfs_srcu); static struct dentry *eventfs_root_lookup(struct inode *dir, @@ -239,6 +252,10 @@ create_file_dentry(struct eventfs_inode *ei, struct dentry **e_dentry, bool invalidate = false; mutex_lock(&eventfs_mutex); + if (ei->is_freed) { + mutex_unlock(&eventfs_mutex); + return NULL; + } /* If the e_dentry already has a dentry, use it */ if (*e_dentry) { /* lookup does not need to up the ref count */ @@ -312,6 +329,8 @@ static void eventfs_post_create_dir(struct eventfs_inode *ei) struct eventfs_inode *ei_child; struct tracefs_inode *ti; + lockdep_assert_held(&eventfs_mutex); + /* srcu lock already held */ /* fill parent-child relation */ list_for_each_entry_srcu(ei_child, &ei->children, list, @@ -325,6 +344,7 @@ static void eventfs_post_create_dir(struct eventfs_inode *ei) /** * create_dir_dentry - Create a directory dentry for the eventfs_inode + * @pei: The eventfs_inode parent of ei. * @ei: The eventfs_inode to create the directory for * @parent: The dentry of the parent of this directory * @lookup: True if this is called by the lookup code @@ -332,12 +352,17 @@ static void eventfs_post_create_dir(struct eventfs_inode *ei) * This creates and attaches a directory dentry to the eventfs_inode @ei. */ static struct dentry * -create_dir_dentry(struct eventfs_inode *ei, struct dentry *parent, bool lookup) +create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei, + struct dentry *parent, bool lookup) { bool invalidate = false; struct dentry *dentry = NULL; mutex_lock(&eventfs_mutex); + if (pei->is_freed || ei->is_freed) { + mutex_unlock(&eventfs_mutex); + return NULL; + } if (ei->dentry) { /* If the dentry already has a dentry, use it */ dentry = ei->dentry; @@ -440,7 +465,7 @@ static struct dentry *eventfs_root_lookup(struct inode *dir, */ mutex_lock(&eventfs_mutex); ei = READ_ONCE(ti->private); - if (ei) + if (ei && !ei->is_freed) ei_dentry = READ_ONCE(ei->dentry); mutex_unlock(&eventfs_mutex); @@ -454,7 +479,7 @@ static struct dentry *eventfs_root_lookup(struct inode *dir, if (strcmp(ei_child->name, name) != 0) continue; ret = simple_lookup(dir, dentry, flags); - create_dir_dentry(ei_child, ei_dentry, true); + create_dir_dentry(ei, ei_child, ei_dentry, true); created = true; break; } @@ -588,7 +613,7 @@ static int dcache_dir_open_wrapper(struct inode *inode, struct file *file) list_for_each_entry_srcu(ei_child, &ei->children, list, srcu_read_lock_held(&eventfs_srcu)) { - d = create_dir_dentry(ei_child, parent, false); + d = create_dir_dentry(ei, ei_child, parent, false); if (d) { ret = add_dentries(&dentries, d, cnt); if (ret < 0) @@ -705,12 +730,20 @@ struct eventfs_inode *eventfs_create_dir(const char *name, struct eventfs_inode ei->nr_entries = size; ei->data = data; INIT_LIST_HEAD(&ei->children); + INIT_LIST_HEAD(&ei->list); mutex_lock(&eventfs_mutex); - list_add_tail(&ei->list, &parent->children); - ei->d_parent = parent->dentry; + if (!parent->is_freed) { + list_add_tail(&ei->list, &parent->children); + ei->d_parent = parent->dentry; + } mutex_unlock(&eventfs_mutex); + /* Was the parent freed? */ + if (list_empty(&ei->list)) { + free_ei(ei); + ei = NULL; + } return ei; } @@ -884,6 +917,11 @@ void eventfs_remove_dir(struct eventfs_inode *ei) for (i = 0; i < ei->nr_entries; i++) unhook_dentry(&ei->d_children[i], &dentry_list); unhook_dentry(&ei->dentry, &dentry_list); + /* + * Note, ei->is_freed is a union along with ei->rcu + * and ei->del_list. When the ei is added to either + * of those lists, it automatically sets ei->is_freed. + */ call_srcu(&eventfs_srcu, &ei->rcu, free_rcu_ei); } mutex_unlock(&eventfs_mutex); diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h index 64fde9490f52..21a1fa682b74 100644 --- a/fs/tracefs/internal.h +++ b/fs/tracefs/internal.h @@ -30,7 +30,7 @@ struct eventfs_inode { const struct eventfs_entry *entries; const char *name; struct list_head children; - struct dentry *dentry; + struct dentry *dentry; /* Check is_freed to access */ struct dentry *d_parent; struct dentry **d_children; void *data; @@ -39,6 +39,7 @@ struct eventfs_inode { * @del_list: list of eventfs_inode to delete * @rcu: eventfs_inode to delete in RCU * @is_freed: node is freed if one of the above is set + * Note if is_freed is set, then dentry is corrupted. */ union { struct list_head del_list; From patchwork Tue Oct 31 19:31:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Steven Rostedt X-Patchwork-Id: 160315 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b90f:0:b0:403:3b70:6f57 with SMTP id t15csp470797vqg; Tue, 31 Oct 2023 12:35:15 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFxKNbO7ci5mTMo44tCHFWwdZzozD9k6kKk7Q5gUfjDfHG5zhEV1sUY35Q40J8bmPQ6abDH X-Received: by 2002:a17:903:245:b0:1c3:6d97:e89e with SMTP id j5-20020a170903024500b001c36d97e89emr17429970plh.58.1698780915134; Tue, 31 Oct 2023 12:35:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1698780915; cv=none; d=google.com; s=arc-20160816; b=mG0+AY2eBs7At5acdTua76rwpoU3UJ22jk0a+lt7G6/ZJcKXKd2W+muunWALOCLEHL D487+Yk4CXrDji6a+/y9HrF9LZ9qXcNdBy2CRAstpkoqJFjHJN379Hwz3i/a9cZ3eHTd h+NyNBbvNXLyLBOBmA2V5vJqzG+vquro8PUK28av2Sze+z9Ohkw8qn4dS/HW7L7uOpJu uZasktAxL5MG+SQ87QgAPmrZUYdHLVbi2W4tOzLzz6Td0Ah7LnuldpGcyfIjcbU0Arbm 1uwO3iiJ8DEokYU5uF90zB/Kz3RV3ijOWaEhn7IW4SRCL4WZ/gNI+v+1MqvPOT2/E/wZ Jkmw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:mime-version:references:subject:cc:to:from:date :user-agent:message-id; bh=tAthvEw05fnRKVHesEKEI51BVMJq45IGrW9PN0LuNFo=; fh=GOzcny/+Yhxxe/LhYnYPHd+JVjDgZ9WgHyPLWbp+hjU=; b=l3zdDQJmAHDLjudNlSZ7gpSRKGm+9199pDnTW0/nGFyi51fXFYkw8G8JxldaLpY5Ym /GC9NcQbjKQshaeXfNRhZq3Ifm7WWxfZOq0nIsl7gw7q5PjDbiReNlApvD6ZiQyy1qEU LvaXRQgsC4C/S5me2sQvknNtEe0XjgeuAwauI/sn1neBD051qhK1DsQq+okzyFhsbU2H rYSsaRGLRYK4Z8tpKwlqIa3QZNTIxPmSnkuTkg1WjLDXYyqZpbpohwr31GRiarAGHWzb fv5+NwNBCAZY7reCAMohjtamBS4OIt9npvayaTpE4fq5bRacdjbs54i79Llx+m4nmQwK HCNA== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from agentk.vger.email (agentk.vger.email. [23.128.96.32]) by mx.google.com with ESMTPS id t10-20020a170902d28a00b001cc53dbf53dsi1341887plc.648.2023.10.31.12.35.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 31 Oct 2023 12:35:15 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) client-ip=23.128.96.32; Authentication-Results: mx.google.com; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.32 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org Received: from out1.vger.email (depot.vger.email [IPv6:2620:137:e000::3:0]) by agentk.vger.email (Postfix) with ESMTP id C94C780CA0AF; Tue, 31 Oct 2023 12:35:11 -0700 (PDT) X-Virus-Status: Clean X-Virus-Scanned: clamav-milter 0.103.10 at agentk.vger.email Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235192AbjJaTej (ORCPT + 33 others); Tue, 31 Oct 2023 15:34:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48544 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234491AbjJaTed (ORCPT ); Tue, 31 Oct 2023 15:34:33 -0400 Received: from smtp.kernel.org (relay.kernel.org [52.25.139.140]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 17D3BDA for ; Tue, 31 Oct 2023 12:34:30 -0700 (PDT) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9D225C433CB; Tue, 31 Oct 2023 19:34:29 +0000 (UTC) Received: from rostedt by gandalf with local (Exim 4.96) (envelope-from ) id 1qxuVQ-00EK9V-2P; Tue, 31 Oct 2023 15:34:28 -0400 Message-ID: <20231031193428.558586557@goodmis.org> User-Agent: quilt/0.66 Date: Tue, 31 Oct 2023 15:31:12 -0400 From: Steven Rostedt To: linux-kernel@vger.kernel.org, linux-trace-kernel@vger.kernel.org Cc: Masami Hiramatsu , Mark Rutland , Andrew Morton , Ajay Kaher Subject: [PATCH v4 3/3] eventfs: Save ownership and mode References: <20231031193109.018322397@goodmis.org> MIME-Version: 1.0 X-Spam-Status: No, score=-0.8 required=5.0 tests=HEADER_FROM_DIFFERENT_DOMAINS, MAILING_LIST_MULTI,SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on agentk.vger.email Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Greylist: Sender passed SPF test, not delayed by milter-greylist-4.6.4 (agentk.vger.email [0.0.0.0]); Tue, 31 Oct 2023 12:35:11 -0700 (PDT) X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1781300896713232415 X-GMAIL-MSGID: 1781300896713232415 From: "Steven Rostedt (Google)" Now that inodes and dentries are created on the fly, they are also reclaimed on memory pressure. Since the ownership and file mode are saved in the inode, if they are freed, any changes to the ownership and mode will be lost. To counter this, if the user changes the permissions or ownership, save them, and when creating the inodes again, restore those changes. Cc: Masami Hiramatsu Cc: Mark Rutland Cc: Ajay Kaher Signed-off-by: Steven Rostedt (Google) --- Changes since v3: https://lore.kernel.org/linux-trace-kernel/20231031113627.2edfa83f@gandalf.local.home - Just rebased as part of this patch series fs/tracefs/event_inode.c | 148 +++++++++++++++++++++++++++++++++++---- fs/tracefs/internal.h | 16 +++++ 2 files changed, 151 insertions(+), 13 deletions(-) diff --git a/fs/tracefs/event_inode.c b/fs/tracefs/event_inode.c index 362a2dba82c2..81e7ccef2783 100644 --- a/fs/tracefs/event_inode.c +++ b/fs/tracefs/event_inode.c @@ -40,6 +40,15 @@ static DEFINE_MUTEX(eventfs_mutex); */ DEFINE_STATIC_SRCU(eventfs_srcu); +/* Mode is unsigned short, use the upper bits for flags */ +enum { + EVENTFS_SAVE_MODE = BIT(16), + EVENTFS_SAVE_UID = BIT(17), + EVENTFS_SAVE_GID = BIT(18), +}; + +#define EVENTFS_MODE_MASK (EVENTFS_SAVE_MODE - 1) + static struct dentry *eventfs_root_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); @@ -47,8 +56,89 @@ static int dcache_dir_open_wrapper(struct inode *inode, struct file *file); static int dcache_readdir_wrapper(struct file *file, struct dir_context *ctx); static int eventfs_release(struct inode *inode, struct file *file); +static void update_attr(struct eventfs_attr *attr, struct iattr *iattr) +{ + unsigned int ia_valid = iattr->ia_valid; + + if (ia_valid & ATTR_MODE) { + attr->mode = (attr->mode & ~EVENTFS_MODE_MASK) | + (iattr->ia_mode & EVENTFS_MODE_MASK) | + EVENTFS_SAVE_MODE; + } + if (ia_valid & ATTR_UID) { + attr->mode |= EVENTFS_SAVE_UID; + attr->uid = iattr->ia_uid; + } + if (ia_valid & ATTR_GID) { + attr->mode |= EVENTFS_SAVE_GID; + attr->gid = iattr->ia_gid; + } +} + +static int eventfs_set_attr(struct mnt_idmap *idmap, struct dentry *dentry, + struct iattr *iattr) +{ + const struct eventfs_entry *entry; + struct eventfs_inode *ei; + const char *name; + int ret; + + mutex_lock(&eventfs_mutex); + ei = dentry->d_fsdata; + /* The LSB is set when the eventfs_inode is being freed */ + if (((unsigned long)ei & 1UL) || ei->is_freed) { + /* Do not allow changes if the event is about to be removed. */ + mutex_unlock(&eventfs_mutex); + return -ENODEV; + } + + /* Preallocate the children mode array if necessary */ + if (!(dentry->d_inode->i_mode & S_IFDIR)) { + if (!ei->entry_attrs) { + ei->entry_attrs = kzalloc(sizeof(*ei->entry_attrs) * ei->nr_entries, + GFP_KERNEL); + if (!ei->entry_attrs) { + ret = -ENOMEM; + goto out; + } + } + } + + ret = simple_setattr(idmap, dentry, iattr); + if (ret < 0) + goto out; + + /* + * If this is a dir, then update the ei cache, only the file + * mode is saved in the ei->m_children, and the ownership is + * determined by the parent directory. + */ + if (dentry->d_inode->i_mode & S_IFDIR) { + update_attr(&ei->attr, iattr); + + } else { + name = dentry->d_name.name; + + for (int i = 0; i < ei->nr_entries; i++) { + entry = &ei->entries[i]; + if (strcmp(name, entry->name) == 0) { + update_attr(&ei->entry_attrs[i], iattr); + break; + } + } + } + out: + mutex_unlock(&eventfs_mutex); + return ret; +} + static const struct inode_operations eventfs_root_dir_inode_operations = { .lookup = eventfs_root_lookup, + .setattr = eventfs_set_attr, +}; + +static const struct inode_operations eventfs_file_inode_operations = { + .setattr = eventfs_set_attr, }; static const struct file_operations eventfs_file_operations = { @@ -59,10 +149,30 @@ static const struct file_operations eventfs_file_operations = { .release = eventfs_release, }; +static void update_inode_attr(struct inode *inode, struct eventfs_attr *attr, umode_t mode) +{ + if (!attr) { + inode->i_mode = mode; + return; + } + + if (attr->mode & EVENTFS_SAVE_MODE) + inode->i_mode = attr->mode & EVENTFS_MODE_MASK; + else + inode->i_mode = mode; + + if (attr->mode & EVENTFS_SAVE_UID) + inode->i_uid = attr->uid; + + if (attr->mode & EVENTFS_SAVE_GID) + inode->i_gid = attr->gid; +} + /** * create_file - create a file in the tracefs filesystem * @name: the name of the file to create. * @mode: the permission that the file should have. + * @attr: saved attributes changed by user * @parent: parent dentry for this file. * @data: something that the caller will want to get to later on. * @fop: struct file_operations that should be used for this file. @@ -72,6 +182,7 @@ static const struct file_operations eventfs_file_operations = { * call. */ static struct dentry *create_file(const char *name, umode_t mode, + struct eventfs_attr *attr, struct dentry *parent, void *data, const struct file_operations *fop) { @@ -95,7 +206,10 @@ static struct dentry *create_file(const char *name, umode_t mode, if (unlikely(!inode)) return eventfs_failed_creating(dentry); - inode->i_mode = mode; + /* If the user updated the directory's attributes, use them */ + update_inode_attr(inode, attr, mode); + + inode->i_op = &eventfs_file_inode_operations; inode->i_fop = fop; inode->i_private = data; @@ -108,19 +222,19 @@ static struct dentry *create_file(const char *name, umode_t mode, /** * create_dir - create a dir in the tracefs filesystem - * @name: the name of the file to create. + * @ei: the eventfs_inode that represents the directory to create * @parent: parent dentry for this file. * * This function will create a dentry for a directory represented by * a eventfs_inode. */ -static struct dentry *create_dir(const char *name, struct dentry *parent) +static struct dentry *create_dir(struct eventfs_inode *ei, struct dentry *parent) { struct tracefs_inode *ti; struct dentry *dentry; struct inode *inode; - dentry = eventfs_start_creating(name, parent); + dentry = eventfs_start_creating(ei->name, parent); if (IS_ERR(dentry)) return dentry; @@ -128,7 +242,9 @@ static struct dentry *create_dir(const char *name, struct dentry *parent) if (unlikely(!inode)) return eventfs_failed_creating(dentry); - inode->i_mode = S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO; + /* If the user updated the directory's attributes, use them */ + update_inode_attr(inode, &ei->attr, S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO); + inode->i_op = &eventfs_root_dir_inode_operations; inode->i_fop = &eventfs_file_operations; @@ -146,6 +262,7 @@ static void free_ei(struct eventfs_inode *ei) { kfree_const(ei->name); kfree(ei->d_children); + kfree(ei->entry_attrs); kfree(ei); } @@ -231,7 +348,7 @@ void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry) /** * create_file_dentry - create a dentry for a file of an eventfs_inode * @ei: the eventfs_inode that the file will be created under - * @e_dentry: a pointer to the d_children[] of the @ei + * @idx: the index into the d_children[] of the @ei * @parent: The parent dentry of the created file. * @name: The name of the file to create * @mode: The mode of the file. @@ -244,10 +361,12 @@ void eventfs_set_ei_status_free(struct tracefs_inode *ti, struct dentry *dentry) * just do a dget() on it and return. Otherwise create the dentry and attach it. */ static struct dentry * -create_file_dentry(struct eventfs_inode *ei, struct dentry **e_dentry, +create_file_dentry(struct eventfs_inode *ei, int idx, struct dentry *parent, const char *name, umode_t mode, void *data, const struct file_operations *fops, bool lookup) { + struct eventfs_attr *attr = NULL; + struct dentry **e_dentry = &ei->d_children[idx]; struct dentry *dentry; bool invalidate = false; @@ -264,13 +383,18 @@ create_file_dentry(struct eventfs_inode *ei, struct dentry **e_dentry, mutex_unlock(&eventfs_mutex); return *e_dentry; } + + /* ei->entry_attrs are protected by SRCU */ + if (ei->entry_attrs) + attr = &ei->entry_attrs[idx]; + mutex_unlock(&eventfs_mutex); /* The lookup already has the parent->d_inode locked */ if (!lookup) inode_lock(parent->d_inode); - dentry = create_file(name, mode, parent, data, fops); + dentry = create_file(name, mode, attr, parent, data, fops); if (!lookup) inode_unlock(parent->d_inode); @@ -378,7 +502,7 @@ create_dir_dentry(struct eventfs_inode *pei, struct eventfs_inode *ei, if (!lookup) inode_lock(parent->d_inode); - dentry = create_dir(ei->name, parent); + dentry = create_dir(ei, parent); if (!lookup) inode_unlock(parent->d_inode); @@ -495,8 +619,7 @@ static struct dentry *eventfs_root_lookup(struct inode *dir, if (r <= 0) continue; ret = simple_lookup(dir, dentry, flags); - create_file_dentry(ei, &ei->d_children[i], - ei_dentry, name, mode, cdata, + create_file_dentry(ei, i, ei_dentry, name, mode, cdata, fops, true); break; } @@ -629,8 +752,7 @@ static int dcache_dir_open_wrapper(struct inode *inode, struct file *file) r = entry->callback(name, &mode, &cdata, &fops); if (r <= 0) continue; - d = create_file_dentry(ei, &ei->d_children[i], - parent, name, mode, cdata, fops, false); + d = create_file_dentry(ei, i, parent, name, mode, cdata, fops, false); if (d) { ret = add_dentries(&dentries, d, cnt); if (ret < 0) diff --git a/fs/tracefs/internal.h b/fs/tracefs/internal.h index 21a1fa682b74..1ec0d167542a 100644 --- a/fs/tracefs/internal.h +++ b/fs/tracefs/internal.h @@ -13,6 +13,18 @@ struct tracefs_inode { struct inode vfs_inode; }; +/* + * struct eventfs_attr - cache the mode and ownership of a eventfs entry + * @mode: saved mode plus flags of what is saved + * @uid: saved uid if changed + * @gid: saved gid if changed + */ +struct eventfs_attr { + int mode; + kuid_t uid; + kgid_t gid; +}; + /* * struct eventfs_inode - hold the properties of the eventfs directories. * @list: link list into the parent directory @@ -22,7 +34,9 @@ struct tracefs_inode { * @dentry: the dentry of the directory * @d_parent: pointer to the parent's dentry * @d_children: The array of dentries to represent the files when created + * @entry_attrs: Saved mode and ownership of the @d_children * @data: The private data to pass to the callbacks + * @attr: Saved mode and ownership of eventfs_inode itself * @nr_entries: The number of items in @entries */ struct eventfs_inode { @@ -33,6 +47,8 @@ struct eventfs_inode { struct dentry *dentry; /* Check is_freed to access */ struct dentry *d_parent; struct dentry **d_children; + struct eventfs_attr *entry_attrs; + struct eventfs_attr attr; void *data; /* * Union - used for deletion