linux-loongson/include/linux/posix_acl.h
Gustavo A. R. Silva dfd500d895 fs: nfs: acl: Avoid -Wflex-array-member-not-at-end warning
-Wflex-array-member-not-at-end was introduced in GCC-14, and we are
getting ready to enable it, globally.

So, in order to avoid ending up with a flexible-array member in the
middle of other structs, we use the `struct_group_tagged()` helper
to create a new tagged `struct posix_acl_hdr`. This structure
groups together all the members of the flexible `struct posix_acl`
except the flexible array.

As a result, the array is effectively separated from the rest of the
members without modifying the memory layout of the flexible structure.
We then change the type of the middle struct member currently causing
trouble from `struct posix_acl` to `struct posix_acl_hdr`.

We also want to ensure that when new members need to be added to the
flexible structure, they are always included within the newly created
tagged struct. For this, we use `static_assert()`. This ensures that the
memory layout for both the flexible structure and the new tagged struct
is the same after any changes.

This approach avoids having to implement `struct posix_acl_hdr` as a
completely separate structure, thus preventing having to maintain two
independent but basically identical structures, closing the door to
potential bugs in the future.

We also use `container_of()` whenever we need to retrieve a pointer to
the flexible structure, through which we can access the flexible-array
member, if necessary.

So, with these changes, fix the following warning:

fs/nfs_common/nfsacl.c:45:26: warning: structure containing a flexible array member is not at the end of another structure [-Wflex-array-member-not-at-end]

Signed-off-by: Gustavo A. R. Silva <gustavoars@kernel.org>
Acked-by: Anna Schumaker <anna.schumaker@oracle.com>
Acked-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
2025-03-10 09:11:04 -04:00

173 lines
4.6 KiB
C

/* SPDX-License-Identifier: GPL-2.0 */
/*
File: linux/posix_acl.h
(C) 2002 Andreas Gruenbacher, <a.gruenbacher@computer.org>
*/
#ifndef __LINUX_POSIX_ACL_H
#define __LINUX_POSIX_ACL_H
#include <linux/bug.h>
#include <linux/slab.h>
#include <linux/rcupdate.h>
#include <linux/refcount.h>
#include <uapi/linux/posix_acl.h>
struct user_namespace;
struct posix_acl_entry {
short e_tag;
unsigned short e_perm;
union {
kuid_t e_uid;
kgid_t e_gid;
};
};
struct posix_acl {
/* New members MUST be added within the struct_group() macro below. */
struct_group_tagged(posix_acl_hdr, hdr,
refcount_t a_refcount;
unsigned int a_count;
struct rcu_head a_rcu;
);
struct posix_acl_entry a_entries[] __counted_by(a_count);
};
static_assert(offsetof(struct posix_acl, a_entries) == sizeof(struct posix_acl_hdr),
"struct member likely outside of struct_group_tagged()");
#define FOREACH_ACL_ENTRY(pa, acl, pe) \
for(pa=(acl)->a_entries, pe=pa+(acl)->a_count; pa<pe; pa++)
/*
* Duplicate an ACL handle.
*/
static inline struct posix_acl *
posix_acl_dup(struct posix_acl *acl)
{
if (acl)
refcount_inc(&acl->a_refcount);
return acl;
}
/*
* Free an ACL handle.
*/
static inline void
posix_acl_release(struct posix_acl *acl)
{
if (acl && refcount_dec_and_test(&acl->a_refcount))
kfree_rcu(acl, a_rcu);
}
/* posix_acl.c */
extern void posix_acl_init(struct posix_acl *, int);
extern struct posix_acl *posix_acl_alloc(unsigned int count, gfp_t flags);
extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t);
extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *);
extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
extern int __posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
extern struct posix_acl *get_posix_acl(struct inode *, int);
int set_posix_acl(struct mnt_idmap *, struct dentry *, int,
struct posix_acl *);
struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type);
struct posix_acl *posix_acl_clone(const struct posix_acl *acl, gfp_t flags);
#ifdef CONFIG_FS_POSIX_ACL
int posix_acl_chmod(struct mnt_idmap *, struct dentry *, umode_t);
extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
struct posix_acl **);
int posix_acl_update_mode(struct mnt_idmap *, struct inode *, umode_t *,
struct posix_acl **);
int simple_set_acl(struct mnt_idmap *, struct dentry *,
struct posix_acl *, int);
extern int simple_acl_create(struct inode *, struct inode *);
struct posix_acl *get_cached_acl(struct inode *inode, int type);
void set_cached_acl(struct inode *inode, int type, struct posix_acl *acl);
void forget_cached_acl(struct inode *inode, int type);
void forget_all_cached_acls(struct inode *inode);
int posix_acl_valid(struct user_namespace *, const struct posix_acl *);
int posix_acl_permission(struct mnt_idmap *, struct inode *,
const struct posix_acl *, int);
static inline void cache_no_acl(struct inode *inode)
{
inode->i_acl = NULL;
inode->i_default_acl = NULL;
}
int vfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
const char *acl_name, struct posix_acl *kacl);
struct posix_acl *vfs_get_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name);
int vfs_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
const char *acl_name);
int posix_acl_listxattr(struct inode *inode, char **buffer,
ssize_t *remaining_size);
#else
static inline int posix_acl_chmod(struct mnt_idmap *idmap,
struct dentry *dentry, umode_t mode)
{
return 0;
}
#define simple_set_acl NULL
static inline int simple_acl_create(struct inode *dir, struct inode *inode)
{
return 0;
}
static inline void cache_no_acl(struct inode *inode)
{
}
static inline int posix_acl_create(struct inode *inode, umode_t *mode,
struct posix_acl **default_acl, struct posix_acl **acl)
{
*default_acl = *acl = NULL;
return 0;
}
static inline void forget_all_cached_acls(struct inode *inode)
{
}
static inline int vfs_set_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *name,
struct posix_acl *acl)
{
return -EOPNOTSUPP;
}
static inline struct posix_acl *vfs_get_acl(struct mnt_idmap *idmap,
struct dentry *dentry,
const char *acl_name)
{
return ERR_PTR(-EOPNOTSUPP);
}
static inline int vfs_remove_acl(struct mnt_idmap *idmap,
struct dentry *dentry, const char *acl_name)
{
return -EOPNOTSUPP;
}
static inline int posix_acl_listxattr(struct inode *inode, char **buffer,
ssize_t *remaining_size)
{
return 0;
}
#endif /* CONFIG_FS_POSIX_ACL */
struct posix_acl *get_inode_acl(struct inode *inode, int type);
#endif /* __LINUX_POSIX_ACL_H */