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