0001
0002
0003
0004
0005
0006
0007 #include "xfs.h"
0008 #include "xfs_fs.h"
0009 #include "xfs_shared.h"
0010 #include "xfs_format.h"
0011 #include "xfs_log_format.h"
0012 #include "xfs_trans_resv.h"
0013 #include "xfs_mount.h"
0014 #include "xfs_da_format.h"
0015 #include "xfs_inode.h"
0016 #include "xfs_trans.h"
0017 #include "xfs_bmap.h"
0018 #include "xfs_da_btree.h"
0019 #include "xfs_attr.h"
0020 #include "xfs_attr_sf.h"
0021 #include "xfs_attr_leaf.h"
0022 #include "xfs_error.h"
0023 #include "xfs_trace.h"
0024 #include "xfs_dir2.h"
0025
0026 STATIC int
0027 xfs_attr_shortform_compare(const void *a, const void *b)
0028 {
0029 xfs_attr_sf_sort_t *sa, *sb;
0030
0031 sa = (xfs_attr_sf_sort_t *)a;
0032 sb = (xfs_attr_sf_sort_t *)b;
0033 if (sa->hash < sb->hash) {
0034 return -1;
0035 } else if (sa->hash > sb->hash) {
0036 return 1;
0037 } else {
0038 return sa->entno - sb->entno;
0039 }
0040 }
0041
0042 #define XFS_ISRESET_CURSOR(cursor) \
0043 (!((cursor)->initted) && !((cursor)->hashval) && \
0044 !((cursor)->blkno) && !((cursor)->offset))
0045
0046
0047
0048
0049
0050
0051
0052 static int
0053 xfs_attr_shortform_list(
0054 struct xfs_attr_list_context *context)
0055 {
0056 struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
0057 struct xfs_inode *dp = context->dp;
0058 struct xfs_attr_sf_sort *sbuf, *sbp;
0059 struct xfs_attr_shortform *sf;
0060 struct xfs_attr_sf_entry *sfe;
0061 int sbsize, nsbuf, count, i;
0062 int error = 0;
0063
0064 sf = (struct xfs_attr_shortform *)dp->i_af.if_u1.if_data;
0065 ASSERT(sf != NULL);
0066 if (!sf->hdr.count)
0067 return 0;
0068
0069 trace_xfs_attr_list_sf(context);
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080 if (context->bufsize == 0 ||
0081 (XFS_ISRESET_CURSOR(cursor) &&
0082 (dp->i_af.if_bytes + sf->hdr.count * 16) < context->bufsize)) {
0083 for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
0084 if (XFS_IS_CORRUPT(context->dp->i_mount,
0085 !xfs_attr_namecheck(sfe->nameval,
0086 sfe->namelen)))
0087 return -EFSCORRUPTED;
0088 context->put_listent(context,
0089 sfe->flags,
0090 sfe->nameval,
0091 (int)sfe->namelen,
0092 (int)sfe->valuelen);
0093
0094
0095
0096
0097 if (context->seen_enough)
0098 break;
0099 sfe = xfs_attr_sf_nextentry(sfe);
0100 }
0101 trace_xfs_attr_list_sf_all(context);
0102 return 0;
0103 }
0104
0105
0106 if (context->bufsize == 0)
0107 return 0;
0108
0109
0110
0111
0112 sbsize = sf->hdr.count * sizeof(*sbuf);
0113 sbp = sbuf = kmem_alloc(sbsize, KM_NOFS);
0114
0115
0116
0117
0118
0119 nsbuf = 0;
0120 for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
0121 if (unlikely(
0122 ((char *)sfe < (char *)sf) ||
0123 ((char *)sfe >= ((char *)sf + dp->i_af.if_bytes)))) {
0124 XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
0125 XFS_ERRLEVEL_LOW,
0126 context->dp->i_mount, sfe,
0127 sizeof(*sfe));
0128 kmem_free(sbuf);
0129 return -EFSCORRUPTED;
0130 }
0131
0132 sbp->entno = i;
0133 sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
0134 sbp->name = sfe->nameval;
0135 sbp->namelen = sfe->namelen;
0136
0137 sbp->valuelen = sfe->valuelen;
0138 sbp->flags = sfe->flags;
0139 sfe = xfs_attr_sf_nextentry(sfe);
0140 sbp++;
0141 nsbuf++;
0142 }
0143
0144
0145
0146
0147 xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
0148
0149
0150
0151
0152 count = 0;
0153 cursor->initted = 1;
0154 cursor->blkno = 0;
0155 for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
0156 if (sbp->hash == cursor->hashval) {
0157 if (cursor->offset == count) {
0158 break;
0159 }
0160 count++;
0161 } else if (sbp->hash > cursor->hashval) {
0162 break;
0163 }
0164 }
0165 if (i == nsbuf)
0166 goto out;
0167
0168
0169
0170
0171 for ( ; i < nsbuf; i++, sbp++) {
0172 if (cursor->hashval != sbp->hash) {
0173 cursor->hashval = sbp->hash;
0174 cursor->offset = 0;
0175 }
0176 if (XFS_IS_CORRUPT(context->dp->i_mount,
0177 !xfs_attr_namecheck(sbp->name,
0178 sbp->namelen))) {
0179 error = -EFSCORRUPTED;
0180 goto out;
0181 }
0182 context->put_listent(context,
0183 sbp->flags,
0184 sbp->name,
0185 sbp->namelen,
0186 sbp->valuelen);
0187 if (context->seen_enough)
0188 break;
0189 cursor->offset++;
0190 }
0191 out:
0192 kmem_free(sbuf);
0193 return error;
0194 }
0195
0196
0197
0198
0199
0200 STATIC int
0201 xfs_attr_node_list_lookup(
0202 struct xfs_attr_list_context *context,
0203 struct xfs_attrlist_cursor_kern *cursor,
0204 struct xfs_buf **pbp)
0205 {
0206 struct xfs_da3_icnode_hdr nodehdr;
0207 struct xfs_da_intnode *node;
0208 struct xfs_da_node_entry *btree;
0209 struct xfs_inode *dp = context->dp;
0210 struct xfs_mount *mp = dp->i_mount;
0211 struct xfs_trans *tp = context->tp;
0212 struct xfs_buf *bp;
0213 int i;
0214 int error = 0;
0215 unsigned int expected_level = 0;
0216 uint16_t magic;
0217
0218 ASSERT(*pbp == NULL);
0219 cursor->blkno = 0;
0220 for (;;) {
0221 error = xfs_da3_node_read(tp, dp, cursor->blkno, &bp,
0222 XFS_ATTR_FORK);
0223 if (error)
0224 return error;
0225 node = bp->b_addr;
0226 magic = be16_to_cpu(node->hdr.info.magic);
0227 if (magic == XFS_ATTR_LEAF_MAGIC ||
0228 magic == XFS_ATTR3_LEAF_MAGIC)
0229 break;
0230 if (magic != XFS_DA_NODE_MAGIC &&
0231 magic != XFS_DA3_NODE_MAGIC) {
0232 XFS_CORRUPTION_ERROR(__func__, XFS_ERRLEVEL_LOW, mp,
0233 node, sizeof(*node));
0234 goto out_corruptbuf;
0235 }
0236
0237 xfs_da3_node_hdr_from_disk(mp, &nodehdr, node);
0238
0239
0240 if (nodehdr.level >= XFS_DA_NODE_MAXDEPTH)
0241 goto out_corruptbuf;
0242
0243
0244 if (cursor->blkno == 0)
0245 expected_level = nodehdr.level - 1;
0246 else if (expected_level != nodehdr.level)
0247 goto out_corruptbuf;
0248 else
0249 expected_level--;
0250
0251 btree = nodehdr.btree;
0252 for (i = 0; i < nodehdr.count; btree++, i++) {
0253 if (cursor->hashval <= be32_to_cpu(btree->hashval)) {
0254 cursor->blkno = be32_to_cpu(btree->before);
0255 trace_xfs_attr_list_node_descend(context,
0256 btree);
0257 break;
0258 }
0259 }
0260 xfs_trans_brelse(tp, bp);
0261
0262 if (i == nodehdr.count)
0263 return 0;
0264
0265
0266 if (XFS_IS_CORRUPT(mp, cursor->blkno == 0))
0267 return -EFSCORRUPTED;
0268 }
0269
0270 if (expected_level != 0)
0271 goto out_corruptbuf;
0272
0273 *pbp = bp;
0274 return 0;
0275
0276 out_corruptbuf:
0277 xfs_buf_mark_corrupt(bp);
0278 xfs_trans_brelse(tp, bp);
0279 return -EFSCORRUPTED;
0280 }
0281
0282 STATIC int
0283 xfs_attr_node_list(
0284 struct xfs_attr_list_context *context)
0285 {
0286 struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
0287 struct xfs_attr3_icleaf_hdr leafhdr;
0288 struct xfs_attr_leafblock *leaf;
0289 struct xfs_da_intnode *node;
0290 struct xfs_buf *bp;
0291 struct xfs_inode *dp = context->dp;
0292 struct xfs_mount *mp = dp->i_mount;
0293 int error = 0;
0294
0295 trace_xfs_attr_node_list(context);
0296
0297 cursor->initted = 1;
0298
0299
0300
0301
0302
0303
0304 bp = NULL;
0305 if (cursor->blkno > 0) {
0306 error = xfs_da3_node_read(context->tp, dp, cursor->blkno, &bp,
0307 XFS_ATTR_FORK);
0308 if ((error != 0) && (error != -EFSCORRUPTED))
0309 return error;
0310 if (bp) {
0311 struct xfs_attr_leaf_entry *entries;
0312
0313 node = bp->b_addr;
0314 switch (be16_to_cpu(node->hdr.info.magic)) {
0315 case XFS_DA_NODE_MAGIC:
0316 case XFS_DA3_NODE_MAGIC:
0317 trace_xfs_attr_list_wrong_blk(context);
0318 xfs_trans_brelse(context->tp, bp);
0319 bp = NULL;
0320 break;
0321 case XFS_ATTR_LEAF_MAGIC:
0322 case XFS_ATTR3_LEAF_MAGIC:
0323 leaf = bp->b_addr;
0324 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
0325 &leafhdr, leaf);
0326 entries = xfs_attr3_leaf_entryp(leaf);
0327 if (cursor->hashval > be32_to_cpu(
0328 entries[leafhdr.count - 1].hashval)) {
0329 trace_xfs_attr_list_wrong_blk(context);
0330 xfs_trans_brelse(context->tp, bp);
0331 bp = NULL;
0332 } else if (cursor->hashval <= be32_to_cpu(
0333 entries[0].hashval)) {
0334 trace_xfs_attr_list_wrong_blk(context);
0335 xfs_trans_brelse(context->tp, bp);
0336 bp = NULL;
0337 }
0338 break;
0339 default:
0340 trace_xfs_attr_list_wrong_blk(context);
0341 xfs_trans_brelse(context->tp, bp);
0342 bp = NULL;
0343 }
0344 }
0345 }
0346
0347
0348
0349
0350
0351
0352 if (bp == NULL) {
0353 error = xfs_attr_node_list_lookup(context, cursor, &bp);
0354 if (error || !bp)
0355 return error;
0356 }
0357 ASSERT(bp != NULL);
0358
0359
0360
0361
0362
0363
0364 for (;;) {
0365 leaf = bp->b_addr;
0366 error = xfs_attr3_leaf_list_int(bp, context);
0367 if (error)
0368 break;
0369 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
0370 if (context->seen_enough || leafhdr.forw == 0)
0371 break;
0372 cursor->blkno = leafhdr.forw;
0373 xfs_trans_brelse(context->tp, bp);
0374 error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
0375 &bp);
0376 if (error)
0377 return error;
0378 }
0379 xfs_trans_brelse(context->tp, bp);
0380 return error;
0381 }
0382
0383
0384
0385
0386 int
0387 xfs_attr3_leaf_list_int(
0388 struct xfs_buf *bp,
0389 struct xfs_attr_list_context *context)
0390 {
0391 struct xfs_attrlist_cursor_kern *cursor = &context->cursor;
0392 struct xfs_attr_leafblock *leaf;
0393 struct xfs_attr3_icleaf_hdr ichdr;
0394 struct xfs_attr_leaf_entry *entries;
0395 struct xfs_attr_leaf_entry *entry;
0396 int i;
0397 struct xfs_mount *mp = context->dp->i_mount;
0398
0399 trace_xfs_attr_list_leaf(context);
0400
0401 leaf = bp->b_addr;
0402 xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
0403 entries = xfs_attr3_leaf_entryp(leaf);
0404
0405 cursor->initted = 1;
0406
0407
0408
0409
0410 if (context->resynch) {
0411 entry = &entries[0];
0412 for (i = 0; i < ichdr.count; entry++, i++) {
0413 if (be32_to_cpu(entry->hashval) == cursor->hashval) {
0414 if (cursor->offset == context->dupcnt) {
0415 context->dupcnt = 0;
0416 break;
0417 }
0418 context->dupcnt++;
0419 } else if (be32_to_cpu(entry->hashval) >
0420 cursor->hashval) {
0421 context->dupcnt = 0;
0422 break;
0423 }
0424 }
0425 if (i == ichdr.count) {
0426 trace_xfs_attr_list_notfound(context);
0427 return 0;
0428 }
0429 } else {
0430 entry = &entries[0];
0431 i = 0;
0432 }
0433 context->resynch = 0;
0434
0435
0436
0437
0438 for (; i < ichdr.count; entry++, i++) {
0439 char *name;
0440 int namelen, valuelen;
0441
0442 if (be32_to_cpu(entry->hashval) != cursor->hashval) {
0443 cursor->hashval = be32_to_cpu(entry->hashval);
0444 cursor->offset = 0;
0445 }
0446
0447 if ((entry->flags & XFS_ATTR_INCOMPLETE) &&
0448 !context->allow_incomplete)
0449 continue;
0450
0451 if (entry->flags & XFS_ATTR_LOCAL) {
0452 xfs_attr_leaf_name_local_t *name_loc;
0453
0454 name_loc = xfs_attr3_leaf_name_local(leaf, i);
0455 name = name_loc->nameval;
0456 namelen = name_loc->namelen;
0457 valuelen = be16_to_cpu(name_loc->valuelen);
0458 } else {
0459 xfs_attr_leaf_name_remote_t *name_rmt;
0460
0461 name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
0462 name = name_rmt->name;
0463 namelen = name_rmt->namelen;
0464 valuelen = be32_to_cpu(name_rmt->valuelen);
0465 }
0466
0467 if (XFS_IS_CORRUPT(context->dp->i_mount,
0468 !xfs_attr_namecheck(name, namelen)))
0469 return -EFSCORRUPTED;
0470 context->put_listent(context, entry->flags,
0471 name, namelen, valuelen);
0472 if (context->seen_enough)
0473 break;
0474 cursor->offset++;
0475 }
0476 trace_xfs_attr_list_leaf_end(context);
0477 return 0;
0478 }
0479
0480
0481
0482
0483 STATIC int
0484 xfs_attr_leaf_list(
0485 struct xfs_attr_list_context *context)
0486 {
0487 struct xfs_buf *bp;
0488 int error;
0489
0490 trace_xfs_attr_leaf_list(context);
0491
0492 context->cursor.blkno = 0;
0493 error = xfs_attr3_leaf_read(context->tp, context->dp, 0, &bp);
0494 if (error)
0495 return error;
0496
0497 error = xfs_attr3_leaf_list_int(bp, context);
0498 xfs_trans_brelse(context->tp, bp);
0499 return error;
0500 }
0501
0502 int
0503 xfs_attr_list_ilocked(
0504 struct xfs_attr_list_context *context)
0505 {
0506 struct xfs_inode *dp = context->dp;
0507
0508 ASSERT(xfs_isilocked(dp, XFS_ILOCK_SHARED | XFS_ILOCK_EXCL));
0509
0510
0511
0512
0513 if (!xfs_inode_hasattr(dp))
0514 return 0;
0515 if (dp->i_af.if_format == XFS_DINODE_FMT_LOCAL)
0516 return xfs_attr_shortform_list(context);
0517 if (xfs_attr_is_leaf(dp))
0518 return xfs_attr_leaf_list(context);
0519 return xfs_attr_node_list(context);
0520 }
0521
0522 int
0523 xfs_attr_list(
0524 struct xfs_attr_list_context *context)
0525 {
0526 struct xfs_inode *dp = context->dp;
0527 uint lock_mode;
0528 int error;
0529
0530 XFS_STATS_INC(dp->i_mount, xs_attr_list);
0531
0532 if (xfs_is_shutdown(dp->i_mount))
0533 return -EIO;
0534
0535 lock_mode = xfs_ilock_attr_map_shared(dp);
0536 error = xfs_attr_list_ilocked(context);
0537 xfs_iunlock(dp, lock_mode);
0538 return error;
0539 }