blob: fe91eac4e2a7b1919228ec9f063a2946e37ec908 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Nathan Scott7b718762005-11-02 14:58:39 +11002 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Nathan Scott7b718762005-11-02 14:58:39 +11005 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * published by the Free Software Foundation.
8 *
Nathan Scott7b718762005-11-02 14:58:39 +11009 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
Nathan Scott7b718762005-11-02 14:58:39 +110014 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "xfs.h"
Nathan Scotta844f452005-11-02 14:38:42 +110019#include "xfs_fs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include "xfs_types.h"
Nathan Scotta844f452005-11-02 14:38:42 +110021#include "xfs_bit.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include "xfs_log.h"
Nathan Scotta844f452005-11-02 14:38:42 +110023#include "xfs_inum.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include "xfs_trans.h"
25#include "xfs_sb.h"
26#include "xfs_ag.h"
27#include "xfs_dir.h"
28#include "xfs_dir2.h"
29#include "xfs_dmapi.h"
30#include "xfs_mount.h"
Nathan Scotta844f452005-11-02 14:38:42 +110031#include "xfs_da_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "xfs_bmap_btree.h"
Nathan Scotta844f452005-11-02 14:38:42 +110033#include "xfs_alloc_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070034#include "xfs_ialloc_btree.h"
35#include "xfs_alloc.h"
36#include "xfs_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include "xfs_dir_sf.h"
38#include "xfs_dir2_sf.h"
Nathan Scotta844f452005-11-02 14:38:42 +110039#include "xfs_attr_sf.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include "xfs_dinode.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include "xfs_inode.h"
Nathan Scotta844f452005-11-02 14:38:42 +110042#include "xfs_inode_item.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070043#include "xfs_bmap.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044#include "xfs_attr.h"
45#include "xfs_attr_leaf.h"
46#include "xfs_error.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
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 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +100061STATIC int xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t which_block,
62 xfs_dabuf_t **bpp);
Linus Torvalds1da177e2005-04-16 15:20:36 -070063STATIC int xfs_attr_leaf_add_work(xfs_dabuf_t *leaf_buffer, xfs_da_args_t *args,
64 int freemap_index);
65STATIC void xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *leaf_buffer);
66STATIC void xfs_attr_leaf_rebalance(xfs_da_state_t *state,
67 xfs_da_state_blk_t *blk1,
68 xfs_da_state_blk_t *blk2);
69STATIC int xfs_attr_leaf_figure_balance(xfs_da_state_t *state,
70 xfs_da_state_blk_t *leaf_blk_1,
71 xfs_da_state_blk_t *leaf_blk_2,
72 int *number_entries_in_blk1,
73 int *number_usedbytes_in_blk1);
74
75/*
Christoph Hellwigba0f32d2005-06-21 15:36:52 +100076 * Routines used for shrinking the Btree.
77 */
78STATIC int xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp,
79 xfs_dabuf_t *bp, int level);
80STATIC int xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp,
81 xfs_dabuf_t *bp);
82STATIC int xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
83 xfs_dablk_t blkno, int blkcnt);
84
85/*
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 * Utility routines.
87 */
88STATIC void xfs_attr_leaf_moveents(xfs_attr_leafblock_t *src_leaf,
89 int src_start,
90 xfs_attr_leafblock_t *dst_leaf,
91 int dst_start, int move_count,
92 xfs_mount_t *mp);
Christoph Hellwigba0f32d2005-06-21 15:36:52 +100093STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index);
94STATIC int xfs_attr_put_listent(xfs_attr_list_context_t *context,
95 attrnames_t *, char *name, int namelen,
96 int valuelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98
99/*========================================================================
Nathan Scottd8cc8902005-11-02 10:34:53 +1100100 * External routines when attribute fork size < XFS_LITINO(mp).
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 *========================================================================*/
102
103/*
Nathan Scottd8cc8902005-11-02 10:34:53 +1100104 * Query whether the requested number of additional bytes of extended
105 * attribute space will be able to fit inline.
106 * Returns zero if not, else the di_forkoff fork offset to be used in the
107 * literal area for attribute data once the new bytes have been added.
108 *
109 * di_forkoff must be 8 byte aligned, hence is stored as a >>3 value;
110 * special case for dev/uuid inodes, they have fixed size data forks.
111 */
112int
113xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes)
114{
115 int offset;
116 int minforkoff; /* lower limit on valid forkoff locations */
117 int maxforkoff; /* upper limit on valid forkoff locations */
118 xfs_mount_t *mp = dp->i_mount;
119
Nathan Scottd8cc8902005-11-02 10:34:53 +1100120 offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */
121
122 switch (dp->i_d.di_format) {
123 case XFS_DINODE_FMT_DEV:
124 minforkoff = roundup(sizeof(xfs_dev_t), 8) >> 3;
125 return (offset >= minforkoff) ? minforkoff : 0;
126 case XFS_DINODE_FMT_UUID:
127 minforkoff = roundup(sizeof(uuid_t), 8) >> 3;
128 return (offset >= minforkoff) ? minforkoff : 0;
129 }
130
Nathan Scott13059ff2006-01-11 15:32:01 +1100131 if (!(mp->m_flags & XFS_MOUNT_ATTR2)) {
Nathan Scottda087ba2005-11-02 15:00:20 +1100132 if (bytes <= XFS_IFORK_ASIZE(dp))
133 return mp->m_attroffset >> 3;
134 return 0;
135 }
136
Nathan Scottd8cc8902005-11-02 10:34:53 +1100137 /* data fork btree root can have at least this many key/ptr pairs */
138 minforkoff = MAX(dp->i_df.if_bytes, XFS_BMDR_SPACE_CALC(MINDBTPTRS));
139 minforkoff = roundup(minforkoff, 8) >> 3;
140
141 /* attr fork btree root can have at least this many key/ptr pairs */
142 maxforkoff = XFS_LITINO(mp) - XFS_BMDR_SPACE_CALC(MINABTPTRS);
143 maxforkoff = maxforkoff >> 3; /* rounded down */
144
145 if (offset >= minforkoff && offset < maxforkoff)
146 return offset;
147 if (offset >= maxforkoff)
148 return maxforkoff;
149 return 0;
150}
151
152/*
153 * Switch on the ATTR2 superblock bit (implies also FEATURES2)
154 */
155STATIC void
156xfs_sbversion_add_attr2(xfs_mount_t *mp, xfs_trans_t *tp)
157{
158 unsigned long s;
159
Nathan Scott13059ff2006-01-11 15:32:01 +1100160 if ((mp->m_flags & XFS_MOUNT_ATTR2) &&
Nathan Scottd8cc8902005-11-02 10:34:53 +1100161 !(XFS_SB_VERSION_HASATTR2(&mp->m_sb))) {
162 s = XFS_SB_LOCK(mp);
163 if (!XFS_SB_VERSION_HASATTR2(&mp->m_sb)) {
164 XFS_SB_VERSION_ADDATTR2(&mp->m_sb);
165 XFS_SB_UNLOCK(mp, s);
166 xfs_mod_sb(tp, XFS_SB_VERSIONNUM | XFS_SB_FEATURES2);
167 } else
168 XFS_SB_UNLOCK(mp, s);
169 }
170}
171
172/*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700173 * Create the initial contents of a shortform attribute list.
174 */
Nathan Scottd8cc8902005-11-02 10:34:53 +1100175void
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176xfs_attr_shortform_create(xfs_da_args_t *args)
177{
178 xfs_attr_sf_hdr_t *hdr;
179 xfs_inode_t *dp;
180 xfs_ifork_t *ifp;
181
182 dp = args->dp;
183 ASSERT(dp != NULL);
184 ifp = dp->i_afp;
185 ASSERT(ifp != NULL);
186 ASSERT(ifp->if_bytes == 0);
187 if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) {
188 ifp->if_flags &= ~XFS_IFEXTENTS; /* just in case */
189 dp->i_d.di_aformat = XFS_DINODE_FMT_LOCAL;
190 ifp->if_flags |= XFS_IFINLINE;
191 } else {
192 ASSERT(ifp->if_flags & XFS_IFINLINE);
193 }
194 xfs_idata_realloc(dp, sizeof(*hdr), XFS_ATTR_FORK);
195 hdr = (xfs_attr_sf_hdr_t *)ifp->if_u1.if_data;
196 hdr->count = 0;
197 INT_SET(hdr->totsize, ARCH_CONVERT, sizeof(*hdr));
198 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700199}
200
201/*
202 * Add a name/value pair to the shortform attribute list.
203 * Overflow from the inode has already been checked for.
204 */
Nathan Scottd8cc8902005-11-02 10:34:53 +1100205void
206xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207{
208 xfs_attr_shortform_t *sf;
209 xfs_attr_sf_entry_t *sfe;
210 int i, offset, size;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100211 xfs_mount_t *mp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700212 xfs_inode_t *dp;
213 xfs_ifork_t *ifp;
214
215 dp = args->dp;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100216 mp = dp->i_mount;
217 dp->i_d.di_forkoff = forkoff;
218 dp->i_df.if_ext_max =
219 XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
220 dp->i_afp->if_ext_max =
221 XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 ifp = dp->i_afp;
224 ASSERT(ifp->if_flags & XFS_IFINLINE);
225 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
226 sfe = &sf->list[0];
227 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT);
228 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
Nathan Scottd8cc8902005-11-02 10:34:53 +1100229#ifdef DEBUG
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 if (sfe->namelen != args->namelen)
231 continue;
232 if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
233 continue;
234 if (((args->flags & ATTR_SECURE) != 0) !=
235 ((sfe->flags & XFS_ATTR_SECURE) != 0))
236 continue;
237 if (((args->flags & ATTR_ROOT) != 0) !=
238 ((sfe->flags & XFS_ATTR_ROOT) != 0))
239 continue;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100240 ASSERT(0);
241#endif
Linus Torvalds1da177e2005-04-16 15:20:36 -0700242 }
243
244 offset = (char *)sfe - (char *)sf;
245 size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
246 xfs_idata_realloc(dp, size, XFS_ATTR_FORK);
247 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
248 sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset);
249
250 sfe->namelen = args->namelen;
251 INT_SET(sfe->valuelen, ARCH_CONVERT, args->valuelen);
252 sfe->flags = (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
253 ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
254 memcpy(sfe->nameval, args->name, args->namelen);
255 memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
256 INT_MOD(sf->hdr.count, ARCH_CONVERT, 1);
257 INT_MOD(sf->hdr.totsize, ARCH_CONVERT, size);
258 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
259
Nathan Scottd8cc8902005-11-02 10:34:53 +1100260 xfs_sbversion_add_attr2(mp, args->trans);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700261}
262
263/*
Nathan Scottd8cc8902005-11-02 10:34:53 +1100264 * Remove an attribute from the shortform attribute list structure.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700265 */
266int
267xfs_attr_shortform_remove(xfs_da_args_t *args)
268{
269 xfs_attr_shortform_t *sf;
270 xfs_attr_sf_entry_t *sfe;
271 int base, size=0, end, totsize, i;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100272 xfs_mount_t *mp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700273 xfs_inode_t *dp;
274
Linus Torvalds1da177e2005-04-16 15:20:36 -0700275 dp = args->dp;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100276 mp = dp->i_mount;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700277 base = sizeof(xfs_attr_sf_hdr_t);
278 sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
279 sfe = &sf->list[0];
Nathan Scottd8cc8902005-11-02 10:34:53 +1100280 end = INT_GET(sf->hdr.count, ARCH_CONVERT);
281 for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700282 base += size, i++) {
283 size = XFS_ATTR_SF_ENTSIZE(sfe);
284 if (sfe->namelen != args->namelen)
285 continue;
286 if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
287 continue;
288 if (((args->flags & ATTR_SECURE) != 0) !=
289 ((sfe->flags & XFS_ATTR_SECURE) != 0))
290 continue;
291 if (((args->flags & ATTR_ROOT) != 0) !=
292 ((sfe->flags & XFS_ATTR_ROOT) != 0))
293 continue;
294 break;
295 }
Nathan Scottd8cc8902005-11-02 10:34:53 +1100296 if (i == end)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700297 return(XFS_ERROR(ENOATTR));
298
Nathan Scottd8cc8902005-11-02 10:34:53 +1100299 /*
300 * Fix up the attribute fork data, covering the hole
301 */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700302 end = base + size;
303 totsize = INT_GET(sf->hdr.totsize, ARCH_CONVERT);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100304 if (end != totsize)
305 memmove(&((char *)sf)[base], &((char *)sf)[end], totsize - end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700306 INT_MOD(sf->hdr.count, ARCH_CONVERT, -1);
307 INT_MOD(sf->hdr.totsize, ARCH_CONVERT, -size);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100308
309 /*
310 * Fix up the start offset of the attribute fork
311 */
312 totsize -= size;
Nathan Scotte0144ca2005-11-25 16:42:22 +1100313 if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname &&
Nathan Scott13059ff2006-01-11 15:32:01 +1100314 (mp->m_flags & XFS_MOUNT_ATTR2)) {
Nathan Scottd8cc8902005-11-02 10:34:53 +1100315 /*
316 * Last attribute now removed, revert to original
317 * inode format making all literal area available
318 * to the data fork once more.
319 */
320 xfs_idestroy_fork(dp, XFS_ATTR_FORK);
321 dp->i_d.di_forkoff = 0;
322 dp->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
323 ASSERT(dp->i_d.di_anextents == 0);
324 ASSERT(dp->i_afp == NULL);
325 dp->i_df.if_ext_max =
326 XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
327 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
328 } else {
329 xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
330 dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize);
331 ASSERT(dp->i_d.di_forkoff);
Nathan Scotte0144ca2005-11-25 16:42:22 +1100332 ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || args->addname ||
Nathan Scott13059ff2006-01-11 15:32:01 +1100333 !(mp->m_flags & XFS_MOUNT_ATTR2));
Nathan Scottd8cc8902005-11-02 10:34:53 +1100334 dp->i_afp->if_ext_max =
335 XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
336 dp->i_df.if_ext_max =
337 XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
338 xfs_trans_log_inode(args->trans, dp,
339 XFS_ILOG_CORE | XFS_ILOG_ADATA);
340 }
341
342 xfs_sbversion_add_attr2(mp, args->trans);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700343
344 return(0);
345}
346
347/*
348 * Look up a name in a shortform attribute list structure.
349 */
350/*ARGSUSED*/
351int
352xfs_attr_shortform_lookup(xfs_da_args_t *args)
353{
354 xfs_attr_shortform_t *sf;
355 xfs_attr_sf_entry_t *sfe;
356 int i;
357 xfs_ifork_t *ifp;
358
359 ifp = args->dp->i_afp;
360 ASSERT(ifp->if_flags & XFS_IFINLINE);
361 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
362 sfe = &sf->list[0];
363 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT);
364 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
365 if (sfe->namelen != args->namelen)
366 continue;
367 if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
368 continue;
369 if (((args->flags & ATTR_SECURE) != 0) !=
370 ((sfe->flags & XFS_ATTR_SECURE) != 0))
371 continue;
372 if (((args->flags & ATTR_ROOT) != 0) !=
373 ((sfe->flags & XFS_ATTR_ROOT) != 0))
374 continue;
375 return(XFS_ERROR(EEXIST));
376 }
377 return(XFS_ERROR(ENOATTR));
378}
379
380/*
381 * Look up a name in a shortform attribute list structure.
382 */
383/*ARGSUSED*/
384int
385xfs_attr_shortform_getvalue(xfs_da_args_t *args)
386{
387 xfs_attr_shortform_t *sf;
388 xfs_attr_sf_entry_t *sfe;
389 int i;
390
391 ASSERT(args->dp->i_d.di_aformat == XFS_IFINLINE);
392 sf = (xfs_attr_shortform_t *)args->dp->i_afp->if_u1.if_data;
393 sfe = &sf->list[0];
394 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT);
395 sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
396 if (sfe->namelen != args->namelen)
397 continue;
398 if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
399 continue;
400 if (((args->flags & ATTR_SECURE) != 0) !=
401 ((sfe->flags & XFS_ATTR_SECURE) != 0))
402 continue;
403 if (((args->flags & ATTR_ROOT) != 0) !=
404 ((sfe->flags & XFS_ATTR_ROOT) != 0))
405 continue;
406 if (args->flags & ATTR_KERNOVAL) {
407 args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
408 return(XFS_ERROR(EEXIST));
409 }
410 if (args->valuelen < INT_GET(sfe->valuelen, ARCH_CONVERT)) {
411 args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
412 return(XFS_ERROR(ERANGE));
413 }
414 args->valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
415 memcpy(args->value, &sfe->nameval[args->namelen],
416 args->valuelen);
417 return(XFS_ERROR(EEXIST));
418 }
419 return(XFS_ERROR(ENOATTR));
420}
421
422/*
423 * Convert from using the shortform to the leaf.
424 */
425int
426xfs_attr_shortform_to_leaf(xfs_da_args_t *args)
427{
428 xfs_inode_t *dp;
429 xfs_attr_shortform_t *sf;
430 xfs_attr_sf_entry_t *sfe;
431 xfs_da_args_t nargs;
432 char *tmpbuffer;
433 int error, i, size;
434 xfs_dablk_t blkno;
435 xfs_dabuf_t *bp;
436 xfs_ifork_t *ifp;
437
438 dp = args->dp;
439 ifp = dp->i_afp;
440 sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
441 size = INT_GET(sf->hdr.totsize, ARCH_CONVERT);
442 tmpbuffer = kmem_alloc(size, KM_SLEEP);
443 ASSERT(tmpbuffer != NULL);
444 memcpy(tmpbuffer, ifp->if_u1.if_data, size);
445 sf = (xfs_attr_shortform_t *)tmpbuffer;
446
447 xfs_idata_realloc(dp, -size, XFS_ATTR_FORK);
448 bp = NULL;
449 error = xfs_da_grow_inode(args, &blkno);
450 if (error) {
451 /*
452 * If we hit an IO error middle of the transaction inside
453 * grow_inode(), we may have inconsistent data. Bail out.
454 */
455 if (error == EIO)
456 goto out;
457 xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */
458 memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */
459 goto out;
460 }
461
462 ASSERT(blkno == 0);
463 error = xfs_attr_leaf_create(args, blkno, &bp);
464 if (error) {
465 error = xfs_da_shrink_inode(args, 0, bp);
466 bp = NULL;
467 if (error)
468 goto out;
469 xfs_idata_realloc(dp, size, XFS_ATTR_FORK); /* try to put */
470 memcpy(ifp->if_u1.if_data, tmpbuffer, size); /* it back */
471 goto out;
472 }
473
474 memset((char *)&nargs, 0, sizeof(nargs));
475 nargs.dp = dp;
476 nargs.firstblock = args->firstblock;
477 nargs.flist = args->flist;
478 nargs.total = args->total;
479 nargs.whichfork = XFS_ATTR_FORK;
480 nargs.trans = args->trans;
481 nargs.oknoent = 1;
482
483 sfe = &sf->list[0];
484 for (i = 0; i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {
485 nargs.name = (char *)sfe->nameval;
486 nargs.namelen = sfe->namelen;
487 nargs.value = (char *)&sfe->nameval[nargs.namelen];
488 nargs.valuelen = INT_GET(sfe->valuelen, ARCH_CONVERT);
489 nargs.hashval = xfs_da_hashname((char *)sfe->nameval,
490 sfe->namelen);
491 nargs.flags = (sfe->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
492 ((sfe->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
493 error = xfs_attr_leaf_lookup_int(bp, &nargs); /* set a->index */
494 ASSERT(error == ENOATTR);
495 error = xfs_attr_leaf_add(bp, &nargs);
496 ASSERT(error != ENOSPC);
497 if (error)
498 goto out;
499 sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
500 }
501 error = 0;
502
503out:
504 if(bp)
505 xfs_da_buf_done(bp);
506 kmem_free(tmpbuffer, size);
507 return(error);
508}
509
510STATIC int
511xfs_attr_shortform_compare(const void *a, const void *b)
512{
513 xfs_attr_sf_sort_t *sa, *sb;
514
515 sa = (xfs_attr_sf_sort_t *)a;
516 sb = (xfs_attr_sf_sort_t *)b;
517 if (INT_GET(sa->hash, ARCH_CONVERT)
518 < INT_GET(sb->hash, ARCH_CONVERT)) {
519 return(-1);
520 } else if (INT_GET(sa->hash, ARCH_CONVERT)
521 > INT_GET(sb->hash, ARCH_CONVERT)) {
522 return(1);
523 } else {
524 return(sa->entno - sb->entno);
525 }
526}
527
528/*
529 * Copy out entries of shortform attribute lists for attr_list().
530 * Shortform atrtribute lists are not stored in hashval sorted order.
531 * If the output buffer is not large enough to hold them all, then we
532 * we have to calculate each entries' hashvalue and sort them before
533 * we can begin returning them to the user.
534 */
535/*ARGSUSED*/
536int
537xfs_attr_shortform_list(xfs_attr_list_context_t *context)
538{
539 attrlist_cursor_kern_t *cursor;
540 xfs_attr_sf_sort_t *sbuf, *sbp;
541 xfs_attr_shortform_t *sf;
542 xfs_attr_sf_entry_t *sfe;
543 xfs_inode_t *dp;
544 int sbsize, nsbuf, count, i;
545
546 ASSERT(context != NULL);
547 dp = context->dp;
548 ASSERT(dp != NULL);
549 ASSERT(dp->i_afp != NULL);
550 sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
551 ASSERT(sf != NULL);
552 if (!sf->hdr.count)
553 return(0);
554 cursor = context->cursor;
555 ASSERT(cursor != NULL);
556
557 xfs_attr_trace_l_c("sf start", context);
558
559 /*
560 * If the buffer is large enough, do not bother with sorting.
561 * Note the generous fudge factor of 16 overhead bytes per entry.
562 */
563 if ((dp->i_afp->if_bytes + INT_GET(sf->hdr.count, ARCH_CONVERT) * 16)
564 < context->bufsize) {
565 for (i = 0, sfe = &sf->list[0];
566 i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {
567 attrnames_t *namesp;
568
569 if (((context->flags & ATTR_SECURE) != 0) !=
570 ((sfe->flags & XFS_ATTR_SECURE) != 0) &&
571 !(context->flags & ATTR_KERNORMALS)) {
572 sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
573 continue;
574 }
575 if (((context->flags & ATTR_ROOT) != 0) !=
576 ((sfe->flags & XFS_ATTR_ROOT) != 0) &&
577 !(context->flags & ATTR_KERNROOTLS)) {
578 sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
579 continue;
580 }
581 namesp = (sfe->flags & XFS_ATTR_SECURE) ? &attr_secure:
582 ((sfe->flags & XFS_ATTR_ROOT) ? &attr_trusted :
583 &attr_user);
584 if (context->flags & ATTR_KERNOVAL) {
585 ASSERT(context->flags & ATTR_KERNAMELS);
586 context->count += namesp->attr_namelen +
587 INT_GET(sfe->namelen, ARCH_CONVERT) + 1;
588 }
589 else {
590 if (xfs_attr_put_listent(context, namesp,
591 (char *)sfe->nameval,
592 (int)sfe->namelen,
593 (int)INT_GET(sfe->valuelen,
594 ARCH_CONVERT)))
595 break;
596 }
597 sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
598 }
599 xfs_attr_trace_l_c("sf big-gulp", context);
600 return(0);
601 }
602
603 /*
604 * It didn't all fit, so we have to sort everything on hashval.
605 */
606 sbsize = INT_GET(sf->hdr.count, ARCH_CONVERT) * sizeof(*sbuf);
607 sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP);
608
609 /*
610 * Scan the attribute list for the rest of the entries, storing
611 * the relevant info from only those that match into a buffer.
612 */
613 nsbuf = 0;
614 for (i = 0, sfe = &sf->list[0];
615 i < INT_GET(sf->hdr.count, ARCH_CONVERT); i++) {
616 if (unlikely(
617 ((char *)sfe < (char *)sf) ||
618 ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) {
619 XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
620 XFS_ERRLEVEL_LOW,
621 context->dp->i_mount, sfe);
622 xfs_attr_trace_l_c("sf corrupted", context);
623 kmem_free(sbuf, sbsize);
624 return XFS_ERROR(EFSCORRUPTED);
625 }
626 if (((context->flags & ATTR_SECURE) != 0) !=
627 ((sfe->flags & XFS_ATTR_SECURE) != 0) &&
628 !(context->flags & ATTR_KERNORMALS)) {
629 sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
630 continue;
631 }
632 if (((context->flags & ATTR_ROOT) != 0) !=
633 ((sfe->flags & XFS_ATTR_ROOT) != 0) &&
634 !(context->flags & ATTR_KERNROOTLS)) {
635 sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
636 continue;
637 }
638 sbp->entno = i;
639 INT_SET(sbp->hash, ARCH_CONVERT,
640 xfs_da_hashname((char *)sfe->nameval, sfe->namelen));
641 sbp->name = (char *)sfe->nameval;
642 sbp->namelen = sfe->namelen;
643 /* These are bytes, and both on-disk, don't endian-flip */
644 sbp->valuelen = sfe->valuelen;
645 sbp->flags = sfe->flags;
646 sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
647 sbp++;
648 nsbuf++;
649 }
650
651 /*
652 * Sort the entries on hash then entno.
653 */
Nathan Scott380b5dc2005-11-02 11:43:18 +1100654 xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 /*
657 * Re-find our place IN THE SORTED LIST.
658 */
659 count = 0;
660 cursor->initted = 1;
661 cursor->blkno = 0;
662 for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
663 if (INT_GET(sbp->hash, ARCH_CONVERT) == cursor->hashval) {
664 if (cursor->offset == count) {
665 break;
666 }
667 count++;
668 } else if (INT_GET(sbp->hash, ARCH_CONVERT) > cursor->hashval) {
669 break;
670 }
671 }
672 if (i == nsbuf) {
673 kmem_free(sbuf, sbsize);
674 xfs_attr_trace_l_c("blk end", context);
675 return(0);
676 }
677
678 /*
679 * Loop putting entries into the user buffer.
680 */
681 for ( ; i < nsbuf; i++, sbp++) {
682 attrnames_t *namesp;
683
684 namesp = (sbp->flags & XFS_ATTR_SECURE) ? &attr_secure :
685 ((sbp->flags & XFS_ATTR_ROOT) ? &attr_trusted :
686 &attr_user);
687
688 if (cursor->hashval != INT_GET(sbp->hash, ARCH_CONVERT)) {
689 cursor->hashval = INT_GET(sbp->hash, ARCH_CONVERT);
690 cursor->offset = 0;
691 }
692 if (context->flags & ATTR_KERNOVAL) {
693 ASSERT(context->flags & ATTR_KERNAMELS);
694 context->count += namesp->attr_namelen +
695 sbp->namelen + 1;
696 } else {
697 if (xfs_attr_put_listent(context, namesp,
698 sbp->name, sbp->namelen,
699 INT_GET(sbp->valuelen, ARCH_CONVERT)))
700 break;
701 }
702 cursor->offset++;
703 }
704
705 kmem_free(sbuf, sbsize);
706 xfs_attr_trace_l_c("sf E-O-F", context);
707 return(0);
708}
709
710/*
711 * Check a leaf attribute block to see if all the entries would fit into
712 * a shortform attribute list.
713 */
714int
715xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp)
716{
717 xfs_attr_leafblock_t *leaf;
718 xfs_attr_leaf_entry_t *entry;
719 xfs_attr_leaf_name_local_t *name_loc;
720 int bytes, i;
721
722 leaf = bp->data;
723 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
724 == XFS_ATTR_LEAF_MAGIC);
725
726 entry = &leaf->entries[0];
727 bytes = sizeof(struct xfs_attr_sf_hdr);
728 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {
729 if (entry->flags & XFS_ATTR_INCOMPLETE)
730 continue; /* don't copy partial entries */
731 if (!(entry->flags & XFS_ATTR_LOCAL))
732 return(0);
733 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
734 if (name_loc->namelen >= XFS_ATTR_SF_ENTSIZE_MAX)
735 return(0);
736 if (INT_GET(name_loc->valuelen, ARCH_CONVERT) >= XFS_ATTR_SF_ENTSIZE_MAX)
737 return(0);
738 bytes += sizeof(struct xfs_attr_sf_entry)-1
739 + name_loc->namelen
740 + INT_GET(name_loc->valuelen, ARCH_CONVERT);
741 }
Nathan Scott13059ff2006-01-11 15:32:01 +1100742 if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) &&
Nathan Scotte0144ca2005-11-25 16:42:22 +1100743 (bytes == sizeof(struct xfs_attr_sf_hdr)))
Nathan Scottd8cc8902005-11-02 10:34:53 +1100744 return(-1);
745 return(xfs_attr_shortform_bytesfit(dp, bytes));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746}
747
748/*
749 * Convert a leaf attribute list to shortform attribute list
750 */
751int
Nathan Scottd8cc8902005-11-02 10:34:53 +1100752xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753{
754 xfs_attr_leafblock_t *leaf;
755 xfs_attr_leaf_entry_t *entry;
756 xfs_attr_leaf_name_local_t *name_loc;
757 xfs_da_args_t nargs;
758 xfs_inode_t *dp;
759 char *tmpbuffer;
760 int error, i;
761
762 dp = args->dp;
763 tmpbuffer = kmem_alloc(XFS_LBSIZE(dp->i_mount), KM_SLEEP);
764 ASSERT(tmpbuffer != NULL);
765
766 ASSERT(bp != NULL);
767 memcpy(tmpbuffer, bp->data, XFS_LBSIZE(dp->i_mount));
768 leaf = (xfs_attr_leafblock_t *)tmpbuffer;
769 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
770 == XFS_ATTR_LEAF_MAGIC);
771 memset(bp->data, 0, XFS_LBSIZE(dp->i_mount));
772
773 /*
774 * Clean out the prior contents of the attribute list.
775 */
776 error = xfs_da_shrink_inode(args, 0, bp);
777 if (error)
778 goto out;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100779
780 if (forkoff == -1) {
Nathan Scott13059ff2006-01-11 15:32:01 +1100781 ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2);
Nathan Scotte0144ca2005-11-25 16:42:22 +1100782
Nathan Scottd8cc8902005-11-02 10:34:53 +1100783 /*
784 * Last attribute was removed, revert to original
785 * inode format making all literal area available
786 * to the data fork once more.
787 */
788 xfs_idestroy_fork(dp, XFS_ATTR_FORK);
789 dp->i_d.di_forkoff = 0;
790 dp->i_d.di_aformat = XFS_DINODE_FMT_EXTENTS;
791 ASSERT(dp->i_d.di_anextents == 0);
792 ASSERT(dp->i_afp == NULL);
793 dp->i_df.if_ext_max =
794 XFS_IFORK_DSIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t);
795 xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 goto out;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100797 }
798
799 xfs_attr_shortform_create(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700800
801 /*
802 * Copy the attributes
803 */
804 memset((char *)&nargs, 0, sizeof(nargs));
805 nargs.dp = dp;
806 nargs.firstblock = args->firstblock;
807 nargs.flist = args->flist;
808 nargs.total = args->total;
809 nargs.whichfork = XFS_ATTR_FORK;
810 nargs.trans = args->trans;
811 nargs.oknoent = 1;
812 entry = &leaf->entries[0];
813 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {
814 if (entry->flags & XFS_ATTR_INCOMPLETE)
815 continue; /* don't copy partial entries */
816 if (!entry->nameidx)
817 continue;
818 ASSERT(entry->flags & XFS_ATTR_LOCAL);
819 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
820 nargs.name = (char *)name_loc->nameval;
821 nargs.namelen = name_loc->namelen;
822 nargs.value = (char *)&name_loc->nameval[nargs.namelen];
823 nargs.valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT);
824 nargs.hashval = INT_GET(entry->hashval, ARCH_CONVERT);
825 nargs.flags = (entry->flags & XFS_ATTR_SECURE) ? ATTR_SECURE :
826 ((entry->flags & XFS_ATTR_ROOT) ? ATTR_ROOT : 0);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100827 xfs_attr_shortform_add(&nargs, forkoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700828 }
829 error = 0;
830
831out:
832 kmem_free(tmpbuffer, XFS_LBSIZE(dp->i_mount));
833 return(error);
834}
835
836/*
837 * Convert from using a single leaf to a root node and a leaf.
838 */
839int
840xfs_attr_leaf_to_node(xfs_da_args_t *args)
841{
842 xfs_attr_leafblock_t *leaf;
843 xfs_da_intnode_t *node;
844 xfs_inode_t *dp;
845 xfs_dabuf_t *bp1, *bp2;
846 xfs_dablk_t blkno;
847 int error;
848
849 dp = args->dp;
850 bp1 = bp2 = NULL;
851 error = xfs_da_grow_inode(args, &blkno);
852 if (error)
853 goto out;
854 error = xfs_da_read_buf(args->trans, args->dp, 0, -1, &bp1,
855 XFS_ATTR_FORK);
856 if (error)
857 goto out;
858 ASSERT(bp1 != NULL);
859 bp2 = NULL;
860 error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp2,
861 XFS_ATTR_FORK);
862 if (error)
863 goto out;
864 ASSERT(bp2 != NULL);
865 memcpy(bp2->data, bp1->data, XFS_LBSIZE(dp->i_mount));
866 xfs_da_buf_done(bp1);
867 bp1 = NULL;
868 xfs_da_log_buf(args->trans, bp2, 0, XFS_LBSIZE(dp->i_mount) - 1);
869
870 /*
871 * Set up the new root node.
872 */
873 error = xfs_da_node_create(args, 0, 1, &bp1, XFS_ATTR_FORK);
874 if (error)
875 goto out;
876 node = bp1->data;
877 leaf = bp2->data;
878 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
879 == XFS_ATTR_LEAF_MAGIC);
880 /* both on-disk, don't endian-flip twice */
881 node->btree[0].hashval =
882 leaf->entries[INT_GET(leaf->hdr.count, ARCH_CONVERT)-1 ].hashval;
883 INT_SET(node->btree[0].before, ARCH_CONVERT, blkno);
884 INT_SET(node->hdr.count, ARCH_CONVERT, 1);
885 xfs_da_log_buf(args->trans, bp1, 0, XFS_LBSIZE(dp->i_mount) - 1);
886 error = 0;
887out:
888 if (bp1)
889 xfs_da_buf_done(bp1);
890 if (bp2)
891 xfs_da_buf_done(bp2);
892 return(error);
893}
894
895
896/*========================================================================
897 * Routines used for growing the Btree.
898 *========================================================================*/
899
900/*
901 * Create the initial contents of a leaf attribute list
902 * or a leaf in a node attribute list.
903 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +1000904STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700905xfs_attr_leaf_create(xfs_da_args_t *args, xfs_dablk_t blkno, xfs_dabuf_t **bpp)
906{
907 xfs_attr_leafblock_t *leaf;
908 xfs_attr_leaf_hdr_t *hdr;
909 xfs_inode_t *dp;
910 xfs_dabuf_t *bp;
911 int error;
912
913 dp = args->dp;
914 ASSERT(dp != NULL);
915 error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp,
916 XFS_ATTR_FORK);
917 if (error)
918 return(error);
919 ASSERT(bp != NULL);
920 leaf = bp->data;
921 memset((char *)leaf, 0, XFS_LBSIZE(dp->i_mount));
922 hdr = &leaf->hdr;
923 INT_SET(hdr->info.magic, ARCH_CONVERT, XFS_ATTR_LEAF_MAGIC);
924 INT_SET(hdr->firstused, ARCH_CONVERT, XFS_LBSIZE(dp->i_mount));
925 if (!hdr->firstused) {
926 INT_SET(hdr->firstused, ARCH_CONVERT,
927 XFS_LBSIZE(dp->i_mount) - XFS_ATTR_LEAF_NAME_ALIGN);
928 }
929
930 INT_SET(hdr->freemap[0].base, ARCH_CONVERT,
931 sizeof(xfs_attr_leaf_hdr_t));
932 INT_SET(hdr->freemap[0].size, ARCH_CONVERT,
933 INT_GET(hdr->firstused, ARCH_CONVERT)
934 - INT_GET(hdr->freemap[0].base,
935 ARCH_CONVERT));
936
937 xfs_da_log_buf(args->trans, bp, 0, XFS_LBSIZE(dp->i_mount) - 1);
938
939 *bpp = bp;
940 return(0);
941}
942
943/*
944 * Split the leaf node, rebalance, then add the new entry.
945 */
946int
947xfs_attr_leaf_split(xfs_da_state_t *state, xfs_da_state_blk_t *oldblk,
948 xfs_da_state_blk_t *newblk)
949{
950 xfs_dablk_t blkno;
951 int error;
952
953 /*
954 * Allocate space for a new leaf node.
955 */
956 ASSERT(oldblk->magic == XFS_ATTR_LEAF_MAGIC);
957 error = xfs_da_grow_inode(state->args, &blkno);
958 if (error)
959 return(error);
960 error = xfs_attr_leaf_create(state->args, blkno, &newblk->bp);
961 if (error)
962 return(error);
963 newblk->blkno = blkno;
964 newblk->magic = XFS_ATTR_LEAF_MAGIC;
965
966 /*
967 * Rebalance the entries across the two leaves.
968 * NOTE: rebalance() currently depends on the 2nd block being empty.
969 */
970 xfs_attr_leaf_rebalance(state, oldblk, newblk);
971 error = xfs_da_blk_link(state, oldblk, newblk);
972 if (error)
973 return(error);
974
975 /*
976 * Save info on "old" attribute for "atomic rename" ops, leaf_add()
977 * modifies the index/blkno/rmtblk/rmtblkcnt fields to show the
978 * "new" attrs info. Will need the "old" info to remove it later.
979 *
980 * Insert the "new" entry in the correct block.
981 */
982 if (state->inleaf)
983 error = xfs_attr_leaf_add(oldblk->bp, state->args);
984 else
985 error = xfs_attr_leaf_add(newblk->bp, state->args);
986
987 /*
988 * Update last hashval in each block since we added the name.
989 */
990 oldblk->hashval = xfs_attr_leaf_lasthash(oldblk->bp, NULL);
991 newblk->hashval = xfs_attr_leaf_lasthash(newblk->bp, NULL);
992 return(error);
993}
994
995/*
996 * Add a name to the leaf attribute list structure.
997 */
998int
999xfs_attr_leaf_add(xfs_dabuf_t *bp, xfs_da_args_t *args)
1000{
1001 xfs_attr_leafblock_t *leaf;
1002 xfs_attr_leaf_hdr_t *hdr;
1003 xfs_attr_leaf_map_t *map;
1004 int tablesize, entsize, sum, tmp, i;
1005
1006 leaf = bp->data;
1007 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
1008 == XFS_ATTR_LEAF_MAGIC);
1009 ASSERT((args->index >= 0)
1010 && (args->index <= INT_GET(leaf->hdr.count, ARCH_CONVERT)));
1011 hdr = &leaf->hdr;
Nathan Scottaa82daa2005-11-02 10:33:33 +11001012 entsize = xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001013 args->trans->t_mountp->m_sb.sb_blocksize, NULL);
1014
1015 /*
1016 * Search through freemap for first-fit on new name length.
1017 * (may need to figure in size of entry struct too)
1018 */
1019 tablesize = (INT_GET(hdr->count, ARCH_CONVERT) + 1)
1020 * sizeof(xfs_attr_leaf_entry_t)
1021 + sizeof(xfs_attr_leaf_hdr_t);
1022 map = &hdr->freemap[XFS_ATTR_LEAF_MAPSIZE-1];
1023 for (sum = 0, i = XFS_ATTR_LEAF_MAPSIZE-1; i >= 0; map--, i--) {
1024 if (tablesize > INT_GET(hdr->firstused, ARCH_CONVERT)) {
1025 sum += INT_GET(map->size, ARCH_CONVERT);
1026 continue;
1027 }
1028 if (!map->size)
1029 continue; /* no space in this map */
1030 tmp = entsize;
1031 if (INT_GET(map->base, ARCH_CONVERT)
1032 < INT_GET(hdr->firstused, ARCH_CONVERT))
1033 tmp += sizeof(xfs_attr_leaf_entry_t);
1034 if (INT_GET(map->size, ARCH_CONVERT) >= tmp) {
1035 tmp = xfs_attr_leaf_add_work(bp, args, i);
1036 return(tmp);
1037 }
1038 sum += INT_GET(map->size, ARCH_CONVERT);
1039 }
1040
1041 /*
1042 * If there are no holes in the address space of the block,
1043 * and we don't have enough freespace, then compaction will do us
1044 * no good and we should just give up.
1045 */
1046 if (!hdr->holes && (sum < entsize))
1047 return(XFS_ERROR(ENOSPC));
1048
1049 /*
1050 * Compact the entries to coalesce free space.
1051 * This may change the hdr->count via dropping INCOMPLETE entries.
1052 */
1053 xfs_attr_leaf_compact(args->trans, bp);
1054
1055 /*
1056 * After compaction, the block is guaranteed to have only one
1057 * free region, in freemap[0]. If it is not big enough, give up.
1058 */
1059 if (INT_GET(hdr->freemap[0].size, ARCH_CONVERT)
1060 < (entsize + sizeof(xfs_attr_leaf_entry_t)))
1061 return(XFS_ERROR(ENOSPC));
1062
1063 return(xfs_attr_leaf_add_work(bp, args, 0));
1064}
1065
1066/*
1067 * Add a name to a leaf attribute list structure.
1068 */
1069STATIC int
1070xfs_attr_leaf_add_work(xfs_dabuf_t *bp, xfs_da_args_t *args, int mapindex)
1071{
1072 xfs_attr_leafblock_t *leaf;
1073 xfs_attr_leaf_hdr_t *hdr;
1074 xfs_attr_leaf_entry_t *entry;
1075 xfs_attr_leaf_name_local_t *name_loc;
1076 xfs_attr_leaf_name_remote_t *name_rmt;
1077 xfs_attr_leaf_map_t *map;
1078 xfs_mount_t *mp;
1079 int tmp, i;
1080
1081 leaf = bp->data;
1082 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
1083 == XFS_ATTR_LEAF_MAGIC);
1084 hdr = &leaf->hdr;
1085 ASSERT((mapindex >= 0) && (mapindex < XFS_ATTR_LEAF_MAPSIZE));
1086 ASSERT((args->index >= 0)
1087 && (args->index <= INT_GET(hdr->count, ARCH_CONVERT)));
1088
1089 /*
1090 * Force open some space in the entry array and fill it in.
1091 */
1092 entry = &leaf->entries[args->index];
1093 if (args->index < INT_GET(hdr->count, ARCH_CONVERT)) {
1094 tmp = INT_GET(hdr->count, ARCH_CONVERT) - args->index;
1095 tmp *= sizeof(xfs_attr_leaf_entry_t);
1096 memmove((char *)(entry+1), (char *)entry, tmp);
1097 xfs_da_log_buf(args->trans, bp,
1098 XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
1099 }
1100 INT_MOD(hdr->count, ARCH_CONVERT, 1);
1101
1102 /*
1103 * Allocate space for the new string (at the end of the run).
1104 */
1105 map = &hdr->freemap[mapindex];
1106 mp = args->trans->t_mountp;
1107 ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
1108 ASSERT((INT_GET(map->base, ARCH_CONVERT) & 0x3) == 0);
Nathan Scottaa82daa2005-11-02 10:33:33 +11001109 ASSERT(INT_GET(map->size, ARCH_CONVERT) >=
1110 xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
1111 mp->m_sb.sb_blocksize, NULL));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001112 ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
1113 ASSERT((INT_GET(map->size, ARCH_CONVERT) & 0x3) == 0);
1114 INT_MOD(map->size, ARCH_CONVERT,
Nathan Scottaa82daa2005-11-02 10:33:33 +11001115 -xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
1116 mp->m_sb.sb_blocksize, &tmp));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 INT_SET(entry->nameidx, ARCH_CONVERT,
1118 INT_GET(map->base, ARCH_CONVERT)
1119 + INT_GET(map->size, ARCH_CONVERT));
1120 INT_SET(entry->hashval, ARCH_CONVERT, args->hashval);
1121 entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
1122 entry->flags |= (args->flags & ATTR_SECURE) ? XFS_ATTR_SECURE :
1123 ((args->flags & ATTR_ROOT) ? XFS_ATTR_ROOT : 0);
1124 if (args->rename) {
1125 entry->flags |= XFS_ATTR_INCOMPLETE;
1126 if ((args->blkno2 == args->blkno) &&
1127 (args->index2 <= args->index)) {
1128 args->index2++;
1129 }
1130 }
1131 xfs_da_log_buf(args->trans, bp,
1132 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
1133 ASSERT((args->index == 0) || (INT_GET(entry->hashval, ARCH_CONVERT)
1134 >= INT_GET((entry-1)->hashval,
1135 ARCH_CONVERT)));
1136 ASSERT((args->index == INT_GET(hdr->count, ARCH_CONVERT)-1) ||
1137 (INT_GET(entry->hashval, ARCH_CONVERT)
1138 <= (INT_GET((entry+1)->hashval, ARCH_CONVERT))));
1139
1140 /*
1141 * Copy the attribute name and value into the new space.
1142 *
1143 * For "remote" attribute values, simply note that we need to
1144 * allocate space for the "remote" value. We can't actually
1145 * allocate the extents in this transaction, and we can't decide
1146 * which blocks they should be as we might allocate more blocks
1147 * as part of this transaction (a split operation for example).
1148 */
1149 if (entry->flags & XFS_ATTR_LOCAL) {
1150 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index);
1151 name_loc->namelen = args->namelen;
1152 INT_SET(name_loc->valuelen, ARCH_CONVERT, args->valuelen);
1153 memcpy((char *)name_loc->nameval, args->name, args->namelen);
1154 memcpy((char *)&name_loc->nameval[args->namelen], args->value,
1155 INT_GET(name_loc->valuelen, ARCH_CONVERT));
1156 } else {
1157 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
1158 name_rmt->namelen = args->namelen;
1159 memcpy((char *)name_rmt->name, args->name, args->namelen);
1160 entry->flags |= XFS_ATTR_INCOMPLETE;
1161 /* just in case */
1162 name_rmt->valuelen = 0;
1163 name_rmt->valueblk = 0;
1164 args->rmtblkno = 1;
1165 args->rmtblkcnt = XFS_B_TO_FSB(mp, args->valuelen);
1166 }
1167 xfs_da_log_buf(args->trans, bp,
1168 XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index),
1169 xfs_attr_leaf_entsize(leaf, args->index)));
1170
1171 /*
1172 * Update the control info for this leaf node
1173 */
1174 if (INT_GET(entry->nameidx, ARCH_CONVERT)
1175 < INT_GET(hdr->firstused, ARCH_CONVERT)) {
1176 /* both on-disk, don't endian-flip twice */
1177 hdr->firstused = entry->nameidx;
1178 }
1179 ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT)
1180 >= ((INT_GET(hdr->count, ARCH_CONVERT)
1181 * sizeof(*entry))+sizeof(*hdr)));
1182 tmp = (INT_GET(hdr->count, ARCH_CONVERT)-1)
1183 * sizeof(xfs_attr_leaf_entry_t)
1184 + sizeof(xfs_attr_leaf_hdr_t);
1185 map = &hdr->freemap[0];
1186 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) {
1187 if (INT_GET(map->base, ARCH_CONVERT) == tmp) {
1188 INT_MOD(map->base, ARCH_CONVERT,
1189 sizeof(xfs_attr_leaf_entry_t));
1190 INT_MOD(map->size, ARCH_CONVERT,
1191 -sizeof(xfs_attr_leaf_entry_t));
1192 }
1193 }
1194 INT_MOD(hdr->usedbytes, ARCH_CONVERT,
1195 xfs_attr_leaf_entsize(leaf, args->index));
1196 xfs_da_log_buf(args->trans, bp,
1197 XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr)));
1198 return(0);
1199}
1200
1201/*
1202 * Garbage collect a leaf attribute list block by copying it to a new buffer.
1203 */
1204STATIC void
1205xfs_attr_leaf_compact(xfs_trans_t *trans, xfs_dabuf_t *bp)
1206{
1207 xfs_attr_leafblock_t *leaf_s, *leaf_d;
1208 xfs_attr_leaf_hdr_t *hdr_s, *hdr_d;
1209 xfs_mount_t *mp;
1210 char *tmpbuffer;
1211
1212 mp = trans->t_mountp;
1213 tmpbuffer = kmem_alloc(XFS_LBSIZE(mp), KM_SLEEP);
1214 ASSERT(tmpbuffer != NULL);
1215 memcpy(tmpbuffer, bp->data, XFS_LBSIZE(mp));
1216 memset(bp->data, 0, XFS_LBSIZE(mp));
1217
1218 /*
1219 * Copy basic information
1220 */
1221 leaf_s = (xfs_attr_leafblock_t *)tmpbuffer;
1222 leaf_d = bp->data;
1223 hdr_s = &leaf_s->hdr;
1224 hdr_d = &leaf_d->hdr;
1225 hdr_d->info = hdr_s->info; /* struct copy */
1226 INT_SET(hdr_d->firstused, ARCH_CONVERT, XFS_LBSIZE(mp));
1227 /* handle truncation gracefully */
1228 if (!hdr_d->firstused) {
1229 INT_SET(hdr_d->firstused, ARCH_CONVERT,
1230 XFS_LBSIZE(mp) - XFS_ATTR_LEAF_NAME_ALIGN);
1231 }
1232 hdr_d->usedbytes = 0;
1233 hdr_d->count = 0;
1234 hdr_d->holes = 0;
1235 INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT,
1236 sizeof(xfs_attr_leaf_hdr_t));
1237 INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT,
1238 INT_GET(hdr_d->firstused, ARCH_CONVERT)
1239 - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
1240
1241 /*
1242 * Copy all entry's in the same (sorted) order,
1243 * but allocate name/value pairs packed and in sequence.
1244 */
1245 xfs_attr_leaf_moveents(leaf_s, 0, leaf_d, 0,
1246 (int)INT_GET(hdr_s->count, ARCH_CONVERT), mp);
1247
1248 xfs_da_log_buf(trans, bp, 0, XFS_LBSIZE(mp) - 1);
1249
1250 kmem_free(tmpbuffer, XFS_LBSIZE(mp));
1251}
1252
1253/*
1254 * Redistribute the attribute list entries between two leaf nodes,
1255 * taking into account the size of the new entry.
1256 *
1257 * NOTE: if new block is empty, then it will get the upper half of the
1258 * old block. At present, all (one) callers pass in an empty second block.
1259 *
1260 * This code adjusts the args->index/blkno and args->index2/blkno2 fields
1261 * to match what it is doing in splitting the attribute leaf block. Those
1262 * values are used in "atomic rename" operations on attributes. Note that
1263 * the "new" and "old" values can end up in different blocks.
1264 */
1265STATIC void
1266xfs_attr_leaf_rebalance(xfs_da_state_t *state, xfs_da_state_blk_t *blk1,
1267 xfs_da_state_blk_t *blk2)
1268{
1269 xfs_da_args_t *args;
1270 xfs_da_state_blk_t *tmp_blk;
1271 xfs_attr_leafblock_t *leaf1, *leaf2;
1272 xfs_attr_leaf_hdr_t *hdr1, *hdr2;
1273 int count, totallen, max, space, swap;
1274
1275 /*
1276 * Set up environment.
1277 */
1278 ASSERT(blk1->magic == XFS_ATTR_LEAF_MAGIC);
1279 ASSERT(blk2->magic == XFS_ATTR_LEAF_MAGIC);
1280 leaf1 = blk1->bp->data;
1281 leaf2 = blk2->bp->data;
1282 ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT)
1283 == XFS_ATTR_LEAF_MAGIC);
1284 ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT)
1285 == XFS_ATTR_LEAF_MAGIC);
1286 args = state->args;
1287
1288 /*
1289 * Check ordering of blocks, reverse if it makes things simpler.
1290 *
1291 * NOTE: Given that all (current) callers pass in an empty
1292 * second block, this code should never set "swap".
1293 */
1294 swap = 0;
1295 if (xfs_attr_leaf_order(blk1->bp, blk2->bp)) {
1296 tmp_blk = blk1;
1297 blk1 = blk2;
1298 blk2 = tmp_blk;
1299 leaf1 = blk1->bp->data;
1300 leaf2 = blk2->bp->data;
1301 swap = 1;
1302 }
1303 hdr1 = &leaf1->hdr;
1304 hdr2 = &leaf2->hdr;
1305
1306 /*
1307 * Examine entries until we reduce the absolute difference in
1308 * byte usage between the two blocks to a minimum. Then get
1309 * the direction to copy and the number of elements to move.
1310 *
1311 * "inleaf" is true if the new entry should be inserted into blk1.
1312 * If "swap" is also true, then reverse the sense of "inleaf".
1313 */
1314 state->inleaf = xfs_attr_leaf_figure_balance(state, blk1, blk2,
1315 &count, &totallen);
1316 if (swap)
1317 state->inleaf = !state->inleaf;
1318
1319 /*
1320 * Move any entries required from leaf to leaf:
1321 */
1322 if (count < INT_GET(hdr1->count, ARCH_CONVERT)) {
1323 /*
1324 * Figure the total bytes to be added to the destination leaf.
1325 */
1326 /* number entries being moved */
1327 count = INT_GET(hdr1->count, ARCH_CONVERT) - count;
1328 space = INT_GET(hdr1->usedbytes, ARCH_CONVERT) - totallen;
1329 space += count * sizeof(xfs_attr_leaf_entry_t);
1330
1331 /*
1332 * leaf2 is the destination, compact it if it looks tight.
1333 */
1334 max = INT_GET(hdr2->firstused, ARCH_CONVERT)
1335 - sizeof(xfs_attr_leaf_hdr_t);
1336 max -= INT_GET(hdr2->count, ARCH_CONVERT)
1337 * sizeof(xfs_attr_leaf_entry_t);
1338 if (space > max) {
1339 xfs_attr_leaf_compact(args->trans, blk2->bp);
1340 }
1341
1342 /*
1343 * Move high entries from leaf1 to low end of leaf2.
1344 */
1345 xfs_attr_leaf_moveents(leaf1,
1346 INT_GET(hdr1->count, ARCH_CONVERT)-count,
1347 leaf2, 0, count, state->mp);
1348
1349 xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1);
1350 xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1);
1351 } else if (count > INT_GET(hdr1->count, ARCH_CONVERT)) {
1352 /*
1353 * I assert that since all callers pass in an empty
1354 * second buffer, this code should never execute.
1355 */
1356
1357 /*
1358 * Figure the total bytes to be added to the destination leaf.
1359 */
1360 /* number entries being moved */
1361 count -= INT_GET(hdr1->count, ARCH_CONVERT);
1362 space = totallen - INT_GET(hdr1->usedbytes, ARCH_CONVERT);
1363 space += count * sizeof(xfs_attr_leaf_entry_t);
1364
1365 /*
1366 * leaf1 is the destination, compact it if it looks tight.
1367 */
1368 max = INT_GET(hdr1->firstused, ARCH_CONVERT)
1369 - sizeof(xfs_attr_leaf_hdr_t);
1370 max -= INT_GET(hdr1->count, ARCH_CONVERT)
1371 * sizeof(xfs_attr_leaf_entry_t);
1372 if (space > max) {
1373 xfs_attr_leaf_compact(args->trans, blk1->bp);
1374 }
1375
1376 /*
1377 * Move low entries from leaf2 to high end of leaf1.
1378 */
1379 xfs_attr_leaf_moveents(leaf2, 0, leaf1,
1380 (int)INT_GET(hdr1->count, ARCH_CONVERT), count,
1381 state->mp);
1382
1383 xfs_da_log_buf(args->trans, blk1->bp, 0, state->blocksize-1);
1384 xfs_da_log_buf(args->trans, blk2->bp, 0, state->blocksize-1);
1385 }
1386
1387 /*
1388 * Copy out last hashval in each block for B-tree code.
1389 */
1390 blk1->hashval =
1391 INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count,
1392 ARCH_CONVERT)-1].hashval, ARCH_CONVERT);
1393 blk2->hashval =
1394 INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count,
1395 ARCH_CONVERT)-1].hashval, ARCH_CONVERT);
1396
1397 /*
1398 * Adjust the expected index for insertion.
1399 * NOTE: this code depends on the (current) situation that the
1400 * second block was originally empty.
1401 *
1402 * If the insertion point moved to the 2nd block, we must adjust
1403 * the index. We must also track the entry just following the
1404 * new entry for use in an "atomic rename" operation, that entry
1405 * is always the "old" entry and the "new" entry is what we are
1406 * inserting. The index/blkno fields refer to the "old" entry,
1407 * while the index2/blkno2 fields refer to the "new" entry.
1408 */
1409 if (blk1->index > INT_GET(leaf1->hdr.count, ARCH_CONVERT)) {
1410 ASSERT(state->inleaf == 0);
1411 blk2->index = blk1->index
1412 - INT_GET(leaf1->hdr.count, ARCH_CONVERT);
1413 args->index = args->index2 = blk2->index;
1414 args->blkno = args->blkno2 = blk2->blkno;
1415 } else if (blk1->index == INT_GET(leaf1->hdr.count, ARCH_CONVERT)) {
1416 if (state->inleaf) {
1417 args->index = blk1->index;
1418 args->blkno = blk1->blkno;
1419 args->index2 = 0;
1420 args->blkno2 = blk2->blkno;
1421 } else {
1422 blk2->index = blk1->index
1423 - INT_GET(leaf1->hdr.count, ARCH_CONVERT);
1424 args->index = args->index2 = blk2->index;
1425 args->blkno = args->blkno2 = blk2->blkno;
1426 }
1427 } else {
1428 ASSERT(state->inleaf == 1);
1429 args->index = args->index2 = blk1->index;
1430 args->blkno = args->blkno2 = blk1->blkno;
1431 }
1432}
1433
1434/*
1435 * Examine entries until we reduce the absolute difference in
1436 * byte usage between the two blocks to a minimum.
1437 * GROT: Is this really necessary? With other than a 512 byte blocksize,
1438 * GROT: there will always be enough room in either block for a new entry.
1439 * GROT: Do a double-split for this case?
1440 */
1441STATIC int
1442xfs_attr_leaf_figure_balance(xfs_da_state_t *state,
1443 xfs_da_state_blk_t *blk1,
1444 xfs_da_state_blk_t *blk2,
1445 int *countarg, int *usedbytesarg)
1446{
1447 xfs_attr_leafblock_t *leaf1, *leaf2;
1448 xfs_attr_leaf_hdr_t *hdr1, *hdr2;
1449 xfs_attr_leaf_entry_t *entry;
1450 int count, max, index, totallen, half;
1451 int lastdelta, foundit, tmp;
1452
1453 /*
1454 * Set up environment.
1455 */
1456 leaf1 = blk1->bp->data;
1457 leaf2 = blk2->bp->data;
1458 hdr1 = &leaf1->hdr;
1459 hdr2 = &leaf2->hdr;
1460 foundit = 0;
1461 totallen = 0;
1462
1463 /*
1464 * Examine entries until we reduce the absolute difference in
1465 * byte usage between the two blocks to a minimum.
1466 */
1467 max = INT_GET(hdr1->count, ARCH_CONVERT)
1468 + INT_GET(hdr2->count, ARCH_CONVERT);
1469 half = (max+1) * sizeof(*entry);
1470 half += INT_GET(hdr1->usedbytes, ARCH_CONVERT)
1471 + INT_GET(hdr2->usedbytes, ARCH_CONVERT)
Nathan Scottaa82daa2005-11-02 10:33:33 +11001472 + xfs_attr_leaf_newentsize(
1473 state->args->namelen,
1474 state->args->valuelen,
1475 state->blocksize, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001476 half /= 2;
1477 lastdelta = state->blocksize;
1478 entry = &leaf1->entries[0];
1479 for (count = index = 0; count < max; entry++, index++, count++) {
1480
1481#define XFS_ATTR_ABS(A) (((A) < 0) ? -(A) : (A))
1482 /*
1483 * The new entry is in the first block, account for it.
1484 */
1485 if (count == blk1->index) {
1486 tmp = totallen + sizeof(*entry) +
Nathan Scottaa82daa2005-11-02 10:33:33 +11001487 xfs_attr_leaf_newentsize(
1488 state->args->namelen,
1489 state->args->valuelen,
1490 state->blocksize, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001491 if (XFS_ATTR_ABS(half - tmp) > lastdelta)
1492 break;
1493 lastdelta = XFS_ATTR_ABS(half - tmp);
1494 totallen = tmp;
1495 foundit = 1;
1496 }
1497
1498 /*
1499 * Wrap around into the second block if necessary.
1500 */
1501 if (count == INT_GET(hdr1->count, ARCH_CONVERT)) {
1502 leaf1 = leaf2;
1503 entry = &leaf1->entries[0];
1504 index = 0;
1505 }
1506
1507 /*
1508 * Figure out if next leaf entry would be too much.
1509 */
1510 tmp = totallen + sizeof(*entry) + xfs_attr_leaf_entsize(leaf1,
1511 index);
1512 if (XFS_ATTR_ABS(half - tmp) > lastdelta)
1513 break;
1514 lastdelta = XFS_ATTR_ABS(half - tmp);
1515 totallen = tmp;
1516#undef XFS_ATTR_ABS
1517 }
1518
1519 /*
1520 * Calculate the number of usedbytes that will end up in lower block.
1521 * If new entry not in lower block, fix up the count.
1522 */
1523 totallen -= count * sizeof(*entry);
1524 if (foundit) {
1525 totallen -= sizeof(*entry) +
Nathan Scottaa82daa2005-11-02 10:33:33 +11001526 xfs_attr_leaf_newentsize(
1527 state->args->namelen,
1528 state->args->valuelen,
1529 state->blocksize, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001530 }
1531
1532 *countarg = count;
1533 *usedbytesarg = totallen;
1534 return(foundit);
1535}
1536
1537/*========================================================================
1538 * Routines used for shrinking the Btree.
1539 *========================================================================*/
1540
1541/*
1542 * Check a leaf block and its neighbors to see if the block should be
1543 * collapsed into one or the other neighbor. Always keep the block
1544 * with the smaller block number.
1545 * If the current block is over 50% full, don't try to join it, return 0.
1546 * If the block is empty, fill in the state structure and return 2.
1547 * If it can be collapsed, fill in the state structure and return 1.
1548 * If nothing can be done, return 0.
1549 *
1550 * GROT: allow for INCOMPLETE entries in calculation.
1551 */
1552int
1553xfs_attr_leaf_toosmall(xfs_da_state_t *state, int *action)
1554{
1555 xfs_attr_leafblock_t *leaf;
1556 xfs_da_state_blk_t *blk;
1557 xfs_da_blkinfo_t *info;
1558 int count, bytes, forward, error, retval, i;
1559 xfs_dablk_t blkno;
1560 xfs_dabuf_t *bp;
1561
1562 /*
1563 * Check for the degenerate case of the block being over 50% full.
1564 * If so, it's not worth even looking to see if we might be able
1565 * to coalesce with a sibling.
1566 */
1567 blk = &state->path.blk[ state->path.active-1 ];
1568 info = blk->bp->data;
1569 ASSERT(INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC);
1570 leaf = (xfs_attr_leafblock_t *)info;
1571 count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
1572 bytes = sizeof(xfs_attr_leaf_hdr_t) +
1573 count * sizeof(xfs_attr_leaf_entry_t) +
1574 INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT);
1575 if (bytes > (state->blocksize >> 1)) {
1576 *action = 0; /* blk over 50%, don't try to join */
1577 return(0);
1578 }
1579
1580 /*
1581 * Check for the degenerate case of the block being empty.
1582 * If the block is empty, we'll simply delete it, no need to
1583 * coalesce it with a sibling block. We choose (aribtrarily)
1584 * to merge with the forward block unless it is NULL.
1585 */
1586 if (count == 0) {
1587 /*
1588 * Make altpath point to the block we want to keep and
1589 * path point to the block we want to drop (this one).
1590 */
1591 forward = info->forw;
1592 memcpy(&state->altpath, &state->path, sizeof(state->path));
1593 error = xfs_da_path_shift(state, &state->altpath, forward,
1594 0, &retval);
1595 if (error)
1596 return(error);
1597 if (retval) {
1598 *action = 0;
1599 } else {
1600 *action = 2;
1601 }
1602 return(0);
1603 }
1604
1605 /*
1606 * Examine each sibling block to see if we can coalesce with
1607 * at least 25% free space to spare. We need to figure out
1608 * whether to merge with the forward or the backward block.
1609 * We prefer coalescing with the lower numbered sibling so as
1610 * to shrink an attribute list over time.
1611 */
1612 /* start with smaller blk num */
1613 forward = (INT_GET(info->forw, ARCH_CONVERT)
1614 < INT_GET(info->back, ARCH_CONVERT));
1615 for (i = 0; i < 2; forward = !forward, i++) {
1616 if (forward)
1617 blkno = INT_GET(info->forw, ARCH_CONVERT);
1618 else
1619 blkno = INT_GET(info->back, ARCH_CONVERT);
1620 if (blkno == 0)
1621 continue;
1622 error = xfs_da_read_buf(state->args->trans, state->args->dp,
1623 blkno, -1, &bp, XFS_ATTR_FORK);
1624 if (error)
1625 return(error);
1626 ASSERT(bp != NULL);
1627
1628 leaf = (xfs_attr_leafblock_t *)info;
1629 count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
1630 bytes = state->blocksize - (state->blocksize>>2);
1631 bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT);
1632 leaf = bp->data;
1633 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
1634 == XFS_ATTR_LEAF_MAGIC);
1635 count += INT_GET(leaf->hdr.count, ARCH_CONVERT);
1636 bytes -= INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT);
1637 bytes -= count * sizeof(xfs_attr_leaf_entry_t);
1638 bytes -= sizeof(xfs_attr_leaf_hdr_t);
1639 xfs_da_brelse(state->args->trans, bp);
1640 if (bytes >= 0)
1641 break; /* fits with at least 25% to spare */
1642 }
1643 if (i >= 2) {
1644 *action = 0;
1645 return(0);
1646 }
1647
1648 /*
1649 * Make altpath point to the block we want to keep (the lower
1650 * numbered block) and path point to the block we want to drop.
1651 */
1652 memcpy(&state->altpath, &state->path, sizeof(state->path));
1653 if (blkno < blk->blkno) {
1654 error = xfs_da_path_shift(state, &state->altpath, forward,
1655 0, &retval);
1656 } else {
1657 error = xfs_da_path_shift(state, &state->path, forward,
1658 0, &retval);
1659 }
1660 if (error)
1661 return(error);
1662 if (retval) {
1663 *action = 0;
1664 } else {
1665 *action = 1;
1666 }
1667 return(0);
1668}
1669
1670/*
1671 * Remove a name from the leaf attribute list structure.
1672 *
1673 * Return 1 if leaf is less than 37% full, 0 if >= 37% full.
1674 * If two leaves are 37% full, when combined they will leave 25% free.
1675 */
1676int
1677xfs_attr_leaf_remove(xfs_dabuf_t *bp, xfs_da_args_t *args)
1678{
1679 xfs_attr_leafblock_t *leaf;
1680 xfs_attr_leaf_hdr_t *hdr;
1681 xfs_attr_leaf_map_t *map;
1682 xfs_attr_leaf_entry_t *entry;
1683 int before, after, smallest, entsize;
1684 int tablesize, tmp, i;
1685 xfs_mount_t *mp;
1686
1687 leaf = bp->data;
1688 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
1689 == XFS_ATTR_LEAF_MAGIC);
1690 hdr = &leaf->hdr;
1691 mp = args->trans->t_mountp;
1692 ASSERT((INT_GET(hdr->count, ARCH_CONVERT) > 0)
1693 && (INT_GET(hdr->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8)));
1694 ASSERT((args->index >= 0)
1695 && (args->index < INT_GET(hdr->count, ARCH_CONVERT)));
1696 ASSERT(INT_GET(hdr->firstused, ARCH_CONVERT)
1697 >= ((INT_GET(hdr->count, ARCH_CONVERT)
1698 * sizeof(*entry))+sizeof(*hdr)));
1699 entry = &leaf->entries[args->index];
1700 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT)
1701 >= INT_GET(hdr->firstused, ARCH_CONVERT));
1702 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT) < XFS_LBSIZE(mp));
1703
1704 /*
1705 * Scan through free region table:
1706 * check for adjacency of free'd entry with an existing one,
1707 * find smallest free region in case we need to replace it,
1708 * adjust any map that borders the entry table,
1709 */
1710 tablesize = INT_GET(hdr->count, ARCH_CONVERT)
1711 * sizeof(xfs_attr_leaf_entry_t)
1712 + sizeof(xfs_attr_leaf_hdr_t);
1713 map = &hdr->freemap[0];
1714 tmp = INT_GET(map->size, ARCH_CONVERT);
1715 before = after = -1;
1716 smallest = XFS_ATTR_LEAF_MAPSIZE - 1;
1717 entsize = xfs_attr_leaf_entsize(leaf, args->index);
1718 for (i = 0; i < XFS_ATTR_LEAF_MAPSIZE; map++, i++) {
1719 ASSERT(INT_GET(map->base, ARCH_CONVERT) < XFS_LBSIZE(mp));
1720 ASSERT(INT_GET(map->size, ARCH_CONVERT) < XFS_LBSIZE(mp));
1721 if (INT_GET(map->base, ARCH_CONVERT) == tablesize) {
1722 INT_MOD(map->base, ARCH_CONVERT,
1723 -sizeof(xfs_attr_leaf_entry_t));
1724 INT_MOD(map->size, ARCH_CONVERT,
1725 sizeof(xfs_attr_leaf_entry_t));
1726 }
1727
1728 if ((INT_GET(map->base, ARCH_CONVERT)
1729 + INT_GET(map->size, ARCH_CONVERT))
1730 == INT_GET(entry->nameidx, ARCH_CONVERT)) {
1731 before = i;
1732 } else if (INT_GET(map->base, ARCH_CONVERT)
1733 == (INT_GET(entry->nameidx, ARCH_CONVERT) + entsize)) {
1734 after = i;
1735 } else if (INT_GET(map->size, ARCH_CONVERT) < tmp) {
1736 tmp = INT_GET(map->size, ARCH_CONVERT);
1737 smallest = i;
1738 }
1739 }
1740
1741 /*
1742 * Coalesce adjacent freemap regions,
1743 * or replace the smallest region.
1744 */
1745 if ((before >= 0) || (after >= 0)) {
1746 if ((before >= 0) && (after >= 0)) {
1747 map = &hdr->freemap[before];
1748 INT_MOD(map->size, ARCH_CONVERT, entsize);
1749 INT_MOD(map->size, ARCH_CONVERT,
1750 INT_GET(hdr->freemap[after].size,
1751 ARCH_CONVERT));
1752 hdr->freemap[after].base = 0;
1753 hdr->freemap[after].size = 0;
1754 } else if (before >= 0) {
1755 map = &hdr->freemap[before];
1756 INT_MOD(map->size, ARCH_CONVERT, entsize);
1757 } else {
1758 map = &hdr->freemap[after];
1759 /* both on-disk, don't endian flip twice */
1760 map->base = entry->nameidx;
1761 INT_MOD(map->size, ARCH_CONVERT, entsize);
1762 }
1763 } else {
1764 /*
1765 * Replace smallest region (if it is smaller than free'd entry)
1766 */
1767 map = &hdr->freemap[smallest];
1768 if (INT_GET(map->size, ARCH_CONVERT) < entsize) {
1769 INT_SET(map->base, ARCH_CONVERT,
1770 INT_GET(entry->nameidx, ARCH_CONVERT));
1771 INT_SET(map->size, ARCH_CONVERT, entsize);
1772 }
1773 }
1774
1775 /*
1776 * Did we remove the first entry?
1777 */
1778 if (INT_GET(entry->nameidx, ARCH_CONVERT)
1779 == INT_GET(hdr->firstused, ARCH_CONVERT))
1780 smallest = 1;
1781 else
1782 smallest = 0;
1783
1784 /*
1785 * Compress the remaining entries and zero out the removed stuff.
1786 */
1787 memset(XFS_ATTR_LEAF_NAME(leaf, args->index), 0, entsize);
1788 INT_MOD(hdr->usedbytes, ARCH_CONVERT, -entsize);
1789 xfs_da_log_buf(args->trans, bp,
1790 XFS_DA_LOGRANGE(leaf, XFS_ATTR_LEAF_NAME(leaf, args->index),
1791 entsize));
1792
1793 tmp = (INT_GET(hdr->count, ARCH_CONVERT) - args->index)
1794 * sizeof(xfs_attr_leaf_entry_t);
1795 memmove((char *)entry, (char *)(entry+1), tmp);
1796 INT_MOD(hdr->count, ARCH_CONVERT, -1);
1797 xfs_da_log_buf(args->trans, bp,
1798 XFS_DA_LOGRANGE(leaf, entry, tmp + sizeof(*entry)));
1799 entry = &leaf->entries[INT_GET(hdr->count, ARCH_CONVERT)];
1800 memset((char *)entry, 0, sizeof(xfs_attr_leaf_entry_t));
1801
1802 /*
1803 * If we removed the first entry, re-find the first used byte
1804 * in the name area. Note that if the entry was the "firstused",
1805 * then we don't have a "hole" in our block resulting from
1806 * removing the name.
1807 */
1808 if (smallest) {
1809 tmp = XFS_LBSIZE(mp);
1810 entry = &leaf->entries[0];
1811 for (i = INT_GET(hdr->count, ARCH_CONVERT)-1;
1812 i >= 0; entry++, i--) {
1813 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT)
1814 >= INT_GET(hdr->firstused, ARCH_CONVERT));
1815 ASSERT(INT_GET(entry->nameidx, ARCH_CONVERT)
1816 < XFS_LBSIZE(mp));
1817 if (INT_GET(entry->nameidx, ARCH_CONVERT) < tmp)
1818 tmp = INT_GET(entry->nameidx, ARCH_CONVERT);
1819 }
1820 INT_SET(hdr->firstused, ARCH_CONVERT, tmp);
1821 if (!hdr->firstused) {
1822 INT_SET(hdr->firstused, ARCH_CONVERT,
1823 tmp - XFS_ATTR_LEAF_NAME_ALIGN);
1824 }
1825 } else {
1826 hdr->holes = 1; /* mark as needing compaction */
1827 }
1828 xfs_da_log_buf(args->trans, bp,
1829 XFS_DA_LOGRANGE(leaf, hdr, sizeof(*hdr)));
1830
1831 /*
1832 * Check if leaf is less than 50% full, caller may want to
1833 * "join" the leaf with a sibling if so.
1834 */
1835 tmp = sizeof(xfs_attr_leaf_hdr_t);
1836 tmp += INT_GET(leaf->hdr.count, ARCH_CONVERT)
1837 * sizeof(xfs_attr_leaf_entry_t);
1838 tmp += INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT);
1839 return(tmp < mp->m_attr_magicpct); /* leaf is < 37% full */
1840}
1841
1842/*
1843 * Move all the attribute list entries from drop_leaf into save_leaf.
1844 */
1845void
1846xfs_attr_leaf_unbalance(xfs_da_state_t *state, xfs_da_state_blk_t *drop_blk,
1847 xfs_da_state_blk_t *save_blk)
1848{
1849 xfs_attr_leafblock_t *drop_leaf, *save_leaf, *tmp_leaf;
1850 xfs_attr_leaf_hdr_t *drop_hdr, *save_hdr, *tmp_hdr;
1851 xfs_mount_t *mp;
1852 char *tmpbuffer;
1853
1854 /*
1855 * Set up environment.
1856 */
1857 mp = state->mp;
1858 ASSERT(drop_blk->magic == XFS_ATTR_LEAF_MAGIC);
1859 ASSERT(save_blk->magic == XFS_ATTR_LEAF_MAGIC);
1860 drop_leaf = drop_blk->bp->data;
1861 save_leaf = save_blk->bp->data;
1862 ASSERT(INT_GET(drop_leaf->hdr.info.magic, ARCH_CONVERT)
1863 == XFS_ATTR_LEAF_MAGIC);
1864 ASSERT(INT_GET(save_leaf->hdr.info.magic, ARCH_CONVERT)
1865 == XFS_ATTR_LEAF_MAGIC);
1866 drop_hdr = &drop_leaf->hdr;
1867 save_hdr = &save_leaf->hdr;
1868
1869 /*
1870 * Save last hashval from dying block for later Btree fixup.
1871 */
1872 drop_blk->hashval =
1873 INT_GET(drop_leaf->entries[INT_GET(drop_leaf->hdr.count,
1874 ARCH_CONVERT)-1].hashval,
1875 ARCH_CONVERT);
1876
1877 /*
1878 * Check if we need a temp buffer, or can we do it in place.
1879 * Note that we don't check "leaf" for holes because we will
1880 * always be dropping it, toosmall() decided that for us already.
1881 */
1882 if (save_hdr->holes == 0) {
1883 /*
1884 * dest leaf has no holes, so we add there. May need
1885 * to make some room in the entry array.
1886 */
1887 if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) {
1888 xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf, 0,
1889 (int)INT_GET(drop_hdr->count, ARCH_CONVERT), mp);
1890 } else {
1891 xfs_attr_leaf_moveents(drop_leaf, 0, save_leaf,
1892 INT_GET(save_hdr->count, ARCH_CONVERT),
1893 (int)INT_GET(drop_hdr->count, ARCH_CONVERT),
1894 mp);
1895 }
1896 } else {
1897 /*
1898 * Destination has holes, so we make a temporary copy
1899 * of the leaf and add them both to that.
1900 */
1901 tmpbuffer = kmem_alloc(state->blocksize, KM_SLEEP);
1902 ASSERT(tmpbuffer != NULL);
1903 memset(tmpbuffer, 0, state->blocksize);
1904 tmp_leaf = (xfs_attr_leafblock_t *)tmpbuffer;
1905 tmp_hdr = &tmp_leaf->hdr;
1906 tmp_hdr->info = save_hdr->info; /* struct copy */
1907 tmp_hdr->count = 0;
1908 INT_SET(tmp_hdr->firstused, ARCH_CONVERT, state->blocksize);
1909 if (!tmp_hdr->firstused) {
1910 INT_SET(tmp_hdr->firstused, ARCH_CONVERT,
1911 state->blocksize - XFS_ATTR_LEAF_NAME_ALIGN);
1912 }
1913 tmp_hdr->usedbytes = 0;
1914 if (xfs_attr_leaf_order(save_blk->bp, drop_blk->bp)) {
1915 xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf, 0,
1916 (int)INT_GET(drop_hdr->count, ARCH_CONVERT),
1917 mp);
1918 xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf,
1919 INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT),
1920 (int)INT_GET(save_hdr->count, ARCH_CONVERT),
1921 mp);
1922 } else {
1923 xfs_attr_leaf_moveents(save_leaf, 0, tmp_leaf, 0,
1924 (int)INT_GET(save_hdr->count, ARCH_CONVERT),
1925 mp);
1926 xfs_attr_leaf_moveents(drop_leaf, 0, tmp_leaf,
1927 INT_GET(tmp_leaf->hdr.count, ARCH_CONVERT),
1928 (int)INT_GET(drop_hdr->count, ARCH_CONVERT),
1929 mp);
1930 }
1931 memcpy((char *)save_leaf, (char *)tmp_leaf, state->blocksize);
1932 kmem_free(tmpbuffer, state->blocksize);
1933 }
1934
1935 xfs_da_log_buf(state->args->trans, save_blk->bp, 0,
1936 state->blocksize - 1);
1937
1938 /*
1939 * Copy out last hashval in each block for B-tree code.
1940 */
1941 save_blk->hashval =
1942 INT_GET(save_leaf->entries[INT_GET(save_leaf->hdr.count,
1943 ARCH_CONVERT)-1].hashval,
1944 ARCH_CONVERT);
1945}
1946
1947/*========================================================================
1948 * Routines used for finding things in the Btree.
1949 *========================================================================*/
1950
1951/*
1952 * Look up a name in a leaf attribute list structure.
1953 * This is the internal routine, it uses the caller's buffer.
1954 *
1955 * Note that duplicate keys are allowed, but only check within the
1956 * current leaf node. The Btree code must check in adjacent leaf nodes.
1957 *
1958 * Return in args->index the index into the entry[] array of either
1959 * the found entry, or where the entry should have been (insert before
1960 * that entry).
1961 *
1962 * Don't change the args->value unless we find the attribute.
1963 */
1964int
1965xfs_attr_leaf_lookup_int(xfs_dabuf_t *bp, xfs_da_args_t *args)
1966{
1967 xfs_attr_leafblock_t *leaf;
1968 xfs_attr_leaf_entry_t *entry;
1969 xfs_attr_leaf_name_local_t *name_loc;
1970 xfs_attr_leaf_name_remote_t *name_rmt;
1971 int probe, span;
1972 xfs_dahash_t hashval;
1973
1974 leaf = bp->data;
1975 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
1976 == XFS_ATTR_LEAF_MAGIC);
1977 ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT)
1978 < (XFS_LBSIZE(args->dp->i_mount)/8));
1979
1980 /*
1981 * Binary search. (note: small blocks will skip this loop)
1982 */
1983 hashval = args->hashval;
1984 probe = span = INT_GET(leaf->hdr.count, ARCH_CONVERT) / 2;
1985 for (entry = &leaf->entries[probe]; span > 4;
1986 entry = &leaf->entries[probe]) {
1987 span /= 2;
1988 if (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)
1989 probe += span;
1990 else if (INT_GET(entry->hashval, ARCH_CONVERT) > hashval)
1991 probe -= span;
1992 else
1993 break;
1994 }
1995 ASSERT((probe >= 0) &&
1996 (!leaf->hdr.count
1997 || (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))));
1998 ASSERT((span <= 4) || (INT_GET(entry->hashval, ARCH_CONVERT)
1999 == hashval));
2000
2001 /*
2002 * Since we may have duplicate hashval's, find the first matching
2003 * hashval in the leaf.
2004 */
2005 while ((probe > 0) && (INT_GET(entry->hashval, ARCH_CONVERT)
2006 >= hashval)) {
2007 entry--;
2008 probe--;
2009 }
2010 while ((probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))
2011 && (INT_GET(entry->hashval, ARCH_CONVERT) < hashval)) {
2012 entry++;
2013 probe++;
2014 }
2015 if ((probe == INT_GET(leaf->hdr.count, ARCH_CONVERT))
2016 || (INT_GET(entry->hashval, ARCH_CONVERT) != hashval)) {
2017 args->index = probe;
2018 return(XFS_ERROR(ENOATTR));
2019 }
2020
2021 /*
2022 * Duplicate keys may be present, so search all of them for a match.
2023 */
2024 for ( ; (probe < INT_GET(leaf->hdr.count, ARCH_CONVERT))
2025 && (INT_GET(entry->hashval, ARCH_CONVERT) == hashval);
2026 entry++, probe++) {
2027/*
2028 * GROT: Add code to remove incomplete entries.
2029 */
2030 /*
2031 * If we are looking for INCOMPLETE entries, show only those.
2032 * If we are looking for complete entries, show only those.
2033 */
2034 if ((args->flags & XFS_ATTR_INCOMPLETE) !=
2035 (entry->flags & XFS_ATTR_INCOMPLETE)) {
2036 continue;
2037 }
2038 if (entry->flags & XFS_ATTR_LOCAL) {
2039 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, probe);
2040 if (name_loc->namelen != args->namelen)
2041 continue;
2042 if (memcmp(args->name, (char *)name_loc->nameval,
2043 args->namelen) != 0)
2044 continue;
2045 if (((args->flags & ATTR_SECURE) != 0) !=
2046 ((entry->flags & XFS_ATTR_SECURE) != 0))
2047 continue;
2048 if (((args->flags & ATTR_ROOT) != 0) !=
2049 ((entry->flags & XFS_ATTR_ROOT) != 0))
2050 continue;
2051 args->index = probe;
2052 return(XFS_ERROR(EEXIST));
2053 } else {
2054 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, probe);
2055 if (name_rmt->namelen != args->namelen)
2056 continue;
2057 if (memcmp(args->name, (char *)name_rmt->name,
2058 args->namelen) != 0)
2059 continue;
2060 if (((args->flags & ATTR_SECURE) != 0) !=
2061 ((entry->flags & XFS_ATTR_SECURE) != 0))
2062 continue;
2063 if (((args->flags & ATTR_ROOT) != 0) !=
2064 ((entry->flags & XFS_ATTR_ROOT) != 0))
2065 continue;
2066 args->index = probe;
2067 args->rmtblkno
2068 = INT_GET(name_rmt->valueblk, ARCH_CONVERT);
2069 args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount,
2070 INT_GET(name_rmt->valuelen,
2071 ARCH_CONVERT));
2072 return(XFS_ERROR(EEXIST));
2073 }
2074 }
2075 args->index = probe;
2076 return(XFS_ERROR(ENOATTR));
2077}
2078
2079/*
2080 * Get the value associated with an attribute name from a leaf attribute
2081 * list structure.
2082 */
2083int
2084xfs_attr_leaf_getvalue(xfs_dabuf_t *bp, xfs_da_args_t *args)
2085{
2086 int valuelen;
2087 xfs_attr_leafblock_t *leaf;
2088 xfs_attr_leaf_entry_t *entry;
2089 xfs_attr_leaf_name_local_t *name_loc;
2090 xfs_attr_leaf_name_remote_t *name_rmt;
2091
2092 leaf = bp->data;
2093 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
2094 == XFS_ATTR_LEAF_MAGIC);
2095 ASSERT(INT_GET(leaf->hdr.count, ARCH_CONVERT)
2096 < (XFS_LBSIZE(args->dp->i_mount)/8));
2097 ASSERT(args->index < ((int)INT_GET(leaf->hdr.count, ARCH_CONVERT)));
2098
2099 entry = &leaf->entries[args->index];
2100 if (entry->flags & XFS_ATTR_LOCAL) {
2101 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index);
2102 ASSERT(name_loc->namelen == args->namelen);
2103 ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0);
2104 valuelen = INT_GET(name_loc->valuelen, ARCH_CONVERT);
2105 if (args->flags & ATTR_KERNOVAL) {
2106 args->valuelen = valuelen;
2107 return(0);
2108 }
2109 if (args->valuelen < valuelen) {
2110 args->valuelen = valuelen;
2111 return(XFS_ERROR(ERANGE));
2112 }
2113 args->valuelen = valuelen;
2114 memcpy(args->value, &name_loc->nameval[args->namelen], valuelen);
2115 } else {
2116 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
2117 ASSERT(name_rmt->namelen == args->namelen);
2118 ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0);
2119 valuelen = INT_GET(name_rmt->valuelen, ARCH_CONVERT);
2120 args->rmtblkno = INT_GET(name_rmt->valueblk, ARCH_CONVERT);
2121 args->rmtblkcnt = XFS_B_TO_FSB(args->dp->i_mount, valuelen);
2122 if (args->flags & ATTR_KERNOVAL) {
2123 args->valuelen = valuelen;
2124 return(0);
2125 }
2126 if (args->valuelen < valuelen) {
2127 args->valuelen = valuelen;
2128 return(XFS_ERROR(ERANGE));
2129 }
2130 args->valuelen = valuelen;
2131 }
2132 return(0);
2133}
2134
2135/*========================================================================
2136 * Utility routines.
2137 *========================================================================*/
2138
2139/*
2140 * Move the indicated entries from one leaf to another.
2141 * NOTE: this routine modifies both source and destination leaves.
2142 */
2143/*ARGSUSED*/
2144STATIC void
2145xfs_attr_leaf_moveents(xfs_attr_leafblock_t *leaf_s, int start_s,
2146 xfs_attr_leafblock_t *leaf_d, int start_d,
2147 int count, xfs_mount_t *mp)
2148{
2149 xfs_attr_leaf_hdr_t *hdr_s, *hdr_d;
2150 xfs_attr_leaf_entry_t *entry_s, *entry_d;
2151 int desti, tmp, i;
2152
2153 /*
2154 * Check for nothing to do.
2155 */
2156 if (count == 0)
2157 return;
2158
2159 /*
2160 * Set up environment.
2161 */
2162 ASSERT(INT_GET(leaf_s->hdr.info.magic, ARCH_CONVERT)
2163 == XFS_ATTR_LEAF_MAGIC);
2164 ASSERT(INT_GET(leaf_d->hdr.info.magic, ARCH_CONVERT)
2165 == XFS_ATTR_LEAF_MAGIC);
2166 hdr_s = &leaf_s->hdr;
2167 hdr_d = &leaf_d->hdr;
2168 ASSERT((INT_GET(hdr_s->count, ARCH_CONVERT) > 0)
2169 && (INT_GET(hdr_s->count, ARCH_CONVERT)
2170 < (XFS_LBSIZE(mp)/8)));
2171 ASSERT(INT_GET(hdr_s->firstused, ARCH_CONVERT) >=
2172 ((INT_GET(hdr_s->count, ARCH_CONVERT)
2173 * sizeof(*entry_s))+sizeof(*hdr_s)));
2174 ASSERT(INT_GET(hdr_d->count, ARCH_CONVERT) < (XFS_LBSIZE(mp)/8));
2175 ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >=
2176 ((INT_GET(hdr_d->count, ARCH_CONVERT)
2177 * sizeof(*entry_d))+sizeof(*hdr_d)));
2178
2179 ASSERT(start_s < INT_GET(hdr_s->count, ARCH_CONVERT));
2180 ASSERT(start_d <= INT_GET(hdr_d->count, ARCH_CONVERT));
2181 ASSERT(count <= INT_GET(hdr_s->count, ARCH_CONVERT));
2182
2183 /*
2184 * Move the entries in the destination leaf up to make a hole?
2185 */
2186 if (start_d < INT_GET(hdr_d->count, ARCH_CONVERT)) {
2187 tmp = INT_GET(hdr_d->count, ARCH_CONVERT) - start_d;
2188 tmp *= sizeof(xfs_attr_leaf_entry_t);
2189 entry_s = &leaf_d->entries[start_d];
2190 entry_d = &leaf_d->entries[start_d + count];
2191 memmove((char *)entry_d, (char *)entry_s, tmp);
2192 }
2193
2194 /*
2195 * Copy all entry's in the same (sorted) order,
2196 * but allocate attribute info packed and in sequence.
2197 */
2198 entry_s = &leaf_s->entries[start_s];
2199 entry_d = &leaf_d->entries[start_d];
2200 desti = start_d;
2201 for (i = 0; i < count; entry_s++, entry_d++, desti++, i++) {
2202 ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT)
2203 >= INT_GET(hdr_s->firstused, ARCH_CONVERT));
2204 tmp = xfs_attr_leaf_entsize(leaf_s, start_s + i);
2205#ifdef GROT
2206 /*
2207 * Code to drop INCOMPLETE entries. Difficult to use as we
2208 * may also need to change the insertion index. Code turned
2209 * off for 6.2, should be revisited later.
2210 */
2211 if (entry_s->flags & XFS_ATTR_INCOMPLETE) { /* skip partials? */
2212 memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp);
2213 INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp);
2214 INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
2215 entry_d--; /* to compensate for ++ in loop hdr */
2216 desti--;
2217 if ((start_s + i) < offset)
2218 result++; /* insertion index adjustment */
2219 } else {
2220#endif /* GROT */
2221 INT_MOD(hdr_d->firstused, ARCH_CONVERT, -tmp);
2222 /* both on-disk, don't endian flip twice */
2223 entry_d->hashval = entry_s->hashval;
2224 /* both on-disk, don't endian flip twice */
2225 entry_d->nameidx = hdr_d->firstused;
2226 entry_d->flags = entry_s->flags;
2227 ASSERT(INT_GET(entry_d->nameidx, ARCH_CONVERT) + tmp
2228 <= XFS_LBSIZE(mp));
2229 memmove(XFS_ATTR_LEAF_NAME(leaf_d, desti),
2230 XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), tmp);
2231 ASSERT(INT_GET(entry_s->nameidx, ARCH_CONVERT) + tmp
2232 <= XFS_LBSIZE(mp));
2233 memset(XFS_ATTR_LEAF_NAME(leaf_s, start_s + i), 0, tmp);
2234 INT_MOD(hdr_s->usedbytes, ARCH_CONVERT, -tmp);
2235 INT_MOD(hdr_d->usedbytes, ARCH_CONVERT, tmp);
2236 INT_MOD(hdr_s->count, ARCH_CONVERT, -1);
2237 INT_MOD(hdr_d->count, ARCH_CONVERT, 1);
2238 tmp = INT_GET(hdr_d->count, ARCH_CONVERT)
2239 * sizeof(xfs_attr_leaf_entry_t)
2240 + sizeof(xfs_attr_leaf_hdr_t);
2241 ASSERT(INT_GET(hdr_d->firstused, ARCH_CONVERT) >= tmp);
2242#ifdef GROT
2243 }
2244#endif /* GROT */
2245 }
2246
2247 /*
2248 * Zero out the entries we just copied.
2249 */
2250 if (start_s == INT_GET(hdr_s->count, ARCH_CONVERT)) {
2251 tmp = count * sizeof(xfs_attr_leaf_entry_t);
2252 entry_s = &leaf_s->entries[start_s];
2253 ASSERT(((char *)entry_s + tmp) <=
2254 ((char *)leaf_s + XFS_LBSIZE(mp)));
2255 memset((char *)entry_s, 0, tmp);
2256 } else {
2257 /*
2258 * Move the remaining entries down to fill the hole,
2259 * then zero the entries at the top.
2260 */
2261 tmp = INT_GET(hdr_s->count, ARCH_CONVERT) - count;
2262 tmp *= sizeof(xfs_attr_leaf_entry_t);
2263 entry_s = &leaf_s->entries[start_s + count];
2264 entry_d = &leaf_s->entries[start_s];
2265 memmove((char *)entry_d, (char *)entry_s, tmp);
2266
2267 tmp = count * sizeof(xfs_attr_leaf_entry_t);
2268 entry_s = &leaf_s->entries[INT_GET(hdr_s->count,
2269 ARCH_CONVERT)];
2270 ASSERT(((char *)entry_s + tmp) <=
2271 ((char *)leaf_s + XFS_LBSIZE(mp)));
2272 memset((char *)entry_s, 0, tmp);
2273 }
2274
2275 /*
2276 * Fill in the freemap information
2277 */
2278 INT_SET(hdr_d->freemap[0].base, ARCH_CONVERT,
2279 sizeof(xfs_attr_leaf_hdr_t));
2280 INT_MOD(hdr_d->freemap[0].base, ARCH_CONVERT,
2281 INT_GET(hdr_d->count, ARCH_CONVERT)
2282 * sizeof(xfs_attr_leaf_entry_t));
2283 INT_SET(hdr_d->freemap[0].size, ARCH_CONVERT,
2284 INT_GET(hdr_d->firstused, ARCH_CONVERT)
2285 - INT_GET(hdr_d->freemap[0].base, ARCH_CONVERT));
2286 hdr_d->freemap[1].base = 0;
2287 hdr_d->freemap[2].base = 0;
2288 hdr_d->freemap[1].size = 0;
2289 hdr_d->freemap[2].size = 0;
2290 hdr_s->holes = 1; /* leaf may not be compact */
2291}
2292
2293/*
2294 * Compare two leaf blocks "order".
2295 * Return 0 unless leaf2 should go before leaf1.
2296 */
2297int
2298xfs_attr_leaf_order(xfs_dabuf_t *leaf1_bp, xfs_dabuf_t *leaf2_bp)
2299{
2300 xfs_attr_leafblock_t *leaf1, *leaf2;
2301
2302 leaf1 = leaf1_bp->data;
2303 leaf2 = leaf2_bp->data;
2304 ASSERT((INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT)
2305 == XFS_ATTR_LEAF_MAGIC) &&
2306 (INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT)
2307 == XFS_ATTR_LEAF_MAGIC));
2308 if ( (INT_GET(leaf1->hdr.count, ARCH_CONVERT) > 0)
2309 && (INT_GET(leaf2->hdr.count, ARCH_CONVERT) > 0)
2310 && ( (INT_GET(leaf2->entries[ 0 ].hashval, ARCH_CONVERT) <
2311 INT_GET(leaf1->entries[ 0 ].hashval, ARCH_CONVERT))
2312 || (INT_GET(leaf2->entries[INT_GET(leaf2->hdr.count,
2313 ARCH_CONVERT)-1].hashval, ARCH_CONVERT) <
2314 INT_GET(leaf1->entries[INT_GET(leaf1->hdr.count,
2315 ARCH_CONVERT)-1].hashval, ARCH_CONVERT))) ) {
2316 return(1);
2317 }
2318 return(0);
2319}
2320
2321/*
2322 * Pick up the last hashvalue from a leaf block.
2323 */
2324xfs_dahash_t
2325xfs_attr_leaf_lasthash(xfs_dabuf_t *bp, int *count)
2326{
2327 xfs_attr_leafblock_t *leaf;
2328
2329 leaf = bp->data;
2330 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
2331 == XFS_ATTR_LEAF_MAGIC);
2332 if (count)
2333 *count = INT_GET(leaf->hdr.count, ARCH_CONVERT);
2334 if (!leaf->hdr.count)
2335 return(0);
2336 return(INT_GET(leaf->entries[INT_GET(leaf->hdr.count,
2337 ARCH_CONVERT)-1].hashval, ARCH_CONVERT));
2338}
2339
2340/*
2341 * Calculate the number of bytes used to store the indicated attribute
2342 * (whether local or remote only calculate bytes in this block).
2343 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +10002344STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002345xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index)
2346{
2347 xfs_attr_leaf_name_local_t *name_loc;
2348 xfs_attr_leaf_name_remote_t *name_rmt;
2349 int size;
2350
2351 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
2352 == XFS_ATTR_LEAF_MAGIC);
2353 if (leaf->entries[index].flags & XFS_ATTR_LOCAL) {
2354 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, index);
2355 size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(name_loc->namelen,
2356 INT_GET(name_loc->valuelen,
2357 ARCH_CONVERT));
2358 } else {
2359 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, index);
2360 size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(name_rmt->namelen);
2361 }
2362 return(size);
2363}
2364
2365/*
2366 * Calculate the number of bytes that would be required to store the new
2367 * attribute (whether local or remote only calculate bytes in this block).
2368 * This routine decides as a side effect whether the attribute will be
2369 * a "local" or a "remote" attribute.
2370 */
2371int
Nathan Scottaa82daa2005-11-02 10:33:33 +11002372xfs_attr_leaf_newentsize(int namelen, int valuelen, int blocksize, int *local)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002373{
2374 int size;
2375
Nathan Scottaa82daa2005-11-02 10:33:33 +11002376 size = XFS_ATTR_LEAF_ENTSIZE_LOCAL(namelen, valuelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002377 if (size < XFS_ATTR_LEAF_ENTSIZE_LOCAL_MAX(blocksize)) {
2378 if (local) {
2379 *local = 1;
2380 }
2381 } else {
Nathan Scottaa82daa2005-11-02 10:33:33 +11002382 size = XFS_ATTR_LEAF_ENTSIZE_REMOTE(namelen);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383 if (local) {
2384 *local = 0;
2385 }
2386 }
2387 return(size);
2388}
2389
2390/*
2391 * Copy out attribute list entries for attr_list(), for leaf attribute lists.
2392 */
2393int
2394xfs_attr_leaf_list_int(xfs_dabuf_t *bp, xfs_attr_list_context_t *context)
2395{
2396 attrlist_cursor_kern_t *cursor;
2397 xfs_attr_leafblock_t *leaf;
2398 xfs_attr_leaf_entry_t *entry;
2399 xfs_attr_leaf_name_local_t *name_loc;
2400 xfs_attr_leaf_name_remote_t *name_rmt;
2401 int retval, i;
2402
2403 ASSERT(bp != NULL);
2404 leaf = bp->data;
2405 cursor = context->cursor;
2406 cursor->initted = 1;
2407
2408 xfs_attr_trace_l_cl("blk start", context, leaf);
2409
2410 /*
2411 * Re-find our place in the leaf block if this is a new syscall.
2412 */
2413 if (context->resynch) {
2414 entry = &leaf->entries[0];
2415 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
2416 entry++, i++) {
2417 if (INT_GET(entry->hashval, ARCH_CONVERT)
2418 == cursor->hashval) {
2419 if (cursor->offset == context->dupcnt) {
2420 context->dupcnt = 0;
2421 break;
2422 }
2423 context->dupcnt++;
2424 } else if (INT_GET(entry->hashval, ARCH_CONVERT)
2425 > cursor->hashval) {
2426 context->dupcnt = 0;
2427 break;
2428 }
2429 }
2430 if (i == INT_GET(leaf->hdr.count, ARCH_CONVERT)) {
2431 xfs_attr_trace_l_c("not found", context);
2432 return(0);
2433 }
2434 } else {
2435 entry = &leaf->entries[0];
2436 i = 0;
2437 }
2438 context->resynch = 0;
2439
2440 /*
2441 * We have found our place, start copying out the new attributes.
2442 */
2443 retval = 0;
2444 for ( ; (i < INT_GET(leaf->hdr.count, ARCH_CONVERT))
2445 && (retval == 0); entry++, i++) {
2446 attrnames_t *namesp;
2447
2448 if (INT_GET(entry->hashval, ARCH_CONVERT) != cursor->hashval) {
2449 cursor->hashval = INT_GET(entry->hashval, ARCH_CONVERT);
2450 cursor->offset = 0;
2451 }
2452
2453 if (entry->flags & XFS_ATTR_INCOMPLETE)
2454 continue; /* skip incomplete entries */
2455 if (((context->flags & ATTR_SECURE) != 0) !=
2456 ((entry->flags & XFS_ATTR_SECURE) != 0) &&
2457 !(context->flags & ATTR_KERNORMALS))
2458 continue; /* skip non-matching entries */
2459 if (((context->flags & ATTR_ROOT) != 0) !=
2460 ((entry->flags & XFS_ATTR_ROOT) != 0) &&
2461 !(context->flags & ATTR_KERNROOTLS))
2462 continue; /* skip non-matching entries */
2463
2464 namesp = (entry->flags & XFS_ATTR_SECURE) ? &attr_secure :
2465 ((entry->flags & XFS_ATTR_ROOT) ? &attr_trusted :
2466 &attr_user);
2467
2468 if (entry->flags & XFS_ATTR_LOCAL) {
2469 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
2470 if (context->flags & ATTR_KERNOVAL) {
2471 ASSERT(context->flags & ATTR_KERNAMELS);
2472 context->count += namesp->attr_namelen +
2473 (int)name_loc->namelen + 1;
2474 } else {
2475 retval = xfs_attr_put_listent(context, namesp,
2476 (char *)name_loc->nameval,
2477 (int)name_loc->namelen,
2478 (int)INT_GET(name_loc->valuelen,
2479 ARCH_CONVERT));
2480 }
2481 } else {
2482 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
2483 if (context->flags & ATTR_KERNOVAL) {
2484 ASSERT(context->flags & ATTR_KERNAMELS);
2485 context->count += namesp->attr_namelen +
2486 (int)name_rmt->namelen + 1;
2487 } else {
2488 retval = xfs_attr_put_listent(context, namesp,
2489 (char *)name_rmt->name,
2490 (int)name_rmt->namelen,
2491 (int)INT_GET(name_rmt->valuelen,
2492 ARCH_CONVERT));
2493 }
2494 }
2495 if (retval == 0) {
2496 cursor->offset++;
2497 }
2498 }
2499 xfs_attr_trace_l_cl("blk end", context, leaf);
2500 return(retval);
2501}
2502
2503#define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \
2504 (((struct attrlist_ent *) 0)->a_name - (char *) 0)
2505#define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \
2506 ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
2507 & ~(sizeof(u_int32_t)-1))
2508
2509/*
2510 * Format an attribute and copy it out to the user's buffer.
2511 * Take care to check values and protect against them changing later,
2512 * we may be reading them directly out of a user buffer.
2513 */
2514/*ARGSUSED*/
Christoph Hellwigba0f32d2005-06-21 15:36:52 +10002515STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002516xfs_attr_put_listent(xfs_attr_list_context_t *context,
2517 attrnames_t *namesp, char *name, int namelen, int valuelen)
2518{
2519 attrlist_ent_t *aep;
2520 int arraytop;
2521
2522 ASSERT(!(context->flags & ATTR_KERNOVAL));
2523 if (context->flags & ATTR_KERNAMELS) {
2524 char *offset;
2525
2526 ASSERT(context->count >= 0);
2527
2528 arraytop = context->count + namesp->attr_namelen + namelen + 1;
2529 if (arraytop > context->firstu) {
2530 context->count = -1; /* insufficient space */
2531 return(1);
2532 }
2533 offset = (char *)context->alist + context->count;
2534 strncpy(offset, namesp->attr_name, namesp->attr_namelen);
2535 offset += namesp->attr_namelen;
2536 strncpy(offset, name, namelen); /* real name */
2537 offset += namelen;
2538 *offset = '\0';
2539 context->count += namesp->attr_namelen + namelen + 1;
2540 return(0);
2541 }
2542
2543 ASSERT(context->count >= 0);
2544 ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
2545 ASSERT(context->firstu >= sizeof(*context->alist));
2546 ASSERT(context->firstu <= context->bufsize);
2547
2548 arraytop = sizeof(*context->alist) +
2549 context->count * sizeof(context->alist->al_offset[0]);
2550 context->firstu -= ATTR_ENTSIZE(namelen);
2551 if (context->firstu < arraytop) {
2552 xfs_attr_trace_l_c("buffer full", context);
2553 context->alist->al_more = 1;
2554 return(1);
2555 }
2556
2557 aep = (attrlist_ent_t *)&(((char *)context->alist)[ context->firstu ]);
2558 aep->a_valuelen = valuelen;
2559 memcpy(aep->a_name, name, namelen);
2560 aep->a_name[ namelen ] = 0;
2561 context->alist->al_offset[ context->count++ ] = context->firstu;
2562 context->alist->al_count = context->count;
2563 xfs_attr_trace_l_c("add", context);
2564 return(0);
2565}
2566
2567/*========================================================================
2568 * Manage the INCOMPLETE flag in a leaf entry
2569 *========================================================================*/
2570
2571/*
2572 * Clear the INCOMPLETE flag on an entry in a leaf block.
2573 */
2574int
2575xfs_attr_leaf_clearflag(xfs_da_args_t *args)
2576{
2577 xfs_attr_leafblock_t *leaf;
2578 xfs_attr_leaf_entry_t *entry;
2579 xfs_attr_leaf_name_remote_t *name_rmt;
2580 xfs_dabuf_t *bp;
2581 int error;
2582#ifdef DEBUG
2583 xfs_attr_leaf_name_local_t *name_loc;
2584 int namelen;
2585 char *name;
2586#endif /* DEBUG */
2587
2588 /*
2589 * Set up the operation.
2590 */
2591 error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
2592 XFS_ATTR_FORK);
2593 if (error) {
2594 return(error);
2595 }
2596 ASSERT(bp != NULL);
2597
2598 leaf = bp->data;
2599 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
2600 == XFS_ATTR_LEAF_MAGIC);
2601 ASSERT(args->index < INT_GET(leaf->hdr.count, ARCH_CONVERT));
2602 ASSERT(args->index >= 0);
2603 entry = &leaf->entries[ args->index ];
2604 ASSERT(entry->flags & XFS_ATTR_INCOMPLETE);
2605
2606#ifdef DEBUG
2607 if (entry->flags & XFS_ATTR_LOCAL) {
2608 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf, args->index);
2609 namelen = name_loc->namelen;
2610 name = (char *)name_loc->nameval;
2611 } else {
2612 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
2613 namelen = name_rmt->namelen;
2614 name = (char *)name_rmt->name;
2615 }
2616 ASSERT(INT_GET(entry->hashval, ARCH_CONVERT) == args->hashval);
2617 ASSERT(namelen == args->namelen);
2618 ASSERT(memcmp(name, args->name, namelen) == 0);
2619#endif /* DEBUG */
2620
2621 entry->flags &= ~XFS_ATTR_INCOMPLETE;
2622 xfs_da_log_buf(args->trans, bp,
2623 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
2624
2625 if (args->rmtblkno) {
2626 ASSERT((entry->flags & XFS_ATTR_LOCAL) == 0);
2627 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
2628 INT_SET(name_rmt->valueblk, ARCH_CONVERT, args->rmtblkno);
2629 INT_SET(name_rmt->valuelen, ARCH_CONVERT, args->valuelen);
2630 xfs_da_log_buf(args->trans, bp,
2631 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
2632 }
2633 xfs_da_buf_done(bp);
2634
2635 /*
2636 * Commit the flag value change and start the next trans in series.
2637 */
2638 error = xfs_attr_rolltrans(&args->trans, args->dp);
2639
2640 return(error);
2641}
2642
2643/*
2644 * Set the INCOMPLETE flag on an entry in a leaf block.
2645 */
2646int
2647xfs_attr_leaf_setflag(xfs_da_args_t *args)
2648{
2649 xfs_attr_leafblock_t *leaf;
2650 xfs_attr_leaf_entry_t *entry;
2651 xfs_attr_leaf_name_remote_t *name_rmt;
2652 xfs_dabuf_t *bp;
2653 int error;
2654
2655 /*
2656 * Set up the operation.
2657 */
2658 error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp,
2659 XFS_ATTR_FORK);
2660 if (error) {
2661 return(error);
2662 }
2663 ASSERT(bp != NULL);
2664
2665 leaf = bp->data;
2666 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
2667 == XFS_ATTR_LEAF_MAGIC);
2668 ASSERT(args->index < INT_GET(leaf->hdr.count, ARCH_CONVERT));
2669 ASSERT(args->index >= 0);
2670 entry = &leaf->entries[ args->index ];
2671
2672 ASSERT((entry->flags & XFS_ATTR_INCOMPLETE) == 0);
2673 entry->flags |= XFS_ATTR_INCOMPLETE;
2674 xfs_da_log_buf(args->trans, bp,
2675 XFS_DA_LOGRANGE(leaf, entry, sizeof(*entry)));
2676 if ((entry->flags & XFS_ATTR_LOCAL) == 0) {
2677 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, args->index);
2678 name_rmt->valueblk = 0;
2679 name_rmt->valuelen = 0;
2680 xfs_da_log_buf(args->trans, bp,
2681 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
2682 }
2683 xfs_da_buf_done(bp);
2684
2685 /*
2686 * Commit the flag value change and start the next trans in series.
2687 */
2688 error = xfs_attr_rolltrans(&args->trans, args->dp);
2689
2690 return(error);
2691}
2692
2693/*
2694 * In a single transaction, clear the INCOMPLETE flag on the leaf entry
2695 * given by args->blkno/index and set the INCOMPLETE flag on the leaf
2696 * entry given by args->blkno2/index2.
2697 *
2698 * Note that they could be in different blocks, or in the same block.
2699 */
2700int
2701xfs_attr_leaf_flipflags(xfs_da_args_t *args)
2702{
2703 xfs_attr_leafblock_t *leaf1, *leaf2;
2704 xfs_attr_leaf_entry_t *entry1, *entry2;
2705 xfs_attr_leaf_name_remote_t *name_rmt;
2706 xfs_dabuf_t *bp1, *bp2;
2707 int error;
2708#ifdef DEBUG
2709 xfs_attr_leaf_name_local_t *name_loc;
2710 int namelen1, namelen2;
2711 char *name1, *name2;
2712#endif /* DEBUG */
2713
2714 /*
2715 * Read the block containing the "old" attr
2716 */
2717 error = xfs_da_read_buf(args->trans, args->dp, args->blkno, -1, &bp1,
2718 XFS_ATTR_FORK);
2719 if (error) {
2720 return(error);
2721 }
2722 ASSERT(bp1 != NULL);
2723
2724 /*
2725 * Read the block containing the "new" attr, if it is different
2726 */
2727 if (args->blkno2 != args->blkno) {
2728 error = xfs_da_read_buf(args->trans, args->dp, args->blkno2,
2729 -1, &bp2, XFS_ATTR_FORK);
2730 if (error) {
2731 return(error);
2732 }
2733 ASSERT(bp2 != NULL);
2734 } else {
2735 bp2 = bp1;
2736 }
2737
2738 leaf1 = bp1->data;
2739 ASSERT(INT_GET(leaf1->hdr.info.magic, ARCH_CONVERT)
2740 == XFS_ATTR_LEAF_MAGIC);
2741 ASSERT(args->index < INT_GET(leaf1->hdr.count, ARCH_CONVERT));
2742 ASSERT(args->index >= 0);
2743 entry1 = &leaf1->entries[ args->index ];
2744
2745 leaf2 = bp2->data;
2746 ASSERT(INT_GET(leaf2->hdr.info.magic, ARCH_CONVERT)
2747 == XFS_ATTR_LEAF_MAGIC);
2748 ASSERT(args->index2 < INT_GET(leaf2->hdr.count, ARCH_CONVERT));
2749 ASSERT(args->index2 >= 0);
2750 entry2 = &leaf2->entries[ args->index2 ];
2751
2752#ifdef DEBUG
2753 if (entry1->flags & XFS_ATTR_LOCAL) {
2754 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf1, args->index);
2755 namelen1 = name_loc->namelen;
2756 name1 = (char *)name_loc->nameval;
2757 } else {
2758 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf1, args->index);
2759 namelen1 = name_rmt->namelen;
2760 name1 = (char *)name_rmt->name;
2761 }
2762 if (entry2->flags & XFS_ATTR_LOCAL) {
2763 name_loc = XFS_ATTR_LEAF_NAME_LOCAL(leaf2, args->index2);
2764 namelen2 = name_loc->namelen;
2765 name2 = (char *)name_loc->nameval;
2766 } else {
2767 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf2, args->index2);
2768 namelen2 = name_rmt->namelen;
2769 name2 = (char *)name_rmt->name;
2770 }
2771 ASSERT(INT_GET(entry1->hashval, ARCH_CONVERT) == INT_GET(entry2->hashval, ARCH_CONVERT));
2772 ASSERT(namelen1 == namelen2);
2773 ASSERT(memcmp(name1, name2, namelen1) == 0);
2774#endif /* DEBUG */
2775
2776 ASSERT(entry1->flags & XFS_ATTR_INCOMPLETE);
2777 ASSERT((entry2->flags & XFS_ATTR_INCOMPLETE) == 0);
2778
2779 entry1->flags &= ~XFS_ATTR_INCOMPLETE;
2780 xfs_da_log_buf(args->trans, bp1,
2781 XFS_DA_LOGRANGE(leaf1, entry1, sizeof(*entry1)));
2782 if (args->rmtblkno) {
2783 ASSERT((entry1->flags & XFS_ATTR_LOCAL) == 0);
2784 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf1, args->index);
2785 INT_SET(name_rmt->valueblk, ARCH_CONVERT, args->rmtblkno);
2786 INT_SET(name_rmt->valuelen, ARCH_CONVERT, args->valuelen);
2787 xfs_da_log_buf(args->trans, bp1,
2788 XFS_DA_LOGRANGE(leaf1, name_rmt, sizeof(*name_rmt)));
2789 }
2790
2791 entry2->flags |= XFS_ATTR_INCOMPLETE;
2792 xfs_da_log_buf(args->trans, bp2,
2793 XFS_DA_LOGRANGE(leaf2, entry2, sizeof(*entry2)));
2794 if ((entry2->flags & XFS_ATTR_LOCAL) == 0) {
2795 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf2, args->index2);
2796 name_rmt->valueblk = 0;
2797 name_rmt->valuelen = 0;
2798 xfs_da_log_buf(args->trans, bp2,
2799 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
2800 }
2801 xfs_da_buf_done(bp1);
2802 if (bp1 != bp2)
2803 xfs_da_buf_done(bp2);
2804
2805 /*
2806 * Commit the flag value change and start the next trans in series.
2807 */
2808 error = xfs_attr_rolltrans(&args->trans, args->dp);
2809
2810 return(error);
2811}
2812
2813/*========================================================================
2814 * Indiscriminately delete the entire attribute fork
2815 *========================================================================*/
2816
2817/*
2818 * Recurse (gasp!) through the attribute nodes until we find leaves.
2819 * We're doing a depth-first traversal in order to invalidate everything.
2820 */
2821int
2822xfs_attr_root_inactive(xfs_trans_t **trans, xfs_inode_t *dp)
2823{
2824 xfs_da_blkinfo_t *info;
2825 xfs_daddr_t blkno;
2826 xfs_dabuf_t *bp;
2827 int error;
2828
2829 /*
2830 * Read block 0 to see what we have to work with.
2831 * We only get here if we have extents, since we remove
2832 * the extents in reverse order the extent containing
2833 * block 0 must still be there.
2834 */
2835 error = xfs_da_read_buf(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
2836 if (error)
2837 return(error);
2838 blkno = xfs_da_blkno(bp);
2839
2840 /*
2841 * Invalidate the tree, even if the "tree" is only a single leaf block.
2842 * This is a depth-first traversal!
2843 */
2844 info = bp->data;
2845 if (INT_GET(info->magic, ARCH_CONVERT) == XFS_DA_NODE_MAGIC) {
2846 error = xfs_attr_node_inactive(trans, dp, bp, 1);
2847 } else if (INT_GET(info->magic, ARCH_CONVERT) == XFS_ATTR_LEAF_MAGIC) {
2848 error = xfs_attr_leaf_inactive(trans, dp, bp);
2849 } else {
2850 error = XFS_ERROR(EIO);
2851 xfs_da_brelse(*trans, bp);
2852 }
2853 if (error)
2854 return(error);
2855
2856 /*
2857 * Invalidate the incore copy of the root block.
2858 */
2859 error = xfs_da_get_buf(*trans, dp, 0, blkno, &bp, XFS_ATTR_FORK);
2860 if (error)
2861 return(error);
2862 xfs_da_binval(*trans, bp); /* remove from cache */
2863 /*
2864 * Commit the invalidate and start the next transaction.
2865 */
2866 error = xfs_attr_rolltrans(trans, dp);
2867
2868 return (error);
2869}
2870
2871/*
2872 * Recurse (gasp!) through the attribute nodes until we find leaves.
2873 * We're doing a depth-first traversal in order to invalidate everything.
2874 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +10002875STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002876xfs_attr_node_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp,
2877 int level)
2878{
2879 xfs_da_blkinfo_t *info;
2880 xfs_da_intnode_t *node;
2881 xfs_dablk_t child_fsb;
2882 xfs_daddr_t parent_blkno, child_blkno;
2883 int error, count, i;
2884 xfs_dabuf_t *child_bp;
2885
2886 /*
2887 * Since this code is recursive (gasp!) we must protect ourselves.
2888 */
2889 if (level > XFS_DA_NODE_MAXDEPTH) {
2890 xfs_da_brelse(*trans, bp); /* no locks for later trans */
2891 return(XFS_ERROR(EIO));
2892 }
2893
2894 node = bp->data;
2895 ASSERT(INT_GET(node->hdr.info.magic, ARCH_CONVERT)
2896 == XFS_DA_NODE_MAGIC);
2897 parent_blkno = xfs_da_blkno(bp); /* save for re-read later */
2898 count = INT_GET(node->hdr.count, ARCH_CONVERT);
2899 if (!count) {
2900 xfs_da_brelse(*trans, bp);
2901 return(0);
2902 }
2903 child_fsb = INT_GET(node->btree[0].before, ARCH_CONVERT);
2904 xfs_da_brelse(*trans, bp); /* no locks for later trans */
2905
2906 /*
2907 * If this is the node level just above the leaves, simply loop
2908 * over the leaves removing all of them. If this is higher up
2909 * in the tree, recurse downward.
2910 */
2911 for (i = 0; i < count; i++) {
2912 /*
2913 * Read the subsidiary block to see what we have to work with.
2914 * Don't do this in a transaction. This is a depth-first
2915 * traversal of the tree so we may deal with many blocks
2916 * before we come back to this one.
2917 */
2918 error = xfs_da_read_buf(*trans, dp, child_fsb, -2, &child_bp,
2919 XFS_ATTR_FORK);
2920 if (error)
2921 return(error);
2922 if (child_bp) {
2923 /* save for re-read later */
2924 child_blkno = xfs_da_blkno(child_bp);
2925
2926 /*
2927 * Invalidate the subtree, however we have to.
2928 */
2929 info = child_bp->data;
2930 if (INT_GET(info->magic, ARCH_CONVERT)
2931 == XFS_DA_NODE_MAGIC) {
2932 error = xfs_attr_node_inactive(trans, dp,
2933 child_bp, level+1);
2934 } else if (INT_GET(info->magic, ARCH_CONVERT)
2935 == XFS_ATTR_LEAF_MAGIC) {
2936 error = xfs_attr_leaf_inactive(trans, dp,
2937 child_bp);
2938 } else {
2939 error = XFS_ERROR(EIO);
2940 xfs_da_brelse(*trans, child_bp);
2941 }
2942 if (error)
2943 return(error);
2944
2945 /*
2946 * Remove the subsidiary block from the cache
2947 * and from the log.
2948 */
2949 error = xfs_da_get_buf(*trans, dp, 0, child_blkno,
2950 &child_bp, XFS_ATTR_FORK);
2951 if (error)
2952 return(error);
2953 xfs_da_binval(*trans, child_bp);
2954 }
2955
2956 /*
2957 * If we're not done, re-read the parent to get the next
2958 * child block number.
2959 */
2960 if ((i+1) < count) {
2961 error = xfs_da_read_buf(*trans, dp, 0, parent_blkno,
2962 &bp, XFS_ATTR_FORK);
2963 if (error)
2964 return(error);
2965 child_fsb = INT_GET(node->btree[i+1].before, ARCH_CONVERT);
2966 xfs_da_brelse(*trans, bp);
2967 }
2968 /*
2969 * Atomically commit the whole invalidate stuff.
2970 */
2971 if ((error = xfs_attr_rolltrans(trans, dp)))
2972 return (error);
2973 }
2974
2975 return(0);
2976}
2977
2978/*
2979 * Invalidate all of the "remote" value regions pointed to by a particular
2980 * leaf block.
2981 * Note that we must release the lock on the buffer so that we are not
2982 * caught holding something that the logging code wants to flush to disk.
2983 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +10002984STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -07002985xfs_attr_leaf_inactive(xfs_trans_t **trans, xfs_inode_t *dp, xfs_dabuf_t *bp)
2986{
2987 xfs_attr_leafblock_t *leaf;
2988 xfs_attr_leaf_entry_t *entry;
2989 xfs_attr_leaf_name_remote_t *name_rmt;
2990 xfs_attr_inactive_list_t *list, *lp;
2991 int error, count, size, tmp, i;
2992
2993 leaf = bp->data;
2994 ASSERT(INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
2995 == XFS_ATTR_LEAF_MAGIC);
2996
2997 /*
2998 * Count the number of "remote" value extents.
2999 */
3000 count = 0;
3001 entry = &leaf->entries[0];
3002 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {
3003 if ( INT_GET(entry->nameidx, ARCH_CONVERT)
3004 && ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
3005 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
3006 if (name_rmt->valueblk)
3007 count++;
3008 }
3009 }
3010
3011 /*
3012 * If there are no "remote" values, we're done.
3013 */
3014 if (count == 0) {
3015 xfs_da_brelse(*trans, bp);
3016 return(0);
3017 }
3018
3019 /*
3020 * Allocate storage for a list of all the "remote" value extents.
3021 */
3022 size = count * sizeof(xfs_attr_inactive_list_t);
3023 list = (xfs_attr_inactive_list_t *)kmem_alloc(size, KM_SLEEP);
3024
3025 /*
3026 * Identify each of the "remote" value extents.
3027 */
3028 lp = list;
3029 entry = &leaf->entries[0];
3030 for (i = 0; i < INT_GET(leaf->hdr.count, ARCH_CONVERT); entry++, i++) {
3031 if ( INT_GET(entry->nameidx, ARCH_CONVERT)
3032 && ((entry->flags & XFS_ATTR_LOCAL) == 0)) {
3033 name_rmt = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
3034 if (name_rmt->valueblk) {
3035 /* both on-disk, don't endian flip twice */
3036 lp->valueblk = name_rmt->valueblk;
3037 INT_SET(lp->valuelen, ARCH_CONVERT,
3038 XFS_B_TO_FSB(dp->i_mount,
3039 INT_GET(name_rmt->valuelen,
3040 ARCH_CONVERT)));
3041 lp++;
3042 }
3043 }
3044 }
3045 xfs_da_brelse(*trans, bp); /* unlock for trans. in freextent() */
3046
3047 /*
3048 * Invalidate each of the "remote" value extents.
3049 */
3050 error = 0;
3051 for (lp = list, i = 0; i < count; i++, lp++) {
3052 tmp = xfs_attr_leaf_freextent(trans, dp,
3053 INT_GET(lp->valueblk,
3054 ARCH_CONVERT),
3055 INT_GET(lp->valuelen,
3056 ARCH_CONVERT));
3057 if (error == 0)
3058 error = tmp; /* save only the 1st errno */
3059 }
3060
3061 kmem_free((xfs_caddr_t)list, size);
3062 return(error);
3063}
3064
3065/*
3066 * Look at all the extents for this logical region,
3067 * invalidate any buffers that are incore/in transactions.
3068 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +10003069STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -07003070xfs_attr_leaf_freextent(xfs_trans_t **trans, xfs_inode_t *dp,
3071 xfs_dablk_t blkno, int blkcnt)
3072{
3073 xfs_bmbt_irec_t map;
3074 xfs_dablk_t tblkno;
3075 int tblkcnt, dblkcnt, nmap, error;
3076 xfs_daddr_t dblkno;
3077 xfs_buf_t *bp;
3078
3079 /*
3080 * Roll through the "value", invalidating the attribute value's
3081 * blocks.
3082 */
3083 tblkno = blkno;
3084 tblkcnt = blkcnt;
3085 while (tblkcnt > 0) {
3086 /*
3087 * Try to remember where we decided to put the value.
3088 */
3089 nmap = 1;
3090 error = xfs_bmapi(*trans, dp, (xfs_fileoff_t)tblkno, tblkcnt,
3091 XFS_BMAPI_ATTRFORK | XFS_BMAPI_METADATA,
3092 NULL, 0, &map, &nmap, NULL);
3093 if (error) {
3094 return(error);
3095 }
3096 ASSERT(nmap == 1);
3097 ASSERT(map.br_startblock != DELAYSTARTBLOCK);
3098
3099 /*
3100 * If it's a hole, these are already unmapped
3101 * so there's nothing to invalidate.
3102 */
3103 if (map.br_startblock != HOLESTARTBLOCK) {
3104
3105 dblkno = XFS_FSB_TO_DADDR(dp->i_mount,
3106 map.br_startblock);
3107 dblkcnt = XFS_FSB_TO_BB(dp->i_mount,
3108 map.br_blockcount);
3109 bp = xfs_trans_get_buf(*trans,
3110 dp->i_mount->m_ddev_targp,
3111 dblkno, dblkcnt, XFS_BUF_LOCK);
3112 xfs_trans_binval(*trans, bp);
3113 /*
3114 * Roll to next transaction.
3115 */
3116 if ((error = xfs_attr_rolltrans(trans, dp)))
3117 return (error);
3118 }
3119
3120 tblkno += map.br_blockcount;
3121 tblkcnt -= map.br_blockcount;
3122 }
3123
3124 return(0);
3125}
3126
3127
3128/*
3129 * Roll from one trans in the sequence of PERMANENT transactions to the next.
3130 */
3131int
3132xfs_attr_rolltrans(xfs_trans_t **transp, xfs_inode_t *dp)
3133{
3134 xfs_trans_t *trans;
3135 unsigned int logres, count;
3136 int error;
3137
3138 /*
3139 * Ensure that the inode is always logged.
3140 */
3141 trans = *transp;
3142 xfs_trans_log_inode(trans, dp, XFS_ILOG_CORE);
3143
3144 /*
3145 * Copy the critical parameters from one trans to the next.
3146 */
3147 logres = trans->t_log_res;
3148 count = trans->t_log_count;
3149 *transp = xfs_trans_dup(trans);
3150
3151 /*
3152 * Commit the current transaction.
3153 * If this commit failed, then it'd just unlock those items that
3154 * are not marked ihold. That also means that a filesystem shutdown
3155 * is in progress. The caller takes the responsibility to cancel
3156 * the duplicate transaction that gets returned.
3157 */
3158 if ((error = xfs_trans_commit(trans, 0, NULL)))
3159 return (error);
3160
3161 trans = *transp;
3162
3163 /*
3164 * Reserve space in the log for th next transaction.
3165 * This also pushes items in the "AIL", the list of logged items,
3166 * out to disk if they are taking up space at the tail of the log
3167 * that we want to use. This requires that either nothing be locked
3168 * across this call, or that anything that is locked be logged in
3169 * the prior and the next transactions.
3170 */
3171 error = xfs_trans_reserve(trans, 0, logres, 0,
3172 XFS_TRANS_PERM_LOG_RES, count);
3173 /*
3174 * Ensure that the inode is in the new transaction and locked.
3175 */
3176 if (!error) {
3177 xfs_trans_ijoin(trans, dp, XFS_ILOCK_EXCL);
3178 xfs_trans_ihold(trans, dp);
3179 }
3180 return (error);
3181
3182}