NFSv4/flexfiles: Use the full 64-bit stripe_unit

ff_layout_alloc_lseg() decodes stripe_unit as the 64-bit value the
protocol defines and struct nfs4_ff_layout_segment stores it as one, but
both consumers narrow it back to 32 bits: nfs4_ff_layout_calc_dss_id()
divides with do_div(), which casts the divisor, and ff_layout_pg_test()
copies it into a u32 first.  A stripe_unit that does not fit is silently
truncated, so the client stripes on a unit the server did not specify --
or divides by zero, if the low 32 bits happen to be clear.

Divide by the full value, with div64_u64() and div64_u64_rem().

Fixes: 20b1d75fb8 ("NFSv4/flexfiles: Add support for striped layouts")
Cc: stable@vger.kernel.org
Assisted-by: Claude:claude-fable-5
Signed-off-by: Benjamin Coddington <bcodding@hammerspace.com>
Signed-off-by: Anna Schumaker <anna.schumaker@hammerspace.com>
This commit is contained in:
Benjamin Coddington 2026-09-15 08:22:04 -04:00 committed by Anna Schumaker
parent a7c8e96d1b
commit 0cc1191538
2 changed files with 7 additions and 7 deletions

View File

@ -995,9 +995,9 @@ ff_layout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
{
unsigned int size;
u64 p_stripe, r_stripe;
u32 stripe_offset;
u64 stripe_offset;
u64 segment_offset = pgio->pg_lseg->pls_range.offset;
u32 stripe_unit = FF_LAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;
u64 stripe_unit = FF_LAYOUT_LSEG(pgio->pg_lseg)->stripe_unit;
/* calls nfs_generic_pg_test */
size = pnfs_generic_pg_test(pgio, prev, req);
@ -1010,21 +1010,21 @@ ff_layout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev,
if (prev) {
p_stripe = (u64)req_offset(prev) - segment_offset;
r_stripe = (u64)req_offset(req) - segment_offset;
do_div(p_stripe, stripe_unit);
do_div(r_stripe, stripe_unit);
p_stripe = div64_u64(p_stripe, stripe_unit);
r_stripe = div64_u64(r_stripe, stripe_unit);
if (p_stripe != r_stripe)
return 0;
}
/* calculate remaining bytes in the current stripe */
div_u64_rem((u64)req_offset(req) - segment_offset,
div64_u64_rem((u64)req_offset(req) - segment_offset,
stripe_unit,
&stripe_offset);
WARN_ON_ONCE(stripe_offset > stripe_unit);
if (stripe_offset >= stripe_unit)
return 0;
return min(stripe_unit - (unsigned int)stripe_offset, size);
return min_t(u64, stripe_unit - stripe_offset, size);
}
static void

View File

@ -220,7 +220,7 @@ nfs4_ff_layout_calc_dss_id(const u64 stripe_unit, const u32 dss_count, const lof
if (dss_count == 1 || stripe_unit == 0)
return 0;
do_div(tmp, stripe_unit);
tmp = div64_u64(tmp, stripe_unit);
return do_div(tmp, dss_count);
}