mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-05 18:41:58 +09:00
ANDROID: block: Support configuring limits below the page size
Allow block drivers to configure the following: * Maximum number of hardware sectors values smaller than PAGE_SIZE >> SECTOR_SHIFT. For PAGE_SIZE = 4096 this means that values below 8 become supported. * A maximum segment size below the page size. This is most useful for page sizes above 4096 bytes. The blk_sub_page_segments static branch will be used in later patches to prevent that performance of block drivers that support segments >= PAGE_SIZE and max_hw_sectors >= PAGE_SIZE >> SECTOR_SHIFT would be affected. This patch may change the behavior of existing block drivers from not working into working. If a block driver calls blk_queue_max_hw_sectors() or blk_queue_max_segment_size(), this is usually done to configure the maximum supported limits. An attempt to configure a limit below what is supported by the block layer causes the block layer to select a larger value. If that value is not supported by the block driver, this may cause other data to be transferred than requested, a kernel crash or other undesirable behavior. Keeps the ABI stable by taking advantage of a hole in the structure! Bug: 308663717 Bug: 319125789 Bug: 324152549 Change-Id: I4a7b605f0f0d82dde0b4703496c7314064f48acb Signed-off-by: Bart Van Assche <bvanassche@acm.org> [jyescas@google.com: disable subpage limits in block/blk-sysfs.c instead block/blk-core.c because the function blk_free_queue() is not defined in 5.15 kernel] Signed-off-by: Juan Yescas <jyescas@google.com>
This commit is contained in:
committed by
Juan Yescas
parent
025c278e84
commit
3f6018f1b6
@@ -168781,6 +168781,12 @@ member {
|
||||
type_id: 0xa7c362b0
|
||||
offset: 1088
|
||||
}
|
||||
member {
|
||||
id: 0x4c1b044f
|
||||
name: "sub_page_limits"
|
||||
type_id: 0x6d7f5ff6
|
||||
offset: 840
|
||||
}
|
||||
member {
|
||||
id: 0xedd64f59
|
||||
name: "sub_reg_offsets"
|
||||
@@ -227137,6 +227143,7 @@ struct_union {
|
||||
member_id: 0x06473753
|
||||
member_id: 0x1bdd5453
|
||||
member_id: 0x26582f94
|
||||
member_id: 0x4c1b044f
|
||||
member_id: 0xaf3e33dd
|
||||
member_id: 0x2d081f94
|
||||
member_id: 0xd671ce1e
|
||||
|
||||
@@ -21,6 +21,11 @@
|
||||
#include "blk.h"
|
||||
#include "blk-wbt.h"
|
||||
|
||||
/* Protects blk_nr_sub_page_limit_queues and blk_sub_page_limits changes. */
|
||||
static DEFINE_MUTEX(blk_sub_page_limit_lock);
|
||||
static uint32_t blk_nr_sub_page_limit_queues;
|
||||
DEFINE_STATIC_KEY_FALSE(blk_sub_page_limits);
|
||||
|
||||
void blk_queue_rq_timeout(struct request_queue *q, unsigned int timeout)
|
||||
{
|
||||
q->rq_timeout = timeout;
|
||||
@@ -60,6 +65,7 @@ void blk_set_default_limits(struct queue_limits *lim)
|
||||
lim->misaligned = 0;
|
||||
lim->zoned = BLK_ZONED_NONE;
|
||||
lim->zone_write_granularity = 0;
|
||||
lim->sub_page_limits = false;
|
||||
}
|
||||
EXPORT_SYMBOL(blk_set_default_limits);
|
||||
|
||||
@@ -104,6 +110,50 @@ void blk_queue_bounce_limit(struct request_queue *q, enum blk_bounce bounce)
|
||||
}
|
||||
EXPORT_SYMBOL(blk_queue_bounce_limit);
|
||||
|
||||
/**
|
||||
* blk_enable_sub_page_limits - enable support for limits below the page size
|
||||
* @lim: request queue limits for which to enable support of these features.
|
||||
*
|
||||
* Enable support for max_segment_size values smaller than PAGE_SIZE and for
|
||||
* max_hw_sectors values below PAGE_SIZE >> SECTOR_SHIFT. Support for these
|
||||
* features is not enabled all the time because of the runtime overhead of these
|
||||
* features.
|
||||
*/
|
||||
static void blk_enable_sub_page_limits(struct queue_limits *lim)
|
||||
{
|
||||
if (lim->sub_page_limits)
|
||||
return;
|
||||
|
||||
lim->sub_page_limits = true;
|
||||
|
||||
mutex_lock(&blk_sub_page_limit_lock);
|
||||
if (++blk_nr_sub_page_limit_queues == 1)
|
||||
static_branch_enable(&blk_sub_page_limits);
|
||||
mutex_unlock(&blk_sub_page_limit_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* blk_disable_sub_page_limits - disable support for limits below the page size
|
||||
* @lim: request queue limits for which to enable support of these features.
|
||||
*
|
||||
* max_segment_size values smaller than PAGE_SIZE and for max_hw_sectors values
|
||||
* below PAGE_SIZE >> SECTOR_SHIFT. Support for these features is not enabled
|
||||
* all the time because of the runtime overhead of these features.
|
||||
*/
|
||||
void blk_disable_sub_page_limits(struct queue_limits *lim)
|
||||
{
|
||||
if (!lim->sub_page_limits)
|
||||
return;
|
||||
|
||||
lim->sub_page_limits = false;
|
||||
|
||||
mutex_lock(&blk_sub_page_limit_lock);
|
||||
WARN_ON_ONCE(blk_nr_sub_page_limit_queues <= 0);
|
||||
if (--blk_nr_sub_page_limit_queues == 0)
|
||||
static_branch_disable(&blk_sub_page_limits);
|
||||
mutex_unlock(&blk_sub_page_limit_lock);
|
||||
}
|
||||
|
||||
/**
|
||||
* blk_queue_max_hw_sectors - set max sectors for a request for this queue
|
||||
* @q: the request queue for the device
|
||||
@@ -129,6 +179,11 @@ void blk_queue_max_hw_sectors(struct request_queue *q, unsigned int max_hw_secto
|
||||
unsigned int min_max_hw_sectors = PAGE_SIZE >> SECTOR_SHIFT;
|
||||
unsigned int max_sectors;
|
||||
|
||||
if (max_hw_sectors < min_max_hw_sectors) {
|
||||
blk_enable_sub_page_limits(limits);
|
||||
min_max_hw_sectors = 1;
|
||||
}
|
||||
|
||||
if (max_hw_sectors < min_max_hw_sectors) {
|
||||
max_hw_sectors = min_max_hw_sectors;
|
||||
pr_info("set to minimum %u\n", max_hw_sectors);
|
||||
@@ -282,6 +337,11 @@ void blk_queue_max_segment_size(struct request_queue *q, unsigned int max_size)
|
||||
{
|
||||
unsigned int min_max_segment_size = PAGE_SIZE;
|
||||
|
||||
if (max_size < min_max_segment_size) {
|
||||
blk_enable_sub_page_limits(&q->limits);
|
||||
min_max_segment_size = SECTOR_SIZE;
|
||||
}
|
||||
|
||||
if (max_size < min_max_segment_size) {
|
||||
max_size = min_max_segment_size;
|
||||
pr_info("set to minimum %u\n", max_size);
|
||||
|
||||
@@ -811,6 +811,8 @@ static void blk_release_queue(struct kobject *kobj)
|
||||
|
||||
blk_queue_free_zone_bitmaps(q);
|
||||
|
||||
blk_disable_sub_page_limits(&q->limits);
|
||||
|
||||
if (queue_is_mq(q))
|
||||
blk_mq_release(q);
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#define BLK_MAX_TIMEOUT (5 * HZ)
|
||||
|
||||
extern struct dentry *blk_debugfs_root;
|
||||
DECLARE_STATIC_KEY_FALSE(blk_sub_page_limits);
|
||||
|
||||
struct internal_request_queue {
|
||||
struct request_queue q;
|
||||
@@ -61,6 +62,14 @@ struct blk_flush_queue *blk_alloc_flush_queue(int node, int cmd_size,
|
||||
gfp_t flags);
|
||||
void blk_free_flush_queue(struct blk_flush_queue *q);
|
||||
|
||||
static inline bool blk_queue_sub_page_limits(const struct queue_limits *lim)
|
||||
{
|
||||
return static_branch_unlikely(&blk_sub_page_limits) &&
|
||||
lim->sub_page_limits;
|
||||
}
|
||||
|
||||
void blk_disable_sub_page_limits(struct queue_limits *q);
|
||||
|
||||
void blk_freeze_queue(struct request_queue *q);
|
||||
void __blk_mq_unfreeze_queue(struct request_queue *q, bool force_atomic);
|
||||
void blk_queue_start_drain(struct request_queue *q);
|
||||
|
||||
@@ -328,6 +328,11 @@ struct queue_limits {
|
||||
unsigned char misaligned;
|
||||
unsigned char discard_misaligned;
|
||||
unsigned char raid_partial_stripes_expensive;
|
||||
|
||||
#ifndef __GENKSYMS__
|
||||
bool sub_page_limits;
|
||||
#endif
|
||||
|
||||
enum blk_zoned_model zoned;
|
||||
|
||||
ANDROID_KABI_RESERVE(1);
|
||||
|
||||
Reference in New Issue
Block a user