Chinaunix首页 | 论坛 | 博客
  • 博客访问: 6266793
  • 博文数量: 2759
  • 博客积分: 1021
  • 博客等级: 中士
  • 技术积分: 4091
  • 用 户 组: 普通用户
  • 注册时间: 2012-03-11 14:14
文章分类

全部博文(2759)

文章存档

2019年(1)

2017年(84)

2016年(196)

2015年(204)

2014年(636)

2013年(1176)

2012年(463)

分类: LINUX

2015-07-18 10:07:33

创建文件时,代码并没有主动调用log  commit提交日志,只是将需要修改的元数据信息写到日志handle。等handle所在的事务超时,log会自动提交,内存transaction内容会刷写到磁盘日志中。写入磁盘日志中的内容为新建文件的inode所在的数据块内容、新建文件父目录文件的inode所在的数据块内容、新建文件父目录文件相关数据块的内容。

ext4_create是创建文件功能的函数。
首先设置原子操作
handle需要的缓冲区个数;
然后使用函数
ext4_new_inode_start_handle创建文件inode,其中包括记录日志内容等,但是比较复杂,所以日后在做分析;
然后设置文件系统日志模式和相关操作函数指针;
然后使用函数
ext4_add_nondirinodedentry建立关联,并且保存日志信息,这个函数下面再做解析;
最后调用
ext4_journal_stop断开handle和事务transaction的链接,此时,当该事务transaction提交时,事务缓冲区中的数据会刷写到磁盘。

static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode,

               bool excl)

{

    handle_t *handle;

    struct inode *inode;

    int err, credits, retries = 0;

 

    dquot_initialize(dir);/* 无操作,可忽略 */

 

    /* 原子操作预期修改的缓冲区个数 */

    credits = (EXT4_DATA_TRANS_BLOCKS(dir->i_sb) +

           EXT4_INDEX_EXTRA_TRANS_BLOCKS + 3);

retry:

    /* 创建inode,主要的函数,里面有保存日志内容的过程,需深入分析====> */

    inode = ext4_new_inode_start_handle(dir, mode, &dentry->d_name, 0,

                        NULL, EXT4_HT_DIR, credits);

    handle = ext4_journal_current_handle();/* 获得当前进程的原子操作数据结构handle */

    err = PTR_ERR(inode);

    if (!IS_ERR(inode)) {

        inode->i_op = &ext4_file_inode_operations;

        inode->i_fop = &ext4_file_operations;

       

        /* 根据日志模式,设置文件系统挂载选项参数;

         * 设置address_space_operations操作函数;

           ====>

         */

        ext4_set_aops(inode);

         /* inodedentry建立关联,并且保存日志信息====> */

        err = ext4_add_nondir(handle, dentry, inode);

        if (!err && IS_DIRSYNC(dir))

            ext4_handle_sync(handle);

    }

     /* 断开handletransaction的链接,当事务提交时,缓冲区数据刷到磁盘 */

    if (handle)

        ext4_journal_stop(handle);

    if (err == -ENOSPC && ext4_should_retry_alloc(dir->i_sb, &retries))

        goto retry;

    return err;

}

ext4_add_nondirinodedentry建立关联,并且保存日志信息。
首先调用
ext4_add_entry函数将文件的dentry加入到哈希目录树,并且将文件父目录的inode和父目录文件的相关数据块置为dirty
然后调用函数
ext4_mark_inode_dirty将新建文件的inode置为dirty
最后将新建文件的
dentryinode建立关联。

static int ext4_add_nondir(handle_t *handle,

        struct dentry *dentry, struct inode *inode)

{

    int err = ext4_add_entry(handle, dentry, inode);/* 文件entry加入哈希目录树,并且修改日志====> */

    if (!err) {

        ext4_mark_inode_dirty(handle, inode);/* 修改日志,将文件inode置为dirty====> */

        unlock_new_inode(inode);

        d_instantiate(dentry, inode);/* dentryinode建立关联,主要是设置对应的成员变量 */

        return 0;

    }

    drop_nlink(inode);

    unlock_new_inode(inode);

    iput(inode);/* inode放入lru缓存链表,供以后使用 */

    return err;

}

下面几个函数功能比较简单,见注释部分即可

static int ext4_add_entry(handle_t *handle, struct dentry *dentry,

              struct inode *inode)

{

    struct inode *dir = dentry->d_parent->d_inode;

    struct buffer_head *bh;

    struct ext4_dir_entry_2 *de;

    struct ext4_dir_entry_tail *t;

    struct super_block *sb;

    int retval;

    int dx_fallback=0;

    unsigned blocksize;

    ext4_lblk_t block, blocks;

    int csum_size = 0;

 

    if (EXT4_HAS_RO_COMPAT_FEATURE(inode->i_sb,

                       EXT4_FEATURE_RO_COMPAT_METADATA_CSUM))

        csum_size = sizeof(struct ext4_dir_entry_tail);

 

    sb = dir->i_sb;

    blocksize = sb->s_blocksize;

    if (!dentry->d_name.len)

        return -EINVAL;

 

    /* inode结构体中是否具有数据,ext4支持inline data功能 */

    if (ext4_has_inline_data(dir)) {

        retval = ext4_try_add_inline_entry(handle, dentry, inode);

        if (retval < 0)

            return retval;

        if (retval == 1) {

            retval = 0;

            return retval;

        }

    }

 

    if (is_dx(dir)) {

        /* 将目录添加到哈希目录树

         * 同时文件父目录的inode置为dirty,父目录的相关数据块置为dirty

         * ====>

         */

        retval = ext4_dx_add_entry(handle, dentry, inode);

。。。。。。省略代码

}


static int ext4_dx_add_entry(handle_t *handle, struct dentry *dentry,

                 struct inode *inode)

{

    struct dx_frame frames[2], *frame;

    struct dx_entry *entries, *at;

    struct dx_hash_info hinfo;

    struct buffer_head *bh;

    struct inode *dir = dentry->d_parent->d_inode;

    struct super_block *sb = dir->i_sb;

    struct ext4_dir_entry_2 *de;

    int err;

 

    frame = dx_probe(&dentry->d_name, dir, &hinfo, frames, &err);

    if (!frame)

        return err;

    entries = frame->entries;

    at = frame->at;

    bh = ext4_read_dirblock(dir, dx_get_block(frame->at), DIRENT);

    if (IS_ERR(bh)) {

        err = PTR_ERR(bh);

        bh = NULL;

        goto cleanup;

    }

 

    BUFFER_TRACE(bh, "get_write_access");

    err = ext4_journal_get_write_access(handle, bh);

    if (err)

        goto journal_error;

 

    err = add_dirent_to_buf(handle, dentry, inode, NULL, bh);

。。。。。。省略代码

}


ext4_mark_inode_dirty函数在jbd2中将inode元数据标记为脏数据,jbd2获得对inode所在磁盘块的写权限,并将inode所在的磁盘块bh挂在日志事务transaction的待处理日志bh链表如t_reserved_list中。

int ext4_mark_inode_dirty(handle_t *handle, struct inode *inode)

{

    struct ext4_iloc iloc;

    struct ext4_sb_info *sbi = EXT4_SB(inode->i_sb);

    static unsigned int mnt_count;

    int err, ret;

 

    might_sleep();

    trace_ext4_mark_inode_dirty(inode, _RET_IP_);

 

    /* 得到inode所在的磁盘块bh,然后jbd2获得对bh的写权限 */

    err = ext4_reserve_inode_write(handle, inode, &iloc);

    if (ext4_handle_valid(handle) &&

        EXT4_I(inode)->i_extra_isize < sbi->s_want_extra_isize &&

        !ext4_test_inode_state(inode, EXT4_STATE_NO_EXPAND)) {

        /*

         * We need extra buffer credits since we may write into EA block

         * with this same handle. If journal_extend fails, then it will

         * only result in a minor loss of functionality for that inode.

         * If this is felt to be critical, then e2fsck should be run to

         * force a large enough s_min_extra_isize.

         */

        if ((jbd2_journal_extend(handle,

                 EXT4_DATA_TRANS_BLOCKS(inode->i_sb))) == 0) {

            ret = ext4_expand_extra_isize(inode,

                              sbi->s_want_extra_isize,

                              iloc, handle);

            if (ret) {

                ext4_set_inode_state(inode,

                             EXT4_STATE_NO_EXPAND);

                if (mnt_count !=

                    le16_to_cpu(sbi->s_es->s_mnt_count)) {

                    ext4_warning(inode->i_sb,

                    "Unable to expand inode %lu. Delete"

                    " some EAs or run e2fsck.",

                    inode->i_ino);

                    mnt_count =

                      le16_to_cpu(sbi->s_es->s_mnt_count);

                }

            }

        }

    }

    if (!err)

        err = ext4_mark_iloc_dirty(handle, inode, &iloc);

    return err;

}



阅读(2449) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~