aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/libxfs
diff options
context:
space:
mode:
authorBrian Foster <bfoster@redhat.com>2015-04-12 21:27:10 -0400
committerDave Chinner <david@fromorbit.com>2015-04-12 21:27:10 -0400
commite87021a2bc100d330ae859c2cc0614be3e335c5a (patch)
treeccda58aff1bf2497ed11f2cc4bc6bbf37552f6ad /fs/xfs/libxfs
parent2f6612415436bab4d923a61d8df399b134247810 (diff)
xfs: use larger in-core attr firstused field and detect overflow
The on-disk xfs_attr3_leaf_hdr structure firstused field is 16-bit and subject to overflow when fs block size is 64k. The field is typically initialized to block size when an attr leaf block is initialized. This problem is demonstrated by assert failures when running xfstests generic/117 on an fs with 64k blocks. To support the existing attr leaf block algorithms for insertion, rebalance and entry movement, increase the size of the in-core firstused field to 32-bit and handle the potential overflow on conversion to/from the on-disk structure. If the overflow condition occurs, set a special value in the firstused field that is translated back on header read. The special value is only required in the case of an empty 64k attr block. A value of zero is used because firstused is initialized to the block size and grows backwards from there. Furthermore, the attribute block header occupies the first bytes of the block. Thus, a value of zero has no other legitimate meaning for this structure. Two new conversion helpers are created to manage the conversion of firstused to and from disk. Signed-off-by: Brian Foster <bfoster@redhat.com> Reviewed-by: Dave Chinner <dchinner@redhat.com> Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs/libxfs')
-rw-r--r--fs/xfs/libxfs/xfs_attr_leaf.c84
-rw-r--r--fs/xfs/libxfs/xfs_da_format.h14
2 files changed, 92 insertions, 6 deletions
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 3337516feeb0..149ef3f66735 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -86,6 +86,80 @@ STATIC void xfs_attr3_leaf_moveents(struct xfs_da_args *args,
86 int move_count); 86 int move_count);
87STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); 87STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
88 88
89/*
90 * attr3 block 'firstused' conversion helpers.
91 *
92 * firstused refers to the offset of the first used byte of the nameval region
93 * of an attr leaf block. The region starts at the tail of the block and expands
94 * backwards towards the middle. As such, firstused is initialized to the block
95 * size for an empty leaf block and is reduced from there.
96 *
97 * The attr3 block size is pegged to the fsb size and the maximum fsb is 64k.
98 * The in-core firstused field is 32-bit and thus supports the maximum fsb size.
99 * The on-disk field is only 16-bit, however, and overflows at 64k. Since this
100 * only occurs at exactly 64k, we use zero as a magic on-disk value to represent
101 * the attr block size. The following helpers manage the conversion between the
102 * in-core and on-disk formats.
103 */
104
105static void
106xfs_attr3_leaf_firstused_from_disk(
107 struct xfs_da_geometry *geo,
108 struct xfs_attr3_icleaf_hdr *to,
109 struct xfs_attr_leafblock *from)
110{
111 struct xfs_attr3_leaf_hdr *hdr3;
112
113 if (from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) {
114 hdr3 = (struct xfs_attr3_leaf_hdr *) from;
115 to->firstused = be16_to_cpu(hdr3->firstused);
116 } else {
117 to->firstused = be16_to_cpu(from->hdr.firstused);
118 }
119
120 /*
121 * Convert from the magic fsb size value to actual blocksize. This
122 * should only occur for empty blocks when the block size overflows
123 * 16-bits.
124 */
125 if (to->firstused == XFS_ATTR3_LEAF_NULLOFF) {
126 ASSERT(!to->count && !to->usedbytes);
127 ASSERT(geo->blksize > USHRT_MAX);
128 to->firstused = geo->blksize;
129 }
130}
131
132static void
133xfs_attr3_leaf_firstused_to_disk(
134 struct xfs_da_geometry *geo,
135 struct xfs_attr_leafblock *to,
136 struct xfs_attr3_icleaf_hdr *from)
137{
138 struct xfs_attr3_leaf_hdr *hdr3;
139 uint32_t firstused;
140
141 /* magic value should only be seen on disk */
142 ASSERT(from->firstused != XFS_ATTR3_LEAF_NULLOFF);
143
144 /*
145 * Scale down the 32-bit in-core firstused value to the 16-bit on-disk
146 * value. This only overflows at the max supported value of 64k. Use the
147 * magic on-disk value to represent block size in this case.
148 */
149 firstused = from->firstused;
150 if (firstused > USHRT_MAX) {
151 ASSERT(from->firstused == geo->blksize);
152 firstused = XFS_ATTR3_LEAF_NULLOFF;
153 }
154
155 if (from->magic == XFS_ATTR3_LEAF_MAGIC) {
156 hdr3 = (struct xfs_attr3_leaf_hdr *) to;
157 hdr3->firstused = cpu_to_be16(firstused);
158 } else {
159 to->hdr.firstused = cpu_to_be16(firstused);
160 }
161}
162
89void 163void
90xfs_attr3_leaf_hdr_from_disk( 164xfs_attr3_leaf_hdr_from_disk(
91 struct xfs_da_geometry *geo, 165 struct xfs_da_geometry *geo,
@@ -105,7 +179,7 @@ xfs_attr3_leaf_hdr_from_disk(
105 to->magic = be16_to_cpu(hdr3->info.hdr.magic); 179 to->magic = be16_to_cpu(hdr3->info.hdr.magic);
106 to->count = be16_to_cpu(hdr3->count); 180 to->count = be16_to_cpu(hdr3->count);
107 to->usedbytes = be16_to_cpu(hdr3->usedbytes); 181 to->usedbytes = be16_to_cpu(hdr3->usedbytes);
108 to->firstused = be16_to_cpu(hdr3->firstused); 182 xfs_attr3_leaf_firstused_from_disk(geo, to, from);
109 to->holes = hdr3->holes; 183 to->holes = hdr3->holes;
110 184
111 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { 185 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
@@ -119,7 +193,7 @@ xfs_attr3_leaf_hdr_from_disk(
119 to->magic = be16_to_cpu(from->hdr.info.magic); 193 to->magic = be16_to_cpu(from->hdr.info.magic);
120 to->count = be16_to_cpu(from->hdr.count); 194 to->count = be16_to_cpu(from->hdr.count);
121 to->usedbytes = be16_to_cpu(from->hdr.usedbytes); 195 to->usedbytes = be16_to_cpu(from->hdr.usedbytes);
122 to->firstused = be16_to_cpu(from->hdr.firstused); 196 xfs_attr3_leaf_firstused_from_disk(geo, to, from);
123 to->holes = from->hdr.holes; 197 to->holes = from->hdr.holes;
124 198
125 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) { 199 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
@@ -134,7 +208,7 @@ xfs_attr3_leaf_hdr_to_disk(
134 struct xfs_attr_leafblock *to, 208 struct xfs_attr_leafblock *to,
135 struct xfs_attr3_icleaf_hdr *from) 209 struct xfs_attr3_icleaf_hdr *from)
136{ 210{
137 int i; 211 int i;
138 212
139 ASSERT(from->magic == XFS_ATTR_LEAF_MAGIC || 213 ASSERT(from->magic == XFS_ATTR_LEAF_MAGIC ||
140 from->magic == XFS_ATTR3_LEAF_MAGIC); 214 from->magic == XFS_ATTR3_LEAF_MAGIC);
@@ -147,7 +221,7 @@ xfs_attr3_leaf_hdr_to_disk(
147 hdr3->info.hdr.magic = cpu_to_be16(from->magic); 221 hdr3->info.hdr.magic = cpu_to_be16(from->magic);
148 hdr3->count = cpu_to_be16(from->count); 222 hdr3->count = cpu_to_be16(from->count);
149 hdr3->usedbytes = cpu_to_be16(from->usedbytes); 223 hdr3->usedbytes = cpu_to_be16(from->usedbytes);
150 hdr3->firstused = cpu_to_be16(from->firstused); 224 xfs_attr3_leaf_firstused_to_disk(geo, to, from);
151 hdr3->holes = from->holes; 225 hdr3->holes = from->holes;
152 hdr3->pad1 = 0; 226 hdr3->pad1 = 0;
153 227
@@ -162,7 +236,7 @@ xfs_attr3_leaf_hdr_to_disk(
162 to->hdr.info.magic = cpu_to_be16(from->magic); 236 to->hdr.info.magic = cpu_to_be16(from->magic);
163 to->hdr.count = cpu_to_be16(from->count); 237 to->hdr.count = cpu_to_be16(from->count);
164 to->hdr.usedbytes = cpu_to_be16(from->usedbytes); 238 to->hdr.usedbytes = cpu_to_be16(from->usedbytes);
165 to->hdr.firstused = cpu_to_be16(from->firstused); 239 xfs_attr3_leaf_firstused_to_disk(geo, to, from);
166 to->hdr.holes = from->holes; 240 to->hdr.holes = from->holes;
167 to->hdr.pad1 = 0; 241 to->hdr.pad1 = 0;
168 242
diff --git a/fs/xfs/libxfs/xfs_da_format.h b/fs/xfs/libxfs/xfs_da_format.h
index 0a49b0286372..74bcbabfa523 100644
--- a/fs/xfs/libxfs/xfs_da_format.h
+++ b/fs/xfs/libxfs/xfs_da_format.h
@@ -725,7 +725,13 @@ struct xfs_attr3_icleaf_hdr {
725 __uint16_t magic; 725 __uint16_t magic;
726 __uint16_t count; 726 __uint16_t count;
727 __uint16_t usedbytes; 727 __uint16_t usedbytes;
728 __uint16_t firstused; 728 /*
729 * firstused is 32-bit here instead of 16-bit like the on-disk variant
730 * to support maximum fsb size of 64k without overflow issues throughout
731 * the attr code. Instead, the overflow condition is handled on
732 * conversion to/from disk.
733 */
734 __uint32_t firstused;
729 __u8 holes; 735 __u8 holes;
730 struct { 736 struct {
731 __uint16_t base; 737 __uint16_t base;
@@ -734,6 +740,12 @@ struct xfs_attr3_icleaf_hdr {
734}; 740};
735 741
736/* 742/*
743 * Special value to represent fs block size in the leaf header firstused field.
744 * Only used when block size overflows the 2-bytes available on disk.
745 */
746#define XFS_ATTR3_LEAF_NULLOFF 0
747
748/*
737 * Flags used in the leaf_entry[i].flags field. 749 * Flags used in the leaf_entry[i].flags field.
738 * NOTE: the INCOMPLETE bit must not collide with the flags bits specified 750 * NOTE: the INCOMPLETE bit must not collide with the flags bits specified
739 * on the system call, they are "or"ed together for various operations. 751 * on the system call, they are "or"ed together for various operations.