]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blame - libxfs/xfs_attr_leaf.c
libxfs: add helper for verifying checksums on xfs_bufs
[thirdparty/xfsprogs-dev.git] / libxfs / xfs_attr_leaf.c
CommitLineData
2bd0ea18 1/*
da23017d 2 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
a24374f4 3 * Copyright (c) 2013 Red Hat, Inc.
da23017d 4 * All Rights Reserved.
5000d01d 5 *
da23017d
NS
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
2bd0ea18 8 * published by the Free Software Foundation.
5000d01d 9 *
da23017d
NS
10 * This program is distributed in the hope that it would be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
5000d01d 14 *
da23017d
NS
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2bd0ea18
NS
18 */
19
20#include <xfs.h>
21
22/*
23 * xfs_attr_leaf.c
24 *
25 * Routines to implement leaf blocks of attributes as Btrees of hashed names.
26 */
27
5e656dbb
BN
28/*========================================================================
29 * Function prototypes for the kernel.
30 *========================================================================*/
31
32/*
33 * Routines used for growing the Btree.
34 */
a24374f4
DC
35STATIC int xfs_attr3_leaf_create(struct xfs_da_args *args,
36 xfs_dablk_t which_block, struct xfs_buf **bpp);
37STATIC int xfs_attr3_leaf_add_work(struct xfs_buf *leaf_buffer,
38 struct xfs_attr3_icleaf_hdr *ichdr,
39 struct xfs_da_args *args, int freemap_index);
40STATIC void xfs_attr3_leaf_compact(struct xfs_da_args *args,
41 struct xfs_attr3_icleaf_hdr *ichdr,
42 struct xfs_buf *leaf_buffer);
43STATIC void xfs_attr3_leaf_rebalance(xfs_da_state_t *state,
5e656dbb
BN
44 xfs_da_state_blk_t *blk1,
45 xfs_da_state_blk_t *blk2);
a24374f4
DC
46STATIC int xfs_attr3_leaf_figure_balance(xfs_da_state_t *state,
47 xfs_da_state_blk_t *leaf_blk_1,
48 struct xfs_attr3_icleaf_hdr *ichdr1,
49 xfs_da_state_blk_t *leaf_blk_2,
50 struct xfs_attr3_icleaf_hdr *ichdr2,
51 int *number_entries_in_blk1,
52 int *number_usedbytes_in_blk1);
5e656dbb
BN
53
54/*
55 * Utility routines.
56 */
a24374f4
DC
57STATIC void xfs_attr3_leaf_moveents(struct xfs_attr_leafblock *src_leaf,
58 struct xfs_attr3_icleaf_hdr *src_ichdr, int src_start,
59 struct xfs_attr_leafblock *dst_leaf,
60 struct xfs_attr3_icleaf_hdr *dst_ichdr, int dst_start,
61 int move_count, struct xfs_mount *mp);
f302e9e4
NS
62STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
63
a24374f4
DC
64void
65xfs_attr3_leaf_hdr_from_disk(
66 struct xfs_attr3_icleaf_hdr *to,
67 struct xfs_attr_leafblock *from)
68{
69 int i;
70
71 ASSERT(from->hdr.info.magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC) ||
72 from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC));
73
74 if (from->hdr.info.magic == cpu_to_be16(XFS_ATTR3_LEAF_MAGIC)) {
75 struct xfs_attr3_leaf_hdr *hdr3 = (struct xfs_attr3_leaf_hdr *)from;
76
77 to->forw = be32_to_cpu(hdr3->info.hdr.forw);
78 to->back = be32_to_cpu(hdr3->info.hdr.back);
79 to->magic = be16_to_cpu(hdr3->info.hdr.magic);
80 to->count = be16_to_cpu(hdr3->count);
81 to->usedbytes = be16_to_cpu(hdr3->usedbytes);
82 to->firstused = be16_to_cpu(hdr3->firstused);
83 to->holes = hdr3->holes;
84
85 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
86 to->freemap[i].base = be16_to_cpu(hdr3->freemap[i].base);
87 to->freemap[i].size = be16_to_cpu(hdr3->freemap[i].size);
88 }
89 return;
90 }
91 to->forw = be32_to_cpu(from->hdr.info.forw);
92 to->back = be32_to_cpu(from->hdr.info.back);
93 to->magic = be16_to_cpu(from->hdr.info.magic);
94 to->count = be16_to_cpu(from->hdr.count);
95 to->usedbytes = be16_to_cpu(from->hdr.usedbytes);
96 to->firstused = be16_to_cpu(from->hdr.firstused);
97 to->holes = from->hdr.holes;
98
99 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
100 to->freemap[i].base = be16_to_cpu(from->hdr.freemap[i].base);
101 to->freemap[i].size = be16_to_cpu(from->hdr.freemap[i].size);
102 }
103}
104
105void
106xfs_attr3_leaf_hdr_to_disk(
107 struct xfs_attr_leafblock *to,
108 struct xfs_attr3_icleaf_hdr *from)
109{
110 int i;
111
112 ASSERT(from->magic == XFS_ATTR_LEAF_MAGIC ||
113 from->magic == XFS_ATTR3_LEAF_MAGIC);
114
115 if (from->magic == XFS_ATTR3_LEAF_MAGIC) {
116 struct xfs_attr3_leaf_hdr *hdr3 = (struct xfs_attr3_leaf_hdr *)to;
117
118 hdr3->info.hdr.forw = cpu_to_be32(from->forw);
119 hdr3->info.hdr.back = cpu_to_be32(from->back);
120 hdr3->info.hdr.magic = cpu_to_be16(from->magic);
121 hdr3->count = cpu_to_be16(from->count);
122 hdr3->usedbytes = cpu_to_be16(from->usedbytes);
123 hdr3->firstused = cpu_to_be16(from->firstused);
124 hdr3->holes = from->holes;
125 hdr3->pad1 = 0;
126
127 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
128 hdr3->freemap[i].base = cpu_to_be16(from->freemap[i].base);
129 hdr3->freemap[i].size = cpu_to_be16(from->freemap[i].size);
130 }
131 return;
132 }
133 to->hdr.info.forw = cpu_to_be32(from->forw);
134 to->hdr.info.back = cpu_to_be32(from->back);
135 to->hdr.info.magic = cpu_to_be16(from->magic);
136 to->hdr.count = cpu_to_be16(from->count);
137 to->hdr.usedbytes = cpu_to_be16(from->usedbytes);
138 to->hdr.firstused = cpu_to_be16(from->firstused);
139 to->hdr.holes = from->holes;
140 to->hdr.pad1 = 0;
141
142 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
143 to->hdr.freemap[i].base = cpu_to_be16(from->freemap[i].base);
144 to->hdr.freemap[i].size = cpu_to_be16(from->freemap[i].size);
145 }
146}
147
148static bool
149xfs_attr3_leaf_verify(
a2ceac1f
DC
150 struct xfs_buf *bp)
151{
152 struct xfs_mount *mp = bp->b_target->bt_mount;
a24374f4
DC
153 struct xfs_attr_leafblock *leaf = bp->b_addr;
154 struct xfs_attr3_icleaf_hdr ichdr;
a2ceac1f 155
a24374f4
DC
156 xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
157
158 if (xfs_sb_version_hascrc(&mp->m_sb)) {
159 struct xfs_da3_node_hdr *hdr3 = bp->b_addr;
160
161 if (ichdr.magic != XFS_ATTR3_LEAF_MAGIC)
162 return false;
163
164 if (!uuid_equal(&hdr3->info.uuid, &mp->m_sb.sb_uuid))
165 return false;
166 if (be64_to_cpu(hdr3->info.blkno) != bp->b_bn)
167 return false;
168 } else {
169 if (ichdr.magic != XFS_ATTR_LEAF_MAGIC)
170 return false;
a2ceac1f 171 }
a24374f4
DC
172 if (ichdr.count == 0)
173 return false;
174
175 /* XXX: need to range check rest of attr header values */
176 /* XXX: hash order check? */
177
178 return true;
a2ceac1f
DC
179}
180
181static void
a24374f4 182xfs_attr3_leaf_write_verify(
a2ceac1f
DC
183 struct xfs_buf *bp)
184{
a24374f4
DC
185 struct xfs_mount *mp = bp->b_target->bt_mount;
186 struct xfs_buf_log_item *bip = bp->b_fspriv;
187 struct xfs_attr3_leaf_hdr *hdr3 = bp->b_addr;
188
189 if (!xfs_attr3_leaf_verify(bp)) {
190 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
191 xfs_buf_ioerror(bp, EFSCORRUPTED);
192 return;
193 }
194
195 if (!xfs_sb_version_hascrc(&mp->m_sb))
196 return;
197
198 if (bip)
199 hdr3->info.lsn = cpu_to_be64(bip->bli_item.li_lsn);
200
201 xfs_update_cksum(bp->b_addr, BBTOB(bp->b_length), XFS_ATTR3_LEAF_CRC_OFF);
a2ceac1f
DC
202}
203
a24374f4
DC
204/*
205 * leaf/node format detection on trees is sketchy, so a node read can be done on
206 * leaf level blocks when detection identifies the tree as a node format tree
207 * incorrectly. In this case, we need to swap the verifier to match the correct
208 * format of the block being read.
209 */
a2ceac1f 210static void
a24374f4
DC
211xfs_attr3_leaf_read_verify(
212 struct xfs_buf *bp)
a2ceac1f 213{
a24374f4
DC
214 struct xfs_mount *mp = bp->b_target->bt_mount;
215
216 if ((xfs_sb_version_hascrc(&mp->m_sb) &&
d21ca64d 217 !xfs_buf_verify_cksum(bp, XFS_ATTR3_LEAF_CRC_OFF)) ||
a24374f4
DC
218 !xfs_attr3_leaf_verify(bp)) {
219 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp, bp->b_addr);
220 xfs_buf_ioerror(bp, EFSCORRUPTED);
221 }
a2ceac1f
DC
222}
223
a24374f4
DC
224const struct xfs_buf_ops xfs_attr3_leaf_buf_ops = {
225 .verify_read = xfs_attr3_leaf_read_verify,
226 .verify_write = xfs_attr3_leaf_write_verify,
a2ceac1f
DC
227};
228
229int
a24374f4 230xfs_attr3_leaf_read(
a2ceac1f
DC
231 struct xfs_trans *tp,
232 struct xfs_inode *dp,
233 xfs_dablk_t bno,
234 xfs_daddr_t mappedbno,
235 struct xfs_buf **bpp)
236{
8b4dc4a9
DC
237 int err;
238
239 err = xfs_da_read_buf(tp, dp, bno, mappedbno, bpp,
a24374f4 240 XFS_ATTR_FORK, &xfs_attr3_leaf_buf_ops);
8b4dc4a9 241 if (!err && tp)
bdc16ee5 242 xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_ATTR_LEAF_BUF);
8b4dc4a9 243 return err;
a2ceac1f
DC
244}
245
57c9fccb 246/*========================================================================
5e656dbb
BN
247 * Namespace helper routines
248 *========================================================================*/
249
250/*
251 * If namespace bits don't match return 0.
252 * If all match then return 1.
253 */
56b2de80 254STATIC int
5e656dbb
BN
255xfs_attr_namesp_match(int arg_flags, int ondisk_flags)
256{
257 return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags);
258}
259
260
261/*========================================================================
262 * External routines when attribute fork size < XFS_LITINO(mp).
57c9fccb
NS
263 *========================================================================*/
264
265/*
6239071d
NS
266 * Query whether the requested number of additional bytes of extended
267 * attribute space will be able to fit inline.
a2ceac1f 268 *
ca86e759
NS
269 * Returns zero if not, else the di_forkoff fork offset to be used in the
270 * literal area for attribute data once the new bytes have been added.
6239071d
NS
271 *
272 * di_forkoff must be 8 byte aligned, hence is stored as a >>3 value;
273 * special case for dev/uuid inodes, they have fixed size data forks.
57c9fccb
NS
274 */
275int
ca86e759
NS
276xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
277{
6239071d
NS
278 int offset;
279 int minforkoff; /* lower limit on valid forkoff locations */
280 int maxforkoff; /* upper limit on valid forkoff locations */
a2ceac1f 281 int dsize;
6239071d 282 xfs_mount_t *mp = dp->i_mount;
ca86e759 283
49f693fa
DC
284 /* rounded down */
285 offset = (XFS_LITINO(mp, dp->i_d.di_version) - bytes) >> 3;
ca86e759
NS
286
287 switch (dp->i_d.di_format) {
288 case XFS_DINODE_FMT_DEV:
289 minforkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
290 return (offset >= minforkoff) ? minforkoff : 0;
291 case XFS_DINODE_FMT_UUID:
292 minforkoff = roundup(sizeof(uuid_t), 8) >> 3;
293 return (offset >= minforkoff) ? minforkoff : 0;
294 }
295
a2ceac1f
DC
296 /*
297 * If the requested numbers of bytes is smaller or equal to the
298 * current attribute fork size we can always proceed.
299 *
300 * Note that if_bytes in the data fork might actually be larger than
301 * the current data fork size is due to delalloc extents. In that
302 * case either the extent count will go down when they are converted
303 * to real extents, or the delalloc conversion will take care of the
304 * literal area rebalancing.
305 */
306 if (bytes <= XFS_IFORK_ASIZE(dp))
307 return dp->i_d.di_forkoff;
308
309 /*
310 * For attr2 we can try to move the forkoff if there is space in the
311 * literal area, but for the old format we are done if there is no
312 * space in the fixed attribute fork.
313 */
314 if (!(mp->m_flags & XFS_MOUNT_ATTR2))
6239071d 315 return 0;
6239071d 316
5e656dbb 317 dsize = dp->i_df.if_bytes;
a2ceac1f 318
5e656dbb
BN
319 switch (dp->i_d.di_format) {
320 case XFS_DINODE_FMT_EXTENTS:
a2ceac1f 321 /*
5e656dbb 322 * If there is no attr fork and the data fork is extents,
a2ceac1f
DC
323 * determine if creating the default attr fork will result
324 * in the extents form migrating to btree. If so, the
325 * minimum offset only needs to be the space required for
5e656dbb 326 * the btree root.
a2ceac1f 327 */
56b2de80
DC
328 if (!dp->i_d.di_forkoff && dp->i_df.if_bytes >
329 xfs_default_attroffset(dp))
5e656dbb
BN
330 dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS);
331 break;
5e656dbb
BN
332 case XFS_DINODE_FMT_BTREE:
333 /*
a2ceac1f
DC
334 * If we have a data btree then keep forkoff if we have one,
335 * otherwise we are adding a new attr, so then we set
336 * minforkoff to where the btree root can finish so we have
5e656dbb
BN
337 * plenty of room for attrs
338 */
339 if (dp->i_d.di_forkoff) {
a2ceac1f 340 if (offset < dp->i_d.di_forkoff)
5e656dbb 341 return 0;
a2ceac1f
DC
342 return dp->i_d.di_forkoff;
343 }
5dfa5cd2 344 dsize = XFS_BMAP_BROOT_SPACE(mp, dp->i_df.if_broot);
5e656dbb
BN
345 break;
346 }
a2ceac1f
DC
347
348 /*
349 * A data fork btree root must have space for at least
5e656dbb
BN
350 * MINDBTPTRS key/ptr pairs if the data fork is small or empty.
351 */
352 minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
ca86e759
NS
353 minforkoff = roundup(minforkoff, 8) >> 3;
354
355 /* attr fork btree root can have at least this many key/ptr pairs */
49f693fa
DC
356 maxforkoff = XFS_LITINO(mp, dp->i_d.di_version) -
357 XFS_BMDR_SPACE_CALC(MINABTPTRS);
ca86e759
NS
358 maxforkoff = maxforkoff >> 3; /* rounded down */
359
ca86e759
NS
360 if (offset >= maxforkoff)
361 return maxforkoff;
a2ceac1f
DC
362 if (offset >= minforkoff)
363 return offset;
ca86e759
NS
364 return 0;
365}
366
6239071d
NS
367/*
368 * Switch on the ATTR2 superblock bit (implies also FEATURES2)
369 */
370STATIC void
371xfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp)
372{
5e656dbb
BN
373 if ((mp->m_flags & XFS_MOUNT_ATTR2) &&
374 !(xfs_sb_version_hasattr2(&mp->m_sb))) {
375 spin_lock(&mp->m_sb_lock);
376 if (!xfs_sb_version_hasattr2(&mp->m_sb)) {
377 xfs_sb_version_addattr2(&mp->m_sb);
378 spin_unlock(&mp->m_sb_lock);
6239071d
NS
379 xfs_mod_sb(tp, XFS_SB_VERSIONNUM | XFS_SB_FEATURES2);
380 } else
5e656dbb 381 spin_unlock(&mp->m_sb_lock);
6239071d
NS
382 }
383}
384
ca86e759
NS
385/*
386 * Create the initial contents of a shortform attribute list.
387 */
388void
57c9fccb
NS
389xfs_attr_shortform_create(xfs_da_args_t *args)
390{
391 xfs_attr_sf_hdr_t *hdr;
392 xfs_inode_t *dp;
393 xfs_ifork_t *ifp;
394
a2ceac1f
DC
395 trace_xfs_attr_sf_create(args);
396
57c9fccb
NS
397 dp = args->dp;
398 ASSERT(dp != NULL);
399 ifp = dp->i_afp;
400 ASSERT(ifp != NULL);
401 ASSERT(ifp->if_bytes == 0);
402 if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) {
403 ifp->if_flags &= ~XFS_IFEXTENTS; /* just in case */
404 dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL;
405 ifp->if_flags |= XFS_IFINLINE;
406 } else {
407 ASSERT(ifp->if_flags & XFS_IFINLINE);
408 }
409 xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK);
410 hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data;
411 hdr->count = 0;
5e656dbb 412 hdr->totsize = cpu_to_be16(sizeof(*hdr));
57c9fccb 413 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
57c9fccb
NS
414}
415
416/*
417 * Add a name/value pair to the shortform attribute list.
418 * Overflow from the inode has already been checked for.
419 */
ca86e759
NS
420void
421xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
57c9fccb
NS
422{
423 xfs_attr_shortform_t *sf;
424 xfs_attr_sf_entry_t *sfe;
425 int i, offset, size;
ca86e759 426 xfs_mount_t *mp;
57c9fccb
NS
427 xfs_inode_t *dp;
428 xfs_ifork_t *ifp;
429
a2ceac1f
DC
430 trace_xfs_attr_sf_add(args);
431
57c9fccb 432 dp = args->dp;
ca86e759
NS
433 mp = dp->i_mount;
434 dp->i_d.di_forkoff = forkoff;
ca86e759 435
57c9fccb
NS
436 ifp = dp->i_afp;
437 ASSERT(ifp->if_flags & XFS_IFINLINE);
438 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
439 sfe = &sf->list[0];
5e656dbb 440 for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
ca86e759 441#ifdef DEBUG
57c9fccb
NS
442 if (sfe->namelen != args->namelen)
443 continue;
444 if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
445 continue;
5e656dbb 446 if (!xfs_attr_namesp_match(args->flags, sfe->flags))
57c9fccb 447 continue;
ca86e759
NS
448 ASSERT(0);
449#endif
57c9fccb
NS
450 }
451
452 offset = (char *)sfe - (char *)sf;
453 size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
454 xfs_idata_realloc(dp, size, XFS_ATTR_FORK);
455 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
456 sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset);
457
458 sfe->namelen = args->namelen;
5e656dbb
BN
459 sfe->valuelen = args->valuelen;
460 sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
57c9fccb
NS
461 memcpy(sfe->nameval, args->name, args->namelen);
462 memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
5e656dbb
BN
463 sf->hdr.count++;
464 be16_add_cpu(&sf->hdr.totsize, size);
57c9fccb
NS
465 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
466
6239071d 467 xfs_sbversion_add_attr2(mp, args->trans);
57c9fccb
NS
468}
469
56b2de80
DC
470/*
471 * After the last attribute is removed revert to original inode format,
472 * making all literal area available to the data fork once more.
473 */
474STATIC void
475xfs_attr_fork_reset(
476 struct xfs_inode *ip,
477 struct xfs_trans *tp)
478{
479 xfs_idestroy_fork(ip, XFS_ATTR_FORK);
480 ip->i_d.di_forkoff = 0;
481 ip->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
482
483 ASSERT(ip->i_d.di_anextents == 0);
484 ASSERT(ip->i_afp == NULL);
485
56b2de80
DC
486 xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
487}
488
57c9fccb 489/*
ca86e759 490 * Remove an attribute from the shortform attribute list structure.
57c9fccb
NS
491 */
492int
493xfs_attr_shortform_remove(xfs_da_args_t *args)
494{
495 xfs_attr_shortform_t *sf;
496 xfs_attr_sf_entry_t *sfe;
497 int base, size=0, end, totsize, i;
ca86e759 498 xfs_mount_t *mp;
57c9fccb
NS
499 xfs_inode_t *dp;
500
a2ceac1f
DC
501 trace_xfs_attr_sf_remove(args);
502
57c9fccb 503 dp = args->dp;
ca86e759 504 mp = dp->i_mount;
57c9fccb
NS
505 base = sizeof(xfs_attr_sf_hdr_t);
506 sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
507 sfe = &sf->list[0];
5e656dbb 508 end = sf->hdr.count;
ca86e759 509 for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
57c9fccb
NS
510 base += size, i++) {
511 size = XFS_ATTR_SF_ENTSIZE(sfe);
512 if (sfe->namelen != args->namelen)
513 continue;
514 if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
515 continue;
5e656dbb 516 if (!xfs_attr_namesp_match(args->flags, sfe->flags))
57c9fccb
NS
517 continue;
518 break;
519 }
ca86e759 520 if (i == end)
57c9fccb
NS
521 return(XFS_ERROR(ENOATTR));
522
ca86e759
NS
523 /*
524 * Fix up the attribute fork data, covering the hole
525 */
57c9fccb 526 end = base + size;
5e656dbb 527 totsize = be16_to_cpu(sf->hdr.totsize);
ca86e759
NS
528 if (end != totsize)
529 memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end);
5e656dbb
BN
530 sf->hdr.count--;
531 be16_add_cpu(&sf->hdr.totsize, -size);
ca86e759
NS
532
533 /*
534 * Fix up the start offset of the attribute fork
535 */
536 totsize -= size;
5e656dbb 537 if (totsize == sizeof(xfs_attr_sf_hdr_t) &&
56b2de80
DC
538 (mp->m_flags & XFS_MOUNT_ATTR2) &&
539 (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
540 !(args->op_flags & XFS_DA_OP_ADDNAME)) {
541 xfs_attr_fork_reset(dp, args->trans);
ca86e759
NS
542 } else {
543 xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
544 dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize);
545 ASSERT(dp->i_d.di_forkoff);
5e656dbb
BN
546 ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) ||
547 (args->op_flags & XFS_DA_OP_ADDNAME) ||
548 !(mp->m_flags & XFS_MOUNT_ATTR2) ||
549 dp->i_d.di_format == XFS_DINODE_FMT_BTREE);
ca86e759
NS
550 xfs_trans_log_inode(args->trans, dp,
551 XFS_ILOG_CORE | XFS_ILOG_ADATA);
552 }
553
6239071d 554 xfs_sbversion_add_attr2(mp, args->trans);
57c9fccb
NS
555
556 return(0);
557}
558
559/*
560 * Look up a name in a shortform attribute list structure.
561 */
562/*ARGSUSED*/
563int
564xfs_attr_shortform_lookup(xfs_da_args_t *args)
565{
566 xfs_attr_shortform_t *sf;
567 xfs_attr_sf_entry_t *sfe;
568 int i;
569 xfs_ifork_t *ifp;
570
a2ceac1f
DC
571 trace_xfs_attr_sf_lookup(args);
572
57c9fccb
NS
573 ifp = args->dp->i_afp;
574 ASSERT(ifp->if_flags & XFS_IFINLINE);
575 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
576 sfe = &sf->list[0];
5e656dbb 577 for (i = 0; i < sf->hdr.count;
57c9fccb
NS
578 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
579 if (sfe->namelen != args->namelen)
580 continue;
581 if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
582 continue;
5e656dbb 583 if (!xfs_attr_namesp_match(args->flags, sfe->flags))
57c9fccb 584 continue;
5e656dbb
BN
585 return(XFS_ERROR(EEXIST));
586 }
587 return(XFS_ERROR(ENOATTR));
588}
589
590/*
591 * Look up a name in a shortform attribute list structure.
592 */
593/*ARGSUSED*/
594int
595xfs_attr_shortform_getvalue(xfs_da_args_t *args)
596{
597 xfs_attr_shortform_t *sf;
598 xfs_attr_sf_entry_t *sfe;
599 int i;
600
e6d77a21 601 ASSERT(args->dp->i_afp->if_flags == XFS_IFINLINE);
5e656dbb
BN
602 sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data;
603 sfe = &sf->list[0];
604 for (i = 0; i < sf->hdr.count;
605 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
606 if (sfe->namelen != args->namelen)
57c9fccb 607 continue;
5e656dbb
BN
608 if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
609 continue;
610 if (!xfs_attr_namesp_match(args->flags, sfe->flags))
611 continue;
612 if (args->flags & ATTR_KERNOVAL) {
613 args->valuelen = sfe->valuelen;
614 return(XFS_ERROR(EEXIST));
615 }
616 if (args->valuelen < sfe->valuelen) {
617 args->valuelen = sfe->valuelen;
618 return(XFS_ERROR(ERANGE));
619 }
620 args->valuelen = sfe->valuelen;
621 memcpy(args->value, &sfe->nameval[args->namelen],
622 args->valuelen);
57c9fccb
NS
623 return(XFS_ERROR(EEXIST));
624 }
625 return(XFS_ERROR(ENOATTR));
626}
627
628/*
629 * Convert from using the shortform to the leaf.
630 */
631int
632xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
633{
634 xfs_inode_t *dp;
635 xfs_attr_shortform_t *sf;
636 xfs_attr_sf_entry_t *sfe;
637 xfs_da_args_t nargs;
638 char *tmpbuffer;
639 int error, i, size;
640 xfs_dablk_t blkno;
a2ceac1f 641 struct xfs_buf *bp;
57c9fccb
NS
642 xfs_ifork_t *ifp;
643
a2ceac1f
DC
644 trace_xfs_attr_sf_to_leaf(args);
645
57c9fccb
NS
646 dp = args->dp;
647 ifp = dp->i_afp;
648 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
5e656dbb 649 size = be16_to_cpu(sf->hdr.totsize);
57c9fccb
NS
650 tmpbuffer = kmem_alloc(size, KM_SLEEP);
651 ASSERT(tmpbuffer != NULL);
652 memcpy(tmpbuffer, ifp->if_u1.if_data, size);
653 sf = (xfs_attr_shortform_t *)tmpbuffer;
654
655 xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
3f17ed4b
DC
656 xfs_bmap_local_to_extents_empty(dp, XFS_ATTR_FORK);
657
57c9fccb
NS
658 bp = NULL;
659 error = xfs_da_grow_inode(args, &blkno);
660 if (error) {
661 /*
662 * If we hit an IO error middle of the transaction inside
663 * grow_inode(), we may have inconsistent data. Bail out.
664 */
665 if (error == EIO)
666 goto out;
667 xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */
668 memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */
669 goto out;
670 }
671
672 ASSERT(blkno == 0);
a24374f4 673 error = xfs_attr3_leaf_create(args, blkno, &bp);
57c9fccb
NS
674 if (error) {
675 error = xfs_da_shrink_inode(args, 0, bp);
676 bp = NULL;
677 if (error)
678 goto out;
679 xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */
680 memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */
681 goto out;
682 }
683
684 memset((char *)&nargs, 0, sizeof(nargs));
685 nargs.dp = dp;
686 nargs.firstblock = args->firstblock;
687 nargs.flist = args->flist;
688 nargs.total = args->total;
689 nargs.whichfork = XFS_ATTR_FORK;
690 nargs.trans = args->trans;
5e656dbb 691 nargs.op_flags = XFS_DA_OP_OKNOENT;
57c9fccb
NS
692
693 sfe = &sf->list[0];
5e656dbb 694 for (i = 0; i < sf->hdr.count; i++) {
56b2de80 695 nargs.name = sfe->nameval;
57c9fccb 696 nargs.namelen = sfe->namelen;
56b2de80 697 nargs.value = &sfe->nameval[nargs.namelen];
5e656dbb 698 nargs.valuelen = sfe->valuelen;
56b2de80 699 nargs.hashval = xfs_da_hashname(sfe->nameval,
57c9fccb 700 sfe->namelen);
5e656dbb 701 nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
a24374f4 702 error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
57c9fccb 703 ASSERT(error == ENOATTR);
a24374f4 704 error = xfs_attr3_leaf_add(bp, &nargs);
57c9fccb
NS
705 ASSERT(error != ENOSPC);
706 if (error)
707 goto out;
708 sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
709 }
710 error = 0;
711
712out:
5e656dbb 713 kmem_free(tmpbuffer);
57c9fccb
NS
714 return(error);
715}
716
717/*
718 * Check a leaf attribute block to see if all the entries would fit into
719 * a shortform attribute list.
720 */
721int
a2ceac1f 722xfs_attr_shortform_allfit(
bdb34d6b
DC
723 struct xfs_buf *bp,
724 struct xfs_inode *dp)
57c9fccb 725{
bdb34d6b
DC
726 struct xfs_attr_leafblock *leaf;
727 struct xfs_attr_leaf_entry *entry;
57c9fccb 728 xfs_attr_leaf_name_local_t *name_loc;
bdb34d6b
DC
729 struct xfs_attr3_icleaf_hdr leafhdr;
730 int bytes;
731 int i;
57c9fccb 732
a2ceac1f 733 leaf = bp->b_addr;
bdb34d6b
DC
734 xfs_attr3_leaf_hdr_from_disk(&leafhdr, leaf);
735 entry = xfs_attr3_leaf_entryp(leaf);
57c9fccb 736
57c9fccb 737 bytes = sizeof(struct xfs_attr_sf_hdr);
bdb34d6b 738 for (i = 0; i < leafhdr.count; entry++, i++) {
57c9fccb
NS
739 if (entry->flags & XFS_ATTR_INCOMPLETE)
740 continue; /* don't copy partial entries */
741 if (!(entry->flags & XFS_ATTR_LOCAL))
742 return(0);
a24374f4 743 name_loc = xfs_attr3_leaf_name_local(leaf, i);
57c9fccb
NS
744 if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX)
745 return(0);
5e656dbb 746 if (be16_to_cpu(name_loc->valuelen) >= XFS_ATTR_SF_ENTSIZE_MAX)
57c9fccb 747 return(0);
bdb34d6b 748 bytes += sizeof(struct xfs_attr_sf_entry) - 1
57c9fccb 749 + name_loc->namelen
5e656dbb 750 + be16_to_cpu(name_loc->valuelen);
57c9fccb 751 }
5e656dbb
BN
752 if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) &&
753 (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) &&
6e3140c7 754 (bytes == sizeof(struct xfs_attr_sf_hdr)))
bdb34d6b
DC
755 return -1;
756 return xfs_attr_shortform_bytesfit(dp, bytes);
57c9fccb
NS
757}
758
759/*
760 * Convert a leaf attribute list to shortform attribute list
761 */
762int
a24374f4
DC
763xfs_attr3_leaf_to_shortform(
764 struct xfs_buf *bp,
765 struct xfs_da_args *args,
766 int forkoff)
57c9fccb 767{
a24374f4
DC
768 struct xfs_attr_leafblock *leaf;
769 struct xfs_attr3_icleaf_hdr ichdr;
770 struct xfs_attr_leaf_entry *entry;
771 struct xfs_attr_leaf_name_local *name_loc;
772 struct xfs_da_args nargs;
773 struct xfs_inode *dp = args->dp;
774 char *tmpbuffer;
775 int error;
776 int i;
57c9fccb 777
a2ceac1f
DC
778 trace_xfs_attr_leaf_to_sf(args);
779
57c9fccb 780 tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP);
a24374f4
DC
781 if (!tmpbuffer)
782 return ENOMEM;
57c9fccb 783
a2ceac1f 784 memcpy(tmpbuffer, bp->b_addr, XFS_LBSIZE(dp->i_mount));
a24374f4 785
57c9fccb 786 leaf = (xfs_attr_leafblock_t *)tmpbuffer;
a24374f4
DC
787 xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
788 entry = xfs_attr3_leaf_entryp(leaf);
789
790 /* XXX (dgc): buffer is about to be marked stale - why zero it? */
a2ceac1f 791 memset(bp->b_addr, 0, XFS_LBSIZE(dp->i_mount));
57c9fccb
NS
792
793 /*
794 * Clean out the prior contents of the attribute list.
795 */
796 error = xfs_da_shrink_inode(args, 0, bp);
797 if (error)
798 goto out;
ca86e759
NS
799
800 if (forkoff == -1) {
5e656dbb
BN
801 ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2);
802 ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE);
56b2de80 803 xfs_attr_fork_reset(dp, args->trans);
57c9fccb 804 goto out;
ca86e759
NS
805 }
806
807 xfs_attr_shortform_create(args);
57c9fccb
NS
808
809 /*
810 * Copy the attributes
811 */
812 memset((char *)&nargs, 0, sizeof(nargs));
813 nargs.dp = dp;
814 nargs.firstblock = args->firstblock;
815 nargs.flist = args->flist;
816 nargs.total = args->total;
817 nargs.whichfork = XFS_ATTR_FORK;
818 nargs.trans = args->trans;
5e656dbb 819 nargs.op_flags = XFS_DA_OP_OKNOENT;
a24374f4
DC
820
821 for (i = 0; i < ichdr.count; entry++, i++) {
57c9fccb
NS
822 if (entry->flags & XFS_ATTR_INCOMPLETE)
823 continue; /* don't copy partial entries */
824 if (!entry->nameidx)
825 continue;
826 ASSERT(entry->flags & XFS_ATTR_LOCAL);
a24374f4 827 name_loc = xfs_attr3_leaf_name_local(leaf, i);
56b2de80 828 nargs.name = name_loc->nameval;
57c9fccb 829 nargs.namelen = name_loc->namelen;
56b2de80 830 nargs.value = &name_loc->nameval[nargs.namelen];
5e656dbb
BN
831 nargs.valuelen = be16_to_cpu(name_loc->valuelen);
832 nargs.hashval = be32_to_cpu(entry->hashval);
833 nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
ca86e759 834 xfs_attr_shortform_add(&nargs, forkoff);
57c9fccb
NS
835 }
836 error = 0;
837
838out:
5e656dbb 839 kmem_free(tmpbuffer);
a24374f4 840 return error;
57c9fccb
NS
841}
842
843/*
844 * Convert from using a single leaf to a root node and a leaf.
845 */
846int
a24374f4
DC
847xfs_attr3_leaf_to_node(
848 struct xfs_da_args *args)
57c9fccb 849{
a24374f4
DC
850 struct xfs_attr_leafblock *leaf;
851 struct xfs_attr3_icleaf_hdr icleafhdr;
852 struct xfs_attr_leaf_entry *entries;
88b32f06 853 struct xfs_da_node_entry *btree;
a24374f4
DC
854 struct xfs_da3_icnode_hdr icnodehdr;
855 struct xfs_da_intnode *node;
856 struct xfs_inode *dp = args->dp;
857 struct xfs_mount *mp = dp->i_mount;
858 struct xfs_buf *bp1 = NULL;
859 struct xfs_buf *bp2 = NULL;
860 xfs_dablk_t blkno;
861 int error;
57c9fccb 862
a2ceac1f
DC
863 trace_xfs_attr_leaf_to_node(args);
864
57c9fccb
NS
865 error = xfs_da_grow_inode(args, &blkno);
866 if (error)
867 goto out;
a24374f4 868 error = xfs_attr3_leaf_read(args->trans, dp, 0, -1, &bp1);
57c9fccb
NS
869 if (error)
870 goto out;
a2ceac1f 871
a24374f4 872 error = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp2, XFS_ATTR_FORK);
57c9fccb
NS
873 if (error)
874 goto out;
a24374f4
DC
875
876 /* copy leaf to new buffer, update identifiers */
bdc16ee5 877 xfs_trans_buf_set_type(args->trans, bp2, XFS_BLFT_ATTR_LEAF_BUF);
a2ceac1f 878 bp2->b_ops = bp1->b_ops;
a24374f4
DC
879 memcpy(bp2->b_addr, bp1->b_addr, XFS_LBSIZE(mp));
880 if (xfs_sb_version_hascrc(&mp->m_sb)) {
881 struct xfs_da3_blkinfo *hdr3 = bp2->b_addr;
882 hdr3->blkno = cpu_to_be64(bp2->b_bn);
883 }
884 xfs_trans_log_buf(args->trans, bp2, 0, XFS_LBSIZE(mp) - 1);
57c9fccb
NS
885
886 /*
887 * Set up the new root node.
888 */
88b32f06 889 error = xfs_da3_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK);
57c9fccb
NS
890 if (error)
891 goto out;
a2ceac1f 892 node = bp1->b_addr;
a24374f4
DC
893 xfs_da3_node_hdr_from_disk(&icnodehdr, node);
894 btree = xfs_da3_node_tree_p(node);
895
a2ceac1f 896 leaf = bp2->b_addr;
a24374f4
DC
897 xfs_attr3_leaf_hdr_from_disk(&icleafhdr, leaf);
898 entries = xfs_attr3_leaf_entryp(leaf);
899
57c9fccb 900 /* both on-disk, don't endian-flip twice */
a24374f4 901 btree[0].hashval = entries[icleafhdr.count - 1].hashval;
88b32f06 902 btree[0].before = cpu_to_be32(blkno);
a24374f4
DC
903 icnodehdr.count = 1;
904 xfs_da3_node_hdr_to_disk(node, &icnodehdr);
905 xfs_trans_log_buf(args->trans, bp1, 0, XFS_LBSIZE(mp) - 1);
57c9fccb
NS
906 error = 0;
907out:
a24374f4 908 return error;
57c9fccb
NS
909}
910
2bd0ea18
NS
911/*========================================================================
912 * Routines used for growing the Btree.
913 *========================================================================*/
914
915/*
916 * Create the initial contents of a leaf attribute list
917 * or a leaf in a node attribute list.
918 */
5e656dbb 919STATIC int
a24374f4
DC
920xfs_attr3_leaf_create(
921 struct xfs_da_args *args,
922 xfs_dablk_t blkno,
923 struct xfs_buf **bpp)
2bd0ea18 924{
a24374f4
DC
925 struct xfs_attr_leafblock *leaf;
926 struct xfs_attr3_icleaf_hdr ichdr;
927 struct xfs_inode *dp = args->dp;
928 struct xfs_mount *mp = dp->i_mount;
929 struct xfs_buf *bp;
930 int error;
2bd0ea18 931
a2ceac1f
DC
932 trace_xfs_attr_leaf_create(args);
933
2bd0ea18
NS
934 error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp,
935 XFS_ATTR_FORK);
936 if (error)
a24374f4
DC
937 return error;
938 bp->b_ops = &xfs_attr3_leaf_buf_ops;
bdc16ee5 939 xfs_trans_buf_set_type(args->trans, bp, XFS_BLFT_ATTR_LEAF_BUF);
a2ceac1f 940 leaf = bp->b_addr;
a24374f4
DC
941 memset(leaf, 0, XFS_LBSIZE(mp));
942
943 memset(&ichdr, 0, sizeof(ichdr));
944 ichdr.firstused = XFS_LBSIZE(mp);
945
946 if (xfs_sb_version_hascrc(&mp->m_sb)) {
947 struct xfs_da3_blkinfo *hdr3 = bp->b_addr;
2bd0ea18 948
a24374f4
DC
949 ichdr.magic = XFS_ATTR3_LEAF_MAGIC;
950
951 hdr3->blkno = cpu_to_be64(bp->b_bn);
952 hdr3->owner = cpu_to_be64(dp->i_ino);
953 uuid_copy(&hdr3->uuid, &mp->m_sb.sb_uuid);
954
955 ichdr.freemap[0].base = sizeof(struct xfs_attr3_leaf_hdr);
956 } else {
957 ichdr.magic = XFS_ATTR_LEAF_MAGIC;
958 ichdr.freemap[0].base = sizeof(struct xfs_attr_leaf_hdr);
959 }
960 ichdr.freemap[0].size = ichdr.firstused - ichdr.freemap[0].base;
2bd0ea18 961
a24374f4
DC
962 xfs_attr3_leaf_hdr_to_disk(leaf, &ichdr);
963 xfs_trans_log_buf(args->trans, bp, 0, XFS_LBSIZE(mp) - 1);
2bd0ea18
NS
964
965 *bpp = bp;
a24374f4 966 return 0;
2bd0ea18
NS
967}
968
969/*
970 * Split the leaf node, rebalance, then add the new entry.
971 */
972int
a24374f4
DC
973xfs_attr3_leaf_split(
974 struct xfs_da_state *state,
975 struct xfs_da_state_blk *oldblk,
976 struct xfs_da_state_blk *newblk)
2bd0ea18
NS
977{
978 xfs_dablk_t blkno;
979 int error;
980
a2ceac1f
DC
981 trace_xfs_attr_leaf_split(state->args);
982
2bd0ea18
NS
983 /*
984 * Allocate space for a new leaf node.
985 */
986 ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC);
987 error = xfs_da_grow_inode(state->args, &blkno);
988 if (error)
989 return(error);
a24374f4 990 error = xfs_attr3_leaf_create(state->args, blkno, &newblk->bp);
2bd0ea18
NS
991 if (error)
992 return(error);
993 newblk->blkno = blkno;
994 newblk->magic = XFS_ATTR_LEAF_MAGIC;
995
996 /*
997 * Rebalance the entries across the two leaves.
998 * NOTE: rebalance() currently depends on the 2nd block being empty.
999 */
a24374f4 1000 xfs_attr3_leaf_rebalance(state, oldblk, newblk);
88b32f06 1001 error = xfs_da3_blk_link(state, oldblk, newblk);
2bd0ea18
NS
1002 if (error)
1003 return(error);
1004
1005 /*
1006 * Save info on "old" attribute for "atomic rename" ops, leaf_add()
1007 * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the
1008 * "new" attrs info. Will need the "old" info to remove it later.
1009 *
1010 * Insert the "new" entry in the correct block.
1011 */
a2ceac1f
DC
1012 if (state->inleaf) {
1013 trace_xfs_attr_leaf_add_old(state->args);
a24374f4 1014 error = xfs_attr3_leaf_add(oldblk->bp, state->args);
a2ceac1f
DC
1015 } else {
1016 trace_xfs_attr_leaf_add_new(state->args);
a24374f4 1017 error = xfs_attr3_leaf_add(newblk->bp, state->args);
a2ceac1f 1018 }
2bd0ea18
NS
1019
1020 /*
1021 * Update last hashval in each block since we added the name.
1022 */
1023 oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL);
1024 newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL);
1025 return(error);
1026}
1027
1028/*
1029 * Add a name to the leaf attribute list structure.
1030 */
1031int
a24374f4 1032xfs_attr3_leaf_add(
a2ceac1f
DC
1033 struct xfs_buf *bp,
1034 struct xfs_da_args *args)
2bd0ea18 1035{
a24374f4
DC
1036 struct xfs_attr_leafblock *leaf;
1037 struct xfs_attr3_icleaf_hdr ichdr;
1038 int tablesize;
1039 int entsize;
1040 int sum;
1041 int tmp;
1042 int i;
2bd0ea18 1043
a2ceac1f
DC
1044 trace_xfs_attr_leaf_add(args);
1045
1046 leaf = bp->b_addr;
a24374f4
DC
1047 xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
1048 ASSERT(args->index >= 0 && args->index <= ichdr.count);
ca86e759 1049 entsize = xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
2bd0ea18
NS
1050 args->trans->t_mountp->m_sb.sb_blocksize, NULL);
1051
1052 /*
1053 * Search through freemap for first-fit on new name length.
1054 * (may need to figure in size of entry struct too)
1055 */
a24374f4
DC
1056 tablesize = (ichdr.count + 1) * sizeof(xfs_attr_leaf_entry_t)
1057 + xfs_attr3_leaf_hdr_size(leaf);
1058 for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE - 1; i >= 0; i--) {
1059 if (tablesize > ichdr.firstused) {
1060 sum += ichdr.freemap[i].size;
2bd0ea18
NS
1061 continue;
1062 }
a24374f4 1063 if (!ichdr.freemap[i].size)
2bd0ea18
NS
1064 continue; /* no space in this map */
1065 tmp = entsize;
a24374f4 1066 if (ichdr.freemap[i].base < ichdr.firstused)
2bd0ea18 1067 tmp += sizeof(xfs_attr_leaf_entry_t);
a24374f4
DC
1068 if (ichdr.freemap[i].size >= tmp) {
1069 tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, i);
1070 goto out_log_hdr;
2bd0ea18 1071 }
a24374f4 1072 sum += ichdr.freemap[i].size;
2bd0ea18
NS
1073 }
1074
1075 /*
1076 * If there are no holes in the address space of the block,
1077 * and we don't have enough freespace, then compaction will do us
1078 * no good and we should just give up.
1079 */
a24374f4
DC
1080 if (!ichdr.holes && sum < entsize)
1081 return XFS_ERROR(ENOSPC);
2bd0ea18
NS
1082
1083 /*
1084 * Compact the entries to coalesce free space.
1085 * This may change the hdr->count via dropping INCOMPLETE entries.
1086 */
a24374f4 1087 xfs_attr3_leaf_compact(args, &ichdr, bp);
2bd0ea18
NS
1088
1089 /*
1090 * After compaction, the block is guaranteed to have only one
dfc130f3 1091 * free region, in freemap[0]. If it is not big enough, give up.
2bd0ea18 1092 */
a24374f4
DC
1093 if (ichdr.freemap[0].size < (entsize + sizeof(xfs_attr_leaf_entry_t))) {
1094 tmp = ENOSPC;
1095 goto out_log_hdr;
1096 }
1097
1098 tmp = xfs_attr3_leaf_add_work(bp, &ichdr, args, 0);
2bd0ea18 1099
a24374f4
DC
1100out_log_hdr:
1101 xfs_attr3_leaf_hdr_to_disk(leaf, &ichdr);
1102 xfs_trans_log_buf(args->trans, bp,
1103 XFS_DA_LOGRANGE(leaf, &leaf->hdr,
1104 xfs_attr3_leaf_hdr_size(leaf)));
1105 return tmp;
2bd0ea18
NS
1106}
1107
1108/*
1109 * Add a name to a leaf attribute list structure.
1110 */
1111STATIC int
a24374f4
DC
1112xfs_attr3_leaf_add_work(
1113 struct xfs_buf *bp,
1114 struct xfs_attr3_icleaf_hdr *ichdr,
1115 struct xfs_da_args *args,
1116 int mapindex)
2bd0ea18 1117{
a24374f4
DC
1118 struct xfs_attr_leafblock *leaf;
1119 struct xfs_attr_leaf_entry *entry;
1120 struct xfs_attr_leaf_name_local *name_loc;
1121 struct xfs_attr_leaf_name_remote *name_rmt;
a24374f4
DC
1122 struct xfs_mount *mp;
1123 int tmp;
1124 int i;
2bd0ea18 1125
a2ceac1f
DC
1126 trace_xfs_attr_leaf_add_work(args);
1127
1128 leaf = bp->b_addr;
a24374f4
DC
1129 ASSERT(mapindex >= 0 && mapindex < XFS_ATTR_LEAF_MAPSIZE);
1130 ASSERT(args->index >= 0 && args->index <= ichdr->count);
2bd0ea18
NS
1131
1132 /*
1133 * Force open some space in the entry array and fill it in.
1134 */
a24374f4
DC
1135 entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
1136 if (args->index < ichdr->count) {
1137 tmp = ichdr->count - args->index;
2bd0ea18 1138 tmp *= sizeof(xfs_attr_leaf_entry_t);
a24374f4 1139 memmove(entry + 1, entry, tmp);
a2ceac1f 1140 xfs_trans_log_buf(args->trans, bp,
2bd0ea18
NS
1141 XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
1142 }
a24374f4 1143 ichdr->count++;
2bd0ea18
NS
1144
1145 /*
1146 * Allocate space for the new string (at the end of the run).
1147 */
2bd0ea18 1148 mp = args->trans->t_mountp;
a24374f4
DC
1149 ASSERT(ichdr->freemap[mapindex].base < XFS_LBSIZE(mp));
1150 ASSERT((ichdr->freemap[mapindex].base & 0x3) == 0);
1151 ASSERT(ichdr->freemap[mapindex].size >=
ca86e759
NS
1152 xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
1153 mp->m_sb.sb_blocksize, NULL));
a24374f4
DC
1154 ASSERT(ichdr->freemap[mapindex].size < XFS_LBSIZE(mp));
1155 ASSERT((ichdr->freemap[mapindex].size & 0x3) == 0);
1156
1157 ichdr->freemap[mapindex].size -=
1158 xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
1159 mp->m_sb.sb_blocksize, &tmp);
1160
1161 entry->nameidx = cpu_to_be16(ichdr->freemap[mapindex].base +
1162 ichdr->freemap[mapindex].size);
5e656dbb 1163 entry->hashval = cpu_to_be32(args->hashval);
2bd0ea18 1164 entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
5e656dbb
BN
1165 entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
1166 if (args->op_flags & XFS_DA_OP_RENAME) {
2bd0ea18
NS
1167 entry->flags |= XFS_ATTR_INCOMPLETE;
1168 if ((args->blkno2 == args->blkno) &&
1169 (args->index2 <= args->index)) {
1170 args->index2++;
1171 }
1172 }
a2ceac1f 1173 xfs_trans_log_buf(args->trans, bp,
2bd0ea18 1174 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
5e656dbb
BN
1175 ASSERT((args->index == 0) ||
1176 (be32_to_cpu(entry->hashval) >= be32_to_cpu((entry-1)->hashval)));
a24374f4 1177 ASSERT((args->index == ichdr->count - 1) ||
5e656dbb 1178 (be32_to_cpu(entry->hashval) <= be32_to_cpu((entry+1)->hashval)));
2bd0ea18
NS
1179
1180 /*
5000d01d 1181 * For "remote" attribute values, simply note that we need to
2bd0ea18
NS
1182 * allocate space for the "remote" value. We can't actually
1183 * allocate the extents in this transaction, and we can't decide
1184 * which blocks they should be as we might allocate more blocks
1185 * as part of this transaction (a split operation for example).
1186 */
1187 if (entry->flags & XFS_ATTR_LOCAL) {
a24374f4 1188 name_loc = xfs_attr3_leaf_name_local(leaf, args->index);
2bd0ea18 1189 name_loc->namelen = args->namelen;
5e656dbb 1190 name_loc->valuelen = cpu_to_be16(args->valuelen);
32181a02
NS
1191 memcpy((char *)name_loc->nameval, args->name, args->namelen);
1192 memcpy((char *)&name_loc->nameval[args->namelen], args->value,
5e656dbb 1193 be16_to_cpu(name_loc->valuelen));
2bd0ea18 1194 } else {
a24374f4 1195 name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
2bd0ea18 1196 name_rmt->namelen = args->namelen;
32181a02 1197 memcpy((char *)name_rmt->name, args->name, args->namelen);
2bd0ea18
NS
1198 entry->flags |= XFS_ATTR_INCOMPLETE;
1199 /* just in case */
46eca962
NS
1200 name_rmt->valuelen = 0;
1201 name_rmt->valueblk = 0;
2bd0ea18 1202 args->rmtblkno = 1;
f08bc2a9 1203 args->rmtblkcnt = xfs_attr3_rmt_blocks(mp, args->valuelen);
2bd0ea18 1204 }
a2ceac1f 1205 xfs_trans_log_buf(args->trans, bp,
a24374f4 1206 XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index),
2bd0ea18
NS
1207 xfs_attr_leaf_entsize(leaf, args->index)));
1208
1209 /*
1210 * Update the control info for this leaf node
1211 */
a24374f4
DC
1212 if (be16_to_cpu(entry->nameidx) < ichdr->firstused)
1213 ichdr->firstused = be16_to_cpu(entry->nameidx);
1214
1215 ASSERT(ichdr->firstused >= ichdr->count * sizeof(xfs_attr_leaf_entry_t)
1216 + xfs_attr3_leaf_hdr_size(leaf));
1217 tmp = (ichdr->count - 1) * sizeof(xfs_attr_leaf_entry_t)
1218 + xfs_attr3_leaf_hdr_size(leaf);
1219
78d6585c 1220 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
a24374f4
DC
1221 if (ichdr->freemap[i].base == tmp) {
1222 ichdr->freemap[i].base += sizeof(xfs_attr_leaf_entry_t);
1223 ichdr->freemap[i].size -= sizeof(xfs_attr_leaf_entry_t);
2bd0ea18
NS
1224 }
1225 }
a24374f4
DC
1226 ichdr->usedbytes += xfs_attr_leaf_entsize(leaf, args->index);
1227 return 0;
2bd0ea18
NS
1228}
1229
1230/*
1231 * Garbage collect a leaf attribute list block by copying it to a new buffer.
1232 */
1233STATIC void
a24374f4 1234xfs_attr3_leaf_compact(
a2ceac1f 1235 struct xfs_da_args *args,
33765cd3 1236 struct xfs_attr3_icleaf_hdr *ichdr_dst,
a2ceac1f 1237 struct xfs_buf *bp)
2bd0ea18 1238{
33765cd3
DC
1239 struct xfs_attr_leafblock *leaf_src;
1240 struct xfs_attr_leafblock *leaf_dst;
1241 struct xfs_attr3_icleaf_hdr ichdr_src;
a2ceac1f
DC
1242 struct xfs_trans *trans = args->trans;
1243 struct xfs_mount *mp = trans->t_mountp;
1244 char *tmpbuffer;
1245
1246 trace_xfs_attr_leaf_compact(args);
2bd0ea18 1247
2bd0ea18 1248 tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP);
a2ceac1f
DC
1249 memcpy(tmpbuffer, bp->b_addr, XFS_LBSIZE(mp));
1250 memset(bp->b_addr, 0, XFS_LBSIZE(mp));
33765cd3
DC
1251 leaf_src = (xfs_attr_leafblock_t *)tmpbuffer;
1252 leaf_dst = bp->b_addr;
2bd0ea18
NS
1253
1254 /*
33765cd3
DC
1255 * Copy the on-disk header back into the destination buffer to ensure
1256 * all the information in the header that is not part of the incore
1257 * header structure is preserved.
2bd0ea18 1258 */
33765cd3
DC
1259 memcpy(bp->b_addr, tmpbuffer, xfs_attr3_leaf_hdr_size(leaf_src));
1260
1261 /* Initialise the incore headers */
1262 ichdr_src = *ichdr_dst; /* struct copy */
1263 ichdr_dst->firstused = XFS_LBSIZE(mp);
1264 ichdr_dst->usedbytes = 0;
1265 ichdr_dst->count = 0;
1266 ichdr_dst->holes = 0;
1267 ichdr_dst->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_src);
1268 ichdr_dst->freemap[0].size = ichdr_dst->firstused -
1269 ichdr_dst->freemap[0].base;
1270
33765cd3
DC
1271 /* write the header back to initialise the underlying buffer */
1272 xfs_attr3_leaf_hdr_to_disk(leaf_dst, ichdr_dst);
2bd0ea18
NS
1273
1274 /*
1275 * Copy all entry's in the same (sorted) order,
1276 * but allocate name/value pairs packed and in sequence.
1277 */
33765cd3
DC
1278 xfs_attr3_leaf_moveents(leaf_src, &ichdr_src, 0, leaf_dst, ichdr_dst, 0,
1279 ichdr_src.count, mp);
a24374f4
DC
1280 /*
1281 * this logs the entire buffer, but the caller must write the header
1282 * back to the buffer when it is finished modifying it.
1283 */
a2ceac1f 1284 xfs_trans_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1);
2bd0ea18 1285
5e656dbb 1286 kmem_free(tmpbuffer);
2bd0ea18
NS
1287}
1288
a24374f4
DC
1289/*
1290 * Compare two leaf blocks "order".
1291 * Return 0 unless leaf2 should go before leaf1.
1292 */
1293static int
1294xfs_attr3_leaf_order(
1295 struct xfs_buf *leaf1_bp,
1296 struct xfs_attr3_icleaf_hdr *leaf1hdr,
1297 struct xfs_buf *leaf2_bp,
1298 struct xfs_attr3_icleaf_hdr *leaf2hdr)
1299{
1300 struct xfs_attr_leaf_entry *entries1;
1301 struct xfs_attr_leaf_entry *entries2;
1302
1303 entries1 = xfs_attr3_leaf_entryp(leaf1_bp->b_addr);
1304 entries2 = xfs_attr3_leaf_entryp(leaf2_bp->b_addr);
1305 if (leaf1hdr->count > 0 && leaf2hdr->count > 0 &&
1306 ((be32_to_cpu(entries2[0].hashval) <
1307 be32_to_cpu(entries1[0].hashval)) ||
1308 (be32_to_cpu(entries2[leaf2hdr->count - 1].hashval) <
1309 be32_to_cpu(entries1[leaf1hdr->count - 1].hashval)))) {
1310 return 1;
1311 }
1312 return 0;
1313}
1314
1315int
1316xfs_attr_leaf_order(
1317 struct xfs_buf *leaf1_bp,
1318 struct xfs_buf *leaf2_bp)
1319{
1320 struct xfs_attr3_icleaf_hdr ichdr1;
1321 struct xfs_attr3_icleaf_hdr ichdr2;
1322
1323 xfs_attr3_leaf_hdr_from_disk(&ichdr1, leaf1_bp->b_addr);
1324 xfs_attr3_leaf_hdr_from_disk(&ichdr2, leaf2_bp->b_addr);
1325 return xfs_attr3_leaf_order(leaf1_bp, &ichdr1, leaf2_bp, &ichdr2);
1326}
1327
2bd0ea18
NS
1328/*
1329 * Redistribute the attribute list entries between two leaf nodes,
1330 * taking into account the size of the new entry.
1331 *
1332 * NOTE: if new block is empty, then it will get the upper half of the
1333 * old block. At present, all (one) callers pass in an empty second block.
1334 *
1335 * This code adjusts the args->index/blkno and args->index2/blkno2 fields
1336 * to match what it is doing in splitting the attribute leaf block. Those
dfc130f3 1337 * values are used in "atomic rename" operations on attributes. Note that
2bd0ea18
NS
1338 * the "new" and "old" values can end up in different blocks.
1339 */
1340STATIC void
a24374f4
DC
1341xfs_attr3_leaf_rebalance(
1342 struct xfs_da_state *state,
1343 struct xfs_da_state_blk *blk1,
1344 struct xfs_da_state_blk *blk2)
2bd0ea18 1345{
a24374f4
DC
1346 struct xfs_da_args *args;
1347 struct xfs_attr_leafblock *leaf1;
1348 struct xfs_attr_leafblock *leaf2;
1349 struct xfs_attr3_icleaf_hdr ichdr1;
1350 struct xfs_attr3_icleaf_hdr ichdr2;
1351 struct xfs_attr_leaf_entry *entries1;
1352 struct xfs_attr_leaf_entry *entries2;
1353 int count;
1354 int totallen;
1355 int max;
1356 int space;
1357 int swap;
2bd0ea18
NS
1358
1359 /*
1360 * Set up environment.
1361 */
1362 ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC);
1363 ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC);
a2ceac1f
DC
1364 leaf1 = blk1->bp->b_addr;
1365 leaf2 = blk2->bp->b_addr;
a24374f4
DC
1366 xfs_attr3_leaf_hdr_from_disk(&ichdr1, leaf1);
1367 xfs_attr3_leaf_hdr_from_disk(&ichdr2, leaf2);
1368 ASSERT(ichdr2.count == 0);
2bd0ea18
NS
1369 args = state->args;
1370
a2ceac1f
DC
1371 trace_xfs_attr_leaf_rebalance(args);
1372
2bd0ea18
NS
1373 /*
1374 * Check ordering of blocks, reverse if it makes things simpler.
1375 *
1376 * NOTE: Given that all (current) callers pass in an empty
1377 * second block, this code should never set "swap".
1378 */
1379 swap = 0;
a24374f4
DC
1380 if (xfs_attr3_leaf_order(blk1->bp, &ichdr1, blk2->bp, &ichdr2)) {
1381 struct xfs_da_state_blk *tmp_blk;
1382 struct xfs_attr3_icleaf_hdr tmp_ichdr;
1383
2bd0ea18
NS
1384 tmp_blk = blk1;
1385 blk1 = blk2;
1386 blk2 = tmp_blk;
a24374f4
DC
1387
1388 /* struct copies to swap them rather than reconverting */
1389 tmp_ichdr = ichdr1;
1390 ichdr1 = ichdr2;
1391 ichdr2 = tmp_ichdr;
1392
a2ceac1f
DC
1393 leaf1 = blk1->bp->b_addr;
1394 leaf2 = blk2->bp->b_addr;
2bd0ea18
NS
1395 swap = 1;
1396 }
2bd0ea18
NS
1397
1398 /*
1399 * Examine entries until we reduce the absolute difference in
1400 * byte usage between the two blocks to a minimum. Then get
1401 * the direction to copy and the number of elements to move.
1402 *
1403 * "inleaf" is true if the new entry should be inserted into blk1.
1404 * If "swap" is also true, then reverse the sense of "inleaf".
1405 */
a24374f4
DC
1406 state->inleaf = xfs_attr3_leaf_figure_balance(state, blk1, &ichdr1,
1407 blk2, &ichdr2,
1408 &count, &totallen);
2bd0ea18
NS
1409 if (swap)
1410 state->inleaf = !state->inleaf;
1411
1412 /*
1413 * Move any entries required from leaf to leaf:
1414 */
a24374f4 1415 if (count < ichdr1.count) {
2bd0ea18
NS
1416 /*
1417 * Figure the total bytes to be added to the destination leaf.
1418 */
1419 /* number entries being moved */
a24374f4
DC
1420 count = ichdr1.count - count;
1421 space = ichdr1.usedbytes - totallen;
2bd0ea18
NS
1422 space += count * sizeof(xfs_attr_leaf_entry_t);
1423
1424 /*
1425 * leaf2 is the destination, compact it if it looks tight.
1426 */
a24374f4
DC
1427 max = ichdr2.firstused - xfs_attr3_leaf_hdr_size(leaf1);
1428 max -= ichdr2.count * sizeof(xfs_attr_leaf_entry_t);
a2ceac1f 1429 if (space > max)
a24374f4 1430 xfs_attr3_leaf_compact(args, &ichdr2, blk2->bp);
2bd0ea18
NS
1431
1432 /*
1433 * Move high entries from leaf1 to low end of leaf2.
1434 */
a24374f4
DC
1435 xfs_attr3_leaf_moveents(leaf1, &ichdr1, ichdr1.count - count,
1436 leaf2, &ichdr2, 0, count, state->mp);
2bd0ea18 1437
a24374f4 1438 } else if (count > ichdr1.count) {
2bd0ea18
NS
1439 /*
1440 * I assert that since all callers pass in an empty
1441 * second buffer, this code should never execute.
1442 */
a2ceac1f 1443 ASSERT(0);
2bd0ea18
NS
1444
1445 /*
1446 * Figure the total bytes to be added to the destination leaf.
1447 */
1448 /* number entries being moved */
a24374f4
DC
1449 count -= ichdr1.count;
1450 space = totallen - ichdr1.usedbytes;
2bd0ea18
NS
1451 space += count * sizeof(xfs_attr_leaf_entry_t);
1452
1453 /*
1454 * leaf1 is the destination, compact it if it looks tight.
1455 */
a24374f4
DC
1456 max = ichdr1.firstused - xfs_attr3_leaf_hdr_size(leaf1);
1457 max -= ichdr1.count * sizeof(xfs_attr_leaf_entry_t);
a2ceac1f 1458 if (space > max)
a24374f4 1459 xfs_attr3_leaf_compact(args, &ichdr1, blk1->bp);
2bd0ea18
NS
1460
1461 /*
1462 * Move low entries from leaf2 to high end of leaf1.
1463 */
a24374f4
DC
1464 xfs_attr3_leaf_moveents(leaf2, &ichdr2, 0, leaf1, &ichdr1,
1465 ichdr1.count, count, state->mp);
2bd0ea18
NS
1466 }
1467
a24374f4
DC
1468 xfs_attr3_leaf_hdr_to_disk(leaf1, &ichdr1);
1469 xfs_attr3_leaf_hdr_to_disk(leaf2, &ichdr2);
1470 xfs_trans_log_buf(args->trans, blk1->bp, 0, state->blocksize-1);
1471 xfs_trans_log_buf(args->trans, blk2->bp, 0, state->blocksize-1);
1472
2bd0ea18
NS
1473 /*
1474 * Copy out last hashval in each block for B-tree code.
1475 */
a24374f4
DC
1476 entries1 = xfs_attr3_leaf_entryp(leaf1);
1477 entries2 = xfs_attr3_leaf_entryp(leaf2);
1478 blk1->hashval = be32_to_cpu(entries1[ichdr1.count - 1].hashval);
1479 blk2->hashval = be32_to_cpu(entries2[ichdr2.count - 1].hashval);
2bd0ea18
NS
1480
1481 /*
1482 * Adjust the expected index for insertion.
1483 * NOTE: this code depends on the (current) situation that the
1484 * second block was originally empty.
1485 *
1486 * If the insertion point moved to the 2nd block, we must adjust
1487 * the index. We must also track the entry just following the
1488 * new entry for use in an "atomic rename" operation, that entry
1489 * is always the "old" entry and the "new" entry is what we are
1490 * inserting. The index/blkno fields refer to the "old" entry,
1491 * while the index2/blkno2 fields refer to the "new" entry.
1492 */
a24374f4 1493 if (blk1->index > ichdr1.count) {
2bd0ea18 1494 ASSERT(state->inleaf == 0);
a24374f4 1495 blk2->index = blk1->index - ichdr1.count;
2bd0ea18
NS
1496 args->index = args->index2 = blk2->index;
1497 args->blkno = args->blkno2 = blk2->blkno;
a24374f4 1498 } else if (blk1->index == ichdr1.count) {
2bd0ea18
NS
1499 if (state->inleaf) {
1500 args->index = blk1->index;
1501 args->blkno = blk1->blkno;
1502 args->index2 = 0;
1503 args->blkno2 = blk2->blkno;
1504 } else {
a2ceac1f
DC
1505 /*
1506 * On a double leaf split, the original attr location
1507 * is already stored in blkno2/index2, so don't
1508 * overwrite it overwise we corrupt the tree.
1509 */
a24374f4 1510 blk2->index = blk1->index - ichdr1.count;
a2ceac1f
DC
1511 args->index = blk2->index;
1512 args->blkno = blk2->blkno;
1513 if (!state->extravalid) {
1514 /*
1515 * set the new attr location to match the old
1516 * one and let the higher level split code
1517 * decide where in the leaf to place it.
1518 */
1519 args->index2 = blk2->index;
1520 args->blkno2 = blk2->blkno;
1521 }
2bd0ea18
NS
1522 }
1523 } else {
1524 ASSERT(state->inleaf == 1);
1525 args->index = args->index2 = blk1->index;
1526 args->blkno = args->blkno2 = blk1->blkno;
1527 }
1528}
1529
1530/*
1531 * Examine entries until we reduce the absolute difference in
1532 * byte usage between the two blocks to a minimum.
1533 * GROT: Is this really necessary? With other than a 512 byte blocksize,
1534 * GROT: there will always be enough room in either block for a new entry.
1535 * GROT: Do a double-split for this case?
1536 */
1537STATIC int
a24374f4
DC
1538xfs_attr3_leaf_figure_balance(
1539 struct xfs_da_state *state,
1540 struct xfs_da_state_blk *blk1,
1541 struct xfs_attr3_icleaf_hdr *ichdr1,
1542 struct xfs_da_state_blk *blk2,
1543 struct xfs_attr3_icleaf_hdr *ichdr2,
1544 int *countarg,
1545 int *usedbytesarg)
2bd0ea18 1546{
a24374f4
DC
1547 struct xfs_attr_leafblock *leaf1 = blk1->bp->b_addr;
1548 struct xfs_attr_leafblock *leaf2 = blk2->bp->b_addr;
1549 struct xfs_attr_leaf_entry *entry;
1550 int count;
1551 int max;
1552 int index;
1553 int totallen = 0;
1554 int half;
1555 int lastdelta;
1556 int foundit = 0;
1557 int tmp;
2bd0ea18
NS
1558
1559 /*
1560 * Examine entries until we reduce the absolute difference in
1561 * byte usage between the two blocks to a minimum.
1562 */
a24374f4
DC
1563 max = ichdr1->count + ichdr2->count;
1564 half = (max + 1) * sizeof(*entry);
1565 half += ichdr1->usedbytes + ichdr2->usedbytes +
1566 xfs_attr_leaf_newentsize(state->args->namelen,
1567 state->args->valuelen,
1568 state->blocksize, NULL);
2bd0ea18
NS
1569 half /= 2;
1570 lastdelta = state->blocksize;
a24374f4 1571 entry = xfs_attr3_leaf_entryp(leaf1);
2bd0ea18
NS
1572 for (count = index = 0; count < max; entry++, index++, count++) {
1573
dfc130f3 1574#define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A))
2bd0ea18
NS
1575 /*
1576 * The new entry is in the first block, account for it.
1577 */
1578 if (count == blk1->index) {
1579 tmp = totallen + sizeof(*entry) +
ca86e759
NS
1580 xfs_attr_leaf_newentsize(
1581 state->args->namelen,
1582 state->args->valuelen,
1583 state->blocksize, NULL);
2bd0ea18
NS
1584 if (XFS_ATTR_ABS(half - tmp) > lastdelta)
1585 break;
1586 lastdelta = XFS_ATTR_ABS(half - tmp);
1587 totallen = tmp;
1588 foundit = 1;
1589 }
1590
1591 /*
1592 * Wrap around into the second block if necessary.
1593 */
a24374f4 1594 if (count == ichdr1->count) {
2bd0ea18 1595 leaf1 = leaf2;
a24374f4 1596 entry = xfs_attr3_leaf_entryp(leaf1);
2bd0ea18
NS
1597 index = 0;
1598 }
1599
1600 /*
1601 * Figure out if next leaf entry would be too much.
1602 */
1603 tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1,
1604 index);
1605 if (XFS_ATTR_ABS(half - tmp) > lastdelta)
1606 break;
1607 lastdelta = XFS_ATTR_ABS(half - tmp);
1608 totallen = tmp;
1609#undef XFS_ATTR_ABS
1610 }
1611
1612 /*
1613 * Calculate the number of usedbytes that will end up in lower block.
1614 * If new entry not in lower block, fix up the count.
1615 */
1616 totallen -= count * sizeof(*entry);
1617 if (foundit) {
5000d01d 1618 totallen -= sizeof(*entry) +
ca86e759
NS
1619 xfs_attr_leaf_newentsize(
1620 state->args->namelen,
1621 state->args->valuelen,
1622 state->blocksize, NULL);
2bd0ea18
NS
1623 }
1624
1625 *countarg = count;
1626 *usedbytesarg = totallen;
a24374f4 1627 return foundit;
2bd0ea18
NS
1628}
1629
1630/*========================================================================
1631 * Routines used for shrinking the Btree.
1632 *========================================================================*/
1633
1634/*
1635 * Check a leaf block and its neighbors to see if the block should be
1636 * collapsed into one or the other neighbor. Always keep the block
1637 * with the smaller block number.
1638 * If the current block is over 50% full, don't try to join it, return 0.
1639 * If the block is empty, fill in the state structure and return 2.
1640 * If it can be collapsed, fill in the state structure and return 1.
1641 * If nothing can be done, return 0.
1642 *
1643 * GROT: allow for INCOMPLETE entries in calculation.
1644 */
1645int
a24374f4
DC
1646xfs_attr3_leaf_toosmall(
1647 struct xfs_da_state *state,
1648 int *action)
2bd0ea18 1649{
a24374f4
DC
1650 struct xfs_attr_leafblock *leaf;
1651 struct xfs_da_state_blk *blk;
1652 struct xfs_attr3_icleaf_hdr ichdr;
1653 struct xfs_buf *bp;
1654 xfs_dablk_t blkno;
1655 int bytes;
1656 int forward;
1657 int error;
1658 int retval;
1659 int i;
a2ceac1f
DC
1660
1661 trace_xfs_attr_leaf_toosmall(state->args);
2bd0ea18
NS
1662
1663 /*
1664 * Check for the degenerate case of the block being over 50% full.
1665 * If so, it's not worth even looking to see if we might be able
1666 * to coalesce with a sibling.
1667 */
1668 blk = &state->path.blk[ state->path.active-1 ];
a24374f4
DC
1669 leaf = blk->bp->b_addr;
1670 xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
1671 bytes = xfs_attr3_leaf_hdr_size(leaf) +
1672 ichdr.count * sizeof(xfs_attr_leaf_entry_t) +
1673 ichdr.usedbytes;
2bd0ea18 1674 if (bytes > (state->blocksize >> 1)) {
4ca431fc 1675 *action = 0; /* blk over 50%, don't try to join */
2bd0ea18
NS
1676 return(0);
1677 }
1678
1679 /*
1680 * Check for the degenerate case of the block being empty.
1681 * If the block is empty, we'll simply delete it, no need to
5e656dbb 1682 * coalesce it with a sibling block. We choose (arbitrarily)
2bd0ea18
NS
1683 * to merge with the forward block unless it is NULL.
1684 */
a24374f4 1685 if (ichdr.count == 0) {
2bd0ea18
NS
1686 /*
1687 * Make altpath point to the block we want to keep and
1688 * path point to the block we want to drop (this one).
1689 */
a24374f4 1690 forward = (ichdr.forw != 0);
32181a02 1691 memcpy(&state->altpath, &state->path, sizeof(state->path));
88b32f06 1692 error = xfs_da3_path_shift(state, &state->altpath, forward,
2bd0ea18
NS
1693 0, &retval);
1694 if (error)
1695 return(error);
1696 if (retval) {
1697 *action = 0;
1698 } else {
1699 *action = 2;
1700 }
a24374f4 1701 return 0;
2bd0ea18
NS
1702 }
1703
1704 /*
1705 * Examine each sibling block to see if we can coalesce with
1706 * at least 25% free space to spare. We need to figure out
1707 * whether to merge with the forward or the backward block.
1708 * We prefer coalescing with the lower numbered sibling so as
1709 * to shrink an attribute list over time.
1710 */
1711 /* start with smaller blk num */
a24374f4 1712 forward = ichdr.forw < ichdr.back;
2bd0ea18 1713 for (i = 0; i < 2; forward = !forward, i++) {
a24374f4 1714 struct xfs_attr3_icleaf_hdr ichdr2;
2bd0ea18 1715 if (forward)
a24374f4 1716 blkno = ichdr.forw;
2bd0ea18 1717 else
a24374f4 1718 blkno = ichdr.back;
2bd0ea18
NS
1719 if (blkno == 0)
1720 continue;
a24374f4 1721 error = xfs_attr3_leaf_read(state->args->trans, state->args->dp,
a2ceac1f 1722 blkno, -1, &bp);
2bd0ea18
NS
1723 if (error)
1724 return(error);
2bd0ea18 1725
a24374f4
DC
1726 xfs_attr3_leaf_hdr_from_disk(&ichdr2, bp->b_addr);
1727
1728 bytes = state->blocksize - (state->blocksize >> 2) -
1729 ichdr.usedbytes - ichdr2.usedbytes -
1730 ((ichdr.count + ichdr2.count) *
1731 sizeof(xfs_attr_leaf_entry_t)) -
1732 xfs_attr3_leaf_hdr_size(leaf);
1733
a2ceac1f 1734 xfs_trans_brelse(state->args->trans, bp);
2bd0ea18
NS
1735 if (bytes >= 0)
1736 break; /* fits with at least 25% to spare */
1737 }
1738 if (i >= 2) {
1739 *action = 0;
1740 return(0);
1741 }
1742
1743 /*
1744 * Make altpath point to the block we want to keep (the lower
1745 * numbered block) and path point to the block we want to drop.
1746 */
32181a02 1747 memcpy(&state->altpath, &state->path, sizeof(state->path));
2bd0ea18 1748 if (blkno < blk->blkno) {
88b32f06 1749 error = xfs_da3_path_shift(state, &state->altpath, forward,
2bd0ea18
NS
1750 0, &retval);
1751 } else {
88b32f06 1752 error = xfs_da3_path_shift(state, &state->path, forward,
2bd0ea18
NS
1753 0, &retval);
1754 }
1755 if (error)
1756 return(error);
1757 if (retval) {
1758 *action = 0;
1759 } else {
1760 *action = 1;
1761 }
1762 return(0);
1763}
1764
57c9fccb
NS
1765/*
1766 * Remove a name from the leaf attribute list structure.
1767 *
1768 * Return 1 if leaf is less than 37% full, 0 if >= 37% full.
1769 * If two leaves are 37% full, when combined they will leave 25% free.
1770 */
1771int
a24374f4
DC
1772xfs_attr3_leaf_remove(
1773 struct xfs_buf *bp,
1774 struct xfs_da_args *args)
57c9fccb 1775{
a24374f4
DC
1776 struct xfs_attr_leafblock *leaf;
1777 struct xfs_attr3_icleaf_hdr ichdr;
1778 struct xfs_attr_leaf_entry *entry;
1779 struct xfs_mount *mp = args->trans->t_mountp;
1780 int before;
1781 int after;
1782 int smallest;
1783 int entsize;
1784 int tablesize;
1785 int tmp;
1786 int i;
57c9fccb 1787
a2ceac1f
DC
1788 trace_xfs_attr_leaf_remove(args);
1789
1790 leaf = bp->b_addr;
a24374f4
DC
1791 xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
1792
1793 ASSERT(ichdr.count > 0 && ichdr.count < XFS_LBSIZE(mp) / 8);
1794 ASSERT(args->index >= 0 && args->index < ichdr.count);
1795 ASSERT(ichdr.firstused >= ichdr.count * sizeof(*entry) +
1796 xfs_attr3_leaf_hdr_size(leaf));
1797
1798 entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
1799
1800 ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused);
5e656dbb 1801 ASSERT(be16_to_cpu(entry->nameidx) < XFS_LBSIZE(mp));
57c9fccb
NS
1802
1803 /*
1804 * Scan through free region table:
1805 * check for adjacency of free'd entry with an existing one,
1806 * find smallest free region in case we need to replace it,
1807 * adjust any map that borders the entry table,
1808 */
a24374f4
DC
1809 tablesize = ichdr.count * sizeof(xfs_attr_leaf_entry_t)
1810 + xfs_attr3_leaf_hdr_size(leaf);
1811 tmp = ichdr.freemap[0].size;
57c9fccb
NS
1812 before = after = -1;
1813 smallest = XFS_ATTR_LEAF_MAPSIZE - 1;
1814 entsize = xfs_attr_leaf_entsize(leaf, args->index);
a24374f4
DC
1815 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; i++) {
1816 ASSERT(ichdr.freemap[i].base < XFS_LBSIZE(mp));
1817 ASSERT(ichdr.freemap[i].size < XFS_LBSIZE(mp));
1818 if (ichdr.freemap[i].base == tablesize) {
1819 ichdr.freemap[i].base -= sizeof(xfs_attr_leaf_entry_t);
1820 ichdr.freemap[i].size += sizeof(xfs_attr_leaf_entry_t);
57c9fccb
NS
1821 }
1822
a24374f4
DC
1823 if (ichdr.freemap[i].base + ichdr.freemap[i].size ==
1824 be16_to_cpu(entry->nameidx)) {
57c9fccb 1825 before = i;
a24374f4
DC
1826 } else if (ichdr.freemap[i].base ==
1827 (be16_to_cpu(entry->nameidx) + entsize)) {
57c9fccb 1828 after = i;
a24374f4
DC
1829 } else if (ichdr.freemap[i].size < tmp) {
1830 tmp = ichdr.freemap[i].size;
57c9fccb
NS
1831 smallest = i;
1832 }
1833 }
1834
1835 /*
1836 * Coalesce adjacent freemap regions,
1837 * or replace the smallest region.
1838 */
1839 if ((before >= 0) || (after >= 0)) {
1840 if ((before >= 0) && (after >= 0)) {
a24374f4
DC
1841 ichdr.freemap[before].size += entsize;
1842 ichdr.freemap[before].size += ichdr.freemap[after].size;
1843 ichdr.freemap[after].base = 0;
1844 ichdr.freemap[after].size = 0;
57c9fccb 1845 } else if (before >= 0) {
a24374f4 1846 ichdr.freemap[before].size += entsize;
57c9fccb 1847 } else {
a24374f4
DC
1848 ichdr.freemap[after].base = be16_to_cpu(entry->nameidx);
1849 ichdr.freemap[after].size += entsize;
57c9fccb
NS
1850 }
1851 } else {
1852 /*
1853 * Replace smallest region (if it is smaller than free'd entry)
1854 */
a24374f4
DC
1855 if (ichdr.freemap[smallest].size < entsize) {
1856 ichdr.freemap[smallest].base = be16_to_cpu(entry->nameidx);
1857 ichdr.freemap[smallest].size = entsize;
57c9fccb
NS
1858 }
1859 }
1860
1861 /*
1862 * Did we remove the first entry?
1863 */
a24374f4 1864 if (be16_to_cpu(entry->nameidx) == ichdr.firstused)
57c9fccb
NS
1865 smallest = 1;
1866 else
1867 smallest = 0;
1868
1869 /*
1870 * Compress the remaining entries and zero out the removed stuff.
1871 */
a24374f4
DC
1872 memset(xfs_attr3_leaf_name(leaf, args->index), 0, entsize);
1873 ichdr.usedbytes -= entsize;
a2ceac1f 1874 xfs_trans_log_buf(args->trans, bp,
a24374f4 1875 XFS_DA_LOGRANGE(leaf, xfs_attr3_leaf_name(leaf, args->index),
57c9fccb
NS
1876 entsize));
1877
a24374f4
DC
1878 tmp = (ichdr.count - args->index) * sizeof(xfs_attr_leaf_entry_t);
1879 memmove(entry, entry + 1, tmp);
1880 ichdr.count--;
a2ceac1f 1881 xfs_trans_log_buf(args->trans, bp,
a24374f4
DC
1882 XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(xfs_attr_leaf_entry_t)));
1883
1884 entry = &xfs_attr3_leaf_entryp(leaf)[ichdr.count];
1885 memset(entry, 0, sizeof(xfs_attr_leaf_entry_t));
57c9fccb
NS
1886
1887 /*
1888 * If we removed the first entry, re-find the first used byte
1889 * in the name area. Note that if the entry was the "firstused",
1890 * then we don't have a "hole" in our block resulting from
1891 * removing the name.
1892 */
1893 if (smallest) {
1894 tmp = XFS_LBSIZE(mp);
a24374f4
DC
1895 entry = xfs_attr3_leaf_entryp(leaf);
1896 for (i = ichdr.count - 1; i >= 0; entry++, i--) {
1897 ASSERT(be16_to_cpu(entry->nameidx) >= ichdr.firstused);
5e656dbb
BN
1898 ASSERT(be16_to_cpu(entry->nameidx) < XFS_LBSIZE(mp));
1899
1900 if (be16_to_cpu(entry->nameidx) < tmp)
1901 tmp = be16_to_cpu(entry->nameidx);
57c9fccb 1902 }
a24374f4
DC
1903 ichdr.firstused = tmp;
1904 if (!ichdr.firstused)
1905 ichdr.firstused = tmp - XFS_ATTR_LEAF_NAME_ALIGN;
57c9fccb 1906 } else {
a24374f4 1907 ichdr.holes = 1; /* mark as needing compaction */
57c9fccb 1908 }
a24374f4 1909 xfs_attr3_leaf_hdr_to_disk(leaf, &ichdr);
a2ceac1f 1910 xfs_trans_log_buf(args->trans, bp,
a24374f4
DC
1911 XFS_DA_LOGRANGE(leaf, &leaf->hdr,
1912 xfs_attr3_leaf_hdr_size(leaf)));
57c9fccb
NS
1913
1914 /*
1915 * Check if leaf is less than 50% full, caller may want to
1916 * "join" the leaf with a sibling if so.
1917 */
a24374f4
DC
1918 tmp = ichdr.usedbytes + xfs_attr3_leaf_hdr_size(leaf) +
1919 ichdr.count * sizeof(xfs_attr_leaf_entry_t);
1920
1921 return tmp < mp->m_attr_magicpct; /* leaf is < 37% full */
57c9fccb
NS
1922}
1923
2bd0ea18
NS
1924/*
1925 * Move all the attribute list entries from drop_leaf into save_leaf.
1926 */
1927void
a24374f4
DC
1928xfs_attr3_leaf_unbalance(
1929 struct xfs_da_state *state,
1930 struct xfs_da_state_blk *drop_blk,
1931 struct xfs_da_state_blk *save_blk)
2bd0ea18 1932{
a24374f4
DC
1933 struct xfs_attr_leafblock *drop_leaf = drop_blk->bp->b_addr;
1934 struct xfs_attr_leafblock *save_leaf = save_blk->bp->b_addr;
1935 struct xfs_attr3_icleaf_hdr drophdr;
1936 struct xfs_attr3_icleaf_hdr savehdr;
1937 struct xfs_attr_leaf_entry *entry;
1938 struct xfs_mount *mp = state->mp;
2bd0ea18 1939
a2ceac1f
DC
1940 trace_xfs_attr_leaf_unbalance(state->args);
1941
a2ceac1f
DC
1942 drop_leaf = drop_blk->bp->b_addr;
1943 save_leaf = save_blk->bp->b_addr;
a24374f4
DC
1944 xfs_attr3_leaf_hdr_from_disk(&drophdr, drop_leaf);
1945 xfs_attr3_leaf_hdr_from_disk(&savehdr, save_leaf);
1946 entry = xfs_attr3_leaf_entryp(drop_leaf);
2bd0ea18
NS
1947
1948 /*
1949 * Save last hashval from dying block for later Btree fixup.
1950 */
a24374f4 1951 drop_blk->hashval = be32_to_cpu(entry[drophdr.count - 1].hashval);
2bd0ea18
NS
1952
1953 /*
1954 * Check if we need a temp buffer, or can we do it in place.
1955 * Note that we don't check "leaf" for holes because we will
1956 * always be dropping it, toosmall() decided that for us already.
1957 */
a24374f4 1958 if (savehdr.holes == 0) {
2bd0ea18
NS
1959 /*
1960 * dest leaf has no holes, so we add there. May need
1961 * to make some room in the entry array.
1962 */
a24374f4
DC
1963 if (xfs_attr3_leaf_order(save_blk->bp, &savehdr,
1964 drop_blk->bp, &drophdr)) {
1965 xfs_attr3_leaf_moveents(drop_leaf, &drophdr, 0,
1966 save_leaf, &savehdr, 0,
1967 drophdr.count, mp);
2bd0ea18 1968 } else {
a24374f4
DC
1969 xfs_attr3_leaf_moveents(drop_leaf, &drophdr, 0,
1970 save_leaf, &savehdr,
1971 savehdr.count, drophdr.count, mp);
2bd0ea18
NS
1972 }
1973 } else {
1974 /*
1975 * Destination has holes, so we make a temporary copy
1976 * of the leaf and add them both to that.
1977 */
a24374f4
DC
1978 struct xfs_attr_leafblock *tmp_leaf;
1979 struct xfs_attr3_icleaf_hdr tmphdr;
1980
fa74cedd
DC
1981 tmp_leaf = kmem_zalloc(state->blocksize, KM_SLEEP);
1982
1983 /*
1984 * Copy the header into the temp leaf so that all the stuff
1985 * not in the incore header is present and gets copied back in
1986 * once we've moved all the entries.
1987 */
1988 memcpy(tmp_leaf, save_leaf, xfs_attr3_leaf_hdr_size(save_leaf));
a24374f4 1989
fa74cedd 1990 memset(&tmphdr, 0, sizeof(tmphdr));
a24374f4
DC
1991 tmphdr.magic = savehdr.magic;
1992 tmphdr.forw = savehdr.forw;
1993 tmphdr.back = savehdr.back;
1994 tmphdr.firstused = state->blocksize;
fa74cedd
DC
1995
1996 /* write the header to the temp buffer to initialise it */
1997 xfs_attr3_leaf_hdr_to_disk(tmp_leaf, &tmphdr);
1998
a24374f4
DC
1999 if (xfs_attr3_leaf_order(save_blk->bp, &savehdr,
2000 drop_blk->bp, &drophdr)) {
2001 xfs_attr3_leaf_moveents(drop_leaf, &drophdr, 0,
2002 tmp_leaf, &tmphdr, 0,
2003 drophdr.count, mp);
2004 xfs_attr3_leaf_moveents(save_leaf, &savehdr, 0,
2005 tmp_leaf, &tmphdr, tmphdr.count,
2006 savehdr.count, mp);
2bd0ea18 2007 } else {
a24374f4
DC
2008 xfs_attr3_leaf_moveents(save_leaf, &savehdr, 0,
2009 tmp_leaf, &tmphdr, 0,
2010 savehdr.count, mp);
2011 xfs_attr3_leaf_moveents(drop_leaf, &drophdr, 0,
2012 tmp_leaf, &tmphdr, tmphdr.count,
2013 drophdr.count, mp);
2bd0ea18 2014 }
a24374f4
DC
2015 memcpy(save_leaf, tmp_leaf, state->blocksize);
2016 savehdr = tmphdr; /* struct copy */
2017 kmem_free(tmp_leaf);
2bd0ea18
NS
2018 }
2019
a24374f4 2020 xfs_attr3_leaf_hdr_to_disk(save_leaf, &savehdr);
a2ceac1f 2021 xfs_trans_log_buf(state->args->trans, save_blk->bp, 0,
2bd0ea18
NS
2022 state->blocksize - 1);
2023
2024 /*
2025 * Copy out last hashval in each block for B-tree code.
2026 */
a24374f4
DC
2027 entry = xfs_attr3_leaf_entryp(save_leaf);
2028 save_blk->hashval = be32_to_cpu(entry[savehdr.count - 1].hashval);
2bd0ea18
NS
2029}
2030
57c9fccb
NS
2031/*========================================================================
2032 * Routines used for finding things in the Btree.
2033 *========================================================================*/
2034
2035/*
2036 * Look up a name in a leaf attribute list structure.
2037 * This is the internal routine, it uses the caller's buffer.
2038 *
2039 * Note that duplicate keys are allowed, but only check within the
2040 * current leaf node. The Btree code must check in adjacent leaf nodes.
2041 *
2042 * Return in args->index the index into the entry[] array of either
2043 * the found entry, or where the entry should have been (insert before
2044 * that entry).
2045 *
2046 * Don't change the args->value unless we find the attribute.
2047 */
2048int
a24374f4
DC
2049xfs_attr3_leaf_lookup_int(
2050 struct xfs_buf *bp,
2051 struct xfs_da_args *args)
57c9fccb 2052{
a24374f4
DC
2053 struct xfs_attr_leafblock *leaf;
2054 struct xfs_attr3_icleaf_hdr ichdr;
2055 struct xfs_attr_leaf_entry *entry;
2056 struct xfs_attr_leaf_entry *entries;
2057 struct xfs_attr_leaf_name_local *name_loc;
2058 struct xfs_attr_leaf_name_remote *name_rmt;
2059 xfs_dahash_t hashval;
2060 int probe;
2061 int span;
57c9fccb 2062
a2ceac1f
DC
2063 trace_xfs_attr_leaf_lookup(args);
2064
2065 leaf = bp->b_addr;
a24374f4
DC
2066 xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
2067 entries = xfs_attr3_leaf_entryp(leaf);
2068 ASSERT(ichdr.count < XFS_LBSIZE(args->dp->i_mount) / 8);
57c9fccb
NS
2069
2070 /*
2071 * Binary search. (note: small blocks will skip this loop)
2072 */
2073 hashval = args->hashval;
a24374f4
DC
2074 probe = span = ichdr.count / 2;
2075 for (entry = &entries[probe]; span > 4; entry = &entries[probe]) {
57c9fccb 2076 span /= 2;
5e656dbb 2077 if (be32_to_cpu(entry->hashval) < hashval)
57c9fccb 2078 probe += span;
5e656dbb 2079 else if (be32_to_cpu(entry->hashval) > hashval)
57c9fccb
NS
2080 probe -= span;
2081 else
2082 break;
2083 }
a24374f4
DC
2084 ASSERT(probe >= 0 && (!ichdr.count || probe < ichdr.count));
2085 ASSERT(span <= 4 || be32_to_cpu(entry->hashval) == hashval);
57c9fccb
NS
2086
2087 /*
2088 * Since we may have duplicate hashval's, find the first matching
2089 * hashval in the leaf.
2090 */
a24374f4 2091 while (probe > 0 && be32_to_cpu(entry->hashval) >= hashval) {
57c9fccb
NS
2092 entry--;
2093 probe--;
2094 }
a24374f4
DC
2095 while (probe < ichdr.count &&
2096 be32_to_cpu(entry->hashval) < hashval) {
57c9fccb
NS
2097 entry++;
2098 probe++;
2099 }
a24374f4 2100 if (probe == ichdr.count || be32_to_cpu(entry->hashval) != hashval) {
57c9fccb 2101 args->index = probe;
a24374f4 2102 return XFS_ERROR(ENOATTR);
57c9fccb
NS
2103 }
2104
2105 /*
2106 * Duplicate keys may be present, so search all of them for a match.
2107 */
a24374f4 2108 for (; probe < ichdr.count && (be32_to_cpu(entry->hashval) == hashval);
57c9fccb
NS
2109 entry++, probe++) {
2110/*
2111 * GROT: Add code to remove incomplete entries.
2112 */
2113 /*
2114 * If we are looking for INCOMPLETE entries, show only those.
2115 * If we are looking for complete entries, show only those.
2116 */
2117 if ((args->flags & XFS_ATTR_INCOMPLETE) !=
2118 (entry->flags & XFS_ATTR_INCOMPLETE)) {
2119 continue;
2120 }
2121 if (entry->flags & XFS_ATTR_LOCAL) {
a24374f4 2122 name_loc = xfs_attr3_leaf_name_local(leaf, probe);
57c9fccb
NS
2123 if (name_loc->namelen != args->namelen)
2124 continue;
a24374f4
DC
2125 if (memcmp(args->name, name_loc->nameval,
2126 args->namelen) != 0)
57c9fccb 2127 continue;
5e656dbb 2128 if (!xfs_attr_namesp_match(args->flags, entry->flags))
57c9fccb
NS
2129 continue;
2130 args->index = probe;
a24374f4 2131 return XFS_ERROR(EEXIST);
57c9fccb 2132 } else {
a24374f4 2133 name_rmt = xfs_attr3_leaf_name_remote(leaf, probe);
57c9fccb
NS
2134 if (name_rmt->namelen != args->namelen)
2135 continue;
a24374f4
DC
2136 if (memcmp(args->name, name_rmt->name,
2137 args->namelen) != 0)
57c9fccb 2138 continue;
5e656dbb 2139 if (!xfs_attr_namesp_match(args->flags, entry->flags))
57c9fccb
NS
2140 continue;
2141 args->index = probe;
bdf62025 2142 args->valuelen = be32_to_cpu(name_rmt->valuelen);
5e656dbb 2143 args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
f08bc2a9
DC
2144 args->rmtblkcnt = xfs_attr3_rmt_blocks(
2145 args->dp->i_mount,
2146 args->valuelen);
a24374f4 2147 return XFS_ERROR(EEXIST);
57c9fccb
NS
2148 }
2149 }
2150 args->index = probe;
a24374f4 2151 return XFS_ERROR(ENOATTR);
57c9fccb
NS
2152}
2153
5e656dbb
BN
2154/*
2155 * Get the value associated with an attribute name from a leaf attribute
2156 * list structure.
2157 */
2158int
a24374f4
DC
2159xfs_attr3_leaf_getvalue(
2160 struct xfs_buf *bp,
2161 struct xfs_da_args *args)
5e656dbb 2162{
a24374f4
DC
2163 struct xfs_attr_leafblock *leaf;
2164 struct xfs_attr3_icleaf_hdr ichdr;
2165 struct xfs_attr_leaf_entry *entry;
2166 struct xfs_attr_leaf_name_local *name_loc;
2167 struct xfs_attr_leaf_name_remote *name_rmt;
2168 int valuelen;
5e656dbb 2169
a2ceac1f 2170 leaf = bp->b_addr;
a24374f4
DC
2171 xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
2172 ASSERT(ichdr.count < XFS_LBSIZE(args->dp->i_mount) / 8);
2173 ASSERT(args->index < ichdr.count);
5e656dbb 2174
a24374f4 2175 entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
5e656dbb 2176 if (entry->flags & XFS_ATTR_LOCAL) {
a24374f4 2177 name_loc = xfs_attr3_leaf_name_local(leaf, args->index);
5e656dbb
BN
2178 ASSERT(name_loc->namelen == args->namelen);
2179 ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0);
2180 valuelen = be16_to_cpu(name_loc->valuelen);
2181 if (args->flags & ATTR_KERNOVAL) {
2182 args->valuelen = valuelen;
a24374f4 2183 return 0;
5e656dbb
BN
2184 }
2185 if (args->valuelen < valuelen) {
2186 args->valuelen = valuelen;
a24374f4 2187 return XFS_ERROR(ERANGE);
5e656dbb
BN
2188 }
2189 args->valuelen = valuelen;
2190 memcpy(args->value, &name_loc->nameval[args->namelen], valuelen);
2191 } else {
a24374f4 2192 name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
5e656dbb
BN
2193 ASSERT(name_rmt->namelen == args->namelen);
2194 ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0);
2195 valuelen = be32_to_cpu(name_rmt->valuelen);
2196 args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
f08bc2a9
DC
2197 args->rmtblkcnt = xfs_attr3_rmt_blocks(args->dp->i_mount,
2198 valuelen);
5e656dbb
BN
2199 if (args->flags & ATTR_KERNOVAL) {
2200 args->valuelen = valuelen;
a24374f4 2201 return 0;
5e656dbb
BN
2202 }
2203 if (args->valuelen < valuelen) {
2204 args->valuelen = valuelen;
a24374f4 2205 return XFS_ERROR(ERANGE);
5e656dbb
BN
2206 }
2207 args->valuelen = valuelen;
2208 }
a24374f4 2209 return 0;
5e656dbb 2210}
2bd0ea18
NS
2211
2212/*========================================================================
2213 * Utility routines.
2214 *========================================================================*/
2215
2216/*
2217 * Move the indicated entries from one leaf to another.
2218 * NOTE: this routine modifies both source and destination leaves.
2219 */
2220/*ARGSUSED*/
2221STATIC void
a24374f4
DC
2222xfs_attr3_leaf_moveents(
2223 struct xfs_attr_leafblock *leaf_s,
2224 struct xfs_attr3_icleaf_hdr *ichdr_s,
2225 int start_s,
2226 struct xfs_attr_leafblock *leaf_d,
2227 struct xfs_attr3_icleaf_hdr *ichdr_d,
2228 int start_d,
2229 int count,
2230 struct xfs_mount *mp)
2bd0ea18 2231{
a24374f4
DC
2232 struct xfs_attr_leaf_entry *entry_s;
2233 struct xfs_attr_leaf_entry *entry_d;
2234 int desti;
2235 int tmp;
2236 int i;
2bd0ea18
NS
2237
2238 /*
2239 * Check for nothing to do.
2240 */
2241 if (count == 0)
2242 return;
2243
2244 /*
2245 * Set up environment.
2246 */
a24374f4
DC
2247 ASSERT(ichdr_s->magic == XFS_ATTR_LEAF_MAGIC ||
2248 ichdr_s->magic == XFS_ATTR3_LEAF_MAGIC);
2249 ASSERT(ichdr_s->magic == ichdr_d->magic);
2250 ASSERT(ichdr_s->count > 0 && ichdr_s->count < XFS_LBSIZE(mp) / 8);
2251 ASSERT(ichdr_s->firstused >= (ichdr_s->count * sizeof(*entry_s))
2252 + xfs_attr3_leaf_hdr_size(leaf_s));
2253 ASSERT(ichdr_d->count < XFS_LBSIZE(mp) / 8);
2254 ASSERT(ichdr_d->firstused >= (ichdr_d->count * sizeof(*entry_d))
2255 + xfs_attr3_leaf_hdr_size(leaf_d));
2256
2257 ASSERT(start_s < ichdr_s->count);
2258 ASSERT(start_d <= ichdr_d->count);
2259 ASSERT(count <= ichdr_s->count);
2260
2bd0ea18
NS
2261
2262 /*
2263 * Move the entries in the destination leaf up to make a hole?
2264 */
a24374f4
DC
2265 if (start_d < ichdr_d->count) {
2266 tmp = ichdr_d->count - start_d;
2bd0ea18 2267 tmp *= sizeof(xfs_attr_leaf_entry_t);
a24374f4
DC
2268 entry_s = &xfs_attr3_leaf_entryp(leaf_d)[start_d];
2269 entry_d = &xfs_attr3_leaf_entryp(leaf_d)[start_d + count];
2270 memmove(entry_d, entry_s, tmp);
2bd0ea18
NS
2271 }
2272
2273 /*
2274 * Copy all entry's in the same (sorted) order,
2275 * but allocate attribute info packed and in sequence.
2276 */
a24374f4
DC
2277 entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s];
2278 entry_d = &xfs_attr3_leaf_entryp(leaf_d)[start_d];
2bd0ea18
NS
2279 desti = start_d;
2280 for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) {
a24374f4 2281 ASSERT(be16_to_cpu(entry_s->nameidx) >= ichdr_s->firstused);
2bd0ea18
NS
2282 tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i);
2283#ifdef GROT
2284 /*
2285 * Code to drop INCOMPLETE entries. Difficult to use as we
dfc130f3 2286 * may also need to change the insertion index. Code turned
2bd0ea18
NS
2287 * off for 6.2, should be revisited later.
2288 */
2289 if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */
a24374f4
DC
2290 memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp);
2291 ichdr_s->usedbytes -= tmp;
2292 ichdr_s->count -= 1;
2bd0ea18
NS
2293 entry_d--; /* to compensate for ++ in loop hdr */
2294 desti--;
2295 if ((start_s + i) < offset)
2296 result++; /* insertion index adjustment */
2297 } else {
2298#endif /* GROT */
a24374f4 2299 ichdr_d->firstused -= tmp;
5ce1d1f7
NS
2300 /* both on-disk, don't endian flip twice */
2301 entry_d->hashval = entry_s->hashval;
a24374f4 2302 entry_d->nameidx = cpu_to_be16(ichdr_d->firstused);
2bd0ea18 2303 entry_d->flags = entry_s->flags;
5e656dbb 2304 ASSERT(be16_to_cpu(entry_d->nameidx) + tmp
2bd0ea18 2305 <= XFS_LBSIZE(mp));
a24374f4
DC
2306 memmove(xfs_attr3_leaf_name(leaf_d, desti),
2307 xfs_attr3_leaf_name(leaf_s, start_s + i), tmp);
5e656dbb 2308 ASSERT(be16_to_cpu(entry_s->nameidx) + tmp
2bd0ea18 2309 <= XFS_LBSIZE(mp));
a24374f4
DC
2310 memset(xfs_attr3_leaf_name(leaf_s, start_s + i), 0, tmp);
2311 ichdr_s->usedbytes -= tmp;
2312 ichdr_d->usedbytes += tmp;
2313 ichdr_s->count -= 1;
2314 ichdr_d->count += 1;
2315 tmp = ichdr_d->count * sizeof(xfs_attr_leaf_entry_t)
2316 + xfs_attr3_leaf_hdr_size(leaf_d);
2317 ASSERT(ichdr_d->firstused >= tmp);
2bd0ea18
NS
2318#ifdef GROT
2319 }
2320#endif /* GROT */
2321 }
2322
2323 /*
2324 * Zero out the entries we just copied.
2325 */
a24374f4 2326 if (start_s == ichdr_s->count) {
2bd0ea18 2327 tmp = count * sizeof(xfs_attr_leaf_entry_t);
a24374f4 2328 entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s];
2bd0ea18
NS
2329 ASSERT(((char *)entry_s + tmp) <=
2330 ((char *)leaf_s + XFS_LBSIZE(mp)));
a24374f4 2331 memset(entry_s, 0, tmp);
2bd0ea18
NS
2332 } else {
2333 /*
2334 * Move the remaining entries down to fill the hole,
2335 * then zero the entries at the top.
2336 */
78d6585c 2337 tmp = (ichdr_s->count - count) * sizeof(xfs_attr_leaf_entry_t);
a24374f4
DC
2338 entry_s = &xfs_attr3_leaf_entryp(leaf_s)[start_s + count];
2339 entry_d = &xfs_attr3_leaf_entryp(leaf_s)[start_s];
2340 memmove(entry_d, entry_s, tmp);
2bd0ea18
NS
2341
2342 tmp = count * sizeof(xfs_attr_leaf_entry_t);
a24374f4 2343 entry_s = &xfs_attr3_leaf_entryp(leaf_s)[ichdr_s->count];
2bd0ea18
NS
2344 ASSERT(((char *)entry_s + tmp) <=
2345 ((char *)leaf_s + XFS_LBSIZE(mp)));
a24374f4 2346 memset(entry_s, 0, tmp);
2bd0ea18
NS
2347 }
2348
2349 /*
2350 * Fill in the freemap information
2351 */
a24374f4
DC
2352 ichdr_d->freemap[0].base = xfs_attr3_leaf_hdr_size(leaf_d);
2353 ichdr_d->freemap[0].base += ichdr_d->count * sizeof(xfs_attr_leaf_entry_t);
2354 ichdr_d->freemap[0].size = ichdr_d->firstused - ichdr_d->freemap[0].base;
2355 ichdr_d->freemap[1].base = 0;
2356 ichdr_d->freemap[2].base = 0;
2357 ichdr_d->freemap[1].size = 0;
2358 ichdr_d->freemap[2].size = 0;
2359 ichdr_s->holes = 1; /* leaf may not be compact */
2bd0ea18
NS
2360}
2361
2362/*
2363 * Pick up the last hashvalue from a leaf block.
2364 */
2365xfs_dahash_t
a2ceac1f
DC
2366xfs_attr_leaf_lasthash(
2367 struct xfs_buf *bp,
2368 int *count)
2bd0ea18 2369{
a24374f4
DC
2370 struct xfs_attr3_icleaf_hdr ichdr;
2371 struct xfs_attr_leaf_entry *entries;
2bd0ea18 2372
a24374f4
DC
2373 xfs_attr3_leaf_hdr_from_disk(&ichdr, bp->b_addr);
2374 entries = xfs_attr3_leaf_entryp(bp->b_addr);
2bd0ea18 2375 if (count)
a24374f4
DC
2376 *count = ichdr.count;
2377 if (!ichdr.count)
2378 return 0;
2379 return be32_to_cpu(entries[ichdr.count - 1].hashval);
2bd0ea18
NS
2380}
2381
2382/*
2383 * Calculate the number of bytes used to store the indicated attribute
2384 * (whether local or remote only calculate bytes in this block).
2385 */
5e656dbb 2386STATIC int
2bd0ea18
NS
2387xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index)
2388{
a24374f4 2389 struct xfs_attr_leaf_entry *entries;
2bd0ea18
NS
2390 xfs_attr_leaf_name_local_t *name_loc;
2391 xfs_attr_leaf_name_remote_t *name_rmt;
2392 int size;
2393
a24374f4
DC
2394 entries = xfs_attr3_leaf_entryp(leaf);
2395 if (entries[index].flags & XFS_ATTR_LOCAL) {
2396 name_loc = xfs_attr3_leaf_name_local(leaf, index);
56b2de80 2397 size = xfs_attr_leaf_entsize_local(name_loc->namelen,
5e656dbb 2398 be16_to_cpu(name_loc->valuelen));
2bd0ea18 2399 } else {
a24374f4 2400 name_rmt = xfs_attr3_leaf_name_remote(leaf, index);
56b2de80 2401 size = xfs_attr_leaf_entsize_remote(name_rmt->namelen);
2bd0ea18 2402 }
a24374f4 2403 return size;
2bd0ea18
NS
2404}
2405
2406/*
2407 * Calculate the number of bytes that would be required to store the new
2408 * attribute (whether local or remote only calculate bytes in this block).
2409 * This routine decides as a side effect whether the attribute will be
2410 * a "local" or a "remote" attribute.
2411 */
2412int
ca86e759 2413xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize, int *local)
2bd0ea18
NS
2414{
2415 int size;
2416
56b2de80
DC
2417 size = xfs_attr_leaf_entsize_local(namelen, valuelen);
2418 if (size < xfs_attr_leaf_entsize_local_max(blocksize)) {
2bd0ea18
NS
2419 if (local) {
2420 *local = 1;
2421 }
2422 } else {
56b2de80 2423 size = xfs_attr_leaf_entsize_remote(namelen);
2bd0ea18
NS
2424 if (local) {
2425 *local = 0;
2426 }
2427 }
a24374f4 2428 return size;
2bd0ea18 2429}
57c9fccb 2430
78d6585c 2431
57c9fccb
NS
2432/*========================================================================
2433 * Manage the INCOMPLETE flag in a leaf entry
2434 *========================================================================*/
2435
2436/*
2437 * Clear the INCOMPLETE flag on an entry in a leaf block.
2438 */
2439int
a24374f4
DC
2440xfs_attr3_leaf_clearflag(
2441 struct xfs_da_args *args)
57c9fccb 2442{
a24374f4
DC
2443 struct xfs_attr_leafblock *leaf;
2444 struct xfs_attr_leaf_entry *entry;
2445 struct xfs_attr_leaf_name_remote *name_rmt;
2446 struct xfs_buf *bp;
2447 int error;
57c9fccb 2448#ifdef DEBUG
a24374f4 2449 struct xfs_attr3_icleaf_hdr ichdr;
57c9fccb
NS
2450 xfs_attr_leaf_name_local_t *name_loc;
2451 int namelen;
2452 char *name;
2453#endif /* DEBUG */
2454
a2ceac1f 2455 trace_xfs_attr_leaf_clearflag(args);
57c9fccb
NS
2456 /*
2457 * Set up the operation.
2458 */
a24374f4 2459 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
a2ceac1f 2460 if (error)
57c9fccb 2461 return(error);
57c9fccb 2462
a2ceac1f 2463 leaf = bp->b_addr;
a24374f4 2464 entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
57c9fccb
NS
2465 ASSERT(entry->flags & XFS_ATTR_INCOMPLETE);
2466
2467#ifdef DEBUG
a24374f4
DC
2468 xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
2469 ASSERT(args->index < ichdr.count);
2470 ASSERT(args->index >= 0);
2471
57c9fccb 2472 if (entry->flags & XFS_ATTR_LOCAL) {
a24374f4 2473 name_loc = xfs_attr3_leaf_name_local(leaf, args->index);
57c9fccb
NS
2474 namelen = name_loc->namelen;
2475 name = (char *)name_loc->nameval;
2476 } else {
a24374f4 2477 name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
57c9fccb
NS
2478 namelen = name_rmt->namelen;
2479 name = (char *)name_rmt->name;
2480 }
5e656dbb 2481 ASSERT(be32_to_cpu(entry->hashval) == args->hashval);
57c9fccb
NS
2482 ASSERT(namelen == args->namelen);
2483 ASSERT(memcmp(name, args->name, namelen) == 0);
2484#endif /* DEBUG */
2485
2486 entry->flags &= ~XFS_ATTR_INCOMPLETE;
a2ceac1f 2487 xfs_trans_log_buf(args->trans, bp,
57c9fccb
NS
2488 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
2489
2490 if (args->rmtblkno) {
2491 ASSERT((entry->flags & XFS_ATTR_LOCAL) == 0);
a24374f4 2492 name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
5e656dbb
BN
2493 name_rmt->valueblk = cpu_to_be32(args->rmtblkno);
2494 name_rmt->valuelen = cpu_to_be32(args->valuelen);
a2ceac1f 2495 xfs_trans_log_buf(args->trans, bp,
57c9fccb
NS
2496 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
2497 }
57c9fccb
NS
2498
2499 /*
2500 * Commit the flag value change and start the next trans in series.
2501 */
5e656dbb 2502 return xfs_trans_roll(&args->trans, args->dp);
57c9fccb
NS
2503}
2504
2505/*
2506 * Set the INCOMPLETE flag on an entry in a leaf block.
2507 */
2508int
a24374f4
DC
2509xfs_attr3_leaf_setflag(
2510 struct xfs_da_args *args)
57c9fccb 2511{
a24374f4
DC
2512 struct xfs_attr_leafblock *leaf;
2513 struct xfs_attr_leaf_entry *entry;
2514 struct xfs_attr_leaf_name_remote *name_rmt;
2515 struct xfs_buf *bp;
57c9fccb 2516 int error;
a24374f4
DC
2517#ifdef DEBUG
2518 struct xfs_attr3_icleaf_hdr ichdr;
2519#endif
57c9fccb 2520
a2ceac1f
DC
2521 trace_xfs_attr_leaf_setflag(args);
2522
57c9fccb
NS
2523 /*
2524 * Set up the operation.
2525 */
a24374f4 2526 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
a2ceac1f 2527 if (error)
57c9fccb 2528 return(error);
57c9fccb 2529
a2ceac1f 2530 leaf = bp->b_addr;
a24374f4
DC
2531#ifdef DEBUG
2532 xfs_attr3_leaf_hdr_from_disk(&ichdr, leaf);
2533 ASSERT(args->index < ichdr.count);
57c9fccb 2534 ASSERT(args->index >= 0);
a24374f4
DC
2535#endif
2536 entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
57c9fccb
NS
2537
2538 ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0);
2539 entry->flags |= XFS_ATTR_INCOMPLETE;
a2ceac1f 2540 xfs_trans_log_buf(args->trans, bp,
57c9fccb
NS
2541 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
2542 if ((entry->flags & XFS_ATTR_LOCAL) == 0) {
a24374f4 2543 name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
57c9fccb
NS
2544 name_rmt->valueblk = 0;
2545 name_rmt->valuelen = 0;
a2ceac1f 2546 xfs_trans_log_buf(args->trans, bp,
57c9fccb
NS
2547 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
2548 }
57c9fccb
NS
2549
2550 /*
2551 * Commit the flag value change and start the next trans in series.
2552 */
5e656dbb 2553 return xfs_trans_roll(&args->trans, args->dp);
57c9fccb
NS
2554}
2555
2556/*
2557 * In a single transaction, clear the INCOMPLETE flag on the leaf entry
2558 * given by args->blkno/index and set the INCOMPLETE flag on the leaf
2559 * entry given by args->blkno2/index2.
2560 *
2561 * Note that they could be in different blocks, or in the same block.
2562 */
2563int
a24374f4
DC
2564xfs_attr3_leaf_flipflags(
2565 struct xfs_da_args *args)
57c9fccb 2566{
a24374f4
DC
2567 struct xfs_attr_leafblock *leaf1;
2568 struct xfs_attr_leafblock *leaf2;
2569 struct xfs_attr_leaf_entry *entry1;
2570 struct xfs_attr_leaf_entry *entry2;
2571 struct xfs_attr_leaf_name_remote *name_rmt;
2572 struct xfs_buf *bp1;
2573 struct xfs_buf *bp2;
57c9fccb
NS
2574 int error;
2575#ifdef DEBUG
a24374f4
DC
2576 struct xfs_attr3_icleaf_hdr ichdr1;
2577 struct xfs_attr3_icleaf_hdr ichdr2;
57c9fccb
NS
2578 xfs_attr_leaf_name_local_t *name_loc;
2579 int namelen1, namelen2;
2580 char *name1, *name2;
2581#endif /* DEBUG */
2582
a2ceac1f
DC
2583 trace_xfs_attr_leaf_flipflags(args);
2584
57c9fccb
NS
2585 /*
2586 * Read the block containing the "old" attr
2587 */
a24374f4 2588 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp1);
a2ceac1f
DC
2589 if (error)
2590 return error;
57c9fccb
NS
2591
2592 /*
2593 * Read the block containing the "new" attr, if it is different
2594 */
2595 if (args->blkno2 != args->blkno) {
a24374f4 2596 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
a2ceac1f
DC
2597 -1, &bp2);
2598 if (error)
2599 return error;
57c9fccb
NS
2600 } else {
2601 bp2 = bp1;
2602 }
2603
a2ceac1f 2604 leaf1 = bp1->b_addr;
a24374f4 2605 entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index];
57c9fccb 2606
a2ceac1f 2607 leaf2 = bp2->b_addr;
a24374f4 2608 entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2];
57c9fccb
NS
2609
2610#ifdef DEBUG
a24374f4
DC
2611 xfs_attr3_leaf_hdr_from_disk(&ichdr1, leaf1);
2612 ASSERT(args->index < ichdr1.count);
2613 ASSERT(args->index >= 0);
2614
2615 xfs_attr3_leaf_hdr_from_disk(&ichdr2, leaf2);
2616 ASSERT(args->index2 < ichdr2.count);
2617 ASSERT(args->index2 >= 0);
2618
57c9fccb 2619 if (entry1->flags & XFS_ATTR_LOCAL) {
a24374f4 2620 name_loc = xfs_attr3_leaf_name_local(leaf1, args->index);
57c9fccb
NS
2621 namelen1 = name_loc->namelen;
2622 name1 = (char *)name_loc->nameval;
2623 } else {
a24374f4 2624 name_rmt = xfs_attr3_leaf_name_remote(leaf1, args->index);
57c9fccb
NS
2625 namelen1 = name_rmt->namelen;
2626 name1 = (char *)name_rmt->name;
2627 }
2628 if (entry2->flags & XFS_ATTR_LOCAL) {
a24374f4 2629 name_loc = xfs_attr3_leaf_name_local(leaf2, args->index2);
57c9fccb
NS
2630 namelen2 = name_loc->namelen;
2631 name2 = (char *)name_loc->nameval;
2632 } else {
a24374f4 2633 name_rmt = xfs_attr3_leaf_name_remote(leaf2, args->index2);
57c9fccb
NS
2634 namelen2 = name_rmt->namelen;
2635 name2 = (char *)name_rmt->name;
2636 }
5e656dbb 2637 ASSERT(be32_to_cpu(entry1->hashval) == be32_to_cpu(entry2->hashval));
57c9fccb
NS
2638 ASSERT(namelen1 == namelen2);
2639 ASSERT(memcmp(name1, name2, namelen1) == 0);
2640#endif /* DEBUG */
2641
2642 ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE);
2643 ASSERT((entry2->flags & XFS_ATTR_INCOMPLETE) == 0);
2644
2645 entry1->flags &= ~XFS_ATTR_INCOMPLETE;
a2ceac1f 2646 xfs_trans_log_buf(args->trans, bp1,
57c9fccb
NS
2647 XFS_DA_LOGRANGE(leaf1, entry1, sizeof(*entry1)));
2648 if (args->rmtblkno) {
2649 ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0);
a24374f4 2650 name_rmt = xfs_attr3_leaf_name_remote(leaf1, args->index);
5e656dbb
BN
2651 name_rmt->valueblk = cpu_to_be32(args->rmtblkno);
2652 name_rmt->valuelen = cpu_to_be32(args->valuelen);
a2ceac1f 2653 xfs_trans_log_buf(args->trans, bp1,
57c9fccb
NS
2654 XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt)));
2655 }
2656
2657 entry2->flags |= XFS_ATTR_INCOMPLETE;
a2ceac1f 2658 xfs_trans_log_buf(args->trans, bp2,
57c9fccb
NS
2659 XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2)));
2660 if ((entry2->flags & XFS_ATTR_LOCAL) == 0) {
a24374f4 2661 name_rmt = xfs_attr3_leaf_name_remote(leaf2, args->index2);
57c9fccb
NS
2662 name_rmt->valueblk = 0;
2663 name_rmt->valuelen = 0;
a2ceac1f 2664 xfs_trans_log_buf(args->trans, bp2,
57c9fccb
NS
2665 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
2666 }
57c9fccb
NS
2667
2668 /*
2669 * Commit the flag value change and start the next trans in series.
2670 */
5e656dbb 2671 error = xfs_trans_roll(&args->trans, args->dp);
57c9fccb 2672
a24374f4 2673 return error;
57c9fccb 2674}