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

📄 mft.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
	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 + -