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

bcachefs: improve validate_bset_keys()

Signed-off-by: Kent Overstreet <kent.overstreet@linux.dev>

+55 -20
+55 -20
fs/bcachefs/btree_io.c
··· 524 524 prt_printf(out, "at btree "); 525 525 bch2_btree_pos_to_text(out, c, b); 526 526 527 - prt_printf(out, "\n node offset %u", b->written); 527 + prt_printf(out, "\n node offset %u/%u", 528 + b->written, btree_ptr_sectors_written(&b->key)); 528 529 if (i) 529 530 prt_printf(out, " bset u64s %u", le16_to_cpu(i->u64s)); 530 531 prt_str(out, ": "); ··· 831 830 (rw == WRITE ? bch2_bkey_val_invalid(c, k, READ, err) : 0); 832 831 } 833 832 833 + static bool __bkey_valid(struct bch_fs *c, struct btree *b, 834 + struct bset *i, struct bkey_packed *k) 835 + { 836 + if (bkey_p_next(k) > vstruct_last(i)) 837 + return false; 838 + 839 + if (k->format > KEY_FORMAT_CURRENT) 840 + return false; 841 + 842 + struct printbuf buf = PRINTBUF; 843 + struct bkey tmp; 844 + struct bkey_s u = __bkey_disassemble(b, k, &tmp); 845 + bool ret = __bch2_bkey_invalid(c, u.s_c, btree_node_type(b), READ, &buf); 846 + printbuf_exit(&buf); 847 + return ret; 848 + } 849 + 834 850 static int validate_bset_keys(struct bch_fs *c, struct btree *b, 835 851 struct bset *i, int write, 836 852 bool have_retry, bool *saw_error) ··· 863 845 k != vstruct_last(i);) { 864 846 struct bkey_s u; 865 847 struct bkey tmp; 848 + unsigned next_good_key; 866 849 867 850 if (btree_err_on(bkey_p_next(k) > vstruct_last(i), 868 851 -BCH_ERR_btree_node_read_err_fixable, ··· 878 859 -BCH_ERR_btree_node_read_err_fixable, 879 860 c, NULL, b, i, 880 861 btree_node_bkey_bad_format, 881 - "invalid bkey format %u", k->format)) { 882 - i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s); 883 - memmove_u64s_down(k, bkey_p_next(k), 884 - (u64 *) vstruct_end(i) - (u64 *) k); 885 - continue; 886 - } 862 + "invalid bkey format %u", k->format)) 863 + goto drop_this_key; 887 864 888 865 /* XXX: validate k->u64s */ 889 866 if (!write) ··· 900 885 c, NULL, b, i, 901 886 btree_node_bad_bkey, 902 887 "invalid bkey: %s", buf.buf); 903 - 904 - i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s); 905 - memmove_u64s_down(k, bkey_p_next(k), 906 - (u64 *) vstruct_end(i) - (u64 *) k); 907 - continue; 888 + goto drop_this_key; 908 889 } 909 890 910 891 if (write) ··· 917 906 prt_printf(&buf, " > "); 918 907 bch2_bkey_to_text(&buf, u.k); 919 908 920 - bch2_dump_bset(c, b, i, 0); 921 - 922 909 if (btree_err(-BCH_ERR_btree_node_read_err_fixable, 923 910 c, NULL, b, i, 924 911 btree_node_bkey_out_of_order, 925 - "%s", buf.buf)) { 926 - i->u64s = cpu_to_le16(le16_to_cpu(i->u64s) - k->u64s); 927 - memmove_u64s_down(k, bkey_p_next(k), 928 - (u64 *) vstruct_end(i) - (u64 *) k); 929 - continue; 930 - } 912 + "%s", buf.buf)) 913 + goto drop_this_key; 931 914 } 932 915 933 916 prev = k; 934 917 k = bkey_p_next(k); 918 + continue; 919 + drop_this_key: 920 + next_good_key = k->u64s; 921 + 922 + if (!next_good_key || 923 + (BSET_BIG_ENDIAN(i) == CPU_BIG_ENDIAN && 924 + version >= bcachefs_metadata_version_snapshot)) { 925 + /* 926 + * only do scanning if bch2_bkey_compat() has nothing to 927 + * do 928 + */ 929 + 930 + if (!__bkey_valid(c, b, i, (void *) ((u64 *) k + next_good_key))) { 931 + for (next_good_key = 1; 932 + next_good_key < (u64 *) vstruct_last(i) - (u64 *) k; 933 + next_good_key++) 934 + if (__bkey_valid(c, b, i, (void *) ((u64 *) k + next_good_key))) 935 + goto got_good_key; 936 + 937 + } 938 + 939 + /* 940 + * didn't find a good key, have to truncate the rest of 941 + * the bset 942 + */ 943 + next_good_key = (u64 *) vstruct_last(i) - (u64 *) k; 944 + } 945 + got_good_key: 946 + le16_add_cpu(&i->u64s, -next_good_key); 947 + memmove_u64s_down(k, bkey_p_next(k), (u64 *) vstruct_end(i) - (u64 *) k); 935 948 } 936 949 fsck_err: 937 950 printbuf_exit(&buf);