patch-2.3.9 linux/fs/ext2/inode.c
Next file: linux/fs/ext2/namei.c
Previous file: linux/fs/ext2/fsync.c
Back to the patch index
Back to the overall index
- Lines: 571
- Date:
Sat Jun 26 12:04:39 1999
- Orig file:
v2.3.8/linux/fs/ext2/inode.c
- Orig date:
Sun Jun 20 15:58:20 1999
diff -u --recursive --new-file v2.3.8/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
@@ -129,23 +129,22 @@
return result;
}
-
-int ext2_bmap (struct inode * inode, int block)
+static inline long ext2_block_map (struct inode * inode, long block)
{
int i, ret;
- int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+ int ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+ int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
ret = 0;
lock_kernel();
if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
+ ext2_warning (inode->i_sb, "ext2_block_map", "block < 0");
goto out;
}
- if (block >= EXT2_NDIR_BLOCKS + addr_per_block +
- (1 << (addr_per_block_bits * 2)) +
- ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
- ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
+ if (block >= EXT2_NDIR_BLOCKS + ptrs +
+ (1 << (ptrs_bits * 2)) +
+ ((1 << (ptrs_bits * 2)) << ptrs_bits)) {
+ ext2_warning (inode->i_sb, "ext2_block_map", "block > big");
goto out;
}
if (block < EXT2_NDIR_BLOCKS) {
@@ -153,7 +152,7 @@
goto out;
}
block -= EXT2_NDIR_BLOCKS;
- if (block < addr_per_block) {
+ if (block < ptrs) {
i = inode_bmap (inode, EXT2_IND_BLOCK);
if (!i)
goto out;
@@ -161,122 +160,64 @@
inode->i_sb->s_blocksize), block);
goto out;
}
- block -= addr_per_block;
- if (block < (1 << (addr_per_block_bits * 2))) {
+ block -= ptrs;
+ if (block < (1 << (ptrs_bits * 2))) {
i = inode_bmap (inode, EXT2_DIND_BLOCK);
if (!i)
goto out;
i = block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize),
- block >> addr_per_block_bits);
+ block >> ptrs_bits);
if (!i)
goto out;
ret = block_bmap (bread (inode->i_dev, i,
inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
+ block & (ptrs - 1));
+ goto out;
}
- block -= (1 << (addr_per_block_bits * 2));
+ block -= (1 << (ptrs_bits * 2));
i = inode_bmap (inode, EXT2_TIND_BLOCK);
if (!i)
goto out;
i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block >> (addr_per_block_bits * 2));
+ block >> (ptrs_bits * 2));
if (!i)
goto out;
i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- (block >> addr_per_block_bits) & (addr_per_block - 1));
+ (block >> ptrs_bits) & (ptrs - 1));
if (!i)
goto out;
ret = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
+ block & (ptrs - 1));
out:
unlock_kernel();
return ret;
}
-int ext2_bmap_create (struct inode * inode, int block)
-{
- int i;
- int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
-
- if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_bmap", "block < 0");
- return 0;
- }
- if (block >= EXT2_NDIR_BLOCKS + addr_per_block +
- (1 << (addr_per_block_bits * 2)) +
- ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
- ext2_warning (inode->i_sb, "ext2_bmap", "block > big");
- return 0;
- }
- if (block < EXT2_NDIR_BLOCKS)
- return inode_bmap (inode, block);
- block -= EXT2_NDIR_BLOCKS;
- if (block < addr_per_block) {
- i = inode_bmap (inode, EXT2_IND_BLOCK);
- if (!i)
- return 0;
- return block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize), block);
- }
- block -= addr_per_block;
- if (block < (1 << (addr_per_block_bits * 2))) {
- i = inode_bmap (inode, EXT2_DIND_BLOCK);
- if (!i)
- return 0;
- i = block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize),
- block >> addr_per_block_bits);
- if (!i)
- return 0;
- return block_bmap (bread (inode->i_dev, i,
- inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
- }
- block -= (1 << (addr_per_block_bits * 2));
- i = inode_bmap (inode, EXT2_TIND_BLOCK);
- if (!i)
- return 0;
- i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block >> (addr_per_block_bits * 2));
- if (!i)
- return 0;
- i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- (block >> addr_per_block_bits) & (addr_per_block - 1));
- if (!i)
- return 0;
- return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
- block & (addr_per_block - 1));
-}
-
static struct buffer_head * inode_getblk (struct inode * inode, int nr,
- int create, int new_block, int * err, int metadata,
- int *phys_block, int *created)
+ int new_block, int * err, int metadata, long *phys, int *new)
{
u32 * p;
int tmp, goal = 0;
struct buffer_head * result;
- int blocks = inode->i_sb->s_blocksize / 512;
+ int blocksize = inode->i_sb->s_blocksize;
p = inode->u.ext2_i.i_data + nr;
repeat:
tmp = le32_to_cpu(*p);
if (tmp) {
if (metadata) {
- struct buffer_head * result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+ result = getblk (inode->i_dev, tmp, blocksize);
if (tmp == le32_to_cpu(*p))
return result;
brelse (result);
goto repeat;
} else {
- *phys_block = tmp;
+ *phys = tmp;
return NULL;
}
}
*err = -EFBIG;
- if (!create)
- goto dont_create;
/* Check file limits.. */
{
@@ -285,7 +226,6 @@
limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
if (new_block >= limit) {
send_sig(SIGXFSZ, current, 0);
-dont_create:
*err = -EFBIG;
return NULL;
}
@@ -313,34 +253,41 @@
ext2_debug ("goal = %d.\n", goal);
tmp = ext2_alloc_block (inode, goal, err);
- if (!tmp)
+ if (!tmp) {
+ *err = -ENOSPC;
return NULL;
+ }
if (metadata) {
- result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+ result = getblk (inode->i_dev, tmp, blocksize);
if (*p) {
ext2_free_blocks (inode, tmp, 1);
brelse (result);
goto repeat;
}
- memset(result->b_data, 0, inode->i_sb->s_blocksize);
+ memset(result->b_data, 0, blocksize);
mark_buffer_uptodate(result, 1);
mark_buffer_dirty(result, 1);
} else {
if (*p) {
+ /*
+ * Nobody is allowed to change block allocation
+ * state from under us:
+ */
+ BUG();
ext2_free_blocks (inode, tmp, 1);
goto repeat;
}
- *phys_block = tmp;
+ *phys = tmp;
result = NULL;
*err = 0;
- *created = 1;
+ *new = 1;
}
*p = cpu_to_le32(tmp);
inode->u.ext2_i.i_next_alloc_block = new_block;
inode->u.ext2_i.i_next_alloc_goal = tmp;
inode->i_ctime = CURRENT_TIME;
- inode->i_blocks += blocks;
+ inode->i_blocks += blocksize/512;
if (IS_SYNC(inode) || inode->u.ext2_i.i_osync)
ext2_sync_inode (inode);
else
@@ -357,24 +304,23 @@
* NULL return in the data case is mandatory.
*/
static struct buffer_head * block_getblk (struct inode * inode,
- struct buffer_head * bh, int nr, int create, int blocksize,
- int new_block, int * err, int metadata, int *phys_block, int *created)
+ struct buffer_head * bh, int nr,
+ int new_block, int * err, int metadata, long *phys, int *new)
{
int tmp, goal = 0;
u32 * p;
struct buffer_head * result;
- int blocks = inode->i_sb->s_blocksize / 512;
+ int blocksize = inode->i_sb->s_blocksize;
unsigned long limit;
-
+
+ result = NULL;
if (!bh)
- return NULL;
+ goto out;
if (!buffer_uptodate(bh)) {
ll_rw_block (READ, 1, &bh);
wait_on_buffer (bh);
- if (!buffer_uptodate(bh)) {
- brelse (bh);
- return NULL;
- }
+ if (!buffer_uptodate(bh))
+ goto out;
}
p = (u32 *) bh->b_data + nr;
repeat:
@@ -382,31 +328,24 @@
if (tmp) {
if (metadata) {
result = getblk (bh->b_dev, tmp, blocksize);
- if (tmp == le32_to_cpu(*p)) {
- brelse (bh);
- return result;
- }
+ if (tmp == le32_to_cpu(*p))
+ goto out;
brelse (result);
goto repeat;
} else {
- *phys_block = tmp;
- brelse (bh);
- return NULL;
+ *phys = tmp;
+ /* result == NULL */
+ goto out;
}
}
*err = -EFBIG;
- if (!create) {
- brelse (bh);
- return NULL;
- }
limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
if (limit < RLIM_INFINITY) {
limit >>= EXT2_BLOCK_SIZE_BITS(inode->i_sb);
if (new_block >= limit) {
- brelse (bh);
send_sig(SIGXFSZ, current, 0);
- return NULL;
+ goto out;
}
}
@@ -423,10 +362,8 @@
goal = bh->b_blocknr;
}
tmp = ext2_alloc_block (inode, goal, err);
- if (!tmp) {
- brelse (bh);
- return NULL;
- }
+ if (!tmp)
+ goto out;
if (metadata) {
result = getblk (bh->b_dev, tmp, blocksize);
if (*p) {
@@ -438,12 +375,10 @@
mark_buffer_uptodate(result, 1);
mark_buffer_dirty(result, 1);
} else {
- *phys_block = tmp;
- result = NULL;
- *err = 0;
- *created = 1;
+ *phys = tmp;
+ *new = 1;
}
- if (le32_to_cpu(*p)) {
+ if (*p) {
ext2_free_blocks (inode, tmp, 1);
brelse (result);
goto repeat;
@@ -455,117 +390,162 @@
wait_on_buffer (bh);
}
inode->i_ctime = CURRENT_TIME;
- inode->i_blocks += blocks;
+ inode->i_blocks += blocksize/512;
mark_inode_dirty(inode);
inode->u.ext2_i.i_next_alloc_block = new_block;
inode->u.ext2_i.i_next_alloc_goal = tmp;
+ *err = 0;
+out:
brelse (bh);
return result;
}
-int ext2_getblk_block (struct inode * inode, long block,
- int create, int * err, int * created)
+int ext2_get_block(struct inode *inode, long iblock, struct buffer_head *bh_result, int create)
{
- struct buffer_head * bh, *tmp;
- unsigned long b;
- unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb);
- int addr_per_block_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
- int phys_block, ret;
+ int ret, err, new;
+ struct buffer_head *bh;
+ unsigned long ptr, phys;
+ /*
+ * block pointers per block
+ */
+ unsigned long ptrs = EXT2_ADDR_PER_BLOCK(inode->i_sb);
+ int ptrs_bits = EXT2_ADDR_PER_BLOCK_BITS(inode->i_sb);
+ const int direct_blocks = EXT2_NDIR_BLOCKS,
+ indirect_blocks = ptrs,
+ double_blocks = (1 << (ptrs_bits * 2)),
+ triple_blocks = (1 << (ptrs_bits * 3));
- lock_kernel();
- ret = 0;
- *err = -EIO;
- if (block < 0) {
- ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
- goto abort;
- }
- if (block > EXT2_NDIR_BLOCKS + addr_per_block +
- (1 << (addr_per_block_bits * 2)) +
- ((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
- ext2_warning (inode->i_sb, "ext2_getblk", "block > big");
- goto abort;
+ if (!create) {
+ /*
+ * Will clean this up further, ext2_block_map() should use the
+ * bh instead of an integer block-number interface.
+ */
+ phys = ext2_block_map(inode, iblock);
+ if (phys) {
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped);
+ }
+ return 0;
}
+
+ err = -EIO;
+ new = 0;
+ ret = 0;
+ bh = NULL;
+
+ lock_kernel();
+
+ if (iblock < 0)
+ goto abort_negative;
+ if (iblock > direct_blocks + indirect_blocks +
+ double_blocks + triple_blocks)
+ goto abort_too_big;
+
/*
* If this is a sequential block allocation, set the next_alloc_block
* to this block now so that all the indblock and data block
* allocations use the same goal zone
*/
- ext2_debug ("block %lu, next %lu, goal %lu.\n", block,
+ ext2_debug ("block %lu, next %lu, goal %lu.\n", iblock,
inode->u.ext2_i.i_next_alloc_block,
inode->u.ext2_i.i_next_alloc_goal);
- if (block == inode->u.ext2_i.i_next_alloc_block + 1) {
+ if (iblock == 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++;
}
- *err = 0; // -ENOSPC;
- b = block;
- *created = 0;
- if (block < EXT2_NDIR_BLOCKS) {
- /*
- * data page.
- */
- tmp = inode_getblk (inode, block, create, b,
- err, 0, &phys_block, created);
+ err = 0;
+ ptr = iblock;
+
+ /*
+ * ok, these macros clean the logic up a bit and make
+ * it much more readable:
+ */
+#define GET_INODE_DATABLOCK(x) \
+ inode_getblk(inode, x, iblock, &err, 0, &phys, &new)
+#define GET_INODE_PTR(x) \
+ inode_getblk(inode, x, iblock, &err, 1, NULL, NULL)
+#define GET_INDIRECT_DATABLOCK(x) \
+ block_getblk (inode, bh, x, iblock, &err, 0, &phys, &new);
+#define GET_INDIRECT_PTR(x) \
+ block_getblk (inode, bh, x, iblock, &err, 1, NULL, NULL);
+
+ if (ptr < direct_blocks) {
+ bh = GET_INODE_DATABLOCK(ptr);
goto out;
}
- block -= EXT2_NDIR_BLOCKS;
- if (block < addr_per_block) {
- bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err, 1, NULL, NULL);
- tmp = block_getblk (inode, bh, block, create,
- inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
- goto out;
- }
- block -= addr_per_block;
- if (block < (1 << (addr_per_block_bits * 2))) {
- bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err, 1, NULL, NULL);
- bh = block_getblk (inode, bh, block >> addr_per_block_bits,
- create, inode->i_sb->s_blocksize, b, err, 1, NULL, NULL);
- tmp = block_getblk (inode, bh, block & (addr_per_block - 1),
- create, inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
- goto out;
- }
- block -= (1 << (addr_per_block_bits * 2));
- bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err, 1, NULL,NULL);
- bh = block_getblk (inode, bh, block >> (addr_per_block_bits * 2),
- create, inode->i_sb->s_blocksize, b, err, 1, NULL,NULL);
- bh = block_getblk (inode, bh, (block >> addr_per_block_bits) &
- (addr_per_block - 1), create, inode->i_sb->s_blocksize,
- b, err, 1, NULL,NULL);
- tmp = block_getblk (inode, bh, block & (addr_per_block - 1), create,
- inode->i_sb->s_blocksize, b, err, 0, &phys_block, created);
+ ptr -= direct_blocks;
+ if (ptr < indirect_blocks) {
+ bh = GET_INODE_PTR(EXT2_IND_BLOCK);
+ goto get_indirect;
+ }
+ ptr -= indirect_blocks;
+ if (ptr < double_blocks) {
+ bh = GET_INODE_PTR(EXT2_DIND_BLOCK);
+ goto get_double;
+ }
+ ptr -= double_blocks;
+ bh = GET_INODE_PTR(EXT2_TIND_BLOCK);
+ bh = GET_INDIRECT_PTR(ptr >> (ptrs_bits * 2));
+get_double:
+ bh = GET_INDIRECT_PTR((ptr >> ptrs_bits) & (ptrs - 1));
+get_indirect:
+ bh = GET_INDIRECT_DATABLOCK(ptr & (ptrs - 1));
+
+#undef GET_INODE_DATABLOCK
+#undef GET_INODE_PTR
+#undef GET_INDIRECT_DATABLOCK
+#undef GET_INDIRECT_PTR
out:
- if (!phys_block)
+ if (bh)
+ BUG(); // temporary debugging check
+ if (err)
goto abort;
- if (*err)
- goto abort;
- ret = phys_block;
+ if (!phys)
+ BUG(); // must not happen either
+
+ bh_result->b_dev = inode->i_dev;
+ bh_result->b_blocknr = phys;
+ bh_result->b_state |= (1UL << BH_Mapped); /* safe */
+ if (new)
+ bh_result->b_state |= (1UL << BH_New);
abort:
unlock_kernel();
- return ret;
+ return err;
+
+abort_negative:
+ ext2_warning (inode->i_sb, "ext2_get_block", "block < 0");
+ goto abort;
+
+abort_too_big:
+ ext2_warning (inode->i_sb, "ext2_get_block", "block > big");
+ goto abort;
}
-struct buffer_head * ext2_getblk (struct inode * inode, long block,
- int create, int * err)
+struct buffer_head * ext2_getblk(struct inode * inode, long block, int create, int * err)
{
- struct buffer_head *tmp = NULL;
- int phys_block;
- int created;
-
- phys_block = ext2_getblk_block (inode, block, create, err, &created);
+ struct buffer_head dummy;
+ int error;
- if (phys_block) {
- tmp = getblk (inode->i_dev, phys_block, inode->i_sb->s_blocksize);
- if (created) {
- memset(tmp->b_data, 0, inode->i_sb->s_blocksize);
- mark_buffer_uptodate(tmp, 1);
- mark_buffer_dirty(tmp, 1);
+ dummy.b_state = 0;
+ dummy.b_blocknr = -1000;
+ error = ext2_get_block(inode, block, &dummy, create);
+ *err = error;
+ if (!error && buffer_mapped(&dummy)) {
+ struct buffer_head *bh;
+ bh = getblk(dummy.b_dev, dummy.b_blocknr, inode->i_sb->s_blocksize);
+ if (buffer_new(&dummy)) {
+ memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+ mark_buffer_uptodate(bh, 1);
+ mark_buffer_dirty(bh, 1);
}
+ return bh;
}
- return tmp;
+ return NULL;
}
struct buffer_head * ext2_bread (struct inode * inode, int block,
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)