mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
Merge tag 'block-7.2-20260625' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux
Pull block fixes from Jens Axboe:
- blk-cgroup locking rework and fixes:
- fix a use-after-free in __blkcg_rstat_flush()
- defer freeing policy data until after an RCU grace period
- defer the blkcg css_put until the blkg is unlinked from
the queue
- unwind the queue_lock nesting under RCU / blkcg->lock
across the lookup, create, associate and destroy paths
- NVMe fixes via Keith:
- Fix a crash and memory leak during invalid cdev teardown,
and related cdev cleanups (Maurizio, John)
- nvmet fixes: handle TCP_CLOSING in the tcp state_change
handler, reject short AUTH_RECEIVE buffers, handle inline
data with a nonzero offset in rdma, fix an sq refcount leak,
and allocate ana_state with the port (Maurizio, Michael,
Bryam, Wentao, Rosen)
- nvme-fc fix to not cancel requests on an IO target before it
is initialized (Mohamed)
- nvme-apple fix to prevent shared tags across queues on Apple
A11 (Nick)
- Various smaller fixes and cleanups (John)
- MD fixes via Yu Kuai:
- raid1/raid10 fixes for writes_pending and barrier reference
leaks on write and discard failures, plus REQ_NOWAIT handling
fixes (Abd-Alrhman)
- raid5 discard accounting and validation, and a batch of fixes
for stripe batch races (Yu Kuai, Chen)
- Protect raid1 head_position during read balancing (Chen)
- block bio-integrity fixes: correct an error injection static key
decrement, fix GFP flag confusion in bio_integrity_alloc_buf(), and
handle REQ_OP_ZONE_APPEND in __bio_integrity_action() (Christoph)
- Fixes for bio_iov_iter_bounce_write(): revert the iov_iter after a
short copy, and respect the iov_iter nofault flag (Qu)
- Invalidate the cached plug timestamp after a task switch, and clear
PF_BLOCK_TS in copy_process() (Usama)
- Fix the IORING_URING_CMD_REISSUE flags check in blkdev_uring_cmd()
(Yitang)
- Remove a redundant plug in __submit_bio() (Wen)
- Don't warn when reclassifying a busy socket lock in nbd (Deepanshu)
* tag 'block-7.2-20260625' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: (45 commits)
block: handle REQ_OP_ZONE_APPEND in __bio_integrity_action
block: fix GFP_ flags confusion in bio_integrity_alloc_buf
block, bfq: don't grab queue_lock to initialize bfq
mm/page_io: don't nest queue_lock under rcu in bio_associate_blkg_from_page()
blk-cgroup: don't nest queue_lock under blkcg->lock in blkcg_destroy_blkgs()
blk-cgroup: don't nest queue_lock under rcu in bio_associate_blkg()
blk-cgroup: don't nest queue_lock under rcu in blkg_lookup_create()
blk-cgroup: don't nest queue_lock under rcu in blkcg_print_blkgs()
blk-cgroup: delay freeing policy data after rcu grace period
blk-cgroup: protect iterating blkgs with blkcg->lock in blkcg_print_stat()
md/raid5: avoid R5_Overlap races while breaking stripe batches
md/raid5: use stripe state snapshot in break_stripe_batch_list()
blk-cgroup: defer blkcg css_put until blkg is unlinked from queue
blk-cgroup: fix UAF in __blkcg_rstat_flush()
block, bfq: protect async queue reset with blkcg locks
nbd: don't warn when reclassifying a busy socket lock
block: fix incorrect error injection static key decrement
md/raid5: let stripe batch bm_seq comparison wrap-safe
md/raid1: protect head_position for read balance
md/raid1: free r1_bio when REQ_NOWAIT is set and read would block on retry
...
This commit is contained in:
@@ -550,13 +550,20 @@ static void bfq_pd_init(struct blkg_policy_data *pd)
|
||||
bfqg->rq_pos_tree = RB_ROOT;
|
||||
}
|
||||
|
||||
static void bfq_pd_free(struct blkg_policy_data *pd)
|
||||
static void bfqg_release(struct rcu_head *rcu)
|
||||
{
|
||||
struct blkg_policy_data *pd =
|
||||
container_of(rcu, struct blkg_policy_data, rcu_head);
|
||||
struct bfq_group *bfqg = pd_to_bfqg(pd);
|
||||
|
||||
bfqg_put(bfqg);
|
||||
}
|
||||
|
||||
static void bfq_pd_free(struct blkg_policy_data *pd)
|
||||
{
|
||||
call_rcu(&pd->rcu_head, bfqg_release);
|
||||
}
|
||||
|
||||
static void bfq_pd_reset_stats(struct blkg_policy_data *pd)
|
||||
{
|
||||
struct bfq_group *bfqg = pd_to_bfqg(pd);
|
||||
@@ -936,14 +943,23 @@ static void bfq_pd_offline(struct blkg_policy_data *pd)
|
||||
|
||||
void bfq_end_wr_async(struct bfq_data *bfqd)
|
||||
{
|
||||
struct request_queue *q = bfqd->queue;
|
||||
struct blkcg_gq *blkg;
|
||||
|
||||
list_for_each_entry(blkg, &bfqd->queue->blkg_list, q_node) {
|
||||
mutex_lock(&q->blkcg_mutex);
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
spin_lock(&bfqd->lock);
|
||||
|
||||
list_for_each_entry(blkg, &q->blkg_list, q_node) {
|
||||
struct bfq_group *bfqg = blkg_to_bfqg(blkg);
|
||||
|
||||
bfq_end_wr_async_queues(bfqd, bfqg);
|
||||
}
|
||||
bfq_end_wr_async_queues(bfqd, bfqd->root_group);
|
||||
|
||||
spin_unlock(&bfqd->lock);
|
||||
spin_unlock_irq(&q->queue_lock);
|
||||
mutex_unlock(&q->blkcg_mutex);
|
||||
}
|
||||
|
||||
static int bfq_io_show_weight_legacy(struct seq_file *sf, void *v)
|
||||
@@ -1147,16 +1163,18 @@ static u64 bfqg_prfill_stat_recursive(struct seq_file *sf,
|
||||
struct cgroup_subsys_state *pos_css;
|
||||
u64 sum = 0;
|
||||
|
||||
lockdep_assert_held(&blkg->q->queue_lock);
|
||||
|
||||
rcu_read_lock();
|
||||
blkg_for_each_descendant_pre(pos_blkg, pos_css, blkg) {
|
||||
struct blkg_policy_data *pd;
|
||||
struct bfq_stat *stat;
|
||||
|
||||
if (!pos_blkg->online)
|
||||
continue;
|
||||
|
||||
stat = (void *)blkg_to_pd(pos_blkg, &blkcg_policy_bfq) + off;
|
||||
pd = blkg_to_pd(pos_blkg, &blkcg_policy_bfq);
|
||||
if (!pd)
|
||||
continue;
|
||||
stat = (void *)pd + off;
|
||||
sum += bfq_stat_read(stat) + atomic64_read(&stat->aux_cnt);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
@@ -1416,7 +1434,9 @@ void bfq_bic_update_cgroup(struct bfq_io_cq *bic, struct bio *bio) {}
|
||||
|
||||
void bfq_end_wr_async(struct bfq_data *bfqd)
|
||||
{
|
||||
spin_lock_irq(&bfqd->lock);
|
||||
bfq_end_wr_async_queues(bfqd, bfqd->root_group);
|
||||
spin_unlock_irq(&bfqd->lock);
|
||||
}
|
||||
|
||||
struct bfq_group *bfq_bio_bfqg(struct bfq_data *bfqd, struct bio *bio)
|
||||
|
||||
@@ -2653,9 +2653,10 @@ static void bfq_end_wr(struct bfq_data *bfqd)
|
||||
}
|
||||
list_for_each_entry(bfqq, &bfqd->idle_list, bfqq_list)
|
||||
bfq_bfqq_end_wr(bfqq);
|
||||
bfq_end_wr_async(bfqd);
|
||||
|
||||
spin_unlock_irq(&bfqd->lock);
|
||||
|
||||
bfq_end_wr_async(bfqd);
|
||||
}
|
||||
|
||||
static sector_t bfq_io_struct_pos(void *io_struct, bool request)
|
||||
@@ -7203,10 +7204,7 @@ static int bfq_init_queue(struct request_queue *q, struct elevator_queue *eq)
|
||||
return -ENOMEM;
|
||||
|
||||
eq->elevator_data = bfqd;
|
||||
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
q->elevator = eq;
|
||||
spin_unlock_irq(&q->queue_lock);
|
||||
|
||||
/*
|
||||
* Our fallback bfqq if bfq_find_alloc_queue() runs into OOM issues.
|
||||
@@ -7239,7 +7237,6 @@ static int bfq_init_queue(struct request_queue *q, struct elevator_queue *eq)
|
||||
* If the disk supports multiple actuators, copy independent
|
||||
* access ranges from the request queue structure.
|
||||
*/
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
if (ia_ranges) {
|
||||
/*
|
||||
* Check if the disk ia_ranges size exceeds the current bfq
|
||||
@@ -7265,7 +7262,6 @@ static int bfq_init_queue(struct request_queue *q, struct elevator_queue *eq)
|
||||
bfqd->sector[0] = 0;
|
||||
bfqd->nr_sectors[0] = get_capacity(q->disk);
|
||||
}
|
||||
spin_unlock_irq(&q->queue_lock);
|
||||
|
||||
INIT_LIST_HEAD(&bfqd->dispatch);
|
||||
|
||||
|
||||
@@ -94,7 +94,7 @@ void bio_integrity_prep(struct bio *bio, unsigned int action)
|
||||
bio_integrity_init(bio, &bid->bip, &bid->bvec, 1);
|
||||
bid->bio = bio;
|
||||
bid->bip.bip_flags |= BIP_BLOCK_INTEGRITY;
|
||||
bio_integrity_alloc_buf(bio, action & BI_ACT_ZERO);
|
||||
bio_integrity_alloc_buf(bio, GFP_NOIO, action & BI_ACT_ZERO);
|
||||
if (action & BI_ACT_CHECK)
|
||||
bio_integrity_setup_default(bio);
|
||||
|
||||
|
||||
@@ -23,10 +23,10 @@ unsigned int fs_bio_integrity_alloc(struct bio *bio)
|
||||
if (!action)
|
||||
return 0;
|
||||
|
||||
iib = mempool_alloc(&fs_bio_integrity_pool, GFP_NOIO);
|
||||
iib = mempool_alloc(&fs_bio_integrity_pool, GFP_NOFS);
|
||||
bio_integrity_init(bio, &iib->bip, &iib->bvec, 1);
|
||||
|
||||
bio_integrity_alloc_buf(bio, action & BI_ACT_ZERO);
|
||||
bio_integrity_alloc_buf(bio, GFP_NOFS, action & BI_ACT_ZERO);
|
||||
if (action & BI_ACT_CHECK)
|
||||
bio_integrity_setup_default(bio);
|
||||
return action;
|
||||
|
||||
@@ -38,6 +38,7 @@ unsigned int __bio_integrity_action(struct bio *bio)
|
||||
}
|
||||
return BI_ACT_BUFFER | BI_ACT_CHECK;
|
||||
case REQ_OP_WRITE:
|
||||
case REQ_OP_ZONE_APPEND:
|
||||
/*
|
||||
* Flush masquerading as write?
|
||||
*/
|
||||
@@ -64,20 +65,18 @@ unsigned int __bio_integrity_action(struct bio *bio)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__bio_integrity_action);
|
||||
|
||||
void bio_integrity_alloc_buf(struct bio *bio, bool zero_buffer)
|
||||
void bio_integrity_alloc_buf(struct bio *bio, gfp_t gfp, bool zero_buffer)
|
||||
{
|
||||
struct blk_integrity *bi = blk_get_integrity(bio->bi_bdev->bd_disk);
|
||||
struct bio_integrity_payload *bip = bio_integrity(bio);
|
||||
unsigned int len = bio_integrity_bytes(bi, bio_sectors(bio));
|
||||
gfp_t gfp = GFP_NOIO | (zero_buffer ? __GFP_ZERO : 0);
|
||||
void *buf;
|
||||
|
||||
buf = kmalloc(len, (gfp & ~__GFP_DIRECT_RECLAIM) |
|
||||
__GFP_NOMEMALLOC | __GFP_NORETRY | __GFP_NOWARN);
|
||||
buf = kmalloc(len, gfp | __GFP_NOWARN | (zero_buffer ? __GFP_ZERO : 0));
|
||||
if (unlikely(!buf)) {
|
||||
struct page *page;
|
||||
|
||||
page = mempool_alloc(&integrity_buf_pool, GFP_NOFS);
|
||||
page = mempool_alloc(&integrity_buf_pool, gfp);
|
||||
if (zero_buffer)
|
||||
memset(page_address(page), 0, len);
|
||||
bvec_set_page(&bip->bip_vec[0], page, len, 0);
|
||||
|
||||
21
block/bio.c
21
block/bio.c
@@ -1321,6 +1321,7 @@ static int bio_iov_iter_bounce_write(struct bio *bio, struct iov_iter *iter,
|
||||
|
||||
do {
|
||||
size_t this_len = min(total_len, SZ_1M);
|
||||
size_t copied;
|
||||
struct folio *folio;
|
||||
|
||||
if (this_len > minsize * 2)
|
||||
@@ -1334,12 +1335,26 @@ static int bio_iov_iter_bounce_write(struct bio *bio, struct iov_iter *iter,
|
||||
break;
|
||||
bio_add_folio_nofail(bio, folio, this_len, 0);
|
||||
|
||||
if (copy_from_iter(folio_address(folio), this_len, iter) !=
|
||||
this_len) {
|
||||
if (iter->nofault)
|
||||
copied = copy_folio_from_iter_atomic(folio, 0, this_len,
|
||||
iter);
|
||||
else
|
||||
copied = copy_folio_from_iter(folio, 0, this_len, iter);
|
||||
if (copied < this_len) {
|
||||
/*
|
||||
* Need to revert the iov iter for all bytes we have
|
||||
* copied.
|
||||
*
|
||||
* However the bio size differs from the real copied
|
||||
* bytes as @this_len is queued but only advanced
|
||||
* less than that.
|
||||
* Need to compensate that for the revert.
|
||||
*/
|
||||
iov_iter_revert(iter, bio->bi_iter.bi_size - this_len +
|
||||
copied);
|
||||
bio_free_folios(bio);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
total_len -= this_len;
|
||||
} while (total_len && bio->bi_vcnt < bio->bi_max_vecs);
|
||||
|
||||
|
||||
@@ -101,24 +101,27 @@ void blkg_rwstat_recursive_sum(struct blkcg_gq *blkg, struct blkcg_policy *pol,
|
||||
struct cgroup_subsys_state *pos_css;
|
||||
unsigned int i;
|
||||
|
||||
lockdep_assert_held(&blkg->q->queue_lock);
|
||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||
|
||||
memset(sum, 0, sizeof(*sum));
|
||||
rcu_read_lock();
|
||||
blkg_for_each_descendant_pre(pos_blkg, pos_css, blkg) {
|
||||
struct blkg_rwstat *rwstat;
|
||||
|
||||
if (!pos_blkg->online)
|
||||
continue;
|
||||
|
||||
if (pol)
|
||||
rwstat = (void *)blkg_to_pd(pos_blkg, pol) + off;
|
||||
else
|
||||
if (pol) {
|
||||
struct blkg_policy_data *pd = blkg_to_pd(pos_blkg, pol);
|
||||
|
||||
if (!pd)
|
||||
continue;
|
||||
rwstat = (void *)pd + off;
|
||||
} else {
|
||||
rwstat = (void *)pos_blkg + off;
|
||||
}
|
||||
|
||||
for (i = 0; i < BLKG_RWSTAT_NR; i++)
|
||||
sum->cnt[i] += blkg_rwstat_read_counter(rwstat, i);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(blkg_rwstat_recursive_sum);
|
||||
|
||||
@@ -136,6 +136,11 @@ static void blkg_free_workfn(struct work_struct *work)
|
||||
spin_unlock_irq(&q->queue_lock);
|
||||
mutex_unlock(&q->blkcg_mutex);
|
||||
|
||||
/*
|
||||
* Release blkcg css ref only after blkg is removed from q->blkg_list,
|
||||
* so concurrent iterators won't see a blkg with a freed blkcg.
|
||||
*/
|
||||
css_put(&blkg->blkcg->css);
|
||||
blk_put_queue(q);
|
||||
free_percpu(blkg->iostat_cpu);
|
||||
percpu_ref_exit(&blkg->refcnt);
|
||||
@@ -164,23 +169,11 @@ static void blkg_free(struct blkcg_gq *blkg)
|
||||
static void __blkg_release(struct rcu_head *rcu)
|
||||
{
|
||||
struct blkcg_gq *blkg = container_of(rcu, struct blkcg_gq, rcu_head);
|
||||
struct blkcg *blkcg = blkg->blkcg;
|
||||
int cpu;
|
||||
|
||||
#ifdef CONFIG_BLK_CGROUP_PUNT_BIO
|
||||
WARN_ON(!bio_list_empty(&blkg->async_bios));
|
||||
#endif
|
||||
/*
|
||||
* Flush all the non-empty percpu lockless lists before releasing
|
||||
* us, given these stat belongs to us.
|
||||
*
|
||||
* blkg_stat_lock is for serializing blkg stat update
|
||||
*/
|
||||
for_each_possible_cpu(cpu)
|
||||
__blkcg_rstat_flush(blkcg, cpu);
|
||||
|
||||
/* release the blkcg and parent blkg refs this blkg has been holding */
|
||||
css_put(&blkg->blkcg->css);
|
||||
blkg_free(blkg);
|
||||
}
|
||||
|
||||
@@ -195,6 +188,17 @@ static void __blkg_release(struct rcu_head *rcu)
|
||||
static void blkg_release(struct percpu_ref *ref)
|
||||
{
|
||||
struct blkcg_gq *blkg = container_of(ref, struct blkcg_gq, refcnt);
|
||||
struct blkcg *blkcg = blkg->blkcg;
|
||||
int cpu;
|
||||
|
||||
/*
|
||||
* Flush all the non-empty percpu lockless lists before releasing
|
||||
* us, given these stat belongs to us.
|
||||
*
|
||||
* blkg_stat_lock is for serializing blkg stat update
|
||||
*/
|
||||
for_each_possible_cpu(cpu)
|
||||
__blkcg_rstat_flush(blkcg, cpu);
|
||||
|
||||
call_rcu(&blkg->rcu_head, __blkg_release);
|
||||
}
|
||||
@@ -313,6 +317,9 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct gendisk *disk,
|
||||
goto out_exit_refcnt;
|
||||
if (!blk_get_queue(disk->queue))
|
||||
goto out_free_iostat;
|
||||
/* blkg holds a reference to blkcg */
|
||||
if (!css_tryget_online(&blkcg->css))
|
||||
goto out_put_queue;
|
||||
|
||||
blkg->q = disk->queue;
|
||||
INIT_LIST_HEAD(&blkg->q_node);
|
||||
@@ -353,6 +360,8 @@ static struct blkcg_gq *blkg_alloc(struct blkcg *blkcg, struct gendisk *disk,
|
||||
while (--i >= 0)
|
||||
if (blkg->pd[i])
|
||||
blkcg_policy[i]->pd_free_fn(blkg->pd[i]);
|
||||
css_put(&blkcg->css);
|
||||
out_put_queue:
|
||||
blk_put_queue(disk->queue);
|
||||
out_free_iostat:
|
||||
free_percpu(blkg->iostat_cpu);
|
||||
@@ -381,18 +390,12 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, struct gendisk *disk,
|
||||
goto err_free_blkg;
|
||||
}
|
||||
|
||||
/* blkg holds a reference to blkcg */
|
||||
if (!css_tryget_online(&blkcg->css)) {
|
||||
ret = -ENODEV;
|
||||
goto err_free_blkg;
|
||||
}
|
||||
|
||||
/* allocate */
|
||||
if (!new_blkg) {
|
||||
new_blkg = blkg_alloc(blkcg, disk, GFP_NOWAIT);
|
||||
if (unlikely(!new_blkg)) {
|
||||
ret = -ENOMEM;
|
||||
goto err_put_css;
|
||||
goto err_free_blkg;
|
||||
}
|
||||
}
|
||||
blkg = new_blkg;
|
||||
@@ -402,7 +405,7 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, struct gendisk *disk,
|
||||
blkg->parent = blkg_lookup(blkcg_parent(blkcg), disk->queue);
|
||||
if (WARN_ON_ONCE(!blkg->parent)) {
|
||||
ret = -ENODEV;
|
||||
goto err_put_css;
|
||||
goto err_free_blkg;
|
||||
}
|
||||
blkg_get(blkg->parent);
|
||||
}
|
||||
@@ -442,8 +445,6 @@ static struct blkcg_gq *blkg_create(struct blkcg *blkcg, struct gendisk *disk,
|
||||
blkg_put(blkg);
|
||||
return ERR_PTR(ret);
|
||||
|
||||
err_put_css:
|
||||
css_put(&blkcg->css);
|
||||
err_free_blkg:
|
||||
if (new_blkg)
|
||||
blkg_free(new_blkg);
|
||||
@@ -468,22 +469,17 @@ static struct blkcg_gq *blkg_lookup_create(struct blkcg *blkcg,
|
||||
{
|
||||
struct request_queue *q = disk->queue;
|
||||
struct blkcg_gq *blkg;
|
||||
unsigned long flags;
|
||||
|
||||
WARN_ON_ONCE(!rcu_read_lock_held());
|
||||
|
||||
blkg = blkg_lookup(blkcg, q);
|
||||
if (blkg)
|
||||
return blkg;
|
||||
|
||||
spin_lock_irqsave(&q->queue_lock, flags);
|
||||
rcu_read_lock();
|
||||
blkg = blkg_lookup(blkcg, q);
|
||||
if (blkg) {
|
||||
if (blkcg != &blkcg_root &&
|
||||
blkg != rcu_dereference(blkcg->blkg_hint))
|
||||
rcu_assign_pointer(blkcg->blkg_hint, blkg);
|
||||
goto found;
|
||||
rcu_read_unlock();
|
||||
return blkg;
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
/*
|
||||
* Create blkgs walking down from blkcg_root to @blkcg, so that all
|
||||
@@ -515,8 +511,6 @@ static struct blkcg_gq *blkg_lookup_create(struct blkcg *blkcg,
|
||||
break;
|
||||
}
|
||||
|
||||
found:
|
||||
spin_unlock_irqrestore(&q->queue_lock, flags);
|
||||
return blkg;
|
||||
}
|
||||
|
||||
@@ -698,9 +692,9 @@ const char *blkg_dev_name(struct blkcg_gq *blkg)
|
||||
*
|
||||
* This function invokes @prfill on each blkg of @blkcg if pd for the
|
||||
* policy specified by @pol exists. @prfill is invoked with @sf, the
|
||||
* policy data and @data and the matching queue lock held. If @show_total
|
||||
* is %true, the sum of the return values from @prfill is printed with
|
||||
* "Total" label at the end.
|
||||
* policy data and @data under RCU read lock. If @show_total is %true, the
|
||||
* sum of the return values from @prfill is printed with "Total" label at the
|
||||
* end.
|
||||
*
|
||||
* This is to be used to construct print functions for
|
||||
* cftype->read_seq_string method.
|
||||
@@ -716,10 +710,14 @@ void blkcg_print_blkgs(struct seq_file *sf, struct blkcg *blkcg,
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(blkg, &blkcg->blkg_list, blkcg_node) {
|
||||
spin_lock_irq(&blkg->q->queue_lock);
|
||||
if (blkcg_policy_enabled(blkg->q, pol))
|
||||
total += prfill(sf, blkg->pd[pol->plid], data);
|
||||
spin_unlock_irq(&blkg->q->queue_lock);
|
||||
struct blkg_policy_data *pd;
|
||||
|
||||
if (!blkcg_policy_enabled(blkg->q, pol))
|
||||
continue;
|
||||
|
||||
pd = blkg_to_pd(blkg, pol);
|
||||
if (pd)
|
||||
total += prfill(sf, pd, data);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
@@ -1190,13 +1188,10 @@ static int blkcg_print_stat(struct seq_file *sf, void *v)
|
||||
else
|
||||
css_rstat_flush(&blkcg->css);
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(blkg, &blkcg->blkg_list, blkcg_node) {
|
||||
spin_lock_irq(&blkg->q->queue_lock);
|
||||
guard(spinlock_irq)(&blkcg->lock);
|
||||
hlist_for_each_entry(blkg, &blkcg->blkg_list, blkcg_node)
|
||||
blkcg_print_one_stat(blkg, sf);
|
||||
spin_unlock_irq(&blkg->q->queue_lock);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1244,6 +1239,21 @@ struct list_head *blkcg_get_cgwb_list(struct cgroup_subsys_state *css)
|
||||
* This finally frees the blkcg.
|
||||
*/
|
||||
|
||||
static struct blkcg_gq *blkcg_get_first_blkg(struct blkcg *blkcg)
|
||||
{
|
||||
struct blkcg_gq *blkg = NULL;
|
||||
|
||||
spin_lock_irq(&blkcg->lock);
|
||||
if (!hlist_empty(&blkcg->blkg_list)) {
|
||||
blkg = hlist_entry(blkcg->blkg_list.first, struct blkcg_gq,
|
||||
blkcg_node);
|
||||
blkg_get(blkg);
|
||||
}
|
||||
spin_unlock_irq(&blkcg->lock);
|
||||
|
||||
return blkg;
|
||||
}
|
||||
|
||||
/**
|
||||
* blkcg_destroy_blkgs - responsible for shooting down blkgs
|
||||
* @blkcg: blkcg of interest
|
||||
@@ -1257,32 +1267,24 @@ struct list_head *blkcg_get_cgwb_list(struct cgroup_subsys_state *css)
|
||||
*/
|
||||
static void blkcg_destroy_blkgs(struct blkcg *blkcg)
|
||||
{
|
||||
struct blkcg_gq *blkg;
|
||||
|
||||
might_sleep();
|
||||
|
||||
spin_lock_irq(&blkcg->lock);
|
||||
|
||||
while (!hlist_empty(&blkcg->blkg_list)) {
|
||||
struct blkcg_gq *blkg = hlist_entry(blkcg->blkg_list.first,
|
||||
struct blkcg_gq, blkcg_node);
|
||||
while ((blkg = blkcg_get_first_blkg(blkcg))) {
|
||||
struct request_queue *q = blkg->q;
|
||||
|
||||
if (need_resched() || !spin_trylock(&q->queue_lock)) {
|
||||
/*
|
||||
* Given that the system can accumulate a huge number
|
||||
* of blkgs in pathological cases, check to see if we
|
||||
* need to rescheduling to avoid softlockup.
|
||||
*/
|
||||
spin_unlock_irq(&blkcg->lock);
|
||||
cond_resched();
|
||||
spin_lock_irq(&blkcg->lock);
|
||||
continue;
|
||||
}
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
spin_lock(&blkcg->lock);
|
||||
|
||||
blkg_destroy(blkg);
|
||||
spin_unlock(&q->queue_lock);
|
||||
}
|
||||
|
||||
spin_unlock_irq(&blkcg->lock);
|
||||
spin_unlock(&blkcg->lock);
|
||||
spin_unlock_irq(&q->queue_lock);
|
||||
|
||||
blkg_put(blkg);
|
||||
cond_resched();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1606,7 +1608,7 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
|
||||
|
||||
pd->blkg = blkg;
|
||||
pd->plid = pol->plid;
|
||||
blkg->pd[pol->plid] = pd;
|
||||
WRITE_ONCE(blkg->pd[pol->plid], pd);
|
||||
|
||||
if (pol->pd_init_fn)
|
||||
pol->pd_init_fn(pd);
|
||||
@@ -1645,7 +1647,7 @@ int blkcg_activate_policy(struct gendisk *disk, const struct blkcg_policy *pol)
|
||||
pol->pd_offline_fn(pd);
|
||||
pd->online = false;
|
||||
pol->pd_free_fn(pd);
|
||||
blkg->pd[pol->plid] = NULL;
|
||||
WRITE_ONCE(blkg->pd[pol->plid], NULL);
|
||||
}
|
||||
spin_unlock(&blkcg->lock);
|
||||
}
|
||||
@@ -2044,6 +2046,18 @@ void blkcg_add_delay(struct blkcg_gq *blkg, u64 now, u64 delta)
|
||||
atomic64_add(delta, &blkg->delay_nsec);
|
||||
}
|
||||
|
||||
static inline struct blkcg_gq *blkg_lookup_tryget(struct blkcg_gq *blkg)
|
||||
{
|
||||
retry:
|
||||
if (blkg_tryget(blkg))
|
||||
return blkg;
|
||||
|
||||
blkg = blkg->parent;
|
||||
if (blkg)
|
||||
goto retry;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
/**
|
||||
* blkg_tryget_closest - try and get a blkg ref on the closet blkg
|
||||
* @bio: target bio
|
||||
@@ -2056,20 +2070,30 @@ void blkcg_add_delay(struct blkcg_gq *blkg, u64 now, u64 delta)
|
||||
static inline struct blkcg_gq *blkg_tryget_closest(struct bio *bio,
|
||||
struct cgroup_subsys_state *css)
|
||||
{
|
||||
struct blkcg_gq *blkg, *ret_blkg = NULL;
|
||||
struct request_queue *q = bio->bi_bdev->bd_queue;
|
||||
struct blkcg *blkcg = css_to_blkcg(css);
|
||||
struct blkcg_gq *blkg;
|
||||
|
||||
rcu_read_lock();
|
||||
blkg = blkg_lookup_create(css_to_blkcg(css), bio->bi_bdev->bd_disk);
|
||||
while (blkg) {
|
||||
if (blkg_tryget(blkg)) {
|
||||
ret_blkg = blkg;
|
||||
break;
|
||||
}
|
||||
blkg = blkg->parent;
|
||||
}
|
||||
blkg = blkg_lookup(blkcg, q);
|
||||
if (likely(blkg))
|
||||
blkg = blkg_lookup_tryget(blkg);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret_blkg;
|
||||
if (blkg)
|
||||
return blkg;
|
||||
|
||||
/*
|
||||
* Fast path failed, we're probably issuing IO in this cgroup the first
|
||||
* time, hold lock to create new blkg.
|
||||
*/
|
||||
spin_lock_irq(&q->queue_lock);
|
||||
blkg = blkg_lookup_create(blkcg, bio->bi_bdev->bd_disk);
|
||||
if (blkg)
|
||||
blkg = blkg_lookup_tryget(blkg);
|
||||
spin_unlock_irq(&q->queue_lock);
|
||||
|
||||
return blkg;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2117,16 +2141,20 @@ void bio_associate_blkg(struct bio *bio)
|
||||
if (blk_op_is_passthrough(bio->bi_opf))
|
||||
return;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
if (bio->bi_blkg)
|
||||
if (bio->bi_blkg) {
|
||||
css = bio_blkcg_css(bio);
|
||||
else
|
||||
bio_associate_blkg_from_css(bio, css);
|
||||
} else {
|
||||
rcu_read_lock();
|
||||
css = blkcg_css();
|
||||
if (!css_tryget_online(css))
|
||||
css = NULL;
|
||||
rcu_read_unlock();
|
||||
|
||||
bio_associate_blkg_from_css(bio, css);
|
||||
|
||||
rcu_read_unlock();
|
||||
bio_associate_blkg_from_css(bio, css);
|
||||
if (css)
|
||||
css_put(css);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(bio_associate_blkg);
|
||||
|
||||
|
||||
@@ -140,6 +140,8 @@ struct blkg_policy_data {
|
||||
struct blkcg_gq *blkg;
|
||||
int plid;
|
||||
bool online;
|
||||
|
||||
struct rcu_head rcu_head;
|
||||
};
|
||||
|
||||
/*
|
||||
@@ -282,9 +284,9 @@ static inline struct blkcg_gq *blkg_lookup(struct blkcg *blkcg,
|
||||
* Return pointer to private data associated with the @blkg-@pol pair.
|
||||
*/
|
||||
static inline struct blkg_policy_data *blkg_to_pd(struct blkcg_gq *blkg,
|
||||
struct blkcg_policy *pol)
|
||||
const struct blkcg_policy *pol)
|
||||
{
|
||||
return blkg ? blkg->pd[pol->plid] : NULL;
|
||||
return blkg ? READ_ONCE(blkg->pd[pol->plid]) : NULL;
|
||||
}
|
||||
|
||||
static inline struct blkcg_policy_data *blkcg_to_cpd(struct blkcg *blkcg,
|
||||
@@ -491,7 +493,7 @@ static inline void blkcg_deactivate_policy(struct gendisk *disk,
|
||||
const struct blkcg_policy *pol) { }
|
||||
|
||||
static inline struct blkg_policy_data *blkg_to_pd(struct blkcg_gq *blkg,
|
||||
struct blkcg_policy *pol) { return NULL; }
|
||||
const struct blkcg_policy *pol) { return NULL; }
|
||||
static inline struct blkcg_gq *pd_to_blkg(struct blkg_policy_data *pd) { return NULL; }
|
||||
static inline void blkg_get(struct blkcg_gq *blkg) { }
|
||||
static inline void blkg_put(struct blkcg_gq *blkg) { }
|
||||
|
||||
@@ -669,11 +669,6 @@ static inline blk_status_t blk_check_zone_append(struct request_queue *q,
|
||||
|
||||
static void __submit_bio(struct bio *bio)
|
||||
{
|
||||
/* If plug is not used, add new plug here to cache nsecs time. */
|
||||
struct blk_plug plug;
|
||||
|
||||
blk_start_plug(&plug);
|
||||
|
||||
if (!bdev_test_flag(bio->bi_bdev, BD_HAS_SUBMIT_BIO)) {
|
||||
blk_mq_submit_bio(bio);
|
||||
} else if (likely(bio_queue_enter(bio) == 0)) {
|
||||
@@ -686,8 +681,6 @@ static void __submit_bio(struct bio *bio)
|
||||
disk->fops->submit_bio(bio);
|
||||
blk_queue_exit(disk->queue);
|
||||
}
|
||||
|
||||
blk_finish_plug(&plug);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -3050,6 +3050,16 @@ static void ioc_pd_init(struct blkg_policy_data *pd)
|
||||
spin_unlock_irqrestore(&ioc->lock, flags);
|
||||
}
|
||||
|
||||
static void iocg_release(struct rcu_head *rcu)
|
||||
{
|
||||
struct blkg_policy_data *pd =
|
||||
container_of(rcu, struct blkg_policy_data, rcu_head);
|
||||
struct ioc_gq *iocg = pd_to_iocg(pd);
|
||||
|
||||
free_percpu(iocg->pcpu_stat);
|
||||
kfree(iocg);
|
||||
}
|
||||
|
||||
static void ioc_pd_free(struct blkg_policy_data *pd)
|
||||
{
|
||||
struct ioc_gq *iocg = pd_to_iocg(pd);
|
||||
@@ -3074,8 +3084,8 @@ static void ioc_pd_free(struct blkg_policy_data *pd)
|
||||
|
||||
hrtimer_cancel(&iocg->waitq_timer);
|
||||
}
|
||||
free_percpu(iocg->pcpu_stat);
|
||||
kfree(iocg);
|
||||
|
||||
call_rcu(&pd->rcu_head, iocg_release);
|
||||
}
|
||||
|
||||
static void ioc_pd_stat(struct blkg_policy_data *pd, struct seq_file *s)
|
||||
@@ -3211,7 +3221,7 @@ static u64 ioc_qos_prfill(struct seq_file *sf, struct blkg_policy_data *pd,
|
||||
if (!dname)
|
||||
return 0;
|
||||
|
||||
spin_lock(&ioc->lock);
|
||||
spin_lock_irq(&ioc->lock);
|
||||
seq_printf(sf, "%s enable=%d ctrl=%s rpct=%u.%02u rlat=%u wpct=%u.%02u wlat=%u min=%u.%02u max=%u.%02u\n",
|
||||
dname, ioc->enabled, ioc->user_qos_params ? "user" : "auto",
|
||||
ioc->params.qos[QOS_RPPM] / 10000,
|
||||
@@ -3224,7 +3234,7 @@ static u64 ioc_qos_prfill(struct seq_file *sf, struct blkg_policy_data *pd,
|
||||
ioc->params.qos[QOS_MIN] % 10000 / 100,
|
||||
ioc->params.qos[QOS_MAX] / 10000,
|
||||
ioc->params.qos[QOS_MAX] % 10000 / 100);
|
||||
spin_unlock(&ioc->lock);
|
||||
spin_unlock_irq(&ioc->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -3420,14 +3430,14 @@ static u64 ioc_cost_model_prfill(struct seq_file *sf,
|
||||
if (!dname)
|
||||
return 0;
|
||||
|
||||
spin_lock(&ioc->lock);
|
||||
spin_lock_irq(&ioc->lock);
|
||||
seq_printf(sf, "%s ctrl=%s model=linear "
|
||||
"rbps=%llu rseqiops=%llu rrandiops=%llu "
|
||||
"wbps=%llu wseqiops=%llu wrandiops=%llu\n",
|
||||
dname, ioc->user_cost_model ? "user" : "auto",
|
||||
u[I_LCOEF_RBPS], u[I_LCOEF_RSEQIOPS], u[I_LCOEF_RRANDIOPS],
|
||||
u[I_LCOEF_WBPS], u[I_LCOEF_WSEQIOPS], u[I_LCOEF_WRANDIOPS]);
|
||||
spin_unlock(&ioc->lock);
|
||||
spin_unlock_irq(&ioc->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -1031,13 +1031,21 @@ static void iolatency_pd_offline(struct blkg_policy_data *pd)
|
||||
iolatency_clear_scaling(blkg);
|
||||
}
|
||||
|
||||
static void iolatency_pd_free(struct blkg_policy_data *pd)
|
||||
static void iolat_release(struct rcu_head *rcu)
|
||||
{
|
||||
struct blkg_policy_data *pd =
|
||||
container_of(rcu, struct blkg_policy_data, rcu_head);
|
||||
struct iolatency_grp *iolat = pd_to_lat(pd);
|
||||
|
||||
free_percpu(iolat->stats);
|
||||
kfree(iolat);
|
||||
}
|
||||
|
||||
static void iolatency_pd_free(struct blkg_policy_data *pd)
|
||||
{
|
||||
call_rcu(&pd->rcu_head, iolat_release);
|
||||
}
|
||||
|
||||
static struct cftype iolatency_files[] = {
|
||||
{
|
||||
.name = "latency",
|
||||
|
||||
@@ -353,14 +353,23 @@ static void throtl_pd_online(struct blkg_policy_data *pd)
|
||||
tg_update_has_rules(tg);
|
||||
}
|
||||
|
||||
static void tg_release(struct rcu_head *rcu)
|
||||
{
|
||||
struct blkg_policy_data *pd =
|
||||
container_of(rcu, struct blkg_policy_data, rcu_head);
|
||||
struct throtl_grp *tg = pd_to_tg(pd);
|
||||
|
||||
blkg_rwstat_exit(&tg->stat_bytes);
|
||||
blkg_rwstat_exit(&tg->stat_ios);
|
||||
kfree(tg);
|
||||
}
|
||||
|
||||
static void throtl_pd_free(struct blkg_policy_data *pd)
|
||||
{
|
||||
struct throtl_grp *tg = pd_to_tg(pd);
|
||||
|
||||
timer_delete_sync(&tg->service_queue.pending_timer);
|
||||
blkg_rwstat_exit(&tg->stat_bytes);
|
||||
blkg_rwstat_exit(&tg->stat_ios);
|
||||
kfree(tg);
|
||||
call_rcu(&pd->rcu_head, tg_release);
|
||||
}
|
||||
|
||||
static struct throtl_grp *
|
||||
|
||||
@@ -120,13 +120,13 @@ static void error_inject_removeall(struct gendisk *disk)
|
||||
struct blk_error_inject *inj;
|
||||
|
||||
mutex_lock(&disk->error_injection_lock);
|
||||
clear_bit(GD_ERROR_INJECT, &disk->state);
|
||||
if (test_and_clear_bit(GD_ERROR_INJECT, &disk->state))
|
||||
static_branch_dec(&blk_error_injection_enabled);
|
||||
while ((inj = list_first_entry_or_null(&disk->error_injection_list,
|
||||
struct blk_error_inject, entry))) {
|
||||
list_del_rcu(&inj->entry);
|
||||
kfree_rcu_mightsleep(inj);
|
||||
}
|
||||
static_branch_dec(&blk_error_injection_enabled);
|
||||
mutex_unlock(&disk->error_injection_lock);
|
||||
}
|
||||
|
||||
|
||||
@@ -951,7 +951,7 @@ int blkdev_uring_cmd(struct io_uring_cmd *cmd, unsigned int issue_flags)
|
||||
u32 cmd_op = cmd->cmd_op;
|
||||
|
||||
/* Read what we need from the SQE on the first issue */
|
||||
if (!(issue_flags & IORING_URING_CMD_REISSUE)) {
|
||||
if (!(cmd->flags & IORING_URING_CMD_REISSUE)) {
|
||||
const struct io_uring_sqe *sqe = cmd->sqe;
|
||||
|
||||
if (unlikely(sqe->ioprio || sqe->__pad1 || sqe->len ||
|
||||
|
||||
@@ -1246,7 +1246,7 @@ static void nbd_reclassify_socket(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
|
||||
if (WARN_ON_ONCE(!sock_allow_reclassification(sk)))
|
||||
if (!sock_allow_reclassification(sk))
|
||||
return;
|
||||
|
||||
switch (sk->sk_family) {
|
||||
|
||||
@@ -2064,18 +2064,23 @@ static void bitmap_end_behind_write(struct mddev *mddev)
|
||||
bitmap->mddev->bitmap_info.max_write_behind);
|
||||
}
|
||||
|
||||
static void bitmap_wait_behind_writes(struct mddev *mddev)
|
||||
static bool bitmap_wait_behind_writes(struct mddev *mddev, bool nowait)
|
||||
{
|
||||
struct bitmap *bitmap = mddev->bitmap;
|
||||
|
||||
/* wait for behind writes to complete */
|
||||
if (bitmap && atomic_read(&bitmap->behind_writes) > 0) {
|
||||
if (nowait)
|
||||
return false;
|
||||
|
||||
pr_debug("md:%s: behind writes in progress - waiting to stop.\n",
|
||||
mdname(mddev));
|
||||
/* need to kick something here to make sure I/O goes? */
|
||||
wait_event(bitmap->behind_wait,
|
||||
atomic_read(&bitmap->behind_writes) == 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void bitmap_destroy(struct mddev *mddev)
|
||||
@@ -2085,7 +2090,7 @@ static void bitmap_destroy(struct mddev *mddev)
|
||||
if (!bitmap) /* there was no bitmap */
|
||||
return;
|
||||
|
||||
bitmap_wait_behind_writes(mddev);
|
||||
bitmap_wait_behind_writes(mddev, false);
|
||||
if (!test_bit(MD_SERIALIZE_POLICY, &mddev->flags))
|
||||
mddev_destroy_serial_pool(mddev, NULL);
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ struct bitmap_operations {
|
||||
|
||||
void (*start_behind_write)(struct mddev *mddev);
|
||||
void (*end_behind_write)(struct mddev *mddev);
|
||||
void (*wait_behind_writes)(struct mddev *mddev);
|
||||
bool (*wait_behind_writes)(struct mddev *mddev, bool nowait);
|
||||
|
||||
md_bitmap_fn *start_write;
|
||||
md_bitmap_fn *end_write;
|
||||
|
||||
@@ -1574,16 +1574,19 @@ static void llbitmap_end_behind_write(struct mddev *mddev)
|
||||
wake_up(&llbitmap->behind_wait);
|
||||
}
|
||||
|
||||
static void llbitmap_wait_behind_writes(struct mddev *mddev)
|
||||
static bool llbitmap_wait_behind_writes(struct mddev *mddev, bool nowait)
|
||||
{
|
||||
struct llbitmap *llbitmap = mddev->bitmap;
|
||||
|
||||
if (!llbitmap)
|
||||
return;
|
||||
if (llbitmap && atomic_read(&llbitmap->behind_writes) > 0) {
|
||||
if (nowait)
|
||||
return false;
|
||||
|
||||
wait_event(llbitmap->behind_wait,
|
||||
atomic_read(&llbitmap->behind_writes) == 0);
|
||||
wait_event(llbitmap->behind_wait,
|
||||
atomic_read(&llbitmap->behind_writes) == 0);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static ssize_t bits_show(struct mddev *mddev, char *page)
|
||||
|
||||
@@ -7050,7 +7050,7 @@ EXPORT_SYMBOL_GPL(md_stop_writes);
|
||||
static void mddev_detach(struct mddev *mddev)
|
||||
{
|
||||
if (md_bitmap_enabled(mddev, false))
|
||||
mddev->bitmap_ops->wait_behind_writes(mddev);
|
||||
mddev->bitmap_ops->wait_behind_writes(mddev, false);
|
||||
if (mddev->pers && mddev->pers->quiesce && !is_md_suspended(mddev)) {
|
||||
mddev->pers->quiesce(mddev, 1);
|
||||
mddev->pers->quiesce(mddev, 0);
|
||||
|
||||
@@ -359,8 +359,8 @@ static inline void update_head_pos(int disk, struct r1bio *r1_bio)
|
||||
{
|
||||
struct r1conf *conf = r1_bio->mddev->private;
|
||||
|
||||
conf->mirrors[disk].head_position =
|
||||
r1_bio->sector + (r1_bio->sectors);
|
||||
WRITE_ONCE(conf->mirrors[disk].head_position,
|
||||
r1_bio->sector + r1_bio->sectors);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -737,7 +737,7 @@ static bool is_sequential(struct r1conf *conf, int disk, struct r1bio *r1_bio)
|
||||
{
|
||||
/* TODO: address issues with this check and concurrency. */
|
||||
return conf->mirrors[disk].next_seq_sect == r1_bio->sector ||
|
||||
conf->mirrors[disk].head_position == r1_bio->sector;
|
||||
READ_ONCE(conf->mirrors[disk].head_position) == r1_bio->sector;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -814,7 +814,8 @@ static int choose_best_rdev(struct r1conf *conf, struct r1bio *r1_bio)
|
||||
set_bit(R1BIO_FailFast, &r1_bio->state);
|
||||
|
||||
pending = atomic_read(&rdev->nr_pending);
|
||||
dist = abs(r1_bio->sector - conf->mirrors[disk].head_position);
|
||||
dist = abs(r1_bio->sector -
|
||||
READ_ONCE(conf->mirrors[disk].head_position));
|
||||
|
||||
/* Don't change to another disk for sequential reads */
|
||||
if (is_sequential(conf, disk, r1_bio)) {
|
||||
@@ -1341,6 +1342,7 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
|
||||
int max_sectors;
|
||||
int rdisk;
|
||||
bool r1bio_existed = !!r1_bio;
|
||||
bool nowait = bio->bi_opf & REQ_NOWAIT;
|
||||
|
||||
/*
|
||||
* An md cloned bio indicates we are in the error path.
|
||||
@@ -1360,9 +1362,14 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
|
||||
* Still need barrier for READ in case that whole
|
||||
* array is frozen.
|
||||
*/
|
||||
if (!wait_read_barrier(conf, bio->bi_iter.bi_sector,
|
||||
bio->bi_opf & REQ_NOWAIT)) {
|
||||
if (!wait_read_barrier(conf, bio->bi_iter.bi_sector, nowait)) {
|
||||
bio_wouldblock_error(bio);
|
||||
|
||||
if (r1bio_existed) {
|
||||
set_bit(R1BIO_Returned, &r1_bio->state);
|
||||
raid_end_bio_io(r1_bio);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1402,7 +1409,11 @@ static void raid1_read_request(struct mddev *mddev, struct bio *bio,
|
||||
* over-take any writes that are 'behind'
|
||||
*/
|
||||
mddev_add_trace_msg(mddev, "raid1 wait behind writes");
|
||||
mddev->bitmap_ops->wait_behind_writes(mddev);
|
||||
if (!mddev->bitmap_ops->wait_behind_writes(mddev, nowait)) {
|
||||
bio_wouldblock_error(bio);
|
||||
set_bit(R1BIO_Returned, &r1_bio->state);
|
||||
goto err_handle;
|
||||
}
|
||||
}
|
||||
|
||||
if (max_sectors < bio_sectors(bio)) {
|
||||
@@ -1501,29 +1512,30 @@ static void raid1_start_write_behind(struct mddev *mddev, struct r1bio *r1_bio,
|
||||
|
||||
}
|
||||
|
||||
static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
int max_write_sectors)
|
||||
static bool raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
int max_sectors)
|
||||
{
|
||||
struct r1conf *conf = mddev->private;
|
||||
struct r1bio *r1_bio;
|
||||
int i, disks, k;
|
||||
unsigned long flags;
|
||||
int first_clone;
|
||||
int max_sectors;
|
||||
bool write_behind = false;
|
||||
bool is_discard = (bio_op(bio) == REQ_OP_DISCARD);
|
||||
bool nowait = bio->bi_opf & REQ_NOWAIT;
|
||||
bool is_discard = op_is_discard(bio->bi_opf);
|
||||
sector_t sector = bio->bi_iter.bi_sector;
|
||||
|
||||
if (mddev_is_clustered(mddev) &&
|
||||
mddev->cluster_ops->area_resyncing(mddev, WRITE,
|
||||
bio->bi_iter.bi_sector, bio_end_sector(bio))) {
|
||||
mddev->cluster_ops->area_resyncing(mddev, WRITE, sector,
|
||||
bio_end_sector(bio))) {
|
||||
|
||||
if (bio->bi_opf & REQ_NOWAIT) {
|
||||
if (nowait) {
|
||||
bio_wouldblock_error(bio);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
wait_event_idle(conf->wait_barrier,
|
||||
!mddev->cluster_ops->area_resyncing(mddev, WRITE,
|
||||
bio->bi_iter.bi_sector,
|
||||
sector,
|
||||
bio_end_sector(bio)));
|
||||
}
|
||||
|
||||
@@ -1532,19 +1544,18 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
* thread has put up a bar for new requests.
|
||||
* Continue immediately if no resync is active currently.
|
||||
*/
|
||||
if (!wait_barrier(conf, bio->bi_iter.bi_sector,
|
||||
bio->bi_opf & REQ_NOWAIT)) {
|
||||
if (!wait_barrier(conf, sector, nowait)) {
|
||||
bio_wouldblock_error(bio);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!wait_blocked_rdev(mddev, bio)) {
|
||||
bio_wouldblock_error(bio);
|
||||
return;
|
||||
goto err_allow_barrier;
|
||||
}
|
||||
|
||||
r1_bio = alloc_r1bio(mddev, bio);
|
||||
r1_bio->sectors = max_write_sectors;
|
||||
r1_bio->sectors = max_sectors;
|
||||
|
||||
/* first select target devices under rcu_lock and
|
||||
* inc refcount on their rdev. Record them by setting
|
||||
@@ -1558,7 +1569,6 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
*/
|
||||
|
||||
disks = conf->raid_disks * 2;
|
||||
max_sectors = r1_bio->sectors;
|
||||
for (i = 0; i < disks; i++) {
|
||||
struct md_rdev *rdev = conf->mirrors[i].rdev;
|
||||
|
||||
@@ -1574,23 +1584,21 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
if (!rdev || test_bit(Faulty, &rdev->flags))
|
||||
continue;
|
||||
|
||||
atomic_inc(&rdev->nr_pending);
|
||||
if (test_bit(WriteErrorSeen, &rdev->flags)) {
|
||||
sector_t first_bad;
|
||||
sector_t bad_sectors;
|
||||
int is_bad;
|
||||
|
||||
is_bad = is_badblock(rdev, r1_bio->sector, max_sectors,
|
||||
is_bad = is_badblock(rdev, sector, max_sectors,
|
||||
&first_bad, &bad_sectors);
|
||||
if (is_bad && first_bad <= r1_bio->sector) {
|
||||
if (is_bad && first_bad <= sector) {
|
||||
/* Cannot write here at all */
|
||||
bad_sectors -= (r1_bio->sector - first_bad);
|
||||
bad_sectors -= (sector - first_bad);
|
||||
if (bad_sectors < max_sectors)
|
||||
/* mustn't write more than bad_sectors
|
||||
* to other devices yet
|
||||
*/
|
||||
max_sectors = bad_sectors;
|
||||
rdev_dec_pending(rdev, mddev);
|
||||
continue;
|
||||
}
|
||||
if (is_bad) {
|
||||
@@ -1604,15 +1612,18 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
* the benefit.
|
||||
*/
|
||||
if (bio->bi_opf & REQ_ATOMIC) {
|
||||
rdev_dec_pending(rdev, mddev);
|
||||
goto err_handle;
|
||||
bio->bi_status = BLK_STS_NOTSUPP;
|
||||
bio_endio(bio);
|
||||
goto err_dec_pending;
|
||||
}
|
||||
|
||||
good_sectors = first_bad - r1_bio->sector;
|
||||
good_sectors = first_bad - sector;
|
||||
if (good_sectors < max_sectors)
|
||||
max_sectors = good_sectors;
|
||||
}
|
||||
}
|
||||
|
||||
atomic_inc(&rdev->nr_pending);
|
||||
r1_bio->bios[i] = bio;
|
||||
}
|
||||
|
||||
@@ -1628,10 +1639,8 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
if (max_sectors < bio_sectors(bio)) {
|
||||
bio = bio_submit_split_bioset(bio, max_sectors,
|
||||
&conf->bio_split);
|
||||
if (!bio) {
|
||||
set_bit(R1BIO_Returned, &r1_bio->state);
|
||||
goto err_handle;
|
||||
}
|
||||
if (!bio)
|
||||
goto err_dec_pending;
|
||||
|
||||
r1_bio->master_bio = bio;
|
||||
r1_bio->sectors = max_sectors;
|
||||
@@ -1675,7 +1684,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
mbio->bi_opf &= ~REQ_NOWAIT;
|
||||
r1_bio->bios[i] = mbio;
|
||||
|
||||
mbio->bi_iter.bi_sector = (r1_bio->sector + rdev->data_offset);
|
||||
mbio->bi_iter.bi_sector = sector + rdev->data_offset;
|
||||
mbio->bi_end_io = raid1_end_write_request;
|
||||
if (test_bit(FailFast, &rdev->flags) &&
|
||||
!test_bit(WriteMostly, &rdev->flags) &&
|
||||
@@ -1684,7 +1693,7 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
mbio->bi_private = r1_bio;
|
||||
|
||||
atomic_inc(&r1_bio->remaining);
|
||||
mddev_trace_remap(mddev, mbio, r1_bio->sector);
|
||||
mddev_trace_remap(mddev, mbio, sector);
|
||||
/* flush_pending_writes() needs access to the rdev so...*/
|
||||
mbio->bi_bdev = (void *)rdev;
|
||||
if (!raid1_add_bio_to_plug(mddev, mbio, raid1_unplug, disks)) {
|
||||
@@ -1699,8 +1708,10 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
|
||||
/* In case raid1d snuck in to freeze_array */
|
||||
wake_up_barrier(conf);
|
||||
return;
|
||||
err_handle:
|
||||
|
||||
return true;
|
||||
|
||||
err_dec_pending:
|
||||
for (k = 0; k < i; k++) {
|
||||
if (r1_bio->bios[k]) {
|
||||
rdev_dec_pending(conf->mirrors[k].rdev, mddev);
|
||||
@@ -1708,7 +1719,12 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
|
||||
}
|
||||
}
|
||||
|
||||
raid_end_bio_io(r1_bio);
|
||||
free_r1bio(r1_bio);
|
||||
|
||||
err_allow_barrier:
|
||||
allow_barrier(conf, sector);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
|
||||
@@ -1732,8 +1748,9 @@ static bool raid1_make_request(struct mddev *mddev, struct bio *bio)
|
||||
if (bio_data_dir(bio) == READ)
|
||||
raid1_read_request(mddev, bio, sectors, NULL);
|
||||
else {
|
||||
md_write_start(mddev,bio);
|
||||
raid1_write_request(mddev, bio, sectors);
|
||||
md_write_start(mddev, bio);
|
||||
if (!raid1_write_request(mddev, bio, sectors))
|
||||
md_write_end(mddev);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1349,7 +1349,7 @@ static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio)
|
||||
}
|
||||
}
|
||||
|
||||
static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
static bool raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
struct r10bio *r10_bio)
|
||||
{
|
||||
struct r10conf *conf = mddev->private;
|
||||
@@ -1365,7 +1365,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
/* Bail out if REQ_NOWAIT is set for the bio */
|
||||
if (bio->bi_opf & REQ_NOWAIT) {
|
||||
bio_wouldblock_error(bio);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
for (;;) {
|
||||
prepare_to_wait(&conf->wait_barrier,
|
||||
@@ -1381,7 +1381,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
sectors = r10_bio->sectors;
|
||||
if (!regular_request_wait(mddev, conf, bio, sectors)) {
|
||||
free_r10bio(r10_bio);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
|
||||
@@ -1398,7 +1398,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
if (bio->bi_opf & REQ_NOWAIT) {
|
||||
allow_barrier(conf);
|
||||
bio_wouldblock_error(bio);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
mddev_add_trace_msg(conf->mddev,
|
||||
"raid10 wait reshape metadata");
|
||||
@@ -1514,7 +1514,8 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
raid10_write_one_disk(mddev, r10_bio, bio, true, i);
|
||||
}
|
||||
one_write_done(r10_bio);
|
||||
return;
|
||||
return true;
|
||||
|
||||
err_handle:
|
||||
for (k = 0; k < i; k++) {
|
||||
int d = r10_bio->devs[k].devnum;
|
||||
@@ -1532,10 +1533,12 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
}
|
||||
|
||||
raid_end_bio_io(r10_bio);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
|
||||
static bool __make_request(struct mddev *mddev, struct bio *bio, int sectors)
|
||||
{
|
||||
bool ret;
|
||||
struct r10conf *conf = mddev->private;
|
||||
struct r10bio *r10_bio;
|
||||
|
||||
@@ -1551,10 +1554,13 @@ static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
|
||||
memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) *
|
||||
conf->geo.raid_disks);
|
||||
|
||||
ret = true;
|
||||
if (bio_data_dir(bio) == READ)
|
||||
raid10_read_request(mddev, bio, r10_bio);
|
||||
else
|
||||
raid10_write_request(mddev, bio, r10_bio);
|
||||
ret = raid10_write_request(mddev, bio, r10_bio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void raid_end_discard_bio(struct r10bio *r10bio)
|
||||
@@ -1633,6 +1639,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
|
||||
|
||||
if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
|
||||
bio_wouldblock_error(bio);
|
||||
md_write_end(mddev);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1675,6 +1682,8 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
|
||||
if (IS_ERR(split)) {
|
||||
bio->bi_status = errno_to_blk_status(PTR_ERR(split));
|
||||
bio_endio(bio);
|
||||
md_write_end(mddev);
|
||||
allow_barrier(conf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1692,6 +1701,8 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
|
||||
if (IS_ERR(split)) {
|
||||
bio->bi_status = errno_to_blk_status(PTR_ERR(split));
|
||||
bio_endio(bio);
|
||||
md_write_end(mddev);
|
||||
allow_barrier(conf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1900,7 +1911,8 @@ static bool raid10_make_request(struct mddev *mddev, struct bio *bio)
|
||||
sectors = chunk_sects -
|
||||
(bio->bi_iter.bi_sector &
|
||||
(chunk_sects - 1));
|
||||
__make_request(mddev, bio, sectors);
|
||||
if (!__make_request(mddev, bio, sectors))
|
||||
md_write_end(mddev);
|
||||
|
||||
/* In case raid10d snuck in to freeze_array */
|
||||
wake_up_barrier(conf);
|
||||
|
||||
@@ -996,7 +996,7 @@ static void stripe_add_to_batch_list(struct r5conf *conf,
|
||||
if (test_and_clear_bit(STRIPE_BIT_DELAY, &sh->state)) {
|
||||
int seq = sh->bm_seq;
|
||||
if (test_bit(STRIPE_BIT_DELAY, &sh->batch_head->state) &&
|
||||
sh->batch_head->bm_seq > seq)
|
||||
sh->batch_head->bm_seq - seq > 0)
|
||||
seq = sh->batch_head->bm_seq;
|
||||
set_bit(STRIPE_BIT_DELAY, &sh->batch_head->state);
|
||||
sh->batch_head->bm_seq = seq;
|
||||
@@ -1134,6 +1134,21 @@ static void defer_issue_bios(struct r5conf *conf, sector_t sector,
|
||||
dispatch_bio_list(&tmp);
|
||||
}
|
||||
|
||||
static bool raid5_discard_limits(struct mddev *mddev, struct bio *bi)
|
||||
{
|
||||
struct r5conf *conf = mddev->private;
|
||||
|
||||
if (mddev->bitmap_id == ID_LLBITMAP)
|
||||
return true;
|
||||
|
||||
if (!conf->raid5_discard_unsupported)
|
||||
return true;
|
||||
|
||||
bi->bi_status = BLK_STS_NOTSUPP;
|
||||
bio_endio(bi);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
raid5_end_read_request(struct bio *bi);
|
||||
static void
|
||||
@@ -4837,55 +4852,62 @@ static void break_stripe_batch_list(struct stripe_head *head_sh,
|
||||
{
|
||||
struct stripe_head *sh, *next;
|
||||
int i;
|
||||
unsigned long state;
|
||||
|
||||
list_for_each_entry_safe(sh, next, &head_sh->batch_list, batch_list) {
|
||||
|
||||
list_del_init(&sh->batch_list);
|
||||
|
||||
WARN_ONCE(sh->state & ((1 << STRIPE_ACTIVE) |
|
||||
(1 << STRIPE_SYNCING) |
|
||||
(1 << STRIPE_REPLACED) |
|
||||
(1 << STRIPE_DELAYED) |
|
||||
(1 << STRIPE_BIT_DELAY) |
|
||||
(1 << STRIPE_FULL_WRITE) |
|
||||
(1 << STRIPE_BIOFILL_RUN) |
|
||||
(1 << STRIPE_COMPUTE_RUN) |
|
||||
(1 << STRIPE_DISCARD) |
|
||||
(1 << STRIPE_BATCH_READY) |
|
||||
(1 << STRIPE_BATCH_ERR)),
|
||||
"stripe state: %lx\n", sh->state);
|
||||
WARN_ONCE(head_sh->state & ((1 << STRIPE_DISCARD) |
|
||||
(1 << STRIPE_REPLACED)),
|
||||
"head stripe state: %lx\n", head_sh->state);
|
||||
state = READ_ONCE(sh->state);
|
||||
WARN_ONCE(state & ((1 << STRIPE_ACTIVE) |
|
||||
(1 << STRIPE_SYNCING) |
|
||||
(1 << STRIPE_REPLACED) |
|
||||
(1 << STRIPE_DELAYED) |
|
||||
(1 << STRIPE_BIT_DELAY) |
|
||||
(1 << STRIPE_FULL_WRITE) |
|
||||
(1 << STRIPE_BIOFILL_RUN) |
|
||||
(1 << STRIPE_COMPUTE_RUN) |
|
||||
(1 << STRIPE_DISCARD) |
|
||||
(1 << STRIPE_BATCH_READY) |
|
||||
(1 << STRIPE_BATCH_ERR)),
|
||||
"stripe state: %lx\n", state);
|
||||
|
||||
state = READ_ONCE(head_sh->state);
|
||||
WARN_ONCE(state & ((1 << STRIPE_DISCARD) |
|
||||
(1 << STRIPE_REPLACED)),
|
||||
"head stripe state: %lx\n", state);
|
||||
|
||||
set_mask_bits(&sh->state, ~(STRIPE_EXPAND_SYNC_FLAGS |
|
||||
(1 << STRIPE_PREREAD_ACTIVE) |
|
||||
(1 << STRIPE_ON_UNPLUG_LIST)),
|
||||
head_sh->state & (1 << STRIPE_INSYNC));
|
||||
state & (1 << STRIPE_INSYNC));
|
||||
|
||||
sh->check_state = head_sh->check_state;
|
||||
sh->reconstruct_state = head_sh->reconstruct_state;
|
||||
spin_lock_irq(&sh->stripe_lock);
|
||||
sh->batch_head = NULL;
|
||||
spin_unlock_irq(&sh->stripe_lock);
|
||||
for (i = 0; i < sh->disks; i++) {
|
||||
if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
|
||||
wake_up_bit(&sh->dev[i].flags, R5_Overlap);
|
||||
sh->dev[i].flags = head_sh->dev[i].flags &
|
||||
sh->dev[i].flags = READ_ONCE(head_sh->dev[i].flags) &
|
||||
(~((1 << R5_WriteError) | (1 << R5_Overlap)));
|
||||
}
|
||||
if (handle_flags == 0 ||
|
||||
sh->state & handle_flags)
|
||||
sh->batch_head = NULL;
|
||||
spin_unlock_irq(&sh->stripe_lock);
|
||||
|
||||
state = READ_ONCE(sh->state);
|
||||
if (handle_flags == 0 || (state & handle_flags))
|
||||
set_bit(STRIPE_HANDLE, &sh->state);
|
||||
raid5_release_stripe(sh);
|
||||
}
|
||||
spin_lock_irq(&head_sh->stripe_lock);
|
||||
head_sh->batch_head = NULL;
|
||||
spin_unlock_irq(&head_sh->stripe_lock);
|
||||
for (i = 0; i < head_sh->disks; i++)
|
||||
if (test_and_clear_bit(R5_Overlap, &head_sh->dev[i].flags))
|
||||
wake_up_bit(&head_sh->dev[i].flags, R5_Overlap);
|
||||
if (head_sh->state & handle_flags)
|
||||
head_sh->batch_head = NULL;
|
||||
spin_unlock_irq(&head_sh->stripe_lock);
|
||||
|
||||
state = READ_ONCE(head_sh->state);
|
||||
if (state & handle_flags)
|
||||
set_bit(STRIPE_HANDLE, &head_sh->state);
|
||||
}
|
||||
|
||||
@@ -5690,7 +5712,10 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
|
||||
{
|
||||
struct r5conf *conf = mddev->private;
|
||||
sector_t logical_sector, last_sector;
|
||||
sector_t first_stripe, last_stripe;
|
||||
struct stripe_head *sh;
|
||||
struct bvec_iter bi_iter;
|
||||
struct bio *orig_bi = bi;
|
||||
int stripe_sectors;
|
||||
|
||||
/* We need to handle this when io_uring supports discard/trim */
|
||||
@@ -5701,19 +5726,38 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
|
||||
/* Skip discard while reshape is happening */
|
||||
return;
|
||||
|
||||
logical_sector = bi->bi_iter.bi_sector & ~((sector_t)RAID5_STRIPE_SECTORS(conf)-1);
|
||||
last_sector = bio_end_sector(bi);
|
||||
|
||||
bi->bi_next = NULL;
|
||||
if (!raid5_discard_limits(mddev, bi))
|
||||
return;
|
||||
|
||||
stripe_sectors = conf->chunk_sectors *
|
||||
(conf->raid_disks - conf->max_degraded);
|
||||
logical_sector = DIV_ROUND_UP_SECTOR_T(logical_sector,
|
||||
stripe_sectors);
|
||||
sector_div(last_sector, stripe_sectors);
|
||||
first_stripe = DIV_ROUND_UP_SECTOR_T(bi->bi_iter.bi_sector,
|
||||
stripe_sectors);
|
||||
last_stripe = bio_end_sector(bi);
|
||||
sector_div(last_stripe, stripe_sectors);
|
||||
|
||||
logical_sector *= conf->chunk_sectors;
|
||||
last_sector *= conf->chunk_sectors;
|
||||
if (first_stripe >= last_stripe) {
|
||||
bio_endio(bi);
|
||||
return;
|
||||
}
|
||||
|
||||
bi_iter = bi->bi_iter;
|
||||
bi->bi_iter.bi_sector = first_stripe * stripe_sectors;
|
||||
bi->bi_iter.bi_size = ((last_stripe - first_stripe) *
|
||||
stripe_sectors) << 9;
|
||||
md_account_bio(mddev, &bi);
|
||||
orig_bi->bi_iter = bi_iter;
|
||||
bi->bi_iter = bi_iter;
|
||||
bi->bi_next = NULL;
|
||||
|
||||
if (mddev->bitmap_id == ID_LLBITMAP &&
|
||||
conf->raid5_discard_unsupported) {
|
||||
bio_endio(bi);
|
||||
return;
|
||||
}
|
||||
|
||||
logical_sector = first_stripe * conf->chunk_sectors;
|
||||
last_sector = last_stripe * conf->chunk_sectors;
|
||||
|
||||
for (; logical_sector < last_sector;
|
||||
logical_sector += RAID5_STRIPE_SECTORS(conf)) {
|
||||
@@ -7804,24 +7848,12 @@ static int raid5_set_limits(struct mddev *mddev)
|
||||
queue_limits_stack_bdev(&lim, rdev->bdev, rdev->new_data_offset,
|
||||
mddev->gendisk->disk_name);
|
||||
|
||||
/*
|
||||
* Zeroing is required for discard, otherwise data could be lost.
|
||||
*
|
||||
* Consider a scenario: discard a stripe (the stripe could be
|
||||
* inconsistent if discard_zeroes_data is 0); write one disk of the
|
||||
* stripe (the stripe could be inconsistent again depending on which
|
||||
* disks are used to calculate parity); the disk is broken; The stripe
|
||||
* data of this disk is lost.
|
||||
*
|
||||
* We only allow DISCARD if the sysadmin has confirmed that only safe
|
||||
* devices are in use by setting a module parameter. A better idea
|
||||
* might be to turn DISCARD into WRITE_ZEROES requests, as that is
|
||||
* required to be safe.
|
||||
*/
|
||||
if (!devices_handle_discard_safely ||
|
||||
lim.max_discard_sectors < (stripe >> 9) ||
|
||||
lim.discard_granularity < stripe)
|
||||
lim.max_hw_discard_sectors = 0;
|
||||
conf->raid5_discard_unsupported = true;
|
||||
else
|
||||
conf->raid5_discard_unsupported = false;
|
||||
|
||||
/*
|
||||
* Requests require having a bitmap for each stripe.
|
||||
@@ -7830,6 +7862,7 @@ static int raid5_set_limits(struct mddev *mddev)
|
||||
lim.max_hw_sectors = RAID5_MAX_REQ_STRIPES << RAID5_STRIPE_SHIFT(conf);
|
||||
if ((lim.max_hw_sectors << 9) < lim.io_opt)
|
||||
lim.max_hw_sectors = lim.io_opt >> 9;
|
||||
lim.max_hw_discard_sectors = UINT_MAX;
|
||||
|
||||
/* No restrictions on the number of segments in the request */
|
||||
lim.max_segments = USHRT_MAX;
|
||||
|
||||
@@ -689,6 +689,7 @@ struct r5conf {
|
||||
struct list_head pending_list;
|
||||
int pending_data_cnt;
|
||||
struct r5pending_data *next_pending_data;
|
||||
bool raid5_discard_unsupported;
|
||||
|
||||
mempool_t *ctx_pool;
|
||||
int ctx_size;
|
||||
|
||||
@@ -225,7 +225,7 @@ static unsigned int apple_nvme_queue_depth(struct apple_nvme_queue *q)
|
||||
{
|
||||
struct apple_nvme *anv = queue_to_apple_nvme(q);
|
||||
|
||||
if (q->is_adminq && anv->hw->has_lsq_nvmmu)
|
||||
if (q->is_adminq)
|
||||
return APPLE_NVME_AQ_DEPTH;
|
||||
|
||||
return anv->hw->max_queue_depth;
|
||||
@@ -303,7 +303,7 @@ static void apple_nvme_submit_cmd_t8015(struct apple_nvme_queue *q,
|
||||
memcpy((void *)q->sqes + (q->sq_tail << APPLE_NVME_IOSQES),
|
||||
cmd, sizeof(*cmd));
|
||||
|
||||
if (++q->sq_tail == anv->hw->max_queue_depth)
|
||||
if (++q->sq_tail == apple_nvme_queue_depth(q))
|
||||
q->sq_tail = 0;
|
||||
|
||||
writel(q->sq_tail, q->sq_db);
|
||||
@@ -1139,10 +1139,7 @@ static void apple_nvme_reset_work(struct work_struct *work)
|
||||
}
|
||||
|
||||
/* Setup the admin queue */
|
||||
if (anv->hw->has_lsq_nvmmu)
|
||||
aqa = APPLE_NVME_AQ_DEPTH - 1;
|
||||
else
|
||||
aqa = anv->hw->max_queue_depth - 1;
|
||||
aqa = APPLE_NVME_AQ_DEPTH - 1;
|
||||
aqa |= aqa << 16;
|
||||
writel(aqa, anv->mmio_nvme + NVME_REG_AQA);
|
||||
writeq(anv->adminq.sq_dma_addr, anv->mmio_nvme + NVME_REG_ASQ);
|
||||
@@ -1325,8 +1322,7 @@ static int apple_nvme_alloc_tagsets(struct apple_nvme *anv)
|
||||
* both queues. The admin queue gets the first APPLE_NVME_AQ_DEPTH which
|
||||
* must be marked as reserved in the IO queue.
|
||||
*/
|
||||
if (anv->hw->has_lsq_nvmmu)
|
||||
anv->tagset.reserved_tags = APPLE_NVME_AQ_DEPTH;
|
||||
anv->tagset.reserved_tags = APPLE_NVME_AQ_DEPTH;
|
||||
anv->tagset.queue_depth = anv->hw->max_queue_depth - 1;
|
||||
anv->tagset.timeout = NVME_IO_TIMEOUT;
|
||||
anv->tagset.numa_node = NUMA_NO_NODE;
|
||||
|
||||
@@ -2379,6 +2379,11 @@ static int nvme_query_fdp_info(struct nvme_ns *ns, struct nvme_ns_info *info)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static bool nvme_invalid_lba_sz(u64 nsze, signed int shift, sector_t *capacity)
|
||||
{
|
||||
return check_shl_overflow(nsze, shift, capacity);
|
||||
}
|
||||
|
||||
static int nvme_update_ns_info_block(struct nvme_ns *ns,
|
||||
struct nvme_ns_info *info)
|
||||
{
|
||||
@@ -2422,10 +2427,8 @@ static int nvme_update_ns_info_block(struct nvme_ns *ns,
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (id->lbaf[lbaf].ds < SECTOR_SHIFT ||
|
||||
check_shl_overflow(le64_to_cpu(id->nsze),
|
||||
id->lbaf[lbaf].ds - SECTOR_SHIFT,
|
||||
&capacity)) {
|
||||
if (nvme_invalid_lba_sz(le64_to_cpu(id->nsze),
|
||||
id->lbaf[lbaf].ds - SECTOR_SHIFT, &capacity)) {
|
||||
dev_warn_once(ns->ctrl->device,
|
||||
"invalid LBA data size %u, skipping namespace\n",
|
||||
id->lbaf[lbaf].ds);
|
||||
@@ -3895,7 +3898,8 @@ void nvme_cdev_del(struct cdev *cdev, struct device *cdev_device)
|
||||
put_device(cdev_device);
|
||||
}
|
||||
|
||||
int nvme_cdev_add(struct cdev *cdev, struct device *cdev_device,
|
||||
int nvme_cdev_add(const char *name, struct cdev *cdev,
|
||||
struct device *cdev_device,
|
||||
const struct file_operations *fops, struct module *owner)
|
||||
{
|
||||
int minor, ret;
|
||||
@@ -3903,6 +3907,12 @@ int nvme_cdev_add(struct cdev *cdev, struct device *cdev_device,
|
||||
minor = ida_alloc(&nvme_ns_chr_minor_ida, GFP_KERNEL);
|
||||
if (minor < 0)
|
||||
return minor;
|
||||
|
||||
ret = dev_set_name(cdev_device, name);
|
||||
if (ret) {
|
||||
ida_free(&nvme_ns_chr_minor_ida, minor);
|
||||
return ret;
|
||||
}
|
||||
cdev_device->devt = MKDEV(MAJOR(nvme_ns_chr_devt), minor);
|
||||
cdev_device->class = &nvme_ns_chr_class;
|
||||
cdev_device->release = nvme_cdev_rel;
|
||||
@@ -3937,18 +3947,21 @@ static const struct file_operations nvme_ns_chr_fops = {
|
||||
.uring_cmd_iopoll = nvme_ns_chr_uring_cmd_iopoll,
|
||||
};
|
||||
|
||||
static int nvme_add_ns_cdev(struct nvme_ns *ns)
|
||||
static void nvme_add_ns_cdev(struct nvme_ns *ns)
|
||||
{
|
||||
int ret;
|
||||
char name[32];
|
||||
|
||||
ns->cdev_device.parent = ns->ctrl->device;
|
||||
ret = dev_set_name(&ns->cdev_device, "ng%dn%d",
|
||||
ns->ctrl->instance, ns->head->instance);
|
||||
if (ret)
|
||||
return ret;
|
||||
snprintf(name, sizeof(name), "ng%dn%d", ns->ctrl->instance,
|
||||
ns->head->instance);
|
||||
|
||||
return nvme_cdev_add(&ns->cdev, &ns->cdev_device, &nvme_ns_chr_fops,
|
||||
ns->ctrl->ops->module);
|
||||
if (nvme_cdev_add(name, &ns->cdev, &ns->cdev_device,
|
||||
&nvme_ns_chr_fops, ns->ctrl->ops->module)) {
|
||||
dev_err(ns->ctrl->device, "Unable to create the %s device\n",
|
||||
name);
|
||||
return;
|
||||
}
|
||||
set_bit(NVME_NS_CDEV_LIVE, &ns->flags);
|
||||
}
|
||||
|
||||
static struct nvme_ns_head *nvme_alloc_ns_head(struct nvme_ctrl *ctrl,
|
||||
@@ -4324,8 +4337,10 @@ static void nvme_ns_remove(struct nvme_ns *ns)
|
||||
/* guarantee not available in head->list */
|
||||
synchronize_srcu(&ns->head->srcu);
|
||||
|
||||
if (!nvme_ns_head_multipath(ns->head))
|
||||
nvme_cdev_del(&ns->cdev, &ns->cdev_device);
|
||||
if (!nvme_ns_head_multipath(ns->head)) {
|
||||
if (test_and_clear_bit(NVME_NS_CDEV_LIVE, &ns->flags))
|
||||
nvme_cdev_del(&ns->cdev, &ns->cdev_device);
|
||||
}
|
||||
|
||||
nvme_mpath_remove_sysfs_link(ns);
|
||||
|
||||
|
||||
@@ -2461,7 +2461,7 @@ __nvme_fc_abort_outstanding_ios(struct nvme_fc_ctrl *ctrl, bool start_queues)
|
||||
* io requests back to the block layer as part of normal completions
|
||||
* (but with error status).
|
||||
*/
|
||||
if (ctrl->ctrl.queue_count > 1) {
|
||||
if (ctrl->ctrl.queue_count > 1 && ctrl->ctrl.tagset) {
|
||||
nvme_quiesce_io_queues(&ctrl->ctrl);
|
||||
nvme_sync_io_queues(&ctrl->ctrl);
|
||||
blk_mq_tagset_busy_iter(&ctrl->tag_set,
|
||||
@@ -2900,6 +2900,11 @@ nvme_fc_create_io_queues(struct nvme_fc_ctrl *ctrl)
|
||||
out_delete_hw_queues:
|
||||
nvme_fc_delete_hw_io_queues(ctrl);
|
||||
out_cleanup_tagset:
|
||||
/*
|
||||
* In CONNECTING state ctrl->ioerr_work will abort both admin
|
||||
* and io tagsets. Cancel it first before removing io tagset.
|
||||
*/
|
||||
cancel_work_sync(&ctrl->ioerr_work);
|
||||
nvme_remove_io_tag_set(&ctrl->ctrl);
|
||||
nvme_fc_free_io_queues(ctrl);
|
||||
|
||||
|
||||
@@ -639,18 +639,21 @@ static const struct file_operations nvme_ns_head_chr_fops = {
|
||||
.uring_cmd_iopoll = nvme_ns_chr_uring_cmd_iopoll,
|
||||
};
|
||||
|
||||
static int nvme_add_ns_head_cdev(struct nvme_ns_head *head)
|
||||
static void nvme_add_ns_head_cdev(struct nvme_ns_head *head)
|
||||
{
|
||||
int ret;
|
||||
char name[32];
|
||||
|
||||
head->cdev_device.parent = &head->subsys->dev;
|
||||
ret = dev_set_name(&head->cdev_device, "ng%dn%d",
|
||||
head->subsys->instance, head->instance);
|
||||
if (ret)
|
||||
return ret;
|
||||
ret = nvme_cdev_add(&head->cdev, &head->cdev_device,
|
||||
&nvme_ns_head_chr_fops, THIS_MODULE);
|
||||
return ret;
|
||||
snprintf(name, sizeof(name), "ng%dn%d", head->subsys->instance,
|
||||
head->instance);
|
||||
|
||||
if (nvme_cdev_add(name, &head->cdev, &head->cdev_device,
|
||||
&nvme_ns_head_chr_fops, THIS_MODULE)) {
|
||||
dev_err(disk_to_dev(head->disk),
|
||||
"Unable to create the %s device\n", name);
|
||||
return;
|
||||
}
|
||||
set_bit(NVME_NSHEAD_CDEV_LIVE, &head->flags);
|
||||
}
|
||||
|
||||
static void nvme_partition_scan_work(struct work_struct *work)
|
||||
@@ -694,7 +697,8 @@ static void nvme_remove_head(struct nvme_ns_head *head)
|
||||
*/
|
||||
kblockd_schedule_work(&head->requeue_work);
|
||||
|
||||
nvme_cdev_del(&head->cdev, &head->cdev_device);
|
||||
if (test_and_clear_bit(NVME_NSHEAD_CDEV_LIVE, &head->flags))
|
||||
nvme_cdev_del(&head->cdev, &head->cdev_device);
|
||||
synchronize_srcu(&head->srcu);
|
||||
del_gendisk(head->disk);
|
||||
}
|
||||
|
||||
@@ -573,6 +573,7 @@ struct nvme_ns_head {
|
||||
atomic_long_t io_fail_no_available_path_count;
|
||||
#define NVME_NSHEAD_DISK_LIVE 0
|
||||
#define NVME_NSHEAD_QUEUE_IF_NO_PATH 1
|
||||
#define NVME_NSHEAD_CDEV_LIVE 2
|
||||
struct nvme_ns __rcu *current_path[];
|
||||
#endif
|
||||
};
|
||||
@@ -611,6 +612,7 @@ struct nvme_ns {
|
||||
#define NVME_NS_FORCE_RO 3
|
||||
#define NVME_NS_READY 4
|
||||
#define NVME_NS_SYSFS_ATTR_LINK 5
|
||||
#define NVME_NS_CDEV_LIVE 6
|
||||
|
||||
struct cdev cdev;
|
||||
struct device cdev_device;
|
||||
@@ -995,7 +997,8 @@ int nvme_get_log(struct nvme_ctrl *ctrl, u32 nsid, u8 log_page, u8 lsp, u8 csi,
|
||||
void *log, size_t size, u64 offset);
|
||||
bool nvme_tryget_ns_head(struct nvme_ns_head *head);
|
||||
void nvme_put_ns_head(struct nvme_ns_head *head);
|
||||
int nvme_cdev_add(struct cdev *cdev, struct device *cdev_device,
|
||||
int nvme_cdev_add(const char *name, struct cdev *cdev,
|
||||
struct device *cdev_device,
|
||||
const struct file_operations *fops, struct module *owner);
|
||||
void nvme_cdev_del(struct cdev *cdev, struct device *cdev_device);
|
||||
int nvme_ioctl(struct block_device *bdev, blk_mode_t mode,
|
||||
|
||||
@@ -394,7 +394,7 @@ static ssize_t nvme_io_errors_store(struct device *dev,
|
||||
return count;
|
||||
}
|
||||
|
||||
struct device_attribute dev_attr_io_errors =
|
||||
static struct device_attribute dev_attr_io_errors =
|
||||
__ATTR(command_error_count, 0644,
|
||||
nvme_io_errors_show, nvme_io_errors_store);
|
||||
|
||||
@@ -441,7 +441,7 @@ static umode_t nvme_ns_diag_attrs_are_visible(struct kobject *kobj,
|
||||
return a->mode;
|
||||
}
|
||||
|
||||
const struct attribute_group nvme_ns_diag_attr_group = {
|
||||
static const struct attribute_group nvme_ns_diag_attr_group = {
|
||||
.name = "diag",
|
||||
.attrs = nvme_ns_diag_attrs,
|
||||
.is_visible = nvme_ns_diag_attrs_are_visible,
|
||||
@@ -1147,7 +1147,7 @@ static ssize_t nvme_adm_errors_store(struct device *dev,
|
||||
return count;
|
||||
}
|
||||
|
||||
struct device_attribute dev_attr_adm_errors =
|
||||
static struct device_attribute dev_attr_adm_errors =
|
||||
__ATTR(command_error_count, 0644,
|
||||
nvme_adm_errors_show, nvme_adm_errors_store);
|
||||
|
||||
|
||||
@@ -2007,7 +2007,6 @@ static void nvmet_port_release(struct config_item *item)
|
||||
list_del(&port->global_entry);
|
||||
|
||||
key_put(port->keyring);
|
||||
kfree(port->ana_state);
|
||||
kfree(port);
|
||||
}
|
||||
|
||||
@@ -2047,16 +2046,10 @@ static struct config_group *nvmet_ports_make(struct config_group *group,
|
||||
if (kstrtou16(name, 0, &portid))
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
port = kzalloc_obj(*port);
|
||||
port = kzalloc_flex(*port, ana_state, NVMET_MAX_ANAGRPS + 1);
|
||||
if (!port)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
port->ana_state = kzalloc_objs(*port->ana_state, NVMET_MAX_ANAGRPS + 1);
|
||||
if (!port->ana_state) {
|
||||
kfree(port);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
if (IS_ENABLED(CONFIG_NVME_TARGET_TCP_TLS) && nvme_keyring_id()) {
|
||||
port->keyring = key_lookup(nvme_keyring_id());
|
||||
if (IS_ERR(port->keyring)) {
|
||||
|
||||
@@ -944,7 +944,7 @@ u16 nvmet_sq_create(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq,
|
||||
|
||||
status = nvmet_check_sqid(ctrl, sqid, true);
|
||||
if (status != NVME_SC_SUCCESS)
|
||||
return status;
|
||||
goto ctrl_put;
|
||||
|
||||
ret = nvmet_sq_init(sq, cq);
|
||||
if (ret) {
|
||||
|
||||
@@ -493,7 +493,31 @@ static void nvmet_auth_failure1(struct nvmet_req *req, void *d, int al)
|
||||
|
||||
u32 nvmet_auth_receive_data_len(struct nvmet_req *req)
|
||||
{
|
||||
return le32_to_cpu(req->cmd->auth_receive.al);
|
||||
struct nvmet_ctrl *ctrl = req->sq->ctrl;
|
||||
u32 al = le32_to_cpu(req->cmd->auth_receive.al);
|
||||
u32 min_len;
|
||||
|
||||
/*
|
||||
* Reject too-short al before kmalloc(al), since the SUCCESS1 and
|
||||
* FAILURE1/default builders write fixed response headers into it.
|
||||
*/
|
||||
switch (req->sq->dhchap_step) {
|
||||
case NVME_AUTH_DHCHAP_MESSAGE_CHALLENGE:
|
||||
return al;
|
||||
case NVME_AUTH_DHCHAP_MESSAGE_SUCCESS1:
|
||||
min_len = sizeof(struct nvmf_auth_dhchap_success1_data);
|
||||
if (req->sq->dhchap_c2)
|
||||
min_len += nvme_auth_hmac_hash_len(ctrl->shash_id);
|
||||
break;
|
||||
default:
|
||||
min_len = sizeof(struct nvmf_auth_dhchap_failure_data);
|
||||
break;
|
||||
}
|
||||
|
||||
if (al < min_len)
|
||||
return 0;
|
||||
|
||||
return al;
|
||||
}
|
||||
|
||||
void nvmet_execute_auth_receive(struct nvmet_req *req)
|
||||
|
||||
@@ -208,7 +208,6 @@ struct nvmet_port {
|
||||
struct list_head global_entry;
|
||||
struct config_group ana_groups_group;
|
||||
struct nvmet_ana_group ana_default_group;
|
||||
enum nvme_ana_state *ana_state;
|
||||
struct key *keyring;
|
||||
void *priv;
|
||||
bool enabled;
|
||||
@@ -217,6 +216,7 @@ struct nvmet_port {
|
||||
int mdts;
|
||||
const struct nvmet_fabrics_ops *tr_ops;
|
||||
bool pi_enable;
|
||||
enum nvme_ana_state ana_state[];
|
||||
};
|
||||
|
||||
static inline struct nvmet_port *to_nvmet_port(struct config_item *item)
|
||||
|
||||
@@ -666,7 +666,8 @@ static void nvmet_rdma_release_rsp(struct nvmet_rdma_rsp *rsp)
|
||||
if (rsp->n_rdma)
|
||||
nvmet_rdma_rw_ctx_destroy(rsp);
|
||||
|
||||
if (rsp->req.sg != rsp->cmd->inline_sg)
|
||||
if (rsp->req.sg < rsp->cmd->inline_sg ||
|
||||
rsp->req.sg >= rsp->cmd->inline_sg + queue->dev->inline_page_count)
|
||||
nvmet_req_free_sgls(&rsp->req);
|
||||
|
||||
if (unlikely(!list_empty_careful(&queue->rsp_wr_wait_list)))
|
||||
@@ -821,24 +822,25 @@ static void nvmet_rdma_write_data_done(struct ib_cq *cq, struct ib_wc *wc)
|
||||
static void nvmet_rdma_use_inline_sg(struct nvmet_rdma_rsp *rsp, u32 len,
|
||||
u64 off)
|
||||
{
|
||||
int sg_count = num_pages(len);
|
||||
u64 page_off = off % PAGE_SIZE;
|
||||
u64 page_idx = off / PAGE_SIZE;
|
||||
int sg_count = num_pages(page_off + len);
|
||||
struct scatterlist *sg;
|
||||
int i;
|
||||
|
||||
sg = rsp->cmd->inline_sg;
|
||||
sg = &rsp->cmd->inline_sg[page_idx];
|
||||
for (i = 0; i < sg_count; i++, sg++) {
|
||||
if (i < sg_count - 1)
|
||||
sg_unmark_end(sg);
|
||||
else
|
||||
sg_mark_end(sg);
|
||||
sg->offset = off;
|
||||
sg->length = min_t(int, len, PAGE_SIZE - off);
|
||||
sg->offset = page_off;
|
||||
sg->length = min_t(u64, len, PAGE_SIZE - page_off);
|
||||
len -= sg->length;
|
||||
if (!i)
|
||||
off = 0;
|
||||
page_off = 0;
|
||||
}
|
||||
|
||||
rsp->req.sg = rsp->cmd->inline_sg;
|
||||
rsp->req.sg = &rsp->cmd->inline_sg[page_idx];
|
||||
rsp->req.sg_cnt = sg_count;
|
||||
}
|
||||
|
||||
|
||||
@@ -1680,6 +1680,7 @@ static void nvmet_tcp_state_change(struct sock *sk)
|
||||
switch (sk->sk_state) {
|
||||
case TCP_FIN_WAIT2:
|
||||
case TCP_LAST_ACK:
|
||||
case TCP_CLOSING:
|
||||
break;
|
||||
case TCP_FIN_WAIT1:
|
||||
case TCP_CLOSE_WAIT:
|
||||
|
||||
@@ -141,7 +141,7 @@ static inline int bio_integrity_add_page(struct bio *bio, struct page *page,
|
||||
}
|
||||
#endif /* CONFIG_BLK_DEV_INTEGRITY */
|
||||
|
||||
void bio_integrity_alloc_buf(struct bio *bio, bool zero_buffer);
|
||||
void bio_integrity_alloc_buf(struct bio *bio, gfp_t gfp, bool zero_buffer);
|
||||
void bio_integrity_free_buf(struct bio_integrity_payload *bip);
|
||||
void bio_integrity_setup_default(struct bio *bio);
|
||||
|
||||
|
||||
@@ -1222,16 +1222,12 @@ static inline void blk_flush_plug(struct blk_plug *plug, bool async)
|
||||
__blk_flush_plug(plug, async);
|
||||
}
|
||||
|
||||
/*
|
||||
* tsk == current here
|
||||
*/
|
||||
static inline void blk_plug_invalidate_ts(struct task_struct *tsk)
|
||||
static __always_inline void blk_plug_invalidate_ts(void)
|
||||
{
|
||||
struct blk_plug *plug = tsk->plug;
|
||||
|
||||
if (plug)
|
||||
plug->cur_ktime = 0;
|
||||
current->flags &= ~PF_BLOCK_TS;
|
||||
if (unlikely(current->flags & PF_BLOCK_TS)) {
|
||||
current->plug->cur_ktime = 0;
|
||||
current->flags &= ~PF_BLOCK_TS;
|
||||
}
|
||||
}
|
||||
|
||||
int blkdev_issue_flush(struct block_device *bdev);
|
||||
@@ -1257,7 +1253,7 @@ static inline void blk_flush_plug(struct blk_plug *plug, bool async)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void blk_plug_invalidate_ts(struct task_struct *tsk)
|
||||
static inline void blk_plug_invalidate_ts(void)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -2338,6 +2338,7 @@ __latent_entropy struct task_struct *copy_process(
|
||||
|
||||
#ifdef CONFIG_BLOCK
|
||||
p->plug = NULL;
|
||||
p->flags &= ~PF_BLOCK_TS;
|
||||
#endif
|
||||
futex_init_task(p);
|
||||
|
||||
|
||||
@@ -5368,6 +5368,12 @@ static struct rq *finish_task_switch(struct task_struct *prev)
|
||||
*/
|
||||
kmap_local_sched_in();
|
||||
|
||||
/*
|
||||
* Any cached block-layer timestamp (plug->cur_ktime) is stale now,
|
||||
* invalidate it.
|
||||
*/
|
||||
blk_plug_invalidate_ts();
|
||||
|
||||
fire_sched_in_preempt_notifiers(current);
|
||||
/*
|
||||
* When switching through a kernel thread, the loop in
|
||||
@@ -7290,12 +7296,10 @@ static inline void sched_submit_work(struct task_struct *tsk)
|
||||
|
||||
static void sched_update_worker(struct task_struct *tsk)
|
||||
{
|
||||
if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER | PF_BLOCK_TS)) {
|
||||
if (tsk->flags & PF_BLOCK_TS)
|
||||
blk_plug_invalidate_ts(tsk);
|
||||
if (tsk->flags & (PF_WQ_WORKER | PF_IO_WORKER)) {
|
||||
if (tsk->flags & PF_WQ_WORKER)
|
||||
wq_worker_running(tsk);
|
||||
else if (tsk->flags & PF_IO_WORKER)
|
||||
else
|
||||
io_wq_worker_running(tsk);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -327,8 +327,13 @@ static void bio_associate_blkg_from_page(struct bio *bio, struct folio *folio)
|
||||
rcu_read_lock();
|
||||
memcg = folio_memcg(folio);
|
||||
css = cgroup_e_css(memcg->css.cgroup, &io_cgrp_subsys);
|
||||
bio_associate_blkg_from_css(bio, css);
|
||||
if (!css || !css_tryget(css))
|
||||
css = NULL;
|
||||
rcu_read_unlock();
|
||||
|
||||
bio_associate_blkg_from_css(bio, css);
|
||||
if (css)
|
||||
css_put(css);
|
||||
}
|
||||
#else
|
||||
#define bio_associate_blkg_from_page(bio, folio) do { } while (0)
|
||||
|
||||
Reference in New Issue
Block a user