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

Configure Feed

Select the types of activity you want to include in your feed.

hfsplus: rework logic of map nodes creation in xattr b-tree

In hfsplus_init_header_node() when node_count > 63488
(header bitmap capacity), the code calculates map_nodes,
subtracts them from free_nodes, and marks their positions
used in the bitmap. However, it doesn't write the actual
map node structure (type, record offsets, bitmap) for
those physical positions, only node 0 is written.

This patch reworks hfsplus_create_attributes_file()
logic by introducing a specialized method of
hfsplus_init_map_node() and writing the allocated
map b-tree's nodes by means of
hfsplus_write_attributes_file_node() method.

cc: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
cc: Yangtao Li <frank.li@vivo.com>
cc: linux-fsdevel@vger.kernel.org
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>
Link: https://lore.kernel.org/r/20260403230556.614171-5-slava@dubeyko.com
Signed-off-by: Viacheslav Dubeyko <slava@dubeyko.com>

+106 -23
+104 -23
fs/hfsplus/xattr.c
··· 50 50 return true; 51 51 } 52 52 53 - static void hfsplus_init_header_node(struct inode *attr_file, 53 + static u32 hfsplus_init_header_node(struct inode *attr_file, 54 54 u32 clump_size, 55 55 char *buf, u16 node_size) 56 56 { ··· 59 59 u16 offset; 60 60 __be16 *rec_offsets; 61 61 u32 hdr_node_map_rec_bits; 62 + u32 map_nodes = 0; 62 63 char *bmp; 63 64 u32 used_nodes; 64 65 u32 used_bmp_bytes; ··· 94 93 hdr_node_map_rec_bits = 8 * (node_size - offset - (4 * sizeof(u16))); 95 94 if (be32_to_cpu(head->node_count) > hdr_node_map_rec_bits) { 96 95 u32 map_node_bits; 97 - u32 map_nodes; 98 96 99 97 desc->next = cpu_to_be32(be32_to_cpu(head->leaf_tail) + 1); 100 98 map_node_bits = 8 * (node_size - sizeof(struct hfs_bnode_desc) - ··· 116 116 *bmp = ~(0xFF >> used_nodes); 117 117 offset += hdr_node_map_rec_bits / 8; 118 118 *--rec_offsets = cpu_to_be16(offset); 119 + 120 + return map_nodes; 121 + } 122 + 123 + /* 124 + * Initialize a map node buffer. Map nodes have a single bitmap record. 125 + */ 126 + static void hfsplus_init_map_node(u8 *buf, u16 node_size, u32 next_node) 127 + { 128 + struct hfs_bnode_desc *desc; 129 + __be16 *rec_offsets; 130 + size_t rec_size = sizeof(__be16); 131 + u16 offset; 132 + 133 + memset(buf, 0, node_size); 134 + 135 + desc = (struct hfs_bnode_desc *)buf; 136 + desc->type = HFS_NODE_MAP; 137 + desc->num_recs = cpu_to_be16(1); 138 + desc->next = cpu_to_be32(next_node); 139 + 140 + /* 141 + * A map node consists of the node descriptor and a single 142 + * map record. The map record is a continuation of the map 143 + * record contained in the header node. The size of the map 144 + * record is the size of the node, minus the size of 145 + * the node descriptor (14 bytes), minus the size of two offsets 146 + * (4 bytes), minus two bytes of free space. That is, the size of 147 + * the map record is the size of the node minus 20 bytes; 148 + * this keeps the length of the map record an even multiple of 4 bytes. 149 + * The start of the map record is not aligned to a 4-byte boundary: 150 + * it starts immediately after the node descriptor 151 + * (at an offset of 14 bytes). 152 + * 153 + * Two record offsets stored at the end of the node: 154 + * record[1] = start of record 0 -> sizeof(hfs_bnode_desc) 155 + * record[2] = start of free space 156 + */ 157 + rec_offsets = (__be16 *)(buf + node_size); 158 + 159 + /* record #1 */ 160 + offset = sizeof(struct hfs_bnode_desc); 161 + *--rec_offsets = cpu_to_be16(offset); 162 + 163 + /* record #2 */ 164 + offset = node_size; 165 + offset -= (u16)HFSPLUS_BTREE_MAP_NODE_RECS_COUNT * rec_size; 166 + offset -= HFSPLUS_BTREE_MAP_NODE_RESERVED_BYTES; 167 + *--rec_offsets = cpu_to_be16(offset); 168 + } 169 + 170 + static inline 171 + int hfsplus_write_attributes_file_node(struct inode *attr_file, char *buf, 172 + u16 node_size, int *index) 173 + { 174 + struct address_space *mapping; 175 + struct page *page; 176 + void *kaddr; 177 + u32 written = 0; 178 + 179 + mapping = attr_file->i_mapping; 180 + 181 + for (; written < node_size; (*index)++, written += PAGE_SIZE) { 182 + page = read_mapping_page(mapping, *index, NULL); 183 + if (IS_ERR(page)) 184 + return PTR_ERR(page); 185 + 186 + kaddr = kmap_local_page(page); 187 + memcpy(kaddr, buf + written, 188 + min_t(size_t, PAGE_SIZE, node_size - written)); 189 + kunmap_local(kaddr); 190 + 191 + set_page_dirty(page); 192 + put_page(page); 193 + } 194 + 195 + return 0; 119 196 } 120 197 121 198 static int hfsplus_create_attributes_file(struct super_block *sb) 122 199 { 123 - int err = 0; 124 200 struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb); 125 201 struct inode *attr_file; 126 202 struct hfsplus_inode_info *hip; 203 + struct hfs_bnode_desc *desc; 127 204 u32 clump_size; 128 205 u16 node_size = HFSPLUS_ATTR_TREE_NODE_SIZE; 206 + u32 next_node; 207 + u32 map_node_idx; 208 + u32 map_nodes; 129 209 char *buf; 130 - int index, written; 131 - struct address_space *mapping; 132 - struct page *page; 210 + int index; 133 211 int old_state = HFSPLUS_EMPTY_ATTR_TREE; 212 + int err = 0; 134 213 135 214 hfs_dbg("ino %d\n", HFSPLUS_ATTR_CNID); 136 215 ··· 274 195 } 275 196 276 197 while (hip->alloc_blocks < hip->clump_blocks) { 277 - err = hfsplus_file_extend(attr_file, false); 198 + err = hfsplus_file_extend(attr_file, true); 278 199 if (unlikely(err)) { 279 200 pr_err("failed to extend attributes file\n"); 280 201 goto end_attr_file_creation; ··· 291 212 goto end_attr_file_creation; 292 213 } 293 214 294 - hfsplus_init_header_node(attr_file, clump_size, buf, node_size); 215 + map_nodes = hfsplus_init_header_node(attr_file, clump_size, buf, node_size); 295 216 296 - mapping = attr_file->i_mapping; 217 + desc = (struct hfs_bnode_desc *)buf; 218 + next_node = be32_to_cpu(desc->next); 297 219 298 220 index = 0; 299 - written = 0; 300 - for (; written < node_size; index++, written += PAGE_SIZE) { 301 - void *kaddr; 302 221 303 - page = read_mapping_page(mapping, index, NULL); 304 - if (IS_ERR(page)) { 305 - err = PTR_ERR(page); 222 + err = hfsplus_write_attributes_file_node(attr_file, buf, 223 + node_size, &index); 224 + if (unlikely(err)) 225 + goto failed_header_node_init; 226 + 227 + for (map_node_idx = 0; map_node_idx < map_nodes; map_node_idx++) { 228 + if (next_node >= map_nodes) 229 + next_node = 0; 230 + 231 + hfsplus_init_map_node(buf, node_size, next_node); 232 + 233 + err = hfsplus_write_attributes_file_node(attr_file, buf, 234 + node_size, &index); 235 + if (unlikely(err)) 306 236 goto failed_header_node_init; 307 - } 308 237 309 - kaddr = kmap_atomic(page); 310 - memcpy(kaddr, buf + written, 311 - min_t(size_t, PAGE_SIZE, node_size - written)); 312 - kunmap_atomic(kaddr); 313 - 314 - set_page_dirty(page); 315 - put_page(page); 238 + next_node++; 316 239 } 317 240 318 241 hfsplus_mark_inode_dirty(HFSPLUS_ATTR_TREE_I(sb), HFSPLUS_I_ATTR_DIRTY);
+2
include/linux/hfs_common.h
··· 518 518 #define HFSPLUS_BTREE_HDR_MAP_REC_INDEX 2 /* Map (bitmap) record in Header node */ 519 519 #define HFSPLUS_BTREE_MAP_NODE_REC_INDEX 0 /* Map record in Map Node */ 520 520 #define HFSPLUS_BTREE_HDR_USER_BYTES 128 521 + #define HFSPLUS_BTREE_MAP_NODE_RECS_COUNT 2 522 + #define HFSPLUS_BTREE_MAP_NODE_RESERVED_BYTES 2 521 523 522 524 /* btree key type */ 523 525 #define HFSPLUS_KEY_CASEFOLDING 0xCF /* case-insensitive */