From: James Bottomley <James.Bottomley@HansenPartnership.com>
To: Al Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org, linux-efi@vger.kernel.org,
Ard Biesheuvel <ardb@kernel.org>, Jeremy Kerr <jk@ozlabs.org>,
Christian Brauner <brauner@kernel.org>
Subject: Re: [PATCH v2 4/6] efivarfs: move freeing of variable entry into evict_inode
Date: Thu, 16 Jan 2025 17:13:05 -0500 [thread overview]
Message-ID: <ae267db4fe60f564c6aa0400dd2a7eef4fe9db18.camel@HansenPartnership.com> (raw)
In-Reply-To: <0b770a342780510f1cd82a506bc67124752b170c.camel@HansenPartnership.com>
On Thu, 2025-01-16 at 14:05 -0500, James Bottomley wrote:
> On Thu, 2025-01-16 at 18:36 +0000, Al Viro wrote:
> > On Mon, Jan 06, 2025 at 06:35:23PM -0800, James Bottomley wrote:
> > > 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.
> >
> > Umm... I'd rather coallocate struct inode and struct efivar_entry;
> > that way once you get rid of the list you don't need -
> > >evict_inode()
> > anymore.
> >
> > It's pretty easy - see e.g.
> > https://lore.kernel.org/all/20250112080705.141166-1-viro@zeniv.linux.org.uk/
> > for recent example of such conversion.
>
> OK, I can do that. Although I think since the number of variables is
> usually around 150, it would probably be overkill to give it its own
> inode cache allocator.
OK, this is what I've got. As you can see from the diffstat it's about
10 lines more than the previous; mostly because of the new allocation
routine, the fact that the root inode has to be special cased for the
list and the guid has to be parsed in efivarfs_create before we have
the inode.
Regards,
James
---
fs/efivarfs/file.c | 6 +++---
fs/efivarfs/inode.c | 27 +++++++++++----------------
fs/efivarfs/internal.h | 6 ++++++
fs/efivarfs/super.c | 45 ++++++++++++++++++++++++++----------------
---
4 files changed, 46 insertions(+), 38 deletions(-)
diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
index 23c51d62f902..176362b73d38 100644
--- a/fs/efivarfs/file.c
+++ b/fs/efivarfs/file.c
@@ -15,10 +15,10 @@
static ssize_t efivarfs_file_write(struct file *file,
const char __user *userbuf, size_t count, loff_t
*ppos)
{
- struct efivar_entry *var = file->private_data;
void *data;
u32 attributes;
struct inode *inode = file->f_mapping->host;
+ struct efivar_entry *var = efivar_entry(inode);
unsigned long datasize = count - sizeof(attributes);
ssize_t bytes;
bool set = false;
@@ -66,7 +66,8 @@ static ssize_t efivarfs_file_write(struct file *file,
static ssize_t efivarfs_file_read(struct file *file, char __user
*userbuf,
size_t count, loff_t *ppos)
{
- struct efivar_entry *var = file->private_data;
+ struct inode *inode = file->f_mapping->host;
+ struct efivar_entry *var = efivar_entry(inode);
unsigned long datasize = 0;
u32 attributes;
void *data;
@@ -107,7 +108,6 @@ static ssize_t efivarfs_file_read(struct file
*file, char __user *userbuf,
}
const struct file_operations efivarfs_file_operations = {
- .open = simple_open,
.read = efivarfs_file_read,
.write = efivarfs_file_write,
};
diff --git a/fs/efivarfs/inode.c b/fs/efivarfs/inode.c
index ec23da8405ff..a13ffb01e149 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,15 +107,15 @@ 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];
var->var.VariableName[i] = '\0';
- inode->i_private = var;
- kmemleak_ignore(var);
-
err = efivar_entry_add(var, &info->efivarfs_list);
if (err)
goto out;
@@ -126,17 +123,15 @@ 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;
}
static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
{
- struct efivar_entry *var = d_inode(dentry)->i_private;
+ struct efivar_entry *var = efivar_entry(d_inode(dentry));
if (efivar_entry_delete(var))
return -EINVAL;
diff --git a/fs/efivarfs/internal.h b/fs/efivarfs/internal.h
index 8d82fc8bca31..fce7d5e5c763 100644
--- a/fs/efivarfs/internal.h
+++ b/fs/efivarfs/internal.h
@@ -29,8 +29,14 @@ 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);
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index d7facc99b745..cfead280534c 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -39,15 +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)
{
- struct efivar_entry *entry = inode->i_private;
+ struct efivar_entry *entry = kzalloc(sizeof(*entry),
GFP_KERNEL);
- if (entry) {
+ 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 (!is_root_inode(inode))
list_del(&entry->list);
- kfree(entry);
- }
- clear_inode(inode);
+ kfree(entry);
}
static int efivarfs_show_options(struct seq_file *m, struct dentry
*root)
@@ -112,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,
};
@@ -233,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,
@@ -255,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);
@@ -268,7 +277,6 @@ static int efivarfs_callback(efi_char16_t *name16,
efi_guid_t vendor,
kfree(name);
inode_lock(inode);
- inode->i_private = entry;
i_size_write(inode, size + sizeof(__u32)); /* attributes +
data */
inode_unlock(inode);
d_add(dentry, inode);
@@ -279,8 +287,7 @@ static int efivarfs_callback(efi_char16_t *name16,
efi_guid_t vendor,
iput(inode);
fail_name:
kfree(name);
-fail:
- kfree(entry);
+
return err;
}
next prev parent reply other threads:[~2025-01-16 22:13 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-01-07 2:35 [PATCH v2 0/6] convert efivarfs to manage object data correctly James Bottomley
2025-01-07 2:35 ` [PATCH v2 1/6] efivarfs: remove unused efi_varaible.Attributes and .kobj James Bottomley
2025-01-07 2:35 ` [PATCH v2 2/6] efivarfs: add helper to convert from UC16 name and GUID to utf8 name James Bottomley
2025-01-07 2:35 ` [PATCH v2 3/6] efivarfs: make variable_is_present use dcache lookup James Bottomley
2025-01-07 2:35 ` [PATCH v2 4/6] efivarfs: move freeing of variable entry into evict_inode James Bottomley
2025-01-16 18:36 ` Al Viro
2025-01-16 19:05 ` James Bottomley
2025-01-16 22:13 ` James Bottomley [this message]
2025-01-19 14:50 ` Ard Biesheuvel
2025-01-19 14:57 ` James Bottomley
2025-01-19 16:31 ` Ard Biesheuvel
2025-01-19 16:46 ` James Bottomley
2025-01-07 2:35 ` [PATCH v2 5/6] efivarfs: remove unused efivarfs_list James Bottomley
2025-01-16 18:42 ` Al Viro
2025-01-16 18:55 ` James Bottomley
2025-01-07 2:35 ` [PATCH v2 6/6] efivarfs: fix error on write to new variable leaving remnants James Bottomley
2025-01-16 18:45 ` Al Viro
2025-01-16 18:54 ` James Bottomley
2025-01-16 18:59 ` Al Viro
2025-01-16 19:04 ` James Bottomley
2025-01-09 9:50 ` [PATCH v2 0/6] convert efivarfs to manage object data correctly Ard Biesheuvel
2025-01-09 14:24 ` Ard Biesheuvel
2025-01-09 15:50 ` James Bottomley
2025-01-09 16:11 ` Ard Biesheuvel
2025-01-18 13:53 ` James Bottomley
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ae267db4fe60f564c6aa0400dd2a7eef4fe9db18.camel@HansenPartnership.com \
--to=james.bottomley@hansenpartnership.com \
--cc=ardb@kernel.org \
--cc=brauner@kernel.org \
--cc=jk@ozlabs.org \
--cc=linux-efi@vger.kernel.org \
--cc=linux-fsdevel@vger.kernel.org \
--cc=viro@zeniv.linux.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox