* Scans a block at the indicated "level" looking for a hole or data, * depending on 'flags'. * * If level > 0, then we are scanning an indirect block looking at its * pointers. If level == 0, then we are looking at a block of dnodes. * * If we don't find what we are looking for in the block, we return ESRCH. * Otherwise, return with *offset pointing to the beginning (if searching * forwar
| 2361 | * level. |
| 2362 | */ |
| 2363 | static int |
| 2364 | dnode_next_offset_level(dnode_t *dn, int flags, uint64_t *offset, |
| 2365 | int lvl, uint64_t blkfill, uint64_t txg) |
| 2366 | { |
| 2367 | dmu_buf_impl_t *db = NULL; |
| 2368 | void *data = NULL; |
| 2369 | uint64_t epbs = dn->dn_phys->dn_indblkshift - SPA_BLKPTRSHIFT; |
| 2370 | uint64_t epb = 1ULL << epbs; |
| 2371 | uint64_t minfill, maxfill; |
| 2372 | boolean_t hole; |
| 2373 | int i, inc, error, span; |
| 2374 | |
| 2375 | ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock)); |
| 2376 | |
| 2377 | hole = ((flags & DNODE_FIND_HOLE) != 0); |
| 2378 | inc = (flags & DNODE_FIND_BACKWARDS) ? -1 : 1; |
| 2379 | ASSERT(txg == 0 || !hole); |
| 2380 | |
| 2381 | if (lvl == dn->dn_phys->dn_nlevels) { |
| 2382 | error = 0; |
| 2383 | epb = dn->dn_phys->dn_nblkptr; |
| 2384 | data = dn->dn_phys->dn_blkptr; |
| 2385 | } else { |
| 2386 | uint64_t blkid = dbuf_whichblock(dn, lvl, *offset); |
| 2387 | error = dbuf_hold_impl(dn, lvl, blkid, TRUE, FALSE, FTAG, &db); |
| 2388 | if (error) { |
| 2389 | if (error != ENOENT) |
| 2390 | return (error); |
| 2391 | if (hole) |
| 2392 | return (0); |
| 2393 | /* |
| 2394 | * This can only happen when we are searching up |
| 2395 | * the block tree for data. We don't really need to |
| 2396 | * adjust the offset, as we will just end up looking |
| 2397 | * at the pointer to this block in its parent, and its |
| 2398 | * going to be unallocated, so we will skip over it. |
| 2399 | */ |
| 2400 | return (SET_ERROR(ESRCH)); |
| 2401 | } |
| 2402 | error = dbuf_read(db, NULL, |
| 2403 | DB_RF_CANFAIL | DB_RF_HAVESTRUCT | |
| 2404 | DB_RF_NO_DECRYPT | DB_RF_NOPREFETCH); |
| 2405 | if (error) { |
| 2406 | dbuf_rele(db, FTAG); |
| 2407 | return (error); |
| 2408 | } |
| 2409 | data = db->db.db_data; |
| 2410 | rw_enter(&db->db_rwlock, RW_READER); |
| 2411 | } |
| 2412 | |
| 2413 | if (db != NULL && txg != 0 && (db->db_blkptr == NULL || |
| 2414 | db->db_blkptr->blk_birth <= txg || |
| 2415 | BP_IS_HOLE(db->db_blkptr))) { |
| 2416 | /* |
| 2417 | * This can only happen when we are searching up the tree |
| 2418 | * and these conditions mean that we need to keep climbing. |
| 2419 | */ |
| 2420 | error = SET_ERROR(ESRCH); |
no test coverage detected