super.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 2,070 行 · 第 1/5 页

C
2,070
字号
/** * setup_lcn_allocator - initialize the cluster allocator * @vol:	volume structure for which to setup the lcn allocator * * Setup the cluster (lcn) allocator to the starting values. */static void setup_lcn_allocator(ntfs_volume *vol){#ifdef NTFS_RW	LCN mft_zone_size, mft_lcn;#endif /* NTFS_RW */	ntfs_debug("vol->mft_zone_multiplier = 0x%x",			vol->mft_zone_multiplier);#ifdef NTFS_RW	/* Determine the size of the MFT zone. */	mft_zone_size = vol->nr_clusters;	switch (vol->mft_zone_multiplier) {  /* % of volume size in clusters */	case 4:		mft_zone_size >>= 1;			/* 50%   */		break;	case 3:		mft_zone_size = (mft_zone_size +				(mft_zone_size >> 1)) >> 2;	/* 37.5% */		break;	case 2:		mft_zone_size >>= 2;			/* 25%   */		break;	/* case 1: */	default:		mft_zone_size >>= 3;			/* 12.5% */		break;	}	/* Setup the mft zone. */	vol->mft_zone_start = vol->mft_zone_pos = vol->mft_lcn;	ntfs_debug("vol->mft_zone_pos = 0x%llx",			(unsigned long long)vol->mft_zone_pos);	/*	 * Calculate the mft_lcn for an unmodified NTFS volume (see mkntfs	 * source) and if the actual mft_lcn is in the expected place or even	 * further to the front of the volume, extend the mft_zone to cover the	 * beginning of the volume as well.  This is in order to protect the	 * area reserved for the mft bitmap as well within the mft_zone itself.	 * On non-standard volumes we do not protect it as the overhead would	 * be higher than the speed increase we would get by doing it.	 */	mft_lcn = (8192 + 2 * vol->cluster_size - 1) / vol->cluster_size;	if (mft_lcn * vol->cluster_size < 16 * 1024)		mft_lcn = (16 * 1024 + vol->cluster_size - 1) /				vol->cluster_size;	if (vol->mft_zone_start <= mft_lcn)		vol->mft_zone_start = 0;	ntfs_debug("vol->mft_zone_start = 0x%llx",			(unsigned long long)vol->mft_zone_start);	/*	 * Need to cap the mft zone on non-standard volumes so that it does	 * not point outside the boundaries of the volume.  We do this by	 * halving the zone size until we are inside the volume.	 */	vol->mft_zone_end = vol->mft_lcn + mft_zone_size;	while (vol->mft_zone_end >= vol->nr_clusters) {		mft_zone_size >>= 1;		vol->mft_zone_end = vol->mft_lcn + mft_zone_size;	}	ntfs_debug("vol->mft_zone_end = 0x%llx",			(unsigned long long)vol->mft_zone_end);	/*	 * Set the current position within each data zone to the start of the	 * respective zone.	 */	vol->data1_zone_pos = vol->mft_zone_end;	ntfs_debug("vol->data1_zone_pos = 0x%llx",			(unsigned long long)vol->data1_zone_pos);	vol->data2_zone_pos = 0;	ntfs_debug("vol->data2_zone_pos = 0x%llx",			(unsigned long long)vol->data2_zone_pos);#endif /* NTFS_RW */}#ifdef NTFS_RW/** * load_and_init_mft_mirror - load and setup the mft mirror inode for a volume * @vol:	ntfs super block describing device whose mft mirror to load * * Return TRUE on success or FALSE on error. */static BOOL load_and_init_mft_mirror(ntfs_volume *vol){	struct inode *tmp_ino;	ntfs_inode *tmp_ni;	ntfs_debug("Entering.");	/* Get mft mirror inode. */	tmp_ino = ntfs_iget(vol->sb, FILE_MFTMirr);	if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {		if (!IS_ERR(tmp_ino))			iput(tmp_ino);		/* Caller will display error message. */		return FALSE;	}	/*	 * Re-initialize some specifics about $MFTMirr's inode as	 * ntfs_read_inode() will have set up the default ones.	 */	/* Set uid and gid to root. */	tmp_ino->i_uid = tmp_ino->i_gid = 0;	/* Regular file.  No access for anyone. */	tmp_ino->i_mode = S_IFREG;	/* No VFS initiated operations allowed for $MFTMirr. */	tmp_ino->i_op = &ntfs_empty_inode_ops;	tmp_ino->i_fop = &ntfs_empty_file_ops;	/* Put back our special address space operations. */	tmp_ino->i_mapping->a_ops = &ntfs_mft_aops;	tmp_ni = NTFS_I(tmp_ino);	/* The $MFTMirr, like the $MFT is multi sector transfer protected. */	NInoSetMstProtected(tmp_ni);	/*	 * Set up our little cheat allowing us to reuse the async read io	 * completion handler for directories.	 */	tmp_ni->itype.index.block_size = vol->mft_record_size;	tmp_ni->itype.index.block_size_bits = vol->mft_record_size_bits;	vol->mftmirr_ino = tmp_ino;	ntfs_debug("Done.");	return TRUE;}/** * check_mft_mirror - compare contents of the mft mirror with the mft * @vol:	ntfs super block describing device whose mft mirror to check * * Return TRUE on success or FALSE on error. */static BOOL check_mft_mirror(ntfs_volume *vol){	unsigned long index;	struct super_block *sb = vol->sb;	ntfs_inode *mirr_ni;	struct page *mft_page, *mirr_page;	u8 *kmft, *kmirr;	runlist_element *rl, rl2[2];	int mrecs_per_page, i;	ntfs_debug("Entering.");	/* Compare contents of $MFT and $MFTMirr. */	mrecs_per_page = PAGE_CACHE_SIZE / vol->mft_record_size;	BUG_ON(!mrecs_per_page);	BUG_ON(!vol->mftmirr_size);	mft_page = mirr_page = NULL;	kmft = kmirr = NULL;	index = i = 0;	do {		u32 bytes;		/* Switch pages if necessary. */		if (!(i % mrecs_per_page)) {			if (index) {				ntfs_unmap_page(mft_page);				ntfs_unmap_page(mirr_page);			}			/* Get the $MFT page. */			mft_page = ntfs_map_page(vol->mft_ino->i_mapping,					index);			if (IS_ERR(mft_page)) {				ntfs_error(sb, "Failed to read $MFT.");				return FALSE;			}			kmft = page_address(mft_page);			/* Get the $MFTMirr page. */			mirr_page = ntfs_map_page(vol->mftmirr_ino->i_mapping,					index);			if (IS_ERR(mirr_page)) {				ntfs_error(sb, "Failed to read $MFTMirr.");				goto mft_unmap_out;			}			kmirr = page_address(mirr_page);			++index;		}		/* Make sure the record is ok. */		if (ntfs_is_baad_recordp((le32*)kmft)) {			ntfs_error(sb, "Incomplete multi sector transfer "					"detected in mft record %i.", i);mm_unmap_out:			ntfs_unmap_page(mirr_page);mft_unmap_out:			ntfs_unmap_page(mft_page);			return FALSE;		}		if (ntfs_is_baad_recordp((le32*)kmirr)) {			ntfs_error(sb, "Incomplete multi sector transfer "					"detected in mft mirror record %i.", i);			goto mm_unmap_out;		}		/* Get the amount of data in the current record. */		bytes = le32_to_cpu(((MFT_RECORD*)kmft)->bytes_in_use);		if (!bytes || bytes > vol->mft_record_size) {			bytes = le32_to_cpu(((MFT_RECORD*)kmirr)->bytes_in_use);			if (!bytes || bytes > vol->mft_record_size)				bytes = vol->mft_record_size;		}		/* Compare the two records. */		if (memcmp(kmft, kmirr, bytes)) {			ntfs_error(sb, "$MFT and $MFTMirr (record %i) do not "					"match.  Run ntfsfix or chkdsk.", i);			goto mm_unmap_out;		}		kmft += vol->mft_record_size;		kmirr += vol->mft_record_size;	} while (++i < vol->mftmirr_size);	/* Release the last pages. */	ntfs_unmap_page(mft_page);	ntfs_unmap_page(mirr_page);	/* Construct the mft mirror runlist by hand. */	rl2[0].vcn = 0;	rl2[0].lcn = vol->mftmirr_lcn;	rl2[0].length = (vol->mftmirr_size * vol->mft_record_size +			vol->cluster_size - 1) / vol->cluster_size;	rl2[1].vcn = rl2[0].length;	rl2[1].lcn = LCN_ENOENT;	rl2[1].length = 0;	/*	 * Because we have just read all of the mft mirror, we know we have	 * mapped the full runlist for it.	 */	mirr_ni = NTFS_I(vol->mftmirr_ino);	down_read(&mirr_ni->runlist.lock);	rl = mirr_ni->runlist.rl;	/* Compare the two runlists.  They must be identical. */	i = 0;	do {		if (rl2[i].vcn != rl[i].vcn || rl2[i].lcn != rl[i].lcn ||				rl2[i].length != rl[i].length) {			ntfs_error(sb, "$MFTMirr location mismatch.  "					"Run chkdsk.");			up_read(&mirr_ni->runlist.lock);			return FALSE;		}	} while (rl2[i++].length);	up_read(&mirr_ni->runlist.lock);	ntfs_debug("Done.");	return TRUE;}/** * load_and_check_logfile - load and check the logfile inode for a volume * @vol:	ntfs super block describing device whose logfile to load * * Return TRUE on success or FALSE on error. */static BOOL load_and_check_logfile(ntfs_volume *vol){	struct inode *tmp_ino;	ntfs_debug("Entering.");	tmp_ino = ntfs_iget(vol->sb, FILE_LogFile);	if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {		if (!IS_ERR(tmp_ino))			iput(tmp_ino);		/* Caller will display error message. */		return FALSE;	}	if (!ntfs_check_logfile(tmp_ino)) {		iput(tmp_ino);		/* ntfs_check_logfile() will have displayed error output. */		return FALSE;	}	vol->logfile_ino = tmp_ino;	ntfs_debug("Done.");	return TRUE;}/** * load_and_init_quota - load and setup the quota file for a volume if present * @vol:	ntfs super block describing device whose quota file to load * * Return TRUE on success or FALSE on error.  If $Quota is not present, we * leave vol->quota_ino as NULL and return success. */static BOOL load_and_init_quota(ntfs_volume *vol){	MFT_REF mref;	struct inode *tmp_ino;	ntfs_name *name = NULL;	static const ntfschar Quota[7] = { const_cpu_to_le16('$'),			const_cpu_to_le16('Q'), const_cpu_to_le16('u'),			const_cpu_to_le16('o'), const_cpu_to_le16('t'),			const_cpu_to_le16('a'), 0 };	static ntfschar Q[3] = { const_cpu_to_le16('$'),			const_cpu_to_le16('Q'), 0 };	ntfs_debug("Entering.");	/*	 * Find the inode number for the quota file by looking up the filename	 * $Quota in the extended system files directory $Extend.	 */	down(&vol->extend_ino->i_sem);	mref = ntfs_lookup_inode_by_name(NTFS_I(vol->extend_ino), Quota, 6,			&name);	up(&vol->extend_ino->i_sem);	if (IS_ERR_MREF(mref)) {		/*		 * If the file does not exist, quotas are disabled and have		 * never been enabled on this volume, just return success.		 */		if (MREF_ERR(mref) == -ENOENT) {			ntfs_debug("$Quota not present.  Volume does not have "					"quotas enabled.");			/*			 * No need to try to set quotas out of date if they are			 * not enabled.			 */			NVolSetQuotaOutOfDate(vol);			return TRUE;		}		/* A real error occured. */		ntfs_error(vol->sb, "Failed to find inode number for $Quota.");		return FALSE;	}	/* We do not care for the type of match that was found. */	if (name)		kfree(name);	/* Get the inode. */	tmp_ino = ntfs_iget(vol->sb, MREF(mref));	if (IS_ERR(tmp_ino) || is_bad_inode(tmp_ino)) {		if (!IS_ERR(tmp_ino))			iput(tmp_ino);		ntfs_error(vol->sb, "Failed to load $Quota.");		return FALSE;	}	vol->quota_ino = tmp_ino;	/* Get the $Q index allocation attribute. */	tmp_ino = ntfs_index_iget(vol->quota_ino, Q, 2);	if (IS_ERR(tmp_ino)) {		ntfs_error(vol->sb, "Failed to load $Quota/$Q index.");		return FALSE;	}	vol->quota_q_ino = tmp_ino;	ntfs_debug("Done.");	return TRUE;}/** * load_and_init_attrdef - load the attribute definitions table for a volume * @vol:	ntfs super block describing device whose attrdef to load * * Return TRUE on success or FALSE on error. */static BOOL load_and_init_attrdef(ntfs_volume *vol){	struct super_block *sb = vol->sb;	struct inode *ino;	struct page *page;	unsigned long index, max_index;	unsigned int size;	ntfs_debug("Entering.");	/* Read attrdef table and setup vol->attrdef and vol->attrdef_size. */	ino = ntfs_iget(sb, FILE_AttrDef);	if (IS_ERR(ino) || is_bad_inode(ino)) {		if (!IS_ERR(ino))			iput(ino);		goto failed;	}	/* The size of FILE_AttrDef must be above 0 and fit inside 31 bits. */	if (!ino->i_size || ino->i_size > 0x7fffffff)		goto iput_failed;	vol->attrdef = (ATTR_DEF*)ntfs_malloc_nofs(ino->i_size);	if (!vol->attrdef)		goto iput_failed;	index = 0;	max_index = ino->i_size >> PAGE_CACHE_SHIFT;	size = PAGE_CACHE_SIZE;	while (index < max_index) {		/* Read the attrdef table and copy it into the linear buffer. */read_partial_attrdef_page:		page = ntfs_map_page(ino->i_mapping, index);		if (IS_ERR(page))			goto free_iput_failed;		memcpy((u8*)vol->attrdef + (index++ << PAGE_CACHE_SHIFT),				page_address(page), size);		ntfs_unmap_page(page);	};	if (size == PAGE_CACHE_SIZE) {		size = ino->i_size & ~PAGE_CACHE_MASK;		if (size)			goto read_partial_attrdef_page;	}	vol->attrdef_size = ino->i_size;	ntfs_debug("Read %llu bytes from $AttrDef.", ino->i_size);	iput(ino);	return TRUE;free_iput_failed:	ntfs_free(vol->attrdef);	vol->attrdef = NULL;iput_failed:	iput(ino);failed:	ntfs_error(sb, "Failed to initialize attribute definition table.");	return FALSE;}#endif /* NTFS_RW *//** * load_and_init_upcase - load the upcase table for an ntfs volume * @vol:	ntfs super block describing device whose upcase to load * * Return TRUE on success or FALSE on error. */static BOOL load_and_init_upcase(ntfs_volume *vol){	struct super_block *sb = vol->sb;

⌨️ 快捷键说明

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