/* Free any zones in NODE greater than or equal to END that are rooted in the block of indirection contained in the zone *P; OFFSET should be the zone position that *P corresponds to. For each zone pointer in *P that should be freed, FREE_ZONE is called with a pointer to the entry for that zone, and the index of the entry within *P. If every zone in *P is freed, then *P is set to 0, otherwise it is left alone. */ static void trunc_indirect_V1 (struct node *node, uint16_t end, uint16_t *p, uint16_t offset, void (*free_zone)(uint16_t *p, unsigned index), struct free_zone_run *fzr) { if (*p) { unsigned index; int modified = 0, all_freed = 1; uint16_t *ind_bh = (uint16_t *) zptr ((zone_t) *p); unsigned first = end < offset ? 0 : end - offset; /* XXX only the first block in a zone does contain pointers */ for (index = first; index < ADDR_PER_BLOCK; index++) if (ind_bh[index]) { (*free_zone)(ind_bh + index, index); if (ind_bh[index]) all_freed = 0;/* Some descendent hasn't been freed. */ else modified = 1; } if (first == 0 && all_freed) { pager_flush_some (diskfs_disk_pager, zoffs ((zone_t) *p), zone_size, 1); free_zone_run_free_ptr (fzr, (zone_t *) p); } else if (modified) record_indir_poke (node, (char *) ind_bh); } }
/* Free any blocks in NODE greater than or equal to END that are rooted in the indirect block *P; OFFSET should be the block position that *P corresponds to. For each block pointer in *P that should be freed, FREE_BLOCK is called with a pointer to the entry for that block, and the index of the entry within *P. If every block in *P is freed, then *P is set to 0, otherwise it is left alone. */ static void trunc_indirect (struct node *node, block_t end, block_t *p, block_t offset, void (*free_block)(block_t *p, unsigned index), struct free_block_run *fbr) { if (*p) { unsigned index; int modified = 0, all_freed = 1; block_t *ind_bh = (block_t *) disk_cache_block_ref (*p); unsigned first = end < offset ? 0 : end - offset; for (index = first; index < addr_per_block; index++) if (ind_bh[index]) { (*free_block)(ind_bh + index, index); if (ind_bh[index]) all_freed = 0; /* Some descendent hasn't been freed. */ else modified = 1; } if (first == 0 && all_freed) { pager_flush_some (diskfs_disk_pager, bptr_index (ind_bh) << log2_block_size, block_size, 1); free_block_run_free_ptr (fbr, p); disk_cache_block_deref (ind_bh); } else if (modified) record_indir_poke (node, ind_bh); else disk_cache_block_deref (ind_bh); } }