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

📄 inode.c

📁 嵌入式系统设计与实例开发实验教材二源码 多线程应用程序设计 串行端口程序设计 AD接口实验 CAN总线通信实验 GPS通信实验 Linux内核移植与编译实验 IC卡读写实验 SD驱动使
💻 C
📖 第 1 页 / 共 5 页
字号:
			if (!bh) {				ext3_error(inode->i_sb, "ext3_free_branches",					   "Read failure, inode=%ld, block=%ld",					   inode->i_ino, nr);				continue;			}			/* This zaps the entire block.  Bottom up. */			BUFFER_TRACE(bh, "free child branches");			ext3_free_branches(handle, inode, bh, (u32*)bh->b_data,					   (u32*)bh->b_data + addr_per_block,					   depth);			/*			 * We've probably journalled the indirect block several			 * times during the truncate.  But it's no longer			 * needed and we now drop it from the transaction via			 * journal_revoke().			 *			 * That's easy if it's exclusively part of this			 * transaction.  But if it's part of the committing			 * transaction then journal_forget() will simply			 * brelse() it.  That means that if the underlying			 * block is reallocated in ext3_get_block(),			 * unmap_underlying_metadata() will find this block			 * and will try to get rid of it.  damn, damn.			 *			 * If this block has already been committed to the			 * journal, a revoke record will be written.  And			 * revoke records must be emitted *before* clearing			 * this block's bit in the bitmaps.			 */			ext3_forget(handle, 1, inode, bh, bh->b_blocknr);			/*			 * Everything below this this pointer has been			 * released.  Now let this top-of-subtree go.			 *			 * We want the freeing of this indirect block to be			 * atomic in the journal with the updating of the			 * bitmap block which owns it.  So make some room in			 * the journal.			 *			 * We zero the parent pointer *after* freeing its			 * pointee in the bitmaps, so if extend_transaction()			 * for some reason fails to put the bitmap changes and			 * the release into the same transaction, recovery			 * will merely complain about releasing a free block,			 * rather than leaking blocks.			 */			if (is_handle_aborted(handle))				return;			if (try_to_extend_transaction(handle, inode)) {				ext3_mark_inode_dirty(handle, inode);				ext3_journal_test_restart(handle, inode);			}			ext3_free_blocks(handle, inode, nr, 1);			if (parent_bh) {				/*				 * The block which we have just freed is				 * pointed to by an indirect block: journal it				 */				BUFFER_TRACE(parent_bh, "get_write_access");				if (!ext3_journal_get_write_access(handle,								   parent_bh)){					*p = 0;					BUFFER_TRACE(parent_bh,					"call ext3_journal_dirty_metadata");					ext3_journal_dirty_metadata(handle, 								    parent_bh);				}			}		}	} else {		/* We have reached the bottom of the tree. */		BUFFER_TRACE(parent_bh, "free data blocks");		ext3_free_data(handle, inode, parent_bh, first, last);	}}/* * ext3_truncate() * * We block out ext3_get_block() block instantiations across the entire * transaction, and VFS/VM ensures that ext3_truncate() cannot run * simultaneously on behalf of the same inode. * * As we work through the truncate and commmit bits of it to the journal there * is one core, guiding principle: the file's tree must always be consistent on * disk.  We must be able to restart the truncate after a crash. * * The file's tree may be transiently inconsistent in memory (although it * probably isn't), but whenever we close off and commit a journal transaction, * the contents of (the filesystem + the journal) must be consistent and * restartable.  It's pretty simple, really: bottom up, right to left (although * left-to-right works OK too). * * Note that at recovery time, journal replay occurs *before* the restart of * truncate against the orphan inode list. * * The committed inode has the new, desired i_size (which is the same as * i_disksize in this case).  After a crash, ext3_orphan_cleanup() will see * that this inode's truncate did not complete and it will again call * ext3_truncate() to have another go.  So there will be instantiated blocks * to the right of the truncation point in a crashed ext3 filesystem.  But * that's fine - as long as they are linked from the inode, the post-crash * ext3_truncate() run will find them and release them. */void ext3_truncate(struct inode * inode){	handle_t *handle;	u32 *i_data = inode->u.ext3_i.i_data;	int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb);	int offsets[4];	Indirect chain[4];	Indirect *partial;	int nr = 0;	int n;	long last_block;	unsigned blocksize;	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||	    S_ISLNK(inode->i_mode)))		return;	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))		return;	ext3_discard_prealloc(inode);	handle = start_transaction(inode);	if (IS_ERR(handle))		return;		/* AKPM: return what? */	blocksize = inode->i_sb->s_blocksize;	last_block = (inode->i_size + blocksize-1)					>> EXT3_BLOCK_SIZE_BITS(inode->i_sb);	ext3_block_truncate_page(handle, inode->i_mapping, inode->i_size);			n = ext3_block_to_path(inode, last_block, offsets);	if (n == 0)		goto out_stop;	/* error */	/*	 * OK.  This truncate is going to happen.  We add the inode to the	 * orphan list, so that if this truncate spans multiple transactions,	 * and we crash, we will resume the truncate when the filesystem	 * recovers.  It also marks the inode dirty, to catch the new size.	 *	 * Implication: the file must always be in a sane, consistent	 * truncatable state while each transaction commits.	 */	if (ext3_orphan_add(handle, inode))		goto out_stop;	/*	 * The orphan list entry will now protect us from any crash which	 * occurs before the truncate completes, so it is now safe to propagate	 * the new, shorter inode size (held for now in i_size) into the	 * on-disk inode. We do this via i_disksize, which is the value which	 * ext3 *really* writes onto the disk inode.	 */	inode->u.ext3_i.i_disksize = inode->i_size;	/*	 * From here we block out all ext3_get_block() callers who want to	 * modify the block allocation tree.	 */	down_write(&inode->u.ext3_i.truncate_sem);	if (n == 1) {		/* direct blocks */		ext3_free_data(handle, inode, NULL, i_data+offsets[0],			       i_data + EXT3_NDIR_BLOCKS);		goto do_indirects;	}	partial = ext3_find_shared(inode, n, offsets, chain, &nr);	/* Kill the top of shared branch (not detached) */	if (nr) {		if (partial == chain) {			/* Shared branch grows from the inode */			ext3_free_branches(handle, inode, NULL,					   &nr, &nr+1, (chain+n-1) - partial);			*partial->p = 0;			/*			 * We mark the inode dirty prior to restart,			 * and prior to stop.  No need for it here.			 */		} else {			/* Shared branch grows from an indirect block */			BUFFER_TRACE(partial->bh, "get_write_access");			ext3_free_branches(handle, inode, partial->bh,					partial->p,					partial->p+1, (chain+n-1) - partial);		}	}	/* Clear the ends of indirect blocks on the shared branch */	while (partial > chain) {		ext3_free_branches(handle, inode, partial->bh, partial->p + 1,				   (u32*)partial->bh->b_data + addr_per_block,				   (chain+n-1) - partial);		BUFFER_TRACE(partial->bh, "call brelse");		brelse (partial->bh);		partial--;	}do_indirects:	/* Kill the remaining (whole) subtrees */	switch (offsets[0]) {		default:			nr = i_data[EXT3_IND_BLOCK];			if (nr) {				ext3_free_branches(handle, inode, NULL,						   &nr, &nr+1, 1);				i_data[EXT3_IND_BLOCK] = 0;			}		case EXT3_IND_BLOCK:			nr = i_data[EXT3_DIND_BLOCK];			if (nr) {				ext3_free_branches(handle, inode, NULL,						   &nr, &nr+1, 2);				i_data[EXT3_DIND_BLOCK] = 0;			}		case EXT3_DIND_BLOCK:			nr = i_data[EXT3_TIND_BLOCK];			if (nr) {				ext3_free_branches(handle, inode, NULL,						   &nr, &nr+1, 3);				i_data[EXT3_TIND_BLOCK] = 0;			}		case EXT3_TIND_BLOCK:			;	}	up_write(&inode->u.ext3_i.truncate_sem);	inode->i_mtime = inode->i_ctime = CURRENT_TIME;	ext3_mark_inode_dirty(handle, inode);	/* In a multi-transaction truncate, we only make the final	 * transaction synchronous */	if (IS_SYNC(inode))		handle->h_sync = 1;out_stop:	/*	 * If this was a simple ftruncate(), and the file will remain alive	 * then we need to clear up the orphan record which we created above.	 * However, if this was a real unlink then we were called by	 * ext3_delete_inode(), and we allow that function to clean up the	 * orphan info for us.	 */	if (inode->i_nlink)		ext3_orphan_del(handle, inode);	ext3_journal_stop(handle, inode);}/*  * ext3_get_inode_loc returns with an extra refcount against the * inode's underlying buffer_head on success.  */int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc){	struct buffer_head *bh = 0;	unsigned long block;	unsigned long block_group;	unsigned long group_desc;	unsigned long desc;	unsigned long offset;	struct ext3_group_desc * gdp;			if ((inode->i_ino != EXT3_ROOT_INO &&		inode->i_ino != EXT3_ACL_IDX_INO &&		inode->i_ino != EXT3_ACL_DATA_INO &&		inode->i_ino != EXT3_JOURNAL_INO &&		inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) ||		inode->i_ino > le32_to_cpu(			inode->i_sb->u.ext3_sb.s_es->s_inodes_count)) {		ext3_error (inode->i_sb, "ext3_get_inode_loc",			    "bad inode number: %lu", inode->i_ino);		goto bad_inode;	}	block_group = (inode->i_ino - 1) / EXT3_INODES_PER_GROUP(inode->i_sb);	if (block_group >= inode->i_sb->u.ext3_sb.s_groups_count) {		ext3_error (inode->i_sb, "ext3_get_inode_loc",			    "group >= groups count");		goto bad_inode;	}	group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(inode->i_sb);	desc = block_group & (EXT3_DESC_PER_BLOCK(inode->i_sb) - 1);	bh = inode->i_sb->u.ext3_sb.s_group_desc[group_desc];	if (!bh) {		ext3_error (inode->i_sb, "ext3_get_inode_loc",			    "Descriptor not loaded");		goto bad_inode;	}	gdp = (struct ext3_group_desc *) bh->b_data;	/*	 * Figure out the offset within the block group inode table	 */	offset = ((inode->i_ino - 1) % EXT3_INODES_PER_GROUP(inode->i_sb)) *		EXT3_INODE_SIZE(inode->i_sb);	block = le32_to_cpu(gdp[desc].bg_inode_table) +		(offset >> EXT3_BLOCK_SIZE_BITS(inode->i_sb));	if (!(bh = sb_bread(inode->i_sb, block))) {		ext3_error (inode->i_sb, "ext3_get_inode_loc",			    "unable to read inode block - "			    "inode=%lu, block=%lu", inode->i_ino, block);		goto bad_inode;	}	offset &= (EXT3_BLOCK_SIZE(inode->i_sb) - 1);	iloc->bh = bh;	iloc->raw_inode = (struct ext3_inode *) (bh->b_data + offset);	iloc->block_group = block_group;		return 0;	 bad_inode:	return -EIO;}void ext3_read_inode(struct inode * inode){	struct ext3_iloc iloc;	struct ext3_inode *raw_inode;	struct buffer_head *bh;	int block;		if(ext3_get_inode_loc(inode, &iloc))		goto bad_inode;	bh = iloc.bh;	raw_inode = iloc.raw_inode;	init_rwsem(&inode->u.ext3_i.truncate_sem);	inode->i_mode = le16_to_cpu(raw_inode->i_mode);	inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);	inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);	if(!(test_opt (inode->i_sb, NO_UID32))) {		inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;		inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;	}	inode->i_nlink = le16_to_cpu(raw_inode->i_links_count);	inode->i_size = le32_to_cpu(raw_inode->i_size);	inode->i_atime = le32_to_cpu(raw_inode->i_atime);	inode->i_ctime = le32_to_cpu(raw_inode->i_ctime);	inode->i_mtime = le32_to_cpu(raw_inode->i_mtime);	inode->u.ext3_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);	/* We now have enough fields to check if the inode was active or not.	 * This is needed because nfsd might try to access dead inodes	 * the test is that same one that e2fsck uses	 * NeilBrown 1999oct15	 */	if (inode->i_nlink == 0) {		if (inode->i_mode == 0 ||		    !(inode->i_sb->u.ext3_sb.s_mount_state & EXT3_ORPHAN_FS)) {			/* this inode is deleted */			brelse (bh);			goto bad_inode;		}		/* The only unlinked inodes we let through here have		 * valid i_mode and are being read by the orphan		 * recovery code: that's fine, we're about to complete		 * the process of deleting those. */	}	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size					 * (for stat), not the fs block					 * size */  	inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);	inode->i_version = ++event;	inode->u.ext3_i.i_flags = le32_to_cpu(raw_inode->i_flags);#ifdef EXT3_FRAGMENTS	inode->u.ext3_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);	inode->u.ext3_i.i_frag_no = raw_inode->i_frag;	inode->u.ext3_i.i_frag_size = raw_inode->i_fsize;#endif	inode->u.ext3_i.i_file_acl = le32_to_cpu(raw_inode->i_file_acl);	if (!S_ISREG(inode->i_mode)) {		inode->u.ext3_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);	} else {		inode->i_size |=			((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;	}	inode->u.ext3_i.i_disksize = inode->i_size;	inode->i_generation = le32_to_cpu(raw_inode->i_generation);#ifdef EXT3_PREALLOCATE	inode->u.ext3_i.i_prealloc_count = 0;#endif	inode->u.ext3_i.i_block_group = iloc.block_group;	/*	 * NOTE! The in-memory inode i_data array is in little-endian order	 * even on big-endian machines: we do NOT byteswap the block numbers!	 */	for (block = 0; block < EXT3_N_BLOCKS; block++)		inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];	INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan);	brelse (iloc.bh);	if (inode->i_ino == EXT3_ACL_IDX_INO ||	    inode->i_ino == EXT3_ACL_DATA_INO)		/* Nothing to do */ ;	else if (S_ISREG(inode->i_mode)) {		inode->i_op = &ext3_file_inode_operations;		inode->i_fop = &ext3_file_operations;		inode->i_mapping->a_ops = &ext3_aops;	} else if (S_ISDIR(inode->i_mode)) {		inode->i_op = &ext3_dir_inode_operations;		inode->i_fop = &ext3_dir_operations;	} else if (S_ISLNK(inode->i_mode)) {		if (!inode->i_blocks)			inode->i_op = &ext3_fast_symlink_inode_operations;		else {			inode->i_op = &page_symlink_inode_operations;			inode->i_mapping->a_ops = &ext3_aops;		}	} else 		init_special_inode(inode, inode->i_mode,				   le32_to_cpu(iloc.raw_inode->i_block[0]));	/* inode->i_attr_flags = 0;				unused */	if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL) {		/* inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS; unused */		inode->i_flags |= S_SYNC;	}	if (inode->u.ext3_i.i_flags & EXT3_APPEND_FL) {		/* inode->i_attr_flags |= ATTR_FLAG_APPEND;	unused */		inode->i_f

⌨️ 快捷键说明

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