From: Christoph Hellwig <hch@infradead.org>
To: NeilBrown <neil@brown.name>
Cc: "Gustavo A. R. Silva" <gustavoars@kernel.org>,
Chuck Lever <chuck.lever@oracle.com>,
Jeff Layton <jlayton@kernel.org>,
Olga Kornievskaia <okorniev@redhat.com>,
Dai Ngo <Dai.Ngo@oracle.com>, Tom Talpey <tom@talpey.com>,
linux-nfs@vger.kernel.org, linux-kernel@vger.kernel.org,
linux-hardening@vger.kernel.org
Subject: Re: [PATCH][next] NFSD: Avoid multiple -Wflex-array-member-not-at-end warnings
Date: Tue, 6 May 2025 23:04:05 -0700 [thread overview]
Message-ID: <aBr31WNad6GFOTda@infradead.org> (raw)
In-Reply-To: <174657431631.3924073.6654014165534485350@noble.neil.brown.name>
On Wed, May 07, 2025 at 09:31:56AM +1000, NeilBrown wrote:
> struct knfsd_fh has a fixed size determined by NFS4_FHSIZE.
> The fact that fh_fsid is "flexible" doesn't mean it is unlimited in
> size. So moving it to the end of other structures is silencing a
> warning but leaving the code as potentially confusing.
>
> Maybe just make it
> u32 fh_fsid[4]; /* in practice the size varies but is always
> * limited by fh_raw above
Don't make this more complicated than needed. Just killing the
magic union overlay over the raw array just complicates things, so
just use indices into it. Below is a simple version, but this can
use some more work to split things up and to entirely avoid the
not exactly natural u32-based addressing in various helpers.
diff --git a/fs/nfsd/export.c b/fs/nfsd/export.c
index 0363720280d4..804aa679a992 100644
--- a/fs/nfsd/export.c
+++ b/fs/nfsd/export.c
@@ -1230,7 +1230,7 @@ rqst_exp_get_by_name(struct svc_rqst *rqstp, struct path *path)
struct svc_export *
rqst_exp_find(struct cache_req *reqp, struct net *net,
struct auth_domain *cl, struct auth_domain *gsscl,
- int fsid_type, u32 *fsidv)
+ int fsid_type, void *fsidv)
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
struct svc_export *gssexp, *exp = ERR_PTR(-ENOENT);
diff --git a/fs/nfsd/export.h b/fs/nfsd/export.h
index 4d92b99c1ffd..9b2719d8a3e2 100644
--- a/fs/nfsd/export.h
+++ b/fs/nfsd/export.h
@@ -131,6 +131,6 @@ static inline struct svc_export *exp_get(struct svc_export *exp)
}
struct svc_export *rqst_exp_find(struct cache_req *reqp, struct net *net,
struct auth_domain *cl, struct auth_domain *gsscl,
- int fsid_type, u32 *fsidv);
+ int fsid_type, void *fsidv);
#endif /* NFSD_EXPORT_H */
diff --git a/fs/nfsd/nfs4layouts.c b/fs/nfsd/nfs4layouts.c
index 290271ac4245..6dcd2c9ec15b 100644
--- a/fs/nfsd/nfs4layouts.c
+++ b/fs/nfsd/nfs4layouts.c
@@ -56,7 +56,7 @@ static void
nfsd4_alloc_devid_map(const struct svc_fh *fhp)
{
const struct knfsd_fh *fh = &fhp->fh_handle;
- size_t fsid_len = key_len(fh->fh_fsid_type);
+ size_t fsid_len = key_len(fh->fh_raw[FH_FSID_TYPE]);
struct nfsd4_deviceid_map *map, *old;
int i;
@@ -64,8 +64,8 @@ nfsd4_alloc_devid_map(const struct svc_fh *fhp)
if (!map)
return;
- map->fsid_type = fh->fh_fsid_type;
- memcpy(&map->fsid, fh->fh_fsid, fsid_len);
+ map->fsid_type = fh->fh_raw[FH_FSID_TYPE];
+ memcpy(&map->fsid, fh->fh_raw + FH_FSID, fsid_len);
spin_lock(&nfsd_devid_lock);
if (fhp->fh_export->ex_devid_map)
@@ -73,9 +73,9 @@ nfsd4_alloc_devid_map(const struct svc_fh *fhp)
for (i = 0; i < DEVID_HASH_SIZE; i++) {
list_for_each_entry(old, &nfsd_devid_hash[i], hash) {
- if (old->fsid_type != fh->fh_fsid_type)
+ if (old->fsid_type != map->fsid_type)
continue;
- if (memcmp(old->fsid, fh->fh_fsid,
+ if (memcmp(old->fsid, map->fsid,
key_len(old->fsid_type)))
continue;
diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
index aef474f1b84b..f58da563d4fd 100644
--- a/fs/nfsd/nfsfh.c
+++ b/fs/nfsd/nfsfh.c
@@ -161,37 +161,40 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct net *net,
if (fh->fh_size == 0)
return nfserr_nofilehandle;
- if (fh->fh_version != 1)
+ if (fh->fh_raw[FH_VERSION] != 1)
return error;
if (--data_left < 0)
return error;
- if (fh->fh_auth_type != 0)
+ if (fh->fh_raw[FH_AUTH_TYPE] != 0)
return error;
- len = key_len(fh->fh_fsid_type) / 4;
+ len = key_len(fh->fh_raw[FH_FSID_TYPE]) / 4;
if (len == 0)
return error;
- if (fh->fh_fsid_type == FSID_MAJOR_MINOR) {
+ if (fh->fh_raw[FH_FSID_TYPE] == FSID_MAJOR_MINOR) {
/* deprecated, convert to type 3 */
+ u32 *fsidv = (u32 *)(fh->fh_raw + FH_FSID);
+
len = key_len(FSID_ENCODE_DEV)/4;
- fh->fh_fsid_type = FSID_ENCODE_DEV;
+ fh->fh_raw[FH_FSID_TYPE] = FSID_ENCODE_DEV;
/*
* struct knfsd_fh uses host-endian fields, which are
* sometimes used to hold net-endian values. This
* confuses sparse, so we must use __force here to
* keep it from complaining.
*/
- fh->fh_fsid[0] = new_encode_dev(MKDEV(ntohl((__force __be32)fh->fh_fsid[0]),
- ntohl((__force __be32)fh->fh_fsid[1])));
- fh->fh_fsid[1] = fh->fh_fsid[2];
+ fsidv[0] = new_encode_dev(MKDEV(
+ ntohl((__force __be32)fsidv[0]),
+ ntohl((__force __be32)fsidv[1])));
+ fsidv[1] = fsidv[2];
}
data_left -= len;
if (data_left < 0)
return error;
exp = rqst_exp_find(rqstp ? &rqstp->rq_chandle : NULL,
net, client, gssclient,
- fh->fh_fsid_type, fh->fh_fsid);
- fid = (struct fid *)(fh->fh_fsid + len);
+ fh->fh_raw[FH_FSID_TYPE], fh->fh_raw + FH_FSID);
+ fid = (struct fid *)(fh->fh_raw + FH_FSID + len);
error = nfserr_stale;
if (IS_ERR(exp)) {
@@ -233,7 +236,7 @@ static __be32 nfsd_set_fh_dentry(struct svc_rqst *rqstp, struct net *net,
*/
error = nfserr_badhandle;
- fileid_type = fh->fh_fileid_type;
+ fileid_type = fh->fh_raw[FH_FILEID_TYPE];
if (fileid_type == FILEID_ROOT)
dentry = dget(exp->ex_path.dentry);
@@ -463,18 +466,19 @@ static void _fh_update(struct svc_fh *fhp, struct svc_export *exp,
{
if (dentry != exp->ex_path.dentry) {
struct fid *fid = (struct fid *)
- (fhp->fh_handle.fh_fsid + fhp->fh_handle.fh_size/4 - 1);
+ (fhp->fh_handle.fh_raw + FH_FSID +
+ fhp->fh_handle.fh_size - 1);
int maxsize = (fhp->fh_maxsize - fhp->fh_handle.fh_size)/4;
int fh_flags = (exp->ex_flags & NFSEXP_NOSUBTREECHECK) ? 0 :
EXPORT_FH_CONNECTABLE;
int fileid_type =
exportfs_encode_fh(dentry, fid, &maxsize, fh_flags);
- fhp->fh_handle.fh_fileid_type =
+ fhp->fh_handle.fh_raw[FH_FILEID_TYPE] =
fileid_type > 0 ? fileid_type : FILEID_INVALID;
fhp->fh_handle.fh_size += maxsize * 4;
} else {
- fhp->fh_handle.fh_fileid_type = FILEID_ROOT;
+ fhp->fh_handle.fh_raw[FH_FILEID_TYPE] = FILEID_ROOT;
}
}
@@ -520,8 +524,8 @@ static void set_version_and_fsid_type(struct svc_fh *fhp, struct svc_export *exp
retry:
version = 1;
if (ref_fh && ref_fh->fh_export == exp) {
- version = ref_fh->fh_handle.fh_version;
- fsid_type = ref_fh->fh_handle.fh_fsid_type;
+ version = ref_fh->fh_handle.fh_raw[FH_VERSION];
+ fsid_type = ref_fh->fh_handle.fh_raw[FH_FSID_TYPE];
ref_fh = NULL;
@@ -562,9 +566,9 @@ static void set_version_and_fsid_type(struct svc_fh *fhp, struct svc_export *exp
fsid_type = FSID_ENCODE_DEV;
else
fsid_type = FSID_DEV;
- fhp->fh_handle.fh_version = version;
+ fhp->fh_handle.fh_raw[FH_VERSION] = version;
if (version)
- fhp->fh_handle.fh_fsid_type = fsid_type;
+ fhp->fh_handle.fh_raw[FH_FSID_TYPE] = fsid_type;
}
__be32
@@ -610,18 +614,18 @@ fh_compose(struct svc_fh *fhp, struct svc_export *exp, struct dentry *dentry,
fhp->fh_export = exp_get(exp);
fhp->fh_handle.fh_size =
- key_len(fhp->fh_handle.fh_fsid_type) + 4;
- fhp->fh_handle.fh_auth_type = 0;
+ key_len(fhp->fh_handle.fh_raw[FH_FSID_TYPE]) + 4;
+ fhp->fh_handle.fh_raw[FH_AUTH_TYPE] = 0;
- mk_fsid(fhp->fh_handle.fh_fsid_type,
- fhp->fh_handle.fh_fsid,
+ mk_fsid(fhp->fh_handle.fh_raw[FH_FSID_TYPE],
+ fhp->fh_handle.fh_raw + FH_FSID,
ex_dev,
d_inode(exp->ex_path.dentry)->i_ino,
exp->ex_fsid, exp->ex_uuid);
if (inode)
_fh_update(fhp, exp, dentry);
- if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID) {
+ if (fhp->fh_handle.fh_raw[FH_FILEID_TYPE] == FILEID_INVALID) {
fh_put(fhp);
return nfserr_stale;
}
@@ -644,11 +648,11 @@ fh_update(struct svc_fh *fhp)
dentry = fhp->fh_dentry;
if (d_really_is_negative(dentry))
goto out_negative;
- if (fhp->fh_handle.fh_fileid_type != FILEID_ROOT)
+ if (fhp->fh_handle.fh_raw[FH_FILEID_TYPE] != FILEID_ROOT)
return 0;
_fh_update(fhp, fhp->fh_export, dentry);
- if (fhp->fh_handle.fh_fileid_type == FILEID_INVALID)
+ if (fhp->fh_handle.fh_raw[FH_FILEID_TYPE] == FILEID_INVALID)
return nfserr_stale;
return 0;
out_bad:
@@ -776,9 +780,9 @@ char * SVCFH_fmt(struct svc_fh *fhp)
enum fsid_source fsid_source(const struct svc_fh *fhp)
{
- if (fhp->fh_handle.fh_version != 1)
+ if (fhp->fh_handle.fh_raw[FH_VERSION] != 1)
return FSIDSOURCE_DEV;
- switch(fhp->fh_handle.fh_fsid_type) {
+ switch(fhp->fh_handle.fh_raw[FH_FSID_TYPE]) {
case FSID_DEV:
case FSID_ENCODE_DEV:
case FSID_MAJOR_MINOR:
diff --git a/fs/nfsd/nfsfh.h b/fs/nfsd/nfsfh.h
index 5103c2f4d225..26975ede465a 100644
--- a/fs/nfsd/nfsfh.h
+++ b/fs/nfsd/nfsfh.h
@@ -43,22 +43,17 @@
* filesystems must not use the values '0' or '0xff'. 'See enum fid_type'
* in include/linux/exportfs.h for currently registered values.
*/
-
struct knfsd_fh {
unsigned int fh_size; /*
* Points to the current size while
* building a new file handle.
*/
- union {
- char fh_raw[NFS4_FHSIZE];
- struct {
- u8 fh_version; /* == 1 */
- u8 fh_auth_type; /* deprecated */
- u8 fh_fsid_type;
- u8 fh_fileid_type;
- u32 fh_fsid[]; /* flexible-array member */
- };
- };
+ char fh_raw[NFS4_FHSIZE];
+#define FH_VERSION 0
+#define FH_AUTH_TYPE 1
+#define FH_FSID_TYPE 2
+#define FH_FILEID_TYPE 3
+#define FH_FSID 4
};
static inline __u32 ino_t_to_u32(ino_t ino)
@@ -141,10 +136,12 @@ extern enum fsid_source fsid_source(const struct svc_fh *fhp);
* sparse from complaining. Since these values are opaque to the
* client, that shouldn't be a problem.
*/
-static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino,
- u32 fsid, unsigned char *uuid)
+static inline void mk_fsid(int vers, void *fsid, dev_t dev, ino_t ino,
+ u32 fsid_num, unsigned char *uuid)
{
+ u32 *fsidv = fsid;
u32 *up;
+
switch(vers) {
case FSID_DEV:
fsidv[0] = (__force __u32)htonl((MAJOR(dev)<<16) |
@@ -152,7 +149,7 @@ static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino,
fsidv[1] = ino_t_to_u32(ino);
break;
case FSID_NUM:
- fsidv[0] = fsid;
+ fsidv[0] = fsid_num;
break;
case FSID_MAJOR_MINOR:
fsidv[0] = (__force __u32)htonl(MAJOR(dev));
@@ -260,9 +257,10 @@ static inline bool fh_match(const struct knfsd_fh *fh1,
static inline bool fh_fsid_match(const struct knfsd_fh *fh1,
const struct knfsd_fh *fh2)
{
- if (fh1->fh_fsid_type != fh2->fh_fsid_type)
+ if (fh1->fh_raw[FH_FSID_TYPE] != fh2->fh_raw[FH_FSID_TYPE])
return false;
- if (memcmp(fh1->fh_fsid, fh2->fh_fsid, key_len(fh1->fh_fsid_type)) != 0)
+ if (memcmp(fh1->fh_raw + FH_FSID, fh2->fh_raw + FH_FSID,
+ key_len(fh1->fh_raw[FH_FSID_TYPE])) != 0)
return false;
return true;
}
prev parent reply other threads:[~2025-05-07 6:04 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-06 20:58 [PATCH][next] NFSD: Avoid multiple -Wflex-array-member-not-at-end warnings Gustavo A. R. Silva
2025-05-06 23:31 ` NeilBrown
2025-05-07 6:04 ` Christoph Hellwig [this message]
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=aBr31WNad6GFOTda@infradead.org \
--to=hch@infradead.org \
--cc=Dai.Ngo@oracle.com \
--cc=chuck.lever@oracle.com \
--cc=gustavoars@kernel.org \
--cc=jlayton@kernel.org \
--cc=linux-hardening@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-nfs@vger.kernel.org \
--cc=neil@brown.name \
--cc=okorniev@redhat.com \
--cc=tom@talpey.com \
/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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.