kernels/linux-2.4.0/fs/ext2/ialloc.c
/*
 * NOTE! When we get the inode, we're the only people
 * that have access to it, and as such there are no
 * race conditions we have to worry about. The inode
 * is not on the hash-lists, and it cannot be reached
 * through the filesystem because the directory entry
 * has been deleted earlier.
 *
 * HOWEVER: we must make sure that we get no aliases,
 * which means that we have to call "clear_inode()"
 * _before_ we mark the inode not in use in the inode
 * bitmaps. Otherwise a newly created file might use
 * the same inode number (not actually the same pointer
 * though), and then we'd have two inodes sharing the
 * same inode number and space on the harddisk.
 */
NOTE. When we get the inode, we're the only people
that have access to it, and as such there are no
race conditions we have to worry about. The inode
is not on the hash-lists, and it cannot be reached
through the filesystem because the directory entry
has been deleted earlier.

we must make sure that we get no aliases,
which means that we have to call "clear_inode()"
_before_ we mark the inode not in use in the inode
bitmaps. Otherwise a newly created file might use
the same inode number (not actually the same pointer
though), and then we'd have two inodes sharing the
same inode number and space on the harddisk.
NOTE . When we get the inode we ' re the only people that have access to it and as such there are no race conditions we have to worry about . The inode is not on the hash - lists and it cannot be reached through the filesystem because the directory entry has been deleted earlier . we must make sure that we get no aliases which means that we have to call " clear_inode () " _before_ we mark the inode not in use in the inode bitmaps . Otherwise a newly created file might use the same inode number ( not actually the same pointer though ) and then we ' d have two inodes sharing the same inode number and space on the harddisk .
void ext2_free_inode (struct inode * inode)
{
	struct super_block * sb = inode->i_sb;
	int is_directory;
	unsigned long ino;
	struct buffer_head * bh;
	struct buffer_head * bh2;
	unsigned long block_group;
	unsigned long bit;
	int bitmap_nr;
	struct ext2_group_desc * gdp;
	struct ext2_super_block * es;
	ino = inode->i_ino;
	ext2_debug ("freeing inode %lu\n", ino);
	DQUOT_FREE_INODE(sb, inode);
	DQUOT_DROP(inode);
	lock_super (sb);
	es = sb->u.ext2_sb.s_es;
	if (ino < EXT2_FIRST_INO(sb) || 
	    ino > le32_to_cpu(es->s_inodes_count)) {
		ext2_error (sb, "free_inode",
			    "reserved inode or nonexistent inode");
		goto error_return;
	}
	block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
	bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb);
	bitmap_nr = load_inode_bitmap (sb, block_group);
	if (bitmap_nr < 0)
		goto error_return;
	bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
	is_directory = S_ISDIR(inode->i_mode);
	clear_inode (inode);
	if (!ext2_clear_bit (bit, bh->b_data))
		ext2_error (sb, "ext2_free_inode",
			      "bit already cleared for inode %lu", ino);
	else {
		gdp = ext2_get_group_desc (sb, block_group, &bh2);
		if (gdp) {
			gdp->bg_free_inodes_count =
				cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1);
			if (is_directory)
				gdp->bg_used_dirs_count =
					cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1);
		}
		mark_buffer_dirty(bh2);
		es->s_free_inodes_count =
			cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
		mark_buffer_dirty(sb->u.ext2_sb.s_sbh);
	}
	mark_buffer_dirty(bh);
	if (sb->s_flags & MS_SYNCHRONOUS) {
		ll_rw_block (WRITE, 1, &bh);
		wait_on_buffer (bh);
	}
	sb->s_dirt = 1;
error_return:
	unlock_super (sb);
}
void ext2_free_inode ( struct inode * inode ) { struct super_block * sb = inode -> i_sb ; int is_directory ; unsigned long ino ; struct buffer_head * bh ; struct buffer_head * bh2 ; unsigned long block_group ; unsigned long bit ; int bitmap_nr ; struct ext2_group_desc * gdp ; struct ext2_super_block * es ; ino = inode -> i_ino ; ext2_debug ( " \n " , ino ) ; DQUOT_FREE_INODE ( sb , inode ) ; DQUOT_DROP ( inode ) ; lock_super ( sb ) ; es = sb -> u . ext2_sb . s_es ; if ( ino < EXT2_FIRST_INO ( sb ) || ino > le32_to_cpu ( es -> s_inodes_count ) ) { ext2_error ( sb , " " , " " ) ; goto error_return ; } block_group = ( ino - 1 ) / EXT2_INODES_PER_GROUP ( sb ) ; bit = ( ino - 1 ) % EXT2_INODES_PER_GROUP ( sb ) ; bitmap_nr = load_inode_bitmap ( sb , block_group ) ; if ( bitmap_nr < 0 ) goto error_return ; bh = sb -> u . ext2_sb . s_inode_bitmap [ bitmap_nr ] ; is_directory = S_ISDIR ( inode -> i_mode ) ; clear_inode ( inode ) ; if ( ! ext2_clear_bit ( bit , bh -> b_data ) ) ext2_error ( sb , " " , " " , ino ) ; else { gdp = ext2_get_group_desc ( sb , block_group , & bh2 ) ; if ( gdp ) { gdp -> bg_free_inodes_count = cpu_to_le16 ( le16_to_cpu ( gdp -> bg_free_inodes_count ) + 1 ) ; if ( is_directory ) gdp -> bg_used_dirs_count = cpu_to_le16 ( le16_to_cpu ( gdp -> bg_used_dirs_count ) - 1 ) ; } mark_buffer_dirty ( bh2 ) ; es -> s_free_inodes_count = cpu_to_le32 ( le32_to_cpu ( es -> s_free_inodes_count ) + 1 ) ; mark_buffer_dirty ( sb -> u . ext2_sb . s_sbh ) ; } mark_buffer_dirty ( bh ) ; if ( sb -> s_flags & MS_SYNCHRONOUS ) { ll_rw_block ( WRITE , 1 , & bh ) ; wait_on_buffer ( bh ) ; } sb -> s_dirt = 1 ; error_return : unlock_super ( sb ) ; }
NOTE!
NOTE!
/*
	 * Note: we must free any quota before locking the superblock,
	 * as writing the quota to disk may need the lock as well.
	 */ /* Do this BEFORE marking the inode not in use */ /* Ok, now we can actually update the inode bitmaps.. */