11c6fdbd8SKent Overstreet /* SPDX-License-Identifier: GPL-2.0 */ 21c6fdbd8SKent Overstreet #ifndef _BCACHEFS_EXTENTS_H 31c6fdbd8SKent Overstreet #define _BCACHEFS_EXTENTS_H 41c6fdbd8SKent Overstreet 51c6fdbd8SKent Overstreet #include "bcachefs.h" 61c6fdbd8SKent Overstreet #include "bkey.h" 71c6fdbd8SKent Overstreet #include "extents_types.h" 81c6fdbd8SKent Overstreet 91c6fdbd8SKent Overstreet struct bch_fs; 100dc17247SKent Overstreet struct btree_trans; 111c6fdbd8SKent Overstreet 1226609b61SKent Overstreet /* extent entries: */ 131c6fdbd8SKent Overstreet 1499aaf570SKent Overstreet #define extent_entry_last(_e) \ 1599aaf570SKent Overstreet ((typeof(&(_e).v->start[0])) bkey_val_end(_e)) 161c6fdbd8SKent Overstreet 1726609b61SKent Overstreet #define entry_to_ptr(_entry) \ 1826609b61SKent Overstreet ({ \ 1926609b61SKent Overstreet EBUG_ON((_entry) && !extent_entry_is_ptr(_entry)); \ 2026609b61SKent Overstreet \ 2126609b61SKent Overstreet __builtin_choose_expr( \ 2226609b61SKent Overstreet type_is_exact(_entry, const union bch_extent_entry *), \ 2326609b61SKent Overstreet (const struct bch_extent_ptr *) (_entry), \ 2426609b61SKent Overstreet (struct bch_extent_ptr *) (_entry)); \ 2526609b61SKent Overstreet }) 261c6fdbd8SKent Overstreet 2726609b61SKent Overstreet /* downcast, preserves const */ 2826609b61SKent Overstreet #define to_entry(_entry) \ 2926609b61SKent Overstreet ({ \ 3026609b61SKent Overstreet BUILD_BUG_ON(!type_is(_entry, union bch_extent_crc *) && \ 3126609b61SKent Overstreet !type_is(_entry, struct bch_extent_ptr *) && \ 3226609b61SKent Overstreet !type_is(_entry, struct bch_extent_stripe_ptr *)); \ 3326609b61SKent Overstreet \ 3426609b61SKent Overstreet __builtin_choose_expr( \ 3526609b61SKent Overstreet (type_is_exact(_entry, const union bch_extent_crc *) || \ 3626609b61SKent Overstreet type_is_exact(_entry, const struct bch_extent_ptr *) ||\ 3726609b61SKent Overstreet type_is_exact(_entry, const struct bch_extent_stripe_ptr *)),\ 3826609b61SKent Overstreet (const union bch_extent_entry *) (_entry), \ 3926609b61SKent Overstreet (union bch_extent_entry *) (_entry)); \ 4026609b61SKent Overstreet }) 411c6fdbd8SKent Overstreet 424de77495SKent Overstreet #define extent_entry_next(_entry) \ 434de77495SKent Overstreet ((typeof(_entry)) ((void *) (_entry) + extent_entry_bytes(_entry))) 444de77495SKent Overstreet 451c6fdbd8SKent Overstreet static inline unsigned 461c6fdbd8SKent Overstreet __extent_entry_type(const union bch_extent_entry *e) 471c6fdbd8SKent Overstreet { 481c6fdbd8SKent Overstreet return e->type ? __ffs(e->type) : BCH_EXTENT_ENTRY_MAX; 491c6fdbd8SKent Overstreet } 501c6fdbd8SKent Overstreet 511c6fdbd8SKent Overstreet static inline enum bch_extent_entry_type 521c6fdbd8SKent Overstreet extent_entry_type(const union bch_extent_entry *e) 531c6fdbd8SKent Overstreet { 541c6fdbd8SKent Overstreet int ret = __ffs(e->type); 551c6fdbd8SKent Overstreet 561c6fdbd8SKent Overstreet EBUG_ON(ret < 0 || ret >= BCH_EXTENT_ENTRY_MAX); 571c6fdbd8SKent Overstreet 581c6fdbd8SKent Overstreet return ret; 591c6fdbd8SKent Overstreet } 601c6fdbd8SKent Overstreet 611c6fdbd8SKent Overstreet static inline size_t extent_entry_bytes(const union bch_extent_entry *entry) 621c6fdbd8SKent Overstreet { 631c6fdbd8SKent Overstreet switch (extent_entry_type(entry)) { 64abce30b7SKent Overstreet #define x(f, n) \ 65abce30b7SKent Overstreet case BCH_EXTENT_ENTRY_##f: \ 66abce30b7SKent Overstreet return sizeof(struct bch_extent_##f); 67abce30b7SKent Overstreet BCH_EXTENT_ENTRY_TYPES() 68abce30b7SKent Overstreet #undef x 691c6fdbd8SKent Overstreet default: 701c6fdbd8SKent Overstreet BUG(); 711c6fdbd8SKent Overstreet } 721c6fdbd8SKent Overstreet } 731c6fdbd8SKent Overstreet 741c6fdbd8SKent Overstreet static inline size_t extent_entry_u64s(const union bch_extent_entry *entry) 751c6fdbd8SKent Overstreet { 761c6fdbd8SKent Overstreet return extent_entry_bytes(entry) / sizeof(u64); 771c6fdbd8SKent Overstreet } 781c6fdbd8SKent Overstreet 791c6fdbd8SKent Overstreet static inline bool extent_entry_is_ptr(const union bch_extent_entry *e) 801c6fdbd8SKent Overstreet { 81b9a7d8acSKent Overstreet return extent_entry_type(e) == BCH_EXTENT_ENTRY_ptr; 821742237bSKent Overstreet } 83b9a7d8acSKent Overstreet 84b9a7d8acSKent Overstreet static inline bool extent_entry_is_stripe_ptr(const union bch_extent_entry *e) 85b9a7d8acSKent Overstreet { 86b9a7d8acSKent Overstreet return extent_entry_type(e) == BCH_EXTENT_ENTRY_stripe_ptr; 871c6fdbd8SKent Overstreet } 881c6fdbd8SKent Overstreet 891c6fdbd8SKent Overstreet static inline bool extent_entry_is_crc(const union bch_extent_entry *e) 901c6fdbd8SKent Overstreet { 911742237bSKent Overstreet switch (extent_entry_type(e)) { 921742237bSKent Overstreet case BCH_EXTENT_ENTRY_crc32: 931742237bSKent Overstreet case BCH_EXTENT_ENTRY_crc64: 941742237bSKent Overstreet case BCH_EXTENT_ENTRY_crc128: 951742237bSKent Overstreet return true; 961742237bSKent Overstreet default: 971742237bSKent Overstreet return false; 981742237bSKent Overstreet } 991c6fdbd8SKent Overstreet } 1001c6fdbd8SKent Overstreet 1011c6fdbd8SKent Overstreet union bch_extent_crc { 1021c6fdbd8SKent Overstreet u8 type; 1031c6fdbd8SKent Overstreet struct bch_extent_crc32 crc32; 1041c6fdbd8SKent Overstreet struct bch_extent_crc64 crc64; 1051c6fdbd8SKent Overstreet struct bch_extent_crc128 crc128; 1061c6fdbd8SKent Overstreet }; 1071c6fdbd8SKent Overstreet 1081c6fdbd8SKent Overstreet #define __entry_to_crc(_entry) \ 1091c6fdbd8SKent Overstreet __builtin_choose_expr( \ 1101c6fdbd8SKent Overstreet type_is_exact(_entry, const union bch_extent_entry *), \ 1111c6fdbd8SKent Overstreet (const union bch_extent_crc *) (_entry), \ 1121c6fdbd8SKent Overstreet (union bch_extent_crc *) (_entry)) 1131c6fdbd8SKent Overstreet 1141c6fdbd8SKent Overstreet #define entry_to_crc(_entry) \ 1151c6fdbd8SKent Overstreet ({ \ 1161c6fdbd8SKent Overstreet EBUG_ON((_entry) && !extent_entry_is_crc(_entry)); \ 1171c6fdbd8SKent Overstreet \ 1181c6fdbd8SKent Overstreet __entry_to_crc(_entry); \ 1191c6fdbd8SKent Overstreet }) 1201c6fdbd8SKent Overstreet 1211c6fdbd8SKent Overstreet static inline struct bch_extent_crc_unpacked 1221c6fdbd8SKent Overstreet bch2_extent_crc_unpack(const struct bkey *k, const union bch_extent_crc *crc) 1231c6fdbd8SKent Overstreet { 1241c6fdbd8SKent Overstreet #define common_fields(_crc) \ 1251c6fdbd8SKent Overstreet .csum_type = _crc.csum_type, \ 1261c6fdbd8SKent Overstreet .compression_type = _crc.compression_type, \ 1271c6fdbd8SKent Overstreet .compressed_size = _crc._compressed_size + 1, \ 1281c6fdbd8SKent Overstreet .uncompressed_size = _crc._uncompressed_size + 1, \ 1291c6fdbd8SKent Overstreet .offset = _crc.offset, \ 1301c6fdbd8SKent Overstreet .live_size = k->size 1311c6fdbd8SKent Overstreet 132642d66d1SKent Overstreet if (!crc) 1331c6fdbd8SKent Overstreet return (struct bch_extent_crc_unpacked) { 1341c6fdbd8SKent Overstreet .compressed_size = k->size, 1351c6fdbd8SKent Overstreet .uncompressed_size = k->size, 1361c6fdbd8SKent Overstreet .live_size = k->size, 1371c6fdbd8SKent Overstreet }; 138642d66d1SKent Overstreet 139642d66d1SKent Overstreet switch (extent_entry_type(to_entry(crc))) { 140642d66d1SKent Overstreet case BCH_EXTENT_ENTRY_crc32: { 1411c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked ret = (struct bch_extent_crc_unpacked) { 1421c6fdbd8SKent Overstreet common_fields(crc->crc32), 1431c6fdbd8SKent Overstreet }; 1441c6fdbd8SKent Overstreet 1451c6fdbd8SKent Overstreet *((__le32 *) &ret.csum.lo) = crc->crc32.csum; 1461c6fdbd8SKent Overstreet 1471c6fdbd8SKent Overstreet memcpy(&ret.csum.lo, &crc->crc32.csum, 1481c6fdbd8SKent Overstreet sizeof(crc->crc32.csum)); 1491c6fdbd8SKent Overstreet 1501c6fdbd8SKent Overstreet return ret; 1511c6fdbd8SKent Overstreet } 152642d66d1SKent Overstreet case BCH_EXTENT_ENTRY_crc64: { 1531c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked ret = (struct bch_extent_crc_unpacked) { 1541c6fdbd8SKent Overstreet common_fields(crc->crc64), 1551c6fdbd8SKent Overstreet .nonce = crc->crc64.nonce, 1561c6fdbd8SKent Overstreet .csum.lo = (__force __le64) crc->crc64.csum_lo, 1571c6fdbd8SKent Overstreet }; 1581c6fdbd8SKent Overstreet 1591c6fdbd8SKent Overstreet *((__le16 *) &ret.csum.hi) = crc->crc64.csum_hi; 1601c6fdbd8SKent Overstreet 1611c6fdbd8SKent Overstreet return ret; 1621c6fdbd8SKent Overstreet } 163642d66d1SKent Overstreet case BCH_EXTENT_ENTRY_crc128: { 1641c6fdbd8SKent Overstreet struct bch_extent_crc_unpacked ret = (struct bch_extent_crc_unpacked) { 1651c6fdbd8SKent Overstreet common_fields(crc->crc128), 1661c6fdbd8SKent Overstreet .nonce = crc->crc128.nonce, 1671c6fdbd8SKent Overstreet .csum = crc->crc128.csum, 1681c6fdbd8SKent Overstreet }; 1691c6fdbd8SKent Overstreet 1701c6fdbd8SKent Overstreet return ret; 1711c6fdbd8SKent Overstreet } 1721c6fdbd8SKent Overstreet default: 1731c6fdbd8SKent Overstreet BUG(); 1741c6fdbd8SKent Overstreet } 1751c6fdbd8SKent Overstreet #undef common_fields 1761c6fdbd8SKent Overstreet } 1771c6fdbd8SKent Overstreet 178ab05de4cSKent Overstreet static inline bool crc_is_compressed(struct bch_extent_crc_unpacked crc) 179ab05de4cSKent Overstreet { 180ab05de4cSKent Overstreet return (crc.compression_type != BCH_COMPRESSION_TYPE_none && 181ab05de4cSKent Overstreet crc.compression_type != BCH_COMPRESSION_TYPE_incompressible); 182ab05de4cSKent Overstreet } 183ab05de4cSKent Overstreet 18426609b61SKent Overstreet /* bkey_ptrs: generically over any key type that has ptrs */ 18526609b61SKent Overstreet 18626609b61SKent Overstreet struct bkey_ptrs_c { 18726609b61SKent Overstreet const union bch_extent_entry *start; 18826609b61SKent Overstreet const union bch_extent_entry *end; 18926609b61SKent Overstreet }; 19026609b61SKent Overstreet 19126609b61SKent Overstreet struct bkey_ptrs { 19226609b61SKent Overstreet union bch_extent_entry *start; 19326609b61SKent Overstreet union bch_extent_entry *end; 19426609b61SKent Overstreet }; 19526609b61SKent Overstreet 1964de77495SKent Overstreet static inline struct bkey_ptrs_c bch2_bkey_ptrs_c(struct bkey_s_c k) 1974de77495SKent Overstreet { 1984de77495SKent Overstreet switch (k.k->type) { 1994de77495SKent Overstreet case KEY_TYPE_btree_ptr: { 2004de77495SKent Overstreet struct bkey_s_c_btree_ptr e = bkey_s_c_to_btree_ptr(k); 201a1019576SKent Overstreet 2024de77495SKent Overstreet return (struct bkey_ptrs_c) { 2034de77495SKent Overstreet to_entry(&e.v->start[0]), 2044de77495SKent Overstreet to_entry(extent_entry_last(e)) 2054de77495SKent Overstreet }; 2064de77495SKent Overstreet } 2074de77495SKent Overstreet case KEY_TYPE_extent: { 2084de77495SKent Overstreet struct bkey_s_c_extent e = bkey_s_c_to_extent(k); 209a1019576SKent Overstreet 2104de77495SKent Overstreet return (struct bkey_ptrs_c) { 2114de77495SKent Overstreet e.v->start, 2124de77495SKent Overstreet extent_entry_last(e) 2134de77495SKent Overstreet }; 2144de77495SKent Overstreet } 2154de77495SKent Overstreet case KEY_TYPE_stripe: { 2164de77495SKent Overstreet struct bkey_s_c_stripe s = bkey_s_c_to_stripe(k); 217a1019576SKent Overstreet 2184de77495SKent Overstreet return (struct bkey_ptrs_c) { 2194de77495SKent Overstreet to_entry(&s.v->ptrs[0]), 2204de77495SKent Overstreet to_entry(&s.v->ptrs[s.v->nr_blocks]), 2214de77495SKent Overstreet }; 2224de77495SKent Overstreet } 2234de77495SKent Overstreet case KEY_TYPE_reflink_v: { 2244de77495SKent Overstreet struct bkey_s_c_reflink_v r = bkey_s_c_to_reflink_v(k); 2251c6fdbd8SKent Overstreet 2264de77495SKent Overstreet return (struct bkey_ptrs_c) { 2274de77495SKent Overstreet r.v->start, 2284de77495SKent Overstreet bkey_val_end(r), 2294de77495SKent Overstreet }; 2304de77495SKent Overstreet } 231548b3d20SKent Overstreet case KEY_TYPE_btree_ptr_v2: { 232548b3d20SKent Overstreet struct bkey_s_c_btree_ptr_v2 e = bkey_s_c_to_btree_ptr_v2(k); 233a1019576SKent Overstreet 234548b3d20SKent Overstreet return (struct bkey_ptrs_c) { 235548b3d20SKent Overstreet to_entry(&e.v->start[0]), 236548b3d20SKent Overstreet to_entry(extent_entry_last(e)) 237548b3d20SKent Overstreet }; 238548b3d20SKent Overstreet } 2394de77495SKent Overstreet default: 2404de77495SKent Overstreet return (struct bkey_ptrs_c) { NULL, NULL }; 2414de77495SKent Overstreet } 2424de77495SKent Overstreet } 2434de77495SKent Overstreet 2444de77495SKent Overstreet static inline struct bkey_ptrs bch2_bkey_ptrs(struct bkey_s k) 2454de77495SKent Overstreet { 2464de77495SKent Overstreet struct bkey_ptrs_c p = bch2_bkey_ptrs_c(k.s_c); 2474de77495SKent Overstreet 2484de77495SKent Overstreet return (struct bkey_ptrs) { 2494de77495SKent Overstreet (void *) p.start, 2504de77495SKent Overstreet (void *) p.end 2514de77495SKent Overstreet }; 2524de77495SKent Overstreet } 2531c6fdbd8SKent Overstreet 25426609b61SKent Overstreet #define __bkey_extent_entry_for_each_from(_start, _end, _entry) \ 25526609b61SKent Overstreet for ((_entry) = (_start); \ 25626609b61SKent Overstreet (_entry) < (_end); \ 25726609b61SKent Overstreet (_entry) = extent_entry_next(_entry)) 2581c6fdbd8SKent Overstreet 25926609b61SKent Overstreet #define __bkey_ptr_next(_ptr, _end) \ 26026609b61SKent Overstreet ({ \ 26126609b61SKent Overstreet typeof(_end) _entry; \ 26226609b61SKent Overstreet \ 26326609b61SKent Overstreet __bkey_extent_entry_for_each_from(to_entry(_ptr), _end, _entry) \ 26426609b61SKent Overstreet if (extent_entry_is_ptr(_entry)) \ 26526609b61SKent Overstreet break; \ 26626609b61SKent Overstreet \ 26726609b61SKent Overstreet _entry < (_end) ? entry_to_ptr(_entry) : NULL; \ 26826609b61SKent Overstreet }) 26926609b61SKent Overstreet 27026609b61SKent Overstreet #define bkey_extent_entry_for_each_from(_p, _entry, _start) \ 27126609b61SKent Overstreet __bkey_extent_entry_for_each_from(_start, (_p).end, _entry) 27226609b61SKent Overstreet 27326609b61SKent Overstreet #define bkey_extent_entry_for_each(_p, _entry) \ 27426609b61SKent Overstreet bkey_extent_entry_for_each_from(_p, _entry, _p.start) 27526609b61SKent Overstreet 27626609b61SKent Overstreet #define __bkey_for_each_ptr(_start, _end, _ptr) \ 27726609b61SKent Overstreet for ((_ptr) = (_start); \ 27826609b61SKent Overstreet ((_ptr) = __bkey_ptr_next(_ptr, _end)); \ 27926609b61SKent Overstreet (_ptr)++) 28026609b61SKent Overstreet 28126609b61SKent Overstreet #define bkey_ptr_next(_p, _ptr) \ 28226609b61SKent Overstreet __bkey_ptr_next(_ptr, (_p).end) 28326609b61SKent Overstreet 28426609b61SKent Overstreet #define bkey_for_each_ptr(_p, _ptr) \ 28526609b61SKent Overstreet __bkey_for_each_ptr(&(_p).start->ptr, (_p).end, _ptr) 28626609b61SKent Overstreet 28726609b61SKent Overstreet #define __bkey_ptr_next_decode(_k, _end, _ptr, _entry) \ 28826609b61SKent Overstreet ({ \ 28926609b61SKent Overstreet __label__ out; \ 29026609b61SKent Overstreet \ 29126609b61SKent Overstreet (_ptr).idx = 0; \ 29237954a27SKent Overstreet (_ptr).has_ec = false; \ 29326609b61SKent Overstreet \ 29426609b61SKent Overstreet __bkey_extent_entry_for_each_from(_entry, _end, _entry) \ 29526609b61SKent Overstreet switch (extent_entry_type(_entry)) { \ 29626609b61SKent Overstreet case BCH_EXTENT_ENTRY_ptr: \ 29726609b61SKent Overstreet (_ptr).ptr = _entry->ptr; \ 29826609b61SKent Overstreet goto out; \ 29926609b61SKent Overstreet case BCH_EXTENT_ENTRY_crc32: \ 30026609b61SKent Overstreet case BCH_EXTENT_ENTRY_crc64: \ 30126609b61SKent Overstreet case BCH_EXTENT_ENTRY_crc128: \ 30226609b61SKent Overstreet (_ptr).crc = bch2_extent_crc_unpack(_k, \ 30326609b61SKent Overstreet entry_to_crc(_entry)); \ 30426609b61SKent Overstreet break; \ 30526609b61SKent Overstreet case BCH_EXTENT_ENTRY_stripe_ptr: \ 30637954a27SKent Overstreet (_ptr).ec = _entry->stripe_ptr; \ 30737954a27SKent Overstreet (_ptr).has_ec = true; \ 30826609b61SKent Overstreet break; \ 30926609b61SKent Overstreet } \ 31026609b61SKent Overstreet out: \ 31126609b61SKent Overstreet _entry < (_end); \ 31226609b61SKent Overstreet }) 31326609b61SKent Overstreet 31426609b61SKent Overstreet #define __bkey_for_each_ptr_decode(_k, _start, _end, _ptr, _entry) \ 31526609b61SKent Overstreet for ((_ptr).crc = bch2_extent_crc_unpack(_k, NULL), \ 31626609b61SKent Overstreet (_entry) = _start; \ 31726609b61SKent Overstreet __bkey_ptr_next_decode(_k, _end, _ptr, _entry); \ 31826609b61SKent Overstreet (_entry) = extent_entry_next(_entry)) 31926609b61SKent Overstreet 32026609b61SKent Overstreet #define bkey_for_each_ptr_decode(_k, _p, _ptr, _entry) \ 32126609b61SKent Overstreet __bkey_for_each_ptr_decode(_k, (_p).start, (_p).end, \ 32226609b61SKent Overstreet _ptr, _entry) 32326609b61SKent Overstreet 32499aaf570SKent Overstreet #define bkey_crc_next(_k, _start, _end, _crc, _iter) \ 32599aaf570SKent Overstreet ({ \ 32699aaf570SKent Overstreet __bkey_extent_entry_for_each_from(_iter, _end, _iter) \ 32799aaf570SKent Overstreet if (extent_entry_is_crc(_iter)) { \ 32899aaf570SKent Overstreet (_crc) = bch2_extent_crc_unpack(_k, \ 32999aaf570SKent Overstreet entry_to_crc(_iter)); \ 33099aaf570SKent Overstreet break; \ 33199aaf570SKent Overstreet } \ 33299aaf570SKent Overstreet \ 33399aaf570SKent Overstreet (_iter) < (_end); \ 33499aaf570SKent Overstreet }) 33599aaf570SKent Overstreet 33699aaf570SKent Overstreet #define __bkey_for_each_crc(_k, _start, _end, _crc, _iter) \ 33799aaf570SKent Overstreet for ((_crc) = bch2_extent_crc_unpack(_k, NULL), \ 33899aaf570SKent Overstreet (_iter) = (_start); \ 33999aaf570SKent Overstreet bkey_crc_next(_k, _start, _end, _crc, _iter); \ 34099aaf570SKent Overstreet (_iter) = extent_entry_next(_iter)) 34199aaf570SKent Overstreet 34299aaf570SKent Overstreet #define bkey_for_each_crc(_k, _p, _crc, _iter) \ 34399aaf570SKent Overstreet __bkey_for_each_crc(_k, (_p).start, (_p).end, _crc, _iter) 34499aaf570SKent Overstreet 3454de77495SKent Overstreet /* Iterate over pointers in KEY_TYPE_extent: */ 3464de77495SKent Overstreet 3474de77495SKent Overstreet #define extent_for_each_entry_from(_e, _entry, _start) \ 3484de77495SKent Overstreet __bkey_extent_entry_for_each_from(_start, \ 3494de77495SKent Overstreet extent_entry_last(_e), _entry) 3504de77495SKent Overstreet 3514de77495SKent Overstreet #define extent_for_each_entry(_e, _entry) \ 3524de77495SKent Overstreet extent_for_each_entry_from(_e, _entry, (_e).v->start) 3534de77495SKent Overstreet 3544de77495SKent Overstreet #define extent_ptr_next(_e, _ptr) \ 3554de77495SKent Overstreet __bkey_ptr_next(_ptr, extent_entry_last(_e)) 3564de77495SKent Overstreet 3574de77495SKent Overstreet #define extent_for_each_ptr(_e, _ptr) \ 3584de77495SKent Overstreet __bkey_for_each_ptr(&(_e).v->start->ptr, extent_entry_last(_e), _ptr) 3594de77495SKent Overstreet 3604de77495SKent Overstreet #define extent_for_each_ptr_decode(_e, _ptr, _entry) \ 3614de77495SKent Overstreet __bkey_for_each_ptr_decode((_e).k, (_e).v->start, \ 3624de77495SKent Overstreet extent_entry_last(_e), _ptr, _entry) 3634de77495SKent Overstreet 36426609b61SKent Overstreet /* utility code common to all keys with pointers: */ 36526609b61SKent Overstreet 3664de77495SKent Overstreet void bch2_mark_io_failure(struct bch_io_failures *, 3674de77495SKent Overstreet struct extent_ptr_decoded *); 3684de77495SKent Overstreet int bch2_bkey_pick_read_device(struct bch_fs *, struct bkey_s_c, 3694de77495SKent Overstreet struct bch_io_failures *, 3704de77495SKent Overstreet struct extent_ptr_decoded *); 37176426098SKent Overstreet 3724de77495SKent Overstreet /* KEY_TYPE_btree_ptr: */ 3734de77495SKent Overstreet 374275c8426SKent Overstreet int bch2_btree_ptr_invalid(const struct bch_fs *, struct bkey_s_c, int, struct printbuf *); 3754de77495SKent Overstreet void bch2_btree_ptr_to_text(struct printbuf *, struct bch_fs *, 3764de77495SKent Overstreet struct bkey_s_c); 37759a38a38SKent Overstreet 378275c8426SKent Overstreet int bch2_btree_ptr_v2_invalid(const struct bch_fs *, struct bkey_s_c, int, struct printbuf *); 379f0ac7df2SKent Overstreet void bch2_btree_ptr_v2_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); 38039fb2983SKent Overstreet void bch2_btree_ptr_v2_compat(enum btree_id, unsigned, unsigned, 38139fb2983SKent Overstreet int, struct bkey_s); 3824de77495SKent Overstreet 383a1019576SKent Overstreet #define bch2_bkey_ops_btree_ptr ((struct bkey_ops) { \ 3844de77495SKent Overstreet .key_invalid = bch2_btree_ptr_invalid, \ 3854de77495SKent Overstreet .val_to_text = bch2_btree_ptr_to_text, \ 3864de77495SKent Overstreet .swab = bch2_ptr_swab, \ 387880e2275SKent Overstreet .trans_trigger = bch2_trans_mark_extent, \ 388880e2275SKent Overstreet .atomic_trigger = bch2_mark_extent, \ 389a1019576SKent Overstreet }) 3904de77495SKent Overstreet 391a1019576SKent Overstreet #define bch2_bkey_ops_btree_ptr_v2 ((struct bkey_ops) { \ 392fad7cfedSKent Overstreet .key_invalid = bch2_btree_ptr_v2_invalid, \ 39359a38a38SKent Overstreet .val_to_text = bch2_btree_ptr_v2_to_text, \ 394548b3d20SKent Overstreet .swab = bch2_ptr_swab, \ 39539fb2983SKent Overstreet .compat = bch2_btree_ptr_v2_compat, \ 396880e2275SKent Overstreet .trans_trigger = bch2_trans_mark_extent, \ 397880e2275SKent Overstreet .atomic_trigger = bch2_mark_extent, \ 398a1019576SKent Overstreet }) 399548b3d20SKent Overstreet 4004de77495SKent Overstreet /* KEY_TYPE_extent: */ 4014de77495SKent Overstreet 40259ba21d9SKent Overstreet bool bch2_extent_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c); 4034de77495SKent Overstreet 404a1019576SKent Overstreet #define bch2_bkey_ops_extent ((struct bkey_ops) { \ 405f0ac7df2SKent Overstreet .key_invalid = bch2_bkey_ptrs_invalid, \ 406f0ac7df2SKent Overstreet .val_to_text = bch2_bkey_ptrs_to_text, \ 4074de77495SKent Overstreet .swab = bch2_ptr_swab, \ 4084de77495SKent Overstreet .key_normalize = bch2_extent_normalize, \ 4094de77495SKent Overstreet .key_merge = bch2_extent_merge, \ 410880e2275SKent Overstreet .trans_trigger = bch2_trans_mark_extent, \ 411880e2275SKent Overstreet .atomic_trigger = bch2_mark_extent, \ 412a1019576SKent Overstreet }) 4134de77495SKent Overstreet 4144de77495SKent Overstreet /* KEY_TYPE_reservation: */ 4154de77495SKent Overstreet 416275c8426SKent Overstreet int bch2_reservation_invalid(const struct bch_fs *, struct bkey_s_c, 417275c8426SKent Overstreet int, struct printbuf *); 4184de77495SKent Overstreet void bch2_reservation_to_text(struct printbuf *, struct bch_fs *, struct bkey_s_c); 41959ba21d9SKent Overstreet bool bch2_reservation_merge(struct bch_fs *, struct bkey_s, struct bkey_s_c); 4204de77495SKent Overstreet 421a1019576SKent Overstreet #define bch2_bkey_ops_reservation ((struct bkey_ops) { \ 4224de77495SKent Overstreet .key_invalid = bch2_reservation_invalid, \ 4234de77495SKent Overstreet .val_to_text = bch2_reservation_to_text, \ 4244de77495SKent Overstreet .key_merge = bch2_reservation_merge, \ 425880e2275SKent Overstreet .trans_trigger = bch2_trans_mark_reservation, \ 426880e2275SKent Overstreet .atomic_trigger = bch2_mark_reservation, \ 427a1019576SKent Overstreet }) 4284de77495SKent Overstreet 4294de77495SKent Overstreet /* Extent checksum entries: */ 4304de77495SKent Overstreet 4314de77495SKent Overstreet bool bch2_can_narrow_extent_crcs(struct bkey_s_c, 4324de77495SKent Overstreet struct bch_extent_crc_unpacked); 4334de77495SKent Overstreet bool bch2_bkey_narrow_crcs(struct bkey_i *, struct bch_extent_crc_unpacked); 4344de77495SKent Overstreet void bch2_extent_crc_append(struct bkey_i *, 4354de77495SKent Overstreet struct bch_extent_crc_unpacked); 4364de77495SKent Overstreet 4374de77495SKent Overstreet /* Generic code for keys with pointers: */ 4384de77495SKent Overstreet 439297d8934SKent Overstreet static inline bool bkey_is_btree_ptr(const struct bkey *k) 440297d8934SKent Overstreet { 441297d8934SKent Overstreet switch (k->type) { 442297d8934SKent Overstreet case KEY_TYPE_btree_ptr: 443297d8934SKent Overstreet case KEY_TYPE_btree_ptr_v2: 444297d8934SKent Overstreet return true; 445297d8934SKent Overstreet default: 446297d8934SKent Overstreet return false; 447297d8934SKent Overstreet } 448297d8934SKent Overstreet } 449297d8934SKent Overstreet 4504de77495SKent Overstreet static inline bool bkey_extent_is_direct_data(const struct bkey *k) 4514de77495SKent Overstreet { 4524de77495SKent Overstreet switch (k->type) { 4534de77495SKent Overstreet case KEY_TYPE_btree_ptr: 454548b3d20SKent Overstreet case KEY_TYPE_btree_ptr_v2: 4554de77495SKent Overstreet case KEY_TYPE_extent: 4564de77495SKent Overstreet case KEY_TYPE_reflink_v: 4574de77495SKent Overstreet return true; 45826609b61SKent Overstreet default: 4594de77495SKent Overstreet return false; 46026609b61SKent Overstreet } 46126609b61SKent Overstreet } 46226609b61SKent Overstreet 463801a3de6SKent Overstreet static inline bool bkey_extent_is_inline_data(const struct bkey *k) 464801a3de6SKent Overstreet { 465801a3de6SKent Overstreet return k->type == KEY_TYPE_inline_data || 466801a3de6SKent Overstreet k->type == KEY_TYPE_indirect_inline_data; 467801a3de6SKent Overstreet } 468801a3de6SKent Overstreet 469801a3de6SKent Overstreet static inline unsigned bkey_inline_data_offset(const struct bkey *k) 470801a3de6SKent Overstreet { 471801a3de6SKent Overstreet switch (k->type) { 472801a3de6SKent Overstreet case KEY_TYPE_inline_data: 473801a3de6SKent Overstreet return sizeof(struct bch_inline_data); 474801a3de6SKent Overstreet case KEY_TYPE_indirect_inline_data: 475801a3de6SKent Overstreet return sizeof(struct bch_indirect_inline_data); 476801a3de6SKent Overstreet default: 477801a3de6SKent Overstreet BUG(); 478801a3de6SKent Overstreet } 479801a3de6SKent Overstreet } 480801a3de6SKent Overstreet 481801a3de6SKent Overstreet static inline unsigned bkey_inline_data_bytes(const struct bkey *k) 482801a3de6SKent Overstreet { 483801a3de6SKent Overstreet return bkey_val_bytes(k) - bkey_inline_data_offset(k); 484801a3de6SKent Overstreet } 485801a3de6SKent Overstreet 486801a3de6SKent Overstreet #define bkey_inline_data_p(_k) (((void *) (_k).v) + bkey_inline_data_offset((_k).k)) 487801a3de6SKent Overstreet 4884de77495SKent Overstreet static inline bool bkey_extent_is_data(const struct bkey *k) 48926609b61SKent Overstreet { 4904de77495SKent Overstreet return bkey_extent_is_direct_data(k) || 491801a3de6SKent Overstreet bkey_extent_is_inline_data(k) || 4924de77495SKent Overstreet k->type == KEY_TYPE_reflink_p; 4934de77495SKent Overstreet } 49426609b61SKent Overstreet 4954de77495SKent Overstreet /* 4964de77495SKent Overstreet * Should extent be counted under inode->i_sectors? 4974de77495SKent Overstreet */ 4984de77495SKent Overstreet static inline bool bkey_extent_is_allocation(const struct bkey *k) 4994de77495SKent Overstreet { 5004de77495SKent Overstreet switch (k->type) { 5014de77495SKent Overstreet case KEY_TYPE_extent: 5024de77495SKent Overstreet case KEY_TYPE_reservation: 5034de77495SKent Overstreet case KEY_TYPE_reflink_p: 5044de77495SKent Overstreet case KEY_TYPE_reflink_v: 5054de77495SKent Overstreet case KEY_TYPE_inline_data: 506801a3de6SKent Overstreet case KEY_TYPE_indirect_inline_data: 5074de77495SKent Overstreet return true; 5084de77495SKent Overstreet default: 5094de77495SKent Overstreet return false; 5104de77495SKent Overstreet } 51126609b61SKent Overstreet } 51226609b61SKent Overstreet 51326609b61SKent Overstreet static inline struct bch_devs_list bch2_bkey_devs(struct bkey_s_c k) 51426609b61SKent Overstreet { 51526609b61SKent Overstreet struct bch_devs_list ret = (struct bch_devs_list) { 0 }; 51626609b61SKent Overstreet struct bkey_ptrs_c p = bch2_bkey_ptrs_c(k); 51726609b61SKent Overstreet const struct bch_extent_ptr *ptr; 51826609b61SKent Overstreet 51926609b61SKent Overstreet bkey_for_each_ptr(p, ptr) 52026609b61SKent Overstreet ret.devs[ret.nr++] = ptr->dev; 52126609b61SKent Overstreet 52226609b61SKent Overstreet return ret; 52326609b61SKent Overstreet } 52426609b61SKent Overstreet 52526609b61SKent Overstreet static inline struct bch_devs_list bch2_bkey_dirty_devs(struct bkey_s_c k) 52626609b61SKent Overstreet { 52726609b61SKent Overstreet struct bch_devs_list ret = (struct bch_devs_list) { 0 }; 52826609b61SKent Overstreet struct bkey_ptrs_c p = bch2_bkey_ptrs_c(k); 52926609b61SKent Overstreet const struct bch_extent_ptr *ptr; 53026609b61SKent Overstreet 53126609b61SKent Overstreet bkey_for_each_ptr(p, ptr) 53226609b61SKent Overstreet if (!ptr->cached) 53326609b61SKent Overstreet ret.devs[ret.nr++] = ptr->dev; 53426609b61SKent Overstreet 53526609b61SKent Overstreet return ret; 53626609b61SKent Overstreet } 53726609b61SKent Overstreet 53826609b61SKent Overstreet static inline struct bch_devs_list bch2_bkey_cached_devs(struct bkey_s_c k) 53926609b61SKent Overstreet { 54026609b61SKent Overstreet struct bch_devs_list ret = (struct bch_devs_list) { 0 }; 54126609b61SKent Overstreet struct bkey_ptrs_c p = bch2_bkey_ptrs_c(k); 54226609b61SKent Overstreet const struct bch_extent_ptr *ptr; 54326609b61SKent Overstreet 54426609b61SKent Overstreet bkey_for_each_ptr(p, ptr) 54526609b61SKent Overstreet if (ptr->cached) 54626609b61SKent Overstreet ret.devs[ret.nr++] = ptr->dev; 54726609b61SKent Overstreet 54826609b61SKent Overstreet return ret; 54926609b61SKent Overstreet } 55026609b61SKent Overstreet 551e1036ce5SKent Overstreet static inline unsigned bch2_bkey_ptr_data_type(struct bkey_s_c k, const struct bch_extent_ptr *ptr) 552e1036ce5SKent Overstreet { 553e1036ce5SKent Overstreet switch (k.k->type) { 554e1036ce5SKent Overstreet case KEY_TYPE_btree_ptr: 555e1036ce5SKent Overstreet case KEY_TYPE_btree_ptr_v2: 556e1036ce5SKent Overstreet return BCH_DATA_btree; 557e1036ce5SKent Overstreet case KEY_TYPE_extent: 558e1036ce5SKent Overstreet case KEY_TYPE_reflink_v: 559e1036ce5SKent Overstreet return BCH_DATA_user; 560e1036ce5SKent Overstreet case KEY_TYPE_stripe: { 561e1036ce5SKent Overstreet struct bkey_s_c_stripe s = bkey_s_c_to_stripe(k); 562e1036ce5SKent Overstreet 563e1036ce5SKent Overstreet BUG_ON(ptr < s.v->ptrs || 564e1036ce5SKent Overstreet ptr >= s.v->ptrs + s.v->nr_blocks); 565e1036ce5SKent Overstreet 566e1036ce5SKent Overstreet return ptr >= s.v->ptrs + s.v->nr_blocks - s.v->nr_redundant 567e1036ce5SKent Overstreet ? BCH_DATA_parity 568e1036ce5SKent Overstreet : BCH_DATA_user; 569e1036ce5SKent Overstreet } 570e1036ce5SKent Overstreet default: 571e1036ce5SKent Overstreet BUG(); 572e1036ce5SKent Overstreet } 573e1036ce5SKent Overstreet } 574e1036ce5SKent Overstreet 57526609b61SKent Overstreet unsigned bch2_bkey_nr_ptrs(struct bkey_s_c); 5764de77495SKent Overstreet unsigned bch2_bkey_nr_ptrs_allocated(struct bkey_s_c); 5774de77495SKent Overstreet unsigned bch2_bkey_nr_ptrs_fully_allocated(struct bkey_s_c); 578ab05de4cSKent Overstreet bool bch2_bkey_is_incompressible(struct bkey_s_c); 5794de77495SKent Overstreet unsigned bch2_bkey_sectors_compressed(struct bkey_s_c); 58035a067b4SKent Overstreet 58135a067b4SKent Overstreet unsigned bch2_bkey_replicas(struct bch_fs *, struct bkey_s_c); 58226609b61SKent Overstreet unsigned bch2_bkey_durability(struct bch_fs *, struct bkey_s_c); 58326609b61SKent Overstreet 584*393a1f68SKent Overstreet void bch2_bkey_drop_device(struct bkey_s, unsigned); 585*393a1f68SKent Overstreet void bch2_bkey_drop_device_noerror(struct bkey_s, unsigned); 586*393a1f68SKent Overstreet const struct bch_extent_ptr *bch2_bkey_has_device(struct bkey_s_c, unsigned); 587*393a1f68SKent Overstreet bool bch2_bkey_has_target(struct bch_fs *, struct bkey_s_c, unsigned); 588*393a1f68SKent Overstreet 5890507962fSKent Overstreet void bch2_bkey_extent_entry_drop(struct bkey_i *, union bch_extent_entry *); 590*393a1f68SKent Overstreet 591*393a1f68SKent Overstreet static inline void bch2_bkey_append_ptr(struct bkey_i *k, struct bch_extent_ptr ptr) 592*393a1f68SKent Overstreet { 593*393a1f68SKent Overstreet EBUG_ON(bch2_bkey_has_device(bkey_i_to_s_c(k), ptr.dev)); 594*393a1f68SKent Overstreet 595*393a1f68SKent Overstreet switch (k->k.type) { 596*393a1f68SKent Overstreet case KEY_TYPE_btree_ptr: 597*393a1f68SKent Overstreet case KEY_TYPE_btree_ptr_v2: 598*393a1f68SKent Overstreet case KEY_TYPE_extent: 599*393a1f68SKent Overstreet EBUG_ON(bkey_val_u64s(&k->k) >= BKEY_EXTENT_VAL_U64s_MAX); 600*393a1f68SKent Overstreet 601*393a1f68SKent Overstreet ptr.type = 1 << BCH_EXTENT_ENTRY_ptr; 602*393a1f68SKent Overstreet 603*393a1f68SKent Overstreet memcpy((void *) &k->v + bkey_val_bytes(&k->k), 604*393a1f68SKent Overstreet &ptr, 605*393a1f68SKent Overstreet sizeof(ptr)); 606*393a1f68SKent Overstreet k->u64s++; 607*393a1f68SKent Overstreet break; 608*393a1f68SKent Overstreet default: 609*393a1f68SKent Overstreet BUG(); 610*393a1f68SKent Overstreet } 611*393a1f68SKent Overstreet } 612*393a1f68SKent Overstreet 61399aaf570SKent Overstreet void bch2_extent_ptr_decoded_append(struct bkey_i *, 61471c9e0baSKent Overstreet struct extent_ptr_decoded *); 61526609b61SKent Overstreet union bch_extent_entry *bch2_bkey_drop_ptr(struct bkey_s, 616a2753581SKent Overstreet struct bch_extent_ptr *); 617a2753581SKent Overstreet 61826609b61SKent Overstreet #define bch2_bkey_drop_ptrs(_k, _ptr, _cond) \ 619a2753581SKent Overstreet do { \ 62026609b61SKent Overstreet struct bkey_ptrs _ptrs = bch2_bkey_ptrs(_k); \ 621a2753581SKent Overstreet \ 62226609b61SKent Overstreet _ptr = &_ptrs.start->ptr; \ 62326609b61SKent Overstreet \ 62426609b61SKent Overstreet while ((_ptr = bkey_ptr_next(_ptrs, _ptr))) { \ 625a2753581SKent Overstreet if (_cond) { \ 62626609b61SKent Overstreet _ptr = (void *) bch2_bkey_drop_ptr(_k, _ptr); \ 62726609b61SKent Overstreet _ptrs = bch2_bkey_ptrs(_k); \ 628a2753581SKent Overstreet continue; \ 629a2753581SKent Overstreet } \ 630a2753581SKent Overstreet \ 631a2753581SKent Overstreet (_ptr)++; \ 632a2753581SKent Overstreet } \ 633a2753581SKent Overstreet } while (0) 6341c6fdbd8SKent Overstreet 6354de77495SKent Overstreet bool bch2_bkey_matches_ptr(struct bch_fs *, struct bkey_s_c, 6364de77495SKent Overstreet struct bch_extent_ptr, u64); 6377f5c5d20SKent Overstreet bool bch2_extents_match(struct bkey_s_c, struct bkey_s_c); 6387f5c5d20SKent Overstreet bool bch2_extent_has_ptr(struct bkey_s_c, struct extent_ptr_decoded, struct bkey_s_c); 6394de77495SKent Overstreet 6404de77495SKent Overstreet bool bch2_extent_normalize(struct bch_fs *, struct bkey_s); 6414de77495SKent Overstreet void bch2_bkey_ptrs_to_text(struct printbuf *, struct bch_fs *, 6424de77495SKent Overstreet struct bkey_s_c); 643275c8426SKent Overstreet int bch2_bkey_ptrs_invalid(const struct bch_fs *, struct bkey_s_c, 644275c8426SKent Overstreet int, struct printbuf *); 6454de77495SKent Overstreet 6461f49dafcSKent Overstreet void bch2_ptr_swab(struct bkey_s); 6474de77495SKent Overstreet 6484de77495SKent Overstreet /* Generic extent code: */ 6494de77495SKent Overstreet 6504cf91b02SKent Overstreet enum bch_extent_overlap { 6514cf91b02SKent Overstreet BCH_EXTENT_OVERLAP_ALL = 0, 6524cf91b02SKent Overstreet BCH_EXTENT_OVERLAP_BACK = 1, 6534cf91b02SKent Overstreet BCH_EXTENT_OVERLAP_FRONT = 2, 6544cf91b02SKent Overstreet BCH_EXTENT_OVERLAP_MIDDLE = 3, 6554cf91b02SKent Overstreet }; 6564cf91b02SKent Overstreet 6574cf91b02SKent Overstreet /* Returns how k overlaps with m */ 6584cf91b02SKent Overstreet static inline enum bch_extent_overlap bch2_extent_overlap(const struct bkey *k, 6594cf91b02SKent Overstreet const struct bkey *m) 6604cf91b02SKent Overstreet { 661e88a75ebSKent Overstreet int cmp1 = bkey_lt(k->p, m->p); 662e88a75ebSKent Overstreet int cmp2 = bkey_gt(bkey_start_pos(k), bkey_start_pos(m)); 6634cf91b02SKent Overstreet 6644cf91b02SKent Overstreet return (cmp1 << 1) + cmp2; 6654cf91b02SKent Overstreet } 6664cf91b02SKent Overstreet 667085ab693SKent Overstreet int bch2_cut_front_s(struct bpos, struct bkey_s); 668085ab693SKent Overstreet int bch2_cut_back_s(struct bpos, struct bkey_s); 6695b8a9227SKent Overstreet 670b1c9358aSKent Overstreet static inline void bch2_cut_front(struct bpos where, struct bkey_i *k) 6715b8a9227SKent Overstreet { 672085ab693SKent Overstreet bch2_cut_front_s(where, bkey_i_to_s(k)); 6735b8a9227SKent Overstreet } 6745b8a9227SKent Overstreet 675085ab693SKent Overstreet static inline void bch2_cut_back(struct bpos where, struct bkey_i *k) 676085ab693SKent Overstreet { 677085ab693SKent Overstreet bch2_cut_back_s(where, bkey_i_to_s(k)); 678085ab693SKent Overstreet } 6793fb5ebcdSKent Overstreet 6803fb5ebcdSKent Overstreet /** 6813fb5ebcdSKent Overstreet * bch_key_resize - adjust size of @k 6823fb5ebcdSKent Overstreet * 6833fb5ebcdSKent Overstreet * bkey_start_offset(k) will be preserved, modifies where the extent ends 6843fb5ebcdSKent Overstreet */ 6853fb5ebcdSKent Overstreet static inline void bch2_key_resize(struct bkey *k, unsigned new_size) 6863fb5ebcdSKent Overstreet { 6873fb5ebcdSKent Overstreet k->p.offset -= k->size; 6883fb5ebcdSKent Overstreet k->p.offset += new_size; 6893fb5ebcdSKent Overstreet k->size = new_size; 6903fb5ebcdSKent Overstreet } 6911c6fdbd8SKent Overstreet 6925b8a9227SKent Overstreet /* 6935b8a9227SKent Overstreet * In extent_sort_fix_overlapping(), insert_fixup_extent(), 6945b8a9227SKent Overstreet * extent_merge_inline() - we're modifying keys in place that are packed. To do 6955b8a9227SKent Overstreet * that we have to unpack the key, modify the unpacked key - then this 6965b8a9227SKent Overstreet * copies/repacks the unpacked to the original as necessary. 6975b8a9227SKent Overstreet */ 6985b8a9227SKent Overstreet static inline void extent_save(struct btree *b, struct bkey_packed *dst, 6995b8a9227SKent Overstreet struct bkey *src) 7005b8a9227SKent Overstreet { 7015b8a9227SKent Overstreet struct bkey_format *f = &b->format; 7025b8a9227SKent Overstreet struct bkey_i *dst_unpacked; 7035b8a9227SKent Overstreet 7045b8a9227SKent Overstreet if ((dst_unpacked = packed_to_bkey(dst))) 7055b8a9227SKent Overstreet dst_unpacked->k = *src; 7065b8a9227SKent Overstreet else 7075b8a9227SKent Overstreet BUG_ON(!bch2_bkey_pack_key(dst, src, f)); 7085b8a9227SKent Overstreet } 7095b8a9227SKent Overstreet 7101c6fdbd8SKent Overstreet #endif /* _BCACHEFS_EXTENTS_H */ 711