Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'for-6.14/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper updates from Mikulas Patocka:

- fix a spelling error in dm-raid

- change kzalloc to kcalloc

- remove useless test in alloc_multiple_bios

- disable REQ_NOWAIT for flushes

- dm-transaction-manager: use red-black trees instead of linear lists

- atomic writes support for dm-linear, dm-stripe and dm-mirror

- dm-crypt: code cleanups and two bugfixes

* tag 'for-6.14/dm-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
dm-crypt: track tag_offset in convert_context
dm-crypt: don't initialize cc_sector again
dm-crypt: don't update io->sector after kcryptd_crypt_write_io_submit()
dm-crypt: use bi_sector in bio when initialize integrity seed
dm-crypt: fully initialize clone->bi_iter in crypt_alloc_buffer()
dm-crypt: set atomic as false when calling crypt_convert() in kworker
dm-mirror: Support atomic writes
dm-io: Warn on creating multiple atomic write bios for a region
dm-stripe: Enable atomic writes
dm-linear: Enable atomic writes
dm: Ensure cloned bio is same length for atomic write
dm-table: atomic writes support
dm-transaction-manager: use red-black trees instead of linear lists
dm: disable REQ_NOWAIT for flushes
dm: remove useless test in alloc_multiple_bios
dm: change kzalloc to kcalloc
dm raid: fix spelling errors in raid_ctr()

+120 -63
+16 -26
drivers/md/dm-crypt.c
··· 59 59 struct bio *bio_out; 60 60 struct bvec_iter iter_out; 61 61 atomic_t cc_pending; 62 + unsigned int tag_offset; 62 63 u64 cc_sector; 63 64 union { 64 65 struct skcipher_request *req; ··· 1188 1187 1189 1188 tag_len = io->cc->tuple_size * (bio_sectors(bio) >> io->cc->sector_shift); 1190 1189 1191 - bip->bip_iter.bi_sector = io->cc->start + io->sector; 1190 + bip->bip_iter.bi_sector = bio->bi_iter.bi_sector; 1192 1191 1193 1192 ret = bio_integrity_add_page(bio, virt_to_page(io->integrity_metadata), 1194 1193 tag_len, offset_in_page(io->integrity_metadata)); ··· 1257 1256 if (bio_out) 1258 1257 ctx->iter_out = bio_out->bi_iter; 1259 1258 ctx->cc_sector = sector + cc->iv_offset; 1259 + ctx->tag_offset = 0; 1260 1260 init_completion(&ctx->restart); 1261 1261 } 1262 1262 ··· 1590 1588 static blk_status_t crypt_convert(struct crypt_config *cc, 1591 1589 struct convert_context *ctx, bool atomic, bool reset_pending) 1592 1590 { 1593 - unsigned int tag_offset = 0; 1594 1591 unsigned int sector_step = cc->sector_size >> SECTOR_SHIFT; 1595 1592 int r; 1596 1593 ··· 1612 1611 atomic_inc(&ctx->cc_pending); 1613 1612 1614 1613 if (crypt_integrity_aead(cc)) 1615 - r = crypt_convert_block_aead(cc, ctx, ctx->r.req_aead, tag_offset); 1614 + r = crypt_convert_block_aead(cc, ctx, ctx->r.req_aead, ctx->tag_offset); 1616 1615 else 1617 - r = crypt_convert_block_skcipher(cc, ctx, ctx->r.req, tag_offset); 1616 + r = crypt_convert_block_skcipher(cc, ctx, ctx->r.req, ctx->tag_offset); 1618 1617 1619 1618 switch (r) { 1620 1619 /* ··· 1634 1633 * exit and continue processing in a workqueue 1635 1634 */ 1636 1635 ctx->r.req = NULL; 1636 + ctx->tag_offset++; 1637 1637 ctx->cc_sector += sector_step; 1638 - tag_offset++; 1639 1638 return BLK_STS_DEV_RESOURCE; 1640 1639 } 1641 1640 } else { ··· 1649 1648 */ 1650 1649 case -EINPROGRESS: 1651 1650 ctx->r.req = NULL; 1651 + ctx->tag_offset++; 1652 1652 ctx->cc_sector += sector_step; 1653 - tag_offset++; 1654 1653 continue; 1655 1654 /* 1656 1655 * The request was already processed (synchronously). ··· 1658 1657 case 0: 1659 1658 atomic_dec(&ctx->cc_pending); 1660 1659 ctx->cc_sector += sector_step; 1661 - tag_offset++; 1660 + ctx->tag_offset++; 1662 1661 if (!atomic) 1663 1662 cond_resched(); 1664 1663 continue; ··· 1720 1719 clone->bi_private = io; 1721 1720 clone->bi_end_io = crypt_endio; 1722 1721 clone->bi_ioprio = io->base_bio->bi_ioprio; 1722 + clone->bi_iter.bi_sector = cc->start + io->sector; 1723 1723 1724 1724 remaining_size = size; 1725 1725 ··· 1911 1909 crypt_dec_pending(io); 1912 1910 return 1; 1913 1911 } 1914 - clone->bi_iter.bi_sector = cc->start + io->sector; 1915 1912 crypt_convert_init(cc, &io->ctx, clone, clone, io->sector); 1916 1913 io->saved_bi_iter = clone->bi_iter; 1917 1914 dm_submit_bio_remap(io->base_bio, clone); ··· 1926 1925 clone = bio_alloc_clone(cc->dev->bdev, io->base_bio, gfp, &cc->bs); 1927 1926 if (!clone) 1928 1927 return 1; 1928 + 1929 + clone->bi_iter.bi_sector = cc->start + io->sector; 1929 1930 clone->bi_private = io; 1930 1931 clone->bi_end_io = crypt_endio; 1931 1932 1932 1933 crypt_inc_pending(io); 1933 - 1934 - clone->bi_iter.bi_sector = cc->start + io->sector; 1935 1934 1936 1935 if (dm_crypt_integrity_io_alloc(io, clone)) { 1937 1936 crypt_dec_pending(io); ··· 2040 2039 /* crypt_convert should have filled the clone bio */ 2041 2040 BUG_ON(io->ctx.iter_out.bi_size); 2042 2041 2043 - clone->bi_iter.bi_sector = cc->start + io->sector; 2044 - 2045 2042 if ((likely(!async) && test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags)) || 2046 2043 test_bit(DM_CRYPT_NO_WRITE_WORKQUEUE, &cc->flags)) { 2047 2044 dm_submit_bio_remap(io->base_bio, clone); ··· 2091 2092 struct crypt_config *cc = io->cc; 2092 2093 struct convert_context *ctx = &io->ctx; 2093 2094 int crypt_finished; 2094 - sector_t sector = io->sector; 2095 2095 blk_status_t r; 2096 2096 2097 2097 wait_for_completion(&ctx->restart); 2098 2098 reinit_completion(&ctx->restart); 2099 2099 2100 - r = crypt_convert(cc, &io->ctx, true, false); 2100 + r = crypt_convert(cc, &io->ctx, false, false); 2101 2101 if (r) 2102 2102 io->error = r; 2103 2103 crypt_finished = atomic_dec_and_test(&ctx->cc_pending); ··· 2107 2109 } 2108 2110 2109 2111 /* Encryption was already finished, submit io now */ 2110 - if (crypt_finished) { 2112 + if (crypt_finished) 2111 2113 kcryptd_crypt_write_io_submit(io, 0); 2112 - io->sector = sector; 2113 - } 2114 2114 2115 2115 crypt_dec_pending(io); 2116 2116 } ··· 2119 2123 struct convert_context *ctx = &io->ctx; 2120 2124 struct bio *clone; 2121 2125 int crypt_finished; 2122 - sector_t sector = io->sector; 2123 2126 blk_status_t r; 2124 2127 2125 2128 /* 2126 2129 * Prevent io from disappearing until this function completes. 2127 2130 */ 2128 2131 crypt_inc_pending(io); 2129 - crypt_convert_init(cc, ctx, NULL, io->base_bio, sector); 2132 + crypt_convert_init(cc, ctx, NULL, io->base_bio, io->sector); 2130 2133 2131 2134 clone = crypt_alloc_buffer(io, io->base_bio->bi_iter.bi_size); 2132 2135 if (unlikely(!clone)) { ··· 2141 2146 io->ctx.bio_in = clone; 2142 2147 io->ctx.iter_in = clone->bi_iter; 2143 2148 } 2144 - 2145 - sector += bio_sectors(clone); 2146 2149 2147 2150 crypt_inc_pending(io); 2148 2151 r = crypt_convert(cc, ctx, ··· 2165 2172 } 2166 2173 2167 2174 /* Encryption was already finished, submit io now */ 2168 - if (crypt_finished) { 2175 + if (crypt_finished) 2169 2176 kcryptd_crypt_write_io_submit(io, 0); 2170 - io->sector = sector; 2171 - } 2172 2177 2173 2178 dec: 2174 2179 crypt_dec_pending(io); ··· 2194 2203 wait_for_completion(&io->ctx.restart); 2195 2204 reinit_completion(&io->ctx.restart); 2196 2205 2197 - r = crypt_convert(cc, &io->ctx, true, false); 2206 + r = crypt_convert(cc, &io->ctx, false, false); 2198 2207 if (r) 2199 2208 io->error = r; 2200 2209 ··· 2212 2221 crypt_inc_pending(io); 2213 2222 2214 2223 if (io->ctx.aead_recheck) { 2215 - io->ctx.cc_sector = io->sector + cc->iv_offset; 2216 2224 r = crypt_convert(cc, &io->ctx, 2217 2225 test_bit(DM_CRYPT_NO_READ_WORKQUEUE, &cc->flags), true); 2218 2226 } else {
+1
drivers/md/dm-io.c
··· 379 379 380 380 atomic_inc(&io->count); 381 381 submit_bio(bio); 382 + WARN_ON_ONCE(opf & REQ_ATOMIC && remaining); 382 383 } while (remaining); 383 384 } 384 385
+3 -2
drivers/md/dm-linear.c
··· 199 199 200 200 static struct target_type linear_target = { 201 201 .name = "linear", 202 - .version = {1, 4, 0}, 202 + .version = {1, 5, 0}, 203 203 .features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_NOWAIT | 204 - DM_TARGET_ZONED_HM | DM_TARGET_PASSES_CRYPTO, 204 + DM_TARGET_ZONED_HM | DM_TARGET_PASSES_CRYPTO | 205 + DM_TARGET_ATOMIC_WRITES, 205 206 .report_zones = linear_report_zones, 206 207 .module = THIS_MODULE, 207 208 .ctr = linear_ctr,
+1 -1
drivers/md/dm-ps-io-affinity.c
··· 116 116 if (!s) 117 117 return -ENOMEM; 118 118 119 - s->path_map = kzalloc(nr_cpu_ids * sizeof(struct path_info *), 119 + s->path_map = kcalloc(nr_cpu_ids, sizeof(struct path_info *), 120 120 GFP_KERNEL); 121 121 if (!s->path_map) 122 122 goto free_selector;
+1 -1
drivers/md/dm-raid.c
··· 3196 3196 if (reshape_sectors || rs_is_raid1(rs)) { 3197 3197 /* 3198 3198 * We can only prepare for a reshape here, because the 3199 - * raid set needs to run to provide the repective reshape 3199 + * raid set needs to run to provide the respective reshape 3200 3200 * check functions via its MD personality instance. 3201 3201 * 3202 3202 * So do the reshape check after md_run() succeeded.
+3 -2
drivers/md/dm-raid1.c
··· 656 656 unsigned int i; 657 657 struct dm_io_region io[MAX_NR_MIRRORS], *dest = io; 658 658 struct mirror *m; 659 - blk_opf_t op_flags = bio->bi_opf & (REQ_FUA | REQ_PREFLUSH); 659 + blk_opf_t op_flags = bio->bi_opf & (REQ_FUA | REQ_PREFLUSH | REQ_ATOMIC); 660 660 struct dm_io_request io_req = { 661 661 .bi_opf = REQ_OP_WRITE | op_flags, 662 662 .mem.type = DM_IO_BIO, ··· 1483 1483 1484 1484 static struct target_type mirror_target = { 1485 1485 .name = "mirror", 1486 - .version = {1, 14, 0}, 1486 + .version = {1, 15, 0}, 1487 1487 .module = THIS_MODULE, 1488 + .features = DM_TARGET_ATOMIC_WRITES, 1488 1489 .ctr = mirror_ctr, 1489 1490 .dtr = mirror_dtr, 1490 1491 .map = mirror_map,
+3 -2
drivers/md/dm-stripe.c
··· 465 465 466 466 static struct target_type stripe_target = { 467 467 .name = "striped", 468 - .version = {1, 6, 0}, 469 - .features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_NOWAIT, 468 + .version = {1, 7, 0}, 469 + .features = DM_TARGET_PASSES_INTEGRITY | DM_TARGET_NOWAIT | 470 + DM_TARGET_ATOMIC_WRITES, 470 471 .module = THIS_MODULE, 471 472 .ctr = stripe_ctr, 472 473 .dtr = stripe_dtr,
+29
drivers/md/dm-table.c
··· 1806 1806 return true; 1807 1807 } 1808 1808 1809 + static int device_not_atomic_write_capable(struct dm_target *ti, 1810 + struct dm_dev *dev, sector_t start, 1811 + sector_t len, void *data) 1812 + { 1813 + return !bdev_can_atomic_write(dev->bdev); 1814 + } 1815 + 1816 + static bool dm_table_supports_atomic_writes(struct dm_table *t) 1817 + { 1818 + for (unsigned int i = 0; i < t->num_targets; i++) { 1819 + struct dm_target *ti = dm_table_get_target(t, i); 1820 + 1821 + if (!dm_target_supports_atomic_writes(ti->type)) 1822 + return false; 1823 + 1824 + if (!ti->type->iterate_devices) 1825 + return false; 1826 + 1827 + if (ti->type->iterate_devices(ti, 1828 + device_not_atomic_write_capable, NULL)) { 1829 + return false; 1830 + } 1831 + } 1832 + return true; 1833 + } 1834 + 1809 1835 int dm_table_set_restrictions(struct dm_table *t, struct request_queue *q, 1810 1836 struct queue_limits *limits) 1811 1837 { ··· 1879 1853 if (r) 1880 1854 return r; 1881 1855 } 1856 + 1857 + if (dm_table_supports_atomic_writes(t)) 1858 + limits->features |= BLK_FEAT_ATOMIC_WRITES; 1882 1859 1883 1860 r = queue_limits_set(q, limits); 1884 1861 if (r)
+21 -10
drivers/md/dm.c
··· 1479 1479 1480 1480 static void alloc_multiple_bios(struct bio_list *blist, struct clone_info *ci, 1481 1481 struct dm_target *ti, unsigned int num_bios, 1482 - unsigned *len, gfp_t gfp_flag) 1482 + unsigned *len) 1483 1483 { 1484 1484 struct bio *bio; 1485 - int try = (gfp_flag & GFP_NOWAIT) ? 0 : 1; 1485 + int try; 1486 1486 1487 - for (; try < 2; try++) { 1487 + for (try = 0; try < 2; try++) { 1488 1488 int bio_nr; 1489 1489 1490 1490 if (try && num_bios > 1) ··· 1508 1508 } 1509 1509 1510 1510 static unsigned int __send_duplicate_bios(struct clone_info *ci, struct dm_target *ti, 1511 - unsigned int num_bios, unsigned int *len, 1512 - gfp_t gfp_flag) 1511 + unsigned int num_bios, unsigned int *len) 1513 1512 { 1514 1513 struct bio_list blist = BIO_EMPTY_LIST; 1515 1514 struct bio *clone; ··· 1525 1526 * Using alloc_multiple_bios(), even if num_bios is 1, to consistently 1526 1527 * support allocating using GFP_NOWAIT with GFP_NOIO fallback. 1527 1528 */ 1528 - alloc_multiple_bios(&blist, ci, ti, num_bios, len, gfp_flag); 1529 + alloc_multiple_bios(&blist, ci, ti, num_bios, len); 1529 1530 while ((clone = bio_list_pop(&blist))) { 1530 1531 if (num_bios > 1) 1531 1532 dm_tio_set_flag(clone_to_tio(clone), DM_TIO_IS_DUPLICATE_BIO); ··· 1563 1564 1564 1565 atomic_add(ti->num_flush_bios, &ci->io->io_count); 1565 1566 bios = __send_duplicate_bios(ci, ti, ti->num_flush_bios, 1566 - NULL, GFP_NOWAIT); 1567 + NULL); 1567 1568 atomic_sub(ti->num_flush_bios - bios, &ci->io->io_count); 1568 1569 } 1569 1570 } else { ··· 1611 1612 __max_io_len(ti, ci->sector, max_granularity, max_sectors)); 1612 1613 1613 1614 atomic_add(num_bios, &ci->io->io_count); 1614 - bios = __send_duplicate_bios(ci, ti, num_bios, &len, GFP_NOIO); 1615 + bios = __send_duplicate_bios(ci, ti, num_bios, &len); 1615 1616 /* 1616 1617 * alloc_io() takes one extra reference for submission, so the 1617 1618 * reference won't reach 0 without the following (+1) subtraction ··· 1745 1746 ci->submit_as_polled = !!(ci->bio->bi_opf & REQ_POLLED); 1746 1747 1747 1748 len = min_t(sector_t, max_io_len(ti, ci->sector), ci->sector_count); 1749 + if (ci->bio->bi_opf & REQ_ATOMIC && len != ci->sector_count) 1750 + return BLK_STS_IOERR; 1751 + 1748 1752 setup_split_accounting(ci, len); 1749 1753 1750 1754 if (unlikely(ci->bio->bi_opf & REQ_NOWAIT)) { ··· 1851 1849 * not go crazy with the clone allocation. 1852 1850 */ 1853 1851 alloc_multiple_bios(&blist, ci, ti, min(nr_reset, 32), 1854 - NULL, GFP_NOIO); 1852 + NULL); 1855 1853 } 1856 1854 1857 1855 /* Get a clone and change it to a regular reset operation. */ ··· 1883 1881 unsigned int bios; 1884 1882 1885 1883 atomic_add(1, &ci->io->io_count); 1886 - bios = __send_duplicate_bios(ci, ti, 1, NULL, GFP_NOIO); 1884 + bios = __send_duplicate_bios(ci, ti, 1, NULL); 1887 1885 atomic_sub(1 - bios, &ci->io->io_count); 1888 1886 1889 1887 ci->sector_count = 0; ··· 1971 1969 1972 1970 /* Only support nowait for normal IO */ 1973 1971 if (unlikely(bio->bi_opf & REQ_NOWAIT) && !is_abnormal) { 1972 + /* 1973 + * Don't support NOWAIT for FLUSH because it may allocate 1974 + * multiple bios and there's no easy way how to undo the 1975 + * allocations. 1976 + */ 1977 + if (bio->bi_opf & REQ_PREFLUSH) { 1978 + bio_wouldblock_error(bio); 1979 + return; 1980 + } 1974 1981 io = alloc_io(md, bio, GFP_NOWAIT); 1975 1982 if (unlikely(!io)) { 1976 1983 /* Unable to do anything without dm_io. */
+37 -17
drivers/md/persistent-data/dm-transaction-manager.c
··· 13 13 #include <linux/export.h> 14 14 #include <linux/mutex.h> 15 15 #include <linux/hash.h> 16 + #include <linux/rbtree.h> 16 17 #include <linux/slab.h> 17 18 #include <linux/device-mapper.h> 18 19 ··· 78 77 /*----------------------------------------------------------------*/ 79 78 80 79 struct shadow_info { 81 - struct hlist_node hlist; 80 + struct rb_node node; 82 81 dm_block_t where; 83 82 }; 84 83 ··· 96 95 struct dm_space_map *sm; 97 96 98 97 spinlock_t lock; 99 - struct hlist_head buckets[DM_HASH_SIZE]; 98 + struct rb_root buckets[DM_HASH_SIZE]; 100 99 101 100 struct prefetch_set prefetches; 102 101 }; ··· 107 106 { 108 107 int r = 0; 109 108 unsigned int bucket = dm_hash_block(b, DM_HASH_MASK); 110 - struct shadow_info *si; 109 + struct rb_node **node; 111 110 112 111 spin_lock(&tm->lock); 113 - hlist_for_each_entry(si, tm->buckets + bucket, hlist) 114 - if (si->where == b) { 112 + node = &tm->buckets[bucket].rb_node; 113 + while (*node) { 114 + struct shadow_info *si = 115 + rb_entry(*node, struct shadow_info, node); 116 + if (b == si->where) { 115 117 r = 1; 116 118 break; 117 119 } 120 + if (b < si->where) 121 + node = &si->node.rb_left; 122 + else 123 + node = &si->node.rb_right; 124 + } 118 125 spin_unlock(&tm->lock); 119 126 120 127 return r; ··· 139 130 140 131 si = kmalloc(sizeof(*si), GFP_NOIO); 141 132 if (si) { 133 + struct rb_node **node, *parent; 142 134 si->where = b; 143 135 bucket = dm_hash_block(b, DM_HASH_MASK); 136 + 144 137 spin_lock(&tm->lock); 145 - hlist_add_head(&si->hlist, tm->buckets + bucket); 138 + node = &tm->buckets[bucket].rb_node; 139 + parent = NULL; 140 + while (*node) { 141 + struct shadow_info *si = 142 + rb_entry(*node, struct shadow_info, node); 143 + parent = *node; 144 + if (b < si->where) 145 + node = &si->node.rb_left; 146 + else 147 + node = &si->node.rb_right; 148 + } 149 + rb_link_node(&si->node, parent, node); 150 + rb_insert_color(&si->node, &tm->buckets[bucket]); 146 151 spin_unlock(&tm->lock); 147 152 } 148 153 } 149 154 150 155 static void wipe_shadow_table(struct dm_transaction_manager *tm) 151 156 { 152 - struct shadow_info *si; 153 - struct hlist_node *tmp; 154 - struct hlist_head *bucket; 155 - int i; 157 + unsigned int i; 156 158 157 159 spin_lock(&tm->lock); 158 160 for (i = 0; i < DM_HASH_SIZE; i++) { 159 - bucket = tm->buckets + i; 160 - hlist_for_each_entry_safe(si, tmp, bucket, hlist) 161 + while (!RB_EMPTY_ROOT(&tm->buckets[i])) { 162 + struct shadow_info *si = 163 + rb_entry(tm->buckets[i].rb_node, struct shadow_info, node); 164 + rb_erase(&si->node, &tm->buckets[i]); 161 165 kfree(si); 162 - 163 - INIT_HLIST_HEAD(bucket); 166 + } 164 167 } 165 - 166 168 spin_unlock(&tm->lock); 167 169 } 168 170 ··· 182 162 static struct dm_transaction_manager *dm_tm_create(struct dm_block_manager *bm, 183 163 struct dm_space_map *sm) 184 164 { 185 - int i; 165 + unsigned int i; 186 166 struct dm_transaction_manager *tm; 187 167 188 168 tm = kmalloc(sizeof(*tm), GFP_KERNEL); ··· 196 176 197 177 spin_lock_init(&tm->lock); 198 178 for (i = 0; i < DM_HASH_SIZE; i++) 199 - INIT_HLIST_HEAD(tm->buckets + i); 179 + tm->buckets[i] = RB_ROOT; 200 180 201 181 prefetch_init(&tm->prefetches); 202 182
+3
include/linux/device-mapper.h
··· 299 299 #define dm_target_supports_mixed_zoned_model(type) (false) 300 300 #endif 301 301 302 + #define DM_TARGET_ATOMIC_WRITES 0x00000400 303 + #define dm_target_supports_atomic_writes(type) ((type)->features & DM_TARGET_ATOMIC_WRITES) 304 + 302 305 struct dm_target { 303 306 struct dm_table *table; 304 307 struct target_type *type;
+2 -2
include/uapi/linux/dm-ioctl.h
··· 286 286 #define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl) 287 287 288 288 #define DM_VERSION_MAJOR 4 289 - #define DM_VERSION_MINOR 48 289 + #define DM_VERSION_MINOR 49 290 290 #define DM_VERSION_PATCHLEVEL 0 291 - #define DM_VERSION_EXTRA "-ioctl (2023-03-01)" 291 + #define DM_VERSION_EXTRA "-ioctl (2025-01-17)" 292 292 293 293 /* Status bits */ 294 294 #define DM_READONLY_FLAG (1 << 0) /* In/Out */