📄 inode.c
字号:
/* No such thing, so let's try location of indirect block */ /*再查找间接块*/ if (ind->bh) return ind->bh->b_blocknr;/*返回目录块本身*/ /* * It is going to be refered from inode itself? OK, just put it into * the same cylinder group then. */ /*返回该inode所在块组的第一个块*/ return (inode->u.ext2_i.i_block_group * EXT2_BLOCKS_PER_GROUP(inode->i_sb)) + le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_first_data_block);}/** * ext2_find_goal - find a prefered place for allocation. * @inode: owner * @block: block we want * @chain: chain of indirect blocks * @partial: pointer to the last triple within a chain * @goal: place to store the result. * * Normally this function find the prefered place for block allocation, * stores it in *@goal and returns zero. If the branch had been changed * under us we return -EAGAIN. *//*寻找一个合适的块进行分配*//*先按顺序试图分配下一个连续的物理块号, *如果失败就调用ext2_find_near()函数从附近找一个物理块号。 *查找规则是:先看当前位置的前面附近是否有合适块, *再看指针是否在间接块号中, *最后,如果指针在节点上,就分配用一柱面的块 */static inline int ext2_find_goal(struct inode *inode,/*文件节点*/ long block,/*需分配的逻辑块号*/ Indirect chain[4],/*间接块的链表*/ Indirect *partial,/*指向chain中最后的三次间接块*/ unsigned long *goal)/*存放找到的物理块号*/{ /* Writer: ->i_next_alloc* */ /*如果逻辑块号正好是按顺序中的下一块号 *即当要分配的文件块号恰好为前次分配操作的后继文件块号, *预示着使用预分配块的可能性 */ if (block == inode->u.ext2_i.i_next_alloc_block + 1) { inode->u.ext2_i.i_next_alloc_block++; inode->u.ext2_i.i_next_alloc_goal++; } /* Writer: end */ /* Reader: pointers, ->i_next_alloc* */ if (verify_chain(chain, partial)) {/*检验iblock的索引路径有没有发生变化*/ /* * try the heuristic for sequential allocation, * failing that at least try to get decent locality. */ /*得到顺序中的下一个物理块号*/ if (block == inode->u.ext2_i.i_next_alloc_block) *goal = inode->u.ext2_i.i_next_alloc_goal;/*使用原分配点的下一块*/ /*得到附近的物理块号*/ if (!*goal) *goal = ext2_find_near(inode, partial);/*在当前目录块上寻找文件的边缘区域*/ return 0; } /* Reader: end */ return -EAGAIN;}/** * ext2_alloc_branch - allocate and set up a chain of blocks. * @inode: owner * @num: depth of the chain (number of blocks to allocate) * @offsets: offsets (in the blocks) to store the pointers to next. * @branch: place to store the chain in. * * This function allocates @num blocks, zeroes out all but the last one, * links them into chain and (if we are synchronous) writes them to disk. * In other words, it prepares a branch that can be spliced onto the * inode. It stores the information about that chain in the branch[], in * the same format as ext2_get_branch() would do. We are calling it after * we had read the existing part of chain and partial points to the last * triple of that (one with zero ->key). Upon the exit we have the same * picture as after the successful ext2_get_block(), excpet that in one * place chain is disconnected - *branch->p is still zero (we did not * set the last link), but branch->key contains the number that should * be placed into *branch->p to fill that gap. * * If allocation fails we free all blocks we've allocated (and forget * their buffer_heads) and return the error value the from failed * ext2_alloc_block() (normally -ENOSPC). Otherwise we set the chain * as described above and return 0. *//*分配并建立一个块链表*/static int ext2_alloc_branch(struct inode *inode,/*需分配块的节点*/ int num,/*间接块的深度,例如:二次间接,num=1*/ unsigned long goal, int *offsets,/*数组offset[num]*/ Indirect *branch)/*储存链表的地方*/{ int blocksize = inode->i_sb->s_blocksize; int n = 0; int err; int i; int parent = ext2_alloc_block(inode, goal, &err);/*分配块*/ branch[0].key = cpu_to_le32(parent);/*分配一块作为iblock在branch[0]上所指的下一块*/ if (parent) for (n = 1; n < num; n++) { struct buffer_head *bh; /* Allocate the next block */ /*分配下一个块,作为iblock在parent所指的下一块, *可能是目录块,也可能是数据块 */ int nr = ext2_alloc_block(inode, parent, &err);/*分配块*/ if (!nr) break; branch[n].key = cpu_to_le32(nr); /* * Get buffer_head for parent block, zero it out and set * the pointer to new one, then send parent to disk. */ bh = sb_getblk(inode->i_sb, parent); /*得到父块的buffer_head结构*/ lock_buffer(bh);/*给缓冲区上锁*/ memset(bh->b_data, 0, blocksize);/*将buffer设置为0*/ branch[n].bh = bh; branch[n].p = (u32*) bh->b_data + offsets[n]; *branch[n].p = branch[n].key;/*初始化iblock在parent块中的索引*/ mark_buffer_uptodate(bh, 1);/*把buffer标志为更新*/ unlock_buffer(bh);/*给缓冲区解锁*/ mark_buffer_dirty_inode(bh, inode);/*将节点与buffer标志为脏*/ if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) { ll_rw_block (WRITE, 1, &bh);/*将bh写入块设备*/ wait_on_buffer (bh);/*在等待队列上等待buffer写入设备*/ } parent = nr; } if (n == num) return 0;/*循环自然结束*/ /* Allocation failed, free what we already allocated */ /*分配失败时,释放已被分配的块*/ 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;}/** * ext2_splice_branch - splice the allocated branch onto inode. * @inode: owner * @block: (logical) number of block we are adding * @chain: chain of indirect blocks (with a missing link - see * ext2_alloc_branch) * @where: location of missing link * @num: number of blocks we are adding * * This function verifies that chain (up to the missing link) had not * changed, fills the missing link and does all housekeeping needed in * inode (->i_blocks, etc.). In case of success we end up with the full * chain to new block and return 0. Otherwise (== chain had been changed) * we free the new blocks (forgetting their buffer_heads, indeed) and * return -EAGAIN. *//*接合块链表*/static inline int ext2_splice_branch(struct inode *inode, long block, Indirect chain[4], Indirect *where, int num){ int i; /* Verify that place we are splicing to is still there and vacant */ /*检验要结合的是否还在并是空闲的*/ /* Writer: pointers, ->i_next_alloc* */ if (!verify_chain(chain, where-1) || *where->p)/*检验iblock的索引路径有没有发生变化*/ /* Writer: end */ goto changed; /* That's it */ *where->p = where->key; inode->u.ext2_i.i_next_alloc_block = block; inode->u.ext2_i.i_next_alloc_goal = le32_to_cpu(where[num-1].key); /*该逻辑块所对应的物理块,作为下一次分配的目的块*/ /* Writer: end */ /* We are done with atomic stuff, now do the rest of housekeeping */ inode->i_ctime = CURRENT_TIME;/*节点的修改时间置为当前时间*/ /* had we spliced it onto indirect block? */ if (where->bh) { mark_buffer_dirty_inode(where->bh, inode); if (IS_SYNC(inode) || inode->u.ext2_i.i_osync) { ll_rw_block (WRITE, 1, &where->bh);/*将bh写入块设备*/ wait_on_buffer(where->bh);/*在等待队列上等待buffer写入设备*/ } } if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)/*inode标志需要同步*/ ext2_sync_inode (inode);/*把节点缓存中数据写入设备*/ else mark_inode_dirty(inode);/*标志inode为脏*/ return 0;changed: 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;}/* * Allocation strategy is simple: if we have to allocate something, we will * have to go the whole way to leaf. So let's do it before attaching anything * to tree, set linkage between the newborn blocks, write them if sync is * required, recheck the path, free and repeat if check fails, otherwise * set the last missing link (that will protect us from any truncate-generated * removals - all blocks on the path are immune now) and possibly force the * write on the parent block. * That has a nice additional property: no special recovery from the failed * allocations is needed - we simply release blocks and do not touch anything * reachable from inode. *//*从逻辑块序号得到对应的物理块, *如果对应物理块被删除,则重新分配,并得到它间接块路径 */ /*这种转换关系是由ext2_inode结构中i_block[]数组描述的。 *i_block[]的前12项为直接块索引表,第13项为间接索引块指针, *第14项为二重索引块指针,第15项为三重索引块指针。 *当文件长度不超过12个块时,可通过直接块索引表直接定位目标块, *当文件长度超过12块并且剩余的部分不超过间接索引块索引数量时, *就在间接索引块中定位目标块,依次类推 */static int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create){ int err = -EIO; int offsets[4];/*描述最多4级的目录项索引*/ Indirect chain[4];/*描述最多4级的索引目录项*/ Indirect *partial; unsigned long goal; int left; /*将文件系统的逻辑块号iblock分解成对索引块的索引路径 *即offset[0]->offset[1]->offset[2]->offset[3] *depth为1表示立即索引,2表示间接索引, *3表示二重索引,4表示三重索引 *offsets[]为iblock在各级索引块上的索引号,depth最大为4, *则offsets[0]指向三重目录块, *offsets[1]为其索引,其值指向二重目录块, *offsets[2]为其索引,其值指向一重目录块, *offsets[3]为其索引,其值指向最终iblock所对应的目的块 */ int depth = ext2_block_to_path(inode, iblock, offsets);/*以逻辑块号为索引查找物理块*/ if (depth == 0) goto out; lock_kernel();/*给内核上锁*/reread: partial = ext2_get_branch(inode, depth, offsets, chain, &err); /*沿着索引路径读取末一个索引块*/ /*加载iblock的各级目录块, *chain[]描述iblock在各级目录块上的索引项和索引值 *chain[0]描述iblock在直接索引目录上的索引项和索引值 *chain[1]描述iblock在间接目录块上的索引项和索引值,依次类推 */ /* Simplest case - block found, no allocation needed */ /*如果iblock对应的物理块存在,当发现block并读取数据正常时*/ if (!partial) {got_it: bh_result->b_dev = inode->i_dev; bh_result->b_blocknr = le32_to_cpu(chain[depth-1].key); bh_result->b_state |= (1UL << BH_Mapped); /* Clean up and exit */ partial = chain+depth-1; /* the whole chain *//* 使partial指向chain[]的未端*/ goto cleanup; } /* Next simple case - plain lookup or failed read of indirect block */ /*清除partial中多余的空间*/ if (!create || err == -EIO) {cleanup: while (partial > chain) { brelse(partial->bh);/*释放各级目录块*/ partial--; } unlock_kernel();/*给内核解锁*/out: return err; } /* * Indirect block might be removed by truncate while we were * reading it. Handling of that case (forget what we've got and * reread) is taken out of the main path. */ /*当正在读取间接块时,间接块可能被truncate命令删除掉, *处理这种情况时必须重新得到间接块路径, *通过重分配块等,然后再去重读取它 */ if (err == -EAGAIN) goto changed; /*如果iblock对应的物理块不存在, *这时partial指向iblock对应的某一级目录项,该目录项的索引值为空 *这时需要为这个空目录项分配一个块 */ if (ext2_find_goal(inode, iblock, chain, partial, &goal) < 0) goto changed; /*寻找一个合适的分配点, *使新分配的块与inode所在的物理块区域尽可能接近 */ left = (chain + depth) - partial;/*需要新建目录块的数目*/ err = ext2_alloc_branch(inode, left, goal, offsets+(partial-chain), partial);/*分配并建立一个块链表*/ /*完成中断的索引路径*/ if (err) goto cleanup; if (ext2_splice_branch(inode, iblock, chain, partial, left) < 0)/*接合块链表*/ goto changed; bh_result->b_state |= (1UL << BH_New); goto got_it;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -