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