summaryrefslogtreecommitdiff
path: root/ext2fs/ialloc.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext2fs/ialloc.c')
-rw-r--r--ext2fs/ialloc.c354
1 files changed, 168 insertions, 186 deletions
diff --git a/ext2fs/ialloc.c b/ext2fs/ialloc.c
index 686c6662..dcc73c8c 100644
--- a/ext2fs/ialloc.c
+++ b/ext2fs/ialloc.c
@@ -1,5 +1,8 @@
-/*
- * Largely stolen from: linux/fs/ext2/ialloc.c
+/* Inode allocation routines.
+ *
+ * Converted to work under the hurd by Miles Bader <miles@gnu.ai.mit.edu>
+ *
+ * Largely stolen from linux/fs/ext2/ialloc.c
*
* Copyright (C) 1992, 1993, 1994, 1995
* Remy Card (card@masi.ibp.fr)
@@ -11,10 +14,6 @@
*/
/*
- * ialloc.c contains the inodes allocation and deallocation routines
- */
-
-/*
* The free inodes are managed by bitmaps. A file system contains several
* blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap
* block for inodes, N blocks for the inode table and data blocks.
@@ -26,63 +25,55 @@
*/
#include "ext2fs.h"
+
+/* ---------------------------------------------------------------- */
void
-ext2_free_inode (struct inode *inode)
+ext2_free_inode (struct node *node, mode_t old_mode)
{
char *bh;
- char *bh2;
unsigned long block_group;
unsigned long bit;
struct ext2_group_desc *gdp;
ino_t inum = node->dn->number;
- if (!inode)
- return;
+ ext2_debug ("freeing inode %lu\n", inum);
- ext2_debug ("freeing inode %lu\n", inode->i_ino);
+ spin_lock (&sblock_lock);
- lock_super (sb);
- if (inum < EXT2_FIRST_INO ||
- inum > sb->u.ext2_sb.s_es->s_inodes_count)
+ if (inum < EXT2_FIRST_INO || inum > sblock->s_inodes_count)
{
- ext2_error (sb, "free_inode",
- "reserved inode or nonexistent inode");
- unlock_super (sb);
+ ext2_error ("free_inode", "reserved inode or nonexistent inode");
+ spin_unlock (&sblock_lock);
return;
}
- es = sb->u.ext2_sb.s_es;
- block_group = (inum - 1) / EXT2_INODES_PER_GROUP (sb);
- bit = (inum - 1) % EXT2_INODES_PER_GROUP (sb);
- bitmap_nr = load_inode_bitmap (sb, block_group);
- bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
+
+ block_group = (inum - 1) / sblock->s_inodes_per_group;
+ bit = (inum - 1) % sblock->s_inodes_per_group;
+
+ gdp = group_desc (glock_group);
+ bh = baddr (gdb->bg_inode_bitmap);
+
if (!clear_bit (bit, bh))
- ext2_warning (sb, "ext2_free_inode",
- "bit already cleared for inode %lu", inum);
+ ext2_warning ("ext2_free_inode", "bit already cleared for inode %u", inum);
else
{
- gdp = get_group_desc (sb, block_group, &bh2);
+ record_poke (bh, block_size);
+
gdp->bg_free_inodes_count++;
- if (S_ISDIR (inode->i_mode))
+ if (S_ISDIR (old_mode))
gdp->bg_used_dirs_count--;
- mark_buffer_dirty (bh2, 1);
- es->s_free_inodes_count++;
- mark_buffer_dirty (sb->u.ext2_sb.s_sbh, 1);
-#if 0
- set_inode_dtime (inode, gdp);
-#endif
- }
- mark_buffer_dirty (bh, 1);
- if (sb->s_flags & MS_SYNCHRONOUS)
- {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
+ record_poke (gdp, sizeof *gdp);
+
+ sblock->s_free_inodes_count++;
}
- sb->s_dirt = 1;
- clear_inode (inode);
- unlock_super (sb);
+ sblock_dirty = 1;
+ spin_unlock (&sblock_lock);
+ alloc_sync(0);
}
+
+/* ---------------------------------------------------------------- */
/*
* There are two policies for allocating an inode. If the new inode is
@@ -94,58 +85,49 @@ ext2_free_inode (struct inode *inode)
* For other inodes, search forward from the parent directory\'s block
* group to find a free inode.
*/
-struct inode *
-ext2_new_inode (const struct inode *dir, int mode)
+ino_t
+ext2_alloc_inode (ino_t dir_inum, mode_t mode)
{
- struct super_block *sb;
char *bh;
- char *bh2;
- int i, j, avefreei;
- struct inode *inode;
- int bitmap_nr;
+ int i, j, inum, avefreei;
struct ext2_group_desc *gdp;
struct ext2_group_desc *tmp;
- struct ext2_super_block *es;
- if (!dir || !(inode = get_empty_inode ()))
- return NULL;
- sb = dir->i_sb;
- inode->i_sb = sb;
- inode->i_flags = sb->s_flags;
- lock_super (sb);
- es = sb->u.ext2_sb.s_es;
+ spin_lock (&sblock_lock);
+
repeat:
gdp = NULL;
i = 0;
if (S_ISDIR (mode))
{
- avefreei = es->s_free_inodes_count /
- sb->u.ext2_sb.s_groups_count;
+ avefreei = sblock->s_free_inodes_count / groups_count;
+
/* I am not yet convinced that this next bit is necessary.
- i = dir->u.ext2_i.i_block_group;
- for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
- tmp = get_group_desc (sb, i, &bh2);
- if ((tmp->bg_used_dirs_count << 8) <
- tmp->bg_free_inodes_count) {
- gdp = tmp;
- break;
- }
- else
- i = ++i % sb->u.ext2_sb.s_groups_count;
- }
+ i = inode_group_num(dir_inum);
+ for (j = 0; j < groups_count; j++)
+ {
+ tmp = group_desc (i);
+ if ((tmp->bg_used_dirs_count << 8) < tmp->bg_free_inodes_count)
+ {
+ gdp = tmp;
+ break;
+ }
+ else
+ i = ++i % groups_count;
+ }
*/
+
if (!gdp)
{
- for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++)
+ for (j = 0; j < groups_count; j++)
{
- tmp = get_group_desc (sb, j, &bh2);
- if (tmp->bg_free_inodes_count &&
- tmp->bg_free_inodes_count >= avefreei)
+ tmp = group_desc (j);
+ if (tmp->bg_free_inodes_count
+ && tmp->bg_free_inodes_count >= avefreei)
{
if (!gdp ||
- (tmp->bg_free_blocks_count >
- gdp->bg_free_blocks_count))
+ (tmp->bg_free_blocks_count > gdp->bg_free_blocks_count))
{
i = j;
gdp = tmp;
@@ -159,8 +141,8 @@ repeat:
/*
* Try to place the inode in its parent directory
*/
- i = dir->u.ext2_i.i_block_group;
- tmp = get_group_desc (sb, i, &bh2);
+ i = inode_group_num(dir_inum);
+ tmp = group_desc (i);
if (tmp->bg_free_inodes_count)
gdp = tmp;
else
@@ -169,12 +151,12 @@ repeat:
* Use a quadratic hash to find a group with a
* free inode
*/
- for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1)
+ for (j = 1; j < groups_count; j <<= 1)
{
i += j;
- if (i >= sb->u.ext2_sb.s_groups_count)
- i -= sb->u.ext2_sb.s_groups_count;
- tmp = get_group_desc (sb, i, &bh2);
+ if (i >= groups_count)
+ i -= groups_count;
+ tmp = group_desc (i);
if (tmp->bg_free_inodes_count)
{
gdp = tmp;
@@ -187,12 +169,12 @@ repeat:
/*
* That failed: try linear search for a free inode
*/
- i = dir->u.ext2_i.i_block_group + 1;
- for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++)
+ i = inode_group_num(dir_inum) + 1;
+ for (j = 2; j < groups_count; j++)
{
- if (++i >= sb->u.ext2_sb.s_groups_count)
+ if (++i >= groups_count)
i = 0;
- tmp = get_group_desc (sb, i, &bh2);
+ tmp = group_desc (i);
if (tmp->bg_free_inodes_count)
{
gdp = tmp;
@@ -204,101 +186,105 @@ repeat:
if (!gdp)
{
- unlock_super (sb);
- iput (inode);
- return NULL;
+ spin_unlock (&sblock_lock);
+ return 0;
}
- bitmap_nr = load_inode_bitmap (sb, i);
- bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
- if ((j = find_first_zero_bit ((unsigned long *) bh,
- EXT2_INODES_PER_GROUP (sb))) <
- EXT2_INODES_PER_GROUP (sb))
+
+ bh = gdp->bg_inode_bitmap;
+ if ((inum =
+ find_first_zero_bit ((unsigned long *) bh, sblock->s_inodes_per_group))
+ < sblock->s_inodes_per_group)
{
- if (set_bit (j, bh))
+ if (set_bit (inum, bh))
{
- ext2_warning (sb, "ext2_new_inode",
- "bit already set for inode %d", j);
+ ext2_warning ("ext2_new_inode",
+ "bit already set for inode %d", inum);
goto repeat;
}
- mark_buffer_dirty (bh, 1);
- if (sb->s_flags & MS_SYNCHRONOUS)
- {
- ll_rw_block (WRITE, 1, &bh);
- wait_on_buffer (bh);
- }
+ record_poke (bh, block_size);
}
else
{
if (gdp->bg_free_inodes_count != 0)
{
- ext2_error (sb, "ext2_new_inode",
- "Free inodes count corrupted in group %d",
- i);
- unlock_super (sb);
- iput (inode);
- return NULL;
+ ext2_error ("ext2_new_inode",
+ "Free inodes count corrupted in group %d", i);
+ inum = 0;
+ goto sync_out;
}
goto repeat;
}
- j += i * EXT2_INODES_PER_GROUP (sb) + 1;
- if (j < EXT2_FIRST_INO || j > es->s_inodes_count)
+
+ inum += i * sblock->s_inodes_per_group + 1;
+ if (inum < EXT2_FIRST_INO || inum > sblock->s_inodes_count)
{
- ext2_error (sb, "ext2_new_inode",
+ ext2_error ("ext2_new_inode",
"reserved inode or inode > inodes count - "
- "block_group = %d,inode=%d", i, j);
- unlock_super (sb);
- iput (inode);
- return NULL;
+ "block_group = %d,inode=%d", i, inum);
+ inum = 0;
+ goto sync_out;
}
+
gdp->bg_free_inodes_count--;
if (S_ISDIR (mode))
gdp->bg_used_dirs_count++;
- mark_buffer_dirty (bh2, 1);
- es->s_free_inodes_count--;
- mark_buffer_dirty (sb->u.ext2_sb.s_sbh, 1);
- sb->s_dirt = 1;
- inode->i_mode = mode;
- inode->i_sb = sb;
- inode->i_count = 1;
- inode->i_nlink = 1;
- inode->i_dev = sb->s_dev;
- inode->i_uid = current->fsuid;
- if (test_opt (sb, GRPID))
- inode->i_gid = dir->i_gid;
- else if (dir->i_mode & S_ISGID)
+ record_poke (gdp, sizeof *gdp);
+
+ sblock->s_free_inodes_count--;
+ sblock_dirty = 1;
+
+ sync_out:
+ spin_unlock (&sblock_lock);
+ alloc_sync (0);
+
+ return inum;
+}
+
+/* ---------------------------------------------------------------- */
+
+error_t
+diskfs_alloc_node (const struct node *dir, int mode, struct node **node)
+{
+ int sex;
+ struct node *np;
+ ino_t inum = ext2_alloc_inode (dir->dn->number, mode);
+
+ if (inum == 0)
+ return ENOSPC;
+
+ err = iget (inum, &np);
+ if (err)
+ return err;
+
+ if (np->dn_stat.st_mode)
+ ext2_panic("Duplicate inode: %d", inum);
+
+ if (np->dn_stat.st_blocks)
{
- inode->i_gid = dir->i_gid;
- if (S_ISDIR (mode))
- mode |= S_ISGID;
+ ext2_warning("Free inode %d had %d blocks", inum, np->dn_stat.st_blocks);
+ np->dn_stat.st_blocks = 0;
+ np->dn_set_ctime = 1;
}
- else
- inode->i_gid = current->fsgid;
- inode->i_dirt = 1;
- node->dn->number = j;
- inode->i_blksize = sb->s_blocksize;
- inode->i_blocks = 0;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags;
- if (S_ISLNK (mode))
- inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL | EXT2_APPEND_FL);
- inode->u.ext2_i.i_faddr = 0;
- inode->u.ext2_i.i_frag_no = 0;
- inode->u.ext2_i.i_frag_size = 0;
- inode->u.ext2_i.i_file_acl = 0;
- inode->u.ext2_i.i_dir_acl = 0;
- inode->u.ext2_i.i_dtime = 0;
- inode->u.ext2_i.i_block_group = i;
- inode->i_op = NULL;
- if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
- inode->i_flags |= MS_SYNCHRONOUS;
- insert_inode_hash (inode);
- inc_inode_version (inode, gdp, mode);
-
- ext2_debug ("allocating inode %lu\n", node->dn->number);
-
- unlock_super (sb);
- return inode;
+
+ np->dn_stat.st_flags = 0;
+
+ /*
+ * Set up a new generation number for this inode.
+ */
+ spin_lock (&gennumberlock);
+ sex = diskfs_mtime->seconds;
+ if (++nextgennumber < (u_long)sex)
+ nextgennumber = sex;
+ np->dn_stat.st_gen = nextgennumber;
+ spin_unlock (&gennumberlock);
+
+ alloc_sync (np);
+
+ *node = np;
+ return 0;
}
+
+/* ---------------------------------------------------------------- */
unsigned long
ext2_count_free_inodes (struct super_block *sb)
@@ -310,63 +296,59 @@ ext2_count_free_inodes (struct super_block *sb)
struct ext2_group_desc *gdp;
int i;
- lock_super (sb);
- es = sb->u.ext2_sb.s_es;
+ spin_lock (&sblock_lock);
+
desc_count = 0;
bitmap_count = 0;
gdp = NULL;
- for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++)
+ for (i = 0; i < groups_count; i++)
{
- gdp = get_group_desc (sb, i, NULL);
+ gdp = group_desc (i);
desc_count += gdp->bg_free_inodes_count;
- bitmap_nr = load_inode_bitmap (sb, i);
- x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
- EXT2_INODES_PER_GROUP (sb) / 8);
- printk ("group %d: stored = %d, counted = %lu\n",
- i, gdp->bg_free_inodes_count, x);
+ x = ext2_count_free (gdp->bg_inode_bitmap, sblock->s_inodes_per_group / 8);
+ printf ("group %d: stored = %d, counted = %lu\n", i, gdp->bg_free_inodes_count, x);
bitmap_count += x;
}
- printk ("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
- es->s_free_inodes_count, desc_count, bitmap_count);
- unlock_super (sb);
+ printf ("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
+ sblock->s_free_inodes_count, desc_count, bitmap_count);
+ spin_unlock (&sblock_lock);
return desc_count;
#else
- return sb->u.ext2_sb.s_es->s_free_inodes_count;
+ return sblock->s_free_inodes_count;
#endif
}
+
+/* ---------------------------------------------------------------- */
void
ext2_check_inodes_bitmap (struct super_block *sb)
{
- struct ext2_super_block *es;
- unsigned long desc_count, bitmap_count, x;
- int bitmap_nr;
- struct ext2_group_desc *gdp;
int i;
+ struct ext2_group_desc *gdp;
+ unsigned long desc_count, bitmap_count, x;
+
+ spin_lock (&sblock_lock);
- lock_super (sb);
- es = sb->u.ext2_sb.s_es;
desc_count = 0;
bitmap_count = 0;
gdp = NULL;
- for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++)
+ for (i = 0; i < groups_count; i++)
{
gdp = get_group_desc (sb, i, NULL);
desc_count += gdp->bg_free_inodes_count;
- bitmap_nr = load_inode_bitmap (sb, i);
- x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
- EXT2_INODES_PER_GROUP (sb) / 8);
+ x = ext2_count_free (gdp->bg_inode_bitmap, sblock->s_inodes_per_group / 8);
if (gdp->bg_free_inodes_count != x)
- ext2_error (sb, "ext2_check_inodes_bitmap",
+ ext2_error ("ext2_check_inodes_bitmap",
"Wrong free inodes count in group %d, "
"stored = %d, counted = %lu", i,
gdp->bg_free_inodes_count, x);
bitmap_count += x;
}
- if (es->s_free_inodes_count != bitmap_count)
- ext2_error (sb, "ext2_check_inodes_bitmap",
+ if (sblock->s_free_inodes_count != bitmap_count)
+ ext2_error ("ext2_check_inodes_bitmap",
"Wrong free inodes count in super block, "
"stored = %lu, counted = %lu",
- (unsigned long) es->s_free_inodes_count, bitmap_count);
- unlock_super (sb);
+ (unsigned long) sblock->s_free_inodes_count, bitmap_count);
+
+ spin_unlock (&sblock_lock);
}