at v4.18 130 lines 4.0 kB view raw
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Copyright (C) 2007 Oracle. All rights reserved. 4 */ 5 6#include <linux/highmem.h> 7#include <asm/unaligned.h> 8 9#include "ctree.h" 10 11static inline u8 get_unaligned_le8(const void *p) 12{ 13 return *(u8 *)p; 14} 15 16static inline void put_unaligned_le8(u8 val, void *p) 17{ 18 *(u8 *)p = val; 19} 20 21/* 22 * this is some deeply nasty code. 23 * 24 * The end result is that anyone who #includes ctree.h gets a 25 * declaration for the btrfs_set_foo functions and btrfs_foo functions, 26 * which are wrappers of btrfs_set_token_#bits functions and 27 * btrfs_get_token_#bits functions, which are defined in this file. 28 * 29 * These setget functions do all the extent_buffer related mapping 30 * required to efficiently read and write specific fields in the extent 31 * buffers. Every pointer to metadata items in btrfs is really just 32 * an unsigned long offset into the extent buffer which has been 33 * cast to a specific type. This gives us all the gcc type checking. 34 * 35 * The extent buffer api is used to do the page spanning work required to 36 * have a metadata blocksize different from the page size. 37 */ 38 39#define DEFINE_BTRFS_SETGET_BITS(bits) \ 40u##bits btrfs_get_token_##bits(const struct extent_buffer *eb, \ 41 const void *ptr, unsigned long off, \ 42 struct btrfs_map_token *token) \ 43{ \ 44 unsigned long part_offset = (unsigned long)ptr; \ 45 unsigned long offset = part_offset + off; \ 46 void *p; \ 47 int err; \ 48 char *kaddr; \ 49 unsigned long map_start; \ 50 unsigned long map_len; \ 51 int size = sizeof(u##bits); \ 52 u##bits res; \ 53 \ 54 if (token && token->kaddr && token->offset <= offset && \ 55 token->eb == eb && \ 56 (token->offset + PAGE_SIZE >= offset + size)) { \ 57 kaddr = token->kaddr; \ 58 p = kaddr + part_offset - token->offset; \ 59 res = get_unaligned_le##bits(p + off); \ 60 return res; \ 61 } \ 62 err = map_private_extent_buffer(eb, offset, size, \ 63 &kaddr, &map_start, &map_len); \ 64 if (err) { \ 65 __le##bits leres; \ 66 \ 67 read_extent_buffer(eb, &leres, offset, size); \ 68 return le##bits##_to_cpu(leres); \ 69 } \ 70 p = kaddr + part_offset - map_start; \ 71 res = get_unaligned_le##bits(p + off); \ 72 if (token) { \ 73 token->kaddr = kaddr; \ 74 token->offset = map_start; \ 75 token->eb = eb; \ 76 } \ 77 return res; \ 78} \ 79void btrfs_set_token_##bits(struct extent_buffer *eb, \ 80 const void *ptr, unsigned long off, \ 81 u##bits val, \ 82 struct btrfs_map_token *token) \ 83{ \ 84 unsigned long part_offset = (unsigned long)ptr; \ 85 unsigned long offset = part_offset + off; \ 86 void *p; \ 87 int err; \ 88 char *kaddr; \ 89 unsigned long map_start; \ 90 unsigned long map_len; \ 91 int size = sizeof(u##bits); \ 92 \ 93 if (token && token->kaddr && token->offset <= offset && \ 94 token->eb == eb && \ 95 (token->offset + PAGE_SIZE >= offset + size)) { \ 96 kaddr = token->kaddr; \ 97 p = kaddr + part_offset - token->offset; \ 98 put_unaligned_le##bits(val, p + off); \ 99 return; \ 100 } \ 101 err = map_private_extent_buffer(eb, offset, size, \ 102 &kaddr, &map_start, &map_len); \ 103 if (err) { \ 104 __le##bits val2; \ 105 \ 106 val2 = cpu_to_le##bits(val); \ 107 write_extent_buffer(eb, &val2, offset, size); \ 108 return; \ 109 } \ 110 p = kaddr + part_offset - map_start; \ 111 put_unaligned_le##bits(val, p + off); \ 112 if (token) { \ 113 token->kaddr = kaddr; \ 114 token->offset = map_start; \ 115 token->eb = eb; \ 116 } \ 117} 118 119DEFINE_BTRFS_SETGET_BITS(8) 120DEFINE_BTRFS_SETGET_BITS(16) 121DEFINE_BTRFS_SETGET_BITS(32) 122DEFINE_BTRFS_SETGET_BITS(64) 123 124void btrfs_node_key(const struct extent_buffer *eb, 125 struct btrfs_disk_key *disk_key, int nr) 126{ 127 unsigned long ptr = btrfs_node_key_ptr_offset(nr); 128 read_eb_member(eb, (struct btrfs_key_ptr *)ptr, 129 struct btrfs_key_ptr, key, disk_key); 130}