⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 extents.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 5 页
字号:
			goto repeat;		}	}out:	return err;}/* * ext4_ext_next_allocated_block: * returns allocated block in subsequent extent or EXT_MAX_BLOCK. * NOTE: it considers block number from index entry as * allocated block. Thus, index entries have to be consistent * with leaves. */static unsigned longext4_ext_next_allocated_block(struct ext4_ext_path *path){	int depth;	BUG_ON(path == NULL);	depth = path->p_depth;	if (depth == 0 && path->p_ext == NULL)		return EXT_MAX_BLOCK;	while (depth >= 0) {		if (depth == path->p_depth) {			/* leaf */			if (path[depth].p_ext !=					EXT_LAST_EXTENT(path[depth].p_hdr))			  return le32_to_cpu(path[depth].p_ext[1].ee_block);		} else {			/* index */			if (path[depth].p_idx !=					EXT_LAST_INDEX(path[depth].p_hdr))			  return le32_to_cpu(path[depth].p_idx[1].ei_block);		}		depth--;	}	return EXT_MAX_BLOCK;}/* * ext4_ext_next_leaf_block: * returns first allocated block from next leaf or EXT_MAX_BLOCK */static unsigned ext4_ext_next_leaf_block(struct inode *inode,					struct ext4_ext_path *path){	int depth;	BUG_ON(path == NULL);	depth = path->p_depth;	/* zero-tree has no leaf blocks at all */	if (depth == 0)		return EXT_MAX_BLOCK;	/* go to index block */	depth--;	while (depth >= 0) {		if (path[depth].p_idx !=				EXT_LAST_INDEX(path[depth].p_hdr))		  return le32_to_cpu(path[depth].p_idx[1].ei_block);		depth--;	}	return EXT_MAX_BLOCK;}/* * ext4_ext_correct_indexes: * if leaf gets modified and modified extent is first in the leaf, * then we have to correct all indexes above. * TODO: do we need to correct tree in all cases? */int ext4_ext_correct_indexes(handle_t *handle, struct inode *inode,				struct ext4_ext_path *path){	struct ext4_extent_header *eh;	int depth = ext_depth(inode);	struct ext4_extent *ex;	__le32 border;	int k, err = 0;	eh = path[depth].p_hdr;	ex = path[depth].p_ext;	BUG_ON(ex == NULL);	BUG_ON(eh == NULL);	if (depth == 0) {		/* there is no tree at all */		return 0;	}	if (ex != EXT_FIRST_EXTENT(eh)) {		/* we correct tree if first leaf got modified only */		return 0;	}	/*	 * TODO: we need correction if border is smaller than current one	 */	k = depth - 1;	border = path[depth].p_ext->ee_block;	err = ext4_ext_get_access(handle, inode, path + k);	if (err)		return err;	path[k].p_idx->ei_block = border;	err = ext4_ext_dirty(handle, inode, path + k);	if (err)		return err;	while (k--) {		/* change all left-side indexes */		if (path[k+1].p_idx != EXT_FIRST_INDEX(path[k+1].p_hdr))			break;		err = ext4_ext_get_access(handle, inode, path + k);		if (err)			break;		path[k].p_idx->ei_block = border;		err = ext4_ext_dirty(handle, inode, path + k);		if (err)			break;	}	return err;}static intext4_can_extents_be_merged(struct inode *inode, struct ext4_extent *ex1,				struct ext4_extent *ex2){	unsigned short ext1_ee_len, ext2_ee_len, max_len;	/*	 * Make sure that either both extents are uninitialized, or	 * both are _not_.	 */	if (ext4_ext_is_uninitialized(ex1) ^ ext4_ext_is_uninitialized(ex2))		return 0;	if (ext4_ext_is_uninitialized(ex1))		max_len = EXT_UNINIT_MAX_LEN;	else		max_len = EXT_INIT_MAX_LEN;	ext1_ee_len = ext4_ext_get_actual_len(ex1);	ext2_ee_len = ext4_ext_get_actual_len(ex2);	if (le32_to_cpu(ex1->ee_block) + ext1_ee_len !=			le32_to_cpu(ex2->ee_block))		return 0;	/*	 * To allow future support for preallocated extents to be added	 * as an RO_COMPAT feature, refuse to merge to extents if	 * this can result in the top bit of ee_len being set.	 */	if (ext1_ee_len + ext2_ee_len > max_len)		return 0;#ifdef AGGRESSIVE_TEST	if (le16_to_cpu(ex1->ee_len) >= 4)		return 0;#endif	if (ext_pblock(ex1) + ext1_ee_len == ext_pblock(ex2))		return 1;	return 0;}/* * This function tries to merge the "ex" extent to the next extent in the tree. * It always tries to merge towards right. If you want to merge towards * left, pass "ex - 1" as argument instead of "ex". * Returns 0 if the extents (ex and ex+1) were _not_ merged and returns * 1 if they got merged. */int ext4_ext_try_to_merge(struct inode *inode,			  struct ext4_ext_path *path,			  struct ext4_extent *ex){	struct ext4_extent_header *eh;	unsigned int depth, len;	int merge_done = 0;	int uninitialized = 0;	depth = ext_depth(inode);	BUG_ON(path[depth].p_hdr == NULL);	eh = path[depth].p_hdr;	while (ex < EXT_LAST_EXTENT(eh)) {		if (!ext4_can_extents_be_merged(inode, ex, ex + 1))			break;		/* merge with next extent! */		if (ext4_ext_is_uninitialized(ex))			uninitialized = 1;		ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)				+ ext4_ext_get_actual_len(ex + 1));		if (uninitialized)			ext4_ext_mark_uninitialized(ex);		if (ex + 1 < EXT_LAST_EXTENT(eh)) {			len = (EXT_LAST_EXTENT(eh) - ex - 1)				* sizeof(struct ext4_extent);			memmove(ex + 1, ex + 2, len);		}		eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries) - 1);		merge_done = 1;		WARN_ON(eh->eh_entries == 0);		if (!eh->eh_entries)			ext4_error(inode->i_sb, "ext4_ext_try_to_merge",			   "inode#%lu, eh->eh_entries = 0!", inode->i_ino);	}	return merge_done;}/* * check if a portion of the "newext" extent overlaps with an * existing extent. * * If there is an overlap discovered, it updates the length of the newext * such that there will be no overlap, and then returns 1. * If there is no overlap found, it returns 0. */unsigned int ext4_ext_check_overlap(struct inode *inode,				    struct ext4_extent *newext,				    struct ext4_ext_path *path){	unsigned long b1, b2;	unsigned int depth, len1;	unsigned int ret = 0;	b1 = le32_to_cpu(newext->ee_block);	len1 = ext4_ext_get_actual_len(newext);	depth = ext_depth(inode);	if (!path[depth].p_ext)		goto out;	b2 = le32_to_cpu(path[depth].p_ext->ee_block);	/*	 * get the next allocated block if the extent in the path	 * is before the requested block(s) 	 */	if (b2 < b1) {		b2 = ext4_ext_next_allocated_block(path);		if (b2 == EXT_MAX_BLOCK)			goto out;	}	/* check for wrap through zero */	if (b1 + len1 < b1) {		len1 = EXT_MAX_BLOCK - b1;		newext->ee_len = cpu_to_le16(len1);		ret = 1;	}	/* check for overlap */	if (b1 + len1 > b2) {		newext->ee_len = cpu_to_le16(b2 - b1);		ret = 1;	}out:	return ret;}/* * ext4_ext_insert_extent: * tries to merge requsted extent into the existing extent or * inserts requested extent as new one into the tree, * creating new leaf in the no-space case. */int ext4_ext_insert_extent(handle_t *handle, struct inode *inode,				struct ext4_ext_path *path,				struct ext4_extent *newext){	struct ext4_extent_header * eh;	struct ext4_extent *ex, *fex;	struct ext4_extent *nearex; /* nearest extent */	struct ext4_ext_path *npath = NULL;	int depth, len, err, next;	unsigned uninitialized = 0;	BUG_ON(ext4_ext_get_actual_len(newext) == 0);	depth = ext_depth(inode);	ex = path[depth].p_ext;	BUG_ON(path[depth].p_hdr == NULL);	/* try to insert block into found extent and return */	if (ex && ext4_can_extents_be_merged(inode, ex, newext)) {		ext_debug("append %d block to %d:%d (from %llu)\n",				ext4_ext_get_actual_len(newext),				le32_to_cpu(ex->ee_block),				ext4_ext_get_actual_len(ex), ext_pblock(ex));		err = ext4_ext_get_access(handle, inode, path + depth);		if (err)			return err;		/*		 * ext4_can_extents_be_merged should have checked that either		 * both extents are uninitialized, or both aren't. Thus we		 * need to check only one of them here.		 */		if (ext4_ext_is_uninitialized(ex))			uninitialized = 1;		ex->ee_len = cpu_to_le16(ext4_ext_get_actual_len(ex)					+ ext4_ext_get_actual_len(newext));		if (uninitialized)			ext4_ext_mark_uninitialized(ex);		eh = path[depth].p_hdr;		nearex = ex;		goto merge;	}repeat:	depth = ext_depth(inode);	eh = path[depth].p_hdr;	if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max))		goto has_space;	/* probably next leaf has space for us? */	fex = EXT_LAST_EXTENT(eh);	next = ext4_ext_next_leaf_block(inode, path);	if (le32_to_cpu(newext->ee_block) > le32_to_cpu(fex->ee_block)	    && next != EXT_MAX_BLOCK) {		ext_debug("next leaf block - %d\n", next);		BUG_ON(npath != NULL);		npath = ext4_ext_find_extent(inode, next, NULL);		if (IS_ERR(npath))			return PTR_ERR(npath);		BUG_ON(npath->p_depth != path->p_depth);		eh = npath[depth].p_hdr;		if (le16_to_cpu(eh->eh_entries) < le16_to_cpu(eh->eh_max)) {			ext_debug("next leaf isnt full(%d)\n",				  le16_to_cpu(eh->eh_entries));			path = npath;			goto repeat;		}		ext_debug("next leaf has no free space(%d,%d)\n",			  le16_to_cpu(eh->eh_entries), le16_to_cpu(eh->eh_max));	}	/*	 * There is no free space in the found leaf.	 * We're gonna add a new leaf in the tree.	 */	err = ext4_ext_create_new_leaf(handle, inode, path, newext);	if (err)		goto cleanup;	depth = ext_depth(inode);	eh = path[depth].p_hdr;has_space:	nearex = path[depth].p_ext;	err = ext4_ext_get_access(handle, inode, path + depth);	if (err)		goto cleanup;	if (!nearex) {		/* there is no extent in this leaf, create first one */		ext_debug("first extent in the leaf: %d:%llu:%d\n",				le32_to_cpu(newext->ee_block),				ext_pblock(newext),				ext4_ext_get_actual_len(newext));		path[depth].p_ext = EXT_FIRST_EXTENT(eh);	} else if (le32_to_cpu(newext->ee_block)			   > le32_to_cpu(nearex->ee_block)) {/*		BUG_ON(newext->ee_block == nearex->ee_block); */		if (nearex != EXT_LAST_EXTENT(eh)) {			len = EXT_MAX_EXTENT(eh) - nearex;			len = (len - 1) * sizeof(struct ext4_extent);			len = len < 0 ? 0 : len;			ext_debug("insert %d:%llu:%d after: nearest 0x%p, "					"move %d from 0x%p to 0x%p\n",					le32_to_cpu(newext->ee_block),					ext_pblock(newext),					ext4_ext_get_actual_len(newext),					nearex, len, nearex + 1, nearex + 2);			memmove(nearex + 2, nearex + 1, len);		}		path[depth].p_ext = nearex + 1;	} else {		BUG_ON(newext->ee_block == nearex->ee_block);		len = (EXT_MAX_EXTENT(eh) - nearex) * sizeof(struct ext4_extent);		len = len < 0 ? 0 : len;		ext_debug("insert %d:%llu:%d before: nearest 0x%p, "				"move %d from 0x%p to 0x%p\n",				le32_to_cpu(newext->ee_block),				ext_pblock(newext),				ext4_ext_get_actual_len(newext),				nearex, len, nearex + 1, nearex + 2);		memmove(nearex + 1, nearex, len);		path[depth].p_ext = nearex;	}	eh->eh_entries = cpu_to_le16(le16_to_cpu(eh->eh_entries)+1);	nearex = path[depth].p_ext;	nearex->ee_block = newext->ee_block;	ext4_ext_store_pblock(nearex, ext_pblock(newext));	nearex->ee_len = newext->ee_len;merge:	/* try to merge extents to the right */	ext4_ext_try_to_merge(inode, path, nearex);	/* try to merge extents to the left */	/* time to correct all indexes above */	err = ext4_ext_correct_indexes(handle, inode, path);	if (err)		goto cleanup;	err = ext4_ext_dirty(handle, inode, path + depth);cleanup:	if (npath) {		ext4_ext_drop_refs(npath);		kfree(npath);	}	ext4_ext_tree_changed(inode);	ext4_ext_invalidate_cache(inode);	return err;}int ext4_ext_walk_space(struct inode *inode, unsigned long block,			unsigned long num, ext_prepare_callback func,			void *cbdata){	struct ext4_ext_path *path = NULL;	struct ext4_ext_cache cbex;	struct ext4_extent *ex;	unsigned long next, start = 0, end = 0;	unsigned long last = block + num;	int depth, exists, err = 0;	BUG_ON(func == NULL);	BUG_ON(inode == NULL);	while (block < last && block != EXT_MAX_BLOCK) {		num = last - block;		/* find extent for this block */		path = ext4_ext_find_extent(inode, block, path);		if (IS_ERR(path)) {			err = PTR_ERR(path);			path = NULL;			break;		}		depth = ext_depth(inode);		BUG_ON(path[depth].p_hdr == NULL);		ex = path[depth].p_ext;		next = ext4_ext_next_allocated_block(path);		exists = 0;		if (!ex) {			/* there is no extent yet, so try to allocate			 * all requested space */			start = block;			end = block + num;		} else if (le32_to_cpu(ex->ee_block) > block) {			/* need to allocate space before found extent */			start = block;			end = le32_to_cpu(ex->ee_block);			if (block + num < end)				end = block + num;		} else if (block >= le32_to_cpu(ex->ee_block)					+ ext4_ext_get_actual_len(ex)) {			/* need to allocate space after found extent */			start = block;			end = block + num;			if (end >= next)				end = next;		} else if (block >= le32_to_cpu(ex->ee_block)) {			/*			 * some part of requested space is covered			 * by found extent			 */			start = block;			end = le32_to_cpu(ex->ee_block)				+ ext4_ext_get_actual_len(ex);			if (block + num < end)				end = block + num;			exists = 1;		} else {			BUG();		}		BUG_ON(end <= start);		if (!exists) {			cbex.ec_block = start;			cbex.ec_len = end - start;			cbex.ec_start = 0;			cbex.ec_type = EXT4_EXT_CACHE_GAP;		} else {			cbex.ec_block = le32_to_cpu(ex->ee_block);			cbex.ec_len = ext4_ext_get_actual_len(ex);			cbex.ec_start = ext_pblock(ex);			cbex.ec_type = EXT4_EXT_CACHE_EXTENT;		}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -