blob: 6eda1828a079ce3eec6997a38744f61b3cc5db17 [file] [log] [blame]
Dave Chinner0b61f8a2018-06-05 19:42:14 -07001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
Nathan Scott7b718762005-11-02 14:58:39 +11003 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
Dave Chinner517c2222013-04-24 18:58:55 +10004 * Copyright (c) 2013 Red Hat, Inc.
Nathan Scott7b718762005-11-02 14:58:39 +11005 * All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07006 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07007#include "xfs.h"
Nathan Scotta844f452005-11-02 14:38:42 +11008#include "xfs_fs.h"
Dave Chinner632b89e2013-10-29 22:11:58 +11009#include "xfs_shared.h"
Dave Chinnera4fbe6a2013-10-23 10:51:50 +110010#include "xfs_format.h"
Dave Chinner239880e2013-10-23 10:50:10 +110011#include "xfs_log_format.h"
12#include "xfs_trans_resv.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include "xfs_sb.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070014#include "xfs_mount.h"
Dave Chinner57062782013-10-15 09:17:51 +110015#include "xfs_da_format.h"
Nathan Scotta844f452005-11-02 14:38:42 +110016#include "xfs_da_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include "xfs_inode.h"
Dave Chinner239880e2013-10-23 10:50:10 +110018#include "xfs_trans.h"
Dave Chinnera4fbe6a2013-10-23 10:51:50 +110019#include "xfs_bmap_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include "xfs_bmap.h"
Dave Chinnera4fbe6a2013-10-23 10:51:50 +110021#include "xfs_attr_sf.h"
22#include "xfs_attr_remote.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include "xfs_attr.h"
24#include "xfs_attr_leaf.h"
25#include "xfs_error.h"
Christoph Hellwig0b1b2132009-12-14 23:14:59 +000026#include "xfs_trace.h"
Dave Chinner517c2222013-04-24 18:58:55 +100027#include "xfs_buf_item.h"
Dave Chinner4bceb182013-10-29 22:11:51 +110028#include "xfs_dir2.h"
Brian Fostera45086e2015-10-12 15:59:25 +110029#include "xfs_log.h"
Dave Chinner517c2222013-04-24 18:58:55 +100030
Linus Torvalds1da177e2005-04-16 15:20:36 -070031
32/*
33 * xfs_attr_leaf.c
34 *
35 * Routines to implement leaf blocks of attributes as Btrees of hashed names.
36 */
37
38/*========================================================================
39 * Function prototypes for the kernel.
40 *========================================================================*/
41
42/*
43 * Routines used for growing the Btree.
44 */
Dave Chinner517c2222013-04-24 18:58:55 +100045STATIC int xfs_attr3_leaf_create(struct xfs_da_args *args,
46 xfs_dablk_t which_block, struct xfs_buf **bpp);
47STATIC int xfs_attr3_leaf_add_work(struct xfs_buf *leaf_buffer,
48 struct xfs_attr3_icleaf_hdr *ichdr,
49 struct xfs_da_args *args, int freemap_index);
50STATIC void xfs_attr3_leaf_compact(struct xfs_da_args *args,
51 struct xfs_attr3_icleaf_hdr *ichdr,
52 struct xfs_buf *leaf_buffer);
53STATIC void xfs_attr3_leaf_rebalance(xfs_da_state_t *state,
Linus Torvalds1da177e2005-04-16 15:20:36 -070054 xfs_da_state_blk_t *blk1,
55 xfs_da_state_blk_t *blk2);
Dave Chinner517c2222013-04-24 18:58:55 +100056STATIC int xfs_attr3_leaf_figure_balance(xfs_da_state_t *state,
57 xfs_da_state_blk_t *leaf_blk_1,
58 struct xfs_attr3_icleaf_hdr *ichdr1,
59 xfs_da_state_blk_t *leaf_blk_2,
60 struct xfs_attr3_icleaf_hdr *ichdr2,
61 int *number_entries_in_blk1,
62 int *number_usedbytes_in_blk1);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063
64/*
65 * Utility routines.
66 */
Dave Chinnerc2c4c472014-06-06 15:21:45 +100067STATIC void xfs_attr3_leaf_moveents(struct xfs_da_args *args,
68 struct xfs_attr_leafblock *src_leaf,
Dave Chinner517c2222013-04-24 18:58:55 +100069 struct xfs_attr3_icleaf_hdr *src_ichdr, int src_start,
70 struct xfs_attr_leafblock *dst_leaf,
71 struct xfs_attr3_icleaf_hdr *dst_ichdr, int dst_start,
Dave Chinnerc2c4c472014-06-06 15:21:45 +100072 int move_count);
Christoph Hellwigba0f32d2005-06-21 15:36:52 +100073STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
Tim Shimmin726801b2006-09-28 11:01:37 +100074
Brian Fostere87021a2015-04-13 11:27:10 +100075/*
76 * attr3 block 'firstused' conversion helpers.
77 *
78 * firstused refers to the offset of the first used byte of the nameval region
79 * of an attr leaf block. The region starts at the tail of the block and expands
80 * backwards towards the middle. As such, firstused is initialized to the block
81 * size for an empty leaf block and is reduced from there.
82 *
83 * The attr3 block size is pegged to the fsb size and the maximum fsb is 64k.
84 * The in-core firstused field is 32-bit and thus supports the maximum fsb size.
85 * The on-disk field is only 16-bit, however, and overflows at 64k. Since this
86 * only occurs at exactly 64k, we use zero as a magic on-disk value to represent
87 * the attr block size. The following helpers manage the conversion between the
88 * in-core and on-disk formats.
89 */
90
91static void
92xfs_attr3_leaf_firstused_from_disk(
93 struct xfs_da_geometry *geo,
94 struct xfs_attr3_icleaf_hdr *to,
95 struct xfs_attr_leafblock *from)
96{
97 struct xfs_attr3_leaf_hdr *hdr3;
98
99 if (from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) {
100 hdr3 = (struct xfs_attr3_leaf_hdr *) from;
101 to->firstused = be16_to_cpu(hdr3->firstused);
102 } else {
103 to->firstused = be16_to_cpu(from->hdr.firstused);
104 }
105
106 /*
107 * Convert from the magic fsb size value to actual blocksize. This
108 * should only occur for empty blocks when the block size overflows
109 * 16-bits.
110 */
111 if (to->firstused == XFS_ATTR3_LEAF_NULLOFF) {
112 ASSERT(!to->count && !to->usedbytes);
113 ASSERT(geo->blksize > USHRT_MAX);
114 to->firstused = geo->blksize;
115 }
116}
117
118static void
119xfs_attr3_leaf_firstused_to_disk(
120 struct xfs_da_geometry *geo,
121 struct xfs_attr_leafblock *to,
122 struct xfs_attr3_icleaf_hdr *from)
123{
124 struct xfs_attr3_leaf_hdr *hdr3;
125 uint32_t firstused;
126
127 /* magic value should only be seen on disk */
128 ASSERT(from->firstused != XFS_ATTR3_LEAF_NULLOFF);
129
130 /*
131 * Scale down the 32-bit in-core firstused value to the 16-bit on-disk
132 * value. This only overflows at the max supported value of 64k. Use the
133 * magic on-disk value to represent block size in this case.
134 */
135 firstused = from->firstused;
136 if (firstused > USHRT_MAX) {
137 ASSERT(from->firstused == geo->blksize);
138 firstused = XFS_ATTR3_LEAF_NULLOFF;
139 }
140
141 if (from->magic == XFS_ATTR3_LEAF_MAGIC) {
142 hdr3 = (struct xfs_attr3_leaf_hdr *) to;
143 hdr3->firstused = cpu_to_be16(firstused);
144 } else {
145 to->hdr.firstused = cpu_to_be16(firstused);
146 }
147}
148
Dave Chinner517c2222013-04-24 18:58:55 +1000149void
150xfs_attr3_leaf_hdr_from_disk(
Brian Foster2f661242015-04-13 11:26:02 +1000151 struct xfs_da_geometry *geo,
Dave Chinner517c2222013-04-24 18:58:55 +1000152 struct xfs_attr3_icleaf_hdr *to,
153 struct xfs_attr_leafblock *from)
154{
155 int i;
156
157 ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) ||
158 from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC));
159
160 if (from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) {
161 struct xfs_attr3_leaf_hdr *hdr3 = (struct xfs_attr3_leaf_hdr *)from;
162
163 to->forw = be32_to_cpu(hdr3->info.hdr.forw);
164 to->back = be32_to_cpu(hdr3->info.hdr.back);
165 to->magic = be16_to_cpu(hdr3->info.hdr.magic);
166 to->count = be16_to_cpu(hdr3->count);
167 to->usedbytes = be16_to_cpu(hdr3->usedbytes);
Brian Fostere87021a2015-04-13 11:27:10 +1000168 xfs_attr3_leaf_firstused_from_disk(geo, to, from);
Dave Chinner517c2222013-04-24 18:58:55 +1000169 to->holes = hdr3->holes;
170
171 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
172 to->freemap[i].base = be16_to_cpu(hdr3->freemap[i].base);
173 to->freemap[i].size = be16_to_cpu(hdr3->freemap[i].size);
174 }
175 return;
176 }
177 to->forw = be32_to_cpu(from->hdr.info.forw);
178 to->back = be32_to_cpu(from->hdr.info.back);
179 to->magic = be16_to_cpu(from->hdr.info.magic);
180 to->count = be16_to_cpu(from->hdr.count);
181 to->usedbytes = be16_to_cpu(from->hdr.usedbytes);
Brian Fostere87021a2015-04-13 11:27:10 +1000182 xfs_attr3_leaf_firstused_from_disk(geo, to, from);
Dave Chinner517c2222013-04-24 18:58:55 +1000183 to->holes = from->hdr.holes;
184
185 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
186 to->freemap[i].base = be16_to_cpu(from->hdr.freemap[i].base);
187 to->freemap[i].size = be16_to_cpu(from->hdr.freemap[i].size);
188 }
189}
190
191void
192xfs_attr3_leaf_hdr_to_disk(
Brian Foster2f661242015-04-13 11:26:02 +1000193 struct xfs_da_geometry *geo,
Dave Chinner517c2222013-04-24 18:58:55 +1000194 struct xfs_attr_leafblock *to,
195 struct xfs_attr3_icleaf_hdr *from)
196{
Brian Fostere87021a2015-04-13 11:27:10 +1000197 int i;
Dave Chinner517c2222013-04-24 18:58:55 +1000198
199 ASSERT(from->magic == XFS_ATTR_LEAF_MAGIC ||
200 from->magic == XFS_ATTR3_LEAF_MAGIC);
201
202 if (from->magic == XFS_ATTR3_LEAF_MAGIC) {
203 struct xfs_attr3_leaf_hdr *hdr3 = (struct xfs_attr3_leaf_hdr *)to;
204
205 hdr3->info.hdr.forw = cpu_to_be32(from->forw);
206 hdr3->info.hdr.back = cpu_to_be32(from->back);
207 hdr3->info.hdr.magic = cpu_to_be16(from->magic);
208 hdr3->count = cpu_to_be16(from->count);
209 hdr3->usedbytes = cpu_to_be16(from->usedbytes);
Brian Fostere87021a2015-04-13 11:27:10 +1000210 xfs_attr3_leaf_firstused_to_disk(geo, to, from);
Dave Chinner517c2222013-04-24 18:58:55 +1000211 hdr3->holes = from->holes;
212 hdr3->pad1 = 0;
213
214 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
215 hdr3->freemap[i].base = cpu_to_be16(from->freemap[i].base);
216 hdr3->freemap[i].size = cpu_to_be16(from->freemap[i].size);
217 }
218 return;
219 }
220 to->hdr.info.forw = cpu_to_be32(from->forw);
221 to->hdr.info.back = cpu_to_be32(from->back);
222 to->hdr.info.magic = cpu_to_be16(from->magic);
223 to->hdr.count = cpu_to_be16(from->count);
224 to->hdr.usedbytes = cpu_to_be16(from->usedbytes);
Brian Fostere87021a2015-04-13 11:27:10 +1000225 xfs_attr3_leaf_firstused_to_disk(geo, to, from);
Dave Chinner517c2222013-04-24 18:58:55 +1000226 to->hdr.holes = from->holes;
227 to->hdr.pad1 = 0;
228
229 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
230 to->hdr.freemap[i].base = cpu_to_be16(from->freemap[i].base);
231 to->hdr.freemap[i].size = cpu_to_be16(from->freemap[i].size);
232 }
233}
234
Darrick J. Wonga6a781a2018-01-08 10:51:03 -0800235static xfs_failaddr_t
Darrick J. Wongc8476062019-10-28 16:12:33 -0700236xfs_attr3_leaf_verify_entry(
237 struct xfs_mount *mp,
238 char *buf_end,
239 struct xfs_attr_leafblock *leaf,
240 struct xfs_attr3_icleaf_hdr *leafhdr,
241 struct xfs_attr_leaf_entry *ent,
242 int idx,
243 __u32 *last_hashval)
244{
245 struct xfs_attr_leaf_name_local *lentry;
246 struct xfs_attr_leaf_name_remote *rentry;
247 char *name_end;
248 unsigned int nameidx;
249 unsigned int namesize;
250 __u32 hashval;
251
252 /* hash order check */
253 hashval = be32_to_cpu(ent->hashval);
254 if (hashval < *last_hashval)
255 return __this_address;
256 *last_hashval = hashval;
257
258 nameidx = be16_to_cpu(ent->nameidx);
259 if (nameidx < leafhdr->firstused || nameidx >= mp->m_attr_geo->blksize)
260 return __this_address;
261
262 /*
263 * Check the name information. The namelen fields are u8 so we can't
264 * possibly exceed the maximum name length of 255 bytes.
265 */
266 if (ent->flags & XFS_ATTR_LOCAL) {
267 lentry = xfs_attr3_leaf_name_local(leaf, idx);
268 namesize = xfs_attr_leaf_entsize_local(lentry->namelen,
269 be16_to_cpu(lentry->valuelen));
270 name_end = (char *)lentry + namesize;
271 if (lentry->namelen == 0)
272 return __this_address;
273 } else {
274 rentry = xfs_attr3_leaf_name_remote(leaf, idx);
275 namesize = xfs_attr_leaf_entsize_remote(rentry->namelen);
276 name_end = (char *)rentry + namesize;
277 if (rentry->namelen == 0)
278 return __this_address;
279 if (!(ent->flags & XFS_ATTR_INCOMPLETE) &&
280 rentry->valueblk == 0)
281 return __this_address;
282 }
283
284 if (name_end > buf_end)
285 return __this_address;
286
287 return NULL;
288}
289
290static xfs_failaddr_t
Dave Chinner517c2222013-04-24 18:58:55 +1000291xfs_attr3_leaf_verify(
Darrick J. Wong79a69bf2018-01-16 18:54:12 -0800292 struct xfs_buf *bp)
Dave Chinnerad14c332012-11-12 22:54:16 +1100293{
Darrick J. Wong79a69bf2018-01-16 18:54:12 -0800294 struct xfs_attr3_icleaf_hdr ichdr;
Christoph Hellwigdbd329f12019-06-28 19:27:29 -0700295 struct xfs_mount *mp = bp->b_mount;
Darrick J. Wong79a69bf2018-01-16 18:54:12 -0800296 struct xfs_attr_leafblock *leaf = bp->b_addr;
Darrick J. Wong79a69bf2018-01-16 18:54:12 -0800297 struct xfs_attr_leaf_entry *entries;
Darrick J. Wongc8476062019-10-28 16:12:33 -0700298 struct xfs_attr_leaf_entry *ent;
299 char *buf_end;
Dave Chinner837514f2018-11-06 07:50:50 -0800300 uint32_t end; /* must be 32bit - see below */
Darrick J. Wongc8476062019-10-28 16:12:33 -0700301 __u32 last_hashval = 0;
Darrick J. Wong65cfcc32018-07-19 12:24:55 -0700302 int i;
Brian Foster8764f982019-02-07 10:45:48 -0800303 xfs_failaddr_t fa;
Dave Chinnerad14c332012-11-12 22:54:16 +1100304
Brian Foster2f661242015-04-13 11:26:02 +1000305 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
Dave Chinner517c2222013-04-24 18:58:55 +1000306
Brian Foster8764f982019-02-07 10:45:48 -0800307 fa = xfs_da3_blkinfo_verify(bp, bp->b_addr);
308 if (fa)
309 return fa;
Brian Foster39708c22019-02-07 10:45:48 -0800310
Eric Sandeen2e1d2332016-12-09 16:49:47 +1100311 /*
312 * In recovery there is a transient state where count == 0 is valid
313 * because we may have transitioned an empty shortform attr to a leaf
314 * if the attr didn't fit in shortform.
315 */
Darrick J. Wong0c60d3a2018-08-01 07:40:48 -0700316 if (!xfs_log_in_recovery(mp) && ichdr.count == 0)
Darrick J. Wonga6a781a2018-01-08 10:51:03 -0800317 return __this_address;
Dave Chinner517c2222013-04-24 18:58:55 +1000318
Darrick J. Wong79a69bf2018-01-16 18:54:12 -0800319 /*
320 * firstused is the block offset of the first name info structure.
321 * Make sure it doesn't go off the block or crash into the header.
322 */
323 if (ichdr.firstused > mp->m_attr_geo->blksize)
324 return __this_address;
325 if (ichdr.firstused < xfs_attr3_leaf_hdr_size(leaf))
326 return __this_address;
327
328 /* Make sure the entries array doesn't crash into the name info. */
329 entries = xfs_attr3_leaf_entryp(bp->b_addr);
330 if ((char *)&entries[ichdr.count] >
331 (char *)bp->b_addr + ichdr.firstused)
332 return __this_address;
333
Darrick J. Wongc8476062019-10-28 16:12:33 -0700334 buf_end = (char *)bp->b_addr + mp->m_attr_geo->blksize;
335 for (i = 0, ent = entries; i < ichdr.count; ent++, i++) {
336 fa = xfs_attr3_leaf_verify_entry(mp, buf_end, leaf, &ichdr,
337 ent, i, &last_hashval);
338 if (fa)
339 return fa;
340 }
Dave Chinner517c2222013-04-24 18:58:55 +1000341
Darrick J. Wong65cfcc32018-07-19 12:24:55 -0700342 /*
343 * Quickly check the freemap information. Attribute data has to be
344 * aligned to 4-byte boundaries, and likewise for the free space.
Dave Chinner837514f2018-11-06 07:50:50 -0800345 *
346 * Note that for 64k block size filesystems, the freemap entries cannot
347 * overflow as they are only be16 fields. However, when checking end
348 * pointer of the freemap, we have to be careful to detect overflows and
349 * so use uint32_t for those checks.
Darrick J. Wong65cfcc32018-07-19 12:24:55 -0700350 */
351 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
352 if (ichdr.freemap[i].base > mp->m_attr_geo->blksize)
353 return __this_address;
354 if (ichdr.freemap[i].base & 0x3)
355 return __this_address;
356 if (ichdr.freemap[i].size > mp->m_attr_geo->blksize)
357 return __this_address;
358 if (ichdr.freemap[i].size & 0x3)
359 return __this_address;
Dave Chinner837514f2018-11-06 07:50:50 -0800360
361 /* be care of 16 bit overflows here */
362 end = (uint32_t)ichdr.freemap[i].base + ichdr.freemap[i].size;
Darrick J. Wong65cfcc32018-07-19 12:24:55 -0700363 if (end < ichdr.freemap[i].base)
364 return __this_address;
365 if (end > mp->m_attr_geo->blksize)
366 return __this_address;
367 }
368
Darrick J. Wonga6a781a2018-01-08 10:51:03 -0800369 return NULL;
Dave Chinner517c2222013-04-24 18:58:55 +1000370}
371
372static void
373xfs_attr3_leaf_write_verify(
374 struct xfs_buf *bp)
375{
Christoph Hellwigdbd329f12019-06-28 19:27:29 -0700376 struct xfs_mount *mp = bp->b_mount;
Carlos Maiolinofb1755a2018-01-24 13:38:48 -0800377 struct xfs_buf_log_item *bip = bp->b_log_item;
Dave Chinner517c2222013-04-24 18:58:55 +1000378 struct xfs_attr3_leaf_hdr *hdr3 = bp->b_addr;
Darrick J. Wongbc1a09b2018-01-08 10:51:03 -0800379 xfs_failaddr_t fa;
Dave Chinner517c2222013-04-24 18:58:55 +1000380
Darrick J. Wongbc1a09b2018-01-08 10:51:03 -0800381 fa = xfs_attr3_leaf_verify(bp);
382 if (fa) {
383 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
Dave Chinner517c2222013-04-24 18:58:55 +1000384 return;
385 }
386
387 if (!xfs_sb_version_hascrc(&mp->m_sb))
388 return;
389
390 if (bip)
391 hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn);
392
Eric Sandeenf1dbcd72014-02-27 15:18:23 +1100393 xfs_buf_update_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF);
Dave Chinner517c2222013-04-24 18:58:55 +1000394}
395
396/*
397 * leaf/node format detection on trees is sketchy, so a node read can be done on
398 * leaf level blocks when detection identifies the tree as a node format tree
399 * incorrectly. In this case, we need to swap the verifier to match the correct
400 * format of the block being read.
401 */
402static void
403xfs_attr3_leaf_read_verify(
404 struct xfs_buf *bp)
405{
Christoph Hellwigdbd329f12019-06-28 19:27:29 -0700406 struct xfs_mount *mp = bp->b_mount;
Darrick J. Wongbc1a09b2018-01-08 10:51:03 -0800407 xfs_failaddr_t fa;
Dave Chinner517c2222013-04-24 18:58:55 +1000408
Eric Sandeence5028c2014-02-27 15:23:10 +1100409 if (xfs_sb_version_hascrc(&mp->m_sb) &&
410 !xfs_buf_verify_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF))
Darrick J. Wongbc1a09b2018-01-08 10:51:03 -0800411 xfs_verifier_error(bp, -EFSBADCRC, __this_address);
412 else {
413 fa = xfs_attr3_leaf_verify(bp);
414 if (fa)
415 xfs_verifier_error(bp, -EFSCORRUPTED, fa);
416 }
Dave Chinner612cfbf2012-11-14 17:52:32 +1100417}
Dave Chinnerad14c332012-11-12 22:54:16 +1100418
Dave Chinner517c2222013-04-24 18:58:55 +1000419const struct xfs_buf_ops xfs_attr3_leaf_buf_ops = {
Eric Sandeen233135b2016-01-04 16:10:19 +1100420 .name = "xfs_attr3_leaf",
Darrick J. Wong15baadf2019-02-16 11:47:28 -0800421 .magic16 = { cpu_to_be16(XFS_ATTR_LEAF_MAGIC),
422 cpu_to_be16(XFS_ATTR3_LEAF_MAGIC) },
Dave Chinner517c2222013-04-24 18:58:55 +1000423 .verify_read = xfs_attr3_leaf_read_verify,
424 .verify_write = xfs_attr3_leaf_write_verify,
Darrick J. Wongb5572592018-01-08 10:51:08 -0800425 .verify_struct = xfs_attr3_leaf_verify,
Dave Chinner1813dd62012-11-14 17:54:40 +1100426};
Dave Chinner612cfbf2012-11-14 17:52:32 +1100427
Dave Chinnerad14c332012-11-12 22:54:16 +1100428int
Dave Chinner517c2222013-04-24 18:58:55 +1000429xfs_attr3_leaf_read(
Dave Chinnerad14c332012-11-12 22:54:16 +1100430 struct xfs_trans *tp,
431 struct xfs_inode *dp,
432 xfs_dablk_t bno,
Dave Chinnerad14c332012-11-12 22:54:16 +1100433 struct xfs_buf **bpp)
434{
Dave Chinnerd75afeb2013-04-03 16:11:29 +1100435 int err;
436
Christoph Hellwigcd2c9f12019-11-20 09:46:04 -0800437 err = xfs_da_read_buf(tp, dp, bno, 0, bpp, XFS_ATTR_FORK,
Christoph Hellwigdfb87592019-11-20 09:46:02 -0800438 &xfs_attr3_leaf_buf_ops);
Darrick J. Wongcd87d862017-07-07 18:55:17 -0700439 if (!err && tp && *bpp)
Dave Chinner61fe1352013-04-03 16:11:30 +1100440 xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF);
Dave Chinnerd75afeb2013-04-03 16:11:29 +1100441 return err;
Dave Chinnerad14c332012-11-12 22:54:16 +1100442}
443
Tim Shimmin726801b2006-09-28 11:01:37 +1000444/*========================================================================
445 * Namespace helper routines
446 *========================================================================*/
447
Christoph Hellwig377f16a2020-02-26 17:30:36 -0800448static bool
449xfs_attr_match(
450 struct xfs_da_args *args,
451 uint8_t namelen,
452 unsigned char *name,
453 int flags)
Tim Shimmin726801b2006-09-28 11:01:37 +1000454{
Christoph Hellwig377f16a2020-02-26 17:30:36 -0800455 if (args->namelen != namelen)
456 return false;
457 if (memcmp(args->name, name, namelen) != 0)
458 return false;
Christoph Hellwig254f8002020-02-26 17:30:43 -0800459 /*
460 * If we are looking for incomplete entries, show only those, else only
461 * show complete entries.
462 */
463 if (args->attr_filter !=
464 (flags & (XFS_ATTR_NSP_ONDISK_MASK | XFS_ATTR_INCOMPLETE)))
Christoph Hellwig377f16a2020-02-26 17:30:36 -0800465 return false;
466 return true;
Tim Shimmin726801b2006-09-28 11:01:37 +1000467}
468
Dave Chinner9df243a2019-08-29 09:04:10 -0700469static int
470xfs_attr_copy_value(
471 struct xfs_da_args *args,
472 unsigned char *value,
473 int valuelen)
474{
475 /*
476 * No copy if all we have to do is get the length
477 */
Christoph Hellwige513e252020-02-26 17:30:35 -0800478 if (!args->valuelen) {
Dave Chinner9df243a2019-08-29 09:04:10 -0700479 args->valuelen = valuelen;
480 return 0;
481 }
482
483 /*
484 * No copy if the length of the existing buffer is too small
485 */
486 if (args->valuelen < valuelen) {
487 args->valuelen = valuelen;
488 return -ERANGE;
489 }
Dave Chinnerddbca702019-08-29 09:04:10 -0700490
Christoph Hellwigd49db182020-02-26 17:30:35 -0800491 if (!args->value) {
Dave Chinnerddbca702019-08-29 09:04:10 -0700492 args->value = kmem_alloc_large(valuelen, 0);
493 if (!args->value)
494 return -ENOMEM;
495 }
Dave Chinner9df243a2019-08-29 09:04:10 -0700496 args->valuelen = valuelen;
497
498 /* remote block xattr requires IO for copy-in */
499 if (args->rmtblkno)
500 return xfs_attr_rmtval_get(args);
501
502 /*
503 * This is to prevent a GCC warning because the remote xattr case
504 * doesn't have a value to pass in. In that case, we never reach here,
505 * but GCC can't work that out and so throws a "passing NULL to
506 * memcpy" warning.
507 */
508 if (!value)
509 return -EINVAL;
510 memcpy(args->value, value, valuelen);
511 return 0;
512}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513
514/*========================================================================
Nathan Scottd8cc8902005-11-02 10:34:53 +1100515 * External routines when attribute fork size < XFS_LITINO(mp).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700516 *========================================================================*/
517
518/*
Nathan Scottd8cc8902005-11-02 10:34:53 +1100519 * Query whether the requested number of additional bytes of extended
520 * attribute space will be able to fit inline.
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000521 *
Nathan Scottd8cc8902005-11-02 10:34:53 +1100522 * Returns zero if not, else the di_forkoff fork offset to be used in the
523 * literal area for attribute data once the new bytes have been added.
524 *
525 * di_forkoff must be 8 byte aligned, hence is stored as a >>3 value;
526 * special case for dev/uuid inodes, they have fixed size data forks.
527 */
528int
Dave Chinner3f8a4f12019-10-17 13:40:33 -0700529xfs_attr_shortform_bytesfit(
530 struct xfs_inode *dp,
531 int bytes)
Nathan Scottd8cc8902005-11-02 10:34:53 +1100532{
Dave Chinner3f8a4f12019-10-17 13:40:33 -0700533 struct xfs_mount *mp = dp->i_mount;
534 int64_t dsize;
535 int minforkoff;
536 int maxforkoff;
537 int offset;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100538
Christoph Hellwig56cea2d2013-03-12 23:30:36 +1100539 /* rounded down */
540 offset = (XFS_LITINO(mp, dp->i_d.di_version) - bytes) >> 3;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100541
Christoph Hellwig42b67dc2017-10-19 11:07:09 -0700542 if (dp->i_d.di_format == XFS_DINODE_FMT_DEV) {
Nathan Scottd8cc8902005-11-02 10:34:53 +1100543 minforkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
544 return (offset >= minforkoff) ? minforkoff : 0;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100545 }
546
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000547 /*
548 * If the requested numbers of bytes is smaller or equal to the
549 * current attribute fork size we can always proceed.
550 *
551 * Note that if_bytes in the data fork might actually be larger than
552 * the current data fork size is due to delalloc extents. In that
553 * case either the extent count will go down when they are converted
554 * to real extents, or the delalloc conversion will take care of the
555 * literal area rebalancing.
556 */
557 if (bytes <= XFS_IFORK_ASIZE(dp))
558 return dp->i_d.di_forkoff;
559
560 /*
561 * For attr2 we can try to move the forkoff if there is space in the
562 * literal area, but for the old format we are done if there is no
563 * space in the fixed attribute fork.
564 */
565 if (!(mp->m_flags & XFS_MOUNT_ATTR2))
Nathan Scottda087ba2005-11-02 15:00:20 +1100566 return 0;
Nathan Scottda087ba2005-11-02 15:00:20 +1100567
Barry Naujoke5889e92007-02-10 18:35:58 +1100568 dsize = dp->i_df.if_bytes;
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000569
Barry Naujoke5889e92007-02-10 18:35:58 +1100570 switch (dp->i_d.di_format) {
571 case XFS_DINODE_FMT_EXTENTS:
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000572 /*
Barry Naujoke5889e92007-02-10 18:35:58 +1100573 * If there is no attr fork and the data fork is extents,
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000574 * determine if creating the default attr fork will result
575 * in the extents form migrating to btree. If so, the
576 * minimum offset only needs to be the space required for
Barry Naujoke5889e92007-02-10 18:35:58 +1100577 * the btree root.
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000578 */
Christoph Hellwig1a5902c2009-03-29 19:26:46 +0200579 if (!dp->i_d.di_forkoff && dp->i_df.if_bytes >
580 xfs_default_attroffset(dp))
Barry Naujoke5889e92007-02-10 18:35:58 +1100581 dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
582 break;
Barry Naujoke5889e92007-02-10 18:35:58 +1100583 case XFS_DINODE_FMT_BTREE:
584 /*
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000585 * If we have a data btree then keep forkoff if we have one,
586 * otherwise we are adding a new attr, so then we set
587 * minforkoff to where the btree root can finish so we have
Barry Naujoke5889e92007-02-10 18:35:58 +1100588 * plenty of room for attrs
589 */
590 if (dp->i_d.di_forkoff) {
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000591 if (offset < dp->i_d.di_forkoff)
Barry Naujoke5889e92007-02-10 18:35:58 +1100592 return 0;
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000593 return dp->i_d.di_forkoff;
594 }
Christoph Hellwigee1a47a2013-04-21 14:53:46 -0500595 dsize = XFS_BMAP_BROOT_SPACE(mp, dp->i_df.if_broot);
Barry Naujoke5889e92007-02-10 18:35:58 +1100596 break;
597 }
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000598
599 /*
600 * A data fork btree root must have space for at least
Barry Naujoke5889e92007-02-10 18:35:58 +1100601 * MINDBTPTRS key/ptr pairs if the data fork is small or empty.
602 */
Dave Chinner3f8a4f12019-10-17 13:40:33 -0700603 minforkoff = max_t(int64_t, dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
Nathan Scottd8cc8902005-11-02 10:34:53 +1100604 minforkoff = roundup(minforkoff, 8) >> 3;
605
606 /* attr fork btree root can have at least this many key/ptr pairs */
Christoph Hellwig56cea2d2013-03-12 23:30:36 +1100607 maxforkoff = XFS_LITINO(mp, dp->i_d.di_version) -
608 XFS_BMDR_SPACE_CALC(MINABTPTRS);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100609 maxforkoff = maxforkoff >> 3; /* rounded down */
610
Nathan Scottd8cc8902005-11-02 10:34:53 +1100611 if (offset >= maxforkoff)
612 return maxforkoff;
Christoph Hellwig4c393a62011-11-19 17:44:30 +0000613 if (offset >= minforkoff)
614 return offset;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100615 return 0;
616}
617
618/*
619 * Switch on the ATTR2 superblock bit (implies also FEATURES2)
620 */
621STATIC void
622xfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp)
623{
Nathan Scott13059ff2006-01-11 15:32:01 +1100624 if ((mp->m_flags & XFS_MOUNT_ATTR2) &&
Eric Sandeen62118702008-03-06 13:44:28 +1100625 !(xfs_sb_version_hasattr2(&mp->m_sb))) {
Eric Sandeen3685c2a2007-10-11 17:42:32 +1000626 spin_lock(&mp->m_sb_lock);
Eric Sandeen62118702008-03-06 13:44:28 +1100627 if (!xfs_sb_version_hasattr2(&mp->m_sb)) {
628 xfs_sb_version_addattr2(&mp->m_sb);
Eric Sandeen3685c2a2007-10-11 17:42:32 +1000629 spin_unlock(&mp->m_sb_lock);
Dave Chinner61e63ec2015-01-22 09:10:31 +1100630 xfs_log_sb(tp);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100631 } else
Eric Sandeen3685c2a2007-10-11 17:42:32 +1000632 spin_unlock(&mp->m_sb_lock);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100633 }
634}
635
636/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 * Create the initial contents of a shortform attribute list.
638 */
Nathan Scottd8cc8902005-11-02 10:34:53 +1100639void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700640xfs_attr_shortform_create(xfs_da_args_t *args)
641{
642 xfs_attr_sf_hdr_t *hdr;
643 xfs_inode_t *dp;
Christoph Hellwig3ba738d2018-07-17 16:51:50 -0700644 struct xfs_ifork *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645
Dave Chinner5a5881c2012-03-22 05:15:13 +0000646 trace_xfs_attr_sf_create(args);
647
Linus Torvalds1da177e2005-04-16 15:20:36 -0700648 dp = args->dp;
649 ASSERT(dp != NULL);
650 ifp = dp->i_afp;
651 ASSERT(ifp != NULL);
652 ASSERT(ifp->if_bytes == 0);
653 if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) {
654 ifp->if_flags &= ~XFS_IFEXTENTS; /* just in case */
655 dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL;
656 ifp->if_flags |= XFS_IFINLINE;
657 } else {
658 ASSERT(ifp->if_flags & XFS_IFINLINE);
659 }
660 xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK);
661 hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data;
662 hdr->count = 0;
Nathan Scott3b244aa2006-03-17 17:29:25 +1100663 hdr->totsize = cpu_to_be16(sizeof(*hdr));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665}
666
667/*
668 * Add a name/value pair to the shortform attribute list.
669 * Overflow from the inode has already been checked for.
670 */
Nathan Scottd8cc8902005-11-02 10:34:53 +1100671void
672xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 xfs_attr_shortform_t *sf;
675 xfs_attr_sf_entry_t *sfe;
676 int i, offset, size;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100677 xfs_mount_t *mp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678 xfs_inode_t *dp;
Christoph Hellwig3ba738d2018-07-17 16:51:50 -0700679 struct xfs_ifork *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700680
Dave Chinner5a5881c2012-03-22 05:15:13 +0000681 trace_xfs_attr_sf_add(args);
682
Linus Torvalds1da177e2005-04-16 15:20:36 -0700683 dp = args->dp;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100684 mp = dp->i_mount;
685 dp->i_d.di_forkoff = forkoff;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100686
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 ifp = dp->i_afp;
688 ASSERT(ifp->if_flags & XFS_IFINLINE);
689 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
690 sfe = &sf->list[0];
Nathan Scott3b244aa2006-03-17 17:29:25 +1100691 for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
Christoph Hellwig377f16a2020-02-26 17:30:36 -0800692 ASSERT(!xfs_attr_match(args, sfe->namelen, sfe->nameval,
693 sfe->flags));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694 }
695
696 offset = (char *)sfe - (char *)sf;
697 size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
698 xfs_idata_realloc(dp, size, XFS_ATTR_FORK);
699 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
700 sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset);
701
702 sfe->namelen = args->namelen;
Nathan Scott3b244aa2006-03-17 17:29:25 +1100703 sfe->valuelen = args->valuelen;
Christoph Hellwigd5f0f492020-02-26 17:30:42 -0800704 sfe->flags = args->attr_filter;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705 memcpy(sfe->nameval, args->name, args->namelen);
706 memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
Nathan Scott3b244aa2006-03-17 17:29:25 +1100707 sf->hdr.count++;
Marcin Slusarz413d57c2008-02-13 15:03:29 -0800708 be16_add_cpu(&sf->hdr.totsize, size);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
710
Nathan Scottd8cc8902005-11-02 10:34:53 +1100711 xfs_sbversion_add_attr2(mp, args->trans);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700712}
713
714/*
Christoph Hellwige1486de2009-02-04 09:36:00 +0100715 * After the last attribute is removed revert to original inode format,
716 * making all literal area available to the data fork once more.
717 */
Dave Chinner6dfe5a02015-05-29 07:40:08 +1000718void
719xfs_attr_fork_remove(
Christoph Hellwige1486de2009-02-04 09:36:00 +0100720 struct xfs_inode *ip,
721 struct xfs_trans *tp)
722{
723 xfs_idestroy_fork(ip, XFS_ATTR_FORK);
724 ip->i_d.di_forkoff = 0;
725 ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
726
727 ASSERT(ip->i_d.di_anextents == 0);
728 ASSERT(ip->i_afp == NULL);
729
Christoph Hellwige1486de2009-02-04 09:36:00 +0100730 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
731}
732
733/*
Nathan Scottd8cc8902005-11-02 10:34:53 +1100734 * Remove an attribute from the shortform attribute list structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700735 */
736int
737xfs_attr_shortform_remove(xfs_da_args_t *args)
738{
739 xfs_attr_shortform_t *sf;
740 xfs_attr_sf_entry_t *sfe;
741 int base, size=0, end, totsize, i;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100742 xfs_mount_t *mp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 xfs_inode_t *dp;
744
Dave Chinner5a5881c2012-03-22 05:15:13 +0000745 trace_xfs_attr_sf_remove(args);
746
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 dp = args->dp;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100748 mp = dp->i_mount;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749 base = sizeof(xfs_attr_sf_hdr_t);
750 sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
751 sfe = &sf->list[0];
Nathan Scott3b244aa2006-03-17 17:29:25 +1100752 end = sf->hdr.count;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100753 for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754 base += size, i++) {
755 size = XFS_ATTR_SF_ENTSIZE(sfe);
Christoph Hellwig377f16a2020-02-26 17:30:36 -0800756 if (xfs_attr_match(args, sfe->namelen, sfe->nameval,
757 sfe->flags))
758 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 }
Nathan Scottd8cc8902005-11-02 10:34:53 +1100760 if (i == end)
Dave Chinner24513372014-06-25 14:58:08 +1000761 return -ENOATTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762
Nathan Scottd8cc8902005-11-02 10:34:53 +1100763 /*
764 * Fix up the attribute fork data, covering the hole
765 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 end = base + size;
Nathan Scott3b244aa2006-03-17 17:29:25 +1100767 totsize = be16_to_cpu(sf->hdr.totsize);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100768 if (end != totsize)
769 memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end);
Nathan Scott3b244aa2006-03-17 17:29:25 +1100770 sf->hdr.count--;
Marcin Slusarz413d57c2008-02-13 15:03:29 -0800771 be16_add_cpu(&sf->hdr.totsize, -size);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100772
773 /*
774 * Fix up the start offset of the attribute fork
775 */
776 totsize -= size;
Barry Naujok6a178102008-05-21 16:42:05 +1000777 if (totsize == sizeof(xfs_attr_sf_hdr_t) &&
Christoph Hellwige1486de2009-02-04 09:36:00 +0100778 (mp->m_flags & XFS_MOUNT_ATTR2) &&
779 (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
780 !(args->op_flags & XFS_DA_OP_ADDNAME)) {
Dave Chinner6dfe5a02015-05-29 07:40:08 +1000781 xfs_attr_fork_remove(dp, args->trans);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100782 } else {
783 xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
784 dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize);
785 ASSERT(dp->i_d.di_forkoff);
Barry Naujok6a178102008-05-21 16:42:05 +1000786 ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) ||
787 (args->op_flags & XFS_DA_OP_ADDNAME) ||
788 !(mp->m_flags & XFS_MOUNT_ATTR2) ||
789 dp->i_d.di_format == XFS_DINODE_FMT_BTREE);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100790 xfs_trans_log_inode(args->trans, dp,
791 XFS_ILOG_CORE | XFS_ILOG_ADATA);
792 }
793
794 xfs_sbversion_add_attr2(mp, args->trans);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700795
Eric Sandeend99831f2014-06-22 15:03:54 +1000796 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700797}
798
799/*
800 * Look up a name in a shortform attribute list structure.
801 */
802/*ARGSUSED*/
803int
804xfs_attr_shortform_lookup(xfs_da_args_t *args)
805{
806 xfs_attr_shortform_t *sf;
807 xfs_attr_sf_entry_t *sfe;
808 int i;
Christoph Hellwig3ba738d2018-07-17 16:51:50 -0700809 struct xfs_ifork *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810
Dave Chinner5a5881c2012-03-22 05:15:13 +0000811 trace_xfs_attr_sf_lookup(args);
812
Linus Torvalds1da177e2005-04-16 15:20:36 -0700813 ifp = args->dp->i_afp;
814 ASSERT(ifp->if_flags & XFS_IFINLINE);
815 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
816 sfe = &sf->list[0];
Nathan Scott3b244aa2006-03-17 17:29:25 +1100817 for (i = 0; i < sf->hdr.count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
Christoph Hellwig377f16a2020-02-26 17:30:36 -0800819 if (xfs_attr_match(args, sfe->namelen, sfe->nameval,
820 sfe->flags))
821 return -EEXIST;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 }
Dave Chinner24513372014-06-25 14:58:08 +1000823 return -ENOATTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824}
825
826/*
Joe Perchescf085a12019-11-07 13:24:52 -0800827 * Retrieve the attribute value and length.
Dave Chinner728bcaa2019-08-29 09:04:08 -0700828 *
Christoph Hellwige513e252020-02-26 17:30:35 -0800829 * If args->valuelen is zero, only the length needs to be returned. Unlike a
830 * lookup, we only return an error if the attribute does not exist or we can't
831 * retrieve the value.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700833int
Dave Chinner9df243a2019-08-29 09:04:10 -0700834xfs_attr_shortform_getvalue(
835 struct xfs_da_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700836{
Dave Chinner9df243a2019-08-29 09:04:10 -0700837 struct xfs_attr_shortform *sf;
838 struct xfs_attr_sf_entry *sfe;
839 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700840
Eric Sandeen914ed442012-03-30 11:24:11 -0500841 ASSERT(args->dp->i_afp->if_flags == XFS_IFINLINE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700842 sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data;
843 sfe = &sf->list[0];
Nathan Scott3b244aa2006-03-17 17:29:25 +1100844 for (i = 0; i < sf->hdr.count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700845 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
Christoph Hellwig377f16a2020-02-26 17:30:36 -0800846 if (xfs_attr_match(args, sfe->namelen, sfe->nameval,
847 sfe->flags))
848 return xfs_attr_copy_value(args,
849 &sfe->nameval[args->namelen], sfe->valuelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 }
Dave Chinner24513372014-06-25 14:58:08 +1000851 return -ENOATTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852}
853
854/*
Darrick J. Wong6e643cd2017-12-07 19:07:02 -0800855 * Convert from using the shortform to the leaf. On success, return the
856 * buffer so that we can keep it locked until we're totally done with it.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700857 */
858int
Darrick J. Wong6e643cd2017-12-07 19:07:02 -0800859xfs_attr_shortform_to_leaf(
Brian Foster32a9b7c2018-07-11 22:26:11 -0700860 struct xfs_da_args *args,
861 struct xfs_buf **leaf_bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700862{
Brian Foster32a9b7c2018-07-11 22:26:11 -0700863 struct xfs_inode *dp;
864 struct xfs_attr_shortform *sf;
865 struct xfs_attr_sf_entry *sfe;
866 struct xfs_da_args nargs;
867 char *tmpbuffer;
868 int error, i, size;
869 xfs_dablk_t blkno;
870 struct xfs_buf *bp;
871 struct xfs_ifork *ifp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872
Dave Chinner5a5881c2012-03-22 05:15:13 +0000873 trace_xfs_attr_sf_to_leaf(args);
874
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 dp = args->dp;
876 ifp = dp->i_afp;
877 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
Nathan Scott3b244aa2006-03-17 17:29:25 +1100878 size = be16_to_cpu(sf->hdr.totsize);
Tetsuo Handa707e0dd2019-08-26 12:06:22 -0700879 tmpbuffer = kmem_alloc(size, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700880 ASSERT(tmpbuffer != NULL);
881 memcpy(tmpbuffer, ifp->if_u1.if_data, size);
882 sf = (xfs_attr_shortform_t *)tmpbuffer;
883
884 xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
Brian Fosteraeea4b72019-10-07 12:54:16 -0700885 xfs_bmap_local_to_extents_empty(args->trans, dp, XFS_ATTR_FORK);
Dave Chinnerf3508bc2013-07-10 07:04:00 +1000886
Linus Torvalds1da177e2005-04-16 15:20:36 -0700887 bp = NULL;
888 error = xfs_da_grow_inode(args, &blkno);
Brian Foster603efeb2019-10-07 12:54:15 -0700889 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891
892 ASSERT(blkno == 0);
Dave Chinner517c2222013-04-24 18:58:55 +1000893 error = xfs_attr3_leaf_create(args, blkno, &bp);
Brian Foster603efeb2019-10-07 12:54:15 -0700894 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700895 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700896
897 memset((char *)&nargs, 0, sizeof(nargs));
898 nargs.dp = dp;
Dave Chinner0650b552014-06-06 15:01:58 +1000899 nargs.geo = args->geo;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 nargs.total = args->total;
901 nargs.whichfork = XFS_ATTR_FORK;
902 nargs.trans = args->trans;
Barry Naujok6a178102008-05-21 16:42:05 +1000903 nargs.op_flags = XFS_DA_OP_OKNOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904
905 sfe = &sf->list[0];
Nathan Scott3b244aa2006-03-17 17:29:25 +1100906 for (i = 0; i < sf->hdr.count; i++) {
Dave Chinnera9273ca2010-01-20 10:47:48 +1100907 nargs.name = sfe->nameval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700908 nargs.namelen = sfe->namelen;
Dave Chinnera9273ca2010-01-20 10:47:48 +1100909 nargs.value = &sfe->nameval[nargs.namelen];
Nathan Scott3b244aa2006-03-17 17:29:25 +1100910 nargs.valuelen = sfe->valuelen;
Dave Chinnera9273ca2010-01-20 10:47:48 +1100911 nargs.hashval = xfs_da_hashname(sfe->nameval,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912 sfe->namelen);
Christoph Hellwigd5f0f492020-02-26 17:30:42 -0800913 nargs.attr_filter = sfe->flags & XFS_ATTR_NSP_ONDISK_MASK;
Dave Chinner517c2222013-04-24 18:58:55 +1000914 error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
Dave Chinner24513372014-06-25 14:58:08 +1000915 ASSERT(error == -ENOATTR);
Dave Chinner517c2222013-04-24 18:58:55 +1000916 error = xfs_attr3_leaf_add(bp, &nargs);
Dave Chinner24513372014-06-25 14:58:08 +1000917 ASSERT(error != -ENOSPC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 if (error)
919 goto out;
920 sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
921 }
922 error = 0;
Darrick J. Wong6e643cd2017-12-07 19:07:02 -0800923 *leaf_bp = bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700924out:
Denys Vlasenkof0e2d932008-05-19 16:31:57 +1000925 kmem_free(tmpbuffer);
Eric Sandeend99831f2014-06-22 15:03:54 +1000926 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927}
928
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929/*
930 * Check a leaf attribute block to see if all the entries would fit into
931 * a shortform attribute list.
932 */
933int
Dave Chinner1d9025e2012-06-22 18:50:14 +1000934xfs_attr_shortform_allfit(
Dave Chinnerb38958d2013-05-20 09:51:14 +1000935 struct xfs_buf *bp,
936 struct xfs_inode *dp)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937{
Dave Chinnerb38958d2013-05-20 09:51:14 +1000938 struct xfs_attr_leafblock *leaf;
939 struct xfs_attr_leaf_entry *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 xfs_attr_leaf_name_local_t *name_loc;
Dave Chinnerb38958d2013-05-20 09:51:14 +1000941 struct xfs_attr3_icleaf_hdr leafhdr;
942 int bytes;
943 int i;
Christoph Hellwigdbd329f12019-06-28 19:27:29 -0700944 struct xfs_mount *mp = bp->b_mount;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700945
Dave Chinner1d9025e2012-06-22 18:50:14 +1000946 leaf = bp->b_addr;
Brian Foster2f661242015-04-13 11:26:02 +1000947 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
Dave Chinnerb38958d2013-05-20 09:51:14 +1000948 entry = xfs_attr3_leaf_entryp(leaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700949
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 bytes = sizeof(struct xfs_attr_sf_hdr);
Dave Chinnerb38958d2013-05-20 09:51:14 +1000951 for (i = 0; i < leafhdr.count; entry++, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952 if (entry->flags & XFS_ATTR_INCOMPLETE)
953 continue; /* don't copy partial entries */
954 if (!(entry->flags & XFS_ATTR_LOCAL))
Eric Sandeend99831f2014-06-22 15:03:54 +1000955 return 0;
Dave Chinner517c2222013-04-24 18:58:55 +1000956 name_loc = xfs_attr3_leaf_name_local(leaf, i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX)
Eric Sandeend99831f2014-06-22 15:03:54 +1000958 return 0;
Nathan Scott053b5752006-03-17 17:29:09 +1100959 if (be16_to_cpu(name_loc->valuelen) >= XFS_ATTR_SF_ENTSIZE_MAX)
Eric Sandeend99831f2014-06-22 15:03:54 +1000960 return 0;
Dave Chinnerb38958d2013-05-20 09:51:14 +1000961 bytes += sizeof(struct xfs_attr_sf_entry) - 1
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962 + name_loc->namelen
Nathan Scott053b5752006-03-17 17:29:09 +1100963 + be16_to_cpu(name_loc->valuelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 }
Nathan Scott13059ff2006-01-11 15:32:01 +1100965 if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) &&
Barry Naujoke5889e92007-02-10 18:35:58 +1100966 (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
Nathan Scotte0144ca2005-11-25 16:42:22 +1100967 (bytes == sizeof(struct xfs_attr_sf_hdr)))
Dave Chinnerb38958d2013-05-20 09:51:14 +1000968 return -1;
969 return xfs_attr_shortform_bytesfit(dp, bytes);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700970}
971
Darrick J. Wong1e1bbd82018-01-08 10:51:05 -0800972/* Verify the consistency of an inline attribute fork. */
973xfs_failaddr_t
974xfs_attr_shortform_verify(
975 struct xfs_inode *ip)
976{
977 struct xfs_attr_shortform *sfp;
978 struct xfs_attr_sf_entry *sfep;
979 struct xfs_attr_sf_entry *next_sfep;
980 char *endp;
981 struct xfs_ifork *ifp;
982 int i;
Dave Chinner3f8a4f12019-10-17 13:40:33 -0700983 int64_t size;
Darrick J. Wong1e1bbd82018-01-08 10:51:05 -0800984
985 ASSERT(ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL);
986 ifp = XFS_IFORK_PTR(ip, XFS_ATTR_FORK);
987 sfp = (struct xfs_attr_shortform *)ifp->if_u1.if_data;
988 size = ifp->if_bytes;
989
990 /*
991 * Give up if the attribute is way too short.
992 */
993 if (size < sizeof(struct xfs_attr_sf_hdr))
994 return __this_address;
995
996 endp = (char *)sfp + size;
997
998 /* Check all reported entries */
999 sfep = &sfp->list[0];
1000 for (i = 0; i < sfp->hdr.count; i++) {
1001 /*
1002 * struct xfs_attr_sf_entry has a variable length.
1003 * Check the fixed-offset parts of the structure are
1004 * within the data buffer.
1005 */
1006 if (((char *)sfep + sizeof(*sfep)) >= endp)
1007 return __this_address;
1008
1009 /* Don't allow names with known bad length. */
1010 if (sfep->namelen == 0)
1011 return __this_address;
1012
1013 /*
1014 * Check that the variable-length part of the structure is
1015 * within the data buffer. The next entry starts after the
1016 * name component, so nextentry is an acceptable test.
1017 */
1018 next_sfep = XFS_ATTR_SF_NEXTENTRY(sfep);
1019 if ((char *)next_sfep > endp)
1020 return __this_address;
1021
1022 /*
1023 * Check for unknown flags. Short form doesn't support
1024 * the incomplete or local bits, so we can use the namespace
1025 * mask here.
1026 */
1027 if (sfep->flags & ~XFS_ATTR_NSP_ONDISK_MASK)
1028 return __this_address;
1029
1030 /*
1031 * Check for invalid namespace combinations. We only allow
1032 * one namespace flag per xattr, so we can just count the
1033 * bits (i.e. hweight) here.
1034 */
1035 if (hweight8(sfep->flags & XFS_ATTR_NSP_ONDISK_MASK) > 1)
1036 return __this_address;
1037
1038 sfep = next_sfep;
1039 }
1040 if ((void *)sfep != (void *)endp)
1041 return __this_address;
1042
1043 return NULL;
1044}
1045
Linus Torvalds1da177e2005-04-16 15:20:36 -07001046/*
1047 * Convert a leaf attribute list to shortform attribute list
1048 */
1049int
Dave Chinner517c2222013-04-24 18:58:55 +10001050xfs_attr3_leaf_to_shortform(
1051 struct xfs_buf *bp,
1052 struct xfs_da_args *args,
1053 int forkoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001054{
Dave Chinner517c2222013-04-24 18:58:55 +10001055 struct xfs_attr_leafblock *leaf;
1056 struct xfs_attr3_icleaf_hdr ichdr;
1057 struct xfs_attr_leaf_entry *entry;
1058 struct xfs_attr_leaf_name_local *name_loc;
1059 struct xfs_da_args nargs;
1060 struct xfs_inode *dp = args->dp;
1061 char *tmpbuffer;
1062 int error;
1063 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001064
Dave Chinner5a5881c2012-03-22 05:15:13 +00001065 trace_xfs_attr_leaf_to_sf(args);
1066
Tetsuo Handa707e0dd2019-08-26 12:06:22 -07001067 tmpbuffer = kmem_alloc(args->geo->blksize, 0);
Dave Chinner517c2222013-04-24 18:58:55 +10001068 if (!tmpbuffer)
Dave Chinner24513372014-06-25 14:58:08 +10001069 return -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001070
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001071 memcpy(tmpbuffer, bp->b_addr, args->geo->blksize);
Dave Chinner517c2222013-04-24 18:58:55 +10001072
Linus Torvalds1da177e2005-04-16 15:20:36 -07001073 leaf = (xfs_attr_leafblock_t *)tmpbuffer;
Brian Foster2f661242015-04-13 11:26:02 +10001074 xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
Dave Chinner517c2222013-04-24 18:58:55 +10001075 entry = xfs_attr3_leaf_entryp(leaf);
1076
1077 /* XXX (dgc): buffer is about to be marked stale - why zero it? */
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001078 memset(bp->b_addr, 0, args->geo->blksize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001079
1080 /*
1081 * Clean out the prior contents of the attribute list.
1082 */
1083 error = xfs_da_shrink_inode(args, 0, bp);
1084 if (error)
1085 goto out;
Nathan Scottd8cc8902005-11-02 10:34:53 +11001086
1087 if (forkoff == -1) {
Nathan Scott13059ff2006-01-11 15:32:01 +11001088 ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2);
Barry Naujoke5889e92007-02-10 18:35:58 +11001089 ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE);
Dave Chinner6dfe5a02015-05-29 07:40:08 +10001090 xfs_attr_fork_remove(dp, args->trans);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 goto out;
Nathan Scottd8cc8902005-11-02 10:34:53 +11001092 }
1093
1094 xfs_attr_shortform_create(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001095
1096 /*
1097 * Copy the attributes
1098 */
1099 memset((char *)&nargs, 0, sizeof(nargs));
Dave Chinner0650b552014-06-06 15:01:58 +10001100 nargs.geo = args->geo;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001101 nargs.dp = dp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001102 nargs.total = args->total;
1103 nargs.whichfork = XFS_ATTR_FORK;
1104 nargs.trans = args->trans;
Barry Naujok6a178102008-05-21 16:42:05 +10001105 nargs.op_flags = XFS_DA_OP_OKNOENT;
Dave Chinner517c2222013-04-24 18:58:55 +10001106
1107 for (i = 0; i < ichdr.count; entry++, i++) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001108 if (entry->flags & XFS_ATTR_INCOMPLETE)
1109 continue; /* don't copy partial entries */
1110 if (!entry->nameidx)
1111 continue;
1112 ASSERT(entry->flags & XFS_ATTR_LOCAL);
Dave Chinner517c2222013-04-24 18:58:55 +10001113 name_loc = xfs_attr3_leaf_name_local(leaf, i);
Dave Chinnera9273ca2010-01-20 10:47:48 +11001114 nargs.name = name_loc->nameval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001115 nargs.namelen = name_loc->namelen;
Dave Chinnera9273ca2010-01-20 10:47:48 +11001116 nargs.value = &name_loc->nameval[nargs.namelen];
Nathan Scott053b5752006-03-17 17:29:09 +11001117 nargs.valuelen = be16_to_cpu(name_loc->valuelen);
Nathan Scott6b19f2d2006-03-17 17:29:02 +11001118 nargs.hashval = be32_to_cpu(entry->hashval);
Christoph Hellwigd5f0f492020-02-26 17:30:42 -08001119 nargs.attr_filter = entry->flags & XFS_ATTR_NSP_ONDISK_MASK;
Nathan Scottd8cc8902005-11-02 10:34:53 +11001120 xfs_attr_shortform_add(&nargs, forkoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 }
1122 error = 0;
1123
1124out:
Denys Vlasenkof0e2d932008-05-19 16:31:57 +10001125 kmem_free(tmpbuffer);
Dave Chinner517c2222013-04-24 18:58:55 +10001126 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001127}
1128
1129/*
1130 * Convert from using a single leaf to a root node and a leaf.
1131 */
1132int
Dave Chinner517c2222013-04-24 18:58:55 +10001133xfs_attr3_leaf_to_node(
1134 struct xfs_da_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001135{
Dave Chinner517c2222013-04-24 18:58:55 +10001136 struct xfs_attr_leafblock *leaf;
1137 struct xfs_attr3_icleaf_hdr icleafhdr;
1138 struct xfs_attr_leaf_entry *entries;
Dave Chinner517c2222013-04-24 18:58:55 +10001139 struct xfs_da3_icnode_hdr icnodehdr;
1140 struct xfs_da_intnode *node;
1141 struct xfs_inode *dp = args->dp;
1142 struct xfs_mount *mp = dp->i_mount;
1143 struct xfs_buf *bp1 = NULL;
1144 struct xfs_buf *bp2 = NULL;
1145 xfs_dablk_t blkno;
1146 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147
Dave Chinner5a5881c2012-03-22 05:15:13 +00001148 trace_xfs_attr_leaf_to_node(args);
1149
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150 error = xfs_da_grow_inode(args, &blkno);
1151 if (error)
1152 goto out;
Christoph Hellwigdfb87592019-11-20 09:46:02 -08001153 error = xfs_attr3_leaf_read(args->trans, dp, 0, &bp1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001154 if (error)
1155 goto out;
Dave Chinnerad14c332012-11-12 22:54:16 +11001156
Christoph Hellwig2911edb2019-11-20 09:46:05 -08001157 error = xfs_da_get_buf(args->trans, dp, blkno, &bp2, XFS_ATTR_FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001158 if (error)
1159 goto out;
Dave Chinner517c2222013-04-24 18:58:55 +10001160
1161 /* copy leaf to new buffer, update identifiers */
Dave Chinner61fe1352013-04-03 16:11:30 +11001162 xfs_trans_buf_set_type(args->trans, bp2, XFS_BLFT_ATTR_LEAF_BUF);
Dave Chinner1813dd62012-11-14 17:54:40 +11001163 bp2->b_ops = bp1->b_ops;
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001164 memcpy(bp2->b_addr, bp1->b_addr, args->geo->blksize);
Dave Chinner517c2222013-04-24 18:58:55 +10001165 if (xfs_sb_version_hascrc(&mp->m_sb)) {
1166 struct xfs_da3_blkinfo *hdr3 = bp2->b_addr;
1167 hdr3->blkno = cpu_to_be64(bp2->b_bn);
1168 }
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001169 xfs_trans_log_buf(args->trans, bp2, 0, args->geo->blksize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001170
1171 /*
1172 * Set up the new root node.
1173 */
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001174 error = xfs_da3_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001175 if (error)
1176 goto out;
Dave Chinner1d9025e2012-06-22 18:50:14 +10001177 node = bp1->b_addr;
Christoph Hellwigf475dc4d2019-11-08 14:53:00 -08001178 xfs_da3_node_hdr_from_disk(mp, &icnodehdr, node);
Dave Chinner517c2222013-04-24 18:58:55 +10001179
1180 leaf = bp2->b_addr;
Brian Foster2f661242015-04-13 11:26:02 +10001181 xfs_attr3_leaf_hdr_from_disk(args->geo, &icleafhdr, leaf);
Dave Chinner517c2222013-04-24 18:58:55 +10001182 entries = xfs_attr3_leaf_entryp(leaf);
1183
1184 /* both on-disk, don't endian-flip twice */
Christoph Hellwig51908ca2019-11-08 14:57:48 -08001185 icnodehdr.btree[0].hashval = entries[icleafhdr.count - 1].hashval;
1186 icnodehdr.btree[0].before = cpu_to_be32(blkno);
Dave Chinner517c2222013-04-24 18:58:55 +10001187 icnodehdr.count = 1;
Christoph Hellwige1c8af12019-11-08 14:57:48 -08001188 xfs_da3_node_hdr_to_disk(dp->i_mount, node, &icnodehdr);
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001189 xfs_trans_log_buf(args->trans, bp1, 0, args->geo->blksize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001190 error = 0;
1191out:
Dave Chinner517c2222013-04-24 18:58:55 +10001192 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193}
1194
Linus Torvalds1da177e2005-04-16 15:20:36 -07001195/*========================================================================
1196 * Routines used for growing the Btree.
1197 *========================================================================*/
1198
1199/*
1200 * Create the initial contents of a leaf attribute list
1201 * or a leaf in a node attribute list.
1202 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +10001203STATIC int
Dave Chinner517c2222013-04-24 18:58:55 +10001204xfs_attr3_leaf_create(
1205 struct xfs_da_args *args,
1206 xfs_dablk_t blkno,
1207 struct xfs_buf **bpp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001208{
Dave Chinner517c2222013-04-24 18:58:55 +10001209 struct xfs_attr_leafblock *leaf;
1210 struct xfs_attr3_icleaf_hdr ichdr;
1211 struct xfs_inode *dp = args->dp;
1212 struct xfs_mount *mp = dp->i_mount;
1213 struct xfs_buf *bp;
1214 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001215
Dave Chinner5a5881c2012-03-22 05:15:13 +00001216 trace_xfs_attr_leaf_create(args);
1217
Christoph Hellwig2911edb2019-11-20 09:46:05 -08001218 error = xfs_da_get_buf(args->trans, args->dp, blkno, &bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001219 XFS_ATTR_FORK);
1220 if (error)
Dave Chinner517c2222013-04-24 18:58:55 +10001221 return error;
1222 bp->b_ops = &xfs_attr3_leaf_buf_ops;
Dave Chinner61fe1352013-04-03 16:11:30 +11001223 xfs_trans_buf_set_type(args->trans, bp, XFS_BLFT_ATTR_LEAF_BUF);
Dave Chinner1d9025e2012-06-22 18:50:14 +10001224 leaf = bp->b_addr;
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001225 memset(leaf, 0, args->geo->blksize);
Dave Chinner517c2222013-04-24 18:58:55 +10001226
1227 memset(&ichdr, 0, sizeof(ichdr));
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001228 ichdr.firstused = args->geo->blksize;
Dave Chinner517c2222013-04-24 18:58:55 +10001229
1230 if (xfs_sb_version_hascrc(&mp->m_sb)) {
1231 struct xfs_da3_blkinfo *hdr3 = bp->b_addr;
1232
1233 ichdr.magic = XFS_ATTR3_LEAF_MAGIC;
1234
1235 hdr3->blkno = cpu_to_be64(bp->b_bn);
1236 hdr3->owner = cpu_to_be64(dp->i_ino);
Eric Sandeence748ea2015-07-29 11:53:31 +10001237 uuid_copy(&hdr3->uuid, &mp->m_sb.sb_meta_uuid);
Dave Chinner517c2222013-04-24 18:58:55 +10001238
1239 ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
1240 } else {
1241 ichdr.magic = XFS_ATTR_LEAF_MAGIC;
1242 ichdr.freemap[0].base = sizeof(struct xfs_attr_leaf_hdr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 }
Dave Chinner517c2222013-04-24 18:58:55 +10001244 ichdr.freemap[0].size = ichdr.firstused - ichdr.freemap[0].base;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001245
Brian Foster2f661242015-04-13 11:26:02 +10001246 xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr);
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001247 xfs_trans_log_buf(args->trans, bp, 0, args->geo->blksize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001248
1249 *bpp = bp;
Dave Chinner517c2222013-04-24 18:58:55 +10001250 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001251}
1252
1253/*
1254 * Split the leaf node, rebalance, then add the new entry.
1255 */
1256int
Dave Chinner517c2222013-04-24 18:58:55 +10001257xfs_attr3_leaf_split(
1258 struct xfs_da_state *state,
1259 struct xfs_da_state_blk *oldblk,
1260 struct xfs_da_state_blk *newblk)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261{
1262 xfs_dablk_t blkno;
1263 int error;
1264
Dave Chinner5a5881c2012-03-22 05:15:13 +00001265 trace_xfs_attr_leaf_split(state->args);
1266
Linus Torvalds1da177e2005-04-16 15:20:36 -07001267 /*
1268 * Allocate space for a new leaf node.
1269 */
1270 ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC);
1271 error = xfs_da_grow_inode(state->args, &blkno);
1272 if (error)
Eric Sandeend99831f2014-06-22 15:03:54 +10001273 return error;
Dave Chinner517c2222013-04-24 18:58:55 +10001274 error = xfs_attr3_leaf_create(state->args, blkno, &newblk->bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001275 if (error)
Eric Sandeend99831f2014-06-22 15:03:54 +10001276 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001277 newblk->blkno = blkno;
1278 newblk->magic = XFS_ATTR_LEAF_MAGIC;
1279
1280 /*
1281 * Rebalance the entries across the two leaves.
1282 * NOTE: rebalance() currently depends on the 2nd block being empty.
1283 */
Dave Chinner517c2222013-04-24 18:58:55 +10001284 xfs_attr3_leaf_rebalance(state, oldblk, newblk);
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001285 error = xfs_da3_blk_link(state, oldblk, newblk);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001286 if (error)
Eric Sandeend99831f2014-06-22 15:03:54 +10001287 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001288
1289 /*
1290 * Save info on "old" attribute for "atomic rename" ops, leaf_add()
1291 * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the
1292 * "new" attrs info. Will need the "old" info to remove it later.
1293 *
1294 * Insert the "new" entry in the correct block.
1295 */
Dave Chinner5a5881c2012-03-22 05:15:13 +00001296 if (state->inleaf) {
1297 trace_xfs_attr_leaf_add_old(state->args);
Dave Chinner517c2222013-04-24 18:58:55 +10001298 error = xfs_attr3_leaf_add(oldblk->bp, state->args);
Dave Chinner5a5881c2012-03-22 05:15:13 +00001299 } else {
1300 trace_xfs_attr_leaf_add_new(state->args);
Dave Chinner517c2222013-04-24 18:58:55 +10001301 error = xfs_attr3_leaf_add(newblk->bp, state->args);
Dave Chinner5a5881c2012-03-22 05:15:13 +00001302 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001303
1304 /*
1305 * Update last hashval in each block since we added the name.
1306 */
1307 oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL);
1308 newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL);
Eric Sandeend99831f2014-06-22 15:03:54 +10001309 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001310}
1311
1312/*
1313 * Add a name to the leaf attribute list structure.
1314 */
1315int
Dave Chinner517c2222013-04-24 18:58:55 +10001316xfs_attr3_leaf_add(
Dave Chinner1d9025e2012-06-22 18:50:14 +10001317 struct xfs_buf *bp,
1318 struct xfs_da_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001319{
Dave Chinner517c2222013-04-24 18:58:55 +10001320 struct xfs_attr_leafblock *leaf;
1321 struct xfs_attr3_icleaf_hdr ichdr;
1322 int tablesize;
1323 int entsize;
1324 int sum;
1325 int tmp;
1326 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001327
Dave Chinner5a5881c2012-03-22 05:15:13 +00001328 trace_xfs_attr_leaf_add(args);
1329
Dave Chinner1d9025e2012-06-22 18:50:14 +10001330 leaf = bp->b_addr;
Brian Foster2f661242015-04-13 11:26:02 +10001331 xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
Dave Chinner517c2222013-04-24 18:58:55 +10001332 ASSERT(args->index >= 0 && args->index <= ichdr.count);
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10001333 entsize = xfs_attr_leaf_newentsize(args, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001334
1335 /*
1336 * Search through freemap for first-fit on new name length.
1337 * (may need to figure in size of entry struct too)
1338 */
Dave Chinner517c2222013-04-24 18:58:55 +10001339 tablesize = (ichdr.count + 1) * sizeof(xfs_attr_leaf_entry_t)
1340 + xfs_attr3_leaf_hdr_size(leaf);
1341 for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE - 1; i >= 0; i--) {
1342 if (tablesize > ichdr.firstused) {
1343 sum += ichdr.freemap[i].size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001344 continue;
1345 }
Dave Chinner517c2222013-04-24 18:58:55 +10001346 if (!ichdr.freemap[i].size)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 continue; /* no space in this map */
1348 tmp = entsize;
Dave Chinner517c2222013-04-24 18:58:55 +10001349 if (ichdr.freemap[i].base < ichdr.firstused)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001350 tmp += sizeof(xfs_attr_leaf_entry_t);
Dave Chinner517c2222013-04-24 18:58:55 +10001351 if (ichdr.freemap[i].size >= tmp) {
1352 tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, i);
1353 goto out_log_hdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001354 }
Dave Chinner517c2222013-04-24 18:58:55 +10001355 sum += ichdr.freemap[i].size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001356 }
1357
1358 /*
1359 * If there are no holes in the address space of the block,
1360 * and we don't have enough freespace, then compaction will do us
1361 * no good and we should just give up.
1362 */
Dave Chinner517c2222013-04-24 18:58:55 +10001363 if (!ichdr.holes && sum < entsize)
Dave Chinner24513372014-06-25 14:58:08 +10001364 return -ENOSPC;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001365
1366 /*
1367 * Compact the entries to coalesce free space.
1368 * This may change the hdr->count via dropping INCOMPLETE entries.
1369 */
Dave Chinner517c2222013-04-24 18:58:55 +10001370 xfs_attr3_leaf_compact(args, &ichdr, bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001371
1372 /*
1373 * After compaction, the block is guaranteed to have only one
1374 * free region, in freemap[0]. If it is not big enough, give up.
1375 */
Dave Chinner517c2222013-04-24 18:58:55 +10001376 if (ichdr.freemap[0].size < (entsize + sizeof(xfs_attr_leaf_entry_t))) {
Dave Chinner24513372014-06-25 14:58:08 +10001377 tmp = -ENOSPC;
Dave Chinner517c2222013-04-24 18:58:55 +10001378 goto out_log_hdr;
1379 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001380
Dave Chinner517c2222013-04-24 18:58:55 +10001381 tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, 0);
1382
1383out_log_hdr:
Brian Foster2f661242015-04-13 11:26:02 +10001384 xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr);
Dave Chinner517c2222013-04-24 18:58:55 +10001385 xfs_trans_log_buf(args->trans, bp,
1386 XFS_DA_LOGRANGE(leaf, &leaf->hdr,
1387 xfs_attr3_leaf_hdr_size(leaf)));
1388 return tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001389}
1390
1391/*
1392 * Add a name to a leaf attribute list structure.
1393 */
1394STATIC int
Dave Chinner517c2222013-04-24 18:58:55 +10001395xfs_attr3_leaf_add_work(
1396 struct xfs_buf *bp,
1397 struct xfs_attr3_icleaf_hdr *ichdr,
1398 struct xfs_da_args *args,
1399 int mapindex)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001400{
Dave Chinner517c2222013-04-24 18:58:55 +10001401 struct xfs_attr_leafblock *leaf;
1402 struct xfs_attr_leaf_entry *entry;
1403 struct xfs_attr_leaf_name_local *name_loc;
1404 struct xfs_attr_leaf_name_remote *name_rmt;
1405 struct xfs_mount *mp;
1406 int tmp;
1407 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001408
Dave Chinneree732592012-11-12 22:53:53 +11001409 trace_xfs_attr_leaf_add_work(args);
1410
Dave Chinner1d9025e2012-06-22 18:50:14 +10001411 leaf = bp->b_addr;
Dave Chinner517c2222013-04-24 18:58:55 +10001412 ASSERT(mapindex >= 0 && mapindex < XFS_ATTR_LEAF_MAPSIZE);
1413 ASSERT(args->index >= 0 && args->index <= ichdr->count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414
1415 /*
1416 * Force open some space in the entry array and fill it in.
1417 */
Dave Chinner517c2222013-04-24 18:58:55 +10001418 entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
1419 if (args->index < ichdr->count) {
1420 tmp = ichdr->count - args->index;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001421 tmp *= sizeof(xfs_attr_leaf_entry_t);
Dave Chinner517c2222013-04-24 18:58:55 +10001422 memmove(entry + 1, entry, tmp);
Dave Chinner1d9025e2012-06-22 18:50:14 +10001423 xfs_trans_log_buf(args->trans, bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
1425 }
Dave Chinner517c2222013-04-24 18:58:55 +10001426 ichdr->count++;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001427
1428 /*
1429 * Allocate space for the new string (at the end of the run).
1430 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001431 mp = args->trans->t_mountp;
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001432 ASSERT(ichdr->freemap[mapindex].base < args->geo->blksize);
Dave Chinner517c2222013-04-24 18:58:55 +10001433 ASSERT((ichdr->freemap[mapindex].base & 0x3) == 0);
1434 ASSERT(ichdr->freemap[mapindex].size >=
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10001435 xfs_attr_leaf_newentsize(args, NULL));
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001436 ASSERT(ichdr->freemap[mapindex].size < args->geo->blksize);
Dave Chinner517c2222013-04-24 18:58:55 +10001437 ASSERT((ichdr->freemap[mapindex].size & 0x3) == 0);
1438
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10001439 ichdr->freemap[mapindex].size -= xfs_attr_leaf_newentsize(args, &tmp);
Dave Chinner517c2222013-04-24 18:58:55 +10001440
1441 entry->nameidx = cpu_to_be16(ichdr->freemap[mapindex].base +
1442 ichdr->freemap[mapindex].size);
Nathan Scott6b19f2d2006-03-17 17:29:02 +11001443 entry->hashval = cpu_to_be32(args->hashval);
Christoph Hellwigd5f0f492020-02-26 17:30:42 -08001444 entry->flags = args->attr_filter;
1445 if (tmp)
1446 entry->flags |= XFS_ATTR_LOCAL;
Barry Naujok6a178102008-05-21 16:42:05 +10001447 if (args->op_flags & XFS_DA_OP_RENAME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001448 entry->flags |= XFS_ATTR_INCOMPLETE;
1449 if ((args->blkno2 == args->blkno) &&
1450 (args->index2 <= args->index)) {
1451 args->index2++;
1452 }
1453 }
Dave Chinner1d9025e2012-06-22 18:50:14 +10001454 xfs_trans_log_buf(args->trans, bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
Nathan Scott6b19f2d2006-03-17 17:29:02 +11001456 ASSERT((args->index == 0) ||
1457 (be32_to_cpu(entry->hashval) >= be32_to_cpu((entry-1)->hashval)));
Dave Chinner517c2222013-04-24 18:58:55 +10001458 ASSERT((args->index == ichdr->count - 1) ||
Nathan Scott6b19f2d2006-03-17 17:29:02 +11001459 (be32_to_cpu(entry->hashval) <= be32_to_cpu((entry+1)->hashval)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001460
1461 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001462 * For "remote" attribute values, simply note that we need to
1463 * allocate space for the "remote" value. We can't actually
1464 * allocate the extents in this transaction, and we can't decide
1465 * which blocks they should be as we might allocate more blocks
1466 * as part of this transaction (a split operation for example).
1467 */
1468 if (entry->flags & XFS_ATTR_LOCAL) {
Dave Chinner517c2222013-04-24 18:58:55 +10001469 name_loc = xfs_attr3_leaf_name_local(leaf, args->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001470 name_loc->namelen = args->namelen;
Nathan Scott053b5752006-03-17 17:29:09 +11001471 name_loc->valuelen = cpu_to_be16(args->valuelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001472 memcpy((char *)name_loc->nameval, args->name, args->namelen);
1473 memcpy((char *)&name_loc->nameval[args->namelen], args->value,
Nathan Scott053b5752006-03-17 17:29:09 +11001474 be16_to_cpu(name_loc->valuelen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001475 } else {
Dave Chinner517c2222013-04-24 18:58:55 +10001476 name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001477 name_rmt->namelen = args->namelen;
1478 memcpy((char *)name_rmt->name, args->name, args->namelen);
1479 entry->flags |= XFS_ATTR_INCOMPLETE;
1480 /* just in case */
1481 name_rmt->valuelen = 0;
1482 name_rmt->valueblk = 0;
1483 args->rmtblkno = 1;
Dave Chinnerad1858d2013-05-21 18:02:08 +10001484 args->rmtblkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen);
Dave Chinner8275cdd2014-05-06 07:37:31 +10001485 args->rmtvaluelen = args->valuelen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001486 }
Dave Chinner1d9025e2012-06-22 18:50:14 +10001487 xfs_trans_log_buf(args->trans, bp,
Dave Chinner517c2222013-04-24 18:58:55 +10001488 XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 xfs_attr_leaf_entsize(leaf, args->index)));
1490
1491 /*
1492 * Update the control info for this leaf node
1493 */
Dave Chinner517c2222013-04-24 18:58:55 +10001494 if (be16_to_cpu(entry->nameidx) < ichdr->firstused)
1495 ichdr->firstused = be16_to_cpu(entry->nameidx);
1496
1497 ASSERT(ichdr->firstused >= ichdr->count * sizeof(xfs_attr_leaf_entry_t)
1498 + xfs_attr3_leaf_hdr_size(leaf));
1499 tmp = (ichdr->count - 1) * sizeof(xfs_attr_leaf_entry_t)
1500 + xfs_attr3_leaf_hdr_size(leaf);
1501
1502 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
1503 if (ichdr->freemap[i].base == tmp) {
1504 ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t);
Brian Foster2a2b5932019-11-15 21:15:08 -08001505 ichdr->freemap[i].size -=
1506 min_t(uint16_t, ichdr->freemap[i].size,
1507 sizeof(xfs_attr_leaf_entry_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001508 }
1509 }
Dave Chinner517c2222013-04-24 18:58:55 +10001510 ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index);
1511 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001512}
1513
1514/*
1515 * Garbage collect a leaf attribute list block by copying it to a new buffer.
1516 */
1517STATIC void
Dave Chinner517c2222013-04-24 18:58:55 +10001518xfs_attr3_leaf_compact(
Dave Chinneree732592012-11-12 22:53:53 +11001519 struct xfs_da_args *args,
Dave Chinnerd4c712b2013-05-21 18:02:06 +10001520 struct xfs_attr3_icleaf_hdr *ichdr_dst,
Dave Chinneree732592012-11-12 22:53:53 +11001521 struct xfs_buf *bp)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522{
Dave Chinnerd4c712b2013-05-21 18:02:06 +10001523 struct xfs_attr_leafblock *leaf_src;
1524 struct xfs_attr_leafblock *leaf_dst;
1525 struct xfs_attr3_icleaf_hdr ichdr_src;
Dave Chinneree732592012-11-12 22:53:53 +11001526 struct xfs_trans *trans = args->trans;
Dave Chinneree732592012-11-12 22:53:53 +11001527 char *tmpbuffer;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001528
Dave Chinneree732592012-11-12 22:53:53 +11001529 trace_xfs_attr_leaf_compact(args);
1530
Tetsuo Handa707e0dd2019-08-26 12:06:22 -07001531 tmpbuffer = kmem_alloc(args->geo->blksize, 0);
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001532 memcpy(tmpbuffer, bp->b_addr, args->geo->blksize);
1533 memset(bp->b_addr, 0, args->geo->blksize);
Dave Chinnerd4c712b2013-05-21 18:02:06 +10001534 leaf_src = (xfs_attr_leafblock_t *)tmpbuffer;
1535 leaf_dst = bp->b_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001536
1537 /*
Dave Chinnerd4c712b2013-05-21 18:02:06 +10001538 * Copy the on-disk header back into the destination buffer to ensure
1539 * all the information in the header that is not part of the incore
1540 * header structure is preserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 */
Dave Chinnerd4c712b2013-05-21 18:02:06 +10001542 memcpy(bp->b_addr, tmpbuffer, xfs_attr3_leaf_hdr_size(leaf_src));
1543
1544 /* Initialise the incore headers */
1545 ichdr_src = *ichdr_dst; /* struct copy */
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001546 ichdr_dst->firstused = args->geo->blksize;
Dave Chinnerd4c712b2013-05-21 18:02:06 +10001547 ichdr_dst->usedbytes = 0;
1548 ichdr_dst->count = 0;
1549 ichdr_dst->holes = 0;
1550 ichdr_dst->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_src);
1551 ichdr_dst->freemap[0].size = ichdr_dst->firstused -
1552 ichdr_dst->freemap[0].base;
1553
Dave Chinnerd4c712b2013-05-21 18:02:06 +10001554 /* write the header back to initialise the underlying buffer */
Brian Foster2f661242015-04-13 11:26:02 +10001555 xfs_attr3_leaf_hdr_to_disk(args->geo, leaf_dst, ichdr_dst);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001556
1557 /*
1558 * Copy all entry's in the same (sorted) order,
1559 * but allocate name/value pairs packed and in sequence.
1560 */
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001561 xfs_attr3_leaf_moveents(args, leaf_src, &ichdr_src, 0,
1562 leaf_dst, ichdr_dst, 0, ichdr_src.count);
Dave Chinner517c2222013-04-24 18:58:55 +10001563 /*
1564 * this logs the entire buffer, but the caller must write the header
1565 * back to the buffer when it is finished modifying it.
1566 */
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001567 xfs_trans_log_buf(trans, bp, 0, args->geo->blksize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001568
Denys Vlasenkof0e2d932008-05-19 16:31:57 +10001569 kmem_free(tmpbuffer);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001570}
1571
1572/*
Dave Chinner517c2222013-04-24 18:58:55 +10001573 * Compare two leaf blocks "order".
1574 * Return 0 unless leaf2 should go before leaf1.
1575 */
1576static int
1577xfs_attr3_leaf_order(
1578 struct xfs_buf *leaf1_bp,
1579 struct xfs_attr3_icleaf_hdr *leaf1hdr,
1580 struct xfs_buf *leaf2_bp,
1581 struct xfs_attr3_icleaf_hdr *leaf2hdr)
1582{
1583 struct xfs_attr_leaf_entry *entries1;
1584 struct xfs_attr_leaf_entry *entries2;
1585
1586 entries1 = xfs_attr3_leaf_entryp(leaf1_bp->b_addr);
1587 entries2 = xfs_attr3_leaf_entryp(leaf2_bp->b_addr);
1588 if (leaf1hdr->count > 0 && leaf2hdr->count > 0 &&
1589 ((be32_to_cpu(entries2[0].hashval) <
1590 be32_to_cpu(entries1[0].hashval)) ||
1591 (be32_to_cpu(entries2[leaf2hdr->count - 1].hashval) <
1592 be32_to_cpu(entries1[leaf1hdr->count - 1].hashval)))) {
1593 return 1;
1594 }
1595 return 0;
1596}
1597
1598int
1599xfs_attr_leaf_order(
1600 struct xfs_buf *leaf1_bp,
1601 struct xfs_buf *leaf2_bp)
1602{
1603 struct xfs_attr3_icleaf_hdr ichdr1;
1604 struct xfs_attr3_icleaf_hdr ichdr2;
Christoph Hellwigdbd329f12019-06-28 19:27:29 -07001605 struct xfs_mount *mp = leaf1_bp->b_mount;
Dave Chinner517c2222013-04-24 18:58:55 +10001606
Brian Foster2f661242015-04-13 11:26:02 +10001607 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr1, leaf1_bp->b_addr);
1608 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr2, leaf2_bp->b_addr);
Dave Chinner517c2222013-04-24 18:58:55 +10001609 return xfs_attr3_leaf_order(leaf1_bp, &ichdr1, leaf2_bp, &ichdr2);
1610}
1611
1612/*
Linus Torvalds1da177e2005-04-16 15:20:36 -07001613 * Redistribute the attribute list entries between two leaf nodes,
1614 * taking into account the size of the new entry.
1615 *
1616 * NOTE: if new block is empty, then it will get the upper half of the
1617 * old block. At present, all (one) callers pass in an empty second block.
1618 *
1619 * This code adjusts the args->index/blkno and args->index2/blkno2 fields
1620 * to match what it is doing in splitting the attribute leaf block. Those
1621 * values are used in "atomic rename" operations on attributes. Note that
1622 * the "new" and "old" values can end up in different blocks.
1623 */
1624STATIC void
Dave Chinner517c2222013-04-24 18:58:55 +10001625xfs_attr3_leaf_rebalance(
1626 struct xfs_da_state *state,
1627 struct xfs_da_state_blk *blk1,
1628 struct xfs_da_state_blk *blk2)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001629{
Dave Chinner517c2222013-04-24 18:58:55 +10001630 struct xfs_da_args *args;
1631 struct xfs_attr_leafblock *leaf1;
1632 struct xfs_attr_leafblock *leaf2;
1633 struct xfs_attr3_icleaf_hdr ichdr1;
1634 struct xfs_attr3_icleaf_hdr ichdr2;
1635 struct xfs_attr_leaf_entry *entries1;
1636 struct xfs_attr_leaf_entry *entries2;
1637 int count;
1638 int totallen;
1639 int max;
1640 int space;
1641 int swap;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001642
1643 /*
1644 * Set up environment.
1645 */
1646 ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC);
1647 ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC);
Dave Chinner1d9025e2012-06-22 18:50:14 +10001648 leaf1 = blk1->bp->b_addr;
1649 leaf2 = blk2->bp->b_addr;
Brian Foster2f661242015-04-13 11:26:02 +10001650 xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr1, leaf1);
1651 xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr2, leaf2);
Dave Chinner517c2222013-04-24 18:58:55 +10001652 ASSERT(ichdr2.count == 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653 args = state->args;
1654
Dave Chinner5a5881c2012-03-22 05:15:13 +00001655 trace_xfs_attr_leaf_rebalance(args);
1656
Linus Torvalds1da177e2005-04-16 15:20:36 -07001657 /*
1658 * Check ordering of blocks, reverse if it makes things simpler.
1659 *
1660 * NOTE: Given that all (current) callers pass in an empty
1661 * second block, this code should never set "swap".
1662 */
1663 swap = 0;
Dave Chinner517c2222013-04-24 18:58:55 +10001664 if (xfs_attr3_leaf_order(blk1->bp, &ichdr1, blk2->bp, &ichdr2)) {
Gustavo A. R. Silva1d5bebb2018-07-11 22:26:38 -07001665 swap(blk1, blk2);
Dave Chinner517c2222013-04-24 18:58:55 +10001666
Gustavo A. R. Silva1d5bebb2018-07-11 22:26:38 -07001667 /* swap structures rather than reconverting them */
1668 swap(ichdr1, ichdr2);
Dave Chinner517c2222013-04-24 18:58:55 +10001669
Dave Chinner1d9025e2012-06-22 18:50:14 +10001670 leaf1 = blk1->bp->b_addr;
1671 leaf2 = blk2->bp->b_addr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001672 swap = 1;
1673 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001674
1675 /*
1676 * Examine entries until we reduce the absolute difference in
1677 * byte usage between the two blocks to a minimum. Then get
1678 * the direction to copy and the number of elements to move.
1679 *
1680 * "inleaf" is true if the new entry should be inserted into blk1.
1681 * If "swap" is also true, then reverse the sense of "inleaf".
1682 */
Dave Chinner517c2222013-04-24 18:58:55 +10001683 state->inleaf = xfs_attr3_leaf_figure_balance(state, blk1, &ichdr1,
1684 blk2, &ichdr2,
1685 &count, &totallen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001686 if (swap)
1687 state->inleaf = !state->inleaf;
1688
1689 /*
1690 * Move any entries required from leaf to leaf:
1691 */
Dave Chinner517c2222013-04-24 18:58:55 +10001692 if (count < ichdr1.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001693 /*
1694 * Figure the total bytes to be added to the destination leaf.
1695 */
1696 /* number entries being moved */
Dave Chinner517c2222013-04-24 18:58:55 +10001697 count = ichdr1.count - count;
1698 space = ichdr1.usedbytes - totallen;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001699 space += count * sizeof(xfs_attr_leaf_entry_t);
1700
1701 /*
1702 * leaf2 is the destination, compact it if it looks tight.
1703 */
Dave Chinner517c2222013-04-24 18:58:55 +10001704 max = ichdr2.firstused - xfs_attr3_leaf_hdr_size(leaf1);
1705 max -= ichdr2.count * sizeof(xfs_attr_leaf_entry_t);
Dave Chinneree732592012-11-12 22:53:53 +11001706 if (space > max)
Dave Chinner517c2222013-04-24 18:58:55 +10001707 xfs_attr3_leaf_compact(args, &ichdr2, blk2->bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001708
1709 /*
1710 * Move high entries from leaf1 to low end of leaf2.
1711 */
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001712 xfs_attr3_leaf_moveents(args, leaf1, &ichdr1,
1713 ichdr1.count - count, leaf2, &ichdr2, 0, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001714
Dave Chinner517c2222013-04-24 18:58:55 +10001715 } else if (count > ichdr1.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001716 /*
1717 * I assert that since all callers pass in an empty
1718 * second buffer, this code should never execute.
1719 */
Dave Chinner07428d72012-11-12 22:09:44 +11001720 ASSERT(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001721
1722 /*
1723 * Figure the total bytes to be added to the destination leaf.
1724 */
1725 /* number entries being moved */
Dave Chinner517c2222013-04-24 18:58:55 +10001726 count -= ichdr1.count;
1727 space = totallen - ichdr1.usedbytes;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001728 space += count * sizeof(xfs_attr_leaf_entry_t);
1729
1730 /*
1731 * leaf1 is the destination, compact it if it looks tight.
1732 */
Dave Chinner517c2222013-04-24 18:58:55 +10001733 max = ichdr1.firstused - xfs_attr3_leaf_hdr_size(leaf1);
1734 max -= ichdr1.count * sizeof(xfs_attr_leaf_entry_t);
Dave Chinneree732592012-11-12 22:53:53 +11001735 if (space > max)
Dave Chinner517c2222013-04-24 18:58:55 +10001736 xfs_attr3_leaf_compact(args, &ichdr1, blk1->bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001737
1738 /*
1739 * Move low entries from leaf2 to high end of leaf1.
1740 */
Dave Chinnerc2c4c472014-06-06 15:21:45 +10001741 xfs_attr3_leaf_moveents(args, leaf2, &ichdr2, 0, leaf1, &ichdr1,
1742 ichdr1.count, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001743 }
1744
Brian Foster2f661242015-04-13 11:26:02 +10001745 xfs_attr3_leaf_hdr_to_disk(state->args->geo, leaf1, &ichdr1);
1746 xfs_attr3_leaf_hdr_to_disk(state->args->geo, leaf2, &ichdr2);
Dave Chinnerb2a21e72014-06-06 15:22:04 +10001747 xfs_trans_log_buf(args->trans, blk1->bp, 0, args->geo->blksize - 1);
1748 xfs_trans_log_buf(args->trans, blk2->bp, 0, args->geo->blksize - 1);
Dave Chinner517c2222013-04-24 18:58:55 +10001749
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 /*
1751 * Copy out last hashval in each block for B-tree code.
1752 */
Dave Chinner517c2222013-04-24 18:58:55 +10001753 entries1 = xfs_attr3_leaf_entryp(leaf1);
1754 entries2 = xfs_attr3_leaf_entryp(leaf2);
1755 blk1->hashval = be32_to_cpu(entries1[ichdr1.count - 1].hashval);
1756 blk2->hashval = be32_to_cpu(entries2[ichdr2.count - 1].hashval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001757
1758 /*
1759 * Adjust the expected index for insertion.
1760 * NOTE: this code depends on the (current) situation that the
1761 * second block was originally empty.
1762 *
1763 * If the insertion point moved to the 2nd block, we must adjust
1764 * the index. We must also track the entry just following the
1765 * new entry for use in an "atomic rename" operation, that entry
1766 * is always the "old" entry and the "new" entry is what we are
1767 * inserting. The index/blkno fields refer to the "old" entry,
1768 * while the index2/blkno2 fields refer to the "new" entry.
1769 */
Dave Chinner517c2222013-04-24 18:58:55 +10001770 if (blk1->index > ichdr1.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001771 ASSERT(state->inleaf == 0);
Dave Chinner517c2222013-04-24 18:58:55 +10001772 blk2->index = blk1->index - ichdr1.count;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001773 args->index = args->index2 = blk2->index;
1774 args->blkno = args->blkno2 = blk2->blkno;
Dave Chinner517c2222013-04-24 18:58:55 +10001775 } else if (blk1->index == ichdr1.count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001776 if (state->inleaf) {
1777 args->index = blk1->index;
1778 args->blkno = blk1->blkno;
1779 args->index2 = 0;
1780 args->blkno2 = blk2->blkno;
1781 } else {
Dave Chinner07428d72012-11-12 22:09:44 +11001782 /*
1783 * On a double leaf split, the original attr location
1784 * is already stored in blkno2/index2, so don't
1785 * overwrite it overwise we corrupt the tree.
1786 */
Dave Chinner517c2222013-04-24 18:58:55 +10001787 blk2->index = blk1->index - ichdr1.count;
Dave Chinner07428d72012-11-12 22:09:44 +11001788 args->index = blk2->index;
1789 args->blkno = blk2->blkno;
1790 if (!state->extravalid) {
1791 /*
1792 * set the new attr location to match the old
1793 * one and let the higher level split code
1794 * decide where in the leaf to place it.
1795 */
1796 args->index2 = blk2->index;
1797 args->blkno2 = blk2->blkno;
1798 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001799 }
1800 } else {
1801 ASSERT(state->inleaf == 1);
1802 args->index = args->index2 = blk1->index;
1803 args->blkno = args->blkno2 = blk1->blkno;
1804 }
1805}
1806
1807/*
1808 * Examine entries until we reduce the absolute difference in
1809 * byte usage between the two blocks to a minimum.
1810 * GROT: Is this really necessary? With other than a 512 byte blocksize,
1811 * GROT: there will always be enough room in either block for a new entry.
1812 * GROT: Do a double-split for this case?
1813 */
1814STATIC int
Dave Chinner517c2222013-04-24 18:58:55 +10001815xfs_attr3_leaf_figure_balance(
1816 struct xfs_da_state *state,
1817 struct xfs_da_state_blk *blk1,
1818 struct xfs_attr3_icleaf_hdr *ichdr1,
1819 struct xfs_da_state_blk *blk2,
1820 struct xfs_attr3_icleaf_hdr *ichdr2,
1821 int *countarg,
1822 int *usedbytesarg)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001823{
Dave Chinner517c2222013-04-24 18:58:55 +10001824 struct xfs_attr_leafblock *leaf1 = blk1->bp->b_addr;
1825 struct xfs_attr_leafblock *leaf2 = blk2->bp->b_addr;
1826 struct xfs_attr_leaf_entry *entry;
1827 int count;
1828 int max;
1829 int index;
1830 int totallen = 0;
1831 int half;
1832 int lastdelta;
1833 int foundit = 0;
1834 int tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001835
1836 /*
1837 * Examine entries until we reduce the absolute difference in
1838 * byte usage between the two blocks to a minimum.
1839 */
Dave Chinner517c2222013-04-24 18:58:55 +10001840 max = ichdr1->count + ichdr2->count;
1841 half = (max + 1) * sizeof(*entry);
1842 half += ichdr1->usedbytes + ichdr2->usedbytes +
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10001843 xfs_attr_leaf_newentsize(state->args, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001844 half /= 2;
Dave Chinnerb2a21e72014-06-06 15:22:04 +10001845 lastdelta = state->args->geo->blksize;
Dave Chinner517c2222013-04-24 18:58:55 +10001846 entry = xfs_attr3_leaf_entryp(leaf1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001847 for (count = index = 0; count < max; entry++, index++, count++) {
1848
1849#define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A))
1850 /*
1851 * The new entry is in the first block, account for it.
1852 */
1853 if (count == blk1->index) {
1854 tmp = totallen + sizeof(*entry) +
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10001855 xfs_attr_leaf_newentsize(state->args, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001856 if (XFS_ATTR_ABS(half - tmp) > lastdelta)
1857 break;
1858 lastdelta = XFS_ATTR_ABS(half - tmp);
1859 totallen = tmp;
1860 foundit = 1;
1861 }
1862
1863 /*
1864 * Wrap around into the second block if necessary.
1865 */
Dave Chinner517c2222013-04-24 18:58:55 +10001866 if (count == ichdr1->count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001867 leaf1 = leaf2;
Dave Chinner517c2222013-04-24 18:58:55 +10001868 entry = xfs_attr3_leaf_entryp(leaf1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001869 index = 0;
1870 }
1871
1872 /*
1873 * Figure out if next leaf entry would be too much.
1874 */
1875 tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1,
1876 index);
1877 if (XFS_ATTR_ABS(half - tmp) > lastdelta)
1878 break;
1879 lastdelta = XFS_ATTR_ABS(half - tmp);
1880 totallen = tmp;
1881#undef XFS_ATTR_ABS
1882 }
1883
1884 /*
1885 * Calculate the number of usedbytes that will end up in lower block.
1886 * If new entry not in lower block, fix up the count.
1887 */
1888 totallen -= count * sizeof(*entry);
1889 if (foundit) {
1890 totallen -= sizeof(*entry) +
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10001891 xfs_attr_leaf_newentsize(state->args, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001892 }
1893
1894 *countarg = count;
1895 *usedbytesarg = totallen;
Dave Chinner517c2222013-04-24 18:58:55 +10001896 return foundit;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001897}
1898
1899/*========================================================================
1900 * Routines used for shrinking the Btree.
1901 *========================================================================*/
1902
1903/*
1904 * Check a leaf block and its neighbors to see if the block should be
1905 * collapsed into one or the other neighbor. Always keep the block
1906 * with the smaller block number.
1907 * If the current block is over 50% full, don't try to join it, return 0.
1908 * If the block is empty, fill in the state structure and return 2.
1909 * If it can be collapsed, fill in the state structure and return 1.
1910 * If nothing can be done, return 0.
1911 *
1912 * GROT: allow for INCOMPLETE entries in calculation.
1913 */
1914int
Dave Chinner517c2222013-04-24 18:58:55 +10001915xfs_attr3_leaf_toosmall(
1916 struct xfs_da_state *state,
1917 int *action)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001918{
Dave Chinner517c2222013-04-24 18:58:55 +10001919 struct xfs_attr_leafblock *leaf;
1920 struct xfs_da_state_blk *blk;
1921 struct xfs_attr3_icleaf_hdr ichdr;
1922 struct xfs_buf *bp;
1923 xfs_dablk_t blkno;
1924 int bytes;
1925 int forward;
1926 int error;
1927 int retval;
1928 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001929
Dave Chinneree732592012-11-12 22:53:53 +11001930 trace_xfs_attr_leaf_toosmall(state->args);
1931
Linus Torvalds1da177e2005-04-16 15:20:36 -07001932 /*
1933 * Check for the degenerate case of the block being over 50% full.
1934 * If so, it's not worth even looking to see if we might be able
1935 * to coalesce with a sibling.
1936 */
1937 blk = &state->path.blk[ state->path.active-1 ];
Dave Chinner517c2222013-04-24 18:58:55 +10001938 leaf = blk->bp->b_addr;
Brian Foster2f661242015-04-13 11:26:02 +10001939 xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr, leaf);
Dave Chinner517c2222013-04-24 18:58:55 +10001940 bytes = xfs_attr3_leaf_hdr_size(leaf) +
1941 ichdr.count * sizeof(xfs_attr_leaf_entry_t) +
1942 ichdr.usedbytes;
Dave Chinnerb2a21e72014-06-06 15:22:04 +10001943 if (bytes > (state->args->geo->blksize >> 1)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001944 *action = 0; /* blk over 50%, don't try to join */
Eric Sandeend99831f2014-06-22 15:03:54 +10001945 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001946 }
1947
1948 /*
1949 * Check for the degenerate case of the block being empty.
1950 * If the block is empty, we'll simply delete it, no need to
Nathan Scottc41564b2006-03-29 08:55:14 +10001951 * coalesce it with a sibling block. We choose (arbitrarily)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001952 * to merge with the forward block unless it is NULL.
1953 */
Dave Chinner517c2222013-04-24 18:58:55 +10001954 if (ichdr.count == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001955 /*
1956 * Make altpath point to the block we want to keep and
1957 * path point to the block we want to drop (this one).
1958 */
Dave Chinner517c2222013-04-24 18:58:55 +10001959 forward = (ichdr.forw != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001960 memcpy(&state->altpath, &state->path, sizeof(state->path));
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001961 error = xfs_da3_path_shift(state, &state->altpath, forward,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001962 0, &retval);
1963 if (error)
Eric Sandeend99831f2014-06-22 15:03:54 +10001964 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001965 if (retval) {
1966 *action = 0;
1967 } else {
1968 *action = 2;
1969 }
Dave Chinner517c2222013-04-24 18:58:55 +10001970 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001971 }
1972
1973 /*
1974 * Examine each sibling block to see if we can coalesce with
1975 * at least 25% free space to spare. We need to figure out
1976 * whether to merge with the forward or the backward block.
1977 * We prefer coalescing with the lower numbered sibling so as
1978 * to shrink an attribute list over time.
1979 */
1980 /* start with smaller blk num */
Dave Chinner517c2222013-04-24 18:58:55 +10001981 forward = ichdr.forw < ichdr.back;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001982 for (i = 0; i < 2; forward = !forward, i++) {
Dave Chinner517c2222013-04-24 18:58:55 +10001983 struct xfs_attr3_icleaf_hdr ichdr2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001984 if (forward)
Dave Chinner517c2222013-04-24 18:58:55 +10001985 blkno = ichdr.forw;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001986 else
Dave Chinner517c2222013-04-24 18:58:55 +10001987 blkno = ichdr.back;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001988 if (blkno == 0)
1989 continue;
Dave Chinner517c2222013-04-24 18:58:55 +10001990 error = xfs_attr3_leaf_read(state->args->trans, state->args->dp,
Christoph Hellwigdfb87592019-11-20 09:46:02 -08001991 blkno, &bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001992 if (error)
Eric Sandeend99831f2014-06-22 15:03:54 +10001993 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001994
Brian Foster2f661242015-04-13 11:26:02 +10001995 xfs_attr3_leaf_hdr_from_disk(state->args->geo, &ichdr2, bp->b_addr);
Dave Chinner517c2222013-04-24 18:58:55 +10001996
Dave Chinnerb2a21e72014-06-06 15:22:04 +10001997 bytes = state->args->geo->blksize -
1998 (state->args->geo->blksize >> 2) -
Dave Chinner517c2222013-04-24 18:58:55 +10001999 ichdr.usedbytes - ichdr2.usedbytes -
2000 ((ichdr.count + ichdr2.count) *
2001 sizeof(xfs_attr_leaf_entry_t)) -
2002 xfs_attr3_leaf_hdr_size(leaf);
2003
Dave Chinner1d9025e2012-06-22 18:50:14 +10002004 xfs_trans_brelse(state->args->trans, bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002005 if (bytes >= 0)
2006 break; /* fits with at least 25% to spare */
2007 }
2008 if (i >= 2) {
2009 *action = 0;
Eric Sandeend99831f2014-06-22 15:03:54 +10002010 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002011 }
2012
2013 /*
2014 * Make altpath point to the block we want to keep (the lower
2015 * numbered block) and path point to the block we want to drop.
2016 */
2017 memcpy(&state->altpath, &state->path, sizeof(state->path));
2018 if (blkno < blk->blkno) {
Dave Chinnerf5ea1102013-04-24 18:58:02 +10002019 error = xfs_da3_path_shift(state, &state->altpath, forward,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002020 0, &retval);
2021 } else {
Dave Chinnerf5ea1102013-04-24 18:58:02 +10002022 error = xfs_da3_path_shift(state, &state->path, forward,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002023 0, &retval);
2024 }
2025 if (error)
Eric Sandeend99831f2014-06-22 15:03:54 +10002026 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002027 if (retval) {
2028 *action = 0;
2029 } else {
2030 *action = 1;
2031 }
Eric Sandeend99831f2014-06-22 15:03:54 +10002032 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002033}
2034
2035/*
2036 * Remove a name from the leaf attribute list structure.
2037 *
2038 * Return 1 if leaf is less than 37% full, 0 if >= 37% full.
2039 * If two leaves are 37% full, when combined they will leave 25% free.
2040 */
2041int
Dave Chinner517c2222013-04-24 18:58:55 +10002042xfs_attr3_leaf_remove(
2043 struct xfs_buf *bp,
2044 struct xfs_da_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002045{
Dave Chinner517c2222013-04-24 18:58:55 +10002046 struct xfs_attr_leafblock *leaf;
2047 struct xfs_attr3_icleaf_hdr ichdr;
2048 struct xfs_attr_leaf_entry *entry;
Dave Chinner517c2222013-04-24 18:58:55 +10002049 int before;
2050 int after;
2051 int smallest;
2052 int entsize;
2053 int tablesize;
2054 int tmp;
2055 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002056
Dave Chinneree732592012-11-12 22:53:53 +11002057 trace_xfs_attr_leaf_remove(args);
2058
Dave Chinner1d9025e2012-06-22 18:50:14 +10002059 leaf = bp->b_addr;
Brian Foster2f661242015-04-13 11:26:02 +10002060 xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
Dave Chinner517c2222013-04-24 18:58:55 +10002061
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002062 ASSERT(ichdr.count > 0 && ichdr.count < args->geo->blksize / 8);
Dave Chinner517c2222013-04-24 18:58:55 +10002063 ASSERT(args->index >= 0 && args->index < ichdr.count);
2064 ASSERT(ichdr.firstused >= ichdr.count * sizeof(*entry) +
2065 xfs_attr3_leaf_hdr_size(leaf));
2066
2067 entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
2068
2069 ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused);
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002070 ASSERT(be16_to_cpu(entry->nameidx) < args->geo->blksize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002071
2072 /*
2073 * Scan through free region table:
2074 * check for adjacency of free'd entry with an existing one,
2075 * find smallest free region in case we need to replace it,
2076 * adjust any map that borders the entry table,
2077 */
Dave Chinner517c2222013-04-24 18:58:55 +10002078 tablesize = ichdr.count * sizeof(xfs_attr_leaf_entry_t)
2079 + xfs_attr3_leaf_hdr_size(leaf);
2080 tmp = ichdr.freemap[0].size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002081 before = after = -1;
2082 smallest = XFS_ATTR_LEAF_MAPSIZE - 1;
2083 entsize = xfs_attr_leaf_entsize(leaf, args->index);
Dave Chinner517c2222013-04-24 18:58:55 +10002084 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002085 ASSERT(ichdr.freemap[i].base < args->geo->blksize);
2086 ASSERT(ichdr.freemap[i].size < args->geo->blksize);
Dave Chinner517c2222013-04-24 18:58:55 +10002087 if (ichdr.freemap[i].base == tablesize) {
2088 ichdr.freemap[i].base -= sizeof(xfs_attr_leaf_entry_t);
2089 ichdr.freemap[i].size += sizeof(xfs_attr_leaf_entry_t);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002090 }
2091
Dave Chinner517c2222013-04-24 18:58:55 +10002092 if (ichdr.freemap[i].base + ichdr.freemap[i].size ==
2093 be16_to_cpu(entry->nameidx)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002094 before = i;
Dave Chinner517c2222013-04-24 18:58:55 +10002095 } else if (ichdr.freemap[i].base ==
2096 (be16_to_cpu(entry->nameidx) + entsize)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002097 after = i;
Dave Chinner517c2222013-04-24 18:58:55 +10002098 } else if (ichdr.freemap[i].size < tmp) {
2099 tmp = ichdr.freemap[i].size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002100 smallest = i;
2101 }
2102 }
2103
2104 /*
2105 * Coalesce adjacent freemap regions,
2106 * or replace the smallest region.
2107 */
2108 if ((before >= 0) || (after >= 0)) {
2109 if ((before >= 0) && (after >= 0)) {
Dave Chinner517c2222013-04-24 18:58:55 +10002110 ichdr.freemap[before].size += entsize;
2111 ichdr.freemap[before].size += ichdr.freemap[after].size;
2112 ichdr.freemap[after].base = 0;
2113 ichdr.freemap[after].size = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002114 } else if (before >= 0) {
Dave Chinner517c2222013-04-24 18:58:55 +10002115 ichdr.freemap[before].size += entsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002116 } else {
Dave Chinner517c2222013-04-24 18:58:55 +10002117 ichdr.freemap[after].base = be16_to_cpu(entry->nameidx);
2118 ichdr.freemap[after].size += entsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002119 }
2120 } else {
2121 /*
2122 * Replace smallest region (if it is smaller than free'd entry)
2123 */
Dave Chinner517c2222013-04-24 18:58:55 +10002124 if (ichdr.freemap[smallest].size < entsize) {
2125 ichdr.freemap[smallest].base = be16_to_cpu(entry->nameidx);
2126 ichdr.freemap[smallest].size = entsize;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002127 }
2128 }
2129
2130 /*
2131 * Did we remove the first entry?
2132 */
Dave Chinner517c2222013-04-24 18:58:55 +10002133 if (be16_to_cpu(entry->nameidx) == ichdr.firstused)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002134 smallest = 1;
2135 else
2136 smallest = 0;
2137
2138 /*
2139 * Compress the remaining entries and zero out the removed stuff.
2140 */
Dave Chinner517c2222013-04-24 18:58:55 +10002141 memset(xfs_attr3_leaf_name(leaf, args->index), 0, entsize);
2142 ichdr.usedbytes -= entsize;
Dave Chinner1d9025e2012-06-22 18:50:14 +10002143 xfs_trans_log_buf(args->trans, bp,
Dave Chinner517c2222013-04-24 18:58:55 +10002144 XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002145 entsize));
2146
Dave Chinner517c2222013-04-24 18:58:55 +10002147 tmp = (ichdr.count - args->index) * sizeof(xfs_attr_leaf_entry_t);
2148 memmove(entry, entry + 1, tmp);
2149 ichdr.count--;
Dave Chinner1d9025e2012-06-22 18:50:14 +10002150 xfs_trans_log_buf(args->trans, bp,
Dave Chinner517c2222013-04-24 18:58:55 +10002151 XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(xfs_attr_leaf_entry_t)));
2152
2153 entry = &xfs_attr3_leaf_entryp(leaf)[ichdr.count];
2154 memset(entry, 0, sizeof(xfs_attr_leaf_entry_t));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002155
2156 /*
2157 * If we removed the first entry, re-find the first used byte
2158 * in the name area. Note that if the entry was the "firstused",
2159 * then we don't have a "hole" in our block resulting from
2160 * removing the name.
2161 */
2162 if (smallest) {
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002163 tmp = args->geo->blksize;
Dave Chinner517c2222013-04-24 18:58:55 +10002164 entry = xfs_attr3_leaf_entryp(leaf);
2165 for (i = ichdr.count - 1; i >= 0; entry++, i--) {
2166 ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused);
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002167 ASSERT(be16_to_cpu(entry->nameidx) < args->geo->blksize);
Nathan Scott6b19f2d2006-03-17 17:29:02 +11002168
2169 if (be16_to_cpu(entry->nameidx) < tmp)
2170 tmp = be16_to_cpu(entry->nameidx);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002171 }
Dave Chinner517c2222013-04-24 18:58:55 +10002172 ichdr.firstused = tmp;
Brian Foster66db8102015-04-13 11:27:59 +10002173 ASSERT(ichdr.firstused != 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002174 } else {
Dave Chinner517c2222013-04-24 18:58:55 +10002175 ichdr.holes = 1; /* mark as needing compaction */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002176 }
Brian Foster2f661242015-04-13 11:26:02 +10002177 xfs_attr3_leaf_hdr_to_disk(args->geo, leaf, &ichdr);
Dave Chinner1d9025e2012-06-22 18:50:14 +10002178 xfs_trans_log_buf(args->trans, bp,
Dave Chinner517c2222013-04-24 18:58:55 +10002179 XFS_DA_LOGRANGE(leaf, &leaf->hdr,
2180 xfs_attr3_leaf_hdr_size(leaf)));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002181
2182 /*
2183 * Check if leaf is less than 50% full, caller may want to
2184 * "join" the leaf with a sibling if so.
2185 */
Dave Chinner517c2222013-04-24 18:58:55 +10002186 tmp = ichdr.usedbytes + xfs_attr3_leaf_hdr_size(leaf) +
2187 ichdr.count * sizeof(xfs_attr_leaf_entry_t);
2188
Dave Chinnered358c02014-06-06 15:18:10 +10002189 return tmp < args->geo->magicpct; /* leaf is < 37% full */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002190}
2191
2192/*
2193 * Move all the attribute list entries from drop_leaf into save_leaf.
2194 */
2195void
Dave Chinner517c2222013-04-24 18:58:55 +10002196xfs_attr3_leaf_unbalance(
2197 struct xfs_da_state *state,
2198 struct xfs_da_state_blk *drop_blk,
2199 struct xfs_da_state_blk *save_blk)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002200{
Dave Chinner517c2222013-04-24 18:58:55 +10002201 struct xfs_attr_leafblock *drop_leaf = drop_blk->bp->b_addr;
2202 struct xfs_attr_leafblock *save_leaf = save_blk->bp->b_addr;
2203 struct xfs_attr3_icleaf_hdr drophdr;
2204 struct xfs_attr3_icleaf_hdr savehdr;
2205 struct xfs_attr_leaf_entry *entry;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
Dave Chinner5a5881c2012-03-22 05:15:13 +00002207 trace_xfs_attr_leaf_unbalance(state->args);
2208
Dave Chinner1d9025e2012-06-22 18:50:14 +10002209 drop_leaf = drop_blk->bp->b_addr;
2210 save_leaf = save_blk->bp->b_addr;
Brian Foster2f661242015-04-13 11:26:02 +10002211 xfs_attr3_leaf_hdr_from_disk(state->args->geo, &drophdr, drop_leaf);
2212 xfs_attr3_leaf_hdr_from_disk(state->args->geo, &savehdr, save_leaf);
Dave Chinner517c2222013-04-24 18:58:55 +10002213 entry = xfs_attr3_leaf_entryp(drop_leaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002214
2215 /*
2216 * Save last hashval from dying block for later Btree fixup.
2217 */
Dave Chinner517c2222013-04-24 18:58:55 +10002218 drop_blk->hashval = be32_to_cpu(entry[drophdr.count - 1].hashval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002219
2220 /*
2221 * Check if we need a temp buffer, or can we do it in place.
2222 * Note that we don't check "leaf" for holes because we will
2223 * always be dropping it, toosmall() decided that for us already.
2224 */
Dave Chinner517c2222013-04-24 18:58:55 +10002225 if (savehdr.holes == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226 /*
2227 * dest leaf has no holes, so we add there. May need
2228 * to make some room in the entry array.
2229 */
Dave Chinner517c2222013-04-24 18:58:55 +10002230 if (xfs_attr3_leaf_order(save_blk->bp, &savehdr,
2231 drop_blk->bp, &drophdr)) {
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002232 xfs_attr3_leaf_moveents(state->args,
2233 drop_leaf, &drophdr, 0,
Dave Chinner517c2222013-04-24 18:58:55 +10002234 save_leaf, &savehdr, 0,
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002235 drophdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002236 } else {
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002237 xfs_attr3_leaf_moveents(state->args,
2238 drop_leaf, &drophdr, 0,
Dave Chinner517c2222013-04-24 18:58:55 +10002239 save_leaf, &savehdr,
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002240 savehdr.count, drophdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002241 }
2242 } else {
2243 /*
2244 * Destination has holes, so we make a temporary copy
2245 * of the leaf and add them both to that.
2246 */
Dave Chinner517c2222013-04-24 18:58:55 +10002247 struct xfs_attr_leafblock *tmp_leaf;
2248 struct xfs_attr3_icleaf_hdr tmphdr;
2249
Tetsuo Handa707e0dd2019-08-26 12:06:22 -07002250 tmp_leaf = kmem_zalloc(state->args->geo->blksize, 0);
Dave Chinner517c2222013-04-24 18:58:55 +10002251
Dave Chinner8517de22013-05-21 18:02:05 +10002252 /*
2253 * Copy the header into the temp leaf so that all the stuff
2254 * not in the incore header is present and gets copied back in
2255 * once we've moved all the entries.
2256 */
2257 memcpy(tmp_leaf, save_leaf, xfs_attr3_leaf_hdr_size(save_leaf));
2258
2259 memset(&tmphdr, 0, sizeof(tmphdr));
Dave Chinner517c2222013-04-24 18:58:55 +10002260 tmphdr.magic = savehdr.magic;
2261 tmphdr.forw = savehdr.forw;
2262 tmphdr.back = savehdr.back;
Dave Chinnerb2a21e72014-06-06 15:22:04 +10002263 tmphdr.firstused = state->args->geo->blksize;
Dave Chinner8517de22013-05-21 18:02:05 +10002264
2265 /* write the header to the temp buffer to initialise it */
Brian Foster2f661242015-04-13 11:26:02 +10002266 xfs_attr3_leaf_hdr_to_disk(state->args->geo, tmp_leaf, &tmphdr);
Dave Chinner8517de22013-05-21 18:02:05 +10002267
Dave Chinner517c2222013-04-24 18:58:55 +10002268 if (xfs_attr3_leaf_order(save_blk->bp, &savehdr,
2269 drop_blk->bp, &drophdr)) {
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002270 xfs_attr3_leaf_moveents(state->args,
2271 drop_leaf, &drophdr, 0,
Dave Chinner517c2222013-04-24 18:58:55 +10002272 tmp_leaf, &tmphdr, 0,
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002273 drophdr.count);
2274 xfs_attr3_leaf_moveents(state->args,
2275 save_leaf, &savehdr, 0,
Dave Chinner517c2222013-04-24 18:58:55 +10002276 tmp_leaf, &tmphdr, tmphdr.count,
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002277 savehdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002278 } else {
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002279 xfs_attr3_leaf_moveents(state->args,
2280 save_leaf, &savehdr, 0,
Dave Chinner517c2222013-04-24 18:58:55 +10002281 tmp_leaf, &tmphdr, 0,
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002282 savehdr.count);
2283 xfs_attr3_leaf_moveents(state->args,
2284 drop_leaf, &drophdr, 0,
Dave Chinner517c2222013-04-24 18:58:55 +10002285 tmp_leaf, &tmphdr, tmphdr.count,
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002286 drophdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002287 }
Dave Chinnerb2a21e72014-06-06 15:22:04 +10002288 memcpy(save_leaf, tmp_leaf, state->args->geo->blksize);
Dave Chinner517c2222013-04-24 18:58:55 +10002289 savehdr = tmphdr; /* struct copy */
2290 kmem_free(tmp_leaf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002291 }
2292
Brian Foster2f661242015-04-13 11:26:02 +10002293 xfs_attr3_leaf_hdr_to_disk(state->args->geo, save_leaf, &savehdr);
Dave Chinner1d9025e2012-06-22 18:50:14 +10002294 xfs_trans_log_buf(state->args->trans, save_blk->bp, 0,
Dave Chinnerb2a21e72014-06-06 15:22:04 +10002295 state->args->geo->blksize - 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002296
2297 /*
2298 * Copy out last hashval in each block for B-tree code.
2299 */
Dave Chinner517c2222013-04-24 18:58:55 +10002300 entry = xfs_attr3_leaf_entryp(save_leaf);
2301 save_blk->hashval = be32_to_cpu(entry[savehdr.count - 1].hashval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002302}
2303
2304/*========================================================================
2305 * Routines used for finding things in the Btree.
2306 *========================================================================*/
2307
2308/*
2309 * Look up a name in a leaf attribute list structure.
2310 * This is the internal routine, it uses the caller's buffer.
2311 *
2312 * Note that duplicate keys are allowed, but only check within the
2313 * current leaf node. The Btree code must check in adjacent leaf nodes.
2314 *
2315 * Return in args->index the index into the entry[] array of either
2316 * the found entry, or where the entry should have been (insert before
2317 * that entry).
2318 *
2319 * Don't change the args->value unless we find the attribute.
2320 */
2321int
Dave Chinner517c2222013-04-24 18:58:55 +10002322xfs_attr3_leaf_lookup_int(
2323 struct xfs_buf *bp,
2324 struct xfs_da_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002325{
Dave Chinner517c2222013-04-24 18:58:55 +10002326 struct xfs_attr_leafblock *leaf;
2327 struct xfs_attr3_icleaf_hdr ichdr;
2328 struct xfs_attr_leaf_entry *entry;
2329 struct xfs_attr_leaf_entry *entries;
2330 struct xfs_attr_leaf_name_local *name_loc;
2331 struct xfs_attr_leaf_name_remote *name_rmt;
2332 xfs_dahash_t hashval;
2333 int probe;
2334 int span;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002335
Dave Chinner5a5881c2012-03-22 05:15:13 +00002336 trace_xfs_attr_leaf_lookup(args);
2337
Dave Chinner1d9025e2012-06-22 18:50:14 +10002338 leaf = bp->b_addr;
Brian Foster2f661242015-04-13 11:26:02 +10002339 xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
Dave Chinner517c2222013-04-24 18:58:55 +10002340 entries = xfs_attr3_leaf_entryp(leaf);
Darrick J. Wonga5155b82019-11-02 09:40:53 -07002341 if (ichdr.count >= args->geo->blksize / 8) {
Darrick J. Wong8d57c212020-03-11 10:37:54 -07002342 xfs_buf_mark_corrupt(bp);
Darrick J. Wong8ba92d42018-01-08 10:51:07 -08002343 return -EFSCORRUPTED;
Darrick J. Wonga5155b82019-11-02 09:40:53 -07002344 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345
2346 /*
2347 * Binary search. (note: small blocks will skip this loop)
2348 */
2349 hashval = args->hashval;
Dave Chinner517c2222013-04-24 18:58:55 +10002350 probe = span = ichdr.count / 2;
2351 for (entry = &entries[probe]; span > 4; entry = &entries[probe]) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002352 span /= 2;
Nathan Scott6b19f2d2006-03-17 17:29:02 +11002353 if (be32_to_cpu(entry->hashval) < hashval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002354 probe += span;
Nathan Scott6b19f2d2006-03-17 17:29:02 +11002355 else if (be32_to_cpu(entry->hashval) > hashval)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002356 probe -= span;
2357 else
2358 break;
2359 }
Darrick J. Wonga5155b82019-11-02 09:40:53 -07002360 if (!(probe >= 0 && (!ichdr.count || probe < ichdr.count))) {
Darrick J. Wong8d57c212020-03-11 10:37:54 -07002361 xfs_buf_mark_corrupt(bp);
Darrick J. Wong8ba92d42018-01-08 10:51:07 -08002362 return -EFSCORRUPTED;
Darrick J. Wonga5155b82019-11-02 09:40:53 -07002363 }
2364 if (!(span <= 4 || be32_to_cpu(entry->hashval) == hashval)) {
Darrick J. Wong8d57c212020-03-11 10:37:54 -07002365 xfs_buf_mark_corrupt(bp);
Darrick J. Wong8ba92d42018-01-08 10:51:07 -08002366 return -EFSCORRUPTED;
Darrick J. Wonga5155b82019-11-02 09:40:53 -07002367 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
2369 /*
2370 * Since we may have duplicate hashval's, find the first matching
2371 * hashval in the leaf.
2372 */
Dave Chinner517c2222013-04-24 18:58:55 +10002373 while (probe > 0 && be32_to_cpu(entry->hashval) >= hashval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002374 entry--;
2375 probe--;
2376 }
Dave Chinner517c2222013-04-24 18:58:55 +10002377 while (probe < ichdr.count &&
2378 be32_to_cpu(entry->hashval) < hashval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002379 entry++;
2380 probe++;
2381 }
Dave Chinner517c2222013-04-24 18:58:55 +10002382 if (probe == ichdr.count || be32_to_cpu(entry->hashval) != hashval) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 args->index = probe;
Dave Chinner24513372014-06-25 14:58:08 +10002384 return -ENOATTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002385 }
2386
2387 /*
2388 * Duplicate keys may be present, so search all of them for a match.
2389 */
Dave Chinner517c2222013-04-24 18:58:55 +10002390 for (; probe < ichdr.count && (be32_to_cpu(entry->hashval) == hashval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002391 entry++, probe++) {
2392/*
2393 * GROT: Add code to remove incomplete entries.
2394 */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002395 if (entry->flags & XFS_ATTR_LOCAL) {
Dave Chinner517c2222013-04-24 18:58:55 +10002396 name_loc = xfs_attr3_leaf_name_local(leaf, probe);
Christoph Hellwig377f16a2020-02-26 17:30:36 -08002397 if (!xfs_attr_match(args, name_loc->namelen,
2398 name_loc->nameval, entry->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002399 continue;
2400 args->index = probe;
Dave Chinner24513372014-06-25 14:58:08 +10002401 return -EEXIST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002402 } else {
Dave Chinner517c2222013-04-24 18:58:55 +10002403 name_rmt = xfs_attr3_leaf_name_remote(leaf, probe);
Christoph Hellwig377f16a2020-02-26 17:30:36 -08002404 if (!xfs_attr_match(args, name_rmt->namelen,
2405 name_rmt->name, entry->flags))
Linus Torvalds1da177e2005-04-16 15:20:36 -07002406 continue;
2407 args->index = probe;
Dave Chinner8275cdd2014-05-06 07:37:31 +10002408 args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen);
Nathan Scottc0f054e2006-03-17 17:29:18 +11002409 args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
Dave Chinnerad1858d2013-05-21 18:02:08 +10002410 args->rmtblkcnt = xfs_attr3_rmt_blocks(
2411 args->dp->i_mount,
Dave Chinner8275cdd2014-05-06 07:37:31 +10002412 args->rmtvaluelen);
Dave Chinner24513372014-06-25 14:58:08 +10002413 return -EEXIST;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002414 }
2415 }
2416 args->index = probe;
Dave Chinner24513372014-06-25 14:58:08 +10002417 return -ENOATTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002418}
2419
2420/*
2421 * Get the value associated with an attribute name from a leaf attribute
2422 * list structure.
Dave Chinner728bcaa2019-08-29 09:04:08 -07002423 *
Christoph Hellwige513e252020-02-26 17:30:35 -08002424 * If args->valuelen is zero, only the length needs to be returned. Unlike a
2425 * lookup, we only return an error if the attribute does not exist or we can't
2426 * retrieve the value.
Linus Torvalds1da177e2005-04-16 15:20:36 -07002427 */
2428int
Dave Chinner517c2222013-04-24 18:58:55 +10002429xfs_attr3_leaf_getvalue(
2430 struct xfs_buf *bp,
2431 struct xfs_da_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002432{
Dave Chinner517c2222013-04-24 18:58:55 +10002433 struct xfs_attr_leafblock *leaf;
2434 struct xfs_attr3_icleaf_hdr ichdr;
2435 struct xfs_attr_leaf_entry *entry;
2436 struct xfs_attr_leaf_name_local *name_loc;
2437 struct xfs_attr_leaf_name_remote *name_rmt;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002438
Dave Chinner1d9025e2012-06-22 18:50:14 +10002439 leaf = bp->b_addr;
Brian Foster2f661242015-04-13 11:26:02 +10002440 xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002441 ASSERT(ichdr.count < args->geo->blksize / 8);
Dave Chinner517c2222013-04-24 18:58:55 +10002442 ASSERT(args->index < ichdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002443
Dave Chinner517c2222013-04-24 18:58:55 +10002444 entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002445 if (entry->flags & XFS_ATTR_LOCAL) {
Dave Chinner517c2222013-04-24 18:58:55 +10002446 name_loc = xfs_attr3_leaf_name_local(leaf, args->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002447 ASSERT(name_loc->namelen == args->namelen);
2448 ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0);
Dave Chinner9df243a2019-08-29 09:04:10 -07002449 return xfs_attr_copy_value(args,
2450 &name_loc->nameval[args->namelen],
2451 be16_to_cpu(name_loc->valuelen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002452 }
Dave Chinnera0e959d2019-08-29 09:04:09 -07002453
2454 name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
2455 ASSERT(name_rmt->namelen == args->namelen);
2456 ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0);
2457 args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen);
2458 args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
2459 args->rmtblkcnt = xfs_attr3_rmt_blocks(args->dp->i_mount,
2460 args->rmtvaluelen);
Dave Chinner9df243a2019-08-29 09:04:10 -07002461 return xfs_attr_copy_value(args, NULL, args->rmtvaluelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002462}
2463
2464/*========================================================================
2465 * Utility routines.
2466 *========================================================================*/
2467
2468/*
2469 * Move the indicated entries from one leaf to another.
2470 * NOTE: this routine modifies both source and destination leaves.
2471 */
2472/*ARGSUSED*/
2473STATIC void
Dave Chinner517c2222013-04-24 18:58:55 +10002474xfs_attr3_leaf_moveents(
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002475 struct xfs_da_args *args,
Dave Chinner517c2222013-04-24 18:58:55 +10002476 struct xfs_attr_leafblock *leaf_s,
2477 struct xfs_attr3_icleaf_hdr *ichdr_s,
2478 int start_s,
2479 struct xfs_attr_leafblock *leaf_d,
2480 struct xfs_attr3_icleaf_hdr *ichdr_d,
2481 int start_d,
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002482 int count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002483{
Dave Chinner517c2222013-04-24 18:58:55 +10002484 struct xfs_attr_leaf_entry *entry_s;
2485 struct xfs_attr_leaf_entry *entry_d;
2486 int desti;
2487 int tmp;
2488 int i;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489
2490 /*
2491 * Check for nothing to do.
2492 */
2493 if (count == 0)
2494 return;
2495
2496 /*
2497 * Set up environment.
2498 */
Dave Chinner517c2222013-04-24 18:58:55 +10002499 ASSERT(ichdr_s->magic == XFS_ATTR_LEAF_MAGIC ||
2500 ichdr_s->magic == XFS_ATTR3_LEAF_MAGIC);
2501 ASSERT(ichdr_s->magic == ichdr_d->magic);
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002502 ASSERT(ichdr_s->count > 0 && ichdr_s->count < args->geo->blksize / 8);
Dave Chinner517c2222013-04-24 18:58:55 +10002503 ASSERT(ichdr_s->firstused >= (ichdr_s->count * sizeof(*entry_s))
2504 + xfs_attr3_leaf_hdr_size(leaf_s));
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002505 ASSERT(ichdr_d->count < args->geo->blksize / 8);
Dave Chinner517c2222013-04-24 18:58:55 +10002506 ASSERT(ichdr_d->firstused >= (ichdr_d->count * sizeof(*entry_d))
2507 + xfs_attr3_leaf_hdr_size(leaf_d));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002508
Dave Chinner517c2222013-04-24 18:58:55 +10002509 ASSERT(start_s < ichdr_s->count);
2510 ASSERT(start_d <= ichdr_d->count);
2511 ASSERT(count <= ichdr_s->count);
2512
Linus Torvalds1da177e2005-04-16 15:20:36 -07002513
2514 /*
2515 * Move the entries in the destination leaf up to make a hole?
2516 */
Dave Chinner517c2222013-04-24 18:58:55 +10002517 if (start_d < ichdr_d->count) {
2518 tmp = ichdr_d->count - start_d;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002519 tmp *= sizeof(xfs_attr_leaf_entry_t);
Dave Chinner517c2222013-04-24 18:58:55 +10002520 entry_s = &xfs_attr3_leaf_entryp(leaf_d)[start_d];
2521 entry_d = &xfs_attr3_leaf_entryp(leaf_d)[start_d + count];
2522 memmove(entry_d, entry_s, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002523 }
2524
2525 /*
2526 * Copy all entry's in the same (sorted) order,
2527 * but allocate attribute info packed and in sequence.
2528 */
Dave Chinner517c2222013-04-24 18:58:55 +10002529 entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s];
2530 entry_d = &xfs_attr3_leaf_entryp(leaf_d)[start_d];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002531 desti = start_d;
2532 for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) {
Dave Chinner517c2222013-04-24 18:58:55 +10002533 ASSERT(be16_to_cpu(entry_s->nameidx) >= ichdr_s->firstused);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002534 tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i);
2535#ifdef GROT
2536 /*
2537 * Code to drop INCOMPLETE entries. Difficult to use as we
2538 * may also need to change the insertion index. Code turned
2539 * off for 6.2, should be revisited later.
2540 */
2541 if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */
Dave Chinner517c2222013-04-24 18:58:55 +10002542 memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp);
2543 ichdr_s->usedbytes -= tmp;
2544 ichdr_s->count -= 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002545 entry_d--; /* to compensate for ++ in loop hdr */
2546 desti--;
2547 if ((start_s + i) < offset)
2548 result++; /* insertion index adjustment */
2549 } else {
2550#endif /* GROT */
Dave Chinner517c2222013-04-24 18:58:55 +10002551 ichdr_d->firstused -= tmp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002552 /* both on-disk, don't endian flip twice */
2553 entry_d->hashval = entry_s->hashval;
Dave Chinner517c2222013-04-24 18:58:55 +10002554 entry_d->nameidx = cpu_to_be16(ichdr_d->firstused);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002555 entry_d->flags = entry_s->flags;
Nathan Scott6b19f2d2006-03-17 17:29:02 +11002556 ASSERT(be16_to_cpu(entry_d->nameidx) + tmp
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002557 <= args->geo->blksize);
Dave Chinner517c2222013-04-24 18:58:55 +10002558 memmove(xfs_attr3_leaf_name(leaf_d, desti),
2559 xfs_attr3_leaf_name(leaf_s, start_s + i), tmp);
Nathan Scott6b19f2d2006-03-17 17:29:02 +11002560 ASSERT(be16_to_cpu(entry_s->nameidx) + tmp
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002561 <= args->geo->blksize);
Dave Chinner517c2222013-04-24 18:58:55 +10002562 memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp);
2563 ichdr_s->usedbytes -= tmp;
2564 ichdr_d->usedbytes += tmp;
2565 ichdr_s->count -= 1;
2566 ichdr_d->count += 1;
2567 tmp = ichdr_d->count * sizeof(xfs_attr_leaf_entry_t)
2568 + xfs_attr3_leaf_hdr_size(leaf_d);
2569 ASSERT(ichdr_d->firstused >= tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002570#ifdef GROT
2571 }
2572#endif /* GROT */
2573 }
2574
2575 /*
2576 * Zero out the entries we just copied.
2577 */
Dave Chinner517c2222013-04-24 18:58:55 +10002578 if (start_s == ichdr_s->count) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002579 tmp = count * sizeof(xfs_attr_leaf_entry_t);
Dave Chinner517c2222013-04-24 18:58:55 +10002580 entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002581 ASSERT(((char *)entry_s + tmp) <=
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002582 ((char *)leaf_s + args->geo->blksize));
Dave Chinner517c2222013-04-24 18:58:55 +10002583 memset(entry_s, 0, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002584 } else {
2585 /*
2586 * Move the remaining entries down to fill the hole,
2587 * then zero the entries at the top.
2588 */
Dave Chinner517c2222013-04-24 18:58:55 +10002589 tmp = (ichdr_s->count - count) * sizeof(xfs_attr_leaf_entry_t);
2590 entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s + count];
2591 entry_d = &xfs_attr3_leaf_entryp(leaf_s)[start_s];
2592 memmove(entry_d, entry_s, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002593
2594 tmp = count * sizeof(xfs_attr_leaf_entry_t);
Dave Chinner517c2222013-04-24 18:58:55 +10002595 entry_s = &xfs_attr3_leaf_entryp(leaf_s)[ichdr_s->count];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002596 ASSERT(((char *)entry_s + tmp) <=
Dave Chinnerc2c4c472014-06-06 15:21:45 +10002597 ((char *)leaf_s + args->geo->blksize));
Dave Chinner517c2222013-04-24 18:58:55 +10002598 memset(entry_s, 0, tmp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002599 }
2600
2601 /*
2602 * Fill in the freemap information
2603 */
Dave Chinner517c2222013-04-24 18:58:55 +10002604 ichdr_d->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_d);
2605 ichdr_d->freemap[0].base += ichdr_d->count * sizeof(xfs_attr_leaf_entry_t);
2606 ichdr_d->freemap[0].size = ichdr_d->firstused - ichdr_d->freemap[0].base;
2607 ichdr_d->freemap[1].base = 0;
2608 ichdr_d->freemap[2].base = 0;
2609 ichdr_d->freemap[1].size = 0;
2610 ichdr_d->freemap[2].size = 0;
2611 ichdr_s->holes = 1; /* leaf may not be compact */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002612}
2613
2614/*
2615 * Pick up the last hashvalue from a leaf block.
2616 */
2617xfs_dahash_t
Dave Chinner1d9025e2012-06-22 18:50:14 +10002618xfs_attr_leaf_lasthash(
2619 struct xfs_buf *bp,
2620 int *count)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002621{
Dave Chinner517c2222013-04-24 18:58:55 +10002622 struct xfs_attr3_icleaf_hdr ichdr;
2623 struct xfs_attr_leaf_entry *entries;
Christoph Hellwigdbd329f12019-06-28 19:27:29 -07002624 struct xfs_mount *mp = bp->b_mount;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002625
Brian Foster2f661242015-04-13 11:26:02 +10002626 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, bp->b_addr);
Dave Chinner517c2222013-04-24 18:58:55 +10002627 entries = xfs_attr3_leaf_entryp(bp->b_addr);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002628 if (count)
Dave Chinner517c2222013-04-24 18:58:55 +10002629 *count = ichdr.count;
2630 if (!ichdr.count)
2631 return 0;
2632 return be32_to_cpu(entries[ichdr.count - 1].hashval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002633}
2634
2635/*
2636 * Calculate the number of bytes used to store the indicated attribute
2637 * (whether local or remote only calculate bytes in this block).
2638 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +10002639STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002640xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index)
2641{
Dave Chinner517c2222013-04-24 18:58:55 +10002642 struct xfs_attr_leaf_entry *entries;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002643 xfs_attr_leaf_name_local_t *name_loc;
2644 xfs_attr_leaf_name_remote_t *name_rmt;
2645 int size;
2646
Dave Chinner517c2222013-04-24 18:58:55 +10002647 entries = xfs_attr3_leaf_entryp(leaf);
2648 if (entries[index].flags & XFS_ATTR_LOCAL) {
2649 name_loc = xfs_attr3_leaf_name_local(leaf, index);
Eric Sandeenc9fb86a2009-01-01 16:40:11 -06002650 size = xfs_attr_leaf_entsize_local(name_loc->namelen,
Nathan Scott053b5752006-03-17 17:29:09 +11002651 be16_to_cpu(name_loc->valuelen));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002652 } else {
Dave Chinner517c2222013-04-24 18:58:55 +10002653 name_rmt = xfs_attr3_leaf_name_remote(leaf, index);
Eric Sandeenc9fb86a2009-01-01 16:40:11 -06002654 size = xfs_attr_leaf_entsize_remote(name_rmt->namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002655 }
Dave Chinner517c2222013-04-24 18:58:55 +10002656 return size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002657}
2658
2659/*
2660 * Calculate the number of bytes that would be required to store the new
2661 * attribute (whether local or remote only calculate bytes in this block).
2662 * This routine decides as a side effect whether the attribute will be
2663 * a "local" or a "remote" attribute.
2664 */
2665int
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10002666xfs_attr_leaf_newentsize(
2667 struct xfs_da_args *args,
2668 int *local)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002669{
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10002670 int size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002671
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10002672 size = xfs_attr_leaf_entsize_local(args->namelen, args->valuelen);
2673 if (size < xfs_attr_leaf_entsize_local_max(args->geo->blksize)) {
2674 if (local)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002675 *local = 1;
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10002676 return size;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002677 }
Dave Chinnerc59f0ad2014-06-06 15:21:27 +10002678 if (local)
2679 *local = 0;
2680 return xfs_attr_leaf_entsize_remote(args->namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002681}
2682
Linus Torvalds1da177e2005-04-16 15:20:36 -07002683
2684/*========================================================================
2685 * Manage the INCOMPLETE flag in a leaf entry
2686 *========================================================================*/
2687
2688/*
2689 * Clear the INCOMPLETE flag on an entry in a leaf block.
2690 */
2691int
Dave Chinner517c2222013-04-24 18:58:55 +10002692xfs_attr3_leaf_clearflag(
2693 struct xfs_da_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002694{
Dave Chinner517c2222013-04-24 18:58:55 +10002695 struct xfs_attr_leafblock *leaf;
2696 struct xfs_attr_leaf_entry *entry;
2697 struct xfs_attr_leaf_name_remote *name_rmt;
2698 struct xfs_buf *bp;
2699 int error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002700#ifdef DEBUG
Dave Chinner517c2222013-04-24 18:58:55 +10002701 struct xfs_attr3_icleaf_hdr ichdr;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002702 xfs_attr_leaf_name_local_t *name_loc;
2703 int namelen;
2704 char *name;
2705#endif /* DEBUG */
2706
Dave Chinner5a5881c2012-03-22 05:15:13 +00002707 trace_xfs_attr_leaf_clearflag(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002708 /*
2709 * Set up the operation.
2710 */
Christoph Hellwigdfb87592019-11-20 09:46:02 -08002711 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
Dave Chinnerad14c332012-11-12 22:54:16 +11002712 if (error)
Eric Sandeend99831f2014-06-22 15:03:54 +10002713 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002714
Dave Chinner1d9025e2012-06-22 18:50:14 +10002715 leaf = bp->b_addr;
Dave Chinner517c2222013-04-24 18:58:55 +10002716 entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002717 ASSERT(entry->flags & XFS_ATTR_INCOMPLETE);
2718
2719#ifdef DEBUG
Brian Foster2f661242015-04-13 11:26:02 +10002720 xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
Dave Chinner517c2222013-04-24 18:58:55 +10002721 ASSERT(args->index < ichdr.count);
2722 ASSERT(args->index >= 0);
2723
Linus Torvalds1da177e2005-04-16 15:20:36 -07002724 if (entry->flags & XFS_ATTR_LOCAL) {
Dave Chinner517c2222013-04-24 18:58:55 +10002725 name_loc = xfs_attr3_leaf_name_local(leaf, args->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002726 namelen = name_loc->namelen;
2727 name = (char *)name_loc->nameval;
2728 } else {
Dave Chinner517c2222013-04-24 18:58:55 +10002729 name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002730 namelen = name_rmt->namelen;
2731 name = (char *)name_rmt->name;
2732 }
Nathan Scott6b19f2d2006-03-17 17:29:02 +11002733 ASSERT(be32_to_cpu(entry->hashval) == args->hashval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002734 ASSERT(namelen == args->namelen);
2735 ASSERT(memcmp(name, args->name, namelen) == 0);
2736#endif /* DEBUG */
2737
2738 entry->flags &= ~XFS_ATTR_INCOMPLETE;
Dave Chinner1d9025e2012-06-22 18:50:14 +10002739 xfs_trans_log_buf(args->trans, bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002740 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
2741
2742 if (args->rmtblkno) {
2743 ASSERT((entry->flags & XFS_ATTR_LOCAL) == 0);
Dave Chinner517c2222013-04-24 18:58:55 +10002744 name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
Nathan Scottc0f054e2006-03-17 17:29:18 +11002745 name_rmt->valueblk = cpu_to_be32(args->rmtblkno);
Dave Chinner8275cdd2014-05-06 07:37:31 +10002746 name_rmt->valuelen = cpu_to_be32(args->rmtvaluelen);
Dave Chinner1d9025e2012-06-22 18:50:14 +10002747 xfs_trans_log_buf(args->trans, bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002748 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
2749 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002750
2751 /*
2752 * Commit the flag value change and start the next trans in series.
2753 */
Christoph Hellwig411350d2017-08-28 10:21:03 -07002754 return xfs_trans_roll_inode(&args->trans, args->dp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002755}
2756
2757/*
2758 * Set the INCOMPLETE flag on an entry in a leaf block.
2759 */
2760int
Dave Chinner517c2222013-04-24 18:58:55 +10002761xfs_attr3_leaf_setflag(
2762 struct xfs_da_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002763{
Dave Chinner517c2222013-04-24 18:58:55 +10002764 struct xfs_attr_leafblock *leaf;
2765 struct xfs_attr_leaf_entry *entry;
2766 struct xfs_attr_leaf_name_remote *name_rmt;
2767 struct xfs_buf *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002768 int error;
Dave Chinner517c2222013-04-24 18:58:55 +10002769#ifdef DEBUG
2770 struct xfs_attr3_icleaf_hdr ichdr;
2771#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -07002772
Dave Chinner5a5881c2012-03-22 05:15:13 +00002773 trace_xfs_attr_leaf_setflag(args);
2774
Linus Torvalds1da177e2005-04-16 15:20:36 -07002775 /*
2776 * Set up the operation.
2777 */
Christoph Hellwigdfb87592019-11-20 09:46:02 -08002778 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp);
Dave Chinnerad14c332012-11-12 22:54:16 +11002779 if (error)
Eric Sandeend99831f2014-06-22 15:03:54 +10002780 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002781
Dave Chinner1d9025e2012-06-22 18:50:14 +10002782 leaf = bp->b_addr;
Dave Chinner517c2222013-04-24 18:58:55 +10002783#ifdef DEBUG
Brian Foster2f661242015-04-13 11:26:02 +10002784 xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr, leaf);
Dave Chinner517c2222013-04-24 18:58:55 +10002785 ASSERT(args->index < ichdr.count);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002786 ASSERT(args->index >= 0);
Dave Chinner517c2222013-04-24 18:58:55 +10002787#endif
2788 entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002789
2790 ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0);
2791 entry->flags |= XFS_ATTR_INCOMPLETE;
Dave Chinner1d9025e2012-06-22 18:50:14 +10002792 xfs_trans_log_buf(args->trans, bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002793 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
2794 if ((entry->flags & XFS_ATTR_LOCAL) == 0) {
Dave Chinner517c2222013-04-24 18:58:55 +10002795 name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002796 name_rmt->valueblk = 0;
2797 name_rmt->valuelen = 0;
Dave Chinner1d9025e2012-06-22 18:50:14 +10002798 xfs_trans_log_buf(args->trans, bp,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002799 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
2800 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002801
2802 /*
2803 * Commit the flag value change and start the next trans in series.
2804 */
Christoph Hellwig411350d2017-08-28 10:21:03 -07002805 return xfs_trans_roll_inode(&args->trans, args->dp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002806}
2807
2808/*
2809 * In a single transaction, clear the INCOMPLETE flag on the leaf entry
2810 * given by args->blkno/index and set the INCOMPLETE flag on the leaf
2811 * entry given by args->blkno2/index2.
2812 *
2813 * Note that they could be in different blocks, or in the same block.
2814 */
2815int
Dave Chinner517c2222013-04-24 18:58:55 +10002816xfs_attr3_leaf_flipflags(
2817 struct xfs_da_args *args)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002818{
Dave Chinner517c2222013-04-24 18:58:55 +10002819 struct xfs_attr_leafblock *leaf1;
2820 struct xfs_attr_leafblock *leaf2;
2821 struct xfs_attr_leaf_entry *entry1;
2822 struct xfs_attr_leaf_entry *entry2;
2823 struct xfs_attr_leaf_name_remote *name_rmt;
2824 struct xfs_buf *bp1;
2825 struct xfs_buf *bp2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002826 int error;
2827#ifdef DEBUG
Dave Chinner517c2222013-04-24 18:58:55 +10002828 struct xfs_attr3_icleaf_hdr ichdr1;
2829 struct xfs_attr3_icleaf_hdr ichdr2;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002830 xfs_attr_leaf_name_local_t *name_loc;
2831 int namelen1, namelen2;
2832 char *name1, *name2;
2833#endif /* DEBUG */
2834
Dave Chinner5a5881c2012-03-22 05:15:13 +00002835 trace_xfs_attr_leaf_flipflags(args);
2836
Linus Torvalds1da177e2005-04-16 15:20:36 -07002837 /*
2838 * Read the block containing the "old" attr
2839 */
Christoph Hellwigdfb87592019-11-20 09:46:02 -08002840 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, &bp1);
Dave Chinnerad14c332012-11-12 22:54:16 +11002841 if (error)
2842 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002843
2844 /*
2845 * Read the block containing the "new" attr, if it is different
2846 */
2847 if (args->blkno2 != args->blkno) {
Dave Chinner517c2222013-04-24 18:58:55 +10002848 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
Christoph Hellwigdfb87592019-11-20 09:46:02 -08002849 &bp2);
Dave Chinnerad14c332012-11-12 22:54:16 +11002850 if (error)
2851 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002852 } else {
2853 bp2 = bp1;
2854 }
2855
Dave Chinner1d9025e2012-06-22 18:50:14 +10002856 leaf1 = bp1->b_addr;
Dave Chinner517c2222013-04-24 18:58:55 +10002857 entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002858
Dave Chinner1d9025e2012-06-22 18:50:14 +10002859 leaf2 = bp2->b_addr;
Dave Chinner517c2222013-04-24 18:58:55 +10002860 entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2];
Linus Torvalds1da177e2005-04-16 15:20:36 -07002861
2862#ifdef DEBUG
Brian Foster2f661242015-04-13 11:26:02 +10002863 xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr1, leaf1);
Dave Chinner517c2222013-04-24 18:58:55 +10002864 ASSERT(args->index < ichdr1.count);
2865 ASSERT(args->index >= 0);
2866
Brian Foster2f661242015-04-13 11:26:02 +10002867 xfs_attr3_leaf_hdr_from_disk(args->geo, &ichdr2, leaf2);
Dave Chinner517c2222013-04-24 18:58:55 +10002868 ASSERT(args->index2 < ichdr2.count);
2869 ASSERT(args->index2 >= 0);
2870
Linus Torvalds1da177e2005-04-16 15:20:36 -07002871 if (entry1->flags & XFS_ATTR_LOCAL) {
Dave Chinner517c2222013-04-24 18:58:55 +10002872 name_loc = xfs_attr3_leaf_name_local(leaf1, args->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002873 namelen1 = name_loc->namelen;
2874 name1 = (char *)name_loc->nameval;
2875 } else {
Dave Chinner517c2222013-04-24 18:58:55 +10002876 name_rmt = xfs_attr3_leaf_name_remote(leaf1, args->index);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002877 namelen1 = name_rmt->namelen;
2878 name1 = (char *)name_rmt->name;
2879 }
2880 if (entry2->flags & XFS_ATTR_LOCAL) {
Dave Chinner517c2222013-04-24 18:58:55 +10002881 name_loc = xfs_attr3_leaf_name_local(leaf2, args->index2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002882 namelen2 = name_loc->namelen;
2883 name2 = (char *)name_loc->nameval;
2884 } else {
Dave Chinner517c2222013-04-24 18:58:55 +10002885 name_rmt = xfs_attr3_leaf_name_remote(leaf2, args->index2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002886 namelen2 = name_rmt->namelen;
2887 name2 = (char *)name_rmt->name;
2888 }
Nathan Scott6b19f2d2006-03-17 17:29:02 +11002889 ASSERT(be32_to_cpu(entry1->hashval) == be32_to_cpu(entry2->hashval));
Linus Torvalds1da177e2005-04-16 15:20:36 -07002890 ASSERT(namelen1 == namelen2);
2891 ASSERT(memcmp(name1, name2, namelen1) == 0);
2892#endif /* DEBUG */
2893
2894 ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE);
2895 ASSERT((entry2->flags & XFS_ATTR_INCOMPLETE) == 0);
2896
2897 entry1->flags &= ~XFS_ATTR_INCOMPLETE;
Dave Chinner1d9025e2012-06-22 18:50:14 +10002898 xfs_trans_log_buf(args->trans, bp1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002899 XFS_DA_LOGRANGE(leaf1, entry1, sizeof(*entry1)));
2900 if (args->rmtblkno) {
2901 ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0);
Dave Chinner517c2222013-04-24 18:58:55 +10002902 name_rmt = xfs_attr3_leaf_name_remote(leaf1, args->index);
Nathan Scottc0f054e2006-03-17 17:29:18 +11002903 name_rmt->valueblk = cpu_to_be32(args->rmtblkno);
Dave Chinner8275cdd2014-05-06 07:37:31 +10002904 name_rmt->valuelen = cpu_to_be32(args->rmtvaluelen);
Dave Chinner1d9025e2012-06-22 18:50:14 +10002905 xfs_trans_log_buf(args->trans, bp1,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002906 XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt)));
2907 }
2908
2909 entry2->flags |= XFS_ATTR_INCOMPLETE;
Dave Chinner1d9025e2012-06-22 18:50:14 +10002910 xfs_trans_log_buf(args->trans, bp2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002911 XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2)));
2912 if ((entry2->flags & XFS_ATTR_LOCAL) == 0) {
Dave Chinner517c2222013-04-24 18:58:55 +10002913 name_rmt = xfs_attr3_leaf_name_remote(leaf2, args->index2);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002914 name_rmt->valueblk = 0;
2915 name_rmt->valuelen = 0;
Dave Chinner1d9025e2012-06-22 18:50:14 +10002916 xfs_trans_log_buf(args->trans, bp2,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002917 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
2918 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002919
2920 /*
2921 * Commit the flag value change and start the next trans in series.
2922 */
Christoph Hellwig411350d2017-08-28 10:21:03 -07002923 error = xfs_trans_roll_inode(&args->trans, args->dp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002924
Dave Chinner517c2222013-04-24 18:58:55 +10002925 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002926}