patch-2.3.7 linux/fs/ext2/inode.c
Next file: linux/fs/ext2/symlink.c
Previous file: linux/fs/ext2/fsync.c
Back to the patch index
Back to the overall index
- Lines: 434
- Date:
Sun Jun 20 15:58:20 1999
- Orig file:
v2.3.6/linux/fs/ext2/inode.c
- Orig date:
Tue May 11 23:01:41 1999
diff -u --recursive --new-file v2.3.6/linux/fs/ext2/inode.c linux/fs/ext2/inode.c
@@ -31,6 +31,7 @@
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/mm.h>
+#include <linux/smp_lock.h>
static int ext2_update_inode(struct inode * inode, int do_sync);
@@ -59,7 +60,7 @@
ext2_free_inode (inode);
}
-#define inode_bmap(inode, nr) ((inode)->u.ext2_i.i_data[(nr)])
+#define inode_bmap(inode, nr) (le32_to_cpu((inode)->u.ext2_i.i_data[(nr)]))
static inline int block_bmap (struct buffer_head * bh, int nr)
{
@@ -92,13 +93,12 @@
#endif
}
-static int ext2_alloc_block (struct inode * inode, unsigned long goal, int * err)
+static int ext2_alloc_block (struct inode * inode, unsigned long goal, int *err)
{
#ifdef EXT2FS_DEBUG
static unsigned long alloc_hits = 0, alloc_attempts = 0;
#endif
unsigned long result;
- struct buffer_head * bh;
wait_on_super (inode->i_sb);
@@ -112,19 +112,6 @@
ext2_debug ("preallocation hit (%lu/%lu).\n",
++alloc_hits, ++alloc_attempts);
- /* It doesn't matter if we block in getblk() since
- we have already atomically allocated the block, and
- are only clearing it now. */
- if (!(bh = getblk (inode->i_sb->s_dev, result,
- inode->i_sb->s_blocksize))) {
- ext2_error (inode->i_sb, "ext2_alloc_block",
- "cannot get block %lu", result);
- return 0;
- }
- memset(bh->b_data, 0, inode->i_sb->s_blocksize);
- mark_buffer_uptodate(bh, 1);
- mark_buffer_dirty(bh, 1);
- brelse (bh);
} else {
ext2_discard_prealloc (inode);
ext2_debug ("preallocation miss (%lu/%lu).\n",
@@ -139,13 +126,76 @@
#else
result = ext2_new_block (inode, goal, 0, 0, err);
#endif
-
return result;
}
int ext2_bmap (struct inode * inode, int 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);
+
+ ret = 0;
+ lock_kernel();
+ if (block < 0) {
+ ext2_warning (inode->i_sb, "ext2_bmap", "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");
+ goto out;
+ }
+ if (block < EXT2_NDIR_BLOCKS) {
+ ret = inode_bmap (inode, block);
+ goto out;
+ }
+ block -= EXT2_NDIR_BLOCKS;
+ if (block < addr_per_block) {
+ i = inode_bmap (inode, EXT2_IND_BLOCK);
+ if (!i)
+ goto out;
+ ret = block_bmap (bread (inode->i_dev, i,
+ inode->i_sb->s_blocksize), block);
+ goto out;
+ }
+ block -= addr_per_block;
+ if (block < (1 << (addr_per_block_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);
+ if (!i)
+ goto out;
+ ret = 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)
+ goto out;
+ i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
+ block >> (addr_per_block_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));
+ if (!i)
+ goto out;
+ ret = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
+ block & (addr_per_block - 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);
@@ -201,7 +251,8 @@
}
static struct buffer_head * inode_getblk (struct inode * inode, int nr,
- int create, int new_block, int * err)
+ int create, int new_block, int * err, int metadata,
+ int *phys_block, int *created)
{
u32 * p;
int tmp, goal = 0;
@@ -210,13 +261,18 @@
p = inode->u.ext2_i.i_data + nr;
repeat:
- tmp = *p;
+ tmp = le32_to_cpu(*p);
if (tmp) {
- struct buffer_head * result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (tmp == *p)
- return result;
- brelse (result);
- goto repeat;
+ if (metadata) {
+ struct buffer_head * result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+ if (tmp == le32_to_cpu(*p))
+ return result;
+ brelse (result);
+ goto repeat;
+ } else {
+ *phys_block = tmp;
+ return NULL;
+ }
}
*err = -EFBIG;
if (!create)
@@ -244,7 +300,7 @@
if (!goal) {
for (tmp = nr - 1; tmp >= 0; tmp--) {
if (inode->u.ext2_i.i_data[tmp]) {
- goal = inode->u.ext2_i.i_data[tmp];
+ goal = le32_to_cpu(inode->u.ext2_i.i_data[tmp]);
break;
}
}
@@ -259,13 +315,28 @@
tmp = ext2_alloc_block (inode, goal, err);
if (!tmp)
return NULL;
- result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
- if (*p) {
- ext2_free_blocks (inode, tmp, 1);
- brelse (result);
- goto repeat;
+ if (metadata) {
+ result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+ if (*p) {
+ ext2_free_blocks (inode, tmp, 1);
+ brelse (result);
+ goto repeat;
+ }
+ memset(result->b_data, 0, inode->i_sb->s_blocksize);
+ mark_buffer_uptodate(result, 1);
+ mark_buffer_dirty(result, 1);
+ } else {
+ if (*p) {
+ ext2_free_blocks (inode, tmp, 1);
+ goto repeat;
+ }
+ *phys_block = tmp;
+ result = NULL;
+ *err = 0;
+ *created = 1;
}
- *p = tmp;
+ *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;
@@ -277,10 +348,17 @@
return result;
}
+/*
+ * metadata / data
+ * possibly create / access
+ * can fail due to: - not present
+ * - out of space
+ *
+ * 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)
+ struct buffer_head * bh, int nr, int create, int blocksize,
+ int new_block, int * err, int metadata, int *phys_block, int *created)
{
int tmp, goal = 0;
u32 * p;
@@ -302,13 +380,19 @@
repeat:
tmp = le32_to_cpu(*p);
if (tmp) {
- result = getblk (bh->b_dev, tmp, blocksize);
- if (tmp == le32_to_cpu(*p)) {
+ if (metadata) {
+ result = getblk (bh->b_dev, tmp, blocksize);
+ if (tmp == le32_to_cpu(*p)) {
+ brelse (bh);
+ return result;
+ }
+ brelse (result);
+ goto repeat;
+ } else {
+ *phys_block = tmp;
brelse (bh);
- return result;
+ return NULL;
}
- brelse (result);
- goto repeat;
}
*err = -EFBIG;
if (!create) {
@@ -343,7 +427,22 @@
brelse (bh);
return NULL;
}
- result = getblk (bh->b_dev, tmp, blocksize);
+ if (metadata) {
+ result = getblk (bh->b_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);
+ mark_buffer_uptodate(result, 1);
+ mark_buffer_dirty(result, 1);
+ } else {
+ *phys_block = tmp;
+ result = NULL;
+ *err = 0;
+ *created = 1;
+ }
if (le32_to_cpu(*p)) {
ext2_free_blocks (inode, tmp, 1);
brelse (result);
@@ -364,24 +463,27 @@
return result;
}
-struct buffer_head * ext2_getblk (struct inode * inode, long block,
- int create, int * err)
+int ext2_getblk_block (struct inode * inode, long block,
+ int create, int * err, int * created)
{
- struct buffer_head * bh;
+ 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;
+ lock_kernel();
+ ret = 0;
*err = -EIO;
if (block < 0) {
ext2_warning (inode->i_sb, "ext2_getblk", "block < 0");
- return NULL;
+ 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");
- return NULL;
+ goto abort;
}
/*
* If this is a sequential block allocation, set the next_alloc_block
@@ -398,32 +500,72 @@
inode->u.ext2_i.i_next_alloc_goal++;
}
- *err = -ENOSPC;
+ *err = 0; // -ENOSPC;
b = block;
- if (block < EXT2_NDIR_BLOCKS)
- return inode_getblk (inode, block, create, b, err);
+ *created = 0;
+ if (block < EXT2_NDIR_BLOCKS) {
+ /*
+ * data page.
+ */
+ tmp = inode_getblk (inode, block, create, b,
+ err, 0, &phys_block, created);
+ goto out;
+ }
block -= EXT2_NDIR_BLOCKS;
if (block < addr_per_block) {
- bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err);
- return block_getblk (inode, bh, block, create,
- inode->i_sb->s_blocksize, b, err);
+ 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);
+ 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);
- return block_getblk (inode, bh, block & (addr_per_block - 1),
- create, inode->i_sb->s_blocksize, b, err);
+ 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);
+ 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);
- bh = block_getblk (inode, bh, (block >> addr_per_block_bits) & (addr_per_block - 1),
- create, inode->i_sb->s_blocksize, b, err);
- return block_getblk (inode, bh, block & (addr_per_block - 1), create,
- inode->i_sb->s_blocksize, b, err);
+ 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);
+
+out:
+ if (!phys_block)
+ goto abort;
+ if (*err)
+ goto abort;
+ ret = phys_block;
+abort:
+ unlock_kernel();
+ return ret;
+}
+
+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);
+
+ 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);
+ }
+ }
+ return tmp;
}
struct buffer_head * ext2_bread (struct inode * inode, int block,
@@ -569,11 +711,14 @@
if (inode->u.ext2_i.i_prealloc_count)
ext2_error (inode->i_sb, "ext2_read_inode",
"New inode has non-zero prealloc count!");
- if (S_ISLNK(inode->i_mode) && !inode->i_blocks)
- for (block = 0; block < EXT2_N_BLOCKS; block++)
- inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
- else for (block = 0; block < EXT2_N_BLOCKS; block++)
- inode->u.ext2_i.i_data[block] = le32_to_cpu(raw_inode->i_block[block]);
+
+ /*
+ * NOTE! The in-memory inode i_blocks array is in little-endian order
+ * even on big-endian machines: we do NOT byteswap the block numbers!
+ */
+ for (block = 0; block < EXT2_N_BLOCKS; block++)
+ inode->u.ext2_i.i_data[block] = raw_inode->i_block[block];
+
if (inode->i_ino == EXT2_ACL_IDX_INO ||
inode->i_ino == EXT2_ACL_DATA_INO)
/* Nothing to do */ ;
@@ -689,11 +834,8 @@
raw_inode->i_generation = cpu_to_le32(inode->i_generation);
if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
- else if (S_ISLNK(inode->i_mode) && !inode->i_blocks)
- for (block = 0; block < EXT2_N_BLOCKS; block++)
- raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
else for (block = 0; block < EXT2_N_BLOCKS; block++)
- raw_inode->i_block[block] = cpu_to_le32(inode->u.ext2_i.i_data[block]);
+ raw_inode->i_block[block] = inode->u.ext2_i.i_data[block];
mark_buffer_dirty(bh, 1);
if (do_sync) {
ll_rw_block (WRITE, 1, &bh);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)