Chinaunix首页 | 论坛 | 博客
  • 博客访问: 563956
  • 博文数量: 252
  • 博客积分: 1068
  • 博客等级: 少尉
  • 技术积分: 1775
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-05 21:33
文章分类

全部博文(252)

文章存档

2013年(21)

2012年(231)

分类: LINUX

2012-06-02 22:22:06

文件在磁盘的存储不同于程序员所看到的文件,主要表现在两个方面:块可以分散在磁盘上(尽管文件系统尽力保持块连续存放以提高访问速度),以及程序员看到的文件似乎比实际的文件大,这是因为程序可以把洞引人文件(通过lseek ()系统调用)。

从本篇博文开始,我们将介绍Ext2文件系统如何管理磁盘空间,也就是说,如何分配和释放索引节点和数据块。有两个主要的问题必须考虑:

(1)空间管理必须尽力避免文件碎片,也就是说,避免文件在物理上存放于几个小的、不相邻的盘块上。文件碎片增加了对文件的连续读操作的平均时间,因为在读操作期间,磁头必须频繁地重新定位。这个问题类似于在内存管理中的“伙伴系统算法”博文中所讨论的RAM的外部碎片问题。

(2)空间管理必须考虑效率,也就是说,内核应该能从文件的偏移量快速地导出Ext2分区上相应的逻辑块号。为了达到此目的,内核应该尽可能地限制对磁盘上寻址表的访问次数,因为对该表的访问会极大地增加文件的平均访问时间。

1 创建索引节点

ext2_new_inode()函数创建Ext2磁盘的索引节点,返回相应的索引节点对象的地址(或失败时为NULL)。该函数谨慎地选择存放该新索引节点的块组;它将无联系的目录散放在不同的组,而且同时把文件存放在父目录的同一组。为了平衡普通文件数与块组中的目录数,Ext2为每一个块组引入“债(debt) ”参数。

ext2_new_inode函数有两个参数:dir,所创建索引节点父目录对应的索引节点对象的地址,新创建的索引节点必须插入到这个目录中,成为其中的一个目录项;mode,要创建的索引节点的类型。后一个参数还包含一个MS_SYNCHRONOUS标志,该标志请求当前进程一直挂起,直到索引节点被分配成功或失败。该函数代码如下:


struct inode *ext2_new_inode(struct inode *dir, int mode)
{
struct super_block *sb;
struct buffer_head *bitmap_bh = NULL;
struct buffer_head *bh2;
int group, i;
ino_t ino = 0;
struct inode * inode;
struct ext2_group_desc *gdp;
struct ext2_super_block *es;
struct ext2_inode_info *ei;
struct ext2_sb_info *sbi;
int err;

sb = dir->i_sb;
inode = new_inode(sb);
if (!inode)
return ERR_PTR(-ENOMEM);

ei = EXT2_I(inode);
sbi = EXT2_SB(sb);
es = sbi->s_es;
if (S_ISDIR(mode)) {
if (test_opt(sb, OLDALLOC))
group = find_group_dir(sb, dir);
else
group = find_group_orlov(sb, dir);
} else
group = find_group_other(sb, dir);

if (group == -1) {
err = -ENOSPC;
goto fail;
}

for (i = 0; i < sbi->s_groups_count; i++) {
gdp = ext2_get_group_desc(sb, group, &bh2);
brelse(bitmap_bh);
bitmap_bh = read_inode_bitmap(sb, group);
if (!bitmap_bh) {
err = -EIO;
goto fail;
}
ino = 0;

repeat_in_this_group:
ino = ext2_find_next_zero_bit((unsigned long *)bitmap_bh->b_data,
EXT2_INODES_PER_GROUP(sb), ino);
if (ino >= EXT2_INODES_PER_GROUP(sb)) {
/*
* Rare race: find_group_xx() decided that there were
* free inodes in this group, but by the time we tried
* to allocate one, they're all gone. This can also
* occur because the counters which find_group_orlov()
* uses are approximate. So just go and search the
* next block group.
*/
if (++group == sbi->s_groups_count)
group = 0;
continue;
}
if (ext2_set_bit_atomic(sb_bgl_lock(sbi, group),
ino, bitmap_bh->b_data)) {
/* we lost this inode */
if (++ino >= EXT2_INODES_PER_GROUP(sb)) {
/* this group is exhausted, try next group */
if (++group == sbi->s_groups_count)
group = 0;
continue;
}
/* try to find free inode in the same group */
goto repeat_in_this_group;
}
goto got;
}

/*
* Scanned all blockgroups.
*/
err = -ENOSPC;
goto fail;
got:
mark_buffer_dirty(bitmap_bh);
if (sb->s_flags & MS_SYNCHRONOUS)
sync_dirty_buffer(bitmap_bh);
brelse(bitmap_bh);

ino += group * EXT2_INODES_PER_GROUP(sb) + 1;
if (ino < EXT2_FIRST_INO(sb) || ino > le32_to_cpu(es->s_inodes_count)) {
ext2_error (sb, "ext2_new_inode",
"reserved inode or inode > inodes count - "
"block_group = %d,inode=%lu", group,
(unsigned long) ino);
err = -EIO;
goto fail;
}

percpu_counter_mod(&sbi->s_freeinodes_counter, -1);
if (S_ISDIR(mode))
percpu_counter_inc(&sbi->s_dirs_counter);

spin_lock(sb_bgl_lock(sbi, group));
gdp->bg_free_inodes_count =
cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
if (S_ISDIR(mode)) {
if (sbi->s_debts[group] < 255)
sbi->s_debts[group]++;
gdp->bg_used_dirs_count =
cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
} else {
if (sbi->s_debts[group])
sbi->s_debts[group]--;
}
spin_unlock(sb_bgl_lock(sbi, group));

sb->s_dirt = 1;
mark_buffer_dirty(bh2);
inode->i_uid = current->fsuid;
if (test_opt (sb, GRPID))
inode->i_gid = dir->i_gid;
else if (dir->i_mode & S_ISGID) {
inode->i_gid = dir->i_gid;
if (S_ISDIR(mode))
mode |= S_ISGID;
} else
inode->i_gid = current->fsgid;
inode->i_mode = mode;

inode->i_ino = ino;
inode->i_blocks = 0;
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
memset(ei->i_data, 0, sizeof(ei->i_data));
ei->i_flags = EXT2_I(dir)->i_flags & ~EXT2_BTREE_FL;
if (S_ISLNK(mode))
ei->i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL);
/* dirsync is only applied to directories */
if (!S_ISDIR(mode))
ei->i_flags &= ~EXT2_DIRSYNC_FL;
ei->i_faddr = 0;
ei->i_frag_no = 0;
ei->i_frag_size = 0;
ei->i_file_acl = 0;
ei->i_dir_acl = 0;
ei->i_dtime = 0;
ei->i_block_group = group;
ei->i_next_alloc_block = 0;
ei->i_next_alloc_goal = 0;
ei->i_prealloc_block = 0;
ei->i_prealloc_count = 0;
ei->i_dir_start_lookup = 0;
ei->i_state = EXT2_STATE_NEW;
ext2_set_inode_flags(inode);
spin_lock(&sbi->s_next_gen_lock);
inode->i_generation = sbi->s_next_generation++;
spin_unlock(&sbi->s_next_gen_lock);
insert_inode_hash(inode);

if (DQUOT_ALLOC_INODE(inode)) {
err = -EDQUOT;
goto fail_drop;
}

err = ext2_init_acl(inode, dir);
if (err)
goto fail_free_drop;

err = ext2_init_security(inode,dir);
if (err)
goto fail_free_drop;

mark_inode_dirty(inode);
ext2_debug("allocating inode %lu/n", inode->i_ino);
ext2_preread_inode(inode);
return inode;

fail_free_drop:
DQUOT_FREE_INODE(inode);

fail_drop:
DQUOT_DROP(inode);
inode->i_flags |= S_NOQUOTA;
inode->i_nlink = 0;
iput(inode);
return ERR_PTR(err);

fail:
make_bad_inode(inode);
iput(inode);
return ERR_PTR(err);
}

1.调用new_inode()分配一个新的VFS索引节点对象,并把它的i_sb字段初始化为存放在dir->i_sb中的超级块地址。然后把它追加到正在用的索引节点链表与超级块链表中:

struct inode *new_inode(struct super_block *sb)
{
/* 32 bits for compatability mode stat calls */
static unsigned int last_ino;
struct inode * inode;

spin_lock_prefetch(&inode_lock);

inode = alloc_inode(sb);
if (inode) {
spin_lock(&inode_lock);
inodes_stat.nr_inodes++;
list_add(&inode->i_list, &inode_in_use);
list_add(&inode->i_sb_list, &sb->s_inodes);
inode->i_ino = ++last_ino;
inode->i_state = 0;
spin_unlock(&inode_lock);
}
return inode;
}

static struct inode *alloc_inode(struct super_block *sb)
{
static const struct address_space_operations empty_aops;
static struct inode_operations empty_iops;
static const struct file_operations empty_fops;
struct inode *inode;

if (sb->s_op->alloc_inode)
inode = sb->s_op->alloc_inode(sb);
else
inode = (struct inode *) kmem_cache_alloc(inode_cachep, SLAB_KERNEL);

if (inode) {
struct address_space * const mapping = &inode->i_data;

inode->i_sb = sb;
inode->i_blkbits = sb->s_blocksize_bits;
inode->i_flags = 0;
atomic_set(&inode->i_count, 1);
inode->i_op = &empty_iops;
inode->i_fop = &empty_fops;
inode->i_nlink = 1;
atomic_set(&inode->i_writecount, 0);
inode->i_size = 0;
inode->i_blocks = 0;
inode->i_bytes = 0;
inode->i_generation = 0;
#ifdef CONFIG_QUOTA
memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
#endif
inode->i_pipe = NULL;
inode->i_bdev = NULL;
inode->i_cdev = NULL;
inode->i_rdev = 0;
inode->i_security = NULL;
inode->dirtied_when = 0;
if (security_inode_alloc(inode)) {
if (inode->i_sb->s_op->destroy_inode)
inode->i_sb->s_op->destroy_inode(inode);
else
kmem_cache_free(inode_cachep, (inode));
return NULL;
}

mapping->a_ops = &empty_aops;
mapping->host = inode;
mapping->flags = 0;
mapping_set_gfp_mask(mapping, GFP_HIGHUSER);
mapping->assoc_mapping = NULL;
mapping->backing_dev_info = &default_backing_dev_info;

/*
* If the block_device provides a backing_dev_info for client
* inodes then use that. Otherwise the inode share the bdev's
* backing_dev_info.
*/
if (sb->s_bdev) {
struct backing_dev_info *bdi;

bdi = sb->s_bdev->bd_inode_backing_dev_info;
if (!bdi)
bdi = sb->s_bdev->bd_inode->i_mapping->backing_dev_info;
mapping->backing_dev_info = bdi;
}
inode->i_private = 0;
inode->i_mapping = mapping;
}
return inode;
}

还记得sb->s_op->alloc_inode(sb)吧,对,就是博文“Ext2的索引节点对象”提到的ext2_alloc_inode函数,我们就不再赘述了。注意,VFS的inode对象是嵌入在ext2_inode_info描述符中的,当执行了ext2_alloc_inode函数以后,new_inode()函数内部就会有一个未初始化的inode结构。随后,new_inode()函数将这个inode分别插入到以inode_in_use和sb->s_inodes为首的循环链表中。

2. 回到ext2_new_inode中,接下来:


struct ext2_inode_info *ei = EXT2_I(inode);
struct ext2_sb_info *sbi = EXT2_SB(sb);
struct ext2_super_block *es = sbi->s_es;
if (S_ISDIR(mode)) {
if (test_opt(sb, OLDALLOC))
group = find_group_dir(sb, dir);
else
group = find_group_orlov(sb, dir);
} else
group = find_group_other(sb, dir);

我们看到,与分配的inode相关的磁盘索引节点映像、磁盘超级快映像和磁盘超级快对象分别由内部变量ei、sbi和es指向。随后如果新的索引节点是一个目录,函数就调用find_group_orlov(sb, dir)为目录找到一个合适的块组(安装ext2时,如果带一个参数OLDALLOC,则会强制内核使用一种简单、老式的方式分配块组:find_group_dir(sb, dir))。find_group_orlov函数的实现比较简单,我们只是概要地介绍一下其中的相关代码,主要描述其中的逻辑关系。为一个目录分配块组总的策略是,尽量把一个该目录的目录项对应的普通文件的所以块放在同一个块组中。该函数执行如下试探法:

a. 以文件系统根root为父目录的目录项应该分散在各个块组。这样,函数在这些块组中去查找一个组,这个组中的空闲索引节点数的比例和空闲块数的比例比平均值高(avefreei = freei / ngroups,avefreeb = free_blocks / ngroups)。如果没有这样的组则跳到第c步。

b. 如果满足下列条件,嵌套目录(父目录不是文件系统根root)就应被存放到父目录块组:
- 该组没有包含太多的目录(desc->bg_used_dirs_count < best_ndir)
- 该组有足够多的空闲索引节点(desc->bg_free_inodes_count < min_inodes)
- 改组有足够多的空闲块(desc->bg_free_blocks_count) < min_blocks)
- 该组有一点小“债”。(块组的债存放在ext2_sb_info描述符的s_debts字段所指向的计数器数组中。每当一个新目录加入,债加1;每当其他类型的文件加入,债减1)

这个“债”有个最大值:max_debt = EXT2_BLOCKS_PER_GROUP(sb) / max(blocks_per_dir, BLOCK_COST),即每个组的块数与每个目录的块数之比值。注意,这里是表示目录文件所对应的块数,不是目录项对应的普通文件,其最大值为BLOCK_COST,即256。

如果父目录组parent_group没有满足这些条件,那么选择第一个上述满足条件的组。如果没有满足条件的组,则跳到第c步。

c. 这是一个“退一步”原则(fallback),当找不到合适的组时使用。函数从包含父目录的块组开始选择第一个满足条件的块组,这个条件是:它的空闲索引节点数比每块组空闲索引节点数的平均值大。

d. find_group_orlov函数最后返回分配给该目录的块组号(group)

3. 如果新索引节点不是个目录,则调用find_group_other(sb, dir),在有空闲索引节点的块组中给它分配一个。该函数从包含父目录的组开始往下找。具体逻辑如下:

a. 从包含父目录dir的块组开始,执行快速的对数查找。这种算法要查找log(n)个块组,这里n是块组总数。该算法一直向前查找直到找到一个可用的块组,具体如下:如果我们把开始的块组称为i,那么,该算法要查找的块组为i mod (n),i+1 mod (n),i+1+2 mod (n),i+1+2+4 mod (n),等等。大家是不是觉得这个东西是不是似曾相识呀,不错,就是伙伴系统算法的思想:
int parent_group = EXT2_I(parent)->i_block_group;
int ngroups = EXT2_SB(sb)->s_groups_count;
group = (group + parent->i_ino) % ngroups;
for (i = 1; i < ngroups; i <<= 1) {
group += i;
if (group >= ngroups)
group -= ngroups;
desc = ext2_get_group_desc (sb, group, &bh);
if (desc && le16_to_cpu(desc->bg_free_inodes_count) &&
le16_to_cpu(desc->bg_free_blocks_count))
goto found;
}

b.如果该算法没有找到含有空闲索引节点的块组,就从包含父目录dir的块组开始执行彻底的线性查找:
group = parent_group;
for (i = 0; i < ngroups; i++) {
if (++group >= ngroups)
group = 0;
desc = ext2_get_group_desc (sb, group, &bh);
if (desc && le16_to_cpu(desc->bg_free_inodes_count))
goto found;
}

4. 好啦,得到了所分配的块组号group,回到ext2_new_inode函数中,下一步要做的事是设置位图。于是调用read_inode_bitmap()得到所选块组的索引节点位图,并从中寻找第一个空闲位,这样就得到了第一个空闲磁盘索引节点号:
static struct buffer_head *
read_inode_bitmap(struct super_block * sb, unsigned long block_group)
{
struct ext2_group_desc *desc;
struct buffer_head *bh = NULL;

desc = ext2_get_group_desc(sb, block_group, NULL);
if (!desc)
goto error_out;

bh = sb_bread(sb, le32_to_cpu(desc->bg_inode_bitmap));
if (!bh)
ext2_error(sb, "read_inode_bitmap",
"Cannot read inode bitmap - "
"block_group = %lu, inode_bitmap = %u",
block_group, le32_to_cpu(desc->bg_inode_bitmap));
error_out:
return bh;
}

我们看到,read_inode_bitmap函数接收超级块和组号作为参数,获得超级快的块组描述符结构,然后将其索引节点位图地址对应的那个块缓存到页高速缓存中。最后将该高速缓存描述符buffer_head返回。

5. 接下来ext2_new_inode函数要做的事,是分配磁盘索引节点:把索引节点位图中的相应位置位:
ext2_set_bit_atomic(sb_bgl_lock(sbi, group), ino, bitmap_bh->b_data)

并把含有这个位图的页高速缓存标记为脏:
mark_buffer_dirty(bitmap_bh);

此外,如果文件系统安装时指定了MS_SYNCHRONOUS标志,则调用sync_dirty_buffer(bitmap_bh)开始I/O写操作并等待,直到写操作终止。

brelse(bitmap_bh),递减bitmap_bh的引用数。

6. 减小ext2_sb_info数据结构中的s_freeinodes_counter字段;而且如果新索引节点是目录,则增大ext2_sb_info数据结构的s_dirs counter字段。
percpu_counter_mod(&sbi->s_freeinodes_counter, -1);
if (S_ISDIR(mode))
percpu_counter_inc(&sbi->s_dirs_counter);

7. 减小组描述符的bg_free_inodes_count字段。如果新的索引节点是一个目录,则增加bg_used_dirs_count字段,并把含有这个组描述符的缓冲区标记为脏:
gdp = ext2_get_group_desc(sb, group, &bh2);
gdp->bg_free_inodes_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
if (S_ISDIR(mode)) {
if (sbi->s_debts[group] < 255)
sbi->s_debts[group]++;
gdp->bg_used_dirs_count =
cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
} else {
if (sbi->s_debts[group])
sbi->s_debts[group]--;
}
sb->s_dirt = 1;
mark_buffer_dirty(bh2);
inode->i_uid = current->fsuid;
注意,依据索引节点指向的是普通文件或目录,相应增减超级块内s_debts数组中的组计数器。

8. 初始化这个索引节点对象的字段。特别是,设置索引节点号i_no,并把xtime.tv_sec的值拷贝到i_atime、i_mtime及i_ctime。把这个块组的索引赋给ext2_inode_info结构的i_block_group字段:
ei->i_block_group = group;

9. 初始化这个索引节点对象的访问控制列表(ACL):
err = ext2_init_acl(inode, dir);
if (err)
goto fail_free_drop;

10. 将新索引节点对象插入散列表inode_hashtable(insert_inode_hash(inode),其数据结构详情请参考《把Linux中的VFS对象串联起来》),调用mark_inode_dirty()把该索引节点对象移进超级块脏索引节点链表:
static inline void insert_inode_hash(struct inode *inode) {
__insert_inode_hash(inode, inode->i_ino);
}
void __insert_inode_hash(struct inode *inode, unsigned long hashval)
{
struct hlist_head *head = inode_hashtable + hash(inode->i_sb, hashval);
spin_lock(&inode_lock);
hlist_add_head(&inode->i_hash, head);
spin_unlock(&inode_lock);
}
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
{
struct hlist_node *first = h->first;
n->next = first;
if (first)
first->pprev = &n->next;
h->first = n;
n->pprev = &h->first;
}

static inline void mark_inode_dirty(struct inode *inode)
{
__mark_inode_dirty(inode, I_DIRTY);
}
void __mark_inode_dirty(struct inode *inode, int flags)
{
struct super_block *sb = inode->i_sb;

/*
* Don't do this for I_DIRTY_PAGES - that doesn't actually
* dirty the inode itself
*/
if (flags & (I_DIRTY_SYNC | I_DIRTY_DATASYNC)) {
if (sb->s_op->dirty_inode)
sb->s_op->dirty_inode(inode);
}

/*
* make sure that changes are seen by all cpus before we test i_state
* -- mikulas
*/
smp_mb();

/* avoid the locking if we can */
if ((inode->i_state & flags) == flags)
return;

if (unlikely(block_dump)) {
struct dentry *dentry = NULL;
const char *name = "?";

if (!list_empty(&inode->i_dentry)) {
dentry = list_entry(inode->i_dentry.next,
struct dentry, d_alias);
if (dentry && dentry->d_name.name)
name = (const char *) dentry->d_name.name;
}

if (inode->i_ino || strcmp(inode->i_sb->s_id, "bdev"))
printk(KERN_DEBUG
"%s(%d): dirtied inode %lu (%s) on %s/n",
current->comm, current->pid, inode->i_ino,
name, inode->i_sb->s_id);
}

spin_lock(&inode_lock);
if ((inode->i_state & flags) != flags) {
const int was_dirty = inode->i_state & I_DIRTY;

inode->i_state |= flags;

/*
* If the inode is locked, just update its dirty state.
* The unlocker will place the inode on the appropriate
* superblock list, based upon its state.
*/
if (inode->i_state & I_LOCK)
goto out;

/*
* Only add valid (hashed) inodes to the superblock's
* dirty list. Add blockdev inodes as well.
*/
if (!S_ISBLK(inode->i_mode)) {
if (hlist_unhashed(&inode->i_hash))
goto out;
}
if (inode->i_state & (I_FREEING|I_CLEAR))
goto out;

/*
* If the inode was already on s_dirty or s_io, don't
* reposition it (that would break s_dirty time-ordering).
*/
if (!was_dirty) {
inode->dirtied_when = jiffies;
list_move(&inode->i_list, &sb->s_dirty);
}
}
out:
spin_unlock(&inode_lock);
}

11. 调用ext2_preread_inode()从磁盘读入包含该索引节点的块,将它存入页高速缓存。进行这种预读是因为最近创建的索引节点可能会被很快写入。


static void ext2_preread_inode(struct inode *inode)
{
unsigned long block_group;
unsigned long offset;
unsigned long block;
struct buffer_head *bh;
struct ext2_group_desc * gdp;
struct backing_dev_info *bdi;

bdi = inode->i_mapping->backing_dev_info;
if (bdi_read_congested(bdi))
return;
if (bdi_write_congested(bdi))
return;

block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb);
gdp = ext2_get_group_desc(inode->i_sb, block_group, &bh);
if (gdp == NULL)
return;

/*
* Figure out the offset within the block group inode table
*/
offset = ((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) *
EXT2_INODE_SIZE(inode->i_sb);
block = le32_to_cpu(gdp->bg_inode_table) +
(offset >> EXT2_BLOCK_SIZE_BITS(inode->i_sb));
sb_breadahead(inode->i_sb, block);
}
static inline void
sb_breadahead(struct super_block *sb, sector_t block)
{
__breadahead(sb->s_bdev, block, sb->s_blocksize);
}

12. 返回新索引节点对象inode的地址。

2 删除索引节点

内核调用ext2_free_inode()函数删除一个磁盘索引节点,把磁盘索引节点表示为索引节点对象,其地址作为参数来传递。内核在进行一系列的清除操作(包括清除内部数据结构和文件中的数据)之后调用这个函数。具体来说,它在下列操作完成之后才执行:索引节点对象已经从散列表中删除,指向这个索引节点的最后一个硬链接已经从适当的目录中删除,文件的长度截为0以回收它的所有数据块。

函数执行下列操作:

1. 调用clear_inode(),它依次执行如下步骤:

a.删除与索引节点关联的“间接”脏缓冲区。它们都存放在一个链表中,该链表的首部在address_space对象inode->i_data的private_list字段。


b.如果索引节点的I_LOCK标志置位,则说明索引节点中的某些缓冲区正处于I/O数据传送中;于是,函数挂起当前进程,直到这些1/O数据传送结束。


c.调用超级块对象的clear_inode方法(如果已定义),但Ext2文件系统没定义这个方法。


d.如果索引节点指向一个设备文件,则从设备的索引节点链表中删除索引节对象,这个链表要么在cdev字符设备描述符的cdev字段,要么在block_device块设备描述符的bd_inodes段。


e.把索引节点的状态置为I_CLEAR(表示索引节点对象的内容不再有意义)。

2. 从每个块组的索引节点号和索引节点数计算包含这个磁盘索引节点的块组的索引。

3. 调用read_inode_bitmap()得到索引节点位图。

4. 增加组描述符的bg_free_inodes_count字段。如果删除的索引节点是一个目录,那么也要减小bg_used_dirs_count字段。把这个组描述符所在的缓冲区标记为脏。

5. 如果删除的索引节点是一个目录,就减小ext2_sb_info结构的s_dirs_counter字段,把超级块的s_dirt标志置1,并把它所在的缓冲区标记为脏。

6. 清除索引节点位图中这个磁盘索引节点对应的位,并把包含这个位图的缓冲区标记为脏。此外,如果文件系统以MS_SYNCHRONIZE标志安装,则sync_dirty_buffer()并等待,直到在位图缓冲区上的写操作终止。

转载:http://blog.csdn.net/yunsongice/article/details/5822472

阅读(740) | 评论(0) | 转发(1) |
0

上一篇:Linux内核通用链表

下一篇:mount or unmount

给主人留下些什么吧!~~