diff --git a/block/bfq-cgroup.c b/block/bfq-cgroup.c index 0bd0332b3d78..e82ff03bda02 100644 --- a/block/bfq-cgroup.c +++ b/block/bfq-cgroup.c @@ -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) diff --git a/block/bfq-iosched.c b/block/bfq-iosched.c index 141c602d5e85..0f75301b3115 100644 --- a/block/bfq-iosched.c +++ b/block/bfq-iosched.c @@ -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); diff --git a/block/bio-integrity-auto.c b/block/bio-integrity-auto.c index 353eed632fcc..b1c733ecfd2e 100644 --- a/block/bio-integrity-auto.c +++ b/block/bio-integrity-auto.c @@ -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); diff --git a/block/bio-integrity-fs.c b/block/bio-integrity-fs.c index 0daa42d9ead7..9c5fe5fa8f0d 100644 --- a/block/bio-integrity-fs.c +++ b/block/bio-integrity-fs.c @@ -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; diff --git a/block/bio-integrity.c b/block/bio-integrity.c index e796de1a749e..b23e2434d80c 100644 --- a/block/bio-integrity.c +++ b/block/bio-integrity.c @@ -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); diff --git a/block/bio.c b/block/bio.c index 811a96796202..f2a5f4d0a967 100644 --- a/block/bio.c +++ b/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); diff --git a/block/blk-cgroup-rwstat.c b/block/blk-cgroup-rwstat.c index a55fb0c53558..aae910713814 100644 --- a/block/blk-cgroup-rwstat.c +++ b/block/blk-cgroup-rwstat.c @@ -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); diff --git a/block/blk-cgroup.c b/block/blk-cgroup.c index 3093c1c03902..d2a1f5903f24 100644 --- a/block/blk-cgroup.c +++ b/block/blk-cgroup.c @@ -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); diff --git a/block/blk-cgroup.h b/block/blk-cgroup.h index f25fecb87c43..615390f751aa 100644 --- a/block/blk-cgroup.h +++ b/block/blk-cgroup.h @@ -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) { } diff --git a/block/blk-core.c b/block/blk-core.c index 73a41df98c9a..365641266c9e 100644 --- a/block/blk-core.c +++ b/block/blk-core.c @@ -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); } /* diff --git a/block/blk-iocost.c b/block/blk-iocost.c index 563cc7dcf348..8b2aeba2e1e3 100644 --- a/block/blk-iocost.c +++ b/block/blk-iocost.c @@ -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; } diff --git a/block/blk-iolatency.c b/block/blk-iolatency.c index 1aaee6fb0f59..cef02b6c5fa9 100644 --- a/block/blk-iolatency.c +++ b/block/blk-iolatency.c @@ -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", diff --git a/block/blk-throttle.c b/block/blk-throttle.c index 47052ba21d1b..ffc3b70065d4 100644 --- a/block/blk-throttle.c +++ b/block/blk-throttle.c @@ -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 * diff --git a/block/error-injection.c b/block/error-injection.c index d24c90e9a25f..cfb83138960c 100644 --- a/block/error-injection.c +++ b/block/error-injection.c @@ -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); } diff --git a/block/ioctl.c b/block/ioctl.c index ab2c9ed79946..3d4ea1537457 100644 --- a/block/ioctl.c +++ b/block/ioctl.c @@ -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 || diff --git a/drivers/block/nbd.c b/drivers/block/nbd.c index 3a585a0c882a..8f10762e90ef 100644 --- a/drivers/block/nbd.c +++ b/drivers/block/nbd.c @@ -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) { diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c index 7d778fe1c47c..0f02e2956398 100644 --- a/drivers/md/md-bitmap.c +++ b/drivers/md/md-bitmap.c @@ -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); diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h index 214f623c7e79..f46674bdfeb9 100644 --- a/drivers/md/md-bitmap.h +++ b/drivers/md/md-bitmap.h @@ -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; diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c index 1adc5b117821..5a4e2abaa757 100644 --- a/drivers/md/md-llbitmap.c +++ b/drivers/md/md-llbitmap.c @@ -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) diff --git a/drivers/md/md.c b/drivers/md/md.c index 096bb64e87bd..d1465bcd86c8 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c @@ -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); diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c index 5b9368bd9e70..afe2ca96ad8c 100644 --- a/drivers/md/raid1.c +++ b/drivers/md/raid1.c @@ -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; } diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index cee5a253a281..0a3cfdd3f5df 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -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); diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index d0d7f96fd7cd..ffb5fcde54a9 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c @@ -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; diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h index 1dfa60a41d91..cb5feae04db2 100644 --- a/drivers/md/raid5.h +++ b/drivers/md/raid5.h @@ -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; diff --git a/drivers/nvme/host/apple.c b/drivers/nvme/host/apple.c index f9327feb87d0..be3b91b43ea5 100644 --- a/drivers/nvme/host/apple.c +++ b/drivers/nvme/host/apple.c @@ -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; diff --git a/drivers/nvme/host/core.c b/drivers/nvme/host/core.c index 3b7a8f7a3542..453c1f0b2dd0 100644 --- a/drivers/nvme/host/core.c +++ b/drivers/nvme/host/core.c @@ -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); diff --git a/drivers/nvme/host/fc.c b/drivers/nvme/host/fc.c index 2c9a6d3c9797..04363b9c4489 100644 --- a/drivers/nvme/host/fc.c +++ b/drivers/nvme/host/fc.c @@ -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); diff --git a/drivers/nvme/host/multipath.c b/drivers/nvme/host/multipath.c index e033ede953cc..9b9a657fa330 100644 --- a/drivers/nvme/host/multipath.c +++ b/drivers/nvme/host/multipath.c @@ -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); } diff --git a/drivers/nvme/host/nvme.h b/drivers/nvme/host/nvme.h index b367c67dcb37..824651cc898d 100644 --- a/drivers/nvme/host/nvme.h +++ b/drivers/nvme/host/nvme.h @@ -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, diff --git a/drivers/nvme/host/sysfs.c b/drivers/nvme/host/sysfs.c index 933a5adfb7af..75b2d69b5957 100644 --- a/drivers/nvme/host/sysfs.c +++ b/drivers/nvme/host/sysfs.c @@ -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); diff --git a/drivers/nvme/target/configfs.c b/drivers/nvme/target/configfs.c index b88f897f06e2..2b69ffcfc8df 100644 --- a/drivers/nvme/target/configfs.c +++ b/drivers/nvme/target/configfs.c @@ -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)) { diff --git a/drivers/nvme/target/core.c b/drivers/nvme/target/core.c index 62dd59b9aa4f..4477c4d6b1ee 100644 --- a/drivers/nvme/target/core.c +++ b/drivers/nvme/target/core.c @@ -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) { diff --git a/drivers/nvme/target/fabrics-cmd-auth.c b/drivers/nvme/target/fabrics-cmd-auth.c index 0a85acf1e5c7..45820a12750d 100644 --- a/drivers/nvme/target/fabrics-cmd-auth.c +++ b/drivers/nvme/target/fabrics-cmd-auth.c @@ -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) diff --git a/drivers/nvme/target/nvmet.h b/drivers/nvme/target/nvmet.h index 3305a88684ec..aaba745e3c21 100644 --- a/drivers/nvme/target/nvmet.h +++ b/drivers/nvme/target/nvmet.h @@ -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) diff --git a/drivers/nvme/target/rdma.c b/drivers/nvme/target/rdma.c index ac26f4f774c4..ea1185b8267e 100644 --- a/drivers/nvme/target/rdma.c +++ b/drivers/nvme/target/rdma.c @@ -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; } diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index 15c52f1f95f1..75a276d73be3 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -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: diff --git a/include/linux/bio-integrity.h b/include/linux/bio-integrity.h index af5178434ec6..c3dda32fd803 100644 --- a/include/linux/bio-integrity.h +++ b/include/linux/bio-integrity.h @@ -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); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 5070851cf924..9213a5716f95 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -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) { } diff --git a/kernel/fork.c b/kernel/fork.c index 892a95214c54..13e38e89a1f3 100644 --- a/kernel/fork.c +++ b/kernel/fork.c @@ -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); diff --git a/kernel/sched/core.c b/kernel/sched/core.c index 3cc6fb1d2054..96226707c2f6 100644 --- a/kernel/sched/core.c +++ b/kernel/sched/core.c @@ -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); } } diff --git a/mm/page_io.c b/mm/page_io.c index 60977c970cdf..b23f494fcc83 100644 --- a/mm/page_io.c +++ b/mm/page_io.c @@ -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)