📄 lcnalloc.c
字号:
/* * Now do pass 2, scanning the first part of the zone * we omitted in pass 1. */ pass = 2; zone_end = zone_start; switch (search_zone) { case 1: /* mft_zone */ zone_start = vol->mft_zone_start; break; case 2: /* data1_zone */ zone_start = vol->mft_zone_end; break; case 4: /* data2_zone */ zone_start = 0; break; default: NTFS_BUG("switch (search_zone) 2"); } /* Sanity check. */ if (zone_end < zone_start) zone_end = zone_start; bmp_pos = zone_start; ntfs_log_trace("Continuing outer while loop, pass = 2, " "zone_start = 0x%llx, zone_end = " "0x%llx, bmp_pos = 0x%llx.\n", zone_start, zone_end, bmp_pos); continue; } /* pass == 2 */done_zones_check: ntfs_log_trace("At done_zones_check, search_zone = %i, done_zones " "before = 0x%x, done_zones after = 0x%x.\n", search_zone, done_zones, done_zones | search_zone); done_zones |= search_zone; if (done_zones < 7) { ntfs_log_trace("Switching zone.\n"); /* Now switch to the next zone we haven't done yet. */ pass = 1; switch (search_zone) { case 1: ntfs_log_trace("Switching from mft zone to data1 " "zone.\n"); /* Update mft zone position. */ if (rlpos) { LCN tc; ntfs_log_trace("Before checks, vol->mft_zone_pos = 0x%llx.\n", (long long) vol->mft_zone_pos); tc = rl[rlpos - 1].lcn + rl[rlpos - 1].length; if (tc >= vol->mft_zone_end) { vol->mft_zone_pos = vol->mft_lcn; if (!vol->mft_zone_end) vol->mft_zone_pos = 0; } else if ((bmp_initial_pos >= vol->mft_zone_pos || tc > vol->mft_zone_pos) && tc >= vol->mft_lcn) vol->mft_zone_pos = tc; ntfs_log_trace("After checks, vol->mft_zone_pos = 0x%llx.\n", (long long) vol->mft_zone_pos); } /* Switch from mft zone to data1 zone. */switch_to_data1_zone: search_zone = 2; zone_start = bmp_initial_pos = vol->data1_zone_pos; zone_end = vol->nr_clusters; if (zone_start == vol->mft_zone_end) pass = 2; if (zone_start >= zone_end) { vol->data1_zone_pos = zone_start = vol->mft_zone_end; pass = 2; } break; case 2: ntfs_log_trace("Switching from data1 zone to data2 " "zone.\n"); /* Update data1 zone position. */ if (rlpos) { LCN tc; ntfs_log_trace("Before checks, vol->data1_zone_pos = 0x%llx.\n", (long long) vol->data1_zone_pos); tc = rl[rlpos - 1].lcn + rl[rlpos - 1].length; if (tc >= vol->nr_clusters) vol->data1_zone_pos = vol->mft_zone_end; else if ((bmp_initial_pos >= vol->data1_zone_pos || tc > vol->data1_zone_pos) && tc >= vol->mft_zone_end) vol->data1_zone_pos = tc; ntfs_log_trace("After checks, vol->data1_zone_pos = 0x%llx.\n", (long long) vol->data1_zone_pos); } /* Switch from data1 zone to data2 zone. */ search_zone = 4; zone_start = bmp_initial_pos = vol->data2_zone_pos; zone_end = vol->mft_zone_start; if (!zone_start) pass = 2; if (zone_start >= zone_end) { vol->data2_zone_pos = zone_start = bmp_initial_pos = 0; pass = 2; } break; case 4: ntfs_log_debug("Switching from data2 zone to data1 " "zone.\n"); /* Update data2 zone position. */ if (rlpos) { LCN tc; ntfs_log_trace("Before checks, vol->data2_zone_pos = 0x%llx.\n", (long long) vol->data2_zone_pos); tc = rl[rlpos - 1].lcn + rl[rlpos - 1].length; if (tc >= vol->mft_zone_start) vol->data2_zone_pos = 0; else if (bmp_initial_pos >= vol->data2_zone_pos || tc > vol->data2_zone_pos) vol->data2_zone_pos = tc; ntfs_log_trace("After checks, vol->data2_zone_pos = 0x%llx.\n", (long long) vol->data2_zone_pos); } /* Switch from data2 zone to data1 zone. */ goto switch_to_data1_zone; /* See above. */ default: NTFS_BUG("switch (search_zone) 3"); } ntfs_log_trace("After zone switch, search_zone = %i, pass = " "%i, bmp_initial_pos = 0x%llx, " "zone_start = 0x%llx, zone_end = " "0x%llx.\n", search_zone, pass, (long long)bmp_initial_pos, (long long)zone_start, (long long)zone_end); bmp_pos = zone_start; if (zone_start == zone_end) { ntfs_log_trace("Empty zone, going to " "done_zones_check.\n"); /* Empty zone. Don't bother searching it. */ goto done_zones_check; } ntfs_log_trace("Continuing outer while loop.\n"); continue; } /* done_zones == 7 */ ntfs_log_trace("All zones are finished.\n"); /* * All zones are finished! If DATA_ZONE, shrink mft zone. If * MFT_ZONE, we have really run out of space. */ mft_zone_size = vol->mft_zone_end - vol->mft_zone_start; ntfs_log_trace("vol->mft_zone_start = 0x%llx, vol->mft_zone_end = " "0x%llx, mft_zone_size = 0x%llx.\n", (long long)vol->mft_zone_start, (long long)vol->mft_zone_end, (long long)mft_zone_size); if (zone == MFT_ZONE || mft_zone_size <= 0) { ntfs_log_trace("No free clusters left, going to err_ret.\n"); /* Really no more space left on device. */ err = ENOSPC; goto err_ret; } /* zone == DATA_ZONE && mft_zone_size > 0 */ ntfs_log_trace("Shrinking mft zone.\n"); zone_end = vol->mft_zone_end; mft_zone_size >>= 1; if (mft_zone_size > 0) vol->mft_zone_end = vol->mft_zone_start + mft_zone_size; else /* mft zone and data2 zone no longer exist. */ vol->data2_zone_pos = vol->mft_zone_start = vol->mft_zone_end = 0; if (vol->mft_zone_pos >= vol->mft_zone_end) { vol->mft_zone_pos = vol->mft_lcn; if (!vol->mft_zone_end) vol->mft_zone_pos = 0; } bmp_pos = zone_start = bmp_initial_pos = vol->data1_zone_pos = vol->mft_zone_end; search_zone = 2; pass = 2; done_zones &= ~2; ntfs_log_trace("After shrinking mft zone, mft_zone_size = 0x%llx, " "vol->mft_zone_start = 0x%llx, " "vol->mft_zone_end = 0x%llx, vol->mft_zone_pos " "= 0x%llx, search_zone = 2, pass = 2, " "dones_zones = 0x%x, zone_start = 0x%llx, " "zone_end = 0x%llx, vol->data1_zone_pos = " "0x%llx, continuing outer while loop.\n", (long long)mft_zone_size, (long long)vol->mft_zone_start, (long long)vol->mft_zone_end, (long long)vol->mft_zone_pos, done_zones, (long long)zone_start, (long long)zone_end, (long long)vol->data1_zone_pos); } ntfs_log_debug("After outer while loop.\n");done_ret: ntfs_log_debug("At done_ret.\n"); /* Add runlist terminator element. */ rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; rl[rlpos].lcn = LCN_RL_NOT_MAPPED; rl[rlpos].length = 0; if (need_writeback) { s64 bw; ntfs_log_trace("Writing back.\n"); need_writeback = 0; bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos, br, buf); if (bw != br) { if (bw < 0) err = errno; else err = EIO; ntfs_log_trace("Bitmap writeback failed in done code path " "with error code %i.\n", err); goto err_ret; } }done_err_ret: ntfs_log_debug("At done_err_ret (follows done_ret).\n"); free(buf); /* Done! */ if (!err) return rl; ntfs_log_trace("Failed to allocate clusters. Returning with error code " "%i.\n", err); errno = err; return NULL;wb_err_ret: ntfs_log_trace("At wb_err_ret.\n"); if (need_writeback) { s64 bw; ntfs_log_trace("Writing back.\n"); need_writeback = 0; bw = ntfs_attr_pwrite(vol->lcnbmp_na, last_read_pos, br, buf); if (bw != br) { if (bw < 0) err = errno; else err = EIO; ntfs_log_trace("Bitmap writeback failed in error code path " "with error code %i.\n", err); } }err_ret: ntfs_log_trace("At err_ret.\n"); if (rl) { if (err == ENOSPC) { ntfs_log_trace("err = ENOSPC, first free lcn = 0x%llx, could " "allocate up to = 0x%llx clusters.\n", (long long)rl[0].lcn, (long long)count - clusters); } /* Add runlist terminator element. */ rl[rlpos].vcn = rl[rlpos - 1].vcn + rl[rlpos - 1].length; rl[rlpos].lcn = LCN_RL_NOT_MAPPED; rl[rlpos].length = 0; /* Deallocate all allocated clusters. */ ntfs_log_trace("Deallocating allocated clusters.\n"); ntfs_cluster_free_from_rl(vol, rl); /* Free the runlist. */ free(rl); rl = NULL; } else { if (err == ENOSPC) { ntfs_log_trace("No space left at all, err = ENOSPC, first " "free lcn = 0x%llx.\n", (long long)vol->data1_zone_pos); } } ntfs_log_trace("rl = NULL, going to done_err_ret.\n"); goto done_err_ret;}/** * ntfs_cluster_free_from_rl - free clusters from runlist * @vol: mounted ntfs volume on which to free the clusters * @rl: runlist from which deallocate clusters * * On success return 0 and on error return -1 with errno set to the error code. */int ntfs_cluster_free_from_rl(ntfs_volume *vol, runlist *rl){ ntfs_log_trace("Entering.\n"); for (; rl->length; rl++) { ntfs_log_trace("Dealloc lcn 0x%llx, len 0x%llx.\n", (long long)rl->lcn, (long long)rl->length); if (rl->lcn >= 0 && ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, rl->length)) { int eo = errno; ntfs_log_trace("Eeek! Deallocation of clusters failed.\n"); errno = eo; return -1; } } return 0;}/** * ntfs_cluster_free - free clusters on an ntfs volume * @vol: mounted ntfs volume on which to free the clusters * @na: attribute whose runlist describes the clusters to free * @start_vcn: vcn in @rl at which to start freeing clusters * @count: number of clusters to free or -1 for all clusters * * Free @count clusters starting at the cluster @start_vcn in the runlist * described by the attribute @na from the mounted ntfs volume @vol. * * If @count is -1, all clusters from @start_vcn to the end of the runlist * are deallocated. * * On success return the number of deallocated clusters (not counting sparse * clusters) and on error return -1 with errno set to the error code. */int ntfs_cluster_free(ntfs_volume *vol, ntfs_attr *na, VCN start_vcn, s64 count){ runlist *rl; s64 nr_freed, delta, to_free; if (!vol || !vol->lcnbmp_na || !na || start_vcn < 0 || (count < 0 && count != -1)) { ntfs_log_trace("Invalid arguments!\n"); errno = EINVAL; return -1; } ntfs_log_trace("Entering for inode 0x%llx, attr 0x%x, count 0x%llx, " "vcn 0x%llx.\n", (unsigned long long)na->ni->mft_no, na->type, (long long)count, (long long)start_vcn); rl = ntfs_attr_find_vcn(na, start_vcn); if (!rl) { if (errno == ENOENT) return 0; else return -1; } if (rl->lcn < 0 && rl->lcn != LCN_HOLE) { errno = EIO; return -1; } /* Find the starting cluster inside the run that needs freeing. */ delta = start_vcn - rl->vcn; /* The number of clusters in this run that need freeing. */ to_free = rl->length - delta; if (count >= 0 && to_free > count) to_free = count; if (rl->lcn != LCN_HOLE) { /* Do the actual freeing of the clusters in this run. */ if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn + delta, to_free)) return -1; /* We have freed @to_free real clusters. */ nr_freed = to_free; } else { /* No real clusters were freed. */ nr_freed = 0; } /* Go to the next run and adjust the number of clusters left to free. */ ++rl; if (count >= 0) count -= to_free; /* * Loop over the remaining runs, using @count as a capping value, and * free them. */ for (; rl->length && count != 0; ++rl) { // FIXME: Need to try ntfs_attr_map_runlist() for attribute // list support! (AIA) if (rl->lcn < 0 && rl->lcn != LCN_HOLE) { // FIXME: Eeek! We need rollback! (AIA) ntfs_log_trace("Eeek! invalid lcn (= %lli). Should attempt " "to map runlist! Leaving inconsistent " "metadata!\n", (long long)rl->lcn); errno = EIO; return -1; } /* The number of clusters in this run that need freeing. */ to_free = rl->length; if (count >= 0 && to_free > count) to_free = count; if (rl->lcn != LCN_HOLE) { /* Do the actual freeing of the clusters in the run. */ if (ntfs_bitmap_clear_run(vol->lcnbmp_na, rl->lcn, to_free)) { int eo = errno; // FIXME: Eeek! We need rollback! (AIA) ntfs_log_trace("Eeek! bitmap clear run failed. " "Leaving inconsistent metadata!\n"); errno = eo; return -1; } /* We have freed @to_free real clusters. */ nr_freed += to_free; } if (count >= 0) count -= to_free; } if (count != -1 && count != 0) { // FIXME: Eeek! BUG() ntfs_log_trace("Eeek! count still not zero (= %lli). Leaving " "inconsistent metadata!\n", (long long)count); errno = EIO; return -1; } /* Done. Return the number of actual clusters that were freed. */ return nr_freed;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -