accessors.c 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2007 Oracle. All rights reserved.
  4. */
  5. #include <linux/unaligned.h>
  6. #include "messages.h"
  7. #include "extent_io.h"
  8. #include "fs.h"
  9. #include "accessors.h"
  10. static void __cold report_setget_bounds(const struct extent_buffer *eb,
  11. const void *ptr, unsigned off, int size)
  12. {
  13. unsigned long member_offset = (unsigned long)ptr + off;
  14. btrfs_warn(eb->fs_info,
  15. "bad eb member %s: ptr 0x%lx start %llu member offset %lu size %d",
  16. (member_offset > eb->len ? "start" : "end"),
  17. (unsigned long)ptr, eb->start, member_offset, size);
  18. }
  19. /* Copy bytes from @src1 and @src2 to @dest. */
  20. static __always_inline void memcpy_split_src(char *dest, const char *src1,
  21. const char *src2, const size_t len1,
  22. const size_t total)
  23. {
  24. memcpy(dest, src1, len1);
  25. memcpy(dest + len1, src2, total - len1);
  26. }
  27. /*
  28. * Macro templates that define helpers to read/write extent buffer data of a
  29. * given size, that are also used via ctree.h for access to item members by
  30. * specialized helpers.
  31. *
  32. * Generic helpers:
  33. * - btrfs_set_8 (for 8/16/32/64)
  34. * - btrfs_get_8 (for 8/16/32/64)
  35. *
  36. * The set/get functions handle data spanning two pages transparently, in case
  37. * metadata block size is larger than page. Every pointer to metadata items is
  38. * an offset into the extent buffer page array, cast to a specific type. This
  39. * gives us all the type checking.
  40. *
  41. * The extent buffer pages stored in the array folios may not form a contiguous
  42. * physical range, but the API functions assume the linear offset to the range
  43. * from 0 to metadata node size.
  44. */
  45. #define DEFINE_BTRFS_SETGET_BITS(bits) \
  46. u##bits btrfs_get_##bits(const struct extent_buffer *eb, \
  47. const void *ptr, unsigned long off) \
  48. { \
  49. const unsigned long member_offset = (unsigned long)ptr + off; \
  50. const unsigned long idx = get_eb_folio_index(eb, member_offset);\
  51. const unsigned long oif = get_eb_offset_in_folio(eb, \
  52. member_offset);\
  53. char *kaddr = folio_address(eb->folios[idx]) + oif; \
  54. const int part = eb->folio_size - oif; \
  55. u8 lebytes[sizeof(u##bits)]; \
  56. \
  57. if (unlikely(member_offset + sizeof(u##bits) > eb->len)) { \
  58. report_setget_bounds(eb, ptr, off, sizeof(u##bits)); \
  59. return 0; \
  60. } \
  61. if (INLINE_EXTENT_BUFFER_PAGES == 1 || sizeof(u##bits) == 1 || \
  62. likely(sizeof(u##bits) <= part)) \
  63. return get_unaligned_le##bits(kaddr); \
  64. \
  65. if (sizeof(u##bits) == 2) { \
  66. lebytes[0] = *kaddr; \
  67. kaddr = folio_address(eb->folios[idx + 1]); \
  68. lebytes[1] = *kaddr; \
  69. } else { \
  70. memcpy_split_src(lebytes, kaddr, \
  71. folio_address(eb->folios[idx + 1]), \
  72. part, sizeof(u##bits)); \
  73. } \
  74. return get_unaligned_le##bits(lebytes); \
  75. } \
  76. void btrfs_set_##bits(const struct extent_buffer *eb, void *ptr, \
  77. unsigned long off, u##bits val) \
  78. { \
  79. const unsigned long member_offset = (unsigned long)ptr + off; \
  80. const unsigned long idx = get_eb_folio_index(eb, member_offset);\
  81. const unsigned long oif = get_eb_offset_in_folio(eb, \
  82. member_offset);\
  83. char *kaddr = folio_address(eb->folios[idx]) + oif; \
  84. const int part = eb->folio_size - oif; \
  85. u8 lebytes[sizeof(u##bits)]; \
  86. \
  87. if (unlikely(member_offset + sizeof(u##bits) > eb->len)) { \
  88. report_setget_bounds(eb, ptr, off, sizeof(u##bits)); \
  89. return; \
  90. } \
  91. if (INLINE_EXTENT_BUFFER_PAGES == 1 || sizeof(u##bits) == 1 || \
  92. likely(sizeof(u##bits) <= part)) { \
  93. put_unaligned_le##bits(val, kaddr); \
  94. return; \
  95. } \
  96. put_unaligned_le##bits(val, lebytes); \
  97. if (sizeof(u##bits) == 2) { \
  98. *kaddr = lebytes[0]; \
  99. kaddr = folio_address(eb->folios[idx + 1]); \
  100. *kaddr = lebytes[1]; \
  101. } else { \
  102. memcpy(kaddr, lebytes, part); \
  103. kaddr = folio_address(eb->folios[idx + 1]); \
  104. memcpy(kaddr, lebytes + part, sizeof(u##bits) - part); \
  105. } \
  106. }
  107. DEFINE_BTRFS_SETGET_BITS(8)
  108. DEFINE_BTRFS_SETGET_BITS(16)
  109. DEFINE_BTRFS_SETGET_BITS(32)
  110. DEFINE_BTRFS_SETGET_BITS(64)
  111. void btrfs_node_key(const struct extent_buffer *eb,
  112. struct btrfs_disk_key *disk_key, int nr)
  113. {
  114. unsigned long ptr = btrfs_node_key_ptr_offset(eb, nr);
  115. read_eb_member(eb, (struct btrfs_key_ptr *)ptr,
  116. struct btrfs_key_ptr, key, disk_key);
  117. }