at v3.5 5.1 kB view raw
1/* 2 * Copyright (C) 2007 Oracle. All rights reserved. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public 6 * License v2 as published by the Free Software Foundation. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 11 * General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public 14 * License along with this program; if not, write to the 15 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 16 * Boston, MA 021110-1307, USA. 17 */ 18 19#include <linux/highmem.h> 20 21/* this is some deeply nasty code. ctree.h has a different 22 * definition for this BTRFS_SETGET_FUNCS macro, behind a #ifndef 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 * 27 * This file declares the macros and then #includes ctree.h, which results 28 * in cpp creating the function here based on the template below. 29 * 30 * These setget functions do all the extent_buffer related mapping 31 * required to efficiently read and write specific fields in the extent 32 * buffers. Every pointer to metadata items in btrfs is really just 33 * an unsigned long offset into the extent buffer which has been 34 * cast to a specific type. This gives us all the gcc type checking. 35 * 36 * The extent buffer api is used to do all the kmapping and page 37 * spanning work required to get extent buffers in highmem and have 38 * a metadata blocksize different from the page size. 39 * 40 * The macro starts with a simple function prototype declaration so that 41 * sparse won't complain about it being static. 42 */ 43 44#define BTRFS_SETGET_FUNCS(name, type, member, bits) \ 45u##bits btrfs_##name(struct extent_buffer *eb, type *s); \ 46void btrfs_set_##name(struct extent_buffer *eb, type *s, u##bits val); \ 47void btrfs_set_token_##name(struct extent_buffer *eb, type *s, u##bits val, struct btrfs_map_token *token); \ 48u##bits btrfs_token_##name(struct extent_buffer *eb, \ 49 type *s, struct btrfs_map_token *token) \ 50{ \ 51 unsigned long part_offset = (unsigned long)s; \ 52 unsigned long offset = part_offset + offsetof(type, member); \ 53 type *p; \ 54 int err; \ 55 char *kaddr; \ 56 unsigned long map_start; \ 57 unsigned long map_len; \ 58 unsigned long mem_len = sizeof(((type *)0)->member); \ 59 u##bits res; \ 60 if (token && token->kaddr && token->offset <= offset && \ 61 token->eb == eb && \ 62 (token->offset + PAGE_CACHE_SIZE >= offset + mem_len)) { \ 63 kaddr = token->kaddr; \ 64 p = (type *)(kaddr + part_offset - token->offset); \ 65 res = le##bits##_to_cpu(p->member); \ 66 return res; \ 67 } \ 68 err = map_private_extent_buffer(eb, offset, \ 69 mem_len, \ 70 &kaddr, &map_start, &map_len); \ 71 if (err) { \ 72 __le##bits leres; \ 73 read_eb_member(eb, s, type, member, &leres); \ 74 return le##bits##_to_cpu(leres); \ 75 } \ 76 p = (type *)(kaddr + part_offset - map_start); \ 77 res = le##bits##_to_cpu(p->member); \ 78 if (token) { \ 79 token->kaddr = kaddr; \ 80 token->offset = map_start; \ 81 token->eb = eb; \ 82 } \ 83 return res; \ 84} \ 85void btrfs_set_token_##name(struct extent_buffer *eb, \ 86 type *s, u##bits val, struct btrfs_map_token *token) \ 87{ \ 88 unsigned long part_offset = (unsigned long)s; \ 89 unsigned long offset = part_offset + offsetof(type, member); \ 90 type *p; \ 91 int err; \ 92 char *kaddr; \ 93 unsigned long map_start; \ 94 unsigned long map_len; \ 95 unsigned long mem_len = sizeof(((type *)0)->member); \ 96 if (token && token->kaddr && token->offset <= offset && \ 97 token->eb == eb && \ 98 (token->offset + PAGE_CACHE_SIZE >= offset + mem_len)) { \ 99 kaddr = token->kaddr; \ 100 p = (type *)(kaddr + part_offset - token->offset); \ 101 p->member = cpu_to_le##bits(val); \ 102 return; \ 103 } \ 104 err = map_private_extent_buffer(eb, offset, \ 105 mem_len, \ 106 &kaddr, &map_start, &map_len); \ 107 if (err) { \ 108 __le##bits val2; \ 109 val2 = cpu_to_le##bits(val); \ 110 write_eb_member(eb, s, type, member, &val2); \ 111 return; \ 112 } \ 113 p = (type *)(kaddr + part_offset - map_start); \ 114 p->member = cpu_to_le##bits(val); \ 115 if (token) { \ 116 token->kaddr = kaddr; \ 117 token->offset = map_start; \ 118 token->eb = eb; \ 119 } \ 120} \ 121void btrfs_set_##name(struct extent_buffer *eb, \ 122 type *s, u##bits val) \ 123{ \ 124 btrfs_set_token_##name(eb, s, val, NULL); \ 125} \ 126u##bits btrfs_##name(struct extent_buffer *eb, \ 127 type *s) \ 128{ \ 129 return btrfs_token_##name(eb, s, NULL); \ 130} \ 131 132#include "ctree.h" 133 134void btrfs_node_key(struct extent_buffer *eb, 135 struct btrfs_disk_key *disk_key, int nr) 136{ 137 unsigned long ptr = btrfs_node_key_ptr_offset(nr); 138 read_eb_member(eb, (struct btrfs_key_ptr *)ptr, 139 struct btrfs_key_ptr, key, disk_key); 140}