aboutsummaryrefslogtreecommitdiffstats
path: root/mm
diff options
authorMiklos Szeredi <mszeredi@redhat.com>2026-06-05 15:53:18 +0200
committerChristian Brauner <brauner@kernel.org>2026-06-06 15:21:41 +0200
commit076e5cef28e27febfc09b5f72544d2b857c75201 (patch)
tree29bcb8b6db7696bd2377f153a6e8f9034f1e68a8 /mm
parent832f4de4c8ba4f19e5df1d016a09917204b17834 (diff)
downloadath-076e5cef28e27febfc09b5f72544d2b857c75201.tar.gz
simple_xattr: change interface to pass struct simple_xattrs **
Change the simple_xattr API to accept pointer-to-pointer (struct simple_xattrs **) instead of pointer. This allows the functions to handle lazy allocation internally without requiring callers to use simple_xattrs_lazy_alloc(). The simple_xattr_set(), simple_xattr_set_limited() and simple_xattr_add() functions now handle allocation when xattrs is NULL. simple_xattrs_free() now also frees the xattrs structure itself and sets the pointer to NULL. This simplifies callers and removes the need for most callers to explicitly manage xattrs allocation and lifetime. In shmem_initxattrs(), the total required space for all initial xattrs (ispace) is pre-calculated and deducted from sbinfo->free_ispace. Since this patch modifies the function to add new xattrs directly to the inode's &info->xattrs list rather than using a local temporary variable, a failure means that the partially populated info->xattrs list remains attached to the inode. When the VFS caller handles the -ENOMEM error, it drops the newly created inode via iput(), shmem_free_inode() adds freed to sbinfo->free_ispace a second time, permanently inflating the tmpfs free space quota. Fix by substracting already added xattrs from ispace. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com> Link: https://patch.msgid.link/20260605135322.2632068-4-mszeredi@redhat.com Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
Diffstat (limited to 'mm')
-rw-r--r--mm/shmem.c34
1 files changed, 10 insertions, 24 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index c7897570fc9f9..cf4ee9f411911 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1425,10 +1425,8 @@ static void shmem_evict_inode(struct inode *inode)
}
}
- if (info->xattrs) {
- simple_xattrs_free(info->xattrs, sbinfo->max_inodes ? &freed : NULL);
- kfree(info->xattrs);
- }
+ simple_xattrs_free(&info->xattrs, sbinfo->max_inodes ? &freed : NULL);
+
shmem_free_inode(inode->i_sb, freed);
WARN_ON(inode->i_blocks);
clear_inode(inode);
@@ -4233,10 +4231,6 @@ static int shmem_initxattrs(struct inode *inode,
const struct xattr *xattr;
size_t ispace = 0;
- CLASS(simple_xattrs, xattrs)();
- if (IS_ERR(xattrs))
- return PTR_ERR(xattrs);
-
if (sbinfo->max_inodes) {
for (xattr = xattr_array; xattr->name != NULL; xattr++) {
ispace += simple_xattr_space(xattr->name,
@@ -4264,8 +4258,11 @@ static int shmem_initxattrs(struct inode *inode,
if (!new_xattr->name)
break;
- if (simple_xattr_add(xattrs, new_xattr))
+ if (simple_xattr_add(&info->xattrs, new_xattr))
break;
+
+ if (sbinfo->max_inodes)
+ ispace -= simple_xattr_space(new_xattr->name, new_xattr->size);
retain_and_null_ptr(new_xattr);
}
@@ -4277,8 +4274,8 @@ static int shmem_initxattrs(struct inode *inode,
}
return -ENOMEM;
}
+ WARN_ON(ispace);
- smp_store_release(&info->xattrs, no_free_ptr(xattrs));
return 0;
}
@@ -4287,14 +4284,9 @@ static int shmem_xattr_handler_get(const struct xattr_handler *handler,
const char *name, void *buffer, size_t size)
{
struct shmem_inode_info *info = SHMEM_I(inode);
- struct simple_xattrs *xattrs;
-
- xattrs = READ_ONCE(info->xattrs);
- if (!xattrs)
- return -ENODATA;
name = xattr_full_name(handler, name);
- return simple_xattr_get(xattrs, name, buffer, size);
+ return simple_xattr_get(&info->xattrs, name, buffer, size);
}
static int shmem_xattr_handler_set(const struct xattr_handler *handler,
@@ -4305,16 +4297,11 @@ static int shmem_xattr_handler_set(const struct xattr_handler *handler,
{
struct shmem_inode_info *info = SHMEM_I(inode);
struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb);
- struct simple_xattrs *xattrs;
struct simple_xattr *old_xattr;
size_t ispace = 0;
name = xattr_full_name(handler, name);
- xattrs = simple_xattrs_lazy_alloc(&info->xattrs, value, flags);
- if (IS_ERR_OR_NULL(xattrs))
- return PTR_ERR(xattrs);
-
if (value && sbinfo->max_inodes) {
ispace = simple_xattr_space(name, size);
raw_spin_lock(&sbinfo->stat_lock);
@@ -4327,7 +4314,7 @@ static int shmem_xattr_handler_set(const struct xattr_handler *handler,
return -ENOSPC;
}
- old_xattr = simple_xattr_set(xattrs, name, value, size, flags);
+ old_xattr = simple_xattr_set(&info->xattrs, name, value, size, flags);
if (!IS_ERR(old_xattr)) {
ispace = 0;
if (old_xattr && sbinfo->max_inodes)
@@ -4375,8 +4362,7 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
struct shmem_inode_info *info = SHMEM_I(d_inode(dentry));
- return simple_xattr_list(d_inode(dentry), READ_ONCE(info->xattrs),
- buffer, size);
+ return simple_xattr_list(d_inode(dentry), &info->xattrs, buffer, size);
}
#endif /* CONFIG_TMPFS_XATTR */