⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mft.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
		ntfs_error(vol->sb, "Failed to free allocated cluster.%s", es);		NVolSetErrors(vol);	}	up_write(&vol->lcnbmp_lock);	if (status.mp_rebuilt) {		if (ntfs_mapping_pairs_build(vol, (u8*)a + le16_to_cpu(				a->data.non_resident.mapping_pairs_offset),				old_alen - le16_to_cpu(				a->data.non_resident.mapping_pairs_offset),				rl2, ll, -1, NULL)) {			ntfs_error(vol->sb, "Failed to restore mapping pairs "					"array.%s", es);			NVolSetErrors(vol);		}		if (ntfs_attr_record_resize(ctx->mrec, a, old_alen)) {			ntfs_error(vol->sb, "Failed to restore attribute "					"record.%s", es);			NVolSetErrors(vol);		}		flush_dcache_mft_record_page(ctx->ntfs_ino);		mark_mft_record_dirty(ctx->ntfs_ino);	}	if (ctx)		ntfs_attr_put_search_ctx(ctx);	if (!IS_ERR(mrec))		unmap_mft_record(mft_ni);	up_write(&mftbmp_ni->runlist.lock);	return ret;}/** * ntfs_mft_bitmap_extend_initialized_nolock - extend mftbmp initialized data * @vol:	volume on which to extend the mft bitmap attribute * * Extend the initialized portion of the mft bitmap attribute on the ntfs * volume @vol by 8 bytes. * * Note:  Only changes initialized_size and data_size, i.e. requires that * allocated_size is big enough to fit the new initialized_size. * * Return 0 on success and -error on error. * * Locking: Caller must hold vol->mftbmp_lock for writing. */static int ntfs_mft_bitmap_extend_initialized_nolock(ntfs_volume *vol){	s64 old_data_size, old_initialized_size;	unsigned long flags;	struct inode *mftbmp_vi;	ntfs_inode *mft_ni, *mftbmp_ni;	ntfs_attr_search_ctx *ctx;	MFT_RECORD *mrec;	ATTR_RECORD *a;	int ret;	ntfs_debug("Extending mft bitmap initiailized (and data) size.");	mft_ni = NTFS_I(vol->mft_ino);	mftbmp_vi = vol->mftbmp_ino;	mftbmp_ni = NTFS_I(mftbmp_vi);	/* Get the attribute record. */	mrec = map_mft_record(mft_ni);	if (IS_ERR(mrec)) {		ntfs_error(vol->sb, "Failed to map mft record.");		return PTR_ERR(mrec);	}	ctx = ntfs_attr_get_search_ctx(mft_ni, mrec);	if (unlikely(!ctx)) {		ntfs_error(vol->sb, "Failed to get search context.");		ret = -ENOMEM;		goto unm_err_out;	}	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.");		if (ret == -ENOENT)			ret = -EIO;		goto put_err_out;	}	a = ctx->attr;	write_lock_irqsave(&mftbmp_ni->size_lock, flags);	old_data_size = i_size_read(mftbmp_vi);	old_initialized_size = mftbmp_ni->initialized_size;	/*	 * We can simply update the initialized_size before filling the space	 * with zeroes because the caller is holding the mft bitmap lock for	 * writing which ensures that no one else is trying to access the data.	 */	mftbmp_ni->initialized_size += 8;	a->data.non_resident.initialized_size =			cpu_to_sle64(mftbmp_ni->initialized_size);	if (mftbmp_ni->initialized_size > old_data_size) {		i_size_write(mftbmp_vi, mftbmp_ni->initialized_size);		a->data.non_resident.data_size =				cpu_to_sle64(mftbmp_ni->initialized_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);	/* Initialize the mft bitmap attribute value with zeroes. */	ret = ntfs_attr_set(mftbmp_ni, old_initialized_size, 8, 0);	if (likely(!ret)) {		ntfs_debug("Done.  (Wrote eight initialized bytes to mft "				"bitmap.");		return 0;	}	ntfs_error(vol->sb, "Failed to write to mft bitmap.");	/* Try to recover from the error. */	mrec = map_mft_record(mft_ni);	if (IS_ERR(mrec)) {		ntfs_error(vol->sb, "Failed to map mft record.%s", es);		NVolSetErrors(vol);		return ret;	}	ctx = ntfs_attr_get_search_ctx(mft_ni, mrec);	if (unlikely(!ctx)) {		ntfs_error(vol->sb, "Failed to get search context.%s", es);		NVolSetErrors(vol);		goto unm_err_out;	}	if (ntfs_attr_lookup(mftbmp_ni->type, mftbmp_ni->name,			mftbmp_ni->name_len, CASE_SENSITIVE, 0, NULL, 0, ctx)) {		ntfs_error(vol->sb, "Failed to find first attribute extent of "				"mft bitmap attribute.%s", es);		NVolSetErrors(vol);put_err_out:		ntfs_attr_put_search_ctx(ctx);unm_err_out:		unmap_mft_record(mft_ni);		goto err_out;	}	a = ctx->attr;	write_lock_irqsave(&mftbmp_ni->size_lock, flags);	mftbmp_ni->initialized_size = old_initialized_size;	a->data.non_resident.initialized_size =			cpu_to_sle64(old_initialized_size);	if (i_size_read(mftbmp_vi) != old_data_size) {		i_size_write(mftbmp_vi, old_data_size);		a->data.non_resident.data_size = cpu_to_sle64(old_data_size);	}	write_unlock_irqrestore(&mftbmp_ni->size_lock, flags);	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);#ifdef DEBUG	read_lock_irqsave(&mftbmp_ni->size_lock, flags);	ntfs_debug("Restored status of mftbmp: allocated_size 0x%llx, "			"data_size 0x%llx, initialized_size 0x%llx.",			(long long)mftbmp_ni->allocated_size,			(long long)i_size_read(mftbmp_vi),			(long long)mftbmp_ni->initialized_size);	read_unlock_irqrestore(&mftbmp_ni->size_lock, flags);#endif /* DEBUG */err_out:	return ret;}/** * ntfs_mft_data_extend_allocation_nolock - extend mft data attribute * @vol:	volume on which to extend the mft data attribute * * Extend the mft data attribute on the ntfs volume @vol by 16 mft records * worth of clusters or if not enough space for this by one mft record worth * of clusters. * * 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->mft_ino)->runlist.lock for *	      writing and releases it before returning. *	    - This function calls functions which take vol->lcnbmp_lock for *	      writing and release it before returning. */static int ntfs_mft_data_extend_allocation_nolock(ntfs_volume *vol){	LCN lcn;	VCN old_last_vcn;	s64 min_nr, nr, ll;	unsigned long flags;	ntfs_inode *mft_ni;	runlist_element *rl, *rl2;	ntfs_attr_search_ctx *ctx = NULL;	MFT_RECORD *mrec;	ATTR_RECORD *a = NULL;	int ret, mp_size;	u32 old_alen = 0;	bool mp_rebuilt = false;	ntfs_debug("Extending mft data allocation.");	mft_ni = NTFS_I(vol->mft_ino);	/*	 * Determine the preferred allocation location, i.e. the last lcn of	 * the mft data attribute.  The allocated size of the mft data	 * attribute cannot be zero so we are ok to do this.	 */	down_write(&mft_ni->runlist.lock);	read_lock_irqsave(&mft_ni->size_lock, flags);	ll = mft_ni->allocated_size;	read_unlock_irqrestore(&mft_ni->size_lock, flags);	rl = ntfs_attr_find_vcn_nolock(mft_ni,			(ll - 1) >> vol->cluster_size_bits, NULL);	if (unlikely(IS_ERR(rl) || !rl->length || rl->lcn < 0)) {		up_write(&mft_ni->runlist.lock);		ntfs_error(vol->sb, "Failed to determine last allocated "				"cluster of mft data 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 data attribute is 0x%llx.", (long long)lcn);	/* Minimum allocation is one mft record worth of clusters. */	min_nr = vol->mft_record_size >> vol->cluster_size_bits;	if (!min_nr)		min_nr = 1;	/* Want to allocate 16 mft records worth of clusters. */	nr = vol->mft_record_size << 4 >> vol->cluster_size_bits;	if (!nr)		nr = min_nr;	/* Ensure we do not go above 2^32-1 mft records. */	read_lock_irqsave(&mft_ni->size_lock, flags);	ll = mft_ni->allocated_size;	read_unlock_irqrestore(&mft_ni->size_lock, flags);	if (unlikely((ll + (nr << vol->cluster_size_bits)) >>			vol->mft_record_size_bits >= (1ll << 32))) {		nr = min_nr;		if (unlikely((ll + (nr << vol->cluster_size_bits)) >>				vol->mft_record_size_bits >= (1ll << 32))) {			ntfs_warning(vol->sb, "Cannot allocate mft record "					"because the maximum number of inodes "					"(2^32) has already been reached.");			up_write(&mft_ni->runlist.lock);			return -ENOSPC;		}	}	ntfs_debug("Trying mft data allocation with %s cluster count %lli.",			nr > min_nr ? "default" : "minimal", (long long)nr);	old_last_vcn = rl[1].vcn;	do {		rl2 = ntfs_cluster_alloc(vol, old_last_vcn, nr, lcn, MFT_ZONE,				true);		if (likely(!IS_ERR(rl2)))			break;		if (PTR_ERR(rl2) != -ENOSPC || nr == min_nr) {			ntfs_error(vol->sb, "Failed to allocate the minimal "					"number of clusters (%lli) for the "					"mft data attribute.", (long long)nr);			up_write(&mft_ni->runlist.lock);			return PTR_ERR(rl2);		}		/*		 * There is not enough space to do the allocation, but there		 * might be enough space to do a minimal allocation so try that		 * before failing.		 */		nr = min_nr;		ntfs_debug("Retrying mft data allocation with minimal cluster "				"count %lli.", (long long)nr);	} while (1);	rl = ntfs_runlists_merge(mft_ni->runlist.rl, rl2);	if (IS_ERR(rl)) {		up_write(&mft_ni->runlist.lock);		ntfs_error(vol->sb, "Failed to merge runlists for mft data "				"attribute.");		if (ntfs_cluster_free_from_rl(vol, rl2)) {			ntfs_error(vol->sb, "Failed to dealocate clusters "					"from the mft data attribute.%s", es);			NVolSetErrors(vol);		}		ntfs_free(rl2);		return PTR_ERR(rl);	}	mft_ni->runlist.rl = rl;	ntfs_debug("Allocated %lli clusters.", (long long)nr);	/* Find the last run in the new runlist. */	for (; rl[1].length; rl++)		;	/* Update the attribute record as well. */	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(mft_ni->type, mft_ni->name, mft_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 data 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 > mft_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 data 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 data 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: Use the special reserved mft records and ensure that		// this extent is not required to find the mft record in		// question.  If no free special records left we would need to		// move an existing record away, insert ours in its place, and		// then place the moved record into the newly allocated space		// and we would then need to update all references to this mft		// record appropriately.  This is rather complicated...		ntfs_error(vol->sb, "Not enough space in this mft record to "				"accomodate extended mft data attribute "				"extent.  Cannot handle this yet.");		ret = -EOPNOTSUPP;		goto undo_alloc;	}	mp_rebuilt = true;	/* 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 of "				"mft data 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 data allocated_size by nr clusters.	 * Reflect this in the ntfs_inode structure and the attribute record.	 * @rl is the last (non-terminator) runlist element of mft data	 * attribute.	 */	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(mft_ni->type, mft_ni->name,				mft_ni->name_len, CASE_SENSITIVE, 0, NULL, 0,				ctx)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -