struct-funcs.c (6392B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2007 Oracle. All rights reserved. 4 */ 5 6#include <asm/unaligned.h> 7 8#include "ctree.h" 9 10static bool check_setget_bounds(const struct extent_buffer *eb, 11 const void *ptr, unsigned off, int size) 12{ 13 const unsigned long member_offset = (unsigned long)ptr + off; 14 15 if (member_offset > eb->len) { 16 btrfs_warn(eb->fs_info, 17 "bad eb member start: ptr 0x%lx start %llu member offset %lu size %d", 18 (unsigned long)ptr, eb->start, member_offset, size); 19 return false; 20 } 21 if (member_offset + size > eb->len) { 22 btrfs_warn(eb->fs_info, 23 "bad eb member end: ptr 0x%lx start %llu member offset %lu size %d", 24 (unsigned long)ptr, eb->start, member_offset, size); 25 return false; 26 } 27 28 return true; 29} 30 31/* 32 * Macro templates that define helpers to read/write extent buffer data of a 33 * given size, that are also used via ctree.h for access to item members by 34 * specialized helpers. 35 * 36 * Generic helpers: 37 * - btrfs_set_8 (for 8/16/32/64) 38 * - btrfs_get_8 (for 8/16/32/64) 39 * 40 * Generic helpers with a token (cached address of the most recently accessed 41 * page): 42 * - btrfs_set_token_8 (for 8/16/32/64) 43 * - btrfs_get_token_8 (for 8/16/32/64) 44 * 45 * The set/get functions handle data spanning two pages transparently, in case 46 * metadata block size is larger than page. Every pointer to metadata items is 47 * an offset into the extent buffer page array, cast to a specific type. This 48 * gives us all the type checking. 49 * 50 * The extent buffer pages stored in the array pages do not form a contiguous 51 * phyusical range, but the API functions assume the linear offset to the range 52 * from 0 to metadata node size. 53 */ 54 55#define DEFINE_BTRFS_SETGET_BITS(bits) \ 56u##bits btrfs_get_token_##bits(struct btrfs_map_token *token, \ 57 const void *ptr, unsigned long off) \ 58{ \ 59 const unsigned long member_offset = (unsigned long)ptr + off; \ 60 const unsigned long idx = get_eb_page_index(member_offset); \ 61 const unsigned long oip = get_eb_offset_in_page(token->eb, \ 62 member_offset); \ 63 const int size = sizeof(u##bits); \ 64 u8 lebytes[sizeof(u##bits)]; \ 65 const int part = PAGE_SIZE - oip; \ 66 \ 67 ASSERT(token); \ 68 ASSERT(token->kaddr); \ 69 ASSERT(check_setget_bounds(token->eb, ptr, off, size)); \ 70 if (token->offset <= member_offset && \ 71 member_offset + size <= token->offset + PAGE_SIZE) { \ 72 return get_unaligned_le##bits(token->kaddr + oip); \ 73 } \ 74 token->kaddr = page_address(token->eb->pages[idx]); \ 75 token->offset = idx << PAGE_SHIFT; \ 76 if (INLINE_EXTENT_BUFFER_PAGES == 1 || oip + size <= PAGE_SIZE ) \ 77 return get_unaligned_le##bits(token->kaddr + oip); \ 78 \ 79 memcpy(lebytes, token->kaddr + oip, part); \ 80 token->kaddr = page_address(token->eb->pages[idx + 1]); \ 81 token->offset = (idx + 1) << PAGE_SHIFT; \ 82 memcpy(lebytes + part, token->kaddr, size - part); \ 83 return get_unaligned_le##bits(lebytes); \ 84} \ 85u##bits btrfs_get_##bits(const struct extent_buffer *eb, \ 86 const void *ptr, unsigned long off) \ 87{ \ 88 const unsigned long member_offset = (unsigned long)ptr + off; \ 89 const unsigned long oip = get_eb_offset_in_page(eb, member_offset); \ 90 const unsigned long idx = get_eb_page_index(member_offset); \ 91 char *kaddr = page_address(eb->pages[idx]); \ 92 const int size = sizeof(u##bits); \ 93 const int part = PAGE_SIZE - oip; \ 94 u8 lebytes[sizeof(u##bits)]; \ 95 \ 96 ASSERT(check_setget_bounds(eb, ptr, off, size)); \ 97 if (INLINE_EXTENT_BUFFER_PAGES == 1 || oip + size <= PAGE_SIZE) \ 98 return get_unaligned_le##bits(kaddr + oip); \ 99 \ 100 memcpy(lebytes, kaddr + oip, part); \ 101 kaddr = page_address(eb->pages[idx + 1]); \ 102 memcpy(lebytes + part, kaddr, size - part); \ 103 return get_unaligned_le##bits(lebytes); \ 104} \ 105void btrfs_set_token_##bits(struct btrfs_map_token *token, \ 106 const void *ptr, unsigned long off, \ 107 u##bits val) \ 108{ \ 109 const unsigned long member_offset = (unsigned long)ptr + off; \ 110 const unsigned long idx = get_eb_page_index(member_offset); \ 111 const unsigned long oip = get_eb_offset_in_page(token->eb, \ 112 member_offset); \ 113 const int size = sizeof(u##bits); \ 114 u8 lebytes[sizeof(u##bits)]; \ 115 const int part = PAGE_SIZE - oip; \ 116 \ 117 ASSERT(token); \ 118 ASSERT(token->kaddr); \ 119 ASSERT(check_setget_bounds(token->eb, ptr, off, size)); \ 120 if (token->offset <= member_offset && \ 121 member_offset + size <= token->offset + PAGE_SIZE) { \ 122 put_unaligned_le##bits(val, token->kaddr + oip); \ 123 return; \ 124 } \ 125 token->kaddr = page_address(token->eb->pages[idx]); \ 126 token->offset = idx << PAGE_SHIFT; \ 127 if (INLINE_EXTENT_BUFFER_PAGES == 1 || oip + size <= PAGE_SIZE) { \ 128 put_unaligned_le##bits(val, token->kaddr + oip); \ 129 return; \ 130 } \ 131 put_unaligned_le##bits(val, lebytes); \ 132 memcpy(token->kaddr + oip, lebytes, part); \ 133 token->kaddr = page_address(token->eb->pages[idx + 1]); \ 134 token->offset = (idx + 1) << PAGE_SHIFT; \ 135 memcpy(token->kaddr, lebytes + part, size - part); \ 136} \ 137void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr, \ 138 unsigned long off, u##bits val) \ 139{ \ 140 const unsigned long member_offset = (unsigned long)ptr + off; \ 141 const unsigned long oip = get_eb_offset_in_page(eb, member_offset); \ 142 const unsigned long idx = get_eb_page_index(member_offset); \ 143 char *kaddr = page_address(eb->pages[idx]); \ 144 const int size = sizeof(u##bits); \ 145 const int part = PAGE_SIZE - oip; \ 146 u8 lebytes[sizeof(u##bits)]; \ 147 \ 148 ASSERT(check_setget_bounds(eb, ptr, off, size)); \ 149 if (INLINE_EXTENT_BUFFER_PAGES == 1 || oip + size <= PAGE_SIZE) { \ 150 put_unaligned_le##bits(val, kaddr + oip); \ 151 return; \ 152 } \ 153 \ 154 put_unaligned_le##bits(val, lebytes); \ 155 memcpy(kaddr + oip, lebytes, part); \ 156 kaddr = page_address(eb->pages[idx + 1]); \ 157 memcpy(kaddr, lebytes + part, size - part); \ 158} 159 160DEFINE_BTRFS_SETGET_BITS(8) 161DEFINE_BTRFS_SETGET_BITS(16) 162DEFINE_BTRFS_SETGET_BITS(32) 163DEFINE_BTRFS_SETGET_BITS(64) 164 165void btrfs_node_key(const struct extent_buffer *eb, 166 struct btrfs_disk_key *disk_key, int nr) 167{ 168 unsigned long ptr = btrfs_node_key_ptr_offset(nr); 169 read_eb_member(eb, (struct btrfs_key_ptr *)ptr, 170 struct btrfs_key_ptr, key, disk_key); 171}