ext2文件系统inode.c分析(二)

2021SC@SDUSC 

/**
 *    ext2_find_shared -找到用于部分截断的间接块。
 *    @inode:      文件的inode
 *    @depth:      要截断chain的深度
 *    @offsets:    该分支中指针的偏移量(参见ext2_block_to_path)
 *    @chain:     用来存放指向局部间接块的指针
 *    @top:         置于(分离的)树枝顶部
 *
 *    这是ext2_truncate()使用的一个辅助函数。

当我们使用truncate()时,我们可能不得不清理几个间接块的末端,但让这些块本身存在。如果引用新的i_size下面的一些数据,则块被部分截断(实际上,它位于第一个完全截断的数据块的路径上)。我们必须解放这条路的顶部以及右边的所有东西。由于在ext2_truncate()完成之前不可能分配超过截断点的内存,所以可以安全地执行后者,但是需要特别注意分支的顶部——截断点以下的pageout可能会试图填充它。

 *
我们原子地将分支的顶部从树中分离出来,将根的块号存储在*@top中,指向部分截断块的buffer_heads的指针存储在@chain[]中。Bh和指向最后一个不应该被删除的元素的指针-在@chain[].p。返回值是指向@chain的最后一个填充元素的指针。
 *

留给调用者做的实际释放子树的工作:

a)释放从*@top开始的子树

b)释放根存储在(@chain[i])中的子树。p + 1 . .年底@chain[我].bh - > b_data)

c)释放从@chain[0]之前的inode生长的子树。P(没有部分被截断的部分)。

 */

static Indirect *ext2_find_shared(struct inode *inode,
                int depth,
                int offsets[4],
                Indirect chain[4],
                __le32 *top)
{
    Indirect *partial, *p;
    int k, err;

    *top = 0;

     /*找到要截断的位置*/
    for (k = depth; k > 1 && !offsets[k-1]; k--)
        ;

/*获得截断位置前边的映射链*/
    partial = ext2_get_branch(inode, k, offsets, chain, &err);

/*如果都没有问题,partial指向最后的节点*/
    if (!partial)
        partial = chain + k-1;
    /* 当我们找到映射链时,如果它保持连续,那么应该保存起来,并且此时链的top不属于我们*/
    write_lock(&EXT2_I(inode)->i_meta_lock);
    if (!partial->key && *partial->p) {
        write_unlock(&EXT2_I(inode)->i_meta_lock);
        goto no_top;
    }

/*找到间接块不为0的链接段*/
    for (p=partial; p>chain && all_zeroes((__le32*)p->bh->b_data,p->p); p--)
        ;

/*好的,我们已经找到了必须存活的最后一个块。映射链的其余部分应该在解锁之前分离。但是,如果其余的映射链都是我们的,并且不会立即从inode增长,那么只删除部分—>p。如果p就是要删除的点,p指针指向之前的块*/
    if (p == chain + k - 1 && p > chain) {
        p->p--;
    } else {
        *top = *p->p;
        *p->p = 0;
    }
    write_unlock(&EXT2_I(inode)->i_meta_lock);

    while(partial > p)
    {
        brelse(partial->bh);
        partial--;
    }
no_top:

/*映射链的头没有映射,返回映射链没有映射的头部*/
    return partial;
}

/**
 *    ext2_free_data - 释放一连串的数据块
 *    @inode:  要进行释放操作的inode
 *    @p:   数据块的数组
 *    @q:   指向数组的末尾
 *
 *    我们正在释放该数组中引用的所有块(数字存储为小端32位),并适当地更新@inode->i_blocks。
 */

static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
{
    unsigned long block_to_free = 0, count = 0;
    unsigned long nr;

    for ( ; p < q ; p++) {

/*数组上的数据都是按照小端32字节排序的,先获得块号*/
        nr = le32_to_cpu(*p);
        if (nr) {
            *p = 0;
            /* 计算块的数目,如果是连续的就一起释放,如果count为0,先别急着释放,看看下边的是不是连续的*/
            if (count == 0)
                goto free_this;

/*如果是连续的,count加一。不连续,就一起释放*/
            else if (block_to_free == nr - count)
                count++;
            else {
                ext2_free_blocks (inode, block_to_free, count);
                mark_inode_dirty(inode);
            free_this:
                block_to_free = nr;
                count = 1;
            }
        }
    }

/*开始释放count个连续的块*/
    if (count > 0) {
        ext2_free_blocks (inode, block_to_free, count);
        mark_inode_dirty(inode);
    }
}

/**
 *    ext2_free_branches -释放一组映射链上的分支
 *    @inode:    要进行操作的inode
 *    @p:    块的数组
 *    @q:    数组结尾
 *    @depth:   释放的分支的深度
 *
 *  我们正在释放从这些分支引用的所有块(数字存储为小端32位),并适当地更新@inode->i_blocks。
 */

static void ext2_free_branches(struct inode *inode, __le32 *p, __le32 *q, int depth)
{
    struct buffer_head * bh;
    unsigned long nr;

    if (depth--) {

/*每一个块存放的指针数目*/
        int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
        for ( ; p < q ; p++) {
            nr = le32_to_cpu(*p);
            if (!nr)
                continue;
            *p = 0;

/*先把这块读入到内存*/
            bh = sb_bread(inode->i_sb, nr);
            /*读取失败的话就报告错误并清除缓冲区 */ 
            if (!bh) {
                ext2_error(inode->i_sb, "ext2_free_branches",
                    "Read failure, inode=%ld, block=%ld",
                    inode->i_ino, nr);
                continue;
            }

/*释放本层的枝干*/
            ext2_free_branches(inode,
                       (__le32*)bh->b_data,
                       (__le32*)bh->b_data + addr_per_block,
                       depth);
            bforget(bh);
            ext2_free_blocks(inode, nr, 1);
            mark_inode_dirty(inode);
        }
    } else

/*只有一层的时候,直接释放*/
        ext2_free_data(inode, p, q);
}

/*该函数的作用是从映射树上截断。调用该函数时必须持有Dax_sem */
static void __ext2_truncate_blocks(struct inode *inode, loff_t offset)
{

/*映射指针所在的额数组*/
    __le32 *i_data = EXT2_I(inode)->i_data;
    struct ext2_inode_info *ei = EXT2_I(inode);

/*没块存放的指针数目*/
    int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
    int offsets[4];
    Indirect chain[4];
    Indirect *partial;
    __le32 nr = 0;
    int n;
    long iblock;
    unsigned blocksize;
    blocksize = inode->i_sb->s_blocksize;

/*iblock是截断的位置,块的大小偏移offset再右移块大小的位数*/
    iblock = (offset + blocksize-1) >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);

#ifdef CONFIG_FS_DAX
    WARN_ON(!rwsem_is_locked(&ei->dax_sem));
#endif

/*获得iblock对应的树叶到树根的路径*/

    n = ext2_block_to_path(inode, iblock, offsets, NULL);
    if (n == 0)
        return;

    /*从这里我们阻塞所有想要修改块分配树的ext2_get_block()调用者。*/
    mutex_lock(&ei->truncate_mutex);

/*如果从直接映射块开始截断,先释放第一层后边的叶子块,然后在释放后边的间接块*/

    if (n == 1) {
        ext2_free_data(inode, i_data+offsets[0],
                    i_data + EXT2_NDIR_BLOCKS);
        goto do_indirects;
    }

/*找到要截断的块所在的枝干*/

    partial = ext2_find_shared(inode, n, offsets, chain, &nr);
    /* 找到之后释放共享分支的顶部*/
    if (nr) {
        if (partial == chain)
            mark_inode_dirty(inode);
        else
            mark_buffer_dirty_inode(partial->bh, inode);
        ext2_free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
    }
    /* 清除共享分支上的间接块的末端*/
    while (partial > chain) {
        ext2_free_branches(inode,
                   partial->p + 1,
                   (__le32*)partial->bh->b_data+addr_per_block,
                   (chain+n-1) - partial);
        mark_buffer_dirty_inode(partial->bh, inode);
        brelse (partial->bh);
        partial--;
    }
do_indirects:

/* 开始释放间接映射块,因为offsets[0]得值是编号,所以会大于1*/
    /* 释放剩余的(整个)子树 */
    switch (offsets[0]) {
        default:

/*先获得一级间接块的编号,释放一级间接块,依次释放二三级间接块*/
            nr = i_data[EXT2_IND_BLOCK];
            if (nr) {
                i_data[EXT2_IND_BLOCK] = 0;
                mark_inode_dirty(inode);
                ext2_free_branches(inode, &nr, &nr+1, 1);
            }
            fallthrough;
        case EXT2_IND_BLOCK:
            nr = i_data[EXT2_DIND_BLOCK];
            if (nr) {
                i_data[EXT2_DIND_BLOCK] = 0;
                mark_inode_dirty(inode);
                ext2_free_branches(inode, &nr, &nr+1, 2);
            }
            fallthrough;
        case EXT2_DIND_BLOCK:
            nr = i_data[EXT2_TIND_BLOCK];
            if (nr) {
                i_data[EXT2_TIND_BLOCK] = 0;
                mark_inode_dirty(inode);
                ext2_free_branches(inode, &nr, &nr+1, 3);
            }
            break;
        case EXT2_TIND_BLOCK:
            ;
    }

    ext2_discard_reservation(inode);

    mutex_unlock(&ei->truncate_mutex);
}

static void ext2_truncate_blocks(struct inode *inode, loff_t offset)
{

/*目录或者链接文件不支持截断*/
    if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
        S_ISLNK(inode->i_mode)))
        return;

/*快速链接也不支持截断*/
    if (ext2_inode_is_fast_symlink(inode))
        return;

/*持有dax_sem原子地执行上面的操作*/

    dax_sem_down_write(EXT2_I(inode));
    __ext2_truncate_blocks(inode, offset);
    dax_sem_up_write(EXT2_I(inode));
}

static int ext2_setsize(struct inode *inode, loff_t newsize)
{
    int error;

/*目录或者链接文件不支持截断*/

    if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
        S_ISLNK(inode->i_mode)))
        return -EINVAL;

/*快速链接也不支持截断*/
    if (ext2_inode_is_fast_symlink(inode))
        return -EINVAL;

/*只能后续加入和不可修改的文件也不可以*/
    if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
        return -EPERM;

    inode_dio_wait(inode);

/*是否持有dax,即是否可以直接访问根据映射方式,选择页截断*/

    if (IS_DAX(inode)) {
        error = iomap_zero_range(inode, newsize,
                     PAGE_ALIGN(newsize) - newsize, NULL,
                     &ext2_iomap_ops);
    } else if (test_opt(inode->i_sb, NOBH))
        error = nobh_truncate_page(inode->i_mapping,
                newsize, ext2_get_block);
    else
        error = block_truncate_page(inode->i_mapping,
                newsize, ext2_get_block);
    if (error)
        return error;

    dax_sem_down_write(EXT2_I(inode));
    truncate_setsize(inode, newsize);
    __ext2_truncate_blocks(inode, newsize);
    dax_sem_up_write(EXT2_I(inode));

/*记录修改时间*/

    inode->i_mtime = inode->i_ctime = current_time(inode);

/*同步更新*/
    if (inode_needs_sync(inode)) {
        sync_mapping_buffers(inode->i_mapping);
        sync_inode_metadata(inode, 1);
    } else {
        mark_inode_dirty(inode);
    }

    return 0;
}

/*ext2文件系统获得一个inode,ino是希望获得inode的号码,p指向inode缓冲区*/

static struct ext2_inode *ext2_get_inode(struct super_block *sb, ino_t ino,
                    struct buffer_head **p)
{
    struct buffer_head * bh;
    unsigned long block_group;
    unsigned long block;
    unsigned long offset;
    struct ext2_group_desc * gdp;

    *p = NULL;

/*检查ino编号是不是合法,小于最小编号,大于编号数目都不行*/
    if ((ino != EXT2_ROOT_INO && ino < EXT2_FIRST_INO(sb)) ||
        ino > le32_to_cpu(EXT2_SB(sb)->s_es->s_inodes_count))
        goto Einval;

/*block_group获得ino在的组号码*/

    block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb);
    gdp = ext2_get_group_desc(sb, block_group, NULL);/*获得这个组的组描述符*/
    if (!gdp)
        goto Egdp;
    /*计算块组inode表中的偏移量*/
    offset = ((ino - 1) % EXT2_INODES_PER_GROUP(sb)) * EXT2_INODE_SIZE(sb);

/*inode在inodetable上的第几个块*/
    block = le32_to_cpu(gdp->bg_inode_table) +
        (offset >> EXT2_BLOCK_SIZE_BITS(sb));

/*读取这个块*/
    if (!(bh = sb_bread(sb, block)))
        goto Eio;

/*p指向inode所在的缓冲区*/

    *p = bh;
    offset &= (EXT2_BLOCK_SIZE(sb) - 1);

/*返回指向对应的inode结构体的位置指针*/
    return (struct ext2_inode *) (bh->b_data + offset);

Einval:
    ext2_error(sb, "ext2_get_inode", "bad inode number: %lu",
           (unsigned long) ino);
    return ERR_PTR(-EINVAL);
Eio:
    ext2_error(sb, "ext2_get_inode",
           "unable to read inode block - inode=%lu, block=%lu",
           (unsigned long) ino, block);
Egdp:
    return ERR_PTR(-EIO);
}

/*设置inode标志,因为ext2_inode_info和inode结构体上的标志虽然意义一样,但是位置不一样,所以要转化一下*/

void ext2_set_inode_flags(struct inode *inode)
{
    unsigned int flags = EXT2_I(inode)->i_flags;

    inode->i_flags &= ~(S_SYNC | S_APPEND | S_IMMUTABLE | S_NOATIME |
                S_DIRSYNC | S_DAX);
    if (flags & EXT2_SYNC_FL)
        inode->i_flags |= S_SYNC;
    if (flags & EXT2_APPEND_FL)
        inode->i_flags |= S_APPEND;
    if (flags & EXT2_IMMUTABLE_FL)
        inode->i_flags |= S_IMMUTABLE;
    if (flags & EXT2_NOATIME_FL)
        inode->i_flags |= S_NOATIME;
    if (flags & EXT2_DIRSYNC_FL)
        inode->i_flags |= S_DIRSYNC;
    if (test_opt(inode->i_sb, DAX) && S_ISREG(inode->i_mode))
        inode->i_flags |= S_DAX;
}

/*设置文件操作*/

void ext2_set_file_ops(struct inode *inode)
{
    inode->i_op = &ext2_file_inode_operations;
    inode->i_fop = &ext2_file_operations;
    if (IS_DAX(inode))
        inode->i_mapping->a_ops = &ext2_dax_aops;
    else if (test_opt(inode->i_sb, NOBH))
        inode->i_mapping->a_ops = &ext2_nobh_aops;
    else
        inode->i_mapping->a_ops = &ext2_aops;
}

/*阅读inode的内容*/

struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
{
    struct ext2_inode_info *ei;
    struct buffer_head * bh = NULL;
    struct ext2_inode *raw_inode;
    struct inode *inode;
    long ret = -EIO;
    int n;
    uid_t i_uid;
    gid_t i_gid;

    inode = iget_locked(sb, ino);
    if (!inode)
        return ERR_PTR(-ENOMEM);
    if (!(inode->i_state & I_NEW))
        return inode;

    ei = EXT2_I(inode);
    ei->i_block_alloc_info = NULL;

/*从硬盘上获得ext2_inode结构体*/

    raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);

/*如果读取进来的是坏的,直接退出*/
    if (IS_ERR(raw_inode)) {
        ret = PTR_ERR(raw_inode);
         goto bad_inode;
    }

/*开始从ext2文件系统上存储的ext2_inode读取数据转化成vfs层的inode数据*/

  /*文件打开模式*/

    inode->i_mode = le16_to_cpu(raw_inode->i_mode);
    i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);
    i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);
    if (!(test_opt (inode->i_sb, NO_UID32))) {/*如果没有NO_UID32位*/
        i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;
        i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;
    }
    i_uid_write(inode, i_uid);
    i_gid_write(inode, i_gid);
    set_nlink(inode, le16_to_cpu(raw_inode->i_links_count)); //引用计数
    inode->i_size = le32_to_cpu(raw_inode->i_size);                //文件大小

/*三种修改时间*/
    inode->i_atime.tv_sec = (signed)le32_to_cpu(raw_inode->i_atime);
    inode->i_ctime.tv_sec = (signed)le32_to_cpu(raw_inode->i_ctime);
    inode->i_mtime.tv_sec = (signed)le32_to_cpu(raw_inode->i_mtime);
    inode->i_atime.tv_nsec = inode->i_mtime.tv_nsec = inode->i_ctime.tv_nsec = 0;
    ei->i_dtime = le32_to_cpu(raw_inode->i_dtime);
    /* 现在我们有足够的字段来检查inode是否处于活动状态。这是必需的,因为nfsd可能会尝试访问死节点,测试与e2fsck使用的NeilBrown 1999oct15相同*/

/* 如果引用计数为0,,并且mode为0,说明文件已经被删除了 */
    if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) {
        /* this inode is deleted */
        ret = -ESTALE;
        goto bad_inode;
    }
    inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);

/*flag标志等字段的读取*/
    ei->i_flags = le32_to_cpu(raw_inode->i_flags);
    ext2_set_inode_flags(inode);
    ei->i_faddr = le32_to_cpu(raw_inode->i_faddr);
    ei->i_frag_no = raw_inode->i_frag;
    ei->i_frag_size = raw_inode->i_fsize;
    ei->i_file_acl = le32_to_cpu(raw_inode->i_file_acl);
    ei->i_dir_acl = 0;

/*判断坏扩展属性块*/

    if (ei->i_file_acl &&
        !ext2_data_block_valid(EXT2_SB(sb), ei->i_file_acl, 1)) {
        ext2_error(sb, "ext2_iget", "bad extended attribute block %u",
               ei->i_file_acl);
        ret = -EFSCORRUPTED;
        goto bad_inode;
    }

    if (S_ISREG(inode->i_mode))
        inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;
    else
        ei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
    if (i_size_read(inode) < 0) {
        ret = -EFSCORRUPTED;
        goto bad_inode;
    }

/*读取和运行时赋值的字段,先赋为0*/
    ei->i_dtime = 0;
    inode->i_generation = le32_to_cpu(raw_inode->i_generation);
    ei->i_state = 0;
    ei->i_block_group = (ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb);
    ei->i_dir_start_lookup = 0;

    /*注意内存中的inode i_data数组即使在大端机器上也是小端顺序的,所以我们不使用字节交换块数*/

/* 复制i_data,就是文件映射指针 */
    for (n = 0; n < EXT2_N_BLOCKS; n++)
        ei->i_data[n] = raw_inode->i_block[n];

/*根据文件的类型不同,设置文件的操作函数集合*/

/*普通文件*/

    if (S_ISREG(inode->i_mode)) {
        ext2_set_file_ops(inode);
    } else if (S_ISDIR(inode->i_mode)) {/*目录文件*/
        inode->i_op = &ext2_dir_inode_operations;
        inode->i_fop = &ext2_dir_operations;
        if (test_opt(inode->i_sb, NOBH))
            inode->i_mapping->a_ops = &ext2_nobh_aops;
        else
            inode->i_mapping->a_ops = &ext2_aops;
    } else if (S_ISLNK(inode->i_mode)) {/*链接文件*/
        if (ext2_inode_is_fast_symlink(inode)) {/*快速链接*/
            inode->i_link = (char *)ei->i_data;
            inode->i_op = &ext2_fast_symlink_inode_operations;
            nd_terminate_link(ei->i_data, inode->i_size,
                sizeof(ei->i_data) - 1);
        } else {/*非快速链接*/
            inode->i_op = &ext2_symlink_inode_operations;
            inode_nohighmem(inode);
            if (test_opt(inode->i_sb, NOBH))
                inode->i_mapping->a_ops = &ext2_nobh_aops;
            else
                inode->i_mapping->a_ops = &ext2_aops;
        }
    } else {/*其他文件*/
        inode->i_op = &ext2_special_inode_operations;
        if (raw_inode->i_block[0])
            init_special_inode(inode, inode->i_mode,
               old_decode_dev(le32_to_cpu(raw_inode->i_block[0])));
        else 
            init_special_inode(inode, inode->i_mode,
               new_decode_dev(le32_to_cpu(raw_inode->i_block[1])));
    }
    brelse (bh);
    unlock_new_inode(inode);
    return inode;
    
bad_inode:
    brelse(bh);
    iget_failed(inode);/*标记这个inode是坏的*/
    return ERR_PTR(ret);
}

/*同步inode数据,把inode的数据写入到硬盘里*/

static int __ext2_write_inode(struct inode *inode, int do_sync)
{
    struct ext2_inode_info *ei = EXT2_I(inode);
    struct super_block *sb = inode->i_sb;
    ino_t ino = inode->i_ino;
    uid_t uid = i_uid_read(inode);
    gid_t gid = i_gid_read(inode);
    struct buffer_head * bh;

/*读取硬盘上的ext2_inode*/
    struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh);
    int n;
    int err = 0;

/*如果读取的inode有问题,返回IO读取错误*/

    if (IS_ERR(raw_inode))
         return -EIO;

    /* 对于内存中索引节点中没有跟踪的字段,将它们初始化为零以用于新的索引节点。*/
    if (ei->i_state & EXT2_STATE_NEW)
        memset(raw_inode, 0, EXT2_SB(sb)->s_inode_size);

/*开始用inode的数据填充raw_inode*/

/*文件打开模式*/

    raw_inode->i_mode = cpu_to_le16(inode->i_mode);
    if (!(test_opt(sb, NO_UID32))) {
        raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid));
        raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid));
/*修复与旧内核的互操作性。否则,旧的索引节点将在uid/gid的上16位不变的情况下重新使用*/
        if (!ei->i_dtime) {
            raw_inode->i_uid_high = cpu_to_le16(high_16_bits(uid));
            raw_inode->i_gid_high = cpu_to_le16(high_16_bits(gid));
        } else {
            raw_inode->i_uid_high = 0;
            raw_inode->i_gid_high = 0;
        }
    } else {
        raw_inode->i_uid_low = cpu_to_le16(fs_high2lowuid(uid));
        raw_inode->i_gid_low = cpu_to_le16(fs_high2lowgid(gid));
        raw_inode->i_uid_high = 0;
        raw_inode->i_gid_high = 0;
    }

/*链接计数,文件大小,修改时间*/
    raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
    raw_inode->i_size = cpu_to_le32(inode->i_size);
    raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec);
    raw_inode->i_ctime = cpu_to_le32(inode->i_ctime.tv_sec);
    raw_inode->i_mtime = cpu_to_le32(inode->i_mtime.tv_sec);

/*文件块数目,删除时间,标志*/

    raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
    raw_inode->i_dtime = cpu_to_le32(ei->i_dtime);
    raw_inode->i_flags = cpu_to_le32(ei->i_flags);


    raw_inode->i_faddr = cpu_to_le32(ei->i_faddr);        /*帧地址*/
    raw_inode->i_frag = ei->i_frag_no;                            /*文件碎片的信息*/
    raw_inode->i_fsize = ei->i_frag_size;
    raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);/*文件的acl控制*/

/*如果不是普通文件,赋值目录的acl控制*/
    if (!S_ISREG(inode->i_mode))
        raw_inode->i_dir_acl = cpu_to_le32(ei->i_dir_acl);
    else {
        raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
        if (inode->i_size > 0x7fffffffULL) {
            if (!EXT2_HAS_RO_COMPAT_FEATURE(sb,
                    EXT2_FEATURE_RO_COMPAT_LARGE_FILE) ||
                EXT2_SB(sb)->s_es->s_rev_level ==
                    cpu_to_le32(EXT2_GOOD_OLD_REV)) {
                   /*如果这是第一个创建的大文件,那么在超级块中添加一个标志。*/
                spin_lock(&EXT2_SB(sb)->s_lock);
                ext2_update_dynamic_rev(sb);
                EXT2_SET_RO_COMPAT_FEATURE(sb,
                    EXT2_FEATURE_RO_COMPAT_LARGE_FILE);
                spin_unlock(&EXT2_SB(sb)->s_lock);
                ext2_sync_super(sb, EXT2_SB(sb)->s_es, 1);
            }
        }
    }
    /*文件系统版本*/
    raw_inode->i_generation = cpu_to_le32(inode->i_generation);

/*字符设备或者是块设备文件*/
    if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {

/*老的设备和新的标识方法不一样*/
        if (old_valid_dev(inode->i_rdev)) {
            raw_inode->i_block[0] =
                cpu_to_le32(old_encode_dev(inode->i_rdev));
            raw_inode->i_block[1] = 0;
        } else {
            raw_inode->i_block[0] = 0;
            raw_inode->i_block[1] =
                cpu_to_le32(new_encode_dev(inode->i_rdev));
            raw_inode->i_block[2] = 0;
        }
    } else for (n = 0; n < EXT2_N_BLOCKS; n++)
        raw_inode->i_block[n] = ei->i_data[n];
    mark_buffer_dirty(bh);

/*同步标记*/
    if (do_sync) {
        sync_dirty_buffer(bh);
        if (buffer_req(bh) && !buffer_uptodate(bh)) {
            printk ("IO error syncing ext2 inode [%s:%08lx]\n",
                sb->s_id, (unsigned long) ino);
            err = -EIO;
        }
    }

/*取消EXT2_STATE_NEW标志位*/
    ei->i_state &= ~EXT2_STATE_NEW;
    brelse (bh);
    return err;
}

/*调用上边的函数,将inode写入到硬盘上*/

int ext2_write_inode(struct inode *inode, struct writeback_control *wbc)
{
    return __ext2_write_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
}

/*获取文件属性*/

int ext2_getattr(struct user_namespace *mnt_userns, const struct path *path,
         struct kstat *stat, u32 request_mask, unsigned int query_flags)
{
    struct inode *inode = d_inode(path->dentry);
    struct ext2_inode_info *ei = EXT2_I(inode);
    unsigned int flags;

/*转化ext2_inode_info结构体上的flags*/

    flags = ei->i_flags & EXT2_FL_USER_VISIBLE;
    if (flags & EXT2_APPEND_FL)
        stat->attributes |= STATX_ATTR_APPEND;
    if (flags & EXT2_COMPR_FL)
        stat->attributes |= STATX_ATTR_COMPRESSED;
    if (flags & EXT2_IMMUTABLE_FL)
        stat->attributes |= STATX_ATTR_IMMUTABLE;
    if (flags & EXT2_NODUMP_FL)
        stat->attributes |= STATX_ATTR_NODUMP;
    stat->attributes_mask |= (STATX_ATTR_APPEND |
            STATX_ATTR_COMPRESSED |
            STATX_ATTR_ENCRYPTED |
            STATX_ATTR_IMMUTABLE |
            STATX_ATTR_NODUMP);

    generic_fillattr(&init_user_ns, inode, stat);
    return 0;
}

/*设置文件属性*/

int ext2_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
         struct iattr *iattr)
{
    struct inode *inode = d_inode(dentry);
    int error;

/*检查文件属性有没有错误*/

    error = setattr_prepare(&init_user_ns, dentry, iattr);
    if (error)
        return error;

    if (is_quota_modification(inode, iattr)) {
        error = dquot_initialize(inode);
        if (error)
            return error;
    }

/*合法且uid和gid一样才可以设置*/
    if ((iattr->ia_valid & ATTR_UID && !uid_eq(iattr->ia_uid, inode->i_uid)) ||
        (iattr->ia_valid & ATTR_GID && !gid_eq(iattr->ia_gid, inode->i_gid))) {
        error = dquot_transfer(inode, iattr);
        if (error)
            return error;
    }

/*合法且size一样才可以设置*/
    if (iattr->ia_valid & ATTR_SIZE && iattr->ia_size != inode->i_size) {
        error = ext2_setsize(inode, iattr->ia_size);
        if (error)
            return error;
    }

/*复制属性*/
    setattr_copy(&init_user_ns, inode, iattr);

/*定义了ATTR_MODE位,就改变acl*/
    if (iattr->ia_valid & ATTR_MODE)
        error = posix_acl_chmod(&init_user_ns, inode, inode->i_mode);
    mark_inode_dirty(inode);

    return error;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值