summaryrefslogtreecommitdiffstats
path: root/include/net/flow.h
diff options
context:
space:
mode:
authorNiklas Cassel <cassel@kernel.org>2026-09-18 16:06:42 +0200
committerJens Axboe <axboe@kernel.dk>2026-09-29 12:54:47 -0600
commit684b413b5483f57c890c171b9400076a0143b918 (patch)
treef167daddad3dce9af44773541373eafbccc9ac61 /include/net/flow.h
downloadlinux-stable-684b413b5483f57c890c171b9400076a0143b918.tar.gz
linux-stable-684b413b5483f57c890c171b9400076a0143b918.zip
virtio_blk: set the zone write granularitygrafted
virtblk_read_zoned_limits() reads the write granularity that the device reports in virtio_blk_zoned_characteristics and assigns it to the physical block size and to io_min, but never to the limit that is named after it. queue_limits.zone_write_granularity is left at zero, so blk_validate_zoned_limits() raises it to the logical block size: if (lim->zone_write_granularity < lim->logical_block_size) lim->zone_write_granularity = lim->logical_block_size; A device that reports a granularity coarser than its logical block size, which is what the field exists to express, therefore has it silently reduced. A 512e host managed disk passed through to a guest reports a logical block size of 512 and a write granularity of 4096, and the guest ends up with a zone write granularity of 512. bio_split_alignment() returns lim->zone_write_granularity if it is non-zero and bio_split_io_at() may split a bio with as per bio_split_alignment(). This can real to the write getting rejected by the host drive, as the write is not aligned to the physical block size. zonefs also takes its block size from bdev_zone_write_granularity(), so it would incorrectly use 512 on a disk that requires 4096. sd_zbc_read_zones() sets the limit from the physical block size for the same reason. NVMe ZNS and null_blk leave it unset, but the fallback gives the right answer for them, as their write granularity is the logical block size. virtio carries a separate value that may exceed it. Set the zone write granularity from the value that the device reports. Fixes: 95bfec41bd3d ("virtio-blk: add support for zoned block devices") Signed-off-by: Niklas Cassel <cassel@kernel.org> Reviewed-by: Stefan Hajnoczi <stefanha@redhat.com> Link: https://patch.msgid.link/20260918140641.2031075-2-cassel@kernel.org Signed-off-by: Jens Axboe <axboe@kernel.dk>
Diffstat (limited to 'include/net/flow.h')
-rw-r--r--include/net/flow.h198
1 files changed, 198 insertions, 0 deletions
diff --git a/include/net/flow.h b/include/net/flow.h
new file mode 100644
index 000000000..ae9481c40
--- /dev/null
+++ b/include/net/flow.h
@@ -0,0 +1,198 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ *
+ * Generic internet FLOW.
+ *
+ */
+
+#ifndef _NET_FLOW_H
+#define _NET_FLOW_H
+
+#include <linux/in6.h>
+#include <linux/atomic.h>
+#include <linux/container_of.h>
+#include <linux/uidgid.h>
+#include <net/inet_dscp.h>
+
+struct flow_keys;
+
+/*
+ * ifindex generation is per-net namespace, and loopback is
+ * always the 1st device in ns (see net_dev_init), thus any
+ * loopback device should get ifindex 1
+ */
+
+#define LOOPBACK_IFINDEX 1
+
+struct flowi_tunnel {
+ __be64 tun_id;
+};
+
+struct flowi_common {
+ int flowic_oif;
+ int flowic_iif;
+ int flowic_l3mdev;
+ __u32 flowic_mark;
+ dscp_t flowic_dscp;
+ __u8 flowic_scope;
+ __u8 flowic_proto;
+ __u8 flowic_flags;
+#define FLOWI_FLAG_ANYSRC 0x01
+#define FLOWI_FLAG_KNOWN_NH 0x02
+#define FLOWI_FLAG_L3MDEV_OIF 0x04
+#define FLOWI_FLAG_ANY_SPORT 0x08
+ __u32 flowic_secid;
+ kuid_t flowic_uid;
+ __u32 flowic_multipath_hash;
+ struct flowi_tunnel flowic_tun_key;
+};
+
+union flowi_uli {
+ struct {
+ __be16 dport;
+ __be16 sport;
+ } ports;
+
+ struct {
+ __u8 type;
+ __u8 code;
+ } icmpt;
+
+ __be32 gre_key;
+
+ struct {
+ __u8 type;
+ } mht;
+};
+
+struct flowi4 {
+ struct flowi_common __fl_common;
+#define flowi4_oif __fl_common.flowic_oif
+#define flowi4_iif __fl_common.flowic_iif
+#define flowi4_l3mdev __fl_common.flowic_l3mdev
+#define flowi4_mark __fl_common.flowic_mark
+#define flowi4_dscp __fl_common.flowic_dscp
+#define flowi4_scope __fl_common.flowic_scope
+#define flowi4_proto __fl_common.flowic_proto
+#define flowi4_flags __fl_common.flowic_flags
+#define flowi4_secid __fl_common.flowic_secid
+#define flowi4_tun_key __fl_common.flowic_tun_key
+#define flowi4_uid __fl_common.flowic_uid
+#define flowi4_multipath_hash __fl_common.flowic_multipath_hash
+
+ /* (saddr,daddr) must be grouped, same order as in IP header */
+ __be32 saddr;
+ __be32 daddr;
+
+ union flowi_uli uli;
+#define fl4_sport uli.ports.sport
+#define fl4_dport uli.ports.dport
+#define fl4_icmp_type uli.icmpt.type
+#define fl4_icmp_code uli.icmpt.code
+#define fl4_mh_type uli.mht.type
+#define fl4_gre_key uli.gre_key
+} __attribute__((__aligned__(BITS_PER_LONG/8)));
+
+static inline void flowi4_init_output(struct flowi4 *fl4, int oif,
+ __u32 mark, __u8 tos, __u8 scope,
+ __u8 proto, __u8 flags,
+ __be32 daddr, __be32 saddr,
+ __be16 dport, __be16 sport,
+ kuid_t uid)
+{
+ fl4->flowi4_oif = oif;
+ fl4->flowi4_iif = LOOPBACK_IFINDEX;
+ fl4->flowi4_l3mdev = 0;
+ fl4->flowi4_mark = mark;
+ fl4->flowi4_dscp = inet_dsfield_to_dscp(tos);
+ fl4->flowi4_scope = scope;
+ fl4->flowi4_proto = proto;
+ fl4->flowi4_flags = flags;
+ fl4->flowi4_secid = 0;
+ fl4->flowi4_tun_key.tun_id = 0;
+ fl4->flowi4_uid = uid;
+ fl4->daddr = daddr;
+ fl4->saddr = saddr;
+ fl4->fl4_dport = dport;
+ fl4->fl4_sport = sport;
+ fl4->flowi4_multipath_hash = 0;
+}
+
+/* Reset some input parameters after previous lookup */
+static inline void flowi4_update_output(struct flowi4 *fl4, int oif,
+ __be32 daddr, __be32 saddr)
+{
+ fl4->flowi4_oif = oif;
+ fl4->daddr = daddr;
+ fl4->saddr = saddr;
+}
+
+
+struct flowi6 {
+ struct flowi_common __fl_common;
+#define flowi6_oif __fl_common.flowic_oif
+#define flowi6_iif __fl_common.flowic_iif
+#define flowi6_l3mdev __fl_common.flowic_l3mdev
+#define flowi6_mark __fl_common.flowic_mark
+#define flowi6_scope __fl_common.flowic_scope
+#define flowi6_proto __fl_common.flowic_proto
+#define flowi6_flags __fl_common.flowic_flags
+#define flowi6_secid __fl_common.flowic_secid
+#define flowi6_tun_key __fl_common.flowic_tun_key
+#define flowi6_uid __fl_common.flowic_uid
+ struct in6_addr daddr;
+ struct in6_addr saddr;
+ /* Note: flowi6_dscp is encoded in flowlabel, too. */
+ __be32 flowlabel;
+ union flowi_uli uli;
+#define fl6_sport uli.ports.sport
+#define fl6_dport uli.ports.dport
+#define fl6_icmp_type uli.icmpt.type
+#define fl6_icmp_code uli.icmpt.code
+#define fl6_mh_type uli.mht.type
+#define fl6_gre_key uli.gre_key
+ __u32 mp_hash;
+} __attribute__((__aligned__(BITS_PER_LONG/8)));
+
+struct flowi {
+ union {
+ struct flowi_common __fl_common;
+ struct flowi4 ip4;
+ struct flowi6 ip6;
+ } u;
+#define flowi_oif u.__fl_common.flowic_oif
+#define flowi_iif u.__fl_common.flowic_iif
+#define flowi_l3mdev u.__fl_common.flowic_l3mdev
+#define flowi_mark u.__fl_common.flowic_mark
+#define flowi_dscp u.__fl_common.flowic_dscp
+#define flowi_scope u.__fl_common.flowic_scope
+#define flowi_proto u.__fl_common.flowic_proto
+#define flowi_flags u.__fl_common.flowic_flags
+#define flowi_secid u.__fl_common.flowic_secid
+#define flowi_tun_key u.__fl_common.flowic_tun_key
+#define flowi_uid u.__fl_common.flowic_uid
+} __attribute__((__aligned__(BITS_PER_LONG/8)));
+
+static inline struct flowi *flowi4_to_flowi(struct flowi4 *fl4)
+{
+ return container_of(fl4, struct flowi, u.ip4);
+}
+
+static inline struct flowi_common *flowi4_to_flowi_common(struct flowi4 *fl4)
+{
+ return &(fl4->__fl_common);
+}
+
+static inline struct flowi *flowi6_to_flowi(struct flowi6 *fl6)
+{
+ return container_of(fl6, struct flowi, u.ip6);
+}
+
+static inline struct flowi_common *flowi6_to_flowi_common(struct flowi6 *fl6)
+{
+ return &(fl6->__fl_common);
+}
+
+__u32 __get_hash_from_flowi6(const struct flowi6 *fl6, struct flow_keys *keys);
+
+#endif