mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
block-7.2-20260717
-----BEGIN PGP SIGNATURE----- iQJEBAABCAAuFiEEwPw5LcreJtl1+l5K99NY+ylx4KYFAmpbBc8QHGF4Ym9lQGtl cm5lbC5kawAKCRD301j7KXHgpibUD/9SCYq0YZSH4fgwv6PwouAdw2/0TogbCf2E OZ+oq76WYeG8Q95iFXLdjv72EkNi+m1cHesn89lhvZkHWu9TAKAeCoXcnfsLIpmp 60e6Dnz7GCTRsv2L9nBEEmsyQdYGVbbMes8hSpBXbcO1jczbr8x9nzBzkfR4XL3z /Vqy1CK9lA0z1+0sVkUrjKt9li7BGodpUPiNdhMReu8nuwuy1mHJ585+Y6pkwHav 1TmaSiQ+NQxSLmyOwG1rzmzWCDdeszAa56exJ6L/T16RJ6rNTPcz2TCjsBcmuupo UytqdUhKaqxlikfrdus0Cnjsn8ivTiXFfYnvNTAWThRuIq+ePC4nzWzuncJTeVdE MIzfND6sTmfOG6Vchrx0CN92nv5gsOprxbLjbM28VSb5Xpad5PYMMGpdkBranI/9 zUkJi0fiJOp0i/uvpltdPqcgvPKBHBhLyi5GPVb+fjLJW2Gm1s1xcBfpKIj+2+S5 A3F2ac626DhcGrKQcZPl71RwAeEWRzP3Zr93Eg1oEQd9uqRz1jH2K8DCGh0fd9mP FppUw/p4GbBnc8QVraIfAIssg12eFU2ZIHvWuTiB/1UnzMuS3gJ8pwEy0s/9ObUJ +8vCI1fZDmbXN7T31rTl/X4npL0AfXtTbG61KcWqvbAhyVmmKNoNPHFj4SA3G0wF p5Y7qj2Jmg== =qHz/ -----END PGP SIGNATURE----- Merge tag 'block-7.2-20260717' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux Pull block fixes from Jens Axboe: - Fixes for the dio bounce buffer helpers: correct the alignment of bounced dio read bios to avoid a double unpin, handle huge zero folios in bio_free_folios(), and don't warn on the larger-order folio attempts in the greedy allocation path. - Try a slab allocation in bio_alloc_bioset() before falling back to the mempool, restoring the previous behavior for non-sleeping allocations from a cache-enabled bioset. - Serialize elevator changes for the same queue using the writer lock. - Fix a race in blk_time_get_ns() where a task preempted between setting PF_BLOCK_TS and the cached-timestamp reload could return 0. - blk-cgroup fix for leaks and the online flag on a radix_tree_insert() failure in blkg_create(). - Free the copied pages when blk_rq_map_kern() fails after blk_rq_append_bio() rejects the bio. - Remove manually added partitions on loop device detach, fixing dead partition devices left behind and a subsequent LOOP_CONFIGURE -EBUSY - Bound the AIX partition lvd scan to the sector that was actually read. - Show the block operation in error injection rules (Jackie) * tag 'block-7.2-20260717' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: block: fix aligning of bounced dio read bios block: handle huge zero folios in bio_free_folios block: try slab allocation in bio_alloc_bioset() before mempool block: show operation in error injection rules block: serialize elevator changes for the same queue using a writer lock block: free copied pages when blk_rq_map_kern() fails block: do not warn when doing greedy allocation in folio_alloc_greedy() partitions: aix: bound the lvd scan to one sector blk-cgroup: fix leaks and online flag on radix_tree_insert failure loop: remove manually added partitions on detach block: fix race in blk_time_get_ns() returning 0
This commit is contained in:
commit
980ab36ae5
64
block/bio.c
64
block/bio.c
|
|
@ -555,6 +555,14 @@ struct bio *bio_alloc_bioset(struct block_device *bdev, unsigned short nr_vecs,
|
|||
bio = bio_alloc_percpu_cache(bs);
|
||||
} else {
|
||||
opf &= ~REQ_ALLOC_CACHE;
|
||||
}
|
||||
|
||||
/*
|
||||
* For a bioset without a percpu cache, or when the percpu cache was
|
||||
* empty, try a slab allocation with optimistic GFP_ flags before
|
||||
* falling back to the mempool.
|
||||
*/
|
||||
if (!bio) {
|
||||
p = kmem_cache_alloc(bs->bio_slab, gfp);
|
||||
if (p)
|
||||
bio = p + bs->front_pad;
|
||||
|
|
@ -1191,7 +1199,7 @@ void bio_iov_bvec_set(struct bio *bio, const struct iov_iter *iter)
|
|||
* for the next iteration.
|
||||
*/
|
||||
static int bio_iov_iter_align_down(struct bio *bio, struct iov_iter *iter,
|
||||
unsigned len_align_mask)
|
||||
struct bio_vec *bv, unsigned len_align_mask)
|
||||
{
|
||||
size_t nbytes = bio->bi_iter.bi_size & len_align_mask;
|
||||
|
||||
|
|
@ -1200,23 +1208,16 @@ static int bio_iov_iter_align_down(struct bio *bio, struct iov_iter *iter,
|
|||
|
||||
iov_iter_revert(iter, nbytes);
|
||||
bio->bi_iter.bi_size -= nbytes;
|
||||
do {
|
||||
struct bio_vec *bv = &bio->bi_io_vec[bio->bi_vcnt - 1];
|
||||
|
||||
if (nbytes < bv->bv_len) {
|
||||
bv->bv_len -= nbytes;
|
||||
break;
|
||||
}
|
||||
|
||||
while (nbytes >= bv->bv_len) {
|
||||
if (bio_flagged(bio, BIO_PAGE_PINNED))
|
||||
unpin_user_page(bv->bv_page);
|
||||
|
||||
bio->bi_vcnt--;
|
||||
if (!--bio->bi_vcnt)
|
||||
return -EFAULT;
|
||||
nbytes -= bv->bv_len;
|
||||
} while (nbytes);
|
||||
|
||||
if (!bio->bi_vcnt)
|
||||
return -EFAULT;
|
||||
bv--;
|
||||
}
|
||||
bv->bv_len -= nbytes;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1276,7 +1277,8 @@ int bio_iov_iter_get_pages(struct bio *bio, struct iov_iter *iter,
|
|||
|
||||
if (is_pci_p2pdma_page(bio->bi_io_vec->bv_page))
|
||||
bio->bi_opf |= REQ_NOMERGE;
|
||||
return bio_iov_iter_align_down(bio, iter, len_align_mask);
|
||||
return bio_iov_iter_align_down(bio, iter,
|
||||
&bio->bi_io_vec[bio->bi_vcnt - 1], len_align_mask);
|
||||
}
|
||||
|
||||
static struct folio *folio_alloc_greedy(gfp_t gfp, size_t *size,
|
||||
|
|
@ -1285,7 +1287,8 @@ static struct folio *folio_alloc_greedy(gfp_t gfp, size_t *size,
|
|||
struct folio *folio;
|
||||
|
||||
while (*size > minsize) {
|
||||
folio = folio_alloc(gfp | __GFP_NORETRY, get_order(*size));
|
||||
folio = folio_alloc(gfp | __GFP_NORETRY | __GFP_NOWARN,
|
||||
get_order(*size));
|
||||
if (folio)
|
||||
return folio;
|
||||
*size = rounddown_pow_of_two(*size - 1);
|
||||
|
|
@ -1302,7 +1305,7 @@ static void bio_free_folios(struct bio *bio)
|
|||
bio_for_each_bvec_all(bv, bio, i) {
|
||||
struct folio *folio = bvec_folio(bv);
|
||||
|
||||
if (!is_zero_folio(folio))
|
||||
if (!is_zero_folio(folio) && !is_huge_zero_folio(folio))
|
||||
folio_put(folio);
|
||||
}
|
||||
}
|
||||
|
|
@ -1360,7 +1363,8 @@ static int bio_iov_iter_bounce_write(struct bio *bio, struct iov_iter *iter,
|
|||
|
||||
if (!bio->bi_iter.bi_size)
|
||||
return -ENOMEM;
|
||||
return bio_iov_iter_align_down(bio, iter, minsize - 1);
|
||||
return bio_iov_iter_align_down(bio, iter,
|
||||
&bio->bi_io_vec[bio->bi_vcnt - 1], minsize - 1);
|
||||
}
|
||||
|
||||
static int bio_iov_iter_bounce_read(struct bio *bio, struct iov_iter *iter,
|
||||
|
|
@ -1368,21 +1372,18 @@ static int bio_iov_iter_bounce_read(struct bio *bio, struct iov_iter *iter,
|
|||
{
|
||||
size_t len = min3(iov_iter_count(iter), maxlen, SZ_1M);
|
||||
struct folio *folio;
|
||||
ssize_t ret;
|
||||
|
||||
folio = folio_alloc_greedy(GFP_KERNEL, &len, minsize);
|
||||
if (!folio)
|
||||
return -ENOMEM;
|
||||
|
||||
do {
|
||||
ssize_t ret;
|
||||
|
||||
ret = iov_iter_extract_bvecs(iter, bio->bi_io_vec + 1, len,
|
||||
&bio->bi_vcnt, bio->bi_max_vecs - 1, 0);
|
||||
if (ret <= 0) {
|
||||
if (!bio->bi_vcnt) {
|
||||
folio_put(folio);
|
||||
return ret;
|
||||
}
|
||||
if (!bio->bi_vcnt)
|
||||
goto out_folio_put;
|
||||
break;
|
||||
}
|
||||
len -= ret;
|
||||
|
|
@ -1398,7 +1399,20 @@ static int bio_iov_iter_bounce_read(struct bio *bio, struct iov_iter *iter,
|
|||
bvec_set_folio(&bio->bi_io_vec[0], folio, bio->bi_iter.bi_size, 0);
|
||||
if (iov_iter_extract_will_pin(iter))
|
||||
bio_set_flag(bio, BIO_PAGE_PINNED);
|
||||
return bio_iov_iter_align_down(bio, iter, minsize - 1);
|
||||
|
||||
/* The first vec stores the bounce buffer, so do not subtract 1 here. */
|
||||
ret = bio_iov_iter_align_down(bio, iter,
|
||||
&bio->bi_io_vec[bio->bi_vcnt], minsize - 1);
|
||||
if (ret)
|
||||
goto out_folio_put;
|
||||
|
||||
/* Update the bounc buffer bv_len to the aligned down size. */
|
||||
bio->bi_io_vec[0].bv_len = bio->bi_iter.bi_size;
|
||||
return 0;
|
||||
|
||||
out_folio_put:
|
||||
folio_put(folio);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -434,15 +434,15 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, struct gendisk *disk,
|
|||
blkg->pd[i]->online = true;
|
||||
}
|
||||
}
|
||||
blkg->online = true;
|
||||
}
|
||||
blkg->online = true;
|
||||
spin_unlock(&blkcg->lock);
|
||||
|
||||
if (!ret)
|
||||
return blkg;
|
||||
|
||||
/* @blkg failed fully initialized, use the usual release path */
|
||||
blkg_put(blkg);
|
||||
percpu_ref_kill(&blkg->refcnt);
|
||||
return ERR_PTR(ret);
|
||||
|
||||
err_free_blkg:
|
||||
|
|
|
|||
|
|
@ -653,6 +653,7 @@ int blk_rq_map_kern(struct request *rq, void *kbuf, unsigned int len,
|
|||
gfp_t gfp_mask)
|
||||
{
|
||||
unsigned long addr = (unsigned long) kbuf;
|
||||
bool do_copy;
|
||||
struct bio *bio;
|
||||
int ret;
|
||||
|
||||
|
|
@ -661,7 +662,8 @@ int blk_rq_map_kern(struct request *rq, void *kbuf, unsigned int len,
|
|||
if (!len || !kbuf)
|
||||
return -EINVAL;
|
||||
|
||||
if (!blk_rq_aligned(rq->q, addr, len) || object_is_on_stack(kbuf))
|
||||
do_copy = !blk_rq_aligned(rq->q, addr, len) || object_is_on_stack(kbuf);
|
||||
if (do_copy)
|
||||
bio = bio_copy_kern(rq, kbuf, len, gfp_mask);
|
||||
else
|
||||
bio = bio_map_kern(rq, kbuf, len, gfp_mask);
|
||||
|
|
@ -670,8 +672,11 @@ int blk_rq_map_kern(struct request *rq, void *kbuf, unsigned int len,
|
|||
return PTR_ERR(bio);
|
||||
|
||||
ret = blk_rq_append_bio(rq, bio);
|
||||
if (unlikely(ret))
|
||||
if (unlikely(ret)) {
|
||||
if (do_copy)
|
||||
bio_free_pages(bio);
|
||||
blk_mq_map_bio_put(bio);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_rq_map_kern);
|
||||
|
|
|
|||
13
block/blk.h
13
block/blk.h
|
|
@ -717,6 +717,7 @@ static inline int req_ref_read(struct request *req)
|
|||
static inline u64 blk_time_get_ns(void)
|
||||
{
|
||||
struct blk_plug *plug = current->plug;
|
||||
u64 now;
|
||||
|
||||
if (!plug || !in_task())
|
||||
return ktime_get_ns();
|
||||
|
|
@ -725,12 +726,18 @@ static inline u64 blk_time_get_ns(void)
|
|||
* 0 could very well be a valid time, but rather than flag "this is
|
||||
* a valid timestamp" separately, just accept that we'll do an extra
|
||||
* ktime_get_ns() if we just happen to get 0 as the current time.
|
||||
*
|
||||
* cur_ktime can be zeroed by pre-emption the moment PF_BLOCK_TS is set.
|
||||
*/
|
||||
if (!plug->cur_ktime) {
|
||||
plug->cur_ktime = ktime_get_ns();
|
||||
now = READ_ONCE(plug->cur_ktime);
|
||||
if (!now) {
|
||||
now = ktime_get_ns();
|
||||
WRITE_ONCE(plug->cur_ktime, now);
|
||||
/* Ensure PF_BLOCK_TS is set after cur_ktime. */
|
||||
barrier();
|
||||
current->flags |= PF_BLOCK_TS;
|
||||
}
|
||||
return plug->cur_ktime;
|
||||
return now;
|
||||
}
|
||||
|
||||
static inline ktime_t blk_time_get(void)
|
||||
|
|
|
|||
|
|
@ -812,8 +812,13 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
|
|||
* reference during concurrent disk deletion:
|
||||
* update_nr_hwq_lock -> kn->active (via del_gendisk -> kobject_del)
|
||||
* kn->active -> update_nr_hwq_lock (via this sysfs write path)
|
||||
*
|
||||
* Use the writer lock instead of the reader lock of update_nr_hwq_lock
|
||||
* to serialize the two-stage elevator switch steps in
|
||||
* elevator_change(): the core switch step under the elevator lock and
|
||||
* the elevator_change_done() step outside the elevator lock.
|
||||
*/
|
||||
if (!down_read_trylock(&set->update_nr_hwq_lock)) {
|
||||
if (!down_write_trylock(&set->update_nr_hwq_lock)) {
|
||||
ret = -EBUSY;
|
||||
goto out;
|
||||
}
|
||||
|
|
@ -824,7 +829,7 @@ ssize_t elv_iosched_store(struct gendisk *disk, const char *buf,
|
|||
} else {
|
||||
ret = -ENOENT;
|
||||
}
|
||||
up_read(&set->update_nr_hwq_lock);
|
||||
up_write(&set->update_nr_hwq_lock);
|
||||
|
||||
out:
|
||||
if (ctx.type)
|
||||
|
|
|
|||
|
|
@ -276,9 +276,10 @@ static int blk_error_injection_show(struct seq_file *s, void *private)
|
|||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(inj, &disk->error_injection_list, entry) {
|
||||
seq_printf(s, "%llu:%llu status=%s,chance=%u",
|
||||
inj->start, inj->end,
|
||||
blk_status_to_tag(inj->status), inj->chance);
|
||||
seq_printf(s, "%llu:%llu op=%s,status=%s,chance=%u",
|
||||
inj->start, inj->end,
|
||||
blk_op_str(inj->op),
|
||||
blk_status_to_tag(inj->status), inj->chance);
|
||||
seq_putc(s, '\n');
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
|
|
|||
|
|
@ -208,7 +208,14 @@ int aix_partition(struct parsed_partitions *state)
|
|||
if (n) {
|
||||
int foundlvs = 0;
|
||||
|
||||
for (i = 0; foundlvs < numlvs && i < state->limit; i += 1) {
|
||||
/*
|
||||
* The lvd array was read as a single sector; only the
|
||||
* struct lvd entries that fit in it are valid. Bound the
|
||||
* scan so an on-disk numlvs larger than that cannot walk
|
||||
* the read buffer out of bounds.
|
||||
*/
|
||||
for (i = 0; foundlvs < numlvs && i < state->limit &&
|
||||
i < SECTOR_SIZE / (int)sizeof(struct lvd); i++) {
|
||||
lvip[i].pps_per_lv = be16_to_cpu(p[i].num_lps);
|
||||
if (lvip[i].pps_per_lv)
|
||||
foundlvs += 1;
|
||||
|
|
|
|||
|
|
@ -1113,6 +1113,7 @@ static void __loop_clr_fd(struct loop_device *lo)
|
|||
struct queue_limits lim;
|
||||
struct file *filp;
|
||||
gfp_t gfp = lo->old_gfp_mask;
|
||||
int err;
|
||||
|
||||
spin_lock_irq(&lo->lo_lock);
|
||||
filp = lo->lo_backing_file;
|
||||
|
|
@ -1146,26 +1147,21 @@ static void __loop_clr_fd(struct loop_device *lo)
|
|||
|
||||
disk_force_media_change(lo->lo_disk);
|
||||
|
||||
if (lo->lo_flags & LO_FLAGS_PARTSCAN) {
|
||||
int err;
|
||||
|
||||
/*
|
||||
* open_mutex has been held already in release path, so don't
|
||||
* acquire it if this function is called in such case.
|
||||
*
|
||||
* If the reread partition isn't from release path, lo_refcnt
|
||||
* must be at least one and it can only become zero when the
|
||||
* current holder is released.
|
||||
*/
|
||||
err = bdev_disk_changed(lo->lo_disk, false);
|
||||
if (err)
|
||||
pr_warn("%s: partition scan of loop%d failed (rc=%d)\n",
|
||||
__func__, lo->lo_number, err);
|
||||
/* Device is gone, no point in returning error */
|
||||
}
|
||||
/*
|
||||
* Remove all partitions, including partitions added manually with
|
||||
* BLKPG, which may exist even if LO_FLAGS_PARTSCAN is not set.
|
||||
*
|
||||
* open_mutex has been held already in release path, so don't acquire
|
||||
* it here.
|
||||
*/
|
||||
err = bdev_disk_changed(lo->lo_disk, false);
|
||||
if (err)
|
||||
pr_warn("%s: partition scan of loop%d failed (rc=%d)\n",
|
||||
__func__, lo->lo_number, err);
|
||||
/* Device is gone, no point in returning error */
|
||||
|
||||
/*
|
||||
* lo->lo_state is set to Lo_unbound here after above partscan has
|
||||
* lo->lo_state is set to Lo_unbound here after removing partitions has
|
||||
* finished. There cannot be anybody else entering __loop_clr_fd() as
|
||||
* Lo_rundown state protects us from all the other places trying to
|
||||
* change the 'lo' device.
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user