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