Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

shmem: adapt to rhashtable-based simple_xattrs with lazy allocation

Adapt tmpfs/shmem to use the rhashtable-based xattr path and switch
from an embedded struct to pointer-based lazy allocation.

Change shmem_inode_info.xattrs from embedded 'struct simple_xattrs' to
a pointer 'struct simple_xattrs *', initialized to NULL. This avoids
the rhashtable overhead for every tmpfs inode, which helps when a lot of
inodes exist.

The xattr store is allocated on first use:

- shmem_initxattrs(): Allocates via simple_xattrs_alloc() when
security modules set initial xattrs during inode creation.

- shmem_xattr_handler_set(): Allocates on first setxattr, with a
short-circuit for removal when no xattrs are stored yet.

All read paths (shmem_xattr_handler_get, shmem_listxattr) check for
NULL xattrs pointer and return -ENODATA or 0 respectively.

Replaced xattr entries are freed via simple_xattr_free_rcu() to allow
concurrent RCU readers to finish.

shmem_evict_inode() conditionally frees the xattr store only when
allocated.

Also change simple_xattr_add() from void to int to propagate
rhashtable insertion failures. shmem_initxattrs() is the only caller.

Link: https://patch.msgid.link/20260216-work-xattr-socket-v1-3-c2efa4f74cb7@kernel.org
Acked-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Christian Brauner <brauner@kernel.org>

+46 -28
+12 -12
fs/xattr.c
··· 1677 1677 * of matching xattrs is wanted. Should only be called during inode 1678 1678 * initialization when a few distinct initial xattrs are supposed to be set. 1679 1679 */ 1680 - void simple_xattr_add(struct simple_xattrs *xattrs, 1681 - struct simple_xattr *new_xattr) 1680 + int simple_xattr_add(struct simple_xattrs *xattrs, 1681 + struct simple_xattr *new_xattr) 1682 1682 { 1683 - if (xattrs->use_rhashtable) { 1684 - WARN_ON(rhashtable_insert_fast(&xattrs->ht, 1685 - &new_xattr->hash_node, 1686 - simple_xattr_params)); 1687 - } else { 1688 - write_lock(&xattrs->lock); 1689 - rb_add(&new_xattr->rb_node, &xattrs->rb_root, 1690 - rbtree_simple_xattr_less); 1691 - write_unlock(&xattrs->lock); 1692 - } 1683 + if (xattrs->use_rhashtable) 1684 + return rhashtable_insert_fast(&xattrs->ht, 1685 + &new_xattr->hash_node, 1686 + simple_xattr_params); 1687 + 1688 + write_lock(&xattrs->lock); 1689 + rb_add(&new_xattr->rb_node, &xattrs->rb_root, 1690 + rbtree_simple_xattr_less); 1691 + write_unlock(&xattrs->lock); 1692 + return 0; 1693 1693 } 1694 1694 1695 1695 /**
+1 -1
include/linux/shmem_fs.h
··· 48 48 }; 49 49 struct timespec64 i_crtime; /* file creation time */ 50 50 struct shared_policy policy; /* NUMA memory alloc policy */ 51 - struct simple_xattrs xattrs; /* list of xattrs */ 51 + struct simple_xattrs *xattrs; /* list of xattrs */ 52 52 pgoff_t fallocend; /* highest fallocate endindex */ 53 53 unsigned int fsflags; /* for FS_IOC_[SG]ETFLAGS */ 54 54 atomic_t stop_eviction; /* hold when working on inode */
+2 -2
include/linux/xattr.h
··· 142 142 size_t size, int flags); 143 143 ssize_t simple_xattr_list(struct inode *inode, struct simple_xattrs *xattrs, 144 144 char *buffer, size_t size); 145 - void simple_xattr_add(struct simple_xattrs *xattrs, 146 - struct simple_xattr *new_xattr); 145 + int simple_xattr_add(struct simple_xattrs *xattrs, 146 + struct simple_xattr *new_xattr); 147 147 int xattr_list_one(char **buffer, ssize_t *remaining_size, const char *name); 148 148 149 149 DEFINE_CLASS(simple_xattr,
+31 -13
mm/shmem.c
··· 1425 1425 } 1426 1426 } 1427 1427 1428 - simple_xattrs_free(&info->xattrs, sbinfo->max_inodes ? &freed : NULL); 1428 + if (info->xattrs) { 1429 + simple_xattrs_free(info->xattrs, sbinfo->max_inodes ? &freed : NULL); 1430 + kfree(info->xattrs); 1431 + } 1429 1432 shmem_free_inode(inode->i_sb, freed); 1430 1433 WARN_ON(inode->i_blocks); 1431 1434 clear_inode(inode); ··· 3104 3101 shmem_set_inode_flags(inode, info->fsflags, NULL); 3105 3102 INIT_LIST_HEAD(&info->shrinklist); 3106 3103 INIT_LIST_HEAD(&info->swaplist); 3107 - simple_xattrs_init(&info->xattrs); 3108 3104 cache_no_acl(inode); 3109 3105 if (sbinfo->noswap) 3110 3106 mapping_set_unevictable(inode->i_mapping); ··· 4257 4255 struct shmem_inode_info *info = SHMEM_I(inode); 4258 4256 struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); 4259 4257 const struct xattr *xattr; 4260 - struct simple_xattr *new_xattr; 4261 4258 size_t ispace = 0; 4262 4259 size_t len; 4260 + 4261 + CLASS(simple_xattrs, xattrs)(); 4262 + if (IS_ERR(xattrs)) 4263 + return PTR_ERR(xattrs); 4263 4264 4264 4265 if (sbinfo->max_inodes) { 4265 4266 for (xattr = xattr_array; xattr->name != NULL; xattr++) { ··· 4282 4277 } 4283 4278 4284 4279 for (xattr = xattr_array; xattr->name != NULL; xattr++) { 4285 - new_xattr = simple_xattr_alloc(xattr->value, xattr->value_len); 4280 + CLASS(simple_xattr, new_xattr)(xattr->value, xattr->value_len); 4286 4281 if (IS_ERR(new_xattr)) 4287 4282 break; 4288 4283 4289 4284 len = strlen(xattr->name) + 1; 4290 4285 new_xattr->name = kmalloc(XATTR_SECURITY_PREFIX_LEN + len, 4291 4286 GFP_KERNEL_ACCOUNT); 4292 - if (!new_xattr->name) { 4293 - kvfree(new_xattr); 4287 + if (!new_xattr->name) 4294 4288 break; 4295 - } 4296 4289 4297 4290 memcpy(new_xattr->name, XATTR_SECURITY_PREFIX, 4298 4291 XATTR_SECURITY_PREFIX_LEN); 4299 4292 memcpy(new_xattr->name + XATTR_SECURITY_PREFIX_LEN, 4300 4293 xattr->name, len); 4301 4294 4302 - simple_xattr_add(&info->xattrs, new_xattr); 4295 + if (simple_xattr_add(xattrs, new_xattr)) 4296 + break; 4297 + retain_and_null_ptr(new_xattr); 4303 4298 } 4304 4299 4305 4300 if (xattr->name != NULL) { ··· 4308 4303 sbinfo->free_ispace += ispace; 4309 4304 raw_spin_unlock(&sbinfo->stat_lock); 4310 4305 } 4311 - simple_xattrs_free(&info->xattrs, NULL); 4312 4306 return -ENOMEM; 4313 4307 } 4314 4308 4309 + smp_store_release(&info->xattrs, no_free_ptr(xattrs)); 4315 4310 return 0; 4316 4311 } 4317 4312 ··· 4320 4315 const char *name, void *buffer, size_t size) 4321 4316 { 4322 4317 struct shmem_inode_info *info = SHMEM_I(inode); 4318 + struct simple_xattrs *xattrs; 4319 + 4320 + xattrs = READ_ONCE(info->xattrs); 4321 + if (!xattrs) 4322 + return -ENODATA; 4323 4323 4324 4324 name = xattr_full_name(handler, name); 4325 - return simple_xattr_get(&info->xattrs, name, buffer, size); 4325 + return simple_xattr_get(xattrs, name, buffer, size); 4326 4326 } 4327 4327 4328 4328 static int shmem_xattr_handler_set(const struct xattr_handler *handler, ··· 4338 4328 { 4339 4329 struct shmem_inode_info *info = SHMEM_I(inode); 4340 4330 struct shmem_sb_info *sbinfo = SHMEM_SB(inode->i_sb); 4331 + struct simple_xattrs *xattrs; 4341 4332 struct simple_xattr *old_xattr; 4342 4333 size_t ispace = 0; 4343 4334 4344 4335 name = xattr_full_name(handler, name); 4336 + 4337 + xattrs = simple_xattrs_lazy_alloc(&info->xattrs, value, flags); 4338 + if (IS_ERR_OR_NULL(xattrs)) 4339 + return PTR_ERR(xattrs); 4340 + 4345 4341 if (value && sbinfo->max_inodes) { 4346 4342 ispace = simple_xattr_space(name, size); 4347 4343 raw_spin_lock(&sbinfo->stat_lock); ··· 4360 4344 return -ENOSPC; 4361 4345 } 4362 4346 4363 - old_xattr = simple_xattr_set(&info->xattrs, name, value, size, flags); 4347 + old_xattr = simple_xattr_set(xattrs, name, value, size, flags); 4364 4348 if (!IS_ERR(old_xattr)) { 4365 4349 ispace = 0; 4366 4350 if (old_xattr && sbinfo->max_inodes) 4367 4351 ispace = simple_xattr_space(old_xattr->name, 4368 4352 old_xattr->size); 4369 - simple_xattr_free(old_xattr); 4353 + simple_xattr_free_rcu(old_xattr); 4370 4354 old_xattr = NULL; 4371 4355 inode_set_ctime_current(inode); 4372 4356 inode_inc_iversion(inode); ··· 4407 4391 static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size) 4408 4392 { 4409 4393 struct shmem_inode_info *info = SHMEM_I(d_inode(dentry)); 4410 - return simple_xattr_list(d_inode(dentry), &info->xattrs, buffer, size); 4394 + 4395 + return simple_xattr_list(d_inode(dentry), READ_ONCE(info->xattrs), 4396 + buffer, size); 4411 4397 } 4412 4398 #endif /* CONFIG_TMPFS_XATTR */ 4413 4399