block-7.0-20260227

-----BEGIN PGP SIGNATURE-----
 
 iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmmhxjgQHGF4Ym9lQGtl
 cm5lbC5kawAKCRD301j7KXHgpqZND/9ZHjUX2BhtEHWayTLpgBl5JYeYvNnxgeKw
 MsQjmkDBJDdpxz5s5Y6zY+OKDhWv+o4VgfgykK5bpn5/kXgwqvKSK9QroVSl6OPk
 JTFo3PQ0KhuZQyBxX+zZPNjgV/Kzop4j7NuNrovrIEJtvgVZuwJx/0h/DdpLez3N
 +l9jWQcjLjFJHHnTuV9Tv1jqhcPU5vxkkEWlZgwkWMxdghMWWw5JDHxGt1w3g6c8
 4Qmn1G3SqAPEItQ+ugU+BL+vYVKVm9/Gaa4JWJTm8d1ADmQxd1xXfkDLSBL2L4EQ
 VU+lkHwFDhx8hjFSeOTps90lTlrUzIaAqYn532VVsU/RMWFzcdUbPJdED7QddUNG
 gGj40sUu5XaMoBKzCRJ6KznYMCK3x15gptz8MAj2hfqcUk+GRLKO9crXj0tU35iP
 sBVMlC66+nVDNQRybqVUMTpizARoFHiRCKSwaFjbsnoe1DkIayn8ghDLhMm9W8Ea
 hgroXlmgafB7Ad/Kt5SSYv0Nw644Zw4bLTrIO1G+OuQf6DRMGt6z5dmmo9arsgjU
 fKNs7Dwb+1d0cpKFNHpnQOc4htO3G1B1stGT6WEJUpd5MXDurw4VoNdaRkOSbi75
 hd+VM+dyJEDHpc/QuRSFBQQqbFLJ4Hfi3z/+oUP8x1FVbDb2u7b+2H7BFgrn08Y+
 EEKRaIQ6PQ==
 =gtEI
 -----END PGP SIGNATURE-----

Merge tag 'block-7.0-20260227' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux

Pull block fixes from Jens Axboe:
 "Two sets of fixes, one for drbd, and one for the zoned loop driver"

* tag 'block-7.0-20260227' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux:
  zloop: check for spurious options passed to remove
  zloop: advertise a volatile write cache
  drbd: fix null-pointer dereference on local read error
  drbd: Replace deprecated strcpy with strscpy
  drbd: fix "LOGIC BUG" in drbd_al_begin_io_nonblock()
This commit is contained in:
Linus Torvalds 2026-02-27 10:42:02 -08:00
commit 78d964c47f
6 changed files with 64 additions and 46 deletions

View file

@ -483,38 +483,20 @@ void drbd_al_begin_io(struct drbd_device *device, struct drbd_interval *i)
int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *i)
{
struct lru_cache *al = device->act_log;
/* for bios crossing activity log extent boundaries,
* we may need to activate two extents in one go */
unsigned first = i->sector >> (AL_EXTENT_SHIFT-9);
unsigned last = i->size == 0 ? first : (i->sector + (i->size >> 9) - 1) >> (AL_EXTENT_SHIFT-9);
unsigned nr_al_extents;
unsigned available_update_slots;
unsigned enr;
D_ASSERT(device, first <= last);
nr_al_extents = 1 + last - first; /* worst case: all touched extends are cold. */
available_update_slots = min(al->nr_elements - al->used,
al->max_pending_changes - al->pending_changes);
/* We want all necessary updates for a given request within the same transaction
* We could first check how many updates are *actually* needed,
* and use that instead of the worst-case nr_al_extents */
if (available_update_slots < nr_al_extents) {
/* Too many activity log extents are currently "hot".
*
* If we have accumulated pending changes already,
* we made progress.
*
* If we cannot get even a single pending change through,
* stop the fast path until we made some progress,
* or requests to "cold" extents could be starved. */
if (!al->pending_changes)
__set_bit(__LC_STARVING, &device->act_log->flags);
return -ENOBUFS;
if (i->partially_in_al_next_enr) {
D_ASSERT(device, first < i->partially_in_al_next_enr);
D_ASSERT(device, last >= i->partially_in_al_next_enr);
first = i->partially_in_al_next_enr;
}
D_ASSERT(device, first <= last);
/* Is resync active in this area? */
for (enr = first; enr <= last; enr++) {
struct lc_element *tmp;
@ -529,14 +511,21 @@ int drbd_al_begin_io_nonblock(struct drbd_device *device, struct drbd_interval *
}
}
/* Checkout the refcounts.
* Given that we checked for available elements and update slots above,
* this has to be successful. */
/* Try to checkout the refcounts. */
for (enr = first; enr <= last; enr++) {
struct lc_element *al_ext;
al_ext = lc_get_cumulative(device->act_log, enr);
if (!al_ext)
drbd_info(device, "LOGIC BUG for enr=%u\n", enr);
if (!al_ext) {
/* Did not work. We may have exhausted the possible
* changes per transaction. Or raced with someone
* "locking" it against changes.
* Remember where to continue from.
*/
if (enr > first)
i->partially_in_al_next_enr = enr;
return -ENOBUFS;
}
}
return 0;
}
@ -556,7 +545,11 @@ void drbd_al_complete_io(struct drbd_device *device, struct drbd_interval *i)
for (enr = first; enr <= last; enr++) {
extent = lc_find(device->act_log, enr);
if (!extent) {
/* Yes, this masks a bug elsewhere. However, during normal
* operation this is harmless, so no need to crash the kernel
* by the BUG_ON(refcount == 0) in lc_put().
*/
if (!extent || extent->refcnt == 0) {
drbd_err(device, "al_complete_io() called on inactive extent %u\n", enr);
continue;
}

View file

@ -8,12 +8,15 @@
struct drbd_interval {
struct rb_node rb;
sector_t sector; /* start sector of the interval */
unsigned int size; /* size in bytes */
sector_t end; /* highest interval end in subtree */
unsigned int size; /* size in bytes */
unsigned int local:1 /* local or remote request? */;
unsigned int waiting:1; /* someone is waiting for completion */
unsigned int completed:1; /* this has been completed already;
* ignore for conflict detection */
/* to resume a partially successful drbd_al_begin_io_nonblock(); */
unsigned int partially_in_al_next_enr;
};
static inline void drbd_clear_interval(struct drbd_interval *i)

View file

@ -32,6 +32,7 @@
#include <linux/memcontrol.h>
#include <linux/mm_inline.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/random.h>
#include <linux/reboot.h>
#include <linux/notifier.h>
@ -732,9 +733,9 @@ int drbd_send_sync_param(struct drbd_peer_device *peer_device)
}
if (apv >= 88)
strcpy(p->verify_alg, nc->verify_alg);
strscpy(p->verify_alg, nc->verify_alg);
if (apv >= 89)
strcpy(p->csums_alg, nc->csums_alg);
strscpy(p->csums_alg, nc->csums_alg);
rcu_read_unlock();
return drbd_send_command(peer_device, sock, cmd, size, NULL, 0);
@ -745,6 +746,7 @@ int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cm
struct drbd_socket *sock;
struct p_protocol *p;
struct net_conf *nc;
size_t integrity_alg_len;
int size, cf;
sock = &connection->data;
@ -762,8 +764,10 @@ int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cm
}
size = sizeof(*p);
if (connection->agreed_pro_version >= 87)
size += strlen(nc->integrity_alg) + 1;
if (connection->agreed_pro_version >= 87) {
integrity_alg_len = strlen(nc->integrity_alg) + 1;
size += integrity_alg_len;
}
p->protocol = cpu_to_be32(nc->wire_protocol);
p->after_sb_0p = cpu_to_be32(nc->after_sb_0p);
@ -778,7 +782,7 @@ int __drbd_send_protocol(struct drbd_connection *connection, enum drbd_packet cm
p->conn_flags = cpu_to_be32(cf);
if (connection->agreed_pro_version >= 87)
strcpy(p->integrity_alg, nc->integrity_alg);
strscpy(p->integrity_alg, nc->integrity_alg, integrity_alg_len);
rcu_read_unlock();
return __conn_send_command(connection, sock, cmd, size, NULL, 0);

View file

@ -3801,14 +3801,14 @@ static int receive_SyncParam(struct drbd_connection *connection, struct packet_i
*new_net_conf = *old_net_conf;
if (verify_tfm) {
strcpy(new_net_conf->verify_alg, p->verify_alg);
strscpy(new_net_conf->verify_alg, p->verify_alg);
new_net_conf->verify_alg_len = strlen(p->verify_alg) + 1;
crypto_free_shash(peer_device->connection->verify_tfm);
peer_device->connection->verify_tfm = verify_tfm;
drbd_info(device, "using verify-alg: \"%s\"\n", p->verify_alg);
}
if (csums_tfm) {
strcpy(new_net_conf->csums_alg, p->csums_alg);
strscpy(new_net_conf->csums_alg, p->csums_alg);
new_net_conf->csums_alg_len = strlen(p->csums_alg) + 1;
crypto_free_shash(peer_device->connection->csums_tfm);
peer_device->connection->csums_tfm = csums_tfm;

View file

@ -621,7 +621,8 @@ int __req_mod(struct drbd_request *req, enum drbd_req_event what,
break;
case READ_COMPLETED_WITH_ERROR:
drbd_set_out_of_sync(peer_device, req->i.sector, req->i.size);
drbd_set_out_of_sync(first_peer_device(device),
req->i.sector, req->i.size);
drbd_report_io_error(device, req);
__drbd_chk_io_error(device, DRBD_READ_ERROR);
fallthrough;

View file

@ -542,6 +542,21 @@ out:
zloop_put_cmd(cmd);
}
/*
* Sync the entire FS containing the zone files instead of walking all files.
*/
static int zloop_flush(struct zloop_device *zlo)
{
struct super_block *sb = file_inode(zlo->data_dir)->i_sb;
int ret;
down_read(&sb->s_umount);
ret = sync_filesystem(sb);
up_read(&sb->s_umount);
return ret;
}
static void zloop_handle_cmd(struct zloop_cmd *cmd)
{
struct request *rq = blk_mq_rq_from_pdu(cmd);
@ -562,11 +577,7 @@ static void zloop_handle_cmd(struct zloop_cmd *cmd)
zloop_rw(cmd);
return;
case REQ_OP_FLUSH:
/*
* Sync the entire FS containing the zone files instead of
* walking all files
*/
cmd->ret = sync_filesystem(file_inode(zlo->data_dir)->i_sb);
cmd->ret = zloop_flush(zlo);
break;
case REQ_OP_ZONE_RESET:
cmd->ret = zloop_reset_zone(zlo, rq_zone_no(rq));
@ -981,7 +992,8 @@ static int zloop_ctl_add(struct zloop_options *opts)
struct queue_limits lim = {
.max_hw_sectors = SZ_1M >> SECTOR_SHIFT,
.chunk_sectors = opts->zone_size,
.features = BLK_FEAT_ZONED,
.features = BLK_FEAT_ZONED | BLK_FEAT_WRITE_CACHE,
};
unsigned int nr_zones, i, j;
struct zloop_device *zlo;
@ -1162,7 +1174,12 @@ static int zloop_ctl_remove(struct zloop_options *opts)
int ret;
if (!(opts->mask & ZLOOP_OPT_ID)) {
pr_err("No ID specified\n");
pr_err("No ID specified for remove\n");
return -EINVAL;
}
if (opts->mask & ~ZLOOP_OPT_ID) {
pr_err("Invalid option specified for remove\n");
return -EINVAL;
}