OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [xfs/] [xfs_attr_leaf.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.