130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o/*
280e808fceb61c2061b32593c610893bf07a863eeTheodore Ts'o * bmap.c --- logical to physical block mapping
330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o *
430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * Copyright (C) 1997 Theodore Ts'o.
530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o *
630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * %Begin-Header%
7543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * This file may be redistributed under the terms of the GNU Library
8543547a52a20cb7e69d74921b2f691078fd55d83Theodore Ts'o * General Public License, version 2.
930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o * %End-Header%
1030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o */
1130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
12d1154eb460efe588eaed3d439c1caaca149fa362Theodore Ts'o#include "config.h"
1330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include <stdio.h>
1430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include <string.h>
1530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#if HAVE_UNISTD_H
1630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#include <unistd.h>
1730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#endif
18cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o#include <errno.h>
1930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
20b5abe6fac9c9e7caf4710501d1657d30e4857ef6Theodore Ts'o#include "ext2_fs.h"
21f404167dda29a59d2be2882328aeb074b9899669Theodore Ts'o#include "ext2fsP.h"
2230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
2378d8f90ffae45808096133c461ef1ee0e65de937Theodore Ts'o#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
2430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define _BMAP_INLINE_	__inline__
2530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#else
2630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define _BMAP_INLINE_
2730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#endif
2830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
2931dbecd482405e0d3a67eb58e1a1c8cb9f2ad83eTheodore Ts'oextern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
30efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o			     struct ext2_inode *inode,
3130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			     char *block_buf, int bmap_flags,
3230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			     blk_t block, blk_t *phys_blk);
3330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
3430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
3530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
36efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'ostatic _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags,
37efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o					      blk_t ind, char *block_buf,
3830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					      int *blocks_alloc,
3930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					      blk_t nr, blk_t *ret_blk)
4030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o{
4130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	errcode_t	retval;
4230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	blk_t		b;
4330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
4430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (!ind) {
451d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		if (flags & BMAP_SET)
461d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			return EXT2_ET_SET_BMAP_NO_IND;
4730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		*ret_blk = 0;
4830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		return 0;
4930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
5030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
5130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (retval)
5230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		return retval;
5330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
541d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o	if (flags & BMAP_SET) {
551d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		b = *ret_blk;
56126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o#ifdef WORDS_BIGENDIAN
57126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o		b = ext2fs_swab32(b);
581d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o#endif
591d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		((blk_t *) block_buf)[nr] = b;
601d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		return io_channel_write_blk(fs->io, ind, 1, block_buf);
611d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o	}
621d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o
6330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	b = ((blk_t *) block_buf)[nr];
6430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
65126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o#ifdef WORDS_BIGENDIAN
66126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o	b = ext2fs_swab32(b);
675df55d7f847e29d23227592a0bb23daad1a61500Theodore Ts'o#endif
6830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
6930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (!b && (flags & BMAP_ALLOC)) {
70407916f5af4443e0ddd9469c57fc1684c07f9294Darrick J. Wong		b = nr ? ext2fs_le32_to_cpu(((blk_t *)block_buf)[nr - 1]) : ind;
7130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		retval = ext2fs_alloc_block(fs, b,
7230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					    block_buf + fs->blocksize, &b);
7330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if (retval)
7430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			return retval;
7530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
76126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o#ifdef WORDS_BIGENDIAN
77126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o		((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
78126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o#else
79126a291c768b523bc228b276d3bea82675a86d09Theodore Ts'o		((blk_t *) block_buf)[nr] = b;
805df55d7f847e29d23227592a0bb23daad1a61500Theodore Ts'o#endif
8130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
8230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
8330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if (retval)
8430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			return retval;
8530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
8630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		(*blocks_alloc)++;
8730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
8830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
8930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	*ret_blk = b;
9030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	return 0;
9130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o}
9230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
93546a1ff18cc912003883ff67ba3e87c69f700fc4Theodore Ts'ostatic _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags,
94efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o					       blk_t dind, char *block_buf,
9530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					       int *blocks_alloc,
9630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					       blk_t nr, blk_t *ret_blk)
9730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o{
981d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger	blk_t		b = 0;
9930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	errcode_t	retval;
1002eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	blk_t		addr_per_block;
101efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1022eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	addr_per_block = (blk_t) fs->blocksize >> 2;
10330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
104efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf,
1051d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				blocks_alloc, nr / addr_per_block, &b);
10630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (retval)
10730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		return retval;
10830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
10930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o				nr % addr_per_block, ret_blk);
11030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	return retval;
11130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o}
11230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
113546a1ff18cc912003883ff67ba3e87c69f700fc4Theodore Ts'ostatic _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
114efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o					       blk_t tind, char *block_buf,
11530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					       int *blocks_alloc,
11630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o					       blk_t nr, blk_t *ret_blk)
11730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o{
1181d6fd6d0c3766a8165e69284c75812574a29c804Andreas Dilger	blk_t		b = 0;
11930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	errcode_t	retval;
1202eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	blk_t		addr_per_block;
121efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
1222eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	addr_per_block = (blk_t) fs->blocksize >> 2;
12330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
124efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf,
1251d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				 blocks_alloc, nr / addr_per_block, &b);
12630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (retval)
12730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		return retval;
12830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
12930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o				nr % addr_per_block, ret_blk);
13030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	return retval;
13130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o}
13230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
133551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'ostatic errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
134551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			     struct ext2_inode *inode,
135551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			     ext2_extent_handle_t handle,
136551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			     char *block_buf, int bmap_flags, blk64_t block,
137551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			     int *ret_flags, int *blocks_alloc,
1388e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o			     blk64_t *phys_blk);
1398e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o
1408e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'ostatic errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
1418e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o				       struct ext2_inode *inode,
1428e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o				       ext2_extent_handle_t handle,
1432a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong				       blk64_t lblk, blk64_t *phys_blk)
1448e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o{
1458e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o	blk64_t	base_block, pblock = 0;
1468e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o	int i;
1478e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o
14877b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_bigalloc(fs->super))
1498e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o		return 0;
1508e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o
1512a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	base_block = lblk & ~EXT2FS_CLUSTER_MASK(fs);
1522a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	/*
1532a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	 * Except for the logical block (lblk) that was passed in, search all
1542a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	 * blocks in this logical cluster for a mapping to a physical cluster.
1552a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	 * If any such map exists, calculate the physical block that maps to
1562a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	 * the logical block and return that.
1572a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	 *
1582a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	 * The old code wouldn't even look if (block % cluster_ratio) == 0;
1592a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	 * this is incorrect if we're allocating blocks in reverse order.
1602a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	 */
1618e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o	for (i = 0; i < EXT2FS_CLUSTER_RATIO(fs); i++) {
1622a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong		if (base_block + i == lblk)
1632a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong			continue;
1648e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o		extent_bmap(fs, ino, inode, handle, 0, 0,
1658e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o			    base_block + i, 0, 0, &pblock);
1668e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o		if (pblock)
1678e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o			break;
1688e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o	}
1698e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o	if (pblock == 0)
1708e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o		return 0;
1712a091427bcbff1fd1cf3f0bccf00da98d52b8f16Darrick J. Wong	*phys_blk = pblock - i + (lblk - base_block);
1728e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o	return 0;
1738e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o}
1748e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o
17584397754250d13e8596dd68c157c4c9863800079Darrick J. Wong/* Try to map a logical block to an already-allocated physical cluster. */
17684397754250d13e8596dd68c157c4c9863800079Darrick J. Wongerrcode_t ext2fs_map_cluster_block(ext2_filsys fs, ext2_ino_t ino,
17784397754250d13e8596dd68c157c4c9863800079Darrick J. Wong				   struct ext2_inode *inode, blk64_t lblk,
17884397754250d13e8596dd68c157c4c9863800079Darrick J. Wong				   blk64_t *pblk)
17984397754250d13e8596dd68c157c4c9863800079Darrick J. Wong{
18084397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	ext2_extent_handle_t handle;
18184397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	errcode_t retval;
18284397754250d13e8596dd68c157c4c9863800079Darrick J. Wong
18384397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	/* Need bigalloc and extents to be enabled */
18484397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	*pblk = 0;
18577b3e9871877fce9908b0696250787fd6ea61af9Darrick J. Wong	if (!ext2fs_has_feature_bigalloc(fs->super) ||
18684397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	    !(inode->i_flags & EXT4_EXTENTS_FL))
18784397754250d13e8596dd68c157c4c9863800079Darrick J. Wong		return 0;
18884397754250d13e8596dd68c157c4c9863800079Darrick J. Wong
18984397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	retval = ext2fs_extent_open2(fs, ino, inode, &handle);
19084397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	if (retval)
19184397754250d13e8596dd68c157c4c9863800079Darrick J. Wong		goto out;
19284397754250d13e8596dd68c157c4c9863800079Darrick J. Wong
19384397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	retval = implied_cluster_alloc(fs, ino, inode, handle, lblk, pblk);
19484397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	if (retval)
19584397754250d13e8596dd68c157c4c9863800079Darrick J. Wong		goto out2;
19684397754250d13e8596dd68c157c4c9863800079Darrick J. Wong
19784397754250d13e8596dd68c157c4c9863800079Darrick J. Wongout2:
19884397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	ext2fs_extent_free(handle);
19984397754250d13e8596dd68c157c4c9863800079Darrick J. Wongout:
20084397754250d13e8596dd68c157c4c9863800079Darrick J. Wong	return retval;
20184397754250d13e8596dd68c157c4c9863800079Darrick J. Wong}
20284397754250d13e8596dd68c157c4c9863800079Darrick J. Wong
2038e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'ostatic errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
2048e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o			     struct ext2_inode *inode,
2058e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o			     ext2_extent_handle_t handle,
2068e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o			     char *block_buf, int bmap_flags, blk64_t block,
2078e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o			     int *ret_flags, int *blocks_alloc,
208551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			     blk64_t *phys_blk)
209551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o{
210127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht	struct blk_alloc_ctx	alloc_ctx;
211551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	struct ext2fs_extent	extent;
212551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	unsigned int		offset;
213551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	errcode_t		retval = 0;
2148e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o	blk64_t			blk64 = 0;
2158e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o	int			alloc = 0;
21660a212f773ba116b4f7a9edb5eb76b40668ea8a0Darrick J. Wong	int			set_flags;
21760a212f773ba116b4f7a9edb5eb76b40668ea8a0Darrick J. Wong
21860a212f773ba116b4f7a9edb5eb76b40668ea8a0Darrick J. Wong	set_flags = bmap_flags & BMAP_UNINIT ? EXT2_EXTENT_SET_BMAP_UNINIT : 0;
219551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o
220551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	if (bmap_flags & BMAP_SET) {
221551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		retval = ext2fs_extent_set_bmap(handle, block,
22260a212f773ba116b4f7a9edb5eb76b40668ea8a0Darrick J. Wong						*phys_blk, set_flags);
223551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		return retval;
224551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	}
225551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	retval = ext2fs_extent_goto(handle, block);
226551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	if (retval) {
227551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		/* If the extent is not found, return phys_blk = 0 */
228551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		if (retval == EXT2_ET_EXTENT_NOT_FOUND)
229551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			goto got_block;
230551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		return retval;
231551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	}
232551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
233551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	if (retval)
234551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		return retval;
235551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	offset = block - extent.e_lblk;
236551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	if (block >= extent.e_lblk && (offset <= extent.e_len)) {
237551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		*phys_blk = extent.e_pblk + offset;
238551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		if (ret_flags && extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
239551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			*ret_flags |= BMAP_RET_UNINIT;
240551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	}
241551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'ogot_block:
242551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
2438e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o		implied_cluster_alloc(fs, ino, inode, handle, block, &blk64);
2448e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o		if (blk64)
2458e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o			goto set_extent;
246551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		retval = extent_bmap(fs, ino, inode, handle, block_buf,
247551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o				     0, block-1, 0, blocks_alloc, &blk64);
248551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		if (retval)
2497b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong			blk64 = ext2fs_find_inode_goal(fs, ino, inode, block);
250127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		alloc_ctx.ino = ino;
251127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		alloc_ctx.inode = inode;
252127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		alloc_ctx.lblk = extent.e_lblk;
253127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		alloc_ctx.flags = BLOCK_ALLOC_DATA;
254127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		retval = ext2fs_alloc_block3(fs, blk64, block_buf, &blk64,
255127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht					     &alloc_ctx);
256551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		if (retval)
257551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			return retval;
2588e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o		blk64 &= ~EXT2FS_CLUSTER_MASK(fs);
2598e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o		blk64 += EXT2FS_CLUSTER_MASK(fs) & block;
2608e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o		alloc++;
2618e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o	set_extent:
262551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		retval = ext2fs_extent_set_bmap(handle, block,
26360a212f773ba116b4f7a9edb5eb76b40668ea8a0Darrick J. Wong						blk64, set_flags);
2646225a154d2616edcd13885797ed5e1c0cc51e0b7Darrick J. Wong		if (retval) {
2656225a154d2616edcd13885797ed5e1c0cc51e0b7Darrick J. Wong			ext2fs_block_alloc_stats2(fs, blk64, -1);
266551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			return retval;
2676225a154d2616edcd13885797ed5e1c0cc51e0b7Darrick J. Wong		}
268551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		/* Update inode after setting extent */
269551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		retval = ext2fs_read_inode(fs, ino, inode);
270551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		if (retval)
271551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			return retval;
2728e8a190fa212ca28efb2e8a8b3318a24d7fc4b7aTheodore Ts'o		*blocks_alloc += alloc;
273551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		*phys_blk = blk64;
274551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	}
275551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	return 0;
276551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o}
277551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o
2781e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wongint ext2fs_file_block_offset_too_big(ext2_filsys fs,
2791e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong				     struct ext2_inode *inode,
2801e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong				     blk64_t offset)
2811e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong{
2821e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	blk64_t addr_per_block, max_map_block;
2831e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong
2841e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	/* Kernel seems to cut us off at 4294967294 blocks */
2851e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	if (offset >= (1ULL << 32) - 1)
2861e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong		return 1;
2871e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong
2881e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	if (inode->i_flags & EXT4_EXTENTS_FL)
2891e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong		return 0;
2901e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong
2911e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	addr_per_block = fs->blocksize >> 2;
2921e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	max_map_block = addr_per_block;
2931e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	max_map_block += addr_per_block * addr_per_block;
2941e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	max_map_block += addr_per_block * addr_per_block * addr_per_block;
2951e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	max_map_block += 12;
2961e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong
2971e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	return offset >= max_map_block;
2981e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong}
299551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o
300cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'oerrcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
301cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		       char *block_buf, int bmap_flags, blk64_t block,
302cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		       int *ret_flags, blk64_t *phys_blk)
30330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o{
30430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	struct ext2_inode inode_buf;
305cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	ext2_extent_handle_t handle = 0;
3062eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	blk_t addr_per_block;
307cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	blk_t	b, blk32;
308127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht	blk64_t b64;
30930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	char	*buf = 0;
31030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	errcode_t	retval = 0;
3111d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o	int		blocks_alloc = 0, inode_dirty = 0;
312127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht	struct blk_alloc_ctx alloc_ctx = {
313127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		.ino	= ino,
314127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		.inode	= inode,
315127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		.lblk	= 0,
316127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		.flags	= BLOCK_ALLOC_DATA,
317127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht	};
31830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
3191d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o	if (!(bmap_flags & BMAP_SET))
3201d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		*phys_blk = 0;
32130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
322cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	if (ret_flags)
323cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		*ret_flags = 0;
324cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o
32530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	/* Read inode structure if necessary */
32630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (!inode) {
32730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		retval = ext2fs_read_inode(fs, ino, &inode_buf);
328b38cd283637dafff6b39d4b76bf76fa2789eb21fTheodore Ts'o		if (retval)
32930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			return retval;
33030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		inode = &inode_buf;
33130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
3322eb374c9401079aa56aa12f0047ca3866e69b754Theodore Ts'o	addr_per_block = (blk_t) fs->blocksize >> 2;
33330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
3341e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong	if (ext2fs_file_block_offset_too_big(fs, inode, block))
3351e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong		return EXT2_ET_FILE_TOO_BIG;
3361e7451493ed67ae94ba5c1d2bed059527bc9848dDarrick J. Wong
337f5f6c020cac429a5484ad0fdaccb44f127912075Zheng Liu	/*
338f5f6c020cac429a5484ad0fdaccb44f127912075Zheng Liu	 * If an inode has inline data, that means that it doesn't have
339f5f6c020cac429a5484ad0fdaccb44f127912075Zheng Liu	 * any blocks and we shouldn't map any blocks for it.
340f5f6c020cac429a5484ad0fdaccb44f127912075Zheng Liu	 */
341f5f6c020cac429a5484ad0fdaccb44f127912075Zheng Liu	if (inode->i_flags & EXT4_INLINE_DATA_FL)
342f5f6c020cac429a5484ad0fdaccb44f127912075Zheng Liu		return EXT2_ET_INLINE_DATA_NO_BLOCK;
343f5f6c020cac429a5484ad0fdaccb44f127912075Zheng Liu
34430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (!block_buf) {
345ee01079a17bfecd17292ccd60058056fb3a8ba6cTheodore Ts'o		retval = ext2fs_get_array(2, fs->blocksize, &buf);
3467b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o		if (retval)
3477b4e4534f9361b21d3fafdd88a58f133decee38cTheodore Ts'o			return retval;
34830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		block_buf = buf;
34930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
35030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
351551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	if (inode->i_flags & EXT4_EXTENTS_FL) {
352551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		retval = ext2fs_extent_open2(fs, ino, inode, &handle);
353551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		if (retval)
354551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o			goto done;
355551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		retval = extent_bmap(fs, ino, inode, handle, block_buf,
356551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o				     bmap_flags, block, ret_flags,
357551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o				     &blocks_alloc, phys_blk);
358551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o		goto done;
359551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o	}
360551e2e46ee2fdf8cfa16e153d3c560203f0f9a5eTheodore Ts'o
36130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (block < EXT2_NDIR_BLOCKS) {
3621d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		if (bmap_flags & BMAP_SET) {
3631d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			b = *phys_blk;
3641d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			inode_bmap(inode, block) = b;
3651d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			inode_dirty++;
3661d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			goto done;
3671d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		}
3681d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o
36930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		*phys_blk = inode_bmap(inode, block);
3707b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong		b = block ? inode_bmap(inode, block - 1) :
3717b486ec08cda3bc67b7f6bdcbcc9cb5783322e6cDarrick J. Wong			    ext2fs_find_inode_goal(fs, ino, inode, block);
372efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
37330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
374127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht			b64 = b;
375127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht			retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
376127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht						     &alloc_ctx);
377127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht			b = b64;
37830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			if (retval)
37930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o				goto done;
38030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			inode_bmap(inode, block) = b;
38130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			blocks_alloc++;
38230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			*phys_blk = b;
38330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		}
38430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		goto done;
38530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
386efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
38730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	/* Indirect block */
38830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	block -= EXT2_NDIR_BLOCKS;
389cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	blk32 = *phys_blk;
39030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (block < addr_per_block) {
39130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		b = inode_bmap(inode, EXT2_IND_BLOCK);
39230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if (!b) {
3931d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			if (!(bmap_flags & BMAP_ALLOC)) {
3941d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				if (bmap_flags & BMAP_SET)
3951d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o					retval = EXT2_ET_SET_BMAP_NO_IND;
3961d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				goto done;
3971d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			}
39830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
39930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			b = inode_bmap(inode, EXT2_IND_BLOCK-1);
400127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht			b64 = b;
401127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht			retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
402127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht						     &alloc_ctx);
403127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht			b = b64;
40430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			if (retval)
40530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o				goto done;
40630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			inode_bmap(inode, EXT2_IND_BLOCK) = b;
40730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			blocks_alloc++;
40830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		}
409efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
410cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o					&blocks_alloc, block, &blk32);
411cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		if (retval == 0)
412cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o			*phys_blk = blk32;
41330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		goto done;
41430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
415efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o
41630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	/* Doubly indirect block  */
41730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	block -= addr_per_block;
41830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (block < addr_per_block * addr_per_block) {
41930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		b = inode_bmap(inode, EXT2_DIND_BLOCK);
42030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if (!b) {
4211d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			if (!(bmap_flags & BMAP_ALLOC)) {
4221d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				if (bmap_flags & BMAP_SET)
4231d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o					retval = EXT2_ET_SET_BMAP_NO_IND;
4241d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				goto done;
4251d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			}
42630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
42730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			b = inode_bmap(inode, EXT2_IND_BLOCK);
428127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht			b64 = b;
429127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht			retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
430127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht						     &alloc_ctx);
431127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht			b = b64;
43230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			if (retval)
43330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o				goto done;
43430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			inode_bmap(inode, EXT2_DIND_BLOCK) = b;
43530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			blocks_alloc++;
43630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		}
437efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o		retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
438cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o					 &blocks_alloc, block, &blk32);
439cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		if (retval == 0)
440cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o			*phys_blk = blk32;
44130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		goto done;
44230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
44330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
44430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	/* Triply indirect block */
44530fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	block -= addr_per_block * addr_per_block;
44630fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	b = inode_bmap(inode, EXT2_TIND_BLOCK);
44730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (!b) {
4481d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		if (!(bmap_flags & BMAP_ALLOC)) {
4491d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o			if (bmap_flags & BMAP_SET)
4501d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o				retval = EXT2_ET_SET_BMAP_NO_IND;
45130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			goto done;
4521d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o		}
45330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
45430fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		b = inode_bmap(inode, EXT2_DIND_BLOCK);
455127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		b64 = b;
456127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
457127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht					     &alloc_ctx);
458127a599529a0c31d8e3bc4da82a5debd670254b6Adrien Schildknecht		b = b64;
45930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		if (retval)
46030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o			goto done;
46130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		inode_bmap(inode, EXT2_TIND_BLOCK) = b;
46230fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		blocks_alloc++;
46330fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
464efc6f628e15de95bcd13e4f0ee223cb42115d520Theodore Ts'o	retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
465cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o				 &blocks_alloc, block, &blk32);
466cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	if (retval == 0)
467cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		*phys_blk = blk32;
46830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'odone:
46960a212f773ba116b4f7a9edb5eb76b40668ea8a0Darrick J. Wong	if (*phys_blk && retval == 0 && (bmap_flags & BMAP_ZERO))
47060a212f773ba116b4f7a9edb5eb76b40668ea8a0Darrick J. Wong		retval = ext2fs_zero_blocks2(fs, *phys_blk, 1, NULL, NULL);
47130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	if (buf)
472c4e3d3f374b409500e3dd05c0b0eca6ac98a6b4eTheodore Ts'o		ext2fs_free_mem(&buf);
473cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	if (handle)
474cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		ext2fs_extent_free(handle);
4751d667534e93e78eedbf2efcef6d7844041675f26Theodore Ts'o	if ((retval == 0) && (blocks_alloc || inode_dirty)) {
4761ca1059fd0126fd2c065f272a566c18f14bab16dTheodore Ts'o		ext2fs_iblk_add_blocks(fs, inode, blocks_alloc);
47730fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o		retval = ext2fs_write_inode(fs, ino, inode);
47830fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	}
47930fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o	return retval;
48030fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o}
48130fab293065b7fc6d7d138e8e9eea533a3560873Theodore Ts'o
482cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'oerrcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
483cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		      char *block_buf, int bmap_flags, blk_t block,
484cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		      blk_t *phys_blk)
485cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o{
486cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	errcode_t ret;
4879c9e1d5fe507d08309e9815eee50ca73e21bd2bdTheodore Ts'o	blk64_t	ret_blk = *phys_blk;
488cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o
489cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	ret = ext2fs_bmap2(fs, ino, inode, block_buf, bmap_flags, block,
490cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o			    0, &ret_blk);
491cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	if (ret)
492cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		return ret;
493cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	if (ret_blk >= ((long long) 1 << 32))
494cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o		return EOVERFLOW;
495cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	*phys_blk = ret_blk;
496cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o	return 0;
497cc9bf5d246fc23267e14cc328728f146aee142e2Theodore Ts'o}
498