2
* Copyright (c) 2000 Silicon Graphics, Inc. All Rights Reserved.
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.
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.
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.
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.
23
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
24
* Mountain View, CA 94043, or:
28
* For further information regarding this notice, see:
30
* http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
35
#include "err_protos.h"
36
#include "attr_repair.h"
41
static int xfs_acl_valid(xfs_acl_t *aclp);
42
static int xfs_mac_valid(xfs_mac_label_t *lp);
46
* For attribute repair, there are 3 formats to worry about. First, is
47
* shortform attributes which reside in the inode. Second is the leaf
48
* form, and lastly the btree. Much of this models after the directory
49
* structure so code resembles the directory repair cases.
50
* For shortform case, if an attribute looks corrupt, it is removed.
51
* If that leaves the shortform down to 0 attributes, it's okay and
52
* will appear to just have a null attribute fork. Some checks are done
53
* for validity of the value field based on what the security needs are.
54
* Calls will be made to xfs_mac_valid or xfs_acl_valid routines if the
55
* security attributes exist. They will be cleared if invalid.
56
* No other values will be checked. The DMF folks do not have current
57
* requirements, but may in the future.
59
* For leaf block attributes, it requires more processing. One sticky
60
* point is that the attributes can be local (within the leaf) or
61
* remote (outside the leaf in other blocks). Thinking of local only
62
* if you get a bad attribute, and want to delete just one, its a-okay
63
* if it remains large enough to still be a leaf block attribute. Otherwise,
64
* it may have to be converted to shortform. How to convert this and when
65
* is an issue. This call is happening in Phase3. Phase5 will capture empty
66
* blocks, but Phase6 allows you to use the simulation library which knows
67
* how to handle attributes in the kernel for converting formats. What we
68
* could do is mark an attribute to be cleared now, but in phase6 somehow
69
* have it cleared for real and then the format changed to shortform if
70
* applicable. Since this requires more work than I anticipate can be
71
* accomplished for the next release, we will instead just say any bad
72
* attribute in the leaf block will make the entire attribute fork be
73
* cleared. The simplest way to do that is to ignore the leaf format, and
74
* call clear_dinode_attr to just make a shortform attribute fork with
77
* Another issue with handling repair on leaf attributes is the remote
78
* blocks. To make sure that they look good and are not used multiple times
79
* by the attribute fork, some mechanism to keep track of all them is necessary.
80
* Do this in the future, time permitting. For now, note that there is no
81
* check for remote blocks and their allocations.
83
* For btree formatted attributes, the model can follow directories. That
84
* would mean go down the tree to the leftmost leaf. From there moving down
85
* the links and processing each. They would call back up the tree, to verify
86
* that the tree structure is okay. Any problems will result in the attribute
87
* fork being emptied and put in shortform format.
91
* This routine just checks what security needs are for attribute values
92
* only called when root flag is set, otherwise these names could exist in
93
* in user attribute land without a conflict.
94
* If value is non-zero, then a remote attribute is being passed in
98
valuecheck(char *namevalue, char *value, int namelen, int valuelen)
100
/* for proper alignment issues, get the structs and bcopy the values */
101
xfs_mac_label_t macl;
106
if ((strncmp(namevalue, SGI_ACL_FILE, SGI_ACL_FILE_SIZE) == 0) ||
107
(strncmp(namevalue, SGI_ACL_DEFAULT,
108
SGI_ACL_DEFAULT_SIZE) == 0)) {
110
bzero(&thisacl, sizeof(xfs_acl_t));
111
bcopy(namevalue+namelen, &thisacl, valuelen);
116
if (xfs_acl_valid((xfs_acl_t *) valuep) != 0) { /* 0 is valid */
118
do_warn("entry contains illegal value in attribute named SGI_ACL_FILE or SGI_ACL_DEFAULT\n");
120
} else if (strncmp(namevalue, SGI_MAC_FILE, SGI_MAC_FILE_SIZE) == 0) {
122
bzero(&macl, sizeof(xfs_mac_label_t));
123
bcopy(namevalue+namelen, &macl, valuelen);
128
if (xfs_mac_valid((xfs_mac_label_t *)valuep) != 1) { /* 1 is valid */
130
*if sysconf says MAC enabled,
131
* temp = mac_from_text("msenhigh/mintlow", NULL)
132
* copy it to value, update valuelen, totsize
133
* This causes pushing up or down of all following
134
* attributes, forcing a attribute format change!!
138
do_warn("entry contains illegal value in attribute named SGI_MAC_LABEL\n");
140
} else if (strncmp(namevalue, SGI_CAP_FILE, SGI_CAP_FILE_SIZE) == 0) {
141
if ( valuelen != sizeof(xfs_cap_set_t)) {
143
do_warn("entry contains illegal value in attribute named SGI_CAP_FILE\n");
152
* this routine validates the attributes in shortform format.
153
* a non-zero return repair value means certain attributes are bogus
154
* and were cleared if possible. Warnings do not generate error conditions
155
* if you cannot modify the structures. repair is set to 1, if anything
159
process_shortform_attr(
164
xfs_attr_shortform_t *asf;
165
xfs_attr_sf_entry_t *currententry, *nextentry, *tempentry;
167
int currentsize, remainingspace;
171
asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT);
173
/* Assumption: hdr.totsize is less than a leaf block and was checked
174
* by lclinode for valid sizes. Check the count though.
176
if (INT_GET(asf->hdr.count, ARCH_CONVERT) == 0)
177
/* then the total size should just be the header length */
178
if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != sizeof(xfs_attr_sf_hdr_t)) {
179
/* whoops there's a discrepancy. Clear the hdr */
181
do_warn("there are no attributes in the fork for inode %llu \n", ino);
182
INT_SET(asf->hdr.totsize, ARCH_CONVERT,
183
sizeof(xfs_attr_sf_hdr_t));
187
do_warn("would junk the attribute fork since the count is 0 for inode %llu\n",ino);
192
currentsize = sizeof(xfs_attr_sf_hdr_t);
193
remainingspace = INT_GET(asf->hdr.totsize, ARCH_CONVERT) - currentsize;
194
nextentry = &asf->list[0];
195
for (i = 0; i < INT_GET(asf->hdr.count, ARCH_CONVERT); i++) {
196
currententry = nextentry;
199
/* don't go off the end if the hdr.count was off */
200
if ((currentsize + (sizeof(xfs_attr_sf_entry_t) - 1)) >
201
INT_GET(asf->hdr.totsize, ARCH_CONVERT))
202
break; /* get out and reset count and totSize */
204
/* if the namelen is 0, can't get to the rest of the entries */
205
if (INT_GET(currententry->namelen, ARCH_CONVERT) == 0) {
206
do_warn("zero length name entry in attribute fork, ");
208
do_warn("truncating attributes for inode %llu to %d \n", ino, i);
210
break; /* and then update hdr fields */
212
do_warn("would truncate attributes for inode %llu to %d \n", ino, i);
216
/* It's okay to have a 0 length valuelen, but do a
217
* rough check to make sure we haven't gone outside of
220
if ((remainingspace < INT_GET(currententry->namelen, ARCH_CONVERT)) ||
221
((remainingspace - INT_GET(currententry->namelen, ARCH_CONVERT))
222
< INT_GET(currententry->valuelen, ARCH_CONVERT))) {
223
do_warn("name or value attribute lengths are too large, \n");
225
do_warn(" truncating attributes for inode %llu to %d \n", ino, i);
227
break; /* and then update hdr fields */
229
do_warn(" would truncate attributes for inode %llu to %d \n", ino, i);
235
/* namecheck checks for / and null terminated for file names.
236
* attributes names currently follow the same rules.
238
if (namecheck((char *)¤tentry->nameval[0],
239
INT_GET(currententry->namelen, ARCH_CONVERT))) {
240
do_warn("entry contains illegal character in shortform attribute name\n");
244
if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) {
245
do_warn("entry has INCOMPLETE flag on in shortform attribute\n");
249
/* Only check values for root security attributes */
250
if (INT_GET(currententry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT)
251
junkit = valuecheck((char *)¤tentry->nameval[0], NULL,
252
INT_GET(currententry->namelen, ARCH_CONVERT), INT_GET(currententry->valuelen, ARCH_CONVERT));
254
remainingspace = remainingspace -
255
XFS_ATTR_SF_ENTSIZE(currententry);
259
/* get rid of only this entry */
260
do_warn("removing attribute entry %d for inode %llu \n", i, ino);
261
tempentry = (xfs_attr_sf_entry_t *)
262
((__psint_t) currententry +
263
XFS_ATTR_SF_ENTSIZE(currententry));
264
memmove(currententry,tempentry,remainingspace);
265
INT_MOD(asf->hdr.count, ARCH_CONVERT, -1);
266
i--; /* no worries, it will wrap back to 0 */
268
continue; /* go back up now */
270
do_warn("would remove attribute entry %d for inode %llu \n", i, ino);
274
/* Let's get ready for the next entry... */
275
nextentry = (xfs_attr_sf_entry_t *)
276
((__psint_t) nextentry +
277
XFS_ATTR_SF_ENTSIZE(currententry));
278
currentsize = currentsize + XFS_ATTR_SF_ENTSIZE(currententry);
283
if (INT_GET(asf->hdr.count, ARCH_CONVERT) != i) {
285
do_warn("would have corrected attribute entry count in inode %llu from %d to %d\n",
286
ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i);
288
do_warn("corrected attribute entry count in inode %llu, was %d, now %d\n",
289
ino, INT_GET(asf->hdr.count, ARCH_CONVERT), i);
290
INT_SET(asf->hdr.count, ARCH_CONVERT, i);
295
/* ASSUMPTION: currentsize <= totsize */
296
if (INT_GET(asf->hdr.totsize, ARCH_CONVERT) != currentsize) {
298
do_warn("would have corrected attribute totsize in inode %llu from %d to %d\n",
299
ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), currentsize);
301
do_warn("corrected attribute entry totsize in inode %llu, was %d, now %d\n",
302
ino, INT_GET(asf->hdr.totsize, ARCH_CONVERT), currentsize);
303
INT_SET(asf->hdr.totsize, ARCH_CONVERT, currentsize);
311
/* This routine brings in blocks from disk one by one and assembles them
312
* in the value buffer. If get_bmapi gets smarter later to return an extent
313
* or list of extents, that would be great. For now, we don't expect too
314
* many blocks per remote value, so one by one is sufficient.
317
rmtval_get(xfs_mount_t *mp, xfs_ino_t ino, blkmap_t *blkmap,
318
xfs_dablk_t blocknum, int valuelen, char* value)
322
int clearit = 0, i = 0, length = 0, amountdone = 0;
324
/* ASSUMPTION: valuelen is a valid number, so use it for looping */
325
/* Note that valuelen is not a multiple of blocksize */
326
while (amountdone < valuelen) {
327
bno = blkmap_get(blkmap, blocknum + i);
328
if (bno == NULLDFSBNO) {
329
do_warn("remote block for attributes of inode %llu"
330
" is missing\n", ino);
334
bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
335
XFS_FSB_TO_BB(mp, 1), 0);
337
do_warn("can't read remote block for attributes"
338
" of inode %llu\n", ino);
342
ASSERT(mp->m_sb.sb_blocksize == XFS_BUF_COUNT(bp));
343
length = MIN(XFS_BUF_COUNT(bp), valuelen - amountdone);
344
bcopy(XFS_BUF_PTR(bp), value, length);
345
amountdone += length;
354
* freespace map for directory and attribute leaf blocks (1 bit per byte)
355
* 1 == used, 0 == free
357
static da_freemap_t attr_freemap[DA_BMAP_SIZE];
359
/* The block is read in. The magic number and forward / backward
360
* links are checked by the caller process_leaf_attr.
361
* If any problems occur the routine returns with non-zero. In
362
* this case the next step is to clear the attribute fork, by
363
* changing it to shortform and zeroing it out. Forkoff need not
368
process_leaf_attr_block(
370
xfs_attr_leafblock_t *leaf,
374
xfs_dahash_t last_hashval,
375
xfs_dahash_t *current_hashval,
378
xfs_attr_leaf_entry_t *entry;
379
xfs_attr_leaf_name_local_t *local;
380
xfs_attr_leaf_name_remote_t *remotep;
381
int i, start, stop, clearit, usedbs, firstb, thissize;
383
clearit = usedbs = 0;
385
firstb = mp->m_sb.sb_blocksize;
386
stop = sizeof(xfs_attr_leaf_hdr_t);
388
/* does the count look sorta valid? */
389
if (INT_GET(leaf->hdr.count, ARCH_CONVERT)
390
* sizeof(xfs_attr_leaf_entry_t)
391
+ sizeof(xfs_attr_leaf_hdr_t)
393
do_warn("bad attribute count %d in attr block %u, inode %llu\n",
394
(int) INT_GET(leaf->hdr.count, ARCH_CONVERT),
399
init_da_freemap(attr_freemap);
400
(void) set_da_freemap(mp, attr_freemap, 0, stop);
402
/* go thru each entry checking for problems */
403
for (i = 0, entry = &leaf->entries[0];
404
i < INT_GET(leaf->hdr.count, ARCH_CONVERT);
407
/* check if index is within some boundary. */
408
if (INT_GET(entry->nameidx, ARCH_CONVERT) > XFS_LBSIZE(mp)) {
409
do_warn("bad attribute nameidx %d in attr block %u, inode %llu\n",
410
(int)INT_GET(entry->nameidx, ARCH_CONVERT),
416
if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_INCOMPLETE) {
417
/* we are inconsistent state. get rid of us */
418
do_warn("attribute entry #%d in attr block %u, inode %llu is INCOMPLETE\n",
424
/* mark the entry used */
425
start = (__psint_t)&leaf->entries[i] - (__psint_t)leaf;
426
stop = start + sizeof(xfs_attr_leaf_entry_t);
427
if (set_da_freemap(mp, attr_freemap, start, stop)) {
428
do_warn("attribute entry %d in attr block %u, inode %llu claims already used space\n",
431
break; /* got an overlap */
434
if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_LOCAL) {
436
local = XFS_ATTR_LEAF_NAME_LOCAL(leaf, i);
437
if ((INT_GET(local->namelen, ARCH_CONVERT) == 0) ||
438
(namecheck((char *)&local->nameval[0],
439
INT_GET(local->namelen, ARCH_CONVERT)))) {
440
do_warn("attribute entry %d in attr block %u, inode %llu has bad name (namelen = %d)\n",
441
i, da_bno, ino, (int) INT_GET(local->namelen, ARCH_CONVERT));
447
/* Check on the hash value. Checking ordering of hash values
448
* is not necessary, since one wrong one clears the whole
449
* fork. If the ordering's wrong, it's caught here or
450
* the kernel code has a bug with transaction logging
451
* or attributes itself. For paranoia reasons, let's check
452
* ordering anyway in case both the name value and the
453
* hashvalue were wrong but matched. Unlikely, however.
455
if (INT_GET(entry->hashval, ARCH_CONVERT) !=
456
libxfs_da_hashname((char *)&local->nameval[0],
457
INT_GET(local->namelen, ARCH_CONVERT)) ||
458
(INT_GET(entry->hashval, ARCH_CONVERT)
460
do_warn("bad hashvalue for attribute entry %d in attr block %u, inode %llu\n",
466
/* Only check values for root security attributes */
467
if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT)
468
if (valuecheck((char *)&local->nameval[0], NULL,
469
INT_GET(local->namelen, ARCH_CONVERT), INT_GET(local->valuelen, ARCH_CONVERT))) {
470
do_warn("bad security value for attribute entry %d in attr block %u, inode %llu\n",
475
thissize = XFS_ATTR_LEAF_ENTSIZE_LOCAL(
476
INT_GET(local->namelen, ARCH_CONVERT), INT_GET(local->valuelen, ARCH_CONVERT));
479
/* do the remote case */
480
remotep = XFS_ATTR_LEAF_NAME_REMOTE(leaf, i);
481
thissize = XFS_ATTR_LEAF_ENTSIZE_REMOTE(
482
INT_GET(remotep->namelen, ARCH_CONVERT));
484
if ((INT_GET(remotep->namelen, ARCH_CONVERT) == 0) ||
485
(namecheck((char *)&remotep->name[0],
486
INT_GET(remotep->namelen, ARCH_CONVERT))) ||
487
(INT_GET(entry->hashval, ARCH_CONVERT)
488
!= libxfs_da_hashname(
489
(char *)&remotep->name[0],
490
INT_GET(remotep->namelen, ARCH_CONVERT))) ||
491
(INT_GET(entry->hashval, ARCH_CONVERT)
493
(INT_GET(remotep->valueblk, ARCH_CONVERT) == 0)) {
494
do_warn("inconsistent remote attribute entry %d in attr block %u, ino %llu\n",
500
if (INT_GET(entry->flags, ARCH_CONVERT) & XFS_ATTR_ROOT) {
502
if ((value = malloc(INT_GET(remotep->valuelen, ARCH_CONVERT)))==NULL){
503
do_warn("cannot malloc enough for remotevalue attribute for inode %llu\n",ino);
504
do_warn("SKIPPING this remote attribute\n");
507
if (rmtval_get(mp, ino, blkmap,
508
INT_GET(remotep->valueblk, ARCH_CONVERT),
509
INT_GET(remotep->valuelen, ARCH_CONVERT), value)) {
510
do_warn("remote attribute get failed for entry %d, inode %llu\n", i,ino);
515
if (valuecheck((char *)&remotep->name[0], value,
516
INT_GET(remotep->namelen, ARCH_CONVERT), INT_GET(remotep->valuelen, ARCH_CONVERT))){
517
do_warn("remote attribute value check failed for entry %d, inode %llu\n", i, ino);
526
*current_hashval = last_hashval
527
= INT_GET(entry->hashval, ARCH_CONVERT);
529
if (set_da_freemap(mp, attr_freemap, INT_GET(entry->nameidx, ARCH_CONVERT),
530
INT_GET(entry->nameidx, ARCH_CONVERT) + thissize)) {
531
do_warn("attribute entry %d in attr block %u, inode %llu claims used space\n",
534
break; /* got an overlap */
537
if (INT_GET(entry->nameidx, ARCH_CONVERT) < firstb)
538
firstb = INT_GET(entry->nameidx, ARCH_CONVERT);
543
/* verify the header information is correct */
545
/* if the holes flag is set, don't reset first_used unless it's
546
* pointing to used bytes. we're being conservative here
547
* since the block will get compacted anyhow by the kernel.
550
if ( (INT_GET(leaf->hdr.holes, ARCH_CONVERT) == 0
551
&& firstb != INT_GET(leaf->hdr.firstused, ARCH_CONVERT))
552
|| INT_GET(leaf->hdr.firstused, ARCH_CONVERT) > firstb) {
554
do_warn("- resetting first used heap value from %d to %d in block %u of attribute fork of inode %llu\n",
555
(int)INT_GET(leaf->hdr.firstused,
556
ARCH_CONVERT), firstb,
558
INT_SET(leaf->hdr.firstused,
559
ARCH_CONVERT, firstb);
562
do_warn("- would reset first used value from %d to %d in block %u of attribute fork of inode %llu\n",
563
(int)INT_GET(leaf->hdr.firstused,
564
ARCH_CONVERT), firstb,
569
if (usedbs != INT_GET(leaf->hdr.usedbytes, ARCH_CONVERT)) {
571
do_warn("- resetting usedbytes cnt from %d to %d in block %u of attribute fork of inode %llu\n",
572
(int)INT_GET(leaf->hdr.usedbytes,
573
ARCH_CONVERT), usedbs, da_bno, ino);
574
INT_SET(leaf->hdr.usedbytes,
575
ARCH_CONVERT, usedbs);
578
do_warn("- would reset usedbytes cnt from %d to %d in block %u of attribute fork of %llu\n",
579
(int)INT_GET(leaf->hdr.usedbytes,
580
ARCH_CONVERT), usedbs,da_bno,ino);
584
/* there's a lot of work in process_leaf_dir_block to go thru
585
* checking for holes and compacting if appropiate. I don't think
586
* attributes need all that, so let's just leave the holes. If
587
* we discover later that this is a good place to do compaction
588
* we can add it then.
591
return (clearit); /* and repair */
596
* returns 0 if the attribute fork is ok, 1 if it has to be junked.
599
process_leaf_attr_level(xfs_mount_t *mp,
600
da_bt_cursor_t *da_cursor)
603
xfs_attr_leafblock_t *leaf;
606
xfs_dfsbno_t dev_bno;
608
xfs_dablk_t prev_bno;
609
xfs_dahash_t current_hashval = 0;
610
xfs_dahash_t greatest_hashval;
612
da_bno = da_cursor->level[0].bno;
613
ino = da_cursor->ino;
618
dev_bno = blkmap_get(da_cursor->blkmap, da_bno);
620
* 0 is the root block and no block
621
* pointer can point to the root block of the btree
625
if (dev_bno == NULLDFSBNO) {
626
do_warn("can't map block %u for attribute fork "
627
"for inode %llu\n", da_bno, ino);
631
bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, dev_bno),
632
XFS_FSB_TO_BB(mp, 1), 0);
634
do_warn("can't read file block %u (fsbno %llu) for"
635
" attribute fork of inode %llu\n",
636
da_bno, dev_bno, ino);
640
leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp);
642
/* check magic number for leaf directory btree block */
643
if (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)
644
!= XFS_ATTR_LEAF_MAGIC) {
645
do_warn("bad attribute leaf magic %#x for inode %llu\n",
646
leaf->hdr.info.magic, ino);
652
* for each block, process the block, verify it's path,
653
* then get next block. update cursor values along the way
655
if (process_leaf_attr_block(mp, leaf, da_bno, ino,
656
da_cursor->blkmap, current_hashval,
657
&greatest_hashval, &repair)) {
663
* index can be set to hdr.count so match the
664
* indexes of the interior blocks -- which at the
665
* end of the block will point to 1 after the final
666
* real entry in the block
668
da_cursor->level[0].hashval = greatest_hashval;
669
da_cursor->level[0].bp = bp;
670
da_cursor->level[0].bno = da_bno;
671
da_cursor->level[0].index
672
= INT_GET(leaf->hdr.count, ARCH_CONVERT);
673
da_cursor->level[0].dirty = repair;
675
if (INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != prev_bno) {
676
do_warn("bad sibling back pointer for block %u in "
677
"attribute fork for inode %llu\n", da_bno, ino);
683
da_bno = INT_GET(leaf->hdr.info.forw, ARCH_CONVERT);
685
if (da_bno != 0 && verify_da_path(mp, da_cursor, 0)) {
690
current_hashval = greatest_hashval;
692
if (repair && !no_modify) {
693
libxfs_writebuf(bp, 0);
698
} while (da_bno != 0);
700
if (verify_final_da_path(mp, da_cursor, 0)) {
702
* verify the final path up (right-hand-side) if still ok
704
do_warn("bad hash path in attribute fork for inode %llu\n",
709
/* releases all buffers holding interior btree blocks */
710
release_da_cursor(mp, da_cursor, 0);
714
/* release all buffers holding interior btree blocks */
715
err_release_da_cursor(mp, da_cursor, 0);
721
* a node directory is a true btree -- where the attribute fork
722
* has gotten big enough that it is represented as a non-trivial (e.g.
723
* has more than just a block) btree.
725
* Note that if we run into any problems, we will trash the attribute fork.
727
* returns 0 if things are ok, 1 if bad
728
* Note this code has been based off process_node_dir.
739
da_bt_cursor_t da_cursor;
742
* try again -- traverse down left-side of tree until we hit
743
* the left-most leaf block setting up the btree cursor along
744
* the way. Then walk the leaf blocks left-to-right, calling
745
* a parent-verification routine each time we traverse a block.
747
bzero(&da_cursor, sizeof(da_bt_cursor_t));
748
da_cursor.active = 0;
752
da_cursor.greatest_bno = 0;
753
da_cursor.blkmap = blkmap;
756
* now process interior node. don't have any buffers held in this path.
758
error = traverse_int_dablock(mp, &da_cursor, &bno, XFS_ATTR_FORK);
760
return(1); /* 0 means unsuccessful */
763
* now pass cursor and bno into leaf-block processing routine
764
* the leaf dir level routine checks the interior paths
765
* up to the root including the final right-most path.
768
return (process_leaf_attr_level(mp, &da_cursor));
772
* Start processing for a leaf or fuller btree.
773
* A leaf directory is one where the attribute fork is too big for
774
* the inode but is small enough to fit into one btree block
775
* outside the inode. This code is modelled after process_leaf_dir_block.
777
* returns 0 if things are ok, 1 if bad (attributes needs to be junked)
778
* repair is set, if anything was changed, but attributes can live thru it
782
process_longform_attr(
787
int *repair) /* out - 1 if something was fixed */
789
xfs_attr_leafblock_t *leaf;
792
xfs_dahash_t next_hashval;
797
bno = blkmap_get(blkmap, 0);
799
if ( bno == NULLDFSBNO ) {
800
if (INT_GET(dip->di_core.di_anextents, ARCH_CONVERT) == 0 &&
801
dip->di_core.di_aformat == XFS_DINODE_FMT_EXTENTS )
802
/* it's okay the kernel can handle this state */
805
do_warn("block 0 of inode %llu attribute fork"
806
" is missing\n", ino);
810
/* FIX FOR bug 653709 -- EKN */
811
if (mp->m_sb.sb_agcount < XFS_FSB_TO_AGNO(mp, bno)) {
812
do_warn("agno of attribute fork of inode %llu out of "
813
"regular partition\n", ino);
817
bp = libxfs_readbuf(mp->m_dev, XFS_FSB_TO_DADDR(mp, bno),
818
XFS_FSB_TO_BB(mp, 1), 0);
820
do_warn("can't read block 0 of inode %llu attribute fork\n",
825
/* verify leaf block */
826
leaf = (xfs_attr_leafblock_t *)XFS_BUF_PTR(bp);
828
/* check sibling pointers in leaf block or root block 0 before
829
* we have to release the btree block
831
if ( INT_GET(leaf->hdr.info.forw, ARCH_CONVERT) != 0
832
|| INT_GET(leaf->hdr.info.back, ARCH_CONVERT) != 0) {
834
do_warn("clearing forw/back pointers in block 0 "
835
"for attributes in inode %llu\n", ino);
837
INT_SET(leaf->hdr.info.forw, ARCH_CONVERT, 0);
838
INT_SET(leaf->hdr.info.back, ARCH_CONVERT, 0);
840
do_warn("would clear forw/back pointers in block 0 "
841
"for attributes in inode %llu\n", ino);
846
* use magic number to tell us what type of attribute this is.
847
* it's possible to have a node or leaf attribute in either an
848
* extent format or btree format attribute fork.
850
switch (INT_GET(leaf->hdr.info.magic, ARCH_CONVERT)) {
851
case XFS_ATTR_LEAF_MAGIC: /* leaf-form attribute */
852
if (process_leaf_attr_block(mp, leaf, 0, ino, blkmap,
853
0, &next_hashval, repair)) {
854
/* the block is bad. lose the attribute fork. */
858
*repair = *repair || repairlinks;
861
case XFS_DA_NODE_MAGIC: /* btree-form attribute */
862
/* must do this now, to release block 0 before the traversal */
865
libxfs_writebuf(bp, 0);
868
return (process_node_attr(mp, ino, dip, blkmap)); /* + repair */
870
do_warn("bad attribute leaf magic # %#x for dir ino %llu\n",
871
INT_GET(leaf->hdr.info.magic, ARCH_CONVERT), ino);
876
if (*repair && !no_modify)
877
libxfs_writebuf(bp, 0);
881
return(0); /* repair may be set */
886
xfs_acl_get_endian(xfs_acl_t *aclp)
888
xfs_acl_entry_t *ace, *end;
890
INT_SET(aclp->acl_cnt, ARCH_CONVERT, aclp->acl_cnt);
891
end = &aclp->acl_entry[0]+aclp->acl_cnt;
892
for (ace = &aclp->acl_entry[0]; ace < end; ace++) {
893
INT_SET(ace->ae_tag, ARCH_CONVERT, ace->ae_tag);
894
INT_SET(ace->ae_id, ARCH_CONVERT, ace->ae_id);
895
INT_SET(ace->ae_perm, ARCH_CONVERT, ace->ae_perm);
900
* returns 1 if attributes got cleared
901
* and 0 if things are ok.
909
int *repair) /* returned if we did repair */
912
xfs_dinode_core_t *dinoc;
914
xfs_attr_shortform_t *asf;
916
dinoc = &dip->di_core;
917
asf = (xfs_attr_shortform_t *) XFS_DFORK_APTR_ARCH(dip, ARCH_CONVERT);
919
if (dinoc->di_aformat == XFS_DINODE_FMT_LOCAL) {
920
ASSERT(INT_GET(asf->hdr.totsize, ARCH_CONVERT) <= XFS_DFORK_ASIZE_ARCH(dip, mp, ARCH_CONVERT));
921
err = process_shortform_attr(ino, dip, repair);
922
} else if (dinoc->di_aformat == XFS_DINODE_FMT_EXTENTS ||
923
dinoc->di_aformat == XFS_DINODE_FMT_BTREE) {
924
err = process_longform_attr(mp, ino, dip, blkmap,
926
/* if err, convert this to shortform and clear it */
927
/* if repair and no error, it's taken care of */
929
do_warn("illegal attribute format %d, ino %llu\n",
930
dinoc->di_aformat, ino);
933
return (err); /* and repair */
940
xfs_acl_valid(xfs_acl_t *aclp)
942
xfs_acl_entry_t *entry, *e;
943
int user = 0, group = 0, other = 0, mask = 0, mask_required = 0;
949
xfs_acl_get_endian(aclp);
951
if (aclp->acl_cnt > XFS_ACL_MAX_ENTRIES)
954
for (i = 0; i < aclp->acl_cnt; i++) {
955
entry = &aclp->acl_entry[i];
956
switch (entry->ae_tag) {
971
for (j = i + 1; j < aclp->acl_cnt; j++) {
972
e = &aclp->acl_entry[j];
973
if (e->ae_id == entry->ae_id &&
974
e->ae_tag == entry->ae_tag)
987
if (!user || !group || !other || (mask_required && !mask))
997
* Check a category or division set to ensure that all values are in
998
* ascending order and each division or category appears only once.
1001
__check_setvalue(const unsigned short *list, unsigned short count)
1005
for (i = 1; i < count ; i++)
1006
if (list[i] <= list[i-1])
1013
* Check the validity of a MAC label.
1016
xfs_mac_valid(xfs_mac_label_t *lp)
1022
* if the total category set and division set is greater than 250
1025
if ((lp->ml_catcount + lp->ml_divcount) > XFS_MAC_MAX_SETS)
1029
* check whether the msentype value is valid, and do they have
1030
* appropriate level, category association.
1032
switch (lp->ml_msen_type) {
1033
case MSEN_ADMIN_LABEL:
1034
case MSEN_EQUAL_LABEL:
1035
case MSEN_HIGH_LABEL:
1036
case MSEN_MLD_HIGH_LABEL:
1037
case MSEN_LOW_LABEL:
1038
case MSEN_MLD_LOW_LABEL:
1039
if (lp->ml_level != 0 || lp->ml_catcount > 0 )
1042
case MSEN_TCSEC_LABEL:
1043
case MSEN_MLD_LABEL:
1044
if (lp->ml_catcount > 0 &&
1045
__check_setvalue(lp->ml_list,
1046
lp->ml_catcount) == -1)
1049
case MSEN_UNKNOWN_LABEL:
1055
* check whether the minttype value is valid, and do they have
1056
* appropriate grade, division association.
1058
switch (lp->ml_mint_type) {
1059
case MINT_BIBA_LABEL:
1060
if (lp->ml_divcount > 0 &&
1061
__check_setvalue(lp->ml_list + lp->ml_catcount,
1062
lp->ml_divcount) == -1)
1065
case MINT_EQUAL_LABEL:
1066
case MINT_HIGH_LABEL:
1067
case MINT_LOW_LABEL:
1068
if (lp->ml_grade != 0 || lp->ml_divcount > 0 )