Add a function to find the max alignment of an atomic write for a bdev when provided with an offset and length. We should be able to optimise this function later, most especially since the values involved are powers-of-2. Signed-off-by: John Garry <john.g.garry@xxxxxxxxxx> --- block/bdev.c | 39 +++++++++++++++++++++++++++++++++++++++ include/linux/blkdev.h | 9 +++++++++ 2 files changed, 48 insertions(+) diff --git a/block/bdev.c b/block/bdev.c index 6a5fd5abaadc..3373f0d5cad9 100644 --- a/block/bdev.c +++ b/block/bdev.c @@ -46,6 +46,45 @@ struct block_device *I_BDEV(struct inode *inode) } EXPORT_SYMBOL(I_BDEV); +unsigned int bdev_find_max_atomic_write_alignment(struct block_device *bdev, + loff_t pos, unsigned int len) +{ + struct request_queue *bd_queue = bdev->bd_queue; + struct queue_limits *limits = &bd_queue->limits; + unsigned int atomic_write_unit_min = limits->atomic_write_unit_min; + unsigned int atomic_write_unit_max = limits->atomic_write_unit_max; + unsigned int max_align; + + pos /= SECTOR_SIZE; + len /= SECTOR_SIZE; + + max_align = min_not_zero(len, atomic_write_unit_max); + + if (len <= 1) + return atomic_write_unit_min * SECTOR_SIZE; + + max_align = rounddown_pow_of_two(max_align); + while (1) { + unsigned int mod1, mod2; + + if (max_align == 0) + return atomic_write_unit_min * SECTOR_SIZE; + + /* This should not happen */ + if (!is_power_of_2(max_align)) + goto end; + + mod1 = len % max_align; + mod2 = pos % max_align; + if (!mod1 && !mod2) + break; +end: + max_align /= 2; + } + + return max_align * SECTOR_SIZE; +} + static void bdev_write_inode(struct block_device *bdev) { struct inode *inode = bdev->bd_inode; diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 19d33b2897b2..96138550928c 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -1529,6 +1529,8 @@ void sync_bdevs(bool wait); void bdev_statx_dioalign(struct inode *inode, struct kstat *stat); void bdev_statx_atomic(struct inode *inode, struct kstat *stat); void printk_all_partitions(void); +unsigned int bdev_find_max_atomic_write_alignment(struct block_device *bdev, + loff_t pos, unsigned int len); #else static inline void invalidate_bdev(struct block_device *bdev) { @@ -1553,6 +1555,13 @@ static inline void bdev_statx_atomic(struct inode *inode, struct kstat *stat) static inline void printk_all_partitions(void) { } +static inline unsigned int bdev_find_max_atomic_write_alignment( + struct block_device *bdev, + loff_t pos, unsigned int len) +{ + return 0; +} + #endif /* CONFIG_BLOCK */ int fsync_bdev(struct block_device *bdev); -- 2.31.1