EXT2普通文件节点的操作方法

来源:互联网 发布:mac切换窗口的快捷键 编辑:程序博客网 时间:2024/05/17 07:14
 


const struct inode_operations ext2_file_inode_operations = {
 .truncate = ext2_truncate,
#ifdef CONFIG_EXT2_FS_XATTR
 .setxattr = generic_setxattr,
 .getxattr = generic_getxattr,
 .listxattr = ext2_listxattr,
 .removexattr = generic_removexattr,
#endif
 .setattr = ext2_setattr,
 .permission = ext2_permission,
 .fiemap  = ext2_fiemap,
};
=======================================
void ext2_truncate(struct inode *inode)
{
001 __le32 *i_data = EXT2_I(inode)->i_data;
002 struct ext2_inode_info *ei = EXT2_I(inode);
003 int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
004 int offsets[4];
005 Indirect chain[4];
006 Indirect *partial;
007 __le32 nr = 0;
008 int n;
009 long iblock;
010 unsigned blocksize;
第1行使用EXT2_I函数,根据VFS中的inode节点,找到内存中的索引节点,它是container_of的封装。
第2行使用EXT2_I函数,给内存中的索引节点赋值。
第3行使用EXT2_ADDR_PER_BLOCK宏,得到每块的地址。
第4-10行分别对偏移,块的大小的定义等。
012 if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
013     S_ISLNK(inode->i_mode)))
014  return;
015 if (ext2_inode_is_fast_symlink(inode))
016  return;
017 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
018  return;
019
020 blocksize = inode->i_sb->s_blocksize;
021 iblock = (inode->i_size + blocksize-1)
022     >> EXT2_BLOCK_SIZE_BITS(inode->i_sb);
023
024 if (mapping_is_xip(inode->i_mapping))
025  xip_truncate_page(inode->i_mapping, inode->i_size);
026 else if (test_opt(inode->i_sb, NOBH))
027  nobh_truncate_page(inode->i_mapping,
028    inode->i_size, ext2_get_block);
029 else
030  block_truncate_page(inode->i_mapping,
031    inode->i_size, ext2_get_block);
032
033 n = ext2_block_to_path(inode, iblock, offsets, NULL);
034 if (n == 0)
035  return;
第12行如果不是普通文件,是目录文件,就是链接文件,则返回。
第15行使用ext2_inode_is_fast_symlink判断是否为快速链接节点。如果是,则返回。
第20行得到块的大小。
第24行判断是否节点是否映射。如果是则调用xip_truncate_page。
第25行判断是否没有缓冲区头部。
第29行否则调用block_truncate_page函数
第33行调用ext2_block_to_path解析出块的编号的数组中的偏移。返回值路径的长度。如果块超出了范围,则返回0。
041 mutex_lock(&ei->truncate_mutex);
043 if (n == 1) {
044  ext2_free_data(inode, i_data+offsets[0],
045     i_data + EXT2_NDIR_BLOCKS);
046  goto do_indirects;
047 }
048
049 partial = ext2_find_shared(inode, n, offsets, chain, &nr);
050 /* Kill the top of shared branch (already detached) */
051 if (nr) {
052  if (partial == chain)
053   mark_inode_dirty(inode);
054  else
055   mark_buffer_dirty_inode(partial->bh, inode);
056  ext2_free_branches(inode, &nr, &nr+1, (chain+n-1) - partial);
057 }
059 while (partial > chain) {
060  ext2_free_branches(inode,
061       partial->p + 1,
062       (__le32*)partial->bh->b_data+addr_per_block,
063       (chain+n-1) - partial);
064  mark_buffer_dirty_inode(partial->bh, inode);
065  brelse (partial->bh);
066  partial--;
067 }
第41行对内存索引节点的加锁
第43行如果n的值为1,则释放数据块的链表,跳转到do_indirects标号处
第49使用ext2_find_shared找到非直接的块。
第51行nr为放在顶部的分枝,如果为真,则判断返回值和指针指向的非直接块是否相等。如果相等,则标记脏的索引节点,否则,标记内存中的脏索引节点。并且释放分支。
第59-67行清除掉以非直接块的结尾,在共享分支上的。
068do_indirects:
069 /* Kill the remaining (whole) subtrees */
070 switch (offsets[0]) {
071  default:
072   nr = i_data[EXT2_IND_BLOCK];
073   if (nr) {
074    i_data[EXT2_IND_BLOCK] = 0;
075    mark_inode_dirty(inode);
076    ext2_free_branches(inode, &nr, &nr+1, 1);
077   }
078  case EXT2_IND_BLOCK:
079   nr = i_data[EXT2_DIND_BLOCK];
080   if (nr) {
081    i_data[EXT2_DIND_BLOCK] = 0;
082    mark_inode_dirty(inode);
083    ext2_free_branches(inode, &nr, &nr+1, 2);
084   }
085  case EXT2_DIND_BLOCK:
086   nr = i_data[EXT2_TIND_BLOCK];
087   if (nr) {
088    i_data[EXT2_TIND_BLOCK] = 0;
089    mark_inode_dirty(inode);
090    ext2_free_branches(inode, &nr, &nr+1, 3);
091   }
092  case EXT2_TIND_BLOCK:
093   ;
094 }
095
096 ext2_discard_reservation(inode);
097
098 mutex_unlock(&ei->truncate_mutex);
099 inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
100 if (inode_needs_sync(inode)) {
101  sync_mapping_buffers(inode->i_mapping);
102  ext2_sync_inode (inode);
103 } else {
104  mark_inode_dirty(inode);
105 }
106}
第70-94行去除掉保留的分枝。分别为直接块,非直接块的处理
第98行解锁。
第99行对索引节点的时间字段赋当前时间的值
第100行判断当前的索引节点是否为同步索引节点。如果是,则使用sync_mapping_buffers,写入一个相联系的buffer中,使用ext2_sync_inode同步节点。否则标记为脏的节点
=======================================
int
generic_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags)
{
01 struct xattr_handler *handler;
02 struct inode *inode = dentry->d_inode;
03
04 if (size == 0)
05  value = "";  /* empty EA, do not remove */
06 handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
07 if (!handler)
08  return -EOPNOTSUPP;
09 return handler->set(inode, name, value, size, flags);
10}
第1行定义一个索引节点增强属性。
第2行索引节点初始化
第6行找到xattr_handler的前缀
第9行调用set方法,个人认为是调用了ext2_xattr_set_acl_default函数,有个不同意见,请指出。没有找到合适的理由。
static int ext2_xattr_set_acl_default(struct inode *inode, const char *name,
      const void *value, size_t size, int flags)
{
 if (strcmp(name, "") != 0)
  return -EINVAL;
 return ext2_xattr_set_acl(inode, ACL_TYPE_DEFAULT, value, size);
}
如果名字为空,则返回,否则就调用ext2_xattr_set_acl来处理。
static int ext2_xattr_set_acl(struct inode *inode, int type, const void *value,size_t size)
{
01 struct posix_acl *acl;
02 int error;
03 if (!test_opt(inode->i_sb, POSIX_ACL))
04  return -EOPNOTSUPP;
05 if (!is_owner_or_cap(inode))
06  return -EPERM;
07 if (value) {
08  acl = posix_acl_from_xattr(value, size);
09  if (IS_ERR(acl))
10   return PTR_ERR(acl);
11  else if (acl) {
12   error = posix_acl_valid(acl);
13   if (error)
14    goto release_and_out;
15  }
16 } else
17  acl = NULL;
18 error = ext2_set_acl(inode, type, acl);
19release_and_out:
20 posix_acl_release(acl);
21 return error;
22}
第8行转换从扩充属性到内存中。
第12行核对acl是否有效,0表示有效,否则无效
第18行设置acl。
第20行释放ACL句柄。
=======================================
ssize_t
generic_getxattr(struct dentry *dentry, const char *name, void *buffer, size_t size)
{
1 struct xattr_handler *handler;
2 struct inode *inode = dentry->d_inode;
3
4 handler = xattr_resolve_name(inode->i_sb->s_xattr, &name);
5 if (!handler)
6  return -EOPNOTSUPP;
7 return handler->get(inode, name, buffer, size);
8}
第7行调用handler的get方法,然后会调用ext2_xattr_get_acl_default方法
static int ext2_xattr_get_acl_default(struct inode *inode, const char *name,
      void *buffer, size_t size)
{
 if (strcmp(name, "") != 0)
  return -EINVAL;
 return ext2_xattr_get_acl(inode, ACL_TYPE_DEFAULT, buffer, size);
}
如果名字为空,直接返回,否则会调用ext2_xattr_get_acl方法。
static int ext2_xattr_get_acl(struct inode *inode, int type, void *buffer, size_t size)
{
01 struct posix_acl *acl;
02 int error;
03 if (!test_opt(inode->i_sb, POSIX_ACL))
04  return -EOPNOTSUPP;
05 acl = ext2_get_acl(inode, type);
06 if (IS_ERR(acl))
07  return PTR_ERR(acl);
08 if (acl == NULL)
09  return -ENODATA;
10 error = posix_acl_to_xattr(acl, buffer, size);
11 posix_acl_release(acl);
12 return error;
13}
第5行得到ACL
第10行转换从扩充属性到内存中
第11行释放ACL句柄
=======================================
ssize_t
ext2_listxattr(struct dentry *dentry, char *buffer, size_t size)
{
 return ext2_xattr_list(dentry->d_inode, buffer, size);
}
使用ext2_xattr_list函数,拷贝文件列表到buffer。
static int ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size)
{
01 struct buffer_head *bh = NULL;
02 struct ext2_xattr_entry *entry;
03 char *end;
04 size_t rest = buffer_size;
05 int error;
07 ea_idebug(inode, "buffer=%p, buffer_size=%ld",
08    buffer, (long)buffer_size);
10 down_read(&EXT2_I(inode)->xattr_sem);
11 error = 0;
12 if (!EXT2_I(inode)->i_file_acl)
13  goto cleanup;
14 ea_idebug(inode, "reading block %d", EXT2_I(inode)->i_file_acl);
15 bh = sb_bread(inode->i_sb, EXT2_I(inode)->i_file_acl);
16 error = -EIO;
17 if (!bh)
18  goto cleanup;
19 ea_bdebug(bh, "b_count=%d, refcount=%d",
20  atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount));
21 end = bh->b_data + bh->b_size;
22 if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) ||
23     HDR(bh)->h_blocks != cpu_to_le32(1)) {
24bad_block: ext2_error(inode->i_sb, "ext2_xattr_list",
25   "inode %ld: bad block %d", inode->i_ino,
26   EXT2_I(inode)->i_file_acl);
27  error = -EIO;
28  goto cleanup;
29 }
31 /* check the on-disk data structure */
32 entry = FIRST_ENTRY(bh);
33 while (!IS_LAST_ENTRY(entry)) {
34  struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(entry);
36  if ((char *)next >= end)
37   goto bad_block;
38  entry = next;
39 }
40 if (ext2_xattr_cache_insert(bh))
41  ea_idebug(inode, "cache insert failed");
44 for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry);
45      entry = EXT2_XATTR_NEXT(entry)) {
46  struct xattr_handler *handler =
47   ext2_xattr_handler(entry->e_name_index);
49  if (handler) {
50  size_t size = handler->list(inode, buffer, rest, entry->e_name,  entry->e_name_len);
53   if (buffer) {
54    if (size > rest) {
55     error = -ERANGE;
56     goto cleanup;
57    }
58    buffer += size;
59   }
60   rest -= size;
61  }
62 }
63 error = buffer_size - rest;  /* total size */
65cleanup:
66 brelse(bh);
67 up_read(&EXT2_I(inode)->xattr_sem);
69 return error;
70}
第10行锁定信号量进行读
第15行使用sb_bread函数,得到缓存区首部,它__bread函数的封装。
第21行计算出end的结束位置。
第32-39行核对磁盘的数据结构,使用宏FIRST_ENTRY得出第一个ext2_xattr_entry描述符,然后循环找到下一个。
第40行创建一个新的entry在扩展属性缓存中,并且把它插入其中,如果没有的情况下。
第41-63行循环列出这些属性。

=======================================
int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
{
01 struct inode *inode = dentry->d_inode;
02 int error;
03
04 error = inode_change_ok(inode, iattr);
05 if (error)
06  return error;
07 if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||
08     (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {
09  error = vfs_dq_transfer(inode, iattr) ? -EDQUOT : 0;
10  if (error)
11   return error;
12 }
13 error = inode_setattr(inode, iattr);
14 if (!error && (iattr->ia_valid & ATTR_MODE))
15  error = ext2_acl_chmod(inode);
16 return error;
17}
第4行设置结点属性
第13行使用inode_setattr函数,对节点的属性的设置。
=======================================
int ext2_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
  u64 start, u64 len)
{
 return generic_block_fiemap(inode, fieinfo, start, len,
        ext2_get_block);
}
文件映射,调用generic_block_fiemap来实现。
int generic_block_fiemap(struct inode *inode,struct fiemap_extent_info *fieinfo, u64 start,
    u64 len, get_block_t *get_block)
{
 int ret;
 mutex_lock(&inode->i_mutex);
 ret = __generic_block_fiemap(inode, fieinfo, start, len, get_block);
 mutex_unlock(&inode->i_mutex);
 return ret;
}
对节点进行加锁,调用__generic_block_fiemap函数具体实现,然后进行解锁。
int __generic_block_fiemap(struct inode *inode,
      struct fiemap_extent_info *fieinfo, u64 start,
      u64 len, get_block_t *get_block)
{
01 struct buffer_head tmp;
02 unsigned int start_blk;
03 long long length = 0, map_len = 0;
04 u64 logical = 0, phys = 0, size = 0;
05 u32 flags = FIEMAP_EXTENT_MERGED;
06 int ret = 0, past_eof = 0, whole_file = 0;
08 if ((ret = fiemap_check_flags(fieinfo, FIEMAP_FLAG_SYNC)))
09  return ret;
11 start_blk = logical_to_blk(inode, start);
13 length = (long long)min_t(u64, len, i_size_read(inode));
14 if (length < len)
15  whole_file = 1;
17 map_len = length;
19 do {
21  memset(&tmp, 0, sizeof(struct buffer_head));
22  tmp.b_size = map_len;
24  ret = get_block(inode, start_blk, &tmp, 0);
25  if (ret)
26   break;
29  if (!buffer_mapped(&tmp)) {
30   length -= blk_to_logical(inode, 1);
31   start_blk++;
32   if (!past_eof &&
33       blk_to_logical(inode, start_blk) >=
34       blk_to_logical(inode, 0)+i_size_read(inode))
35    past_eof = 1;
36   if (past_eof && size) {
37    flags = FIEMAP_EXTENT_MERGED|FIEMAP_EXTENT_LAST;
38    ret = fiemap_fill_next_extent(fieinfo, logical, phys, size,flags);
41    break;
42   }
45   if (length <= 0 || past_eof)
46    break;
47  } else {
49   if (length <= 0 && !whole_file) {
50    ret = fiemap_fill_next_extent(fieinfo, logical, phys, size,flags);
53    break;
54   }
55   if (size) {
56    ret = fiemap_fill_next_extent(fieinfo, logical, phys, size, flags);
59    if (ret)
60     break;
61   }
63   logical = blk_to_logical(inode, start_blk);
64   phys = blk_to_logical(inode, tmp.b_blocknr);
65   size = tmp.b_size;
66   flags = FIEMAP_EXTENT_MERGED;
68   length -= tmp.b_size;
69   start_blk += logical_to_blk(inode, size);
70   if (!past_eof &&
71       logical+size >=
72       blk_to_logical(inode, 0)+i_size_read(inode))
73    past_eof = 1;
74  }
75  cond_resched();
76 } while (1);
77
78 /* if ret is 1 then we just hit the end of the extent array */
79 if (ret == 1)
80  ret = 0;
82 return ret;
83}
第8行为请求的标志fiemap进行核对。0表示成功,其它为失败。
第11行使用logical_to_blk得到开始的块地址。
第13行使用min_t宏来返回,最后两个参数的最小值
第14行如果最小值为i_size_read(inode),则whole_file 值设置为1
第17行把最小值赋给映射的长度。
第19-76行尽可能的设置连续块的大小。
第21行初始化缓冲区头部。
第24行get_block函数是使用ext2_get_block来实现其功能
第30行如果缓冲区的映射为假,则长度减去blk_to_logical所返回的大小
第32-74行处理文件中用动。fiemap_fill_next_extent是fiemap帮助功能。
第75行会重新调度。
第82行返回程序。