mirror of https://github.com/torvalds/linux.git
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:
commit
78d964c47f
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -542,6 +542,21 @@ static void zloop_rw(struct zloop_cmd *cmd)
|
|||
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;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue