📄 mft.c
字号:
pass_end = NTFS_I(vol->mft_ino)->allocated_size >> vol->mft_record_size_bits; read_unlock_irqrestore(&NTFS_I(vol->mft_ino)->size_lock, flags); read_lock_irqsave(&NTFS_I(vol->mftbmp_ino)->size_lock, flags); ll = NTFS_I(vol->mftbmp_ino)->initialized_size << 3; read_unlock_irqrestore(&NTFS_I(vol->mftbmp_ino)->size_lock, flags); if (pass_end > ll) pass_end = ll; pass = 1; if (!base_ni) data_pos = vol->mft_data_pos; else data_pos = base_ni->mft_no + 1; if (data_pos < 24) data_pos = 24; if (data_pos >= pass_end) { data_pos = 24; pass = 2; /* This happens on a freshly formatted volume. */ if (data_pos >= pass_end) return -ENOSPC; } pass_start = data_pos; ntfs_debug("Starting bitmap search: pass %u, pass_start 0x%llx, " "pass_end 0x%llx, data_pos 0x%llx.", pass, (long long)pass_start, (long long)pass_end, (long long)data_pos); /* Loop until a free mft record is found. */ for (; pass <= 2;) { /* Cap size to pass_end. */ ofs = data_pos >> 3; page_ofs = ofs & ~PAGE_CACHE_MASK; size = PAGE_CACHE_SIZE - page_ofs; ll = ((pass_end + 7) >> 3) - ofs; if (size > ll) size = ll; size <<= 3; /* * If we are still within the active pass, search the next page * for a zero bit. */ if (size) { page = ntfs_map_page(mftbmp_mapping, ofs >> PAGE_CACHE_SHIFT); if (unlikely(IS_ERR(page))) { ntfs_error(vol->sb, "Failed to read mft " "bitmap, aborting."); return PTR_ERR(page); } buf = (u8*)page_address(page) + page_ofs; bit = data_pos & 7; data_pos &= ~7ull; ntfs_debug("Before inner for loop: size 0x%x, " "data_pos 0x%llx, bit 0x%llx", size, (long long)data_pos, (long long)bit); for (; bit < size && data_pos + bit < pass_end; bit &= ~7ull, bit += 8) { byte = buf + (bit >> 3); if (*byte == 0xff) continue; b = ffz((unsigned long)*byte); if (b < 8 && b >= (bit & 7)) { ll = data_pos + (bit & ~7ull) + b; if (unlikely(ll > (1ll << 32))) { ntfs_unmap_page(page); return -ENOSPC; } *byte |= 1 << b; flush_dcache_page(page); set_page_dirty(page); ntfs_unmap_page(page); ntfs_debug("Done. (Found and " "allocated mft record " "0x%llx.)", (long long)ll); return ll; } } ntfs_debug("After inner for loop: size 0x%x, " "data_pos 0x%llx, bit 0x%llx", size, (long long)data_pos, (long long)bit); data_pos += size; ntfs_unmap_page(page); /* * If the end of the pass has not been reached yet, * continue searching the mft bitmap for a zero bit. */ if (data_pos < pass_end) continue; } /* Do the next pass. */ if (++pass == 2) { /* * Starting the second pass, in which we scan the first * part of the zone which we omitted earlier. */ pass_end = pass_start; data_pos = pass_start = 24; ntfs_debug("pass %i, pass_start 0x%llx, pass_end " "0x%llx.", pass, (long long)pass_start, (long long)pass_end); if (data_pos >= pass_end) break; } } /* No free mft records in currently initialized mft bitmap. */ ntfs_debug("Done. (No free mft records left in currently initialized " "mft bitmap.)"); return -ENOSPC;}/** * ntfs_mft_bitmap_extend_allocation_nolock - extend mft bitmap by a cluster * @vol: volume on which to extend the mft bitmap attribute * * Extend the mft bitmap attribute on the ntfs volume @vol by one cluster. * * Note: Only changes allocated_size, i.e. does not touch initialized_size or * data_size. * * Return 0 on success and -errno on error. * * Locking: - Caller must hold vol->mftbmp_lock for writing. * - This function takes NTFS_I(vol->mftbmp_ino)->runlist.lock for * writing and releases it before returning. * - This function takes vol->lcnbmp_lock for writing and releases it * before returning. */static int ntfs_mft_bitmap_extend_allocation_nolock(ntfs_volume *vol){ LCN lcn; s64 ll; unsigned long flags; struct page *page; ntfs_inode *mft_ni, *mftbmp_ni; runlist_element *rl, *rl2 = NULL; ntfs_attr_search_ctx *ctx = NULL; MFT_RECORD *mrec; ATTR_RECORD *a = NULL; int ret, mp_size; u32 old_alen = 0; u8 *b, tb; struct { u8 added_cluster:1; u8 added_run:1; u8 mp_rebuilt:1; } status = { 0, 0, 0 }; ntfs_debug("Extending mft bitmap allocation."); mft_ni = NTFS_I(vol->mft_ino); mftbmp_ni = NTFS_I(vol->mftbmp_ino); /* * Determine the last lcn of the mft bitmap. The allocated size of the * mft bitmap cannot be zero so we are ok to do this. */ down_write(&mftbmp_ni->runlist.lock); read_lock_irqsave(&mftbmp_ni->size_lock, flags); ll = mftbmp_ni->allocated_size; read_unlock_irqrestore(&mftbmp_ni->size_lock, flags); rl = ntfs_attr_find_vcn_nolock(mftbmp_ni, (ll - 1) >> vol->cluster_size_bits, NULL); if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) { up_write(&mftbmp_ni->runlist.lock); ntfs_error(vol->sb, "Failed to determine last allocated " "cluster of mft bitmap attribute."); if (!IS_ERR(rl)) ret = -EIO; else ret = PTR_ERR(rl); return ret; } lcn = rl->lcn + rl->length; ntfs_debug("Last lcn of mft bitmap attribute is 0x%llx.", (long long)lcn); /* * Attempt to get the cluster following the last allocated cluster by * hand as it may be in the MFT zone so the allocator would not give it * to us. */ ll = lcn >> 3; page = ntfs_map_page(vol->lcnbmp_ino->i_mapping, ll >> PAGE_CACHE_SHIFT); if (IS_ERR(page)) { up_write(&mftbmp_ni->runlist.lock); ntfs_error(vol->sb, "Failed to read from lcn bitmap."); return PTR_ERR(page); } b = (u8*)page_address(page) + (ll & ~PAGE_CACHE_MASK); tb = 1 << (lcn & 7ull); down_write(&vol->lcnbmp_lock); if (*b != 0xff && !(*b & tb)) { /* Next cluster is free, allocate it. */ *b |= tb; flush_dcache_page(page); set_page_dirty(page); up_write(&vol->lcnbmp_lock); ntfs_unmap_page(page); /* Update the mft bitmap runlist. */ rl->length++; rl[1].vcn++; status.added_cluster = 1; ntfs_debug("Appending one cluster to mft bitmap."); } else { up_write(&vol->lcnbmp_lock); ntfs_unmap_page(page); /* Allocate a cluster from the DATA_ZONE. */ rl2 = ntfs_cluster_alloc(vol, rl[1].vcn, 1, lcn, DATA_ZONE, true); if (IS_ERR(rl2)) { up_write(&mftbmp_ni->runlist.lock); ntfs_error(vol->sb, "Failed to allocate a cluster for " "the mft bitmap."); return PTR_ERR(rl2); } rl = ntfs_runlists_merge(mftbmp_ni->runlist.rl, rl2); if (IS_ERR(rl)) { up_write(&mftbmp_ni->runlist.lock); ntfs_error(vol->sb, "Failed to merge runlists for mft " "bitmap."); if (ntfs_cluster_free_from_rl(vol, rl2)) { ntfs_error(vol->sb, "Failed to dealocate " "allocated cluster.%s", es); NVolSetErrors(vol); } ntfs_free(rl2); return PTR_ERR(rl); } mftbmp_ni->runlist.rl = rl; status.added_run = 1; ntfs_debug("Adding one run to mft bitmap."); /* Find the last run in the new runlist. */ for (; rl[1].length; rl++) ; } /* * Update the attribute record as well. Note: @rl is the last * (non-terminator) runlist element of mft bitmap. */ mrec = map_mft_record(mft_ni); if (IS_ERR(mrec)) { ntfs_error(vol->sb, "Failed to map mft record."); ret = PTR_ERR(mrec); goto undo_alloc; } ctx = ntfs_attr_get_search_ctx(mft_ni, mrec); if (unlikely(!ctx)) { ntfs_error(vol->sb, "Failed to get search context."); ret = -ENOMEM; goto undo_alloc; } ret = ntfs_attr_lookup(mftbmp_ni->type, mftbmp_ni->name, mftbmp_ni->name_len, CASE_SENSITIVE, rl[1].vcn, NULL, 0, ctx); if (unlikely(ret)) { ntfs_error(vol->sb, "Failed to find last attribute extent of " "mft bitmap attribute."); if (ret == -ENOENT) ret = -EIO; goto undo_alloc; } a = ctx->attr; ll = sle64_to_cpu(a->data.non_resident.lowest_vcn); /* Search back for the previous last allocated cluster of mft bitmap. */ for (rl2 = rl; rl2 > mftbmp_ni->runlist.rl; rl2--) { if (ll >= rl2->vcn) break; } BUG_ON(ll < rl2->vcn); BUG_ON(ll >= rl2->vcn + rl2->length); /* Get the size for the new mapping pairs array for this extent. */ mp_size = ntfs_get_size_for_mapping_pairs(vol, rl2, ll, -1); if (unlikely(mp_size <= 0)) { ntfs_error(vol->sb, "Get size for mapping pairs failed for " "mft bitmap attribute extent."); ret = mp_size; if (!ret) ret = -EIO; goto undo_alloc; } /* Expand the attribute record if necessary. */ old_alen = le32_to_cpu(a->length); ret = ntfs_attr_record_resize(ctx->mrec, a, mp_size + le16_to_cpu(a->data.non_resident.mapping_pairs_offset)); if (unlikely(ret)) { if (ret != -ENOSPC) { ntfs_error(vol->sb, "Failed to resize attribute " "record for mft bitmap attribute."); goto undo_alloc; } // TODO: Deal with this by moving this extent to a new mft // record or by starting a new extent in a new mft record or by // moving other attributes out of this mft record. // Note: It will need to be a special mft record and if none of // those are available it gets rather complicated... ntfs_error(vol->sb, "Not enough space in this mft record to " "accomodate extended mft bitmap attribute " "extent. Cannot handle this yet."); ret = -EOPNOTSUPP; goto undo_alloc; } status.mp_rebuilt = 1; /* Generate the mapping pairs array directly into the attr record. */ ret = ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(a->data.non_resident.mapping_pairs_offset), mp_size, rl2, ll, -1, NULL); if (unlikely(ret)) { ntfs_error(vol->sb, "Failed to build mapping pairs array for " "mft bitmap attribute."); goto undo_alloc; } /* Update the highest_vcn. */ a->data.non_resident.highest_vcn = cpu_to_sle64(rl[1].vcn - 1); /* * We now have extended the mft bitmap allocated_size by one cluster. * Reflect this in the ntfs_inode structure and the attribute record. */ if (a->data.non_resident.lowest_vcn) { /* * We are not in the first attribute extent, switch to it, but * first ensure the changes will make it to disk later. */ flush_dcache_mft_record_page(ctx->ntfs_ino); mark_mft_record_dirty(ctx->ntfs_ino); ntfs_attr_reinit_search_ctx(ctx); ret = ntfs_attr_lookup(mftbmp_ni->type, mftbmp_ni->name, mftbmp_ni->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx); if (unlikely(ret)) { ntfs_error(vol->sb, "Failed to find first attribute " "extent of mft bitmap attribute."); goto restore_undo_alloc; } a = ctx->attr; } write_lock_irqsave(&mftbmp_ni->size_lock, flags); mftbmp_ni->allocated_size += vol->cluster_size; a->data.non_resident.allocated_size = cpu_to_sle64(mftbmp_ni->allocated_size); write_unlock_irqrestore(&mftbmp_ni->size_lock, flags); /* Ensure the changes make it to disk. */ flush_dcache_mft_record_page(ctx->ntfs_ino); mark_mft_record_dirty(ctx->ntfs_ino); ntfs_attr_put_search_ctx(ctx); unmap_mft_record(mft_ni); up_write(&mftbmp_ni->runlist.lock); ntfs_debug("Done."); return 0;restore_undo_alloc: ntfs_attr_reinit_search_ctx(ctx); if (ntfs_attr_lookup(mftbmp_ni->type, mftbmp_ni->name, mftbmp_ni->name_len, CASE_SENSITIVE, rl[1].vcn, NULL, 0, ctx)) { ntfs_error(vol->sb, "Failed to find last attribute extent of " "mft bitmap attribute.%s", es); write_lock_irqsave(&mftbmp_ni->size_lock, flags); mftbmp_ni->allocated_size += vol->cluster_size; write_unlock_irqrestore(&mftbmp_ni->size_lock, flags); ntfs_attr_put_search_ctx(ctx); unmap_mft_record(mft_ni); up_write(&mftbmp_ni->runlist.lock); /* * The only thing that is now wrong is ->allocated_size of the * base attribute extent which chkdsk should be able to fix. */ NVolSetErrors(vol); return ret; } a = ctx->attr; a->data.non_resident.highest_vcn = cpu_to_sle64(rl[1].vcn - 2);undo_alloc: if (status.added_cluster) { /* Truncate the last run in the runlist by one cluster. */ rl->length--; rl[1].vcn--; } else if (status.added_run) { lcn = rl->lcn; /* Remove the last run from the runlist. */ rl->lcn = rl[1].lcn; rl->length = 0; } /* Deallocate the cluster. */ down_write(&vol->lcnbmp_lock); if (ntfs_bitmap_clear_bit(vol->lcnbmp_ino, lcn)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -