ext2文件系统源代码之inode.c
今天,我们来看ext2文件系统源代码里边最大的一个文件inode.c。
在讲这个文件之前,我需要仙鹤大家说一个概念,就是间接块的概念,ext2文件系统在块大小为4096的时候可以支持的最大文件大小是4T大小,而ext2_inode结构体,就是ext2文件系统的inode在硬盘上的存储格式,__le32 i_block[EXT2_N_BLOCKS];EXT2_N_BLOCKS是15,如果每一个指针指向一个块,顶多也就是15*4K就是60K字节,这是肯定不够的,ext2是怎么实现的呢?ext2有一个间接块的概念,在15个指针里有0-11是直接指针,12是一级间接指针,13是二级间接指针,14是三级间接指针。直接指针就是一个指针指向的block就是文件的内容,就是一个指针指向4K的块。一级间接指针就是这个指针指向一个block,这个block内的不是文件的内容,而是4096/4=1024个指针,每一个指针指向一个block,这个block内就是文件的内容。二级间接块就是指针指向的block内部是指针,每一个指针指向一个block,这个block内部是1024个指针,每一个指针指向一个block,这个block内的数据就是文件的内容,三级间接块大家应该就明白了。
所以,直接寻址指针大小是1*4K=4K,一级间接寻址指针是(4096/4)*4K=4M,二级间接指针是(4096/4)*(4096/4)*4K=4G,所以三级间接指针就是4T,大家应该明白了吧。
这个文件有1300+行,看起来真的很费力,但是万丈高楼平地起,不去想多么困难,直接开始吧!
/* 作者信息* linux/fs/ext2/inode.c* 又是这个大神,我记住了,Remy Card,如果将来有机会,我一定要去拜访下这个人* Copyright (C) 1992, 1993, 1994, 1995* Remy Card (card@masi.ibp.fr)* Laboratoire MASI - Institut Blaise Pascal* Universite Pierre et Marie Curie (Paris VI)** from** linux/fs/minix/inode.c** Copyright (C) 1991, 1992 Linus Torvalds** Goal-directed block allocation by Stephen Tweedie* (sct@dcs.ed.ac.uk), 1993, 1998* Big-endian to little-endian byte-swapping/bitmaps by* David S. Miller (davem@caip.rutgers.edu), 1995* 64-bit file support on 64-bit platforms by Jakub Jelinek* (jj@sunsite.ms.mff.cuni.cz)** Assorted race fixes, rewrite of ext2_get_block() by Al Viro, 2000*/#include <linux/smp_lock.h>
#include <linux/time.h>
#include <linux/highuid.h>
#include <linux/pagemap.h>
#include <linux/quotaops.h>
#include <linux/module.h>
#include <linux/writeback.h>
#include <linux/buffer_head.h>
#include <linux/mpage.h>
#include "ext2.h"
#include "acl.h"
#include "xip.h"MODULE_AUTHOR("Remy Card and others");
MODULE_DESCRIPTION("Second Extended Filesystem");
MODULE_LICENSE("GPL");static int ext2_update_inode(struct inode * inode, int do_sync);/*检测一个inode是不是一个快速符号链接,快速符号链接是一个ext2文件系统的特性,要求符号链接指向的文件名是一个短的路径名,小于等于60字节,就把它的路径名放在一个inode里,而不用通过一个数据块来进行转换*/
static inline int ext2_inode_is_fast_symlink(struct inode *inode)
{/*先获得inode对应的内存的信息结构体ext2_inode_info,看看有没有acl控制*/int ea_blocks = EXT2_I(inode)->i_file_acl ?/*s_blocksize是文件的块大小,右移9位就是占有的磁道数目*/(inode->i_sb->s_blocksize >> 9) : 0;/*判断i_mode,还要求这个符号链接不占用一个块*/return (S_ISLNK(inode->i_mode) &&inode->i_blocks - ea_blocks == 0);
}/*在iput()的时候调用,inode可能是坏的,所以我们需要检查*/
void ext2_put_inode(struct inode *inode)
{/*只要不是坏的,释放掉inode申请的预分配块空间*/if (!is_bad_inode(inode))ext2_discard_prealloc(inode);
}/*在最后一个iput()的时候调用,当引用计数为0的时候*/
void ext2_delete_inode (struct inode * inode)
{/*内存管理系统的函数,把inode对应的页删除掉*/truncate_inode_pages(&inode->i_data, 0);/*如果坏页,就跳转到no_delete*/if (is_bad_inode(inode))goto no_delete;/*删除时间登记*/EXT2_I(inode)->i_dtime = get_seconds();/*只要修改,就标记脏*/mark_inode_dirty(inode);/*更新*/ext2_update_inode(inode, inode_needs_sync(inode));/*删除后大小为0*/inode->i_size = 0;/*如果占有块*/if (inode->i_blocks)/*释放那些块*/ext2_truncate (inode);/*释放inode,之前讲过的*/ext2_free_inode (inode);return;
no_delete:/*清理inode*/clear_inode(inode);
}
/*把预分配的块都释放掉*/
void ext2_discard_prealloc (struct inode * inode)
{
/*如果配置了EXT2_PREALLOCATE才会有预分配*/
#ifdef EXT2_PREALLOCATE/*ext2_inode_info结构体记录了预分配的信息*/struct ext2_inode_info *ei = EXT2_I(inode);/*对于ext2_inode_info的书写要上写锁*/write_lock(&ei->i_meta_lock);/*如果有预分配菜释放,没有就不释放了*/if (ei->i_prealloc_count) {/*预分配的块数目*/unsigned short total = ei->i_prealloc_count;/*预分配的开始块号*/unsigned long block = ei->i_prealloc_block;/*修改为0,,标记没有预分配块啦*/ei->i_prealloc_count = 0;ei->i_prealloc_block = 0;write_unlock(&ei->i_meta_lock);/*之前讲过的函数,释放预分配的从block开始一共total个块*/ext2_free_blocks (inode, block, total);return;} elsewrite_unlock(&ei->i_meta_lock);
#endif
}
/*ext2为一个数据块分配空间,goal是期望预分配的块号*/
static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
{
#ifdef EXT2FS_DEBUGstatic unsigned long alloc_hits, alloc_attempts;
#endifunsigned long result;/*如果配置了预分配宏*/
#ifdef EXT2_PREALLOCATE/*先获得要分配块的文件的inode的内存里的结构体ext2_inode_info*/struct ext2_inode_info *ei = EXT2_I(inode);/*对ext2_inode_info结构体书写之前必须上锁*/write_lock(&ei->i_meta_lock);/*如果之前已经预分配了块,并且还没用完,并且传入的参数goal就是预分配的块号或者之前的块号*/if (ei->i_prealloc_count &&(goal == ei->i_prealloc_block || goal + 1 == ei->i_prealloc_block)){/*result就是要返回的块号,然后ext2_inode_info结构体指示的i_prealloc_block字段,也就是预分配的块的第一块的块号要加一,i_prealloc_count字段,也就是可用的块数减一*/result = ei->i_prealloc_block++;ei->i_prealloc_count--;/*写完以后要解锁*/write_unlock(&ei->i_meta_lock);ext2_debug ("preallocation hit (%lu/%lu).\n",++alloc_hits, ++alloc_attempts);} else {/*运行到这里说明预分配块已经不足了或者是和goal参数期望的不一致,我们就按用户期望的来分配*/write_unlock(&ei->i_meta_lock);/*既然用户不想使用预分配的块,我们就把预分配的块全部释放掉*/ext2_discard_prealloc (inode);ext2_debug ("preallocation miss (%lu/%lu).\n",alloc_hits, ++alloc_attempts);/*如果这是一个普通文件的话,在用户的goal参数附近预分配块*/if (S_ISREG(inode->i_mode))result = ext2_new_block (inode, goal, &ei->i_prealloc_count,&ei->i_prealloc_block, err);else/*ext2的策略,其他的文件不用预分配,否则,就在goal处分配一个块*/result = ext2_new_block(inode, goal, NULL, NULL, err);}
#else/*如果没有定义预分配宏,直接在goal处分配一个块*/result = ext2_new_block (inode, goal, 0, 0, err);
#endif/*最后返回得到的块号*/return result;
}
/*间接指向的结构体,用于ext2的间接块的实现*/
typedef struct {/*指针,对应映射表中对应下标处的指针*/__le32 *p;/*指针的值,对应就是物理块号,如果为0就说明还没有映射下一个块*/__le32 key;/*当前间接块的内存缓冲,如果是直接映射,这个指针是NULL*/struct buffer_head *bh;
} Indirect;
/*增加链接,把间接指针指向这个内存缓冲区,v就是15个指针之一的指针的值*/
static inline void add_chain(Indirect *p, struct buffer_head *bh, __le32 *v)
{p->key = *(p->p = v);p->bh = bh;
}
/*给定两个indirect结构体,检查这两个结构体是不是构成一条有效的映射链,每从设备上读入一个块的时候都要进行检查,因为读入是费时间的操作,可能已经有块的内容被改变了,可能会有其他的程序吧这个文件的后边的块删除掉,每一项都是检查映射表里的内容是不是更改了*/
static inline int verify_chain(Indirect *from, Indirect *to)
{/*从from开始,只要from->key == *from->p,就是对的,对的就下一位*/while (from <= to && from->key == *from->p)from++;/*检查结束,如果from > to,说明都正确,返回非零值*/return (from > to);
}/**ext2文件系统的根据文件的一个数据块号返回这个数据块在ext2内的存储地址,因为ext2的数据块存储是12个直接指针加上三个间接指针的,所以需要一个长度为4的数组作为返回值。inode是我们要查的block所在的文件,i_block是文件内的逻辑块号,offsets是长度为四的数组,返回值是路径的长度,如果这个block在直接块指向的块上,返回长度就是0,数组后三个值就没有意义,数组的第一个值就是块所在的直接指针的偏移值加一。如果这个block在二级指针指向的间接块上,那么返回值就是2,offset[2]就是指向第三层数据块的偏移。如果要寻找的block后边是一个间接块的话,就把设为非零值*/
static int ext2_block_to_path(struct inode *inode,long i_block, int offsets[4], int *boundary)
{/*每一个块可以存放的指针的数目*/int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);/*每一个块可以存放的指针的数目的二进制位数目*/int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);/*direct_blocks是直接块的数目*/const long direct_blocks = EXT2_NDIR_BLOCKS,/*一级间接块指针可以指向的块的数目*/indirect_blocks = ptrs,/*二级间接块指针可以指向的block的数目*/double_blocks = (1 << (ptrs_bits * 2));int n = 0;int final = 0;/*如果块号小于0,这肯定是有问题的*/if (i_block < 0) {ext2_warning (inode->i_sb, "ext2_block_to_path", "block < 0");/*如果块号码小于直接指针的数目12,就说明这个数据块在直接指针指向的块里边*/} else if (i_block < direct_blocks) {/*offset[0]就是对应的偏移,12个直接指针的第i_block个就指向我们得到的这个数据块,final指向对应的最后一个块号*/offsets[n++] = i_block;final = direct_blocks;/*如果块号大于12但是小于一级间接块可以指向的块的数目1024,就说明这个块在一级指针指向的数据块里*/} else if ( (i_block -= direct_blocks) < indirect_blocks) {/*offset[0]就是第一个进入的指针,就是一级间接指针*/offsets[n++] = EXT2_IND_BLOCK;/*offset[1]就是第二个进入的指针,就是减去之前的额2个直接指针的i_block*/offsets[n++] = i_block;/*final就是所在的间接块内最后一块*/final = ptrs;/*如果i_block大于一级间接块指向的块数目,小于二级间接块指向的块数目,说明在二级间接指针指向的块里边*/} else if ((i_block -= indirect_blocks) < double_blocks) {/*第一个进入的指针,二级间接指针*/offsets[n++] = EXT2_DIND_BLOCK;/*路径中第二个进入的指针,右移12位就是二级间接指针指向的block里的对应的间接指针的排名*/offsets[n++] = i_block >> ptrs_bits;/*第三个要进入的路径指针,最后的块内的偏移排名*/offsets[n++] = i_block & (ptrs - 1);/*块内有1024个,最后一个就是1024*/final = ptrs;/*如果块号大于二级指针指向的块的数目,小于三级指针指向的块的数目*/} else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {/*第一个要进入的指针,三级指针*/offsets[n++] = EXT2_TIND_BLOCK;/*三级指针指向的块内排名*/offsets[n++] = i_block >> (ptrs_bits * 2);/*三级指针指向的块内指针的下一个块内排名*/offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);/*最后的指向的块内排名*/offsets[n++] = i_block & (ptrs - 1);/*块内有1024个,最后一个就是1024*/final = ptrs;} else {ext2_warning (inode->i_sb, "ext2_block_to_path", "block > big");}/*如果要寻找的块是在块内的最后一个指针指向的,*boundary的值就是1*/if (boundary)*boundary = (i_block & (ptrs - 1)) == (final - 1);return n;
}/** ext2_get_branch函数,根据传入的路径偏移值获得对应的chain结构体指向对应块的数据,offset是传入的参数,offset内是每一级的在块内的偏移排名,depth是路径的层数。所以这个得到的映射链就像一棵树上的一个枝干一样,也就是我们这个函数的名字的由来,自此,ext2_get_branch函数和上边的ext2_block_to_path函数完成了从文件内的块号到物理块号的映射*/
static Indirect *ext2_get_branch(struct inode *inode,int depth,int *offsets,Indirect chain[4],int *err)
{/*对应的文件系统超级块*/struct super_block *sb = inode->i_sb;Indirect *p = chain;struct buffer_head *bh;*err = 0;/*使得间接块结构体指向路径的第一级,EXT2_I(inode)获得inode的内存里的信息结构体ext2_inode_info,然后从i_data获得15个指针的值,加上offset就得到了偏移*/add_chain (chain, NULL, EXT2_I(inode)->i_data + *offsets);/*如果key=0,说明这个指针没有指向一个块,说明逻辑块的指针还没有和数据块产生映射关系*/if (!p->key)goto no_block;/*一层一层解决*/while (--depth) {/*驱动层的读写函数读取上一层找到的间接块的数据*/bh = sb_bread(sb, le32_to_cpu(p->key));if (!bh)goto failure;read_lock(&EXT2_I(inode)->i_meta_lock);/*检验建立的这个间接结构体有没有问题*/if (!verify_chain(chain, p))goto changed;/*建立下一层的chain结构体,(__le32*)bh->b_data + *++offsets的意思是,上边得到bh缓冲区是间接块的缓冲区,加上偏移就是下一级的入口*/add_chain(++p, bh, (__le32*)bh->b_data + *++offsets);read_unlock(&EXT2_I(inode)->i_meta_lock);/*如果下一级没有块了*/if (!p->key)goto no_block;}return NULL;changed:/*说明在我们建立chain的时候,这个chain被修改了,再来一遍*/read_unlock(&EXT2_I(inode)->i_meta_lock);brelse(bh);*err = -EAGAIN;goto no_block;
failure:*err = -EIO;
no_block:return p;
}/** 为分配找一个有充足位置的地点,参数ind是希望的返回值是要分配的地点。分配的规则是,首先寻找这个块所在的指针块上面之前的近的块,如果没找到,就去参数ind所在的间接块内找,如果还没有找到,就去inode所在的磁道块组内找一个。*/
static unsigned long ext2_find_near(struct inode *inode, Indirect *ind)
{/*由inode获得内存里的ext2_inode_info结构体*/struct ext2_inode_info *ei = EXT2_I(inode);/*首先把start指向当前所在的映射块的起点*/__le32 *start = ind->bh ? (__le32 *) ind->bh->b_data : ei->i_data;__le32 *p;unsigned long bg_start;unsigned long colour;/* 遍历从start到ind,就是映射断裂的地方,找映射空洞后边的第一个块 */for (p = ind->p - 1; p >= start; p--)if (*p)return le32_to_cpu(*p);/* 没有,就找一个间接块*/if (ind->bh)return ind->bh->b_blocknr;/*去磁道所在的组找一个块,bg_start得到的是文件所在的组开始块号*/bg_start = (ei->i_block_group * EXT2_BLOCKS_PER_GROUP(inode->i_sb)) +le32_to_cpu(EXT2_SB(inode->i_sb)->s_es->s_first_data_block);/*colour是组内的偏移,根据进程用户的pid来随机,是为了防止不同的用户发生冲突*/colour = (current->pid % 16) *(EXT2_BLOCKS_PER_GROUP(inode->i_sb) / 16);return bg_start + colour;
}/** 寻找分配地点,inode是要分配的块所属的inode,block是文件内的逻辑块号,chain是间接块数组,partial是chain的最后一项,goal用来返回建议的块号,成功的话,返回0,失败返回错误码*/
static inline int ext2_find_goal(struct inode *inode,long block,Indirect chain[4],Indirect *partial,unsigned long *goal)
{/*块分配里常用的ext2_inode_info结构体*/struct ext2_inode_info *ei = EXT2_I(inode);write_lock(&ei->i_meta_lock);/*i_next_alloc_block代表这个文件的下一次要分配的的文件内逻辑块号,i_next_alloc_goal是下一次可以分配的物理块号,一般情况下,文件内的逻辑块号是一块一块的顺序分配的*/if ((block == ei->i_next_alloc_block + 1) && ei->i_next_alloc_goal) {ei->i_next_alloc_block++;ei->i_next_alloc_goal++;} /*说明块分配是跳跃的,新的逻辑块号与原先的最后一个逻辑块号之间有空洞*/if (verify_chain(chain, partial)) {/* 要求顺序的下一个块,那就返回希望分配的块*/if (block == ei->i_next_alloc_block)*goal = ei->i_next_alloc_goal;/*如果goal是0,说明用户没有希望分配的点,那我们就自己找一个距离映射链断裂的地方近一点的点*/if (!*goal)*goal = ext2_find_near(inode, partial);write_unlock(&ei->i_meta_lock);return 0;}write_unlock(&ei->i_meta_lock);return -EAGAIN;
}/** 为映射链分配空间,并初始化这个块的地址chain。inode是文件的主人,num是要建立的chain的层数,表示还有几层需要建立,offset是要存放的偏移地址的后一个,branch是要存放的chain的地址,就是之前的映射断裂的地方。这个函数分配num个块,除了最后一个都会初始化为0,然后同步, */
static int ext2_alloc_branch(struct inode *inode,int num,unsigned long goal,int *offsets,Indirect *branch)
{/*块大小*/int blocksize = inode->i_sb->s_blocksize;int n = 0;int err;int i;/*上边刚讲过,在goal附近分配一个块*/int parent = ext2_alloc_block(inode, goal, &err);/*建立开始的第一个的索引key,块号*/branch[0].key = cpu_to_le32(parent);/*逐层建立对应的chain*/if (parent) for (n = 1; n < num; n++) {struct buffer_head *bh;/* 分配下一块 */int nr = ext2_alloc_block(inode, parent, &err);if (!nr)break;/*下一层的块号*/branch[n].key = cpu_to_le32(nr);/*得到父节点的块缓冲区,初始化为0,设置指针指向新的一个把父写入硬盘 */bh = sb_getblk(inode->i_sb, parent);if (!bh) {err = -EIO;break;}/*写缓冲区之前都要锁住*/lock_buffer(bh);/*初始化缓冲区为0*/memset(bh->b_data, 0, blocksize);/*当前路径链的间接块缓冲区,p执行间接块上的offset对应的偏移地址*/branch[n].bh = bh;branch[n].p = (__le32 *) bh->b_data + offsets[n];*branch[n].p = branch[n].key;/*更新缓冲区*/set_buffer_uptodate(bh);unlock_buffer(bh);/*标记为脏*/mark_buffer_dirty_inode(bh, inode);/* 目录的同步*/if (S_ISDIR(inode->i_mode) && IS_DIRSYNC(inode))sync_dirty_buffer(bh);parent = nr;}/*如果分配够了,就返回*/if (n == num)return 0;/* 分配失败,就释放我们之前分配的块,bforget函数是内存管理系统的释放buffer的函数*/for (i = 1; i < n; i++)bforget(branch[i].bh);/*然后释放这间接块所占用的数据块*/for (i = 0; i < n; i++)ext2_free_blocks(inode, le32_to_cpu(branch[i].key), 1);return err;
}/** 粘结分配的分支,inode是属于的文件inode,block是逻辑块号,chain是间接块链,where是迷失的节点位置,num是增加的块数目*/
static inline int ext2_splice_branch(struct inode *inode,long block,Indirect chain[4],Indirect *where,int num)
{struct ext2_inode_info *ei = EXT2_I(inode);int i;/* 检查我们要粘结的位置有没有变*/write_lock(&ei->i_meta_lock);if (!verify_chain(chain, where-1) || *where->p)goto changed;/*就是这里,断的那一点的p指向key,i_next_alloc_block是下一次分配的文件内的逻辑号,i_next_alloc_goal是希望分配的物理块号*/*where->p = where->key;ei->i_next_alloc_block = block;ei->i_next_alloc_goal = le32_to_cpu(where[num-1].key);write_unlock(&ei->i_meta_lock);/*主要工作ok,做一些小工作,修改时间*/inode->i_ctime = CURRENT_TIME_SEC;/* 是间接块?*/if (where->bh)mark_buffer_dirty_inode(where->bh, inode);mark_inode_dirty(inode);return 0;changed:/*释放掉*/write_unlock(&ei->i_meta_lock);for (i = 1; i < num; i++)bforget(where[i].bh);for (i = 0; i < num; i++)ext2_free_blocks(inode, le32_to_cpu(where[i].key), 1);return -EAGAIN;
}/* 根据文件的逻辑块号得到文件的物理块号,iblock是块在文件内的逻辑块号,参数create标识是否需要创建*/
int ext2_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create)
{int err = -EIO;int offsets[4];Indirect chain[4];Indirect *partial;unsigned long goal;int left;int boundary = 0;/*前边讲过的函数,根据文件的inode和文件的文件内块号,得到这个文件的存储地址,返回值是深度,offset是偏移数组*/int depth = ext2_block_to_path(inode, iblock, offsets, &boundary);/*如果返回0,说明错误*/if (depth == 0)goto out;reread:/*根据传入的offset得到对应的chain数组*/partial = ext2_get_branch(inode, depth, offsets, chain, &err);/* 最好的情况,找到了这个块,不需要分配*/if (!partial) {
got_it:/*建立bh_result缓冲区和inode所在文件系统和对应的数据块的映射关系*/map_bh(bh_result, inode->i_sb, le32_to_cpu(chain[depth-1].key));/*如果是边界,设置缓冲区边界*/if (boundary)set_buffer_boundary(bh_result);/* partial指向最后一个,然后清理 */partial = chain+depth-1; goto cleanup;}/* 检查下,如果参数要求不创建块或者是读取失败的话,就直接清理了*/if (!create || err == -EIO) {
cleanup:while (partial > chain) {brelse(partial->bh);partial--;}
out:return err;}/* 运行到这里,说明间接块可能被删除了,如果删除了,就跳转到changed*/if (err == -EAGAIN)goto changed;/*说明映射链断裂了,那就找一个块分配先*/goal = 0;/*寻找一个分配的块号*/if (ext2_find_goal(inode, iblock, chain, partial, &goal) < 0)goto changed;/*left是chain的最后地址距离partial*/left = (chain + depth) - partial;/*从断裂的地方补齐映射链*/err = ext2_alloc_branch(inode, left, goal,offsets+(partial-chain), partial);if (err)goto cleanup;/*判断文件系统是不是使用xip*/if (ext2_use_xip(inode->i_sb)) {/*需要清理块*/err = ext2_clear_xip_target (inode,le32_to_cpu(chain[depth-1].key));if (err)goto cleanup;}/*把刚刚分配的树枝粘结到树上*/if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)goto changed;set_buffer_new(bh_result);goto got_it;/*被修改了,返回错误*/
changed:while (partial > chain) {brelse(partial->bh);partial--;}goto reread;
}
/*地址空间的操作函数,写入一个page*/
static int ext2_writepage(struct page *page, struct writeback_control *wbc)
{return block_write_full_page(page, ext2_get_block, wbc);
}
/*读取一个页到内存*/
static int ext2_readpage(struct file *file, struct page *page)
{return mpage_readpage(page, ext2_get_block);
}
/*读取多个页,参数nr_pages是页数*/
static int
ext2_readpages(struct file *file, struct address_space *mapping,struct list_head *pages, unsigned nr_pages)
{return mpage_readpages(mapping, pages, nr_pages, ext2_get_block);
}
/*写入准备,都是调用文件系统上层的函数*/
static int
ext2_prepare_write(struct file *file, struct page *page,unsigned from, unsigned to)
{return block_prepare_write(page,from,to,ext2_get_block);
}
/*无缓冲区的写入准备*/
static int
ext2_nobh_prepare_write(struct file *file, struct page *page,unsigned from, unsigned to)
{return nobh_prepare_write(page,from,to,ext2_get_block);
}
/*无缓冲区模式的写入页*/
static int ext2_nobh_writepage(struct page *page,struct writeback_control *wbc)
{return nobh_writepage(page, ext2_get_block, wbc);
}
/*ext2的块的映射*/
static sector_t ext2_bmap(struct address_space *mapping, sector_t block)
{return generic_block_bmap(mapping,block,ext2_get_block);
}
/*块设备直接IO操作*/
static ssize_t
ext2_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,loff_t offset, unsigned long nr_segs)
{struct file *file = iocb->ki_filp;struct inode *inode = file->f_mapping->host;return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,offset, nr_segs, ext2_get_block, NULL);
}
/*写入page*/
static int
ext2_writepages(struct address_space *mapping, struct writeback_control *wbc)
{return mpage_writepages(mapping, wbc, ext2_get_block);
}
/*地址空间操作函数*/
const struct address_space_operations ext2_aops = {.readpage = ext2_readpage,.readpages = ext2_readpages,.writepage = ext2_writepage,.sync_page = block_sync_page,.prepare_write = ext2_prepare_write,.commit_write = generic_commit_write,.bmap = ext2_bmap,.direct_IO = ext2_direct_IO,.writepages = ext2_writepages,.migratepage = buffer_migrate_page,
};
/*片内执行的ext2文件系统对应的地址空间操作函数集合*/
const struct address_space_operations ext2_aops_xip = {.bmap = ext2_bmap,.get_xip_page = ext2_get_xip_page,
};
/*没有缓冲区的地址空间集合*/
const struct address_space_operations ext2_nobh_aops = {.readpage = ext2_readpage,.readpages = ext2_readpages,.writepage = ext2_nobh_writepage,.sync_page = block_sync_page,.prepare_write = ext2_nobh_prepare_write,.commit_write = nobh_commit_write,.bmap = ext2_bmap,.direct_IO = ext2_direct_IO,.writepages = ext2_writepages,.migratepage = buffer_migrate_page,
};/* 寻找第一个非零值,在p到q之间,如果都是0,返回1*/
static inline int all_zeroes(__le32 *p, __le32 *q)
{while (p < q)if (*p++)return 0;return 1;
}/** 为局部阶段寻找一个间接块,inode是文件的inode,depth是要截断chain的深度,offsets是偏移数组,chain用来存放指向局部间接块的指针*/
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;/*partial还没有映射*/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--);/* 找到了要删除的点 ,如果p就是要删除的点,p指针指向之前的块*/if (p == chain + k - 1 && p > chain) {p->p--;} else {/*top返回枝干的头部*/*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;
}/** 释放一连串的数据块,inode数所属的文件,p是数据块的数组,q指向结尾*/
static inline void ext2_free_data(struct inode *inode, __le32 *p, __le32 *q)
{unsigned long block_to_free = 0, count = 0;unsigned long nr;/*从p到q*/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 {mark_inode_dirty(inode);ext2_free_blocks (inode, block_to_free, count);/*先标记下来*/free_this:block_to_free = nr;count = 1;}}}/*收尾*/if (count > 0) {mark_inode_dirty(inode);ext2_free_blocks (inode, block_to_free, count);}
}/** 递归函数,逐层释放,释放一组映射链上的枝干,p是块的数组,q是数组结尾,depth是释放的枝干的深度 */
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);/*遍历p到q*/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);
}
/*从映射树上截断*/
void ext2_truncate (struct inode * inode)
{/*映射指针所在的额数组*/__le32 *i_data = EXT2_I(inode)->i_data;/*没块存放的指针数目*/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;/*目录或者链接文件不支持截断*/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;/*只能后续加入和不可修改的文件不可以*/if (IS_APPEND(inode) || IS_IMMUTABLE(inode))return;/*把预分配的都释放掉吧*/ext2_discard_prealloc(inode);/*块大小*/blocksize = inode->i_sb->s_blocksize;/*iblock是截断的位置*/iblock = (inode->i_size + blocksize-1)>> EXT2_BLOCK_SIZE_BITS(inode->i_sb);/*根据映射方式,选择页截断*/if (mapping_is_xip(inode->i_mapping))xip_truncate_page(inode->i_mapping, inode->i_size);else if (test_opt(inode->i_sb, NOBH))nobh_truncate_page(inode->i_mapping, inode->i_size);elseblock_truncate_page(inode->i_mapping,inode->i_size, ext2_get_block);/*获得iblock对应的树叶到树根的路径*/n = ext2_block_to_path(inode, iblock, offsets, NULL);if (n == 0)return;/*如果从直接映射块开始截断,先释放第一层后边的叶子块,然后在释放后边的间接块*/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);elsemark_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);}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);}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);}case EXT2_TIND_BLOCK:/*三级间接块*/;}/*记录修改时间*/inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;/*更新*/if (inode_needs_sync(inode)) {sync_mapping_buffers(inode->i_mapping);ext2_sync_inode (inode);} else {mark_inode_dirty(inode);}
}
/*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, &bh);if (!gdp)goto Egdp;/*搞明白我们想要的inode在组内的inodetable上的所在块内偏移,*/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的flag标志,因为ext2_inode_info和inode结构体上的标志虽然意义一样,但是韦德位置不一样,所以要转化一下*/
void ext2_set_inode_flags(struct inode *inode)
{/*先获得ext2_inode_info上的flag*/unsigned int flags = EXT2_I(inode)->i_flags;/*转化成inode上的*/inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC);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;
}/* 和上边的函数正好相反,这个函数把inode结构体的flag转化成ext2_inode_info结构体上的*/
void ext2_get_inode_flags(struct ext2_inode_info *ei)
{/*获得inode结构体的flag*/unsigned int flags = ei->vfs_inode.i_flags;/*转化*/ei->i_flags &= ~(EXT2_SYNC_FL|EXT2_APPEND_FL|EXT2_IMMUTABLE_FL|EXT2_NOATIME_FL|EXT2_DIRSYNC_FL);if (flags & S_SYNC)ei->i_flags |= EXT2_SYNC_FL;if (flags & S_APPEND)ei->i_flags |= EXT2_APPEND_FL;if (flags & S_IMMUTABLE)ei->i_flags |= EXT2_IMMUTABLE_FL;if (flags & S_NOATIME)ei->i_flags |= EXT2_NOATIME_FL;if (flags & S_DIRSYNC)ei->i_flags |= EXT2_DIRSYNC_FL;
}
/*阅读inode的内容,参数是想要的inode*/
void ext2_read_inode (struct inode * inode)
{struct ext2_inode_info *ei = EXT2_I(inode);ino_t ino = inode->i_ino;struct buffer_head * bh;/*从硬盘上获得ext2_inode结构体*/struct ext2_inode * raw_inode = ext2_get_inode(inode->i_sb, ino, &bh);int n;/*配置了acl控制,ext2_inode_info结构体的acl值设置为没有缓存*/
#ifdef CONFIG_EXT2_FS_POSIX_ACLei->i_acl = EXT2_ACL_NOT_CACHED;ei->i_default_acl = EXT2_ACL_NOT_CACHED;
#endif/*如果读取进来的是坏的,直接退出*/if (IS_ERR(raw_inode))goto bad_inode;/*开始从ext2文件系统上存储的ext2_inode读取数据转化成vfs层的inode数据*//*文件打开模式*/inode->i_mode = le16_to_cpu(raw_inode->i_mode);/*文件的uid和gid*/inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low);inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low);/*如果没有NO_UID32位*/if (!(test_opt (inode->i_sb, NO_UID32))) {inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16;inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16;}/*引用计数,文件大小*/inode->i_nlink = 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);/* 如果引用计数为0,,并且mode为0,说明文件已经被删除了 */if (inode->i_nlink == 0 && (inode->i_mode == 0 || ei->i_dtime)) {brelse (bh);goto bad_inode;}/*inode文件的块数目*/inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);/*flag标志等字段的读取*/ei->i_flags = le32_to_cpu(raw_inode->i_flags);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 (S_ISREG(inode->i_mode))inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32;elseei->i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);/*读取和运行时赋值的字段,先赋为0*/ei->i_dtime = 0;inode->i_generation = le32_to_cpu(raw_inode->i_generation);ei->i_state = 0;ei->i_next_alloc_block = 0;ei->i_next_alloc_goal = 0;ei->i_prealloc_count = 0;ei->i_block_group = (ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb);ei->i_dir_start_lookup = 0;/* 复制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)) {inode->i_op = &ext2_file_inode_operations;if (ext2_use_xip(inode->i_sb)) {inode->i_mapping->a_ops = &ext2_aops_xip;inode->i_fop = &ext2_xip_file_operations;} else if (test_opt(inode->i_sb, NOBH)) {inode->i_mapping->a_ops = &ext2_nobh_aops;inode->i_fop = &ext2_file_operations;} else {inode->i_mapping->a_ops = &ext2_aops;inode->i_fop = &ext2_file_operations;}} 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;elseinode->i_mapping->a_ops = &ext2_aops;} else if (S_ISLNK(inode->i_mode)) {/*链接文件*/if (ext2_inode_is_fast_symlink(inode))inode->i_op = &ext2_fast_symlink_inode_operations;else {inode->i_op = &ext2_symlink_inode_operations;if (test_opt(inode->i_sb, NOBH))inode->i_mapping->a_ops = &ext2_nobh_aops;elseinode->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);ext2_set_inode_flags(inode);return;bad_inode:/*标记这个inode是坏的*/make_bad_inode(inode);return;
}
/*同步inode数据,把inode的数据写入到硬盘里*/
static int ext2_update_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 = inode->i_uid;gid_t gid = inode->i_gid;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;/* 如果这个inode是新的,全部设置为0 */if (ei->i_state & EXT2_STATE_NEW)memset(raw_inode, 0, EXT2_SB(sb)->s_inode_size);/*转化ext2_inode_info的flag到inode上边*/ext2_get_inode_flags(ei);/*开始用inode的数据填充raw_inode*//*文件打开模式*/raw_inode->i_mode = cpu_to_le16(inode->i_mode);/*uid和gid*/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));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;/*文件的acl控制*/raw_inode->i_file_acl = cpu_to_le32(ei->i_file_acl);/*如果不是普通文件*/if (!S_ISREG(inode->i_mode))/*赋值目录的acl控制*/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)) {/* If this is the first large file* created, add a flag to the superblock.*/lock_kernel();ext2_update_dynamic_rev(sb);EXT2_SET_RO_COMPAT_FEATURE(sb,EXT2_FEATURE_RO_COMPAT_LARGE_FILE);unlock_kernel();ext2_write_super(sb);}}}/*文件系统版本*/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, int wait)
{return ext2_update_inode(inode, wait);
}
/*同步inode,调用fs层的函数,同步inode*/
int ext2_sync_inode(struct inode *inode)
{struct writeback_control wbc = {.sync_mode = WB_SYNC_ALL,.nr_to_write = 0, /* sys_fsync did this */};return sync_inode(inode, &wbc);
}
/*设置文件属性*/
int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
{struct inode *inode = dentry->d_inode;int error;/*检查文件属性有没有错误*/error = inode_change_ok(inode, iattr);if (error)return error;/*合法且uid和gid一样才可以设置*/if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) ||(iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) {error = DQUOT_TRANSFER(inode, iattr) ? -EDQUOT : 0;if (error)return error;}/*调用inode_setattr来设置属性*/error = inode_setattr(inode, iattr);/*定义了ATTR_MODE位,就改变acl*/if (!error && (iattr->ia_valid & ATTR_MODE))error = ext2_acl_chmod(inode);return error;
}
ext2文件系统源代码之inode.c相关推荐
- ext2文件系统源代码之dir.c
今天我们来看ext2源代码的dir.c文件,这个文件是做和目录有关的操作的,也是很重要的一个文件,大家认真看哦,有什么和我不一致的大家一起探讨~~ 在讲这个之前我觉得还是先说下ext2文件系统的目录方 ...
- ext2文件系统源代码之super.c
今天来看一个ext2文件系统里的super.c文件,这个文件的内容是文件系统里的超级块的相关函数,对于文件系统有很大的重要性,并且这个文件也很长,好啦,我们开始看吧. /* 日常作者信息* linux ...
- linux之EXT2文件系统--理解block/block group/索引结点inode/索引位图
0. 文件系统和图书馆 在linux上操作文件,和在图书馆借书是非常相似的. 硬盘上的文件系统,好比图书馆的书架:而vfs则是图书馆的管理系统. 内核的工作: 1. 维护一个文件的目录树(dentry ...
- Linux ext2文件系统小结
本文来源:http://learn.akae.cn/media/ch29s02.html 有修改 1.ext2文件系统整体布局 一个磁盘可以划分成多个分区,每个分区必须先用格式化工具(例如某种mkfs ...
- ext2文件系统了解
一个磁盘可以划分成多个分区,每个分区必须先用格式化工具(例如mkfs命令)格式化成某种格式的文件系统,然后才能存储文件,格式化的过程会在磁盘上写一些管理存储布局的信息.下以ext2文件系统为例说明文件 ...
- Linux 文件系统及 ext2 文件系统
linux 支持的文件系统类型 Ext2: 有点像 UNIX 文件系统.有 blocks,inodes,directories 的概念. Ext3: Ext2 的加强版,添加了日志的功 ...
- ext2文件系统 - mke2fs
上一遍博文的重点其实将ext2整体的组织框架,我们知道了ext2文件系统由块组组成,每个块组里面的组织形式.我们甚至直接把超级块和组描述符里面的内容,用十六进制形式展现了出来.这篇博文主要讲述如何 ...
- linux VFS 虚拟文件系统 简介 super_block inode dentry file
1.简介 1.Linux 中允许众多不同的文件系统共存,如 ext2, ext3, vfat 等.通过使用同一套文件 I/O 系统 调用即可对 Linux 中的任意文件进行操作而无需考虑其所在的具体文 ...
- Linux文件系统基础之inode和dentry
inode和dentry在VFS和实体的文件系统(ext2.ext3等)中都是比较重要的概念.首先看一下虚拟文件系统的标准定义:虚拟文件系统(英语:Virtual file system,缩写为VFS ...
- 转:ext2文件系统详解
第一部分磁盘的物理组成 磁盘的基本概念: 扇区为最小的物理存储单位,每个扇区为512字节. 将扇区组成一个圆,那就是柱面,柱面是分区的最小单位. 第一个扇区很重要,里面有硬盘主引导记录(Masterb ...
最新文章
- mysql报196271错误_超过mysql最大连接的异常
- 完全背包问题(信息学奥数一本通-T1268)
- pythonfilelist_Python 列表list使用介绍
- arcgis 属性表中起点终点创建线_【ArcGIS开发】shapefile矢量数据遍历、求交、与属性更新...
- 如何将Eclipse的javaWeb项目改为IDEA的maven项目
- 小白程序员的成长之路《时间管理大师》
- Docker 开启镜像加速 (网易和阿里)
- SPI通信协议简要介绍
- 公司研制的CPU卡燃气表正式投放北京市场
- 史上最全:Mac搭建Airtest IDE +IOS 测试环境
- 模块一 day09 文件操作相关
- Ubuntu下键盘输入错乱问题,输入自动变为希腊字母和符号
- android 播放器架构,Android播放器框架设计系列-1
- PHP+ajaxfileupload 实现用户头像上传
- SAP中图文展示分摊和分配的区别
- 用手机对电脑进行远程关机
- 《雪盈王》,一本漫画,一个游戏,一场梦……
- 常用国名与首都(英文)
- 使用Matlab提取ADC采样数据中的噪声
- js 字符串去除特殊符号,去重