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;
}