inode.c

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

C
2,057
字号
	ntfs_error(vi->i_sb, "Failed with error code %i while reading index "			"inode (mft_no 0x%lx, name_len %i.", -err, vi->i_ino,			ni->name_len);	make_bad_inode(vi);	return err;}/** * ntfs_read_inode_mount - special read_inode for mount time use only * @vi:		inode to read * * Read inode FILE_MFT at mount time, only called with super_block lock * held from within the read_super() code path. * * This function exists because when it is called the page cache for $MFT/$DATA * is not initialized and hence we cannot get at the contents of mft records * by calling map_mft_record*(). * * Further it needs to cope with the circular references problem, i.e. cannot * load any attributes other than $ATTRIBUTE_LIST until $DATA is loaded, because * we do not know where the other extent mft records are yet and again, because * we cannot call map_mft_record*() yet.  Obviously this applies only when an * attribute list is actually present in $MFT inode. * * We solve these problems by starting with the $DATA attribute before anything * else and iterating using ntfs_attr_lookup($DATA) over all extents.  As each * extent is found, we decompress_mapping_pairs() including the implied * ntfs_merge_runlists().  Each step of the iteration necessarily provides * sufficient information for the next step to complete. * * This should work but there are two possible pit falls (see inline comments * below), but only time will tell if they are real pits or just smoke... */int ntfs_read_inode_mount(struct inode *vi){	VCN next_vcn, last_vcn, highest_vcn;	s64 block;	struct super_block *sb = vi->i_sb;	ntfs_volume *vol = NTFS_SB(sb);	struct buffer_head *bh;	ntfs_inode *ni;	MFT_RECORD *m = NULL;	ATTR_RECORD *attr;	ntfs_attr_search_ctx *ctx;	unsigned int i, nr_blocks;	int err;	ntfs_debug("Entering.");	/* Initialize the ntfs specific part of @vi. */	ntfs_init_big_inode(vi);	ni = NTFS_I(vi);	/* Setup the data attribute. It is special as it is mst protected. */	NInoSetNonResident(ni);	NInoSetMstProtected(ni);	ni->type = AT_DATA;	ni->name = NULL;	ni->name_len = 0;	/*	 * This sets up our little cheat allowing us to reuse the async read io	 * completion handler for directories.	 */	ni->itype.index.block_size = vol->mft_record_size;	ni->itype.index.block_size_bits = vol->mft_record_size_bits;	/* Very important! Needed to be able to call map_mft_record*(). */	vol->mft_ino = vi;	/* Allocate enough memory to read the first mft record. */	if (vol->mft_record_size > 64 * 1024) {		ntfs_error(sb, "Unsupported mft record size %i (max 64kiB).",				vol->mft_record_size);		goto err_out;	}	i = vol->mft_record_size;	if (i < sb->s_blocksize)		i = sb->s_blocksize;	m = (MFT_RECORD*)ntfs_malloc_nofs(i);	if (!m) {		ntfs_error(sb, "Failed to allocate buffer for $MFT record 0.");		goto err_out;	}	/* Determine the first block of the $MFT/$DATA attribute. */	block = vol->mft_lcn << vol->cluster_size_bits >>			sb->s_blocksize_bits;	nr_blocks = vol->mft_record_size >> sb->s_blocksize_bits;	if (!nr_blocks)		nr_blocks = 1;	/* Load $MFT/$DATA's first mft record. */	for (i = 0; i < nr_blocks; i++) {		bh = sb_bread(sb, block++);		if (!bh) {			ntfs_error(sb, "Device read failed.");			goto err_out;		}		memcpy((char*)m + (i << sb->s_blocksize_bits), bh->b_data,				sb->s_blocksize);		brelse(bh);	}	/* Apply the mst fixups. */	if (post_read_mst_fixup((NTFS_RECORD*)m, vol->mft_record_size)) {		/* FIXME: Try to use the $MFTMirr now. */		ntfs_error(sb, "MST fixup failed. $MFT is corrupt.");		goto err_out;	}	/* Need this to sanity check attribute list references to $MFT. */	vi->i_generation = ni->seq_no = le16_to_cpu(m->sequence_number);	/* Provides readpage() and sync_page() for map_mft_record(). */	vi->i_mapping->a_ops = &ntfs_mft_aops;	ctx = ntfs_attr_get_search_ctx(ni, m);	if (!ctx) {		err = -ENOMEM;		goto err_out;	}	/* Find the attribute list attribute if present. */	err = ntfs_attr_lookup(AT_ATTRIBUTE_LIST, NULL, 0, 0, 0, NULL, 0, ctx);	if (err) {		if (unlikely(err != -ENOENT)) {			ntfs_error(sb, "Failed to lookup attribute list "					"attribute. You should run chkdsk.");			goto put_err_out;		}	} else /* if (!err) */ {		ATTR_LIST_ENTRY *al_entry, *next_al_entry;		u8 *al_end;		ntfs_debug("Attribute list attribute found in $MFT.");		NInoSetAttrList(ni);		if (ctx->attr->flags & ATTR_IS_ENCRYPTED ||				ctx->attr->flags & ATTR_COMPRESSION_MASK ||				ctx->attr->flags & ATTR_IS_SPARSE) {			ntfs_error(sb, "Attribute list attribute is "					"compressed/encrypted/sparse. Not "					"allowed. $MFT is corrupt. You should "					"run chkdsk.");			goto put_err_out;		}		/* Now allocate memory for the attribute list. */		ni->attr_list_size = (u32)ntfs_attr_size(ctx->attr);		ni->attr_list = ntfs_malloc_nofs(ni->attr_list_size);		if (!ni->attr_list) {			ntfs_error(sb, "Not enough memory to allocate buffer "					"for attribute list.");			goto put_err_out;		}		if (ctx->attr->non_resident) {			NInoSetAttrListNonResident(ni);			if (ctx->attr->data.non_resident.lowest_vcn) {				ntfs_error(sb, "Attribute list has non zero "						"lowest_vcn. $MFT is corrupt. "						"You should run chkdsk.");				goto put_err_out;			}			/* Setup the runlist. */			ni->attr_list_rl.rl = decompress_mapping_pairs(vol,					ctx->attr, NULL);			if (IS_ERR(ni->attr_list_rl.rl)) {				err = PTR_ERR(ni->attr_list_rl.rl);				ni->attr_list_rl.rl = NULL;				ntfs_error(sb, "Mapping pairs decompression "						"failed with error code %i.",						-err);				goto put_err_out;			}			/* Now load the attribute list. */			if ((err = load_attribute_list(vol, &ni->attr_list_rl,					ni->attr_list, ni->attr_list_size,					sle64_to_cpu(ctx->attr->data.					non_resident.initialized_size)))) {				ntfs_error(sb, "Failed to load attribute list "						"attribute with error code %i.",						-err);				goto put_err_out;			}		} else /* if (!ctx.attr->non_resident) */ {			if ((u8*)ctx->attr + le16_to_cpu(					ctx->attr->data.resident.value_offset) +					le32_to_cpu(					ctx->attr->data.resident.value_length) >					(u8*)ctx->mrec + vol->mft_record_size) {				ntfs_error(sb, "Corrupt attribute list "						"attribute.");				goto put_err_out;			}			/* Now copy the attribute list. */			memcpy(ni->attr_list, (u8*)ctx->attr + le16_to_cpu(					ctx->attr->data.resident.value_offset),					le32_to_cpu(					ctx->attr->data.resident.value_length));		}		/* The attribute list is now setup in memory. */		/*		 * FIXME: I don't know if this case is actually possible.		 * According to logic it is not possible but I have seen too		 * many weird things in MS software to rely on logic... Thus we		 * perform a manual search and make sure the first $MFT/$DATA		 * extent is in the base inode. If it is not we abort with an		 * error and if we ever see a report of this error we will need		 * to do some magic in order to have the necessary mft record		 * loaded and in the right place in the page cache. But		 * hopefully logic will prevail and this never happens...		 */		al_entry = (ATTR_LIST_ENTRY*)ni->attr_list;		al_end = (u8*)al_entry + ni->attr_list_size;		for (;; al_entry = next_al_entry) {			/* Out of bounds check. */			if ((u8*)al_entry < ni->attr_list ||					(u8*)al_entry > al_end)				goto em_put_err_out;			/* Catch the end of the attribute list. */			if ((u8*)al_entry == al_end)				goto em_put_err_out;			if (!al_entry->length)				goto em_put_err_out;			if ((u8*)al_entry + 6 > al_end || (u8*)al_entry +					le16_to_cpu(al_entry->length) > al_end)				goto em_put_err_out;			next_al_entry = (ATTR_LIST_ENTRY*)((u8*)al_entry +					le16_to_cpu(al_entry->length));			if (le32_to_cpu(al_entry->type) >					const_le32_to_cpu(AT_DATA))				goto em_put_err_out;			if (AT_DATA != al_entry->type)				continue;			/* We want an unnamed attribute. */			if (al_entry->name_length)				goto em_put_err_out;			/* Want the first entry, i.e. lowest_vcn == 0. */			if (al_entry->lowest_vcn)				goto em_put_err_out;			/* First entry has to be in the base mft record. */			if (MREF_LE(al_entry->mft_reference) != vi->i_ino) {				/* MFT references do not match, logic fails. */				ntfs_error(sb, "BUG: The first $DATA extent "						"of $MFT is not in the base "						"mft record. Please report "						"you saw this message to "						"linux-ntfs-dev@lists."						"sourceforge.net");				goto put_err_out;			} else {				/* Sequence numbers must match. */				if (MSEQNO_LE(al_entry->mft_reference) !=						ni->seq_no)					goto em_put_err_out;				/* Got it. All is ok. We can stop now. */				break;			}		}	}	ntfs_attr_reinit_search_ctx(ctx);	/* Now load all attribute extents. */	attr = NULL;	next_vcn = last_vcn = highest_vcn = 0;	while (!(err = ntfs_attr_lookup(AT_DATA, NULL, 0, 0, next_vcn, NULL, 0,			ctx))) {		runlist_element *nrl;		/* Cache the current attribute. */		attr = ctx->attr;		/* $MFT must be non-resident. */		if (!attr->non_resident) {			ntfs_error(sb, "$MFT must be non-resident but a "					"resident extent was found. $MFT is "					"corrupt. Run chkdsk.");			goto put_err_out;		}		/* $MFT must be uncompressed and unencrypted. */		if (attr->flags & ATTR_COMPRESSION_MASK ||				attr->flags & ATTR_IS_ENCRYPTED ||				attr->flags & ATTR_IS_SPARSE) {			ntfs_error(sb, "$MFT must be uncompressed, "					"non-sparse, and unencrypted but a "					"compressed/sparse/encrypted extent "					"was found. $MFT is corrupt. Run "					"chkdsk.");			goto put_err_out;		}		/*		 * Decompress the mapping pairs array of this extent and merge		 * the result into the existing runlist. No need for locking		 * as we have exclusive access to the inode at this time and we		 * are a mount in progress task, too.		 */		nrl = decompress_mapping_pairs(vol, attr, ni->runlist.rl);		if (IS_ERR(nrl)) {			ntfs_error(sb, "decompress_mapping_pairs() failed with "					"error code %ld. $MFT is corrupt.",					PTR_ERR(nrl));			goto put_err_out;		}		ni->runlist.rl = nrl;		/* Are we in the first extent? */		if (!next_vcn) {			if (attr->data.non_resident.lowest_vcn) {				ntfs_error(sb, "First extent of $DATA "						"attribute has non zero "						"lowest_vcn. $MFT is corrupt. "						"You should run chkdsk.");				goto put_err_out;			}			/* Get the last vcn in the $DATA attribute. */			last_vcn = sle64_to_cpu(					attr->data.non_resident.allocated_size)					>> vol->cluster_size_bits;			/* Fill in the inode size. */			vi->i_size = sle64_to_cpu(					attr->data.non_resident.data_size);			ni->initialized_size = sle64_to_cpu(attr->data.					non_resident.initialized_size);			ni->allocated_size = sle64_to_cpu(					attr->data.non_resident.allocated_size);			/*			 * Verify the number of mft records does not exceed			 * 2^32 - 1.			 */			if ((vi->i_size >> vol->mft_record_size_bits) >=					(1ULL << 32)) {				ntfs_error(sb, "$MFT is too big! Aborting.");				goto put_err_out;			}			/*			 * We have got the first extent of the runlist for			 * $MFT which means it is now relatively safe to call			 * the normal ntfs_read_inode() function.			 * Complete reading the inode, this will actually			 * re-read the mft record for $MFT, this time entering			 * it into the page cache with which we complete the			 * kick start of the volume. It should be safe to do			 * this now as the first extent of $MFT/$DATA is			 * already known and we would hope that we don't need			 * further extents in order to find the other			 * attributes belonging to $MFT. Only time will tell if			 * this is really the case. If not we will have to play			 * magic at this point, possibly duplicating a lot of			 * ntfs_read_inode() at this point. We will need to			 * ensure we do enough of its work to be able to call			 * ntfs_read_inode() on extents of $MFT/$DATA. But lets			 * hope this never happens...			 */			ntfs_read_locked_inode(vi);			if (is_bad_inode(vi)) {				ntfs_error(sb, "ntfs_read_inode() of $MFT "						"failed. BUG or corrupt $MFT. "						"Run chkdsk and if no errors "						"are found, please report you "						"saw this message to "						"linux-ntfs-dev@lists."						"sourceforge.net");				ntfs_attr_put_search_ctx(ctx);				/* Revert to the safe super operations. */				ntfs_free(m);				return -1;			}			/*			 * Re-initialize some specifics about $MFT's inode as			 * ntfs_read_inode() will have set up the default ones.			 */			/* Set uid and gid to root. */			vi->i_uid = vi->i_gid = 0;			/* Regular file. No access for anyone. */			vi->i_mode = S_IFREG;			/* No VFS initiated operations allowed for $MFT. */			vi->i_op = &ntfs_empty_inode_ops;			vi->i_fop = &ntfs_empty_file_ops;			/* Put back our special address space operations. */			vi->i_mapping->a_ops = &ntfs_mft_aops;		}		/* Get the lowest vcn for the next extent. */		highest_vcn = sle64_to_cpu(attr->data.non_resident.highest_vcn);		next_vcn = highest_vcn + 1;		/* Only one extent or error, which we catch below. */		if (next_vcn <= 0)			break;		/* Avoid endless loops due to corruption. */		if (next_vcn < sle64_to_cpu(				attr->data.non_resident.lowest_vcn)) {			ntfs_error(sb, "$MFT has corrupt attribute list "					"attribute. Run chkdsk.");			goto put_err_out;		}	}	if (err != -ENOENT) {		ntfs_error(sb, "Failed to lookup $MFT/$DATA attribute extent. "				"$MFT is corrupt. Run chkdsk.");		goto put_err_out;	}	if (!attr) {		ntfs_error(sb, "$MFT/$DATA attribute not found. $MFT is "				"corrupt. Run chkdsk.");		goto put_err_out;	}	if (highest_vcn 

⌨️ 快捷键说明

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