From patchwork Sun Jan 19 15:12:07 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13944495 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 053384315F; Sun, 19 Jan 2025 15:12:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299558; cv=none; b=FttHGv7Xl5mmB5is+VvlxMKpUiptE0EZiaos23TmsaTT/d5e8c06/k9L6PFsLwemgS/MPpRSg2bSPgmjBffZVcJvzIQ2R3nlMTvKOeE3bm0/CJDsrCTeSzs2LVHSuRB7rePw/aWH9FFYPFpup+1HOt5afv4PEuWzR834a5jxC2M= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299558; c=relaxed/simple; bh=LXUMqhGpXyCk+mN3SeUyOyODLVWgqRr9V9axoWpO9Oc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=Ru2T9gSSD9BJujiH0J1ar7HQ8zNksvT995GCq3hDbKOiyCL/UXyVdzr43DEJj+2KFsf3j+vUD08qbqBiHkTL3401Yhzil4wgyrDkGnf/bOwyhJ5W2PEWcdELNSrF5O9p+yM7ue3VIMogpjnZ6+bvS7ygtXma34GB0roler/vFf4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=AiRajHNk; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="AiRajHNk" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1737299556; bh=LXUMqhGpXyCk+mN3SeUyOyODLVWgqRr9V9axoWpO9Oc=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=AiRajHNkbMqVl0ILKSACb0lj+X7khTaGL3t1KlMV6GZd4sV3N+h15rcRUih4h/6e8 6HE39ehG4A3q96yxLYgEQv1mYEYvC5mfsuvEIE1Qsxgdx7vYbViGOExMcZcsYFx5xj 8x1L4lEULH/vQj9CRW05cuLq83PYohfq92hWOVT0= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 1541E128056F; Sun, 19 Jan 2025 10:12:36 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id sakN7IG3IB1P; Sun, 19 Jan 2025 10:12:36 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 42E3812804E8; Sun, 19 Jan 2025 10:12:35 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v3 1/8] efivarfs: remove unused efi_varaible.Attributes and .kobj Date: Sun, 19 Jan 2025 10:12:07 -0500 Message-Id: <20250119151214.23562-2-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> References: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 These fields look to be remnants of older code: Attributes was likely meant to stash the variable attributes, but doesn't because we always read them from the variable store and kobj was likely left over from an older iteration of code where we manually created the objects instead of using a filesystem. Signed-off-by: James Bottomley --- fs/efivarfs/internal.h | 2 -- fs/efivarfs/super.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index 74f0602a9e01..64d15d1bb6bf 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -24,13 +24,11 @@ struct efivarfs_fs_info { struct efi_variable { efi_char16_t VariableName[EFI_VAR_NAME_LEN/sizeof(efi_char16_t)]; efi_guid_t VendorGuid; - __u32 Attributes; }; struct efivar_entry { struct efi_variable var; struct list_head list; - struct kobject kobj; }; int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index beba15673be8..d3c8528274aa 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -245,7 +245,7 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, inode_lock(inode); inode->i_private = entry; - i_size_write(inode, size + sizeof(entry->var.Attributes)); + i_size_write(inode, size + sizeof(__u32)); /* attributes + data */ inode_unlock(inode); d_add(dentry, inode); From patchwork Sun Jan 19 15:12:08 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13944496 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 100C61DF267; Sun, 19 Jan 2025 15:12:50 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299572; cv=none; b=L8PahL8c2ceU7AannlmR3s9BIiXd4oUY1YtyU1w5zmxtVhfANhEtXH2x4hsCe2OAE8Waw2z/vmkEfXYibxeVKCzJ2N3UiyEnFY1mkdaVGHcbe5gLyAZnfmfvGsfoh8pcdjidEH5Hi06J7h0BEB9U68oXoUi+YSPU0z1htIw0ikE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299572; c=relaxed/simple; bh=1zOgWcapBQJgcm45Fqy3RGNsrJnsNIwbYD2rxUWAOr0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=mPBQPgS6yoen+3nPmnk+aloE+bojA65IK8xcHnQm1l202tm4747BPypCjS0XsmzSEoAbexPjmw8IXZFuXQs8J3U8ZZLjFyANWwmOzU8YIevNfa6opRJ2tsqV9sY85jyzSLMJfiHSUAs9HCAtZ7bzYiokDHQhHrCqfMBfgXeoon0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=K4WPms49; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="K4WPms49" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1737299570; bh=1zOgWcapBQJgcm45Fqy3RGNsrJnsNIwbYD2rxUWAOr0=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=K4WPms49LUc5fkzLjkRLtOEzfEN3+bQZUJcvznxYYNkvofzm36jKVSPN/WYSoM4m2 YIOrRLj97GwQUEkEuWhWwsmfY0QRgjAG+91MwXYIelSNkt85+cA3+eobxRkCTXPe4L 3tOPa7iDYMZjif8ajAaVJtVH6eON5VITLTbeNakQ= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 4A551128056F; Sun, 19 Jan 2025 10:12:50 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id sClYeGBA7Ilh; Sun, 19 Jan 2025 10:12:50 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 8486312804E8; Sun, 19 Jan 2025 10:12:49 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v3 2/8] efivarfs: add helper to convert from UC16 name and GUID to utf8 name Date: Sun, 19 Jan 2025 10:12:08 -0500 Message-Id: <20250119151214.23562-3-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> References: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 These will be used by a later patch to check for uniqueness on initial EFI variable iteration. Signed-off-by: James Bottomley --- fs/efivarfs/internal.h | 1 + fs/efivarfs/super.c | 17 +++-------------- fs/efivarfs/vars.c | 25 +++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 14 deletions(-) diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index 64d15d1bb6bf..c10efc1ad0a7 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -55,6 +55,7 @@ bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, unsigned long data_size); bool efivar_variable_is_removable(efi_guid_t vendor, const char *name, size_t len); +char *efivar_get_utf8name(const efi_char16_t *name16, efi_guid_t *vendor); extern const struct file_operations efivarfs_file_operations; extern const struct inode_operations efivarfs_dir_inode_operations; diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index d3c8528274aa..b22441f7f7c6 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -205,27 +205,16 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, memcpy(entry->var.VariableName, name16, name_size); memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); - len = ucs2_utf8size(entry->var.VariableName); - - /* name, plus '-', plus GUID, plus NUL*/ - name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); + name = efivar_get_utf8name(name16, &vendor); if (!name) goto fail; - ucs2_as_utf8(name, entry->var.VariableName, len); + /* length of the variable name itself: remove GUID and separator */ + len = strlen(name) - EFI_VARIABLE_GUID_LEN - 1; if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) is_removable = true; - name[len] = '-'; - - efi_guid_to_str(&entry->var.VendorGuid, name + len + 1); - - name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; - - /* replace invalid slashes like kobject_set_name_vargs does for /sys/firmware/efi/vars. */ - strreplace(name, '/', '!'); - inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0, is_removable); if (!inode) diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c index f7d43c847ee9..13594087d9ee 100644 --- a/fs/efivarfs/vars.c +++ b/fs/efivarfs/vars.c @@ -225,6 +225,31 @@ variable_matches(const char *var_name, size_t len, const char *match_name, } } +char * +efivar_get_utf8name(const efi_char16_t *name16, efi_guid_t *vendor) +{ + int len = ucs2_utf8size(name16); + char *name; + + /* name, plus '-', plus GUID, plus NUL*/ + name = kmalloc(len + 1 + EFI_VARIABLE_GUID_LEN + 1, GFP_KERNEL); + if (!name) + return NULL; + + ucs2_as_utf8(name, name16, len); + + name[len] = '-'; + + efi_guid_to_str(vendor, name + len + 1); + + name[len + EFI_VARIABLE_GUID_LEN+1] = '\0'; + + /* replace invalid slashes like kobject_set_name_vargs does for /sys/firmware/efi/vars. */ + strreplace(name, '/', '!'); + + return name; +} + bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, unsigned long data_size) From patchwork Sun Jan 19 15:12:09 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13944497 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6D3C44315F; Sun, 19 Jan 2025 15:13:14 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299596; cv=none; b=PPy0ly7+hibr5qJqVDp8MWa577SDhtcps3WQYzkibg2yGr9NM+xfJdOiGeYMGEjXWtV/5a5g8+KeoT6/5wbbnSWlt1wco8bXDZe2ar8jhkxATyBp/4aQECZUzlcX/IDYaUKJ0sqwyngxoLS17CPDR7eWHIAd0ZlCDeQgqOuMC5Q= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299596; c=relaxed/simple; bh=OJkRkHwCEqTFagotBRzVUHjnmsnMz0CSgaXEDuj3qV0=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=sk/jWhSFetP13rCWgoopboHmbrMttTrxIiWtdSNY81iWhFjdHEwrbJ8bl3z0A1wYrbV0w4NSf8c4gPbNCxzKlU6tEkJKxrrgeqSh2ErZuB+qNjjoIaOEPcnYygqfugqzWL9hRhUXbt6/d2oxcyZobQTRwpntosd23nQcCIKLwM0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=fUGoYrND; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="fUGoYrND" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1737299594; bh=OJkRkHwCEqTFagotBRzVUHjnmsnMz0CSgaXEDuj3qV0=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=fUGoYrNDhpLU6KGhkccAJ1/shWttbuH3jIF3XAvmZBFz2jXtESOsY79SOJ76RwCU+ 3aDv+cifi9L5RWozSd8mAkPb43GqdJVSKwu7+NX6UEtztKlV4KReF2tEv0sQ/bOlCF lkB9FK/t4aMGuCrUjk/PyprA188agkmjvFAedUU4= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 030FF128056F; Sun, 19 Jan 2025 10:13:14 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id bdrxtmdbanGn; Sun, 19 Jan 2025 10:13:13 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 9392412804E8; Sun, 19 Jan 2025 10:13:12 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v3 3/8] efivarfs: make variable_is_present use dcache lookup Date: Sun, 19 Jan 2025 10:12:09 -0500 Message-Id: <20250119151214.23562-4-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> References: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Instead of searching the variable entry list for a variable, use the dcache lookup functions to find it instead. Also add an efivarfs_ prefix to the function now it is no longer static. Signed-off-by: James Bottomley --- v2: add IS_ERR_OR_NULL check before doing dput --- fs/efivarfs/internal.h | 2 ++ fs/efivarfs/super.c | 29 +++++++++++++++++++++++++++++ fs/efivarfs/vars.c | 26 ++------------------------ 3 files changed, 33 insertions(+), 24 deletions(-) diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index c10efc1ad0a7..597ccaa60d37 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -56,6 +56,8 @@ bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, bool efivar_variable_is_removable(efi_guid_t vendor, const char *name, size_t len); char *efivar_get_utf8name(const efi_char16_t *name16, efi_guid_t *vendor); +bool efivarfs_variable_is_present(efi_char16_t *variable_name, + efi_guid_t *vendor, void *data); extern const struct file_operations efivarfs_file_operations; extern const struct inode_operations efivarfs_dir_inode_operations; diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index b22441f7f7c6..9e90823f8009 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -181,6 +181,35 @@ static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name) return ERR_PTR(-ENOMEM); } +bool efivarfs_variable_is_present(efi_char16_t *variable_name, + efi_guid_t *vendor, void *data) +{ + char *name = efivar_get_utf8name(variable_name, vendor); + struct super_block *sb = data; + struct dentry *dentry; + struct qstr qstr; + + if (!name) + /* + * If the allocation failed there'll already be an + * error in the log (and likely a huge and growing + * number of them since they system will be under + * extreme memory pressure), so simply assume + * collision for safety but don't add to the log + * flood. + */ + return true; + + qstr.name = name; + qstr.len = strlen(name); + dentry = d_hash_and_lookup(sb->s_root, &qstr); + kfree(name); + if (!IS_ERR_OR_NULL(dentry)) + dput(dentry); + + return dentry != NULL; +} + static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, unsigned long name_size, void *data, struct list_head *list) diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c index 13594087d9ee..b2fc5bdc759a 100644 --- a/fs/efivarfs/vars.c +++ b/fs/efivarfs/vars.c @@ -313,28 +313,6 @@ efivar_variable_is_removable(efi_guid_t vendor, const char *var_name, return found; } -static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor, - struct list_head *head) -{ - struct efivar_entry *entry, *n; - unsigned long strsize1, strsize2; - bool found = false; - - strsize1 = ucs2_strsize(variable_name, EFI_VAR_NAME_LEN); - list_for_each_entry_safe(entry, n, head, list) { - strsize2 = ucs2_strsize(entry->var.VariableName, EFI_VAR_NAME_LEN); - if (strsize1 == strsize2 && - !memcmp(variable_name, &(entry->var.VariableName), - strsize2) && - !efi_guidcmp(entry->var.VendorGuid, - *vendor)) { - found = true; - break; - } - } - return found; -} - /* * Returns the size of variable_name, in bytes, including the * terminating NULL character, or variable_name_size if no NULL @@ -439,8 +417,8 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, * we'll ever see a different variable name, * and may end up looping here forever. */ - if (variable_is_present(variable_name, &vendor_guid, - head)) { + if (efivarfs_variable_is_present(variable_name, + &vendor_guid, data)) { dup_variable_bug(variable_name, &vendor_guid, variable_name_size); status = EFI_NOT_FOUND; From patchwork Sun Jan 19 15:12:10 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13944498 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E456B4315F; Sun, 19 Jan 2025 15:13:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299614; cv=none; b=YyqA2zNl2+UDydiDxlt8OPUNzwiO0/AD7TCO7in7cFSBg4j/PZ25FhyffH30qhydRKsx1dLh/TX0fJpKn2ZBYdE24DwafZazBUSU6ajw3TMI3ofSwc+dLsrhtkJdeWfxKS7esAnEmhN2Xvua03MMC9xi+5yDDotrR0KwhIUTgb4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299614; c=relaxed/simple; bh=3TD51SxpLzycrp38uYDhQmKJwYUUIsV6ycV56MlAc9E=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=VYmRTZScCwDahBu7cPbeWFu7bfRaIRi78sMKipD7Z+mIPLhfdiDJBa1X9tM5mL/YtVg8MHGIVoj5FB2Uc9i/pJm9rulTKbkA1hTPUACpBlc4oVfAEck864pxsVGgFRr7bM/YAIfwzsvFDRpJoz0YcLyKmBVJwm81qDxoi/LYPfo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=Z30h1e9N; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="Z30h1e9N" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1737299612; bh=3TD51SxpLzycrp38uYDhQmKJwYUUIsV6ycV56MlAc9E=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=Z30h1e9NZtG+I5LBUDcTt7DD0m3bhzblsrpf5EfdKWSRIznzsdqn/sY+8p8ZkpD2N lDy6L5HTwtPm4W2ptLTYhz51B8rRcgjhf7yqFt7+G+2Yp7I20wQmi07Nkwe9LEl9ZZ iyNH3IQkfjrmI++SP+xPfc1ANuFiCDUXRZlMkZRg= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 254051286343; Sun, 19 Jan 2025 10:13:32 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id p_rY8OKmrO4L; Sun, 19 Jan 2025 10:13:32 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 55E45128633D; Sun, 19 Jan 2025 10:13:31 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v3 4/8] efivarfs: move variable lifetime management into the inodes Date: Sun, 19 Jan 2025 10:12:10 -0500 Message-Id: <20250119151214.23562-5-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> References: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Make the inodes the default management vehicle for struct efivar_entry, so they are now all freed automatically if the file is removed and on unmount in kill_litter_super(). Remove the now superfluous iterator to free the entries after kill_litter_super(). Also fixes a bug where some entry freeing was missing causing efivarfs to leak memory. Signed-off-by: James Bottomley --- v3: Move from evict_inode to alloc_inode/free_inode --- fs/efivarfs/inode.c | 23 +++++++++---------- fs/efivarfs/internal.h | 7 +++++- fs/efivarfs/super.c | 51 ++++++++++++++++++++++++------------------ fs/efivarfs/vars.c | 39 +++----------------------------- 4 files changed, 48 insertions(+), 72 deletions(-) diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c index a4a6587ecd2e..259c97be4cc7 100644 --- a/fs/efivarfs/inode.c +++ b/fs/efivarfs/inode.c @@ -82,26 +82,23 @@ static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir, struct efivar_entry *var; int namelen, i = 0, err = 0; bool is_removable = false; + efi_guid_t vendor; if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len)) return -EINVAL; - var = kzalloc(sizeof(struct efivar_entry), GFP_KERNEL); - if (!var) - return -ENOMEM; - /* length of the variable name itself: remove GUID and separator */ namelen = dentry->d_name.len - EFI_VARIABLE_GUID_LEN - 1; - err = guid_parse(dentry->d_name.name + namelen + 1, &var->var.VendorGuid); + err = guid_parse(dentry->d_name.name + namelen + 1, &vendor); if (err) goto out; - if (guid_equal(&var->var.VendorGuid, &LINUX_EFI_RANDOM_SEED_TABLE_GUID)) { + if (guid_equal(&vendor, &LINUX_EFI_RANDOM_SEED_TABLE_GUID)) { err = -EPERM; goto out; } - if (efivar_variable_is_removable(var->var.VendorGuid, + if (efivar_variable_is_removable(vendor, dentry->d_name.name, namelen)) is_removable = true; @@ -110,6 +107,9 @@ static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir, err = -ENOMEM; goto out; } + var = efivar_entry(inode); + + var->var.VendorGuid = vendor; for (i = 0; i < namelen; i++) var->var.VariableName[i] = dentry->d_name.name[i]; @@ -117,7 +117,6 @@ static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir, var->var.VariableName[i] = '\0'; inode->i_private = var; - kmemleak_ignore(var); err = efivar_entry_add(var, &info->efivarfs_list); if (err) @@ -126,11 +125,9 @@ static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir, d_instantiate(dentry, inode); dget(dentry); out: - if (err) { - kfree(var); - if (inode) - iput(inode); - } + if (err && inode) + iput(inode); + return err; } diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index 597ccaa60d37..fce7d5e5c763 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -29,15 +29,20 @@ struct efi_variable { struct efivar_entry { struct efi_variable var; struct list_head list; + struct inode vfs_inode; }; +static inline struct efivar_entry *efivar_entry(struct inode *inode) +{ + return container_of(inode, struct efivar_entry, vfs_inode); +} + int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, struct list_head *), void *data, struct list_head *head); int efivar_entry_add(struct efivar_entry *entry, struct list_head *head); void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head); -void efivar_entry_remove(struct efivar_entry *entry); int efivar_entry_delete(struct efivar_entry *entry); int efivar_entry_size(struct efivar_entry *entry, unsigned long *size); diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 9e90823f8009..85ab3af3f1e9 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -39,9 +39,25 @@ static int efivarfs_ops_notifier(struct notifier_block *nb, unsigned long event, return NOTIFY_OK; } -static void efivarfs_evict_inode(struct inode *inode) +static struct inode *efivarfs_alloc_inode(struct super_block *sb) { - clear_inode(inode); + struct efivar_entry *entry = kzalloc(sizeof(*entry), GFP_KERNEL); + + if (!entry) + return NULL; + + inode_init_once(&entry->vfs_inode); + + return &entry->vfs_inode; +} + +static void efivarfs_free_inode(struct inode *inode) +{ + struct efivar_entry *entry = efivar_entry(inode); + + if (inode->i_private) + list_del(&entry->list); + kfree(entry); } static int efivarfs_show_options(struct seq_file *m, struct dentry *root) @@ -106,7 +122,8 @@ static int efivarfs_statfs(struct dentry *dentry, struct kstatfs *buf) static const struct super_operations efivarfs_ops = { .statfs = efivarfs_statfs, .drop_inode = generic_delete_inode, - .evict_inode = efivarfs_evict_inode, + .alloc_inode = efivarfs_alloc_inode, + .free_inode = efivarfs_free_inode, .show_options = efivarfs_show_options, }; @@ -227,21 +244,14 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, if (guid_equal(&vendor, &LINUX_EFI_RANDOM_SEED_TABLE_GUID)) return 0; - entry = kzalloc(sizeof(*entry), GFP_KERNEL); - if (!entry) - return err; - - memcpy(entry->var.VariableName, name16, name_size); - memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); - name = efivar_get_utf8name(name16, &vendor); if (!name) - goto fail; + return err; /* length of the variable name itself: remove GUID and separator */ len = strlen(name) - EFI_VARIABLE_GUID_LEN - 1; - if (efivar_variable_is_removable(entry->var.VendorGuid, name, len)) + if (efivar_variable_is_removable(vendor, name, len)) is_removable = true; inode = efivarfs_get_inode(sb, d_inode(root), S_IFREG | 0644, 0, @@ -249,6 +259,11 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, if (!inode) goto fail_name; + entry = efivar_entry(inode); + + memcpy(entry->var.VariableName, name16, name_size); + memcpy(&(entry->var.VendorGuid), &vendor, sizeof(efi_guid_t)); + dentry = efivarfs_alloc_dentry(root, name); if (IS_ERR(dentry)) { err = PTR_ERR(dentry); @@ -273,16 +288,8 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, iput(inode); fail_name: kfree(name); -fail: - kfree(entry); - return err; -} -static int efivarfs_destroy(struct efivar_entry *entry, void *data) -{ - efivar_entry_remove(entry); - kfree(entry); - return 0; + return err; } enum { @@ -407,7 +414,7 @@ static void efivarfs_kill_sb(struct super_block *sb) kill_litter_super(sb); /* Remove all entries and destroy */ - efivar_entry_iter(efivarfs_destroy, &sfi->efivarfs_list, NULL); + WARN_ON(!list_empty(&sfi->efivarfs_list)); kfree(sfi); } diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c index b2fc5bdc759a..bb9406e03a10 100644 --- a/fs/efivarfs/vars.c +++ b/fs/efivarfs/vars.c @@ -485,34 +485,6 @@ void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head) list_add(&entry->list, head); } -/** - * efivar_entry_remove - remove entry from variable list - * @entry: entry to remove from list - * - * Returns 0 on success, or a kernel error code on failure. - */ -void efivar_entry_remove(struct efivar_entry *entry) -{ - list_del(&entry->list); -} - -/* - * efivar_entry_list_del_unlock - remove entry from variable list - * @entry: entry to remove - * - * Remove @entry from the variable list and release the list lock. - * - * NOTE: slightly weird locking semantics here - we expect to be - * called with the efivars lock already held, and we release it before - * returning. This is because this function is usually called after - * set_variable() while the lock is still held. - */ -static void efivar_entry_list_del_unlock(struct efivar_entry *entry) -{ - list_del(&entry->list); - efivar_unlock(); -} - /** * efivar_entry_delete - delete variable and remove entry from list * @entry: entry containing variable to delete @@ -536,12 +508,10 @@ int efivar_entry_delete(struct efivar_entry *entry) status = efivar_set_variable_locked(entry->var.VariableName, &entry->var.VendorGuid, 0, 0, NULL, false); - if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) { - efivar_unlock(); + efivar_unlock(); + if (!(status == EFI_SUCCESS || status == EFI_NOT_FOUND)) return efi_status_to_err(status); - } - efivar_entry_list_del_unlock(entry); return 0; } @@ -679,10 +649,7 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, &entry->var.VendorGuid, NULL, size, NULL); - if (status == EFI_NOT_FOUND) - efivar_entry_list_del_unlock(entry); - else - efivar_unlock(); + efivar_unlock(); if (status && status != EFI_BUFFER_TOO_SMALL) return efi_status_to_err(status); From patchwork Sun Jan 19 15:12:11 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13944499 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 6A85E1C5F19; Sun, 19 Jan 2025 15:14:19 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299661; cv=none; b=TAlyN18fUEF2y+yDklX/5o2XOie+70i1Vnl29bBouH3Qz/oEyP0gd2l9ZqGS0xAuWNQ/Jyy1zBtxLKRfIn8OXJF0ebiW+bIziy7ni0NCTp61yKEvdEM8uZSOeLN3DgLvLHk1pjn93eypXg3npKMkstG4GLP8hzNTaGrYhnx9wRo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299661; c=relaxed/simple; bh=7FscRwnfdxeFvFBck3pc9ZFnfTATbHRmPcryX9J7SNA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=XQUi9zWGB+3n7iC1PkAN7dIgzu+UpziPFsrUdlQW9mNhmOCgwbju0cGDv1EIL96tkov9eQ1Tep7eLAbD2LsDeiNJNOXqpYrqa961zc9dZPisLEDMk12rTfD8nKs+f2p+ZxOsFlKgYbE8VQ4+I+DSyEUTRwhBAVkSBDXgbyMJhaQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=WOwJdwow; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="WOwJdwow" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1737299657; bh=7FscRwnfdxeFvFBck3pc9ZFnfTATbHRmPcryX9J7SNA=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=WOwJdwowSpw8lS50aQIx4C20Xb9xi8U+cZZeNNuxqDu3Am3rxkI23XOUYOazJ3shg XDzcTRws7OCuG5s7i7xy01MU/Zt72Hq7x7pANe4L40txs67Qvs0xjd+IttVZefIoUB n1/1VGbt6yDCmw6Oi5z5FxowiV9MTUcQMovkRRQA= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id E9EDA128635D; Sun, 19 Jan 2025 10:14:17 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id yrTLMTERVp8K; Sun, 19 Jan 2025 10:14:17 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 1262D1286343; Sun, 19 Jan 2025 10:14:17 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v3 5/8] efivarfs: remove unused efivarfs_list Date: Sun, 19 Jan 2025 10:12:11 -0500 Message-Id: <20250119151214.23562-6-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> References: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Remove all function helpers and mentions of the efivarfs_list now that all consumers of the list have been removed and entry management goes exclusively through the inode. Signed-off-by: James Bottomley --- v3: tidy up returns in efivarfs_create (iput was never used) --- fs/efivarfs/inode.c | 24 +++--------- fs/efivarfs/internal.h | 12 +----- fs/efivarfs/super.c | 12 +----- fs/efivarfs/vars.c | 89 ++++++------------------------------------ 4 files changed, 21 insertions(+), 116 deletions(-) diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c index 259c97be4cc7..98a7299a9ee9 100644 --- a/fs/efivarfs/inode.c +++ b/fs/efivarfs/inode.c @@ -77,7 +77,6 @@ static bool efivarfs_valid_name(const char *str, int len) static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode, bool excl) { - struct efivarfs_fs_info *info = dir->i_sb->s_fs_info; struct inode *inode = NULL; struct efivar_entry *var; int namelen, i = 0, err = 0; @@ -92,21 +91,17 @@ static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir, err = guid_parse(dentry->d_name.name + namelen + 1, &vendor); if (err) - goto out; - if (guid_equal(&vendor, &LINUX_EFI_RANDOM_SEED_TABLE_GUID)) { - err = -EPERM; - goto out; - } + return err; + if (guid_equal(&vendor, &LINUX_EFI_RANDOM_SEED_TABLE_GUID)) + return -EPERM; if (efivar_variable_is_removable(vendor, dentry->d_name.name, namelen)) is_removable = true; inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0, is_removable); - if (!inode) { - err = -ENOMEM; - goto out; - } + if (!inode) + return -ENOMEM; var = efivar_entry(inode); var->var.VendorGuid = vendor; @@ -118,17 +113,10 @@ static int efivarfs_create(struct mnt_idmap *idmap, struct inode *dir, inode->i_private = var; - err = efivar_entry_add(var, &info->efivarfs_list); - if (err) - goto out; - d_instantiate(dentry, inode); dget(dentry); -out: - if (err && inode) - iput(inode); - return err; + return 0; } static int efivarfs_unlink(struct inode *dir, struct dentry *dentry) diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index fce7d5e5c763..4366f7949614 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -6,7 +6,6 @@ #ifndef EFIVAR_FS_INTERNAL_H #define EFIVAR_FS_INTERNAL_H -#include #include struct efivarfs_mount_opts { @@ -16,7 +15,6 @@ struct efivarfs_mount_opts { struct efivarfs_fs_info { struct efivarfs_mount_opts mount_opts; - struct list_head efivarfs_list; struct super_block *sb; struct notifier_block nb; }; @@ -28,7 +26,6 @@ struct efi_variable { struct efivar_entry { struct efi_variable var; - struct list_head list; struct inode vfs_inode; }; @@ -37,12 +34,9 @@ static inline struct efivar_entry *efivar_entry(struct inode *inode) return container_of(inode, struct efivar_entry, vfs_inode); } -int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, - struct list_head *), - void *data, struct list_head *head); +int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), + void *data); -int efivar_entry_add(struct efivar_entry *entry, struct list_head *head); -void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head); int efivar_entry_delete(struct efivar_entry *entry); int efivar_entry_size(struct efivar_entry *entry, unsigned long *size); @@ -53,8 +47,6 @@ int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, unsigned long *size, void *data, bool *set); -int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), - struct list_head *head, void *data); bool efivar_validate(efi_guid_t vendor, efi_char16_t *var_name, u8 *data, unsigned long data_size); diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 85ab3af3f1e9..7b3650c97e60 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -55,8 +55,6 @@ static void efivarfs_free_inode(struct inode *inode) { struct efivar_entry *entry = efivar_entry(inode); - if (inode->i_private) - list_del(&entry->list); kfree(entry); } @@ -228,8 +226,7 @@ bool efivarfs_variable_is_present(efi_char16_t *variable_name, } static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, - unsigned long name_size, void *data, - struct list_head *list) + unsigned long name_size, void *data) { struct super_block *sb = (struct super_block *)data; struct efivar_entry *entry; @@ -271,7 +268,6 @@ static int efivarfs_callback(efi_char16_t *name16, efi_guid_t vendor, } __efivar_entry_get(entry, NULL, &size, NULL); - __efivar_entry_add(entry, list); /* copied by the above to local storage in the dentry. */ kfree(name); @@ -361,7 +357,7 @@ static int efivarfs_fill_super(struct super_block *sb, struct fs_context *fc) if (err) return err; - return efivar_init(efivarfs_callback, sb, &sfi->efivarfs_list); + return efivar_init(efivarfs_callback, sb); } static int efivarfs_get_tree(struct fs_context *fc) @@ -396,8 +392,6 @@ static int efivarfs_init_fs_context(struct fs_context *fc) if (!sfi) return -ENOMEM; - INIT_LIST_HEAD(&sfi->efivarfs_list); - sfi->mount_opts.uid = GLOBAL_ROOT_UID; sfi->mount_opts.gid = GLOBAL_ROOT_GID; @@ -413,8 +407,6 @@ static void efivarfs_kill_sb(struct super_block *sb) blocking_notifier_chain_unregister(&efivar_ops_nh, &sfi->nb); kill_litter_super(sb); - /* Remove all entries and destroy */ - WARN_ON(!list_empty(&sfi->efivarfs_list)); kfree(sfi); } diff --git a/fs/efivarfs/vars.c b/fs/efivarfs/vars.c index bb9406e03a10..d0beecbf9441 100644 --- a/fs/efivarfs/vars.c +++ b/fs/efivarfs/vars.c @@ -364,16 +364,14 @@ static void dup_variable_bug(efi_char16_t *str16, efi_guid_t *vendor_guid, * efivar_init - build the initial list of EFI variables * @func: callback function to invoke for every variable * @data: function-specific data to pass to @func - * @head: initialised head of variable list * * Get every EFI variable from the firmware and invoke @func. @func - * should call efivar_entry_add() to build the list of variables. + * should populate the initial dentry and inode tree. * * Returns 0 on success, or a kernel error code on failure. */ -int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, - struct list_head *), - void *data, struct list_head *head) +int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *), + void *data) { unsigned long variable_name_size = 512; efi_char16_t *variable_name; @@ -424,7 +422,7 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, status = EFI_NOT_FOUND; } else { err = func(variable_name, vendor_guid, - variable_name_size, data, head); + variable_name_size, data); if (err) status = EFI_NOT_FOUND; } @@ -456,42 +454,12 @@ int efivar_init(int (*func)(efi_char16_t *, efi_guid_t, unsigned long, void *, } /** - * efivar_entry_add - add entry to variable list - * @entry: entry to add to list - * @head: list head - * - * Returns 0 on success, or a kernel error code on failure. - */ -int efivar_entry_add(struct efivar_entry *entry, struct list_head *head) -{ - int err; - - err = efivar_lock(); - if (err) - return err; - list_add(&entry->list, head); - efivar_unlock(); - - return 0; -} - -/** - * __efivar_entry_add - add entry to variable list - * @entry: entry to add to list - * @head: list head - */ -void __efivar_entry_add(struct efivar_entry *entry, struct list_head *head) -{ - list_add(&entry->list, head); -} - -/** - * efivar_entry_delete - delete variable and remove entry from list + * efivar_entry_delete - delete variable * @entry: entry containing variable to delete * - * Delete the variable from the firmware and remove @entry from the - * variable list. It is the caller's responsibility to free @entry - * once we return. + * Delete the variable from the firmware. It is the caller's + * responsibility to free @entry (by deleting the dentry/inode) once + * we return. * * Returns 0 on success, -EINTR if we can't grab the semaphore, * converted EFI status code if set_variable() fails. @@ -605,7 +573,7 @@ int efivar_entry_get(struct efivar_entry *entry, u32 *attributes, * get_variable() fail. * * If the EFI variable does not exist when calling set_variable() - * (EFI_NOT_FOUND), @entry is removed from the variable list. + * (EFI_NOT_FOUND). */ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, unsigned long *size, void *data, bool *set) @@ -621,9 +589,8 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, return -EINVAL; /* - * The lock here protects the get_variable call, the conditional - * set_variable call, and removal of the variable from the efivars - * list (in the case of an authenticated delete). + * The lock here protects the get_variable call and the + * conditional set_variable call */ err = efivar_lock(); if (err) @@ -661,37 +628,3 @@ int efivar_entry_set_get_size(struct efivar_entry *entry, u32 attributes, return err; } - -/** - * efivar_entry_iter - iterate over variable list - * @func: callback function - * @head: head of variable list - * @data: function-specific data to pass to callback - * - * Iterate over the list of EFI variables and call @func with every - * entry on the list. It is safe for @func to remove entries in the - * list via efivar_entry_delete() while iterating. - * - * Some notes for the callback function: - * - a non-zero return value indicates an error and terminates the loop - * - @func is called from atomic context - */ -int efivar_entry_iter(int (*func)(struct efivar_entry *, void *), - struct list_head *head, void *data) -{ - struct efivar_entry *entry, *n; - int err = 0; - - err = efivar_lock(); - if (err) - return err; - - list_for_each_entry_safe(entry, n, head, list) { - err = func(entry, data); - if (err) - break; - } - efivar_unlock(); - - return err; -} From patchwork Sun Jan 19 15:12:12 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13944500 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C938D4315F; Sun, 19 Jan 2025 15:14:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299694; cv=none; b=maU8lNPmp3S79P5PRfswmulwfnpjMoUMqhBujClQ1+/gRKLSRUFFzR637hSCYFd+nau0Cvar5ZMBy6IUC2vRInFGniurcAVv2N+QWUY9FQuvHFlbIspBGg5H1okAFWJ6tYs5DELaBR4uUiDGdvffxfiik7sBSrdvqqFzxhPo6aY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299694; c=relaxed/simple; bh=k3ugGnUYfk97WZDv7aczKcguvs55qIarCGeHFhZ1knc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=ZmaxF69ba+olxAUxZ1axqpT9GTkhVmJGUHyjiUMqHvzLC2bUfikHyDzKGhtFMFS9yEGGT44+PsVbOlMLx+zMf/VMtPQ906djVvNtkbzmckEs9DWFoLl2GCTetLwfHmahzOpbvJZMQGZct0J/93lNru7z6RSJtWHypUttp920pTk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=FPCzq4sn; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="FPCzq4sn" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1737299690; bh=k3ugGnUYfk97WZDv7aczKcguvs55qIarCGeHFhZ1knc=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=FPCzq4sneM/NjnS3O93DQ+Dv9JYmDWizVMtfJqyDuK1bmwSEpEoz1OQOeSvfA09Eg YbjWQsh2hKtM9jSo+RXJqevkX2i0H0Tuj6dVd02f5ero5WWY4jW3FooCc3l7e2z01Q zMSajTRAYhBxSLkqKAYiPY8HWB3ZyBZb6oQm/RT0= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id B88A2128635D; Sun, 19 Jan 2025 10:14:50 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id x8XYHRDrrPDP; Sun, 19 Jan 2025 10:14:49 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id CD0691286343; Sun, 19 Jan 2025 10:14:48 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v3 6/8] efivarfs: fix error on write to new variable leaving remnants Date: Sun, 19 Jan 2025 10:12:12 -0500 Message-Id: <20250119151214.23562-7-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> References: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Make variable cleanup go through the fops release mechanism and use zero inode size as the indicator to delete the file. Since all EFI variables must have an initial u32 attribute, zero size occurs either because the update deleted the variable or because an unsuccessful write after create caused the size never to be set in the first place. In the case of multiple racing opens and closes, the open is counted to ensure that the zero size check is done on the last close. Even though this fixes the bug that a create either not followed by a write or followed by a write that errored would leave a remnant file for the variable, the file will appear momentarily globally visible until the last close of the fd deletes it. This is safe because the normal filesystem operations will mediate any races; however, it is still possible for a directory listing at that instant between create and close contain a zero size variable that doesn't exist in the EFI table. Signed-off-by: James Bottomley --- v2: implement counter for last close v3: add removed state to struct efivar_entry and use in place of d_unhashed() --- fs/efivarfs/file.c | 59 +++++++++++++++++++++++++++++++++++------- fs/efivarfs/internal.h | 2 ++ fs/efivarfs/super.c | 1 + 3 files changed, 53 insertions(+), 9 deletions(-) diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c index 23c51d62f902..cb1b6d0c3454 100644 --- a/fs/efivarfs/file.c +++ b/fs/efivarfs/file.c @@ -36,28 +36,41 @@ static ssize_t efivarfs_file_write(struct file *file, if (IS_ERR(data)) return PTR_ERR(data); + inode_lock(inode); + if (var->removed) { + /* + * file got removed; don't allow a set. Caused by an + * unsuccessful create or successful delete write + * racing with us. + */ + bytes = -EIO; + goto out; + } + bytes = efivar_entry_set_get_size(var, attributes, &datasize, data, &set); - if (!set && bytes) { + if (!set) { if (bytes == -ENOENT) bytes = -EIO; goto out; } if (bytes == -ENOENT) { - drop_nlink(inode); - d_delete(file->f_path.dentry); - dput(file->f_path.dentry); + /* + * zero size signals to release that the write deleted + * the variable + */ + i_size_write(inode, 0); } else { - inode_lock(inode); i_size_write(inode, datasize + sizeof(attributes)); inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode)); - inode_unlock(inode); } bytes = count; out: + inode_unlock(inode); + kfree(data); return bytes; @@ -106,8 +119,36 @@ static ssize_t efivarfs_file_read(struct file *file, char __user *userbuf, return size; } +static int efivarfs_file_release(struct inode *inode, struct file *file) +{ + struct efivar_entry *var = inode->i_private; + + inode_lock(inode); + var->removed = (--var->open_count == 0 && i_size_read(inode) == 0); + inode_unlock(inode); + + if (var->removed) + simple_recursive_removal(file->f_path.dentry, NULL); + + return 0; +} + +static int efivarfs_file_open(struct inode *inode, struct file *file) +{ + struct efivar_entry *entry = inode->i_private; + + file->private_data = entry; + + inode_lock(inode); + entry->open_count++; + inode_unlock(inode); + + return 0; +} + const struct file_operations efivarfs_file_operations = { - .open = simple_open, - .read = efivarfs_file_read, - .write = efivarfs_file_write, + .open = efivarfs_file_open, + .read = efivarfs_file_read, + .write = efivarfs_file_write, + .release = efivarfs_file_release, }; diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h index 4366f7949614..1f84844fe032 100644 --- a/fs/efivarfs/internal.h +++ b/fs/efivarfs/internal.h @@ -27,6 +27,8 @@ struct efi_variable { struct efivar_entry { struct efi_variable var; struct inode vfs_inode; + unsigned long open_count; + bool removed; }; static inline struct efivar_entry *efivar_entry(struct inode *inode) diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c index 7b3650c97e60..89010c5878ce 100644 --- a/fs/efivarfs/super.c +++ b/fs/efivarfs/super.c @@ -47,6 +47,7 @@ static struct inode *efivarfs_alloc_inode(struct super_block *sb) return NULL; inode_init_once(&entry->vfs_inode); + entry->removed = false; return &entry->vfs_inode; } From patchwork Sun Jan 19 15:12:13 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13944501 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 797CB1DF738; Sun, 19 Jan 2025 15:15:09 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299710; cv=none; b=CaYzqLbJwXNKGaeS++kuuT53N7scZV6BHGJk5a8reB/VcuL3HVGCjqSla+c0ggG7JyM0EczJLaX5+28fXITG0z7Z8omgwwyuDRNIzboZnTLt9ao7n4x0xNWSaNS79WUzKCqmspqS7xWmsNPaGVugFVxy2zccGCeS2Brk/R/gSj0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299710; c=relaxed/simple; bh=FOhEZuJahzY/OP78uZ1cWHE5DQ0X8kQy+/dgQawrX7U=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=B8S1wrCDBdcqM/DvpYfWuYyRFBaE4DvBCqTUSLIQEmPlhKTHijDf2Iwy4ugemkDaB0vcy8QMGZKSDBVDGddb+kRUNHSkM1LWkw6H2PXJ8vgwXRo98VbwcZOxQ7152u9ShaTkBFPyhP/A9YfoQE238mHtrwv7JF8gtyzgrpCDKXI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=G5BwpQkC; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="G5BwpQkC" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1737299709; bh=FOhEZuJahzY/OP78uZ1cWHE5DQ0X8kQy+/dgQawrX7U=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=G5BwpQkCqvTq7ZkBibfRvnsd9cLndIGu9zrPfUgZd4YZl3Q3Yihlq1HcPFV6taS6n LPlfmESd83rV7oipePQ+DC571ENjSD2ZcUdqa3rWfM6NUFmn3g1etAd9Ps7/KjDdn0 5CY0RftiJyx2zsYckAu8s3cYOy1x3SWWt6x9a69M= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 1AC67128635D; Sun, 19 Jan 2025 10:15:09 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id wIU3HkBWal3O; Sun, 19 Jan 2025 10:15:09 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 52A521286343; Sun, 19 Jan 2025 10:15:08 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v3 7/8] selftests/efivarfs: fix tests for failed write removal Date: Sun, 19 Jan 2025 10:12:13 -0500 Message-Id: <20250119151214.23562-8-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> References: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The current self tests expect the zero size remnants that failed variable creation leaves. Update the tests to verify these are now absent. Signed-off-by: James Bottomley --- tools/testing/selftests/efivarfs/efivarfs.sh | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tools/testing/selftests/efivarfs/efivarfs.sh b/tools/testing/selftests/efivarfs/efivarfs.sh index 96677282789b..4a84a810dc2c 100755 --- a/tools/testing/selftests/efivarfs/efivarfs.sh +++ b/tools/testing/selftests/efivarfs/efivarfs.sh @@ -76,11 +76,11 @@ test_create_empty() : > $file - if [ ! -e $file ]; then - echo "$file can not be created without writing" >&2 + if [ -e $file ]; then + echo "$file can be created without writing" >&2 + file_cleanup $file exit 1 fi - file_cleanup $file } test_create_read() @@ -89,10 +89,13 @@ test_create_read() ./create-read $file if [ $? -ne 0 ]; then echo "create and read $file failed" + exit 1 + fi + if [ -e $file ]; then + echo "file still exists and should not" file_cleanup $file exit 1 fi - file_cleanup $file } test_delete() From patchwork Sun Jan 19 15:12:14 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: James Bottomley X-Patchwork-Id: 13944502 Received: from bedivere.hansenpartnership.com (bedivere.hansenpartnership.com [104.223.66.194]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3218F1401C; Sun, 19 Jan 2025 15:15:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=104.223.66.194 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299749; cv=none; b=F/VHUf1C63Y+kfrClIkl1dMBe7aYyNeXVXrLOYxpCt1E9OPPzvSxpAeKyPTkvwsSp1Vj3leVMOll9lXXiPwManul/Eu0V0/7zw7YH5TpGITKOTmjqAgMTHX2FG6+MdiAqNaXdvHTHpH1V7VLSMAX5zAIDv2VKCafgSIXYHIqOCU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1737299749; c=relaxed/simple; bh=aTXkvWtNPTWphz69PgMRfYO//YWs6Qr/ccLbO6weQqc=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=mjykGfkAIKh2uf2VZ9NmIk5p7p+y0Ud9C2J8LHExwxtVjFfjOm+qdVM7pxvZwzzzctTPjkcBJFZh2NTWUzQfYdk7LMvRSpEPNBbpQx/nPzs3iC8ezDzih5OQFqg4OZ2MNnuyGmhYtD5vJ1abC4wJnXHm7s9fFjTa4Yeg9FQnAso= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com; spf=pass smtp.mailfrom=HansenPartnership.com; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b=qo48mERn; arc=none smtp.client-ip=104.223.66.194 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=HansenPartnership.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=hansenpartnership.com header.i=@hansenpartnership.com header.b="qo48mERn" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=hansenpartnership.com; s=20151216; t=1737299747; bh=aTXkvWtNPTWphz69PgMRfYO//YWs6Qr/ccLbO6weQqc=; h=From:To:Subject:Date:Message-Id:In-Reply-To:References:From; b=qo48mERnchIGgNG9E4o92dQXzWzXSETCCYKQCe3ooigp3CvCps40ThXVKPLYWl6tf AC39g2elGHMZD0070Fy/9fjJWxu2bE2sV84O2OXkZjWWZF7gCOfVl4dvWjPkoOzi5q V2tN/kkzcBXbSTD1/vaF8+OK5d3ovsP7zNRBxzQs= Received: from localhost (localhost [127.0.0.1]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 61A03128694C; Sun, 19 Jan 2025 10:15:47 -0500 (EST) Received: from bedivere.hansenpartnership.com ([127.0.0.1]) by localhost (bedivere.hansenpartnership.com [127.0.0.1]) (amavis, port 10024) with ESMTP id LXqHuufayWZO; Sun, 19 Jan 2025 10:15:47 -0500 (EST) Received: from lingrow.int.hansenpartnership.com (unknown [153.66.160.227]) by bedivere.hansenpartnership.com (Postfix) with ESMTP id 90A251286946; Sun, 19 Jan 2025 10:15:46 -0500 (EST) From: James Bottomley To: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org Cc: Ard Biesheuvel , Jeremy Kerr , Christian Brauner , Al Viro Subject: [PATCH v3 8/8] selftests/efivarfs: add concurrent update tests Date: Sun, 19 Jan 2025 10:12:14 -0500 Message-Id: <20250119151214.23562-9-James.Bottomley@HansenPartnership.com> X-Mailer: git-send-email 2.35.3 In-Reply-To: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> References: <20250119151214.23562-1-James.Bottomley@HansenPartnership.com> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 The delete on last close functionality can now only be tested properly by using multiple threads to hold open the variable files and testing what happens as they complete. Signed-off-by: James Bottomley --- tools/testing/selftests/efivarfs/efivarfs.sh | 114 +++++++++++++++++++ 1 file changed, 114 insertions(+) diff --git a/tools/testing/selftests/efivarfs/efivarfs.sh b/tools/testing/selftests/efivarfs/efivarfs.sh index 4a84a810dc2c..69b77bbf146d 100755 --- a/tools/testing/selftests/efivarfs/efivarfs.sh +++ b/tools/testing/selftests/efivarfs/efivarfs.sh @@ -227,6 +227,116 @@ test_no_set_size() exit $ret } +setup_test_multiple() +{ + ## + # we're going to do multi-threaded tests, so create a couple + # of pipes for synchronization + ## + + # empty is because arrays number from 0 but jobs number from 1 + p=("" /tmp/efivarfs_pipe1 /tmp/efivarfs_pipe2 /tmp/efivarfs_pipe3) + # create but ignore failure + mknod ${p[1]} p + mknod ${p[2]} p + mknod ${p[3]} p + + declare -g var=$efivarfs_mount/test_multiple-$test_guid + + cleanup() { + for f in ${p[@]}; do + rm -f ${f} + done + if [ -e $var ]; then + file_cleanup $var + fi + } + trap cleanup exit + + waitpipe() { + cat ${p[$1]} > /dev/null + } + + endjob() { + echo 1 > ${p[$1]} + while jobs %${1}; do true; done > /dev/null 2>&1 + } +} + +test_multiple_zero_size() +{ + ## + # check for remove on last close, set up three threads all + # holding the variable (one write and two reads) and then + # close them sequentially (waiting for completion) and check + # the state of the variable + ## + + { waitpipe 1; echo 1; } > $var 2> /dev/null & + # zero length file should exist + [ -e $var ] || exit 1 + # second and third delayed close + { waitpipe 2; } < $var & + { waitpipe 3; } < $var & + # close first fd + endjob 1 + # var should only be deleted on last close + [ -e $var ] || exit 1 + # close second fd + endjob 2 + [ -e $var ] || exit 1 + # file should go on last close + endjob 3 + [ ! -e $var ] || exit 1 +} + +test_multiple_create() +{ + ## + # set multiple threads to access the variable but delay + # the final write to check the close of 2 and 3. The + # final write should succeed in creating the variable + ## + { waitpipe 1; printf '\x07\x00\x00\x00\x54'; } > $var & + [ -e $var -a ! -s $var ] || exit 1 + { waitpipe 2; } < $var & + { waitpipe 3; } < $var & + # close second and third fds + endjob 2 + # var should only be created (have size) on last close + [ -e $var -a ! -s $var ] || exit 1 + endjob 3 + [ -e $var -a ! -s $var ] || exit 1 + # close first fd + endjob 1 + # variable should still exist + [ -s $var ] || exit 1 + file_cleanup $var +} + +test_multiple_delete_on_write() { + ## + # delete the variable on final write; seqencing similar + # to test_multiple_create() + ## + printf '\x07\x00\x00\x00\x54' > $var + chattr -i $var + { waitpipe 1; printf '\x07\x00\x00\x00'; } > $var & + [ -e $var -a -s $var ] || exit 1 + { waitpipe 2; } < $var & + { waitpipe 3; } < $var & + # close first fd; write should set variable size to zero + endjob 1 + # var should only be deleted on last close + [ -e $var -a ! -s $var ] || exit 1 + endjob 2 + [ -e $var ] || exit 1 + # close last fd + endjob 3 + # variable should now be removed + [ ! -e $var ] || exit 1 +} + check_prereqs rc=0 @@ -240,5 +350,9 @@ run_test test_open_unlink run_test test_valid_filenames run_test test_invalid_filenames run_test test_no_set_size +setup_test_multiple +run_test test_multiple_zero_size +run_test test_multiple_create +run_test test_multiple_delete_on_write exit $rc