예제 #1
0
파일: ialloc.c 프로젝트: Larhard/hurd
/* Free node NP; the on disk copy has already been synced with
   diskfs_node_update (where NP->dn_stat.st_mode was 0).  It's
   mode used to be OLD_MODE.  */
void
diskfs_free_node (struct node *np, mode_t old_mode)
{
  char *bh;
  unsigned long block_group;
  unsigned long bit;
  struct ext2_group_desc *gdp;
  ino_t inum = np->cache_id;

  assert (!diskfs_readonly);

  ext2_debug ("freeing inode %u", inum);

  pthread_spin_lock (&global_lock);

  if (inum < EXT2_FIRST_INO (sblock) || inum > sblock->s_inodes_count)
    {
      ext2_error ("reserved inode or nonexistent inode: %Ld", inum);
      pthread_spin_unlock (&global_lock);
      return;
    }

  block_group = (inum - 1) / sblock->s_inodes_per_group;
  bit = (inum - 1) % sblock->s_inodes_per_group;

  gdp = group_desc (block_group);
  bh = disk_cache_block_ref (gdp->bg_inode_bitmap);

  if (!clear_bit (bit, bh))
    ext2_warning ("bit already cleared for inode %Ld", inum);
  else
    {
      disk_cache_block_ref_ptr (bh);
      record_global_poke (bh);

      gdp->bg_free_inodes_count++;
      if (S_ISDIR (old_mode))
	gdp->bg_used_dirs_count--;
      disk_cache_block_ref_ptr (gdp);
      record_global_poke (gdp);

      sblock->s_free_inodes_count++;
    }

  disk_cache_block_deref (bh);
  sblock_dirty = 1;
  pthread_spin_unlock (&global_lock);
  alloc_sync(0);
}
예제 #2
0
ino_t
minixfs_new_inode (void)
{
  char *bh = bptr (I_MAP_BOFFS);
  ino_t inum;
  unsigned long bits = sblock->s_ninodes;

  spin_lock (&global_lock);

 repeat:
  inum = find_first_zero_bit ((unsigned long *) bh, bits);
  if (inum < bits)
    {
      assert (sblock_info->s_free_inodes_count > 0);
      minixfs_debug ("eligible bit found at position %Lu", inum);

      if (set_bit (inum, bh))
	{
	  /* shouldn't happen */
	  minixfs_warning ("bit already set for inode %Lu", inum);
	  goto repeat;
	}
      record_global_poke (bh);
    }
  else
    {
      assert (sblock_info->s_free_inodes_count == 0);
      minixfs_debug ("no more free inodes");
      inum = 0;
      goto sync_out;
    }

  if (inum < MINIXFS_FIRST_INO)
    {
      minixfs_error ("reserved inode");
      inum = 0;
      goto sync_out;
    }

  sblock_info->s_free_inodes_count--;

 sync_out:
  spin_unlock (&global_lock);
  alloc_sync (0);

  return inum;
}
예제 #3
0
/* Free node NP; the on disk copy has already been synced with
   diskfs_node_update (where NP->dn_stat.st_mode was 0).  Its
   mode used to be OLD_MODE.  */
void
diskfs_free_node (struct node *np, mode_t old_mode)
{
  char *bh;
  ino_t inum = np->cache_id;
  block_t imap_block;

  assert (!diskfs_readonly);

  spin_lock (&global_lock);

  if (inum < MINIXFS_FIRST_INO || inum > sblock->s_ninodes)
    {
      minixfs_error ("trying to free a reserved or nonexistent inode: %Lu",
		     inum);
      spin_unlock (&global_lock);
      return;
    }

  minixfs_debug ("freeing inode %Lu", inum);

  imap_block = inum >> LOG2_BITS_PER_BLOCK;
  if (imap_block >= sblock->s_imap_blocks) 
    {
      minixfs_error ("nonexistent imap in superblock: %u", imap_block);
      spin_unlock (&global_lock);
      return;
    }
  
  bh = bptr (I_MAP_BOFFS + imap_block);
  if (! clear_bit (inum & (BITS_PER_BLOCK - 1), bh))
    minixfs_warning ("bit already cleared for inode %Lu", inum);
  else
    {
      record_global_poke (bh);
      sblock_info->s_free_inodes_count++;
    }

  spin_unlock (&global_lock);
  alloc_sync (0);
}
예제 #4
0
파일: ialloc.c 프로젝트: Larhard/hurd
/*
 * There are two policies for allocating an inode.  If the new inode is
 * a directory, then a forward search is made for a block group with both
 * free space and a low directory-to-inode ratio; if that fails, then of
 * the groups with above-average free space, that group with the fewest
 * directories already is chosen.
 *
 * For other inodes, search forward from the parent directory\'s block
 * group to find a free inode.
 */
ino_t
ext2_alloc_inode (ino_t dir_inum, mode_t mode)
{
  char *bh = NULL;
  int i, j, avefreei;
  ino_t inum;
  struct ext2_group_desc *gdp;
  struct ext2_group_desc *tmp;

  pthread_spin_lock (&global_lock);

repeat:
  assert (bh == NULL);
  gdp = NULL;
  i = 0;

  if (S_ISDIR (mode))
    {
      avefreei = sblock->s_free_inodes_count / groups_count;

/* I am not yet convinced that this next bit is necessary.
      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 < groups_count; j++)
	    {
	      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))
		    {
		      i = j;
		      gdp = tmp;
		    }
		}
	    }
	}
    }
  else
    {
      /*
       * Try to place the inode in its parent directory
       */
      i = inode_group_num(dir_inum);
      tmp = group_desc (i);
      if (tmp->bg_free_inodes_count)
	gdp = tmp;
      else
	{
	  /*
	   * Use a quadratic hash to find a group with a
	   * free inode
	   */
	  for (j = 1; j < groups_count; j <<= 1)
	    {
	      i += j;
	      if (i >= groups_count)
		i -= groups_count;
	      tmp = group_desc (i);
	      if (tmp->bg_free_inodes_count)
		{
		  gdp = tmp;
		  break;
		}
	    }
	}
      if (!gdp)
	{
	  /*
	   * That failed: try linear search for a free inode
	   */
	  i = inode_group_num(dir_inum) + 1;
	  for (j = 2; j < groups_count; j++)
	    {
	      if (++i >= groups_count)
		i = 0;
	      tmp = group_desc (i);
	      if (tmp->bg_free_inodes_count)
		{
		  gdp = tmp;
		  break;
		}
	    }
	}
    }

  if (!gdp)
    {
      pthread_spin_unlock (&global_lock);
      return 0;
    }

  bh = disk_cache_block_ref (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 (inum, bh))
	{
	  ext2_warning ("bit already set for inode %d", inum);
	  disk_cache_block_deref (bh);
	  bh = NULL;
	  goto repeat;
	}
      record_global_poke (bh);
      bh = NULL;
    }
  else
    {
      disk_cache_block_deref (bh);
      bh = NULL;
      if (gdp->bg_free_inodes_count != 0)
	{
	  ext2_error ("free inodes count corrupted in group %d", i);
	  inum = 0;
	  goto sync_out;
	}
      goto repeat;
    }

  inum += i * sblock->s_inodes_per_group + 1;
  if (inum < EXT2_FIRST_INO (sblock) || inum > sblock->s_inodes_count)
    {
      ext2_error ("reserved inode or inode > inodes count - "
		  "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++;
  disk_cache_block_ref_ptr (gdp);
  record_global_poke (gdp);

  sblock->s_free_inodes_count--;
  sblock_dirty = 1;

 sync_out:
  assert (bh == NULL);
  pthread_spin_unlock (&global_lock);
  alloc_sync (0);

  /* Make sure the coming read_node won't complain about bad
     fields.  */
  {
    struct ext2_inode *di = dino_ref (inum);
    memset (di, 0, sizeof *di);
    dino_deref (di);
  }

  return inum;
}