📄 ext3-extents-2.6.15.patch
字号:
+ if (ext3_ext_check_header(eh))+ goto err;+ }++ path[ppos].p_depth = i;+ path[ppos].p_hdr = eh;+ path[ppos].p_ext = NULL;+ path[ppos].p_idx = NULL;++ if (ext3_ext_check_header(eh))+ goto err;++ /* find extent */+ ext3_ext_binsearch(tree, path + ppos, block);++ ext3_ext_show_path(tree, path);++ return path;++err:+ printk(KERN_ERR "EXT3-fs: header is corrupted!\n");+ if (path) {+ ext3_ext_drop_refs(path);+ kfree(path);+ }+ return ERR_PTR(-EIO);+}++/*+ * insert new index [logical;ptr] into the block at cupr+ * it check where to insert: before curp or after curp+ */+static int ext3_ext_insert_index(handle_t *handle,+ struct ext3_extents_tree *tree,+ struct ext3_ext_path *curp,+ int logical, int ptr)+{+ struct ext3_extent_idx *ix;+ int len, err;++ if ((err = ext3_ext_get_access(handle, tree, curp)))+ return err;++ EXT_ASSERT(logical != curp->p_idx->ei_block);+ len = EXT_MAX_INDEX(curp->p_hdr) - curp->p_idx;+ if (logical > curp->p_idx->ei_block) {+ /* insert after */+ if (curp->p_idx != EXT_LAST_INDEX(curp->p_hdr)) {+ len = (len - 1) * sizeof(struct ext3_extent_idx);+ len = len < 0 ? 0 : len;+ ext_debug(tree, "insert new index %d after: %d. "+ "move %d from 0x%p to 0x%p\n",+ logical, ptr, len,+ (curp->p_idx + 1), (curp->p_idx + 2));+ memmove(curp->p_idx + 2, curp->p_idx + 1, len);+ }+ ix = curp->p_idx + 1;+ } else {+ /* insert before */+ len = len * sizeof(struct ext3_extent_idx);+ len = len < 0 ? 0 : len;+ ext_debug(tree, "insert new index %d before: %d. "+ "move %d from 0x%p to 0x%p\n",+ logical, ptr, len,+ curp->p_idx, (curp->p_idx + 1));+ memmove(curp->p_idx + 1, curp->p_idx, len);+ ix = curp->p_idx;+ }++ ix->ei_block = logical;+ ix->ei_leaf = ptr;+ ix->ei_leaf_hi = ix->ei_unused = 0;+ curp->p_hdr->eh_entries++;++ EXT_ASSERT(curp->p_hdr->eh_entries <= curp->p_hdr->eh_max);+ EXT_ASSERT(ix <= EXT_LAST_INDEX(curp->p_hdr));++ err = ext3_ext_dirty(handle, tree, curp);+ ext3_std_error(tree->inode->i_sb, err);++ return err;+}++/*+ * routine inserts new subtree into the path, using free index entry+ * at depth 'at:+ * - allocates all needed blocks (new leaf and all intermediate index blocks)+ * - makes decision where to split+ * - moves remaining extens and index entries (right to the split point)+ * into the newly allocated blocks+ * - initialize subtree+ */+static int ext3_ext_split(handle_t *handle, struct ext3_extents_tree *tree,+ struct ext3_ext_path *path,+ struct ext3_extent *newext, int at)+{+ struct buffer_head *bh = NULL;+ int depth = EXT_DEPTH(tree);+ struct ext3_extent_header *neh;+ struct ext3_extent_idx *fidx;+ struct ext3_extent *ex;+ int i = at, k, m, a;+ unsigned long newblock, oldblock, border;+ int *ablocks = NULL; /* array of allocated blocks */+ int err = 0;++ /* make decision: where to split? */+ /* FIXME: now desicion is simplest: at current extent */++ /* if current leaf will be splitted, then we should use + * border from split point */+ EXT_ASSERT(path[depth].p_ext <= EXT_MAX_EXTENT(path[depth].p_hdr));+ if (path[depth].p_ext != EXT_MAX_EXTENT(path[depth].p_hdr)) {+ border = path[depth].p_ext[1].ee_block;+ ext_debug(tree, "leaf will be splitted."+ " next leaf starts at %d\n",+ (int)border);+ } else {+ border = newext->ee_block;+ ext_debug(tree, "leaf will be added."+ " next leaf starts at %d\n",+ (int)border);+ }++ /* + * if error occurs, then we break processing+ * and turn filesystem read-only. so, index won't+ * be inserted and tree will be in consistent+ * state. next mount will repair buffers too+ */++ /*+ * get array to track all allocated blocks+ * we need this to handle errors and free blocks+ * upon them+ */+ ablocks = kmalloc(sizeof(unsigned long) * depth, GFP_NOFS);+ if (!ablocks)+ return -ENOMEM;+ memset(ablocks, 0, sizeof(unsigned long) * depth);++ /* allocate all needed blocks */+ ext_debug(tree, "allocate %d blocks for indexes/leaf\n", depth - at);+ for (a = 0; a < depth - at; a++) {+ newblock = ext3_ext_new_block(handle, tree, path, newext, &err);+ if (newblock == 0)+ goto cleanup;+ ablocks[a] = newblock;+ }++ /* initialize new leaf */+ newblock = ablocks[--a];+ EXT_ASSERT(newblock);+ bh = sb_getblk(tree->inode->i_sb, newblock);+ if (!bh) {+ err = -EIO;+ goto cleanup;+ }+ lock_buffer(bh);++ if ((err = ext3_journal_get_create_access(handle, bh)))+ goto cleanup;++ neh = EXT_BLOCK_HDR(bh);+ neh->eh_entries = 0;+ neh->eh_max = ext3_ext_space_block(tree);+ neh->eh_magic = EXT3_EXT_MAGIC;+ neh->eh_depth = 0;+ ex = EXT_FIRST_EXTENT(neh);++ /* move remain of path[depth] to the new leaf */+ EXT_ASSERT(path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max);+ /* start copy from next extent */+ /* TODO: we could do it by single memmove */+ m = 0;+ path[depth].p_ext++;+ while (path[depth].p_ext <=+ EXT_MAX_EXTENT(path[depth].p_hdr)) {+ ext_debug(tree, "move %d:%d:%d in new leaf %lu\n",+ path[depth].p_ext->ee_block,+ path[depth].p_ext->ee_start,+ path[depth].p_ext->ee_len,+ newblock);+ memmove(ex++, path[depth].p_ext++, sizeof(struct ext3_extent));+ neh->eh_entries++;+ m++;+ }+ set_buffer_uptodate(bh);+ unlock_buffer(bh);++ if ((err = ext3_journal_dirty_metadata(handle, bh)))+ goto cleanup; + brelse(bh);+ bh = NULL;++ /* correct old leaf */+ if (m) {+ if ((err = ext3_ext_get_access(handle, tree, path + depth)))+ goto cleanup;+ path[depth].p_hdr->eh_entries -= m;+ if ((err = ext3_ext_dirty(handle, tree, path + depth)))+ goto cleanup;+ + }++ /* create intermediate indexes */+ k = depth - at - 1;+ EXT_ASSERT(k >= 0);+ if (k)+ ext_debug(tree, "create %d intermediate indices\n", k);+ /* insert new index into current index block */+ /* current depth stored in i var */+ i = depth - 1;+ while (k--) {+ oldblock = newblock;+ newblock = ablocks[--a];+ bh = sb_getblk(tree->inode->i_sb, newblock);+ if (!bh) {+ err = -EIO;+ goto cleanup;+ }+ lock_buffer(bh);++ if ((err = ext3_journal_get_create_access(handle, bh)))+ goto cleanup;++ neh = EXT_BLOCK_HDR(bh);+ neh->eh_entries = 1;+ neh->eh_magic = EXT3_EXT_MAGIC;+ neh->eh_max = ext3_ext_space_block_idx(tree);+ neh->eh_depth = depth - i; + fidx = EXT_FIRST_INDEX(neh);+ fidx->ei_block = border;+ fidx->ei_leaf = oldblock;+ fidx->ei_leaf_hi = fidx->ei_unused = 0;++ ext_debug(tree, "int.index at %d (block %lu): %lu -> %lu\n",+ i, newblock, border, oldblock);+ /* copy indexes */+ m = 0;+ path[i].p_idx++;++ ext_debug(tree, "cur 0x%p, last 0x%p\n", path[i].p_idx,+ EXT_MAX_INDEX(path[i].p_hdr));+ EXT_ASSERT(EXT_MAX_INDEX(path[i].p_hdr) ==+ EXT_LAST_INDEX(path[i].p_hdr));+ while (path[i].p_idx <= EXT_MAX_INDEX(path[i].p_hdr)) {+ ext_debug(tree, "%d: move %d:%d in new index %lu\n",+ i, path[i].p_idx->ei_block,+ path[i].p_idx->ei_leaf, newblock);+ memmove(++fidx, path[i].p_idx++,+ sizeof(struct ext3_extent_idx));+ neh->eh_entries++;+ EXT_ASSERT(neh->eh_entries <= neh->eh_max);+ m++;+ }+ set_buffer_uptodate(bh);+ unlock_buffer(bh);++ if ((err = ext3_journal_dirty_metadata(handle, bh)))+ goto cleanup;+ brelse(bh);+ bh = NULL;++ /* correct old index */+ if (m) {+ err = ext3_ext_get_access(handle, tree, path + i);+ if (err)+ goto cleanup;+ path[i].p_hdr->eh_entries -= m;+ err = ext3_ext_dirty(handle, tree, path + i);+ if (err)+ goto cleanup;+ }++ i--;+ }++ /* insert new index */+ if (!err)+ err = ext3_ext_insert_index(handle, tree, path + at,+ border, newblock);++cleanup:+ if (bh) {+ if (buffer_locked(bh))+ unlock_buffer(bh);+ brelse(bh);+ }++ if (err) {+ /* free all allocated blocks in error case */+ for (i = 0; i < depth; i++) {+ if (!ablocks[i])+ continue;+ ext3_free_blocks(handle, tree->inode, ablocks[i], 1);+ }+ }+ kfree(ablocks);++ return err;+}++/*+ * routine implements tree growing procedure:+ * - allocates new block+ * - moves top-level data (index block or leaf) into the new block+ * - initialize new top-level, creating index that points to the+ * just created block+ */+static int ext3_ext_grow_indepth(handle_t *handle,+ struct ext3_extents_tree *tree,+ struct ext3_ext_path *path,+ struct ext3_extent *newext)+{+ struct ext3_ext_path *curp = path;+ struct ext3_extent_header *neh;+ struct ext3_extent_idx *fidx;+ struct buffer_head *bh;+ unsigned long newblock;+ int err = 0;++ newblock = ext3_ext_new_block(handle, tree, path, newext, &err);+ if (newblock == 0)+ return err;++ bh = sb_getblk(tree->inode->i_sb, newblock);+ if (!bh) {+ err = -EIO;+ ext3_std_error(tree->inode->i_sb, err);+ return err;+ }+ lock_buffer(bh);++ if ((err = ext3_journal_get_create_access(handle, bh))) {+ unlock_buffer(bh);+ goto out; + }++ /* move top-level index/leaf into new block */+ memmove(bh->b_data, curp->p_hdr, tree->buffer_len);++ /* set size of new block */+ neh = EXT_BLOCK_HDR(bh);+ /* old root could have indexes or leaves+ * so calculate eh_max right way */+ if (EXT_DEPTH(tree))+ neh->eh_max = ext3_ext_space_block_idx(tree);+ else+ neh->eh_max = ext3_ext_space_block(tree);+ neh->eh_magic = EXT3_EXT_MAGIC;+ set_buffer_uptodate(bh);+ unlock_buffer(bh);++ if ((err = ext3_journal_dirty_metadata(handle, bh)))+ goto out;++ /* create index in new top-level index: num,max,pointer */+ if ((err = ext3_ext_get_access(handle, tree, curp)))+ goto out;++ curp->p_hdr->eh_magic = EXT3_EXT_MAGIC;+ curp->p_hdr->eh_max = ext3_ext_space_root_idx(tree);+ curp->p_hdr->eh_entries = 1;+ curp->p_idx = EXT_FIRST_INDEX(curp->p_hdr);+ /* FIXME: it works, but actually path[0] can be index */+ curp->p_idx->ei_block = EXT_FIRST_EXTENT(path[0].p_hdr)->ee_block;+ curp->p_idx->ei_leaf = newblock;+ curp->p_idx->ei_leaf_hi = curp->p_idx->ei_unused = 0;++ neh = EXT_ROOT_HDR(tree);+ fidx = EXT_FIRST_INDEX(neh);+ ext_debug(tree, "new root: num %d(%d), lblock %d, ptr %d\n",+ neh->eh_entries, neh->eh_max, fidx->ei_block, fidx->ei_leaf); ++ neh->eh_depth = path->p_depth + 1;+ err = ext3_ext_dirty(handle, tree, curp);+out:+ brelse(bh);++ return err;+}++/*+ * routine finds empty index and adds new leaf. if no free index found+ * then it requests in-depth growing+ */+static int ext3_ext_create_new_leaf(handle_t *handle,+ struct ext3_extents_tree *tree,+ struct ext3_ext_path *path,+ struct ext3_extent *newext)+{+ struct ext3_ext_path *curp;+ int depth, i, err = 0;++repeat:+ i = depth = EXT_DEPTH(tree);+ + /* walk up to the tree and look for free index entry */+ curp = path + depth;+ while (i > 0 && !EXT_HAS_FREE_INDEX(curp)) {+ i--;+ curp--;+ }++ /* we use already allocated block for index block+ * so, subsequent data blocks should be contigoues */+ if (EXT_HAS_FREE_INDEX(curp)) {+ /* if we found index with free entry, then use that+ * entry: create all needed subtree and add new leaf */+ err = ext3_ext_split(handle, tree, path, newext, i);++ /* refill path */+ ext3_ext_drop_refs(path);+ path = ext3_ext_find_extent(tree, newext->ee_block, path);+ if (IS_ERR(path))+ err = PTR_ERR(path);+ } else {+ /* tree is full, time to grow in depth */+ err = ext3_ext_grow_indepth(handle, tree, path, newext);++ /* refill path */+ ext3_ext_drop_refs(path);+ path = ext3_ext_find_extent(tree, newext->ee_block, path);+ if (IS_ERR(path))+ err = PTR_ERR(path);++ /*+ * only first (depth 0 -> 1) produces free space+ * in all other cases we have to split growed tree+ */+ depth = EXT_DEPTH(tree);+ if (path[depth].p_hdr->eh_entries == path[depth].p_hdr->eh_max) {+ /* now we need split */+ goto repeat;+ }+ }++ if (err)+ return err;++ return 0;+}++/*+ * returns allocated block in subsequent extent or EXT_MAX_BLOCK+ * NOTE: it consider block number from index entry as+ * allocated block. thus, index entries have to be consistent+ * with leafs+ */+static unsigned long+ext3_ext_next_allocated_block(struct ext3_ext_path *path)+{+ int depth;++ EXT_ASSERT(path != NULL);+ depth = path->p_depth;++ if (depth == 0 && path->p_ext == NULL)+ return EXT_MAX_BLOCK;++ /* FIXME: what if index isn't full ?! */+ while (depth >= 0) {+ if (depth == path->p_depth) {+ /* leaf */+ if (path[depth].p_ext !=+ EXT_LAST_EXTENT(path[depth].p_hdr))+ return path[depth].p_ext[1].ee_block;+ } else {+ /* index */+ if (path[depth].p_idx !=+ EXT_LAST_INDEX(path[depth].p_hdr))+ return path[depth].p_idx[1].ei_block;+ }+ depth--; + }++ return EXT_MAX_BLOCK;+}++/*+ * returns first allocated block from next leaf or EXT_MAX_BLOCK+ */+static unsigned ext3_ext_next_leaf_block(struct ext3_extents_tree *tree,+ struct ext3_ext_path *path)+{+ int depth;++ EXT_ASSERT(path != NULL);+ depth = path->p_depth;+
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -