* FAILED: patch "[PATCH] NFSv4/flexfiles: reject zero filehandle version count" failed to apply to 6.12-stable tree
@ 2026-07-02 13:55 gregkh
2026-07-05 3:11 ` [PATCH 6.12.y 1/5] nfsd: add nfsd_file_{get,put} to 'nfs_to' nfsd_localio_operations Sasha Levin
0 siblings, 1 reply; 6+ messages in thread
From: gregkh @ 2026-07-02 13:55 UTC (permalink / raw)
To: michael.bommarito, anna.schumaker; +Cc: stable
The patch below does not apply to the 6.12-stable tree.
If someone wants it applied there, or to any other stable or longterm
tree, then please email the backport, including the original git commit
id to <stable@vger.kernel.org>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.12.y
git checkout FETCH_HEAD
git cherry-pick -x 2c6bb3c40bc24f6aa8dfbe6fe98c3ad6389203f2
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<stable@vger.kernel.org>' --in-reply-to '2026070242-poker-barricade-3a69@gregkh' --subject-prefix 'PATCH 6.12.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 2c6bb3c40bc24f6aa8dfbe6fe98c3ad6389203f2 Mon Sep 17 00:00:00 2001
From: Michael Bommarito <michael.bommarito@gmail.com>
Date: Wed, 13 May 2026 12:26:56 -0400
Subject: [PATCH] NFSv4/flexfiles: reject zero filehandle version count
ff_layout_alloc_lseg() decodes the filehandle-version array count
from the flexfiles layout body. The value is used as the count for
kzalloc_objs(), and the current code only rejects NULL.
A zero count yields ZERO_SIZE_PTR, which can be stored in
dss_info->fh_versions even though later flexfiles paths assume that at
least one filehandle version exists.
Reject fh_count == 0 before the allocation, matching the existing zero
version_count validation in the flexfiles GETDEVICEINFO parser.
A QEMU/KASAN run with a malformed flexfiles layout hit:
KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
RIP: 0010:ff_layout_encode_ff_layoutupdate.isra.0+0x15f/0x750
ff_layout_encode_layoutreturn+0x683/0x970
nfs4_xdr_enc_layoutreturn+0x278/0x3a0
Kernel panic - not syncing: Fatal exception
The patched kernel rejects the malformed layout without KASAN/oops/panic,
and a valid fh_count=1 regression still opens, reads, and unmounts cleanly.
Cc: stable@vger.kernel.org
Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver")
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
index 6a84d85e0651..99caa8d28c25 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.c
+++ b/fs/nfs/flexfilelayout/flexfilelayout.c
@@ -551,6 +551,10 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
if (!p)
goto out_err_free;
fh_count = be32_to_cpup(p);
+ if (fh_count == 0) {
+ rc = -EINVAL;
+ goto out_err_free;
+ }
dss_info->fh_versions =
kzalloc_objs(struct nfs_fh, fh_count, gfp_flags);
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6.12.y 1/5] nfsd: add nfsd_file_{get,put} to 'nfs_to' nfsd_localio_operations
2026-07-02 13:55 FAILED: patch "[PATCH] NFSv4/flexfiles: reject zero filehandle version count" failed to apply to 6.12-stable tree gregkh
@ 2026-07-05 3:11 ` Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 2/5] nfs_common: rename functions that invalidate LOCALIO nfs_clients Sasha Levin
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Sasha Levin @ 2026-07-05 3:11 UTC (permalink / raw)
To: stable; +Cc: Mike Snitzer, Jeff Layton, Chuck Lever, Anna Schumaker,
Sasha Levin
From: Mike Snitzer <snitzer@kernel.org>
[ Upstream commit a61466315d7afca032342183a57e62d5e3a3157c ]
In later a commit LOCALIO must call both nfsd_file_get and
nfsd_file_put to manage extra nfsd_file references.
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Acked-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
Stable-dep-of: 2c6bb3c40bc2 ("NFSv4/flexfiles: reject zero filehandle version count")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfsd/localio.c | 2 ++
include/linux/nfslocalio.h | 2 ++
2 files changed, 4 insertions(+)
diff --git a/fs/nfsd/localio.c b/fs/nfsd/localio.c
index ce6d408598c788..f9a91cd3b5ec74 100644
--- a/fs/nfsd/localio.c
+++ b/fs/nfsd/localio.c
@@ -29,6 +29,8 @@ static const struct nfsd_localio_operations nfsd_localio_ops = {
.nfsd_net_put = nfsd_net_put,
.nfsd_open_local_fh = nfsd_open_local_fh,
.nfsd_file_put_local = nfsd_file_put_local,
+ .nfsd_file_get = nfsd_file_get,
+ .nfsd_file_put = nfsd_file_put,
.nfsd_file_file = nfsd_file_file,
};
diff --git a/include/linux/nfslocalio.h b/include/linux/nfslocalio.h
index e1b8018ba6399a..7b2a86213d9e9f 100644
--- a/include/linux/nfslocalio.h
+++ b/include/linux/nfslocalio.h
@@ -56,6 +56,8 @@ struct nfsd_localio_operations {
const struct nfs_fh *,
const fmode_t);
struct net *(*nfsd_file_put_local)(struct nfsd_file *);
+ struct nfsd_file *(*nfsd_file_get)(struct nfsd_file *);
+ void (*nfsd_file_put)(struct nfsd_file *);
struct file *(*nfsd_file_file)(struct nfsd_file *);
} ____cacheline_aligned;
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6.12.y 2/5] nfs_common: rename functions that invalidate LOCALIO nfs_clients
2026-07-05 3:11 ` [PATCH 6.12.y 1/5] nfsd: add nfsd_file_{get,put} to 'nfs_to' nfsd_localio_operations Sasha Levin
@ 2026-07-05 3:11 ` Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 3/5] NFSv4/flexfiles: Remove cred local variable dependency Sasha Levin
` (2 subsequent siblings)
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-07-05 3:11 UTC (permalink / raw)
To: stable; +Cc: Mike Snitzer, NeilBrown, Jeff Layton, Anna Schumaker, Sasha Levin
From: Mike Snitzer <snitzer@kernel.org>
[ Upstream commit b49f049a22227df701bfbca083d6cc859496e615 ]
Rename nfs_uuid_invalidate_one_client to nfs_localio_disable_client.
Rename nfs_uuid_invalidate_clients to nfs_localio_invalidate_clients.
Signed-off-by: Mike Snitzer <snitzer@kernel.org>
Reviewed-by: NeilBrown <neilb@suse.de>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
Stable-dep-of: 2c6bb3c40bc2 ("NFSv4/flexfiles: reject zero filehandle version count")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfs/localio.c | 2 +-
fs/nfs_common/nfslocalio.c | 8 ++++----
fs/nfsd/nfsctl.c | 4 ++--
include/linux/nfslocalio.h | 5 +++--
4 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/fs/nfs/localio.c b/fs/nfs/localio.c
index 84fe3ef21b6da9..c59f205b513081 100644
--- a/fs/nfs/localio.c
+++ b/fs/nfs/localio.c
@@ -141,7 +141,7 @@ void nfs_local_disable(struct nfs_client *clp)
spin_lock(&clp->cl_localio_lock);
if (test_and_clear_bit(NFS_CS_LOCAL_IO, &clp->cl_flags)) {
trace_nfs_local_disable(clp);
- nfs_uuid_invalidate_one_client(&clp->cl_uuid);
+ nfs_localio_disable_client(&clp->cl_uuid);
}
spin_unlock(&clp->cl_localio_lock);
}
diff --git a/fs/nfs_common/nfslocalio.c b/fs/nfs_common/nfslocalio.c
index e6fbc45ec4f149..ae07ec16550218 100644
--- a/fs/nfs_common/nfslocalio.c
+++ b/fs/nfs_common/nfslocalio.c
@@ -107,7 +107,7 @@ static void nfs_uuid_put_locked(nfs_uuid_t *nfs_uuid)
list_del_init(&nfs_uuid->list);
}
-void nfs_uuid_invalidate_clients(struct list_head *list)
+void nfs_localio_invalidate_clients(struct list_head *list)
{
nfs_uuid_t *nfs_uuid, *tmp;
@@ -116,9 +116,9 @@ void nfs_uuid_invalidate_clients(struct list_head *list)
nfs_uuid_put_locked(nfs_uuid);
spin_unlock(&nfs_uuid_lock);
}
-EXPORT_SYMBOL_GPL(nfs_uuid_invalidate_clients);
+EXPORT_SYMBOL_GPL(nfs_localio_invalidate_clients);
-void nfs_uuid_invalidate_one_client(nfs_uuid_t *nfs_uuid)
+void nfs_localio_disable_client(nfs_uuid_t *nfs_uuid)
{
if (nfs_uuid->net) {
spin_lock(&nfs_uuid_lock);
@@ -126,7 +126,7 @@ void nfs_uuid_invalidate_one_client(nfs_uuid_t *nfs_uuid)
spin_unlock(&nfs_uuid_lock);
}
}
-EXPORT_SYMBOL_GPL(nfs_uuid_invalidate_one_client);
+EXPORT_SYMBOL_GPL(nfs_localio_disable_client);
/*
* Caller is responsible for calling nfsd_net_put and
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 6b37d939a6ceb1..7b0a6beee96ed8 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -2296,14 +2296,14 @@ static __net_init int nfsd_net_init(struct net *net)
* nfsd_net_pre_exit - Disconnect localio clients from net namespace
* @net: a network namespace that is about to be destroyed
*
- * This invalidated ->net pointers held by localio clients
+ * This invalidates ->net pointers held by localio clients
* while they can still safely access nn->counter.
*/
static __net_exit void nfsd_net_pre_exit(struct net *net)
{
struct nfsd_net *nn = net_generic(net, nfsd_net_id);
- nfs_uuid_invalidate_clients(&nn->local_clients);
+ nfs_localio_invalidate_clients(&nn->local_clients);
}
#endif
diff --git a/include/linux/nfslocalio.h b/include/linux/nfslocalio.h
index 7b2a86213d9e9f..6d87b7a78680a5 100644
--- a/include/linux/nfslocalio.h
+++ b/include/linux/nfslocalio.h
@@ -37,8 +37,9 @@ bool nfs_uuid_begin(nfs_uuid_t *);
void nfs_uuid_end(nfs_uuid_t *);
void nfs_uuid_is_local(const uuid_t *, struct list_head *,
struct net *, struct auth_domain *, struct module *);
-void nfs_uuid_invalidate_clients(struct list_head *list);
-void nfs_uuid_invalidate_one_client(nfs_uuid_t *nfs_uuid);
+
+void nfs_localio_disable_client(nfs_uuid_t *nfs_uuid);
+void nfs_localio_invalidate_clients(struct list_head *list);
/* localio needs to map filehandle -> struct nfsd_file */
extern struct nfsd_file *
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6.12.y 3/5] NFSv4/flexfiles: Remove cred local variable dependency
2026-07-05 3:11 ` [PATCH 6.12.y 1/5] nfsd: add nfsd_file_{get,put} to 'nfs_to' nfsd_localio_operations Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 2/5] nfs_common: rename functions that invalidate LOCALIO nfs_clients Sasha Levin
@ 2026-07-05 3:11 ` Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 4/5] NFSv4/flexfiles: Add data structure support for striped layouts Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 5/5] NFSv4/flexfiles: reject zero filehandle version count Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-07-05 3:11 UTC (permalink / raw)
To: stable; +Cc: Jonathan Curley, Anna Schumaker, Sasha Levin
From: Jonathan Curley <jcurley@purestorage.com>
[ Upstream commit fec80afc41afa3016421115427df8d00dc491ee5 ]
No-op preparation change to remove dependency on cred local
variable. Subsequent striping diff has a cred per stripe so this local
variable can't be trusted to be the same.
Signed-off-by: Jonathan Curley <jcurley@purestorage.com>
Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
Stable-dep-of: 2c6bb3c40bc2 ("NFSv4/flexfiles: reject zero filehandle version count")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfs/flexfilelayout/flexfilelayout.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
index 6469846971966b..8d43ba6e3ecc23 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.c
+++ b/fs/nfs/flexfilelayout/flexfilelayout.c
@@ -531,10 +531,10 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
if (mirror != fls->mirror_array[i]) {
/* swap cred ptrs so free_mirror will clean up old */
if (lgr->range.iomode == IOMODE_READ) {
- cred = xchg(&mirror->ro_cred, cred);
+ cred = xchg(&mirror->ro_cred, fls->mirror_array[i]->ro_cred);
rcu_assign_pointer(fls->mirror_array[i]->ro_cred, cred);
} else {
- cred = xchg(&mirror->rw_cred, cred);
+ cred = xchg(&mirror->rw_cred, fls->mirror_array[i]->rw_cred);
rcu_assign_pointer(fls->mirror_array[i]->rw_cred, cred);
}
ff_layout_free_mirror(fls->mirror_array[i]);
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6.12.y 4/5] NFSv4/flexfiles: Add data structure support for striped layouts
2026-07-05 3:11 ` [PATCH 6.12.y 1/5] nfsd: add nfsd_file_{get,put} to 'nfs_to' nfsd_localio_operations Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 2/5] nfs_common: rename functions that invalidate LOCALIO nfs_clients Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 3/5] NFSv4/flexfiles: Remove cred local variable dependency Sasha Levin
@ 2026-07-05 3:11 ` Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 5/5] NFSv4/flexfiles: reject zero filehandle version count Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-07-05 3:11 UTC (permalink / raw)
To: stable; +Cc: Jonathan Curley, Anna Schumaker, Sasha Levin
From: Jonathan Curley <jcurley@purestorage.com>
[ Upstream commit d442670c0f63c46b7f348f68fb2002af597708f2 ]
Adds a new struct nfs4_ff_layout_ds_stripe that represents a data
server stripe within a layout. A new dynamically allocated array of
this type has been added to nfs4_ff_layout_mirror and per stripe
configuration information has been moved from the mirror type to the
stripe based on the RFC.
Signed-off-by: Jonathan Curley <jcurley@purestorage.com>
Signed-off-by: Anna Schumaker <anna.schumaker@oracle.com>
Stable-dep-of: 2c6bb3c40bc2 ("NFSv4/flexfiles: reject zero filehandle version count")
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfs/flexfilelayout/flexfilelayout.c | 149 ++++++++++++----------
fs/nfs/flexfilelayout/flexfilelayout.h | 27 ++--
fs/nfs/flexfilelayout/flexfilelayoutdev.c | 54 ++++----
3 files changed, 128 insertions(+), 102 deletions(-)
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
index 8d43ba6e3ecc23..36270f6a759ec7 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.c
+++ b/fs/nfs/flexfilelayout/flexfilelayout.c
@@ -183,13 +183,13 @@ static bool ff_mirror_match_fh(const struct nfs4_ff_layout_mirror *m1,
{
int i, j;
- if (m1->fh_versions_cnt != m2->fh_versions_cnt)
+ if (m1->dss[0].fh_versions_cnt != m2->dss[0].fh_versions_cnt)
return false;
- for (i = 0; i < m1->fh_versions_cnt; i++) {
+ for (i = 0; i < m1->dss[0].fh_versions_cnt; i++) {
bool found_fh = false;
- for (j = 0; j < m2->fh_versions_cnt; j++) {
- if (nfs_compare_fh(&m1->fh_versions[i],
- &m2->fh_versions[j]) == 0) {
+ for (j = 0; j < m2->dss[0].fh_versions_cnt; j++) {
+ if (nfs_compare_fh(&m1->dss[0].fh_versions[i],
+ &m2->dss[0].fh_versions[j]) == 0) {
found_fh = true;
break;
}
@@ -210,7 +210,8 @@ ff_layout_add_mirror(struct pnfs_layout_hdr *lo,
spin_lock(&inode->i_lock);
list_for_each_entry(pos, &ff_layout->mirrors, mirrors) {
- if (memcmp(&mirror->devid, &pos->devid, sizeof(pos->devid)) != 0)
+ if (memcmp(&mirror->dss[0].devid, &pos->dss[0].devid,
+ sizeof(pos->dss[0].devid)) != 0)
continue;
if (!ff_mirror_match_fh(mirror, pos))
continue;
@@ -238,30 +239,46 @@ ff_layout_remove_mirror(struct nfs4_ff_layout_mirror *mirror)
mirror->layout = NULL;
}
-static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(gfp_t gfp_flags)
+static struct nfs4_ff_layout_mirror *ff_layout_alloc_mirror(u32 dss_count,
+ gfp_t gfp_flags)
{
struct nfs4_ff_layout_mirror *mirror;
mirror = kzalloc(sizeof(*mirror), gfp_flags);
- if (mirror != NULL) {
- spin_lock_init(&mirror->lock);
- refcount_set(&mirror->ref, 1);
- INIT_LIST_HEAD(&mirror->mirrors);
+ if (mirror == NULL)
+ return NULL;
+
+ spin_lock_init(&mirror->lock);
+ refcount_set(&mirror->ref, 1);
+ INIT_LIST_HEAD(&mirror->mirrors);
+
+ mirror->dss_count = dss_count;
+ mirror->dss =
+ kcalloc(dss_count, sizeof(struct nfs4_ff_layout_ds_stripe),
+ gfp_flags);
+ if (mirror->dss == NULL) {
+ kfree(mirror);
+ return NULL;
}
+
return mirror;
}
static void ff_layout_free_mirror(struct nfs4_ff_layout_mirror *mirror)
{
- const struct cred *cred;
+ const struct cred *cred;
+ int dss_id = 0;
ff_layout_remove_mirror(mirror);
- kfree(mirror->fh_versions);
- cred = rcu_access_pointer(mirror->ro_cred);
+
+ kfree(mirror->dss[dss_id].fh_versions);
+ cred = rcu_access_pointer(mirror->dss[dss_id].ro_cred);
put_cred(cred);
- cred = rcu_access_pointer(mirror->rw_cred);
+ cred = rcu_access_pointer(mirror->dss[dss_id].rw_cred);
put_cred(cred);
- nfs4_ff_layout_put_deviceid(mirror->mirror_ds);
+ nfs4_ff_layout_put_deviceid(mirror->dss[dss_id].mirror_ds);
+
+ kfree(mirror->dss);
kfree(mirror);
}
@@ -371,8 +388,8 @@ static void ff_layout_sort_mirrors(struct nfs4_ff_layout_segment *fls)
for (i = 0; i < fls->mirror_array_cnt - 1; i++) {
for (j = i + 1; j < fls->mirror_array_cnt; j++)
- if (fls->mirror_array[i]->efficiency <
- fls->mirror_array[j]->efficiency)
+ if (fls->mirror_array[i]->dss[0].efficiency <
+ fls->mirror_array[j]->dss[0].efficiency)
swap(fls->mirror_array[i],
fls->mirror_array[j]);
}
@@ -426,35 +443,35 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
fls->mirror_array_cnt = mirror_array_cnt;
fls->stripe_unit = stripe_unit;
+ u32 dss_count = 0;
for (i = 0; i < fls->mirror_array_cnt; i++) {
struct nfs4_ff_layout_mirror *mirror;
struct cred *kcred;
const struct cred __rcu *cred;
kuid_t uid;
kgid_t gid;
- u32 ds_count, fh_count, id;
- int j;
+ u32 fh_count, id;
+ int j, dss_id = 0;
rc = -EIO;
p = xdr_inline_decode(&stream, 4);
if (!p)
goto out_err_free;
- ds_count = be32_to_cpup(p);
+
+ dss_count = be32_to_cpup(p);
/* FIXME: allow for striping? */
- if (ds_count != 1)
+ if (dss_count != 1)
goto out_err_free;
- fls->mirror_array[i] = ff_layout_alloc_mirror(gfp_flags);
+ fls->mirror_array[i] = ff_layout_alloc_mirror(dss_count, gfp_flags);
if (fls->mirror_array[i] == NULL) {
rc = -ENOMEM;
goto out_err_free;
}
- fls->mirror_array[i]->ds_count = ds_count;
-
/* deviceid */
- rc = decode_deviceid(&stream, &fls->mirror_array[i]->devid);
+ rc = decode_deviceid(&stream, &fls->mirror_array[i]->dss[dss_id].devid);
if (rc)
goto out_err_free;
@@ -463,10 +480,10 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
p = xdr_inline_decode(&stream, 4);
if (!p)
goto out_err_free;
- fls->mirror_array[i]->efficiency = be32_to_cpup(p);
+ fls->mirror_array[i]->dss[dss_id].efficiency = be32_to_cpup(p);
/* stateid */
- rc = decode_pnfs_stateid(&stream, &fls->mirror_array[i]->stateid);
+ rc = decode_pnfs_stateid(&stream, &fls->mirror_array[i]->dss[dss_id].stateid);
if (rc)
goto out_err_free;
@@ -477,22 +494,22 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
goto out_err_free;
fh_count = be32_to_cpup(p);
- fls->mirror_array[i]->fh_versions =
- kcalloc(fh_count, sizeof(struct nfs_fh),
- gfp_flags);
- if (fls->mirror_array[i]->fh_versions == NULL) {
+ fls->mirror_array[i]->dss[dss_id].fh_versions =
+ kcalloc(fh_count, sizeof(struct nfs_fh),
+ gfp_flags);
+ if (fls->mirror_array[i]->dss[dss_id].fh_versions == NULL) {
rc = -ENOMEM;
goto out_err_free;
}
for (j = 0; j < fh_count; j++) {
rc = decode_nfs_fh(&stream,
- &fls->mirror_array[i]->fh_versions[j]);
+ &fls->mirror_array[i]->dss[dss_id].fh_versions[j]);
if (rc)
goto out_err_free;
}
- fls->mirror_array[i]->fh_versions_cnt = fh_count;
+ fls->mirror_array[i]->dss[dss_id].fh_versions_cnt = fh_count;
/* user */
rc = decode_name(&stream, &id);
@@ -523,19 +540,21 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
cred = RCU_INITIALIZER(kcred);
if (lgr->range.iomode == IOMODE_READ)
- rcu_assign_pointer(fls->mirror_array[i]->ro_cred, cred);
+ rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].ro_cred, cred);
else
- rcu_assign_pointer(fls->mirror_array[i]->rw_cred, cred);
+ rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].rw_cred, cred);
mirror = ff_layout_add_mirror(lh, fls->mirror_array[i]);
if (mirror != fls->mirror_array[i]) {
/* swap cred ptrs so free_mirror will clean up old */
if (lgr->range.iomode == IOMODE_READ) {
- cred = xchg(&mirror->ro_cred, fls->mirror_array[i]->ro_cred);
- rcu_assign_pointer(fls->mirror_array[i]->ro_cred, cred);
+ cred = xchg(&mirror->dss[dss_id].ro_cred,
+ fls->mirror_array[i]->dss[dss_id].ro_cred);
+ rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].ro_cred, cred);
} else {
- cred = xchg(&mirror->rw_cred, fls->mirror_array[i]->rw_cred);
- rcu_assign_pointer(fls->mirror_array[i]->rw_cred, cred);
+ cred = xchg(&mirror->dss[dss_id].rw_cred,
+ fls->mirror_array[i]->dss[dss_id].rw_cred);
+ rcu_assign_pointer(fls->mirror_array[i]->dss[dss_id].rw_cred, cred);
}
ff_layout_free_mirror(fls->mirror_array[i]);
fls->mirror_array[i] = mirror;
@@ -623,8 +642,8 @@ nfs4_ff_layoutstat_start_io(struct nfs4_ff_layout_mirror *mirror,
struct nfs4_flexfile_layout *ffl = FF_LAYOUT_FROM_HDR(mirror->layout);
nfs4_ff_start_busy_timer(&layoutstat->busy_timer, now);
- if (!mirror->start_time)
- mirror->start_time = now;
+ if (!mirror->dss[0].start_time)
+ mirror->dss[0].start_time = now;
if (mirror->report_interval != 0)
report_interval = (s64)mirror->report_interval * 1000LL;
else if (layoutstats_timer != 0)
@@ -679,8 +698,8 @@ nfs4_ff_layout_stat_io_start_read(struct inode *inode,
bool report;
spin_lock(&mirror->lock);
- report = nfs4_ff_layoutstat_start_io(mirror, &mirror->read_stat, now);
- nfs4_ff_layout_stat_io_update_requested(&mirror->read_stat, requested);
+ report = nfs4_ff_layoutstat_start_io(mirror, &mirror->dss[0].read_stat, now);
+ nfs4_ff_layout_stat_io_update_requested(&mirror->dss[0].read_stat, requested);
set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
spin_unlock(&mirror->lock);
@@ -695,7 +714,7 @@ nfs4_ff_layout_stat_io_end_read(struct rpc_task *task,
__u64 completed)
{
spin_lock(&mirror->lock);
- nfs4_ff_layout_stat_io_update_completed(&mirror->read_stat,
+ nfs4_ff_layout_stat_io_update_completed(&mirror->dss[0].read_stat,
requested, completed,
ktime_get(), task->tk_start);
set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
@@ -710,8 +729,8 @@ nfs4_ff_layout_stat_io_start_write(struct inode *inode,
bool report;
spin_lock(&mirror->lock);
- report = nfs4_ff_layoutstat_start_io(mirror , &mirror->write_stat, now);
- nfs4_ff_layout_stat_io_update_requested(&mirror->write_stat, requested);
+ report = nfs4_ff_layoutstat_start_io(mirror, &mirror->dss[0].write_stat, now);
+ nfs4_ff_layout_stat_io_update_requested(&mirror->dss[0].write_stat, requested);
set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
spin_unlock(&mirror->lock);
@@ -730,7 +749,7 @@ nfs4_ff_layout_stat_io_end_write(struct rpc_task *task,
requested = completed = 0;
spin_lock(&mirror->lock);
- nfs4_ff_layout_stat_io_update_completed(&mirror->write_stat,
+ nfs4_ff_layout_stat_io_update_completed(&mirror->dss[0].write_stat,
requested, completed, ktime_get(), task->tk_start);
set_bit(NFS4_FF_MIRROR_STAT_AVAIL, &mirror->flags);
spin_unlock(&mirror->lock);
@@ -772,7 +791,7 @@ ff_layout_choose_ds_for_read(struct pnfs_layout_segment *lseg,
continue;
if (check_device &&
- nfs4_test_deviceid_unavailable(&mirror->mirror_ds->id_node)) {
+ nfs4_test_deviceid_unavailable(&mirror->dss[0].mirror_ds->id_node)) {
// reinitialize the error state in case if this is the last iteration
ds = ERR_PTR(-EINVAL);
continue;
@@ -881,7 +900,7 @@ ff_layout_pg_init_read(struct nfs_pageio_descriptor *pgio,
mirror = FF_LAYOUT_COMP(pgio->pg_lseg, ds_idx);
pgm = &pgio->pg_mirrors[0];
- pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].rsize;
+ pgm->pg_bsize = mirror->dss[0].mirror_ds->ds_versions[0].rsize;
pgio->pg_mirror_idx = ds_idx;
return;
@@ -953,7 +972,7 @@ ff_layout_pg_init_write(struct nfs_pageio_descriptor *pgio,
goto retry;
}
pgm = &pgio->pg_mirrors[i];
- pgm->pg_bsize = mirror->mirror_ds->ds_versions[0].wsize;
+ pgm->pg_bsize = mirror->dss[0].mirror_ds->ds_versions[0].wsize;
}
if (NFS_SERVER(pgio->pg_inode)->flags &
@@ -2013,7 +2032,7 @@ select_ds_fh_from_commit(struct pnfs_layout_segment *lseg, u32 i)
/* FIXME: Assume that there is only one NFS version available
* for the DS.
*/
- return &flseg->mirror_array[i]->fh_versions[0];
+ return &flseg->mirror_array[i]->dss[0].fh_versions[0];
}
static int ff_layout_initiate_commit(struct nfs_commit_data *data, int how)
@@ -2129,10 +2148,10 @@ static void ff_layout_cancel_io(struct pnfs_layout_segment *lseg)
for (idx = 0; idx < flseg->mirror_array_cnt; idx++) {
mirror = flseg->mirror_array[idx];
- mirror_ds = mirror->mirror_ds;
+ mirror_ds = mirror->dss[0].mirror_ds;
if (IS_ERR_OR_NULL(mirror_ds))
continue;
- ds = mirror->mirror_ds->ds;
+ ds = mirror->dss[0].mirror_ds->ds;
if (!ds)
continue;
ds_clp = ds->ds_clp;
@@ -2533,8 +2552,8 @@ ff_layout_encode_ff_layoutupdate(struct xdr_stream *xdr,
struct nfs4_ff_layout_mirror *mirror)
{
struct nfs4_pnfs_ds_addr *da;
- struct nfs4_pnfs_ds *ds = mirror->mirror_ds->ds;
- struct nfs_fh *fh = &mirror->fh_versions[0];
+ struct nfs4_pnfs_ds *ds = mirror->dss[0].mirror_ds->ds;
+ struct nfs_fh *fh = &mirror->dss[0].fh_versions[0];
__be32 *p;
da = list_first_entry(&ds->ds_addrs, struct nfs4_pnfs_ds_addr, da_node);
@@ -2547,12 +2566,12 @@ ff_layout_encode_ff_layoutupdate(struct xdr_stream *xdr,
xdr_encode_opaque(p, fh->data, fh->size);
/* ff_io_latency4 read */
spin_lock(&mirror->lock);
- ff_layout_encode_io_latency(xdr, &mirror->read_stat.io_stat);
+ ff_layout_encode_io_latency(xdr, &mirror->dss[0].read_stat.io_stat);
/* ff_io_latency4 write */
- ff_layout_encode_io_latency(xdr, &mirror->write_stat.io_stat);
+ ff_layout_encode_io_latency(xdr, &mirror->dss[0].write_stat.io_stat);
spin_unlock(&mirror->lock);
/* nfstime4 */
- ff_layout_encode_nfstime(xdr, ktime_sub(ktime_get(), mirror->start_time));
+ ff_layout_encode_nfstime(xdr, ktime_sub(ktime_get(), mirror->dss[0].start_time));
/* bool */
p = xdr_reserve_space(xdr, 4);
*p = cpu_to_be32(false);
@@ -2599,7 +2618,7 @@ ff_layout_mirror_prepare_stats(struct pnfs_layout_hdr *lo,
list_for_each_entry(mirror, &ff_layout->mirrors, mirrors) {
if (i >= dev_limit)
break;
- if (IS_ERR_OR_NULL(mirror->mirror_ds))
+ if (IS_ERR_OR_NULL(mirror->dss[0].mirror_ds))
continue;
if (!test_and_clear_bit(NFS4_FF_MIRROR_STAT_AVAIL,
&mirror->flags) &&
@@ -2608,15 +2627,15 @@ ff_layout_mirror_prepare_stats(struct pnfs_layout_hdr *lo,
/* mirror refcount put in cleanup_layoutstats */
if (!refcount_inc_not_zero(&mirror->ref))
continue;
- dev = &mirror->mirror_ds->id_node;
+ dev = &mirror->dss[0].mirror_ds->id_node;
memcpy(&devinfo->dev_id, &dev->deviceid, NFS4_DEVICEID4_SIZE);
devinfo->offset = 0;
devinfo->length = NFS4_MAX_UINT64;
spin_lock(&mirror->lock);
- devinfo->read_count = mirror->read_stat.io_stat.ops_completed;
- devinfo->read_bytes = mirror->read_stat.io_stat.bytes_completed;
- devinfo->write_count = mirror->write_stat.io_stat.ops_completed;
- devinfo->write_bytes = mirror->write_stat.io_stat.bytes_completed;
+ devinfo->read_count = mirror->dss[0].read_stat.io_stat.ops_completed;
+ devinfo->read_bytes = mirror->dss[0].read_stat.io_stat.bytes_completed;
+ devinfo->write_count = mirror->dss[0].write_stat.io_stat.ops_completed;
+ devinfo->write_bytes = mirror->dss[0].write_stat.io_stat.bytes_completed;
spin_unlock(&mirror->lock);
devinfo->layout_type = LAYOUT_FLEX_FILES;
devinfo->ld_private.ops = &layoutstat_ops;
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.h b/fs/nfs/flexfilelayout/flexfilelayout.h
index f84b3fb0dddd80..cf688889c91887 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.h
+++ b/fs/nfs/flexfilelayout/flexfilelayout.h
@@ -71,24 +71,31 @@ struct nfs4_ff_layoutstat {
struct nfs4_ff_busy_timer busy_timer;
};
-struct nfs4_ff_layout_mirror {
- struct pnfs_layout_hdr *layout;
- struct list_head mirrors;
- u32 ds_count;
- u32 efficiency;
+struct nfs4_ff_layout_mirror;
+
+struct nfs4_ff_layout_ds_stripe {
+ struct nfs4_ff_layout_mirror *mirror;
struct nfs4_deviceid devid;
+ u32 efficiency;
struct nfs4_ff_layout_ds *mirror_ds;
u32 fh_versions_cnt;
struct nfs_fh *fh_versions;
nfs4_stateid stateid;
const struct cred __rcu *ro_cred;
const struct cred __rcu *rw_cred;
- refcount_t ref;
- spinlock_t lock;
- unsigned long flags;
struct nfs4_ff_layoutstat read_stat;
struct nfs4_ff_layoutstat write_stat;
ktime_t start_time;
+};
+
+struct nfs4_ff_layout_mirror {
+ struct pnfs_layout_hdr *layout;
+ struct list_head mirrors;
+ u32 dss_count;
+ struct nfs4_ff_layout_ds_stripe *dss;
+ refcount_t ref;
+ spinlock_t lock;
+ unsigned long flags;
u32 report_interval;
};
@@ -154,7 +161,7 @@ FF_LAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg, u32 idx)
struct nfs4_ff_layout_mirror *mirror = FF_LAYOUT_COMP(lseg, idx);
if (mirror != NULL) {
- struct nfs4_ff_layout_ds *mirror_ds = mirror->mirror_ds;
+ struct nfs4_ff_layout_ds *mirror_ds = mirror->dss[0].mirror_ds;
if (!IS_ERR_OR_NULL(mirror_ds))
return &mirror_ds->id_node;
@@ -183,7 +190,7 @@ ff_layout_no_read_on_rw(struct pnfs_layout_segment *lseg)
static inline int
nfs4_ff_layout_ds_version(const struct nfs4_ff_layout_mirror *mirror)
{
- return mirror->mirror_ds->ds_versions[0].version;
+ return mirror->dss[0].mirror_ds->ds_versions[0].version;
}
struct nfs4_ff_layout_ds *
diff --git a/fs/nfs/flexfilelayout/flexfilelayoutdev.c b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
index 5ab9ac32f858e0..9c127565870ec4 100644
--- a/fs/nfs/flexfilelayout/flexfilelayoutdev.c
+++ b/fs/nfs/flexfilelayout/flexfilelayoutdev.c
@@ -259,7 +259,7 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
if (status == 0)
return 0;
- if (IS_ERR_OR_NULL(mirror->mirror_ds))
+ if (IS_ERR_OR_NULL(mirror->dss[0].mirror_ds))
return -EINVAL;
dserr = kmalloc(sizeof(*dserr), gfp_flags);
@@ -271,8 +271,8 @@ int ff_layout_track_ds_error(struct nfs4_flexfile_layout *flo,
dserr->length = length;
dserr->status = status;
dserr->opnum = opnum;
- nfs4_stateid_copy(&dserr->stateid, &mirror->stateid);
- memcpy(&dserr->deviceid, &mirror->mirror_ds->id_node.deviceid,
+ nfs4_stateid_copy(&dserr->stateid, &mirror->dss[0].stateid);
+ memcpy(&dserr->deviceid, &mirror->dss[0].mirror_ds->id_node.deviceid,
NFS4_DEVICEID4_SIZE);
spin_lock(&flo->generic_hdr.plh_inode->i_lock);
@@ -287,9 +287,9 @@ ff_layout_get_mirror_cred(struct nfs4_ff_layout_mirror *mirror, u32 iomode)
const struct cred *cred, __rcu **pcred;
if (iomode == IOMODE_READ)
- pcred = &mirror->ro_cred;
+ pcred = &mirror->dss[0].ro_cred;
else
- pcred = &mirror->rw_cred;
+ pcred = &mirror->dss[0].rw_cred;
rcu_read_lock();
do {
@@ -307,7 +307,7 @@ struct nfs_fh *
nfs4_ff_layout_select_ds_fh(struct nfs4_ff_layout_mirror *mirror)
{
/* FIXME: For now assume there is only 1 version available for the DS */
- return &mirror->fh_versions[0];
+ return &mirror->dss[0].fh_versions[0];
}
void
@@ -315,7 +315,7 @@ nfs4_ff_layout_select_ds_stateid(const struct nfs4_ff_layout_mirror *mirror,
nfs4_stateid *stateid)
{
if (nfs4_ff_layout_ds_version(mirror) == 4)
- nfs4_stateid_copy(stateid, &mirror->stateid);
+ nfs4_stateid_copy(stateid, &mirror->dss[0].stateid);
}
static bool
@@ -324,23 +324,23 @@ ff_layout_init_mirror_ds(struct pnfs_layout_hdr *lo,
{
if (mirror == NULL)
goto outerr;
- if (mirror->mirror_ds == NULL) {
+ if (mirror->dss[0].mirror_ds == NULL) {
struct nfs4_deviceid_node *node;
struct nfs4_ff_layout_ds *mirror_ds = ERR_PTR(-ENODEV);
node = nfs4_find_get_deviceid(NFS_SERVER(lo->plh_inode),
- &mirror->devid, lo->plh_lc_cred,
+ &mirror->dss[0].devid, lo->plh_lc_cred,
GFP_KERNEL);
if (node)
mirror_ds = FF_LAYOUT_MIRROR_DS(node);
/* check for race with another call to this function */
- if (cmpxchg(&mirror->mirror_ds, NULL, mirror_ds) &&
+ if (cmpxchg(&mirror->dss[0].mirror_ds, NULL, mirror_ds) &&
mirror_ds != ERR_PTR(-ENODEV))
nfs4_put_deviceid_node(node);
}
- if (IS_ERR(mirror->mirror_ds))
+ if (IS_ERR(mirror->dss[0].mirror_ds))
goto outerr;
return true;
@@ -379,7 +379,7 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
if (!ff_layout_init_mirror_ds(lseg->pls_layout, mirror))
goto noconnect;
- ds = mirror->mirror_ds->ds;
+ ds = mirror->dss[0].mirror_ds->ds;
if (READ_ONCE(ds->ds_clp))
goto out;
/* matching smp_wmb() in _nfs4_pnfs_v3/4_ds_connect */
@@ -388,10 +388,10 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
/* FIXME: For now we assume the server sent only one version of NFS
* to use for the DS.
*/
- status = nfs4_pnfs_ds_connect(s, ds, &mirror->mirror_ds->id_node,
+ status = nfs4_pnfs_ds_connect(s, ds, &mirror->dss[0].mirror_ds->id_node,
dataserver_timeo, dataserver_retrans,
- mirror->mirror_ds->ds_versions[0].version,
- mirror->mirror_ds->ds_versions[0].minor_version);
+ mirror->dss[0].mirror_ds->ds_versions[0].version,
+ mirror->dss[0].mirror_ds->ds_versions[0].minor_version);
/* connect success, check rsize/wsize limit */
if (!status) {
@@ -404,10 +404,10 @@ nfs4_ff_layout_prepare_ds(struct pnfs_layout_segment *lseg,
max_payload =
nfs_block_size(rpc_max_payload(ds->ds_clp->cl_rpcclient),
NULL);
- if (mirror->mirror_ds->ds_versions[0].rsize > max_payload)
- mirror->mirror_ds->ds_versions[0].rsize = max_payload;
- if (mirror->mirror_ds->ds_versions[0].wsize > max_payload)
- mirror->mirror_ds->ds_versions[0].wsize = max_payload;
+ if (mirror->dss[0].mirror_ds->ds_versions[0].rsize > max_payload)
+ mirror->dss[0].mirror_ds->ds_versions[0].rsize = max_payload;
+ if (mirror->dss[0].mirror_ds->ds_versions[0].wsize > max_payload)
+ mirror->dss[0].mirror_ds->ds_versions[0].wsize = max_payload;
goto out;
}
noconnect:
@@ -430,7 +430,7 @@ ff_layout_get_ds_cred(struct nfs4_ff_layout_mirror *mirror,
{
const struct cred *cred;
- if (mirror && !mirror->mirror_ds->ds_versions[0].tightly_coupled) {
+ if (mirror && !mirror->dss[0].mirror_ds->ds_versions[0].tightly_coupled) {
cred = ff_layout_get_mirror_cred(mirror, range->iomode);
if (!cred)
cred = get_cred(mdscred);
@@ -453,7 +453,7 @@ struct rpc_clnt *
nfs4_ff_find_or_create_ds_client(struct nfs4_ff_layout_mirror *mirror,
struct nfs_client *ds_clp, struct inode *inode)
{
- switch (mirror->mirror_ds->ds_versions[0].version) {
+ switch (mirror->dss[0].mirror_ds->ds_versions[0].version) {
case 3:
/* For NFSv3 DS, flavor is set when creating DS connections */
return ds_clp->cl_rpcclient;
@@ -564,11 +564,11 @@ static bool ff_read_layout_has_available_ds(struct pnfs_layout_segment *lseg)
for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) {
mirror = FF_LAYOUT_COMP(lseg, idx);
if (mirror) {
- if (!mirror->mirror_ds)
+ if (!mirror->dss[0].mirror_ds)
return true;
- if (IS_ERR(mirror->mirror_ds))
+ if (IS_ERR(mirror->dss[0].mirror_ds))
continue;
- devid = &mirror->mirror_ds->id_node;
+ devid = &mirror->dss[0].mirror_ds->id_node;
if (!nfs4_test_deviceid_unavailable(devid))
return true;
}
@@ -585,11 +585,11 @@ static bool ff_rw_layout_has_available_ds(struct pnfs_layout_segment *lseg)
for (idx = 0; idx < FF_LAYOUT_MIRROR_COUNT(lseg); idx++) {
mirror = FF_LAYOUT_COMP(lseg, idx);
- if (!mirror || IS_ERR(mirror->mirror_ds))
+ if (!mirror || IS_ERR(mirror->dss[0].mirror_ds))
return false;
- if (!mirror->mirror_ds)
+ if (!mirror->dss[0].mirror_ds)
continue;
- devid = &mirror->mirror_ds->id_node;
+ devid = &mirror->dss[0].mirror_ds->id_node;
if (nfs4_test_deviceid_unavailable(devid))
return false;
}
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 6.12.y 5/5] NFSv4/flexfiles: reject zero filehandle version count
2026-07-05 3:11 ` [PATCH 6.12.y 1/5] nfsd: add nfsd_file_{get,put} to 'nfs_to' nfsd_localio_operations Sasha Levin
` (2 preceding siblings ...)
2026-07-05 3:11 ` [PATCH 6.12.y 4/5] NFSv4/flexfiles: Add data structure support for striped layouts Sasha Levin
@ 2026-07-05 3:11 ` Sasha Levin
3 siblings, 0 replies; 6+ messages in thread
From: Sasha Levin @ 2026-07-05 3:11 UTC (permalink / raw)
To: stable; +Cc: Michael Bommarito, Anna Schumaker, Sasha Levin
From: Michael Bommarito <michael.bommarito@gmail.com>
[ Upstream commit 2c6bb3c40bc24f6aa8dfbe6fe98c3ad6389203f2 ]
ff_layout_alloc_lseg() decodes the filehandle-version array count
from the flexfiles layout body. The value is used as the count for
kzalloc_objs(), and the current code only rejects NULL.
A zero count yields ZERO_SIZE_PTR, which can be stored in
dss_info->fh_versions even though later flexfiles paths assume that at
least one filehandle version exists.
Reject fh_count == 0 before the allocation, matching the existing zero
version_count validation in the flexfiles GETDEVICEINFO parser.
A QEMU/KASAN run with a malformed flexfiles layout hit:
KASAN: null-ptr-deref in range [0x0000000000000010-0x0000000000000017]
RIP: 0010:ff_layout_encode_ff_layoutupdate.isra.0+0x15f/0x750
ff_layout_encode_layoutreturn+0x683/0x970
nfs4_xdr_enc_layoutreturn+0x278/0x3a0
Kernel panic - not syncing: Fatal exception
The patched kernel rejects the malformed layout without KASAN/oops/panic,
and a valid fh_count=1 regression still opens, reads, and unmounts cleanly.
Cc: stable@vger.kernel.org
Fixes: d67ae825a59d ("pnfs/flexfiles: Add the FlexFile Layout Driver")
Assisted-by: Claude:claude-opus-4-7
Signed-off-by: Michael Bommarito <michael.bommarito@gmail.com>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---
fs/nfs/flexfilelayout/flexfilelayout.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/fs/nfs/flexfilelayout/flexfilelayout.c b/fs/nfs/flexfilelayout/flexfilelayout.c
index 36270f6a759ec7..7e1494cc116b29 100644
--- a/fs/nfs/flexfilelayout/flexfilelayout.c
+++ b/fs/nfs/flexfilelayout/flexfilelayout.c
@@ -493,6 +493,10 @@ ff_layout_alloc_lseg(struct pnfs_layout_hdr *lh,
if (!p)
goto out_err_free;
fh_count = be32_to_cpup(p);
+ if (fh_count == 0) {
+ rc = -EINVAL;
+ goto out_err_free;
+ }
fls->mirror_array[i]->dss[dss_id].fh_versions =
kcalloc(fh_count, sizeof(struct nfs_fh),
--
2.53.0
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-07-05 3:11 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-02 13:55 FAILED: patch "[PATCH] NFSv4/flexfiles: reject zero filehandle version count" failed to apply to 6.12-stable tree gregkh
2026-07-05 3:11 ` [PATCH 6.12.y 1/5] nfsd: add nfsd_file_{get,put} to 'nfs_to' nfsd_localio_operations Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 2/5] nfs_common: rename functions that invalidate LOCALIO nfs_clients Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 3/5] NFSv4/flexfiles: Remove cred local variable dependency Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 4/5] NFSv4/flexfiles: Add data structure support for striped layouts Sasha Levin
2026-07-05 3:11 ` [PATCH 6.12.y 5/5] NFSv4/flexfiles: reject zero filehandle version count Sasha Levin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox