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