OpenCores
URL https://opencores.org/ocsvn/or1k_old/or1k_old/trunk

Subversion Repositories or1k_old

[/] [or1k_old/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [ext2/] [ialloc.c] - Diff between revs 1765 and 1782

Only display areas with differences | Details | Blame | View Log

Rev 1765 Rev 1782
/*
/*
 *  linux/fs/ext2/ialloc.c
 *  linux/fs/ext2/ialloc.c
 *
 *
 * Copyright (C) 1992, 1993, 1994, 1995
 * Copyright (C) 1992, 1993, 1994, 1995
 * Remy Card (card@masi.ibp.fr)
 * Remy Card (card@masi.ibp.fr)
 * Laboratoire MASI - Institut Blaise Pascal
 * Laboratoire MASI - Institut Blaise Pascal
 * Universite Pierre et Marie Curie (Paris VI)
 * Universite Pierre et Marie Curie (Paris VI)
 *
 *
 *  BSD ufs-inspired inode and directory allocation by
 *  BSD ufs-inspired inode and directory allocation by
 *  Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
 *  Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
 *  Big-endian to little-endian byte-swapping/bitmaps by
 *  Big-endian to little-endian byte-swapping/bitmaps by
 *        David S. Miller (davem@caip.rutgers.edu), 1995
 *        David S. Miller (davem@caip.rutgers.edu), 1995
 */
 */
 
 
/*
/*
 * ialloc.c contains the inodes allocation and deallocation routines
 * ialloc.c contains the inodes allocation and deallocation routines
 */
 */
 
 
/*
/*
 * The free inodes are managed by bitmaps.  A file system contains several
 * The free inodes are managed by bitmaps.  A file system contains several
 * blocks groups.  Each group contains 1 bitmap block for blocks, 1 bitmap
 * blocks groups.  Each group contains 1 bitmap block for blocks, 1 bitmap
 * block for inodes, N blocks for the inode table and data blocks.
 * block for inodes, N blocks for the inode table and data blocks.
 *
 *
 * The file system contains group descriptors which are located after the
 * The file system contains group descriptors which are located after the
 * super block.  Each descriptor contains the number of the bitmap block and
 * super block.  Each descriptor contains the number of the bitmap block and
 * the free blocks count in the block.  The descriptors are loaded in memory
 * the free blocks count in the block.  The descriptors are loaded in memory
 * when a file system is mounted (see ext2_read_super).
 * when a file system is mounted (see ext2_read_super).
 */
 */
 
 
#include <linux/fs.h>
#include <linux/fs.h>
#include <linux/ext2_fs.h>
#include <linux/ext2_fs.h>
#include <linux/sched.h>
#include <linux/sched.h>
#include <linux/stat.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/string.h>
#include <linux/locks.h>
#include <linux/locks.h>
 
 
#include <asm/bitops.h>
#include <asm/bitops.h>
#include <asm/byteorder.h>
#include <asm/byteorder.h>
 
 
static struct ext2_group_desc * get_group_desc (struct super_block * sb,
static struct ext2_group_desc * get_group_desc (struct super_block * sb,
                                                unsigned int block_group,
                                                unsigned int block_group,
                                                struct buffer_head ** bh)
                                                struct buffer_head ** bh)
{
{
        unsigned long group_desc;
        unsigned long group_desc;
        unsigned long desc;
        unsigned long desc;
        struct ext2_group_desc * gdp;
        struct ext2_group_desc * gdp;
 
 
        if (block_group >= sb->u.ext2_sb.s_groups_count)
        if (block_group >= sb->u.ext2_sb.s_groups_count)
                ext2_panic (sb, "get_group_desc",
                ext2_panic (sb, "get_group_desc",
                            "block_group >= groups_count - "
                            "block_group >= groups_count - "
                            "block_group = %d, groups_count = %lu",
                            "block_group = %d, groups_count = %lu",
                            block_group, sb->u.ext2_sb.s_groups_count);
                            block_group, sb->u.ext2_sb.s_groups_count);
 
 
        group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
        group_desc = block_group / EXT2_DESC_PER_BLOCK(sb);
        desc = block_group % EXT2_DESC_PER_BLOCK(sb);
        desc = block_group % EXT2_DESC_PER_BLOCK(sb);
        if (!sb->u.ext2_sb.s_group_desc[group_desc])
        if (!sb->u.ext2_sb.s_group_desc[group_desc])
                ext2_panic (sb, "get_group_desc",
                ext2_panic (sb, "get_group_desc",
                            "Group descriptor not loaded - "
                            "Group descriptor not loaded - "
                            "block_group = %d, group_desc = %lu, desc = %lu",
                            "block_group = %d, group_desc = %lu, desc = %lu",
                             block_group, group_desc, desc);
                             block_group, group_desc, desc);
        gdp = (struct ext2_group_desc *)
        gdp = (struct ext2_group_desc *)
                sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
                sb->u.ext2_sb.s_group_desc[group_desc]->b_data;
        if (bh)
        if (bh)
                *bh = sb->u.ext2_sb.s_group_desc[group_desc];
                *bh = sb->u.ext2_sb.s_group_desc[group_desc];
        return gdp + desc;
        return gdp + desc;
}
}
 
 
/*
/*
 * Read the inode allocation bitmap for a given block_group, reading
 * Read the inode allocation bitmap for a given block_group, reading
 * into the specified slot in the superblock's bitmap cache.
 * into the specified slot in the superblock's bitmap cache.
 *
 *
 * Return >=0 on success or a -ve error code.
 * Return >=0 on success or a -ve error code.
 */
 */
 
 
static int read_inode_bitmap (struct super_block * sb,
static int read_inode_bitmap (struct super_block * sb,
                              unsigned long block_group,
                              unsigned long block_group,
                              unsigned int bitmap_nr)
                              unsigned int bitmap_nr)
{
{
        struct ext2_group_desc * gdp;
        struct ext2_group_desc * gdp;
        struct buffer_head * bh;
        struct buffer_head * bh;
        int retval = 0;
        int retval = 0;
 
 
        gdp = get_group_desc (sb, block_group, NULL);
        gdp = get_group_desc (sb, block_group, NULL);
        bh = bread (sb->s_dev, swab32(gdp->bg_inode_bitmap), sb->s_blocksize);
        bh = bread (sb->s_dev, swab32(gdp->bg_inode_bitmap), sb->s_blocksize);
        if (!bh) {
        if (!bh) {
                ext2_error (sb, "read_inode_bitmap",
                ext2_error (sb, "read_inode_bitmap",
                            "Cannot read inode bitmap - "
                            "Cannot read inode bitmap - "
                            "block_group = %lu, inode_bitmap = %lu",
                            "block_group = %lu, inode_bitmap = %lu",
                            block_group, (unsigned long) swab32(gdp->bg_inode_bitmap));
                            block_group, (unsigned long) swab32(gdp->bg_inode_bitmap));
                retval = -EIO;
                retval = -EIO;
        }
        }
        /*
        /*
         * On IO error, just leave a zero in the superblock's block pointer for
         * On IO error, just leave a zero in the superblock's block pointer for
         * this group.  The IO will be retried next time.
         * this group.  The IO will be retried next time.
         */
         */
        sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
        sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
        sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh;
        sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh;
        return retval;
        return retval;
}
}
 
 
/*
/*
 * load_inode_bitmap loads the inode bitmap for a blocks group
 * load_inode_bitmap loads the inode bitmap for a blocks group
 *
 *
 * It maintains a cache for the last bitmaps loaded.  This cache is managed
 * It maintains a cache for the last bitmaps loaded.  This cache is managed
 * with a LRU algorithm.
 * with a LRU algorithm.
 *
 *
 * Notes:
 * Notes:
 * 1/ There is one cache per mounted file system.
 * 1/ There is one cache per mounted file system.
 * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
 * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups,
 *    this function reads the bitmap without maintaining a LRU cache.
 *    this function reads the bitmap without maintaining a LRU cache.
 *
 *
 * Return the slot used to store the bitmap, or a -ve error code.
 * Return the slot used to store the bitmap, or a -ve error code.
 */
 */
static int load_inode_bitmap (struct super_block * sb,
static int load_inode_bitmap (struct super_block * sb,
                              unsigned int block_group)
                              unsigned int block_group)
{
{
        int i, j, retval = 0;
        int i, j, retval = 0;
        unsigned long inode_bitmap_number;
        unsigned long inode_bitmap_number;
        struct buffer_head * inode_bitmap;
        struct buffer_head * inode_bitmap;
 
 
        if (block_group >= sb->u.ext2_sb.s_groups_count)
        if (block_group >= sb->u.ext2_sb.s_groups_count)
                ext2_panic (sb, "load_inode_bitmap",
                ext2_panic (sb, "load_inode_bitmap",
                            "block_group >= groups_count - "
                            "block_group >= groups_count - "
                            "block_group = %d, groups_count = %lu",
                            "block_group = %d, groups_count = %lu",
                             block_group, sb->u.ext2_sb.s_groups_count);
                             block_group, sb->u.ext2_sb.s_groups_count);
        if (sb->u.ext2_sb.s_loaded_inode_bitmaps > 0 &&
        if (sb->u.ext2_sb.s_loaded_inode_bitmaps > 0 &&
            sb->u.ext2_sb.s_inode_bitmap_number[0] == block_group)
            sb->u.ext2_sb.s_inode_bitmap_number[0] == block_group)
                return 0;
                return 0;
        if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
        if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) {
                if (sb->u.ext2_sb.s_inode_bitmap[block_group]) {
                if (sb->u.ext2_sb.s_inode_bitmap[block_group]) {
                        if (sb->u.ext2_sb.s_inode_bitmap_number[block_group] != block_group)
                        if (sb->u.ext2_sb.s_inode_bitmap_number[block_group] != block_group)
                                ext2_panic (sb, "load_inode_bitmap",
                                ext2_panic (sb, "load_inode_bitmap",
                                            "block_group != inode_bitmap_number");
                                            "block_group != inode_bitmap_number");
                        else
                        else
                                return block_group;
                                return block_group;
                } else {
                } else {
                        retval = read_inode_bitmap (sb, block_group, block_group);
                        retval = read_inode_bitmap (sb, block_group, block_group);
                        if (retval < 0)
                        if (retval < 0)
                                return retval;
                                return retval;
                        return block_group;
                        return block_group;
                }
                }
        }
        }
 
 
        for (i = 0; i < sb->u.ext2_sb.s_loaded_inode_bitmaps &&
        for (i = 0; i < sb->u.ext2_sb.s_loaded_inode_bitmaps &&
                    sb->u.ext2_sb.s_inode_bitmap_number[i] != block_group;
                    sb->u.ext2_sb.s_inode_bitmap_number[i] != block_group;
             i++)
             i++)
                ;
                ;
        if (i < sb->u.ext2_sb.s_loaded_inode_bitmaps &&
        if (i < sb->u.ext2_sb.s_loaded_inode_bitmaps &&
            sb->u.ext2_sb.s_inode_bitmap_number[i] == block_group) {
            sb->u.ext2_sb.s_inode_bitmap_number[i] == block_group) {
                inode_bitmap_number = sb->u.ext2_sb.s_inode_bitmap_number[i];
                inode_bitmap_number = sb->u.ext2_sb.s_inode_bitmap_number[i];
                inode_bitmap = sb->u.ext2_sb.s_inode_bitmap[i];
                inode_bitmap = sb->u.ext2_sb.s_inode_bitmap[i];
                for (j = i; j > 0; j--) {
                for (j = i; j > 0; j--) {
                        sb->u.ext2_sb.s_inode_bitmap_number[j] =
                        sb->u.ext2_sb.s_inode_bitmap_number[j] =
                                sb->u.ext2_sb.s_inode_bitmap_number[j - 1];
                                sb->u.ext2_sb.s_inode_bitmap_number[j - 1];
                        sb->u.ext2_sb.s_inode_bitmap[j] =
                        sb->u.ext2_sb.s_inode_bitmap[j] =
                                sb->u.ext2_sb.s_inode_bitmap[j - 1];
                                sb->u.ext2_sb.s_inode_bitmap[j - 1];
                }
                }
                sb->u.ext2_sb.s_inode_bitmap_number[0] = inode_bitmap_number;
                sb->u.ext2_sb.s_inode_bitmap_number[0] = inode_bitmap_number;
                sb->u.ext2_sb.s_inode_bitmap[0] = inode_bitmap;
                sb->u.ext2_sb.s_inode_bitmap[0] = inode_bitmap;
 
 
                /*
                /*
                 * There's still one special case here --- if inode_bitmap == 0
                 * There's still one special case here --- if inode_bitmap == 0
                 * then our last attempt to read the bitmap failed and we have
                 * then our last attempt to read the bitmap failed and we have
                 * just ended up caching that failure.  Try again to read it.
                 * just ended up caching that failure.  Try again to read it.
                 */
                 */
                if (!inode_bitmap)
                if (!inode_bitmap)
                        retval = read_inode_bitmap (sb, block_group, 0);
                        retval = read_inode_bitmap (sb, block_group, 0);
        } else {
        } else {
                if (sb->u.ext2_sb.s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
                if (sb->u.ext2_sb.s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED)
                        sb->u.ext2_sb.s_loaded_inode_bitmaps++;
                        sb->u.ext2_sb.s_loaded_inode_bitmaps++;
                else
                else
                        brelse (sb->u.ext2_sb.s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
                        brelse (sb->u.ext2_sb.s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1]);
                for (j = sb->u.ext2_sb.s_loaded_inode_bitmaps - 1; j > 0; j--) {
                for (j = sb->u.ext2_sb.s_loaded_inode_bitmaps - 1; j > 0; j--) {
                        sb->u.ext2_sb.s_inode_bitmap_number[j] =
                        sb->u.ext2_sb.s_inode_bitmap_number[j] =
                                sb->u.ext2_sb.s_inode_bitmap_number[j - 1];
                                sb->u.ext2_sb.s_inode_bitmap_number[j - 1];
                        sb->u.ext2_sb.s_inode_bitmap[j] =
                        sb->u.ext2_sb.s_inode_bitmap[j] =
                                sb->u.ext2_sb.s_inode_bitmap[j - 1];
                                sb->u.ext2_sb.s_inode_bitmap[j - 1];
                }
                }
                retval = read_inode_bitmap (sb, block_group, 0);
                retval = read_inode_bitmap (sb, block_group, 0);
        }
        }
        return retval;
        return retval;
}
}
 
 
void ext2_free_inode (struct inode * inode)
void ext2_free_inode (struct inode * inode)
{
{
        struct super_block * sb;
        struct super_block * sb;
        struct buffer_head * bh;
        struct buffer_head * bh;
        struct buffer_head * bh2;
        struct buffer_head * bh2;
        unsigned long block_group;
        unsigned long block_group;
        unsigned long bit;
        unsigned long bit;
        int bitmap_nr;
        int bitmap_nr;
        struct ext2_group_desc * gdp;
        struct ext2_group_desc * gdp;
        struct ext2_super_block * es;
        struct ext2_super_block * es;
 
 
        if (!inode)
        if (!inode)
                return;
                return;
        if (!inode->i_dev) {
        if (!inode->i_dev) {
                printk ("ext2_free_inode: inode has no device\n");
                printk ("ext2_free_inode: inode has no device\n");
                return;
                return;
        }
        }
        if (inode->i_count > 1) {
        if (inode->i_count > 1) {
                printk ("ext2_free_inode: inode has count=%ld\n",
                printk ("ext2_free_inode: inode has count=%ld\n",
                        inode->i_count);
                        inode->i_count);
                return;
                return;
        }
        }
        if (inode->i_nlink) {
        if (inode->i_nlink) {
                printk ("ext2_free_inode: inode has nlink=%d\n",
                printk ("ext2_free_inode: inode has nlink=%d\n",
                        inode->i_nlink);
                        inode->i_nlink);
                return;
                return;
        }
        }
        sb = inode->i_sb;
        sb = inode->i_sb;
        if (!sb) {
        if (!sb) {
                printk("ext2_free_inode: inode on nonexistent device\n");
                printk("ext2_free_inode: inode on nonexistent device\n");
                return;
                return;
        }
        }
 
 
        ext2_debug ("freeing inode %lu\n", inode->i_ino);
        ext2_debug ("freeing inode %lu\n", inode->i_ino);
 
 
        /* We need to kill quota references now, before grabbing the
        /* We need to kill quota references now, before grabbing the
         * superblock lock because writing the quota out to disk
         * superblock lock because writing the quota out to disk
         * may need to lock the superblock as well.
         * may need to lock the superblock as well.
         *
         *
         * It is safe to do this early instead of the original
         * It is safe to do this early instead of the original
         * places because we cannot be here in ext2_free_inode
         * places because we cannot be here in ext2_free_inode
         * if any other references to this inode exist at all.
         * if any other references to this inode exist at all.
         *
         *
         * Based upon a 2.1.x fix by Bill Hawes.   --DaveM
         * Based upon a 2.1.x fix by Bill Hawes.   --DaveM
         */
         */
        if (sb->dq_op) {
        if (sb->dq_op) {
                sb->dq_op->free_inode (inode, 1);
                sb->dq_op->free_inode (inode, 1);
                if (IS_WRITABLE (inode))
                if (IS_WRITABLE (inode))
                        sb->dq_op->drop(inode);
                        sb->dq_op->drop(inode);
        }
        }
 
 
        lock_super (sb);
        lock_super (sb);
        if (inode->i_ino < EXT2_FIRST_INO(sb) ||
        if (inode->i_ino < EXT2_FIRST_INO(sb) ||
            inode->i_ino > swab32(sb->u.ext2_sb.s_es->s_inodes_count)) {
            inode->i_ino > swab32(sb->u.ext2_sb.s_es->s_inodes_count)) {
                ext2_error (sb, "free_inode",
                ext2_error (sb, "free_inode",
                            "reserved inode or nonexistent inode");
                            "reserved inode or nonexistent inode");
                unlock_super (sb);
                unlock_super (sb);
                return;
                return;
        }
        }
        es = sb->u.ext2_sb.s_es;
        es = sb->u.ext2_sb.s_es;
        block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb);
        block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb);
        bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb);
        bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb);
        bitmap_nr = load_inode_bitmap (sb, block_group);
        bitmap_nr = load_inode_bitmap (sb, block_group);
        if (bitmap_nr < 0) {
        if (bitmap_nr < 0) {
                unlock_super (sb);
                unlock_super (sb);
                return;
                return;
        }
        }
 
 
        bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
        bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
        if (!__ext2_clear_bit (bit, bh->b_data))
        if (!__ext2_clear_bit (bit, bh->b_data))
                ext2_warning (sb, "ext2_free_inode",
                ext2_warning (sb, "ext2_free_inode",
                              "bit already cleared for inode %lu", inode->i_ino);
                              "bit already cleared for inode %lu", inode->i_ino);
        else {
        else {
                gdp = get_group_desc (sb, block_group, &bh2);
                gdp = get_group_desc (sb, block_group, &bh2);
                gdp->bg_free_inodes_count =
                gdp->bg_free_inodes_count =
                        swab16(swab16(gdp->bg_free_inodes_count) + 1);
                        swab16(swab16(gdp->bg_free_inodes_count) + 1);
                if (S_ISDIR(inode->i_mode))
                if (S_ISDIR(inode->i_mode))
                        gdp->bg_used_dirs_count =
                        gdp->bg_used_dirs_count =
                                swab16(swab16(gdp->bg_used_dirs_count) - 1);
                                swab16(swab16(gdp->bg_used_dirs_count) - 1);
                mark_buffer_dirty(bh2, 1);
                mark_buffer_dirty(bh2, 1);
                es->s_free_inodes_count =
                es->s_free_inodes_count =
                        swab32(swab32(es->s_free_inodes_count) + 1);
                        swab32(swab32(es->s_free_inodes_count) + 1);
                mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
                mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
                inode->i_dirt = 0;
                inode->i_dirt = 0;
        }
        }
        mark_buffer_dirty(bh, 1);
        mark_buffer_dirty(bh, 1);
        if (sb->s_flags & MS_SYNCHRONOUS) {
        if (sb->s_flags & MS_SYNCHRONOUS) {
                ll_rw_block (WRITE, 1, &bh);
                ll_rw_block (WRITE, 1, &bh);
                wait_on_buffer (bh);
                wait_on_buffer (bh);
        }
        }
        sb->s_dirt = 1;
        sb->s_dirt = 1;
        clear_inode (inode);
        clear_inode (inode);
        unlock_super (sb);
        unlock_super (sb);
}
}
 
 
/*
/*
 * This function increments the inode version number
 * This function increments the inode version number
 *
 *
 * This may be used one day by the NFS server
 * This may be used one day by the NFS server
 */
 */
static void inc_inode_version (struct inode * inode,
static void inc_inode_version (struct inode * inode,
                               struct ext2_group_desc *gdp,
                               struct ext2_group_desc *gdp,
                               int mode)
                               int mode)
{
{
        inode->u.ext2_i.i_version++;
        inode->u.ext2_i.i_version++;
        inode->i_dirt = 1;
        inode->i_dirt = 1;
 
 
        return;
        return;
}
}
 
 
/*
/*
 * There are two policies for allocating an inode.  If the new inode is
 * 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
 * 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
 * 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
 * the groups with above-average free space, that group with the fewest
 * directories already is chosen.
 * directories already is chosen.
 *
 *
 * For other inodes, search forward from the parent directory\'s block
 * For other inodes, search forward from the parent directory\'s block
 * group to find a free inode.
 * group to find a free inode.
 */
 */
struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err)
struct inode * ext2_new_inode (const struct inode * dir, int mode, int * err)
{
{
        struct super_block * sb;
        struct super_block * sb;
        struct buffer_head * bh;
        struct buffer_head * bh;
        struct buffer_head * bh2;
        struct buffer_head * bh2;
        int i, j, avefreei;
        int i, j, avefreei;
        struct inode * inode;
        struct inode * inode;
        int bitmap_nr;
        int bitmap_nr;
        struct ext2_group_desc * gdp;
        struct ext2_group_desc * gdp;
        struct ext2_group_desc * tmp;
        struct ext2_group_desc * tmp;
        struct ext2_super_block * es;
        struct ext2_super_block * es;
 
 
        if (!dir || !(inode = get_empty_inode ()))
        if (!dir || !(inode = get_empty_inode ()))
        {
        {
                *err=-ENOMEM;
                *err=-ENOMEM;
                return NULL;
                return NULL;
        }
        }
        sb = dir->i_sb;
        sb = dir->i_sb;
        inode->i_sb = sb;
        inode->i_sb = sb;
        inode->i_flags = sb->s_flags;
        inode->i_flags = sb->s_flags;
        lock_super (sb);
        lock_super (sb);
        es = sb->u.ext2_sb.s_es;
        es = sb->u.ext2_sb.s_es;
repeat:
repeat:
        gdp = NULL; i=0;
        gdp = NULL; i=0;
 
 
        *err = -ENOSPC;
        *err = -ENOSPC;
        if (S_ISDIR(mode)) {
        if (S_ISDIR(mode)) {
                avefreei = swab32(es->s_free_inodes_count) /
                avefreei = swab32(es->s_free_inodes_count) /
                        sb->u.ext2_sb.s_groups_count;
                        sb->u.ext2_sb.s_groups_count;
/* I am not yet convinced that this next bit is necessary.
/* I am not yet convinced that this next bit is necessary.
                i = dir->u.ext2_i.i_block_group;
                i = dir->u.ext2_i.i_block_group;
                for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
                for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
                        tmp = get_group_desc (sb, i, &bh2);
                        tmp = get_group_desc (sb, i, &bh2);
                        if ((swab16(tmp->bg_used_dirs_count) << 8) <
                        if ((swab16(tmp->bg_used_dirs_count) << 8) <
                            swab16(tmp->bg_free_inodes_count)) {
                            swab16(tmp->bg_free_inodes_count)) {
                                gdp = tmp;
                                gdp = tmp;
                                break;
                                break;
                        }
                        }
                        else
                        else
                        i = ++i % sb->u.ext2_sb.s_groups_count;
                        i = ++i % sb->u.ext2_sb.s_groups_count;
                }
                }
*/
*/
                if (!gdp) {
                if (!gdp) {
                        for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
                        for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) {
                                tmp = get_group_desc (sb, j, &bh2);
                                tmp = get_group_desc (sb, j, &bh2);
                                if (swab16(tmp->bg_free_inodes_count) &&
                                if (swab16(tmp->bg_free_inodes_count) &&
                                        swab16(tmp->bg_free_inodes_count) >= avefreei) {
                                        swab16(tmp->bg_free_inodes_count) >= avefreei) {
                                        if (!gdp ||
                                        if (!gdp ||
                                            (swab16(tmp->bg_free_blocks_count) >
                                            (swab16(tmp->bg_free_blocks_count) >
                                             swab16(gdp->bg_free_blocks_count))) {
                                             swab16(gdp->bg_free_blocks_count))) {
                                                i = j;
                                                i = j;
                                                gdp = tmp;
                                                gdp = tmp;
                                        }
                                        }
                                }
                                }
                        }
                        }
                }
                }
        }
        }
        else
        else
        {
        {
                /*
                /*
                 * Try to place the inode in its parent directory
                 * Try to place the inode in its parent directory
                 */
                 */
                i = dir->u.ext2_i.i_block_group;
                i = dir->u.ext2_i.i_block_group;
                tmp = get_group_desc (sb, i, &bh2);
                tmp = get_group_desc (sb, i, &bh2);
                if (swab16(tmp->bg_free_inodes_count))
                if (swab16(tmp->bg_free_inodes_count))
                        gdp = tmp;
                        gdp = tmp;
                else
                else
                {
                {
                        /*
                        /*
                         * Use a quadratic hash to find a group with a
                         * Use a quadratic hash to find a group with a
                         * free inode
                         * free inode
                         */
                         */
                        for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1) {
                        for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1) {
                                i += j;
                                i += j;
                                if (i >= sb->u.ext2_sb.s_groups_count)
                                if (i >= sb->u.ext2_sb.s_groups_count)
                                        i -= sb->u.ext2_sb.s_groups_count;
                                        i -= sb->u.ext2_sb.s_groups_count;
                                tmp = get_group_desc (sb, i, &bh2);
                                tmp = get_group_desc (sb, i, &bh2);
                                if (swab16(tmp->bg_free_inodes_count)) {
                                if (swab16(tmp->bg_free_inodes_count)) {
                                        gdp = tmp;
                                        gdp = tmp;
                                        break;
                                        break;
                                }
                                }
                        }
                        }
                }
                }
                if (!gdp) {
                if (!gdp) {
                        /*
                        /*
                         * That failed: try linear search for a free inode
                         * That failed: try linear search for a free inode
                         */
                         */
                        i = dir->u.ext2_i.i_block_group + 1;
                        i = dir->u.ext2_i.i_block_group + 1;
                        for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) {
                        for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) {
                                if (++i >= sb->u.ext2_sb.s_groups_count)
                                if (++i >= sb->u.ext2_sb.s_groups_count)
                                        i = 0;
                                        i = 0;
                                tmp = get_group_desc (sb, i, &bh2);
                                tmp = get_group_desc (sb, i, &bh2);
                                if (swab16(tmp->bg_free_inodes_count)) {
                                if (swab16(tmp->bg_free_inodes_count)) {
                                        gdp = tmp;
                                        gdp = tmp;
                                        break;
                                        break;
                                }
                                }
                        }
                        }
                }
                }
        }
        }
 
 
        if (!gdp) {
        if (!gdp) {
                unlock_super (sb);
                unlock_super (sb);
                iput(inode);
                iput(inode);
                return NULL;
                return NULL;
        }
        }
        bitmap_nr = load_inode_bitmap (sb, i);
        bitmap_nr = load_inode_bitmap (sb, i);
        if (bitmap_nr < 0) {
        if (bitmap_nr < 0) {
                unlock_super (sb);
                unlock_super (sb);
                iput(inode);
                iput(inode);
                *err = -EIO;
                *err = -EIO;
                return NULL;
                return NULL;
        }
        }
 
 
        bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
        bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr];
        if ((j = __ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
        if ((j = __ext2_find_first_zero_bit ((unsigned long *) bh->b_data,
                                      EXT2_INODES_PER_GROUP(sb))) <
                                      EXT2_INODES_PER_GROUP(sb))) <
            EXT2_INODES_PER_GROUP(sb)) {
            EXT2_INODES_PER_GROUP(sb)) {
                if (__ext2_set_bit (j, bh->b_data)) {
                if (__ext2_set_bit (j, bh->b_data)) {
                        ext2_warning (sb, "ext2_new_inode",
                        ext2_warning (sb, "ext2_new_inode",
                                      "bit already set for inode %d", j);
                                      "bit already set for inode %d", j);
                        goto repeat;
                        goto repeat;
                }
                }
                mark_buffer_dirty(bh, 1);
                mark_buffer_dirty(bh, 1);
                if (sb->s_flags & MS_SYNCHRONOUS) {
                if (sb->s_flags & MS_SYNCHRONOUS) {
                        ll_rw_block (WRITE, 1, &bh);
                        ll_rw_block (WRITE, 1, &bh);
                        wait_on_buffer (bh);
                        wait_on_buffer (bh);
                }
                }
        } else {
        } else {
                if (swab16(gdp->bg_free_inodes_count) != 0) {
                if (swab16(gdp->bg_free_inodes_count) != 0) {
                        ext2_error (sb, "ext2_new_inode",
                        ext2_error (sb, "ext2_new_inode",
                                    "Free inodes count corrupted in group %d",
                                    "Free inodes count corrupted in group %d",
                                    i);
                                    i);
                        unlock_super (sb);
                        unlock_super (sb);
                        iput (inode);
                        iput (inode);
                        return NULL;
                        return NULL;
                }
                }
                goto repeat;
                goto repeat;
        }
        }
        j += i * EXT2_INODES_PER_GROUP(sb) + 1;
        j += i * EXT2_INODES_PER_GROUP(sb) + 1;
        if (j < EXT2_FIRST_INO(sb) || j > swab32(es->s_inodes_count)) {
        if (j < EXT2_FIRST_INO(sb) || j > swab32(es->s_inodes_count)) {
                ext2_error (sb, "ext2_new_inode",
                ext2_error (sb, "ext2_new_inode",
                            "reserved inode or inode > inodes count - "
                            "reserved inode or inode > inodes count - "
                            "block_group = %d,inode=%d", i, j);
                            "block_group = %d,inode=%d", i, j);
                unlock_super (sb);
                unlock_super (sb);
                iput (inode);
                iput (inode);
                return NULL;
                return NULL;
        }
        }
        gdp->bg_free_inodes_count =
        gdp->bg_free_inodes_count =
                swab16(swab16(gdp->bg_free_inodes_count) - 1);
                swab16(swab16(gdp->bg_free_inodes_count) - 1);
        if (S_ISDIR(mode))
        if (S_ISDIR(mode))
                gdp->bg_used_dirs_count =
                gdp->bg_used_dirs_count =
                        swab16(swab16(gdp->bg_used_dirs_count) + 1);
                        swab16(swab16(gdp->bg_used_dirs_count) + 1);
        mark_buffer_dirty(bh2, 1);
        mark_buffer_dirty(bh2, 1);
        es->s_free_inodes_count =
        es->s_free_inodes_count =
                swab32(swab32(es->s_free_inodes_count) - 1);
                swab32(swab32(es->s_free_inodes_count) - 1);
        mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
        mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
        sb->s_dirt = 1;
        sb->s_dirt = 1;
        inode->i_mode = mode;
        inode->i_mode = mode;
        inode->i_sb = sb;
        inode->i_sb = sb;
        inode->i_count = 1;
        inode->i_count = 1;
        inode->i_nlink = 1;
        inode->i_nlink = 1;
        inode->i_dev = sb->s_dev;
        inode->i_dev = sb->s_dev;
        inode->i_uid = current->fsuid;
        inode->i_uid = current->fsuid;
        if (test_opt (sb, GRPID))
        if (test_opt (sb, GRPID))
                inode->i_gid = dir->i_gid;
                inode->i_gid = dir->i_gid;
        else if (dir->i_mode & S_ISGID) {
        else if (dir->i_mode & S_ISGID) {
                inode->i_gid = dir->i_gid;
                inode->i_gid = dir->i_gid;
                if (S_ISDIR(mode))
                if (S_ISDIR(mode))
                        mode |= S_ISGID;
                        mode |= S_ISGID;
        } else
        } else
                inode->i_gid = current->fsgid;
                inode->i_gid = current->fsgid;
        inode->i_dirt = 1;
        inode->i_dirt = 1;
        inode->i_ino = j;
        inode->i_ino = j;
        inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat), not the fs block size */
        inode->i_blksize = PAGE_SIZE;   /* This is the optimal IO size (for stat), not the fs block size */
        inode->i_blocks = 0;
        inode->i_blocks = 0;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
        inode->u.ext2_i.i_new_inode = 1;
        inode->u.ext2_i.i_new_inode = 1;
        inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags;
        inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags;
        if (S_ISLNK(mode))
        if (S_ISLNK(mode))
                inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL | EXT2_APPEND_FL);
                inode->u.ext2_i.i_flags &= ~(EXT2_IMMUTABLE_FL | EXT2_APPEND_FL);
        inode->u.ext2_i.i_faddr = 0;
        inode->u.ext2_i.i_faddr = 0;
        inode->u.ext2_i.i_frag_no = 0;
        inode->u.ext2_i.i_frag_no = 0;
        inode->u.ext2_i.i_frag_size = 0;
        inode->u.ext2_i.i_frag_size = 0;
        inode->u.ext2_i.i_file_acl = 0;
        inode->u.ext2_i.i_file_acl = 0;
        inode->u.ext2_i.i_dir_acl = 0;
        inode->u.ext2_i.i_dir_acl = 0;
        inode->u.ext2_i.i_dtime = 0;
        inode->u.ext2_i.i_dtime = 0;
        inode->u.ext2_i.i_block_group = i;
        inode->u.ext2_i.i_block_group = i;
        inode->i_op = NULL;
        inode->i_op = NULL;
        if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
        if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
                inode->i_flags |= MS_SYNCHRONOUS;
                inode->i_flags |= MS_SYNCHRONOUS;
        insert_inode_hash(inode);
        insert_inode_hash(inode);
        inc_inode_version (inode, gdp, mode);
        inc_inode_version (inode, gdp, mode);
 
 
        unlock_super (sb);
        unlock_super (sb);
        if (sb->dq_op) {
        if (sb->dq_op) {
                sb->dq_op->initialize (inode, -1);
                sb->dq_op->initialize (inode, -1);
                if (sb->dq_op->alloc_inode (inode, 1)) {
                if (sb->dq_op->alloc_inode (inode, 1)) {
                        sb->dq_op->drop (inode);
                        sb->dq_op->drop (inode);
                        inode->i_nlink = 0;
                        inode->i_nlink = 0;
                        iput (inode);
                        iput (inode);
                        *err = -EDQUOT;
                        *err = -EDQUOT;
                        return NULL;
                        return NULL;
                }
                }
                inode->i_flags |= S_WRITE;
                inode->i_flags |= S_WRITE;
        }
        }
        ext2_debug ("allocating inode %lu\n", inode->i_ino);
        ext2_debug ("allocating inode %lu\n", inode->i_ino);
 
 
        *err = 0;
        *err = 0;
        return inode;
        return inode;
}
}
 
 
unsigned long ext2_count_free_inodes (struct super_block * sb)
unsigned long ext2_count_free_inodes (struct super_block * sb)
{
{
#ifdef EXT2FS_DEBUG
#ifdef EXT2FS_DEBUG
        struct ext2_super_block * es;
        struct ext2_super_block * es;
        unsigned long desc_count, bitmap_count, x;
        unsigned long desc_count, bitmap_count, x;
        int bitmap_nr;
        int bitmap_nr;
        struct ext2_group_desc * gdp;
        struct ext2_group_desc * gdp;
        int i;
        int i;
 
 
        lock_super (sb);
        lock_super (sb);
        es = sb->u.ext2_sb.s_es;
        es = sb->u.ext2_sb.s_es;
        desc_count = 0;
        desc_count = 0;
        bitmap_count = 0;
        bitmap_count = 0;
        gdp = NULL;
        gdp = NULL;
        for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
        for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
                gdp = get_group_desc (sb, i, NULL);
                gdp = get_group_desc (sb, i, NULL);
                desc_count += swab16(gdp->bg_free_inodes_count);
                desc_count += swab16(gdp->bg_free_inodes_count);
                bitmap_nr = load_inode_bitmap (sb, i);
                bitmap_nr = load_inode_bitmap (sb, i);
                if (bitmap_nr < 0)
                if (bitmap_nr < 0)
                        continue;
                        continue;
 
 
                x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
                x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
                                     EXT2_INODES_PER_GROUP(sb) / 8);
                                     EXT2_INODES_PER_GROUP(sb) / 8);
                printk ("group %d: stored = %d, counted = %lu\n",
                printk ("group %d: stored = %d, counted = %lu\n",
                        i, swab16(gdp->bg_free_inodes_count), x);
                        i, swab16(gdp->bg_free_inodes_count), x);
                bitmap_count += x;
                bitmap_count += x;
        }
        }
        printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
        printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
                swab32(es->s_free_inodes_count), desc_count, bitmap_count);
                swab32(es->s_free_inodes_count), desc_count, bitmap_count);
        unlock_super (sb);
        unlock_super (sb);
        return desc_count;
        return desc_count;
#else
#else
        return swab32(sb->u.ext2_sb.s_es->s_free_inodes_count);
        return swab32(sb->u.ext2_sb.s_es->s_free_inodes_count);
#endif
#endif
}
}
 
 
void ext2_check_inodes_bitmap (struct super_block * sb)
void ext2_check_inodes_bitmap (struct super_block * sb)
{
{
        struct ext2_super_block * es;
        struct ext2_super_block * es;
        unsigned long desc_count, bitmap_count, x;
        unsigned long desc_count, bitmap_count, x;
        int bitmap_nr;
        int bitmap_nr;
        struct ext2_group_desc * gdp;
        struct ext2_group_desc * gdp;
        int i;
        int i;
 
 
        lock_super (sb);
        lock_super (sb);
        es = sb->u.ext2_sb.s_es;
        es = sb->u.ext2_sb.s_es;
        desc_count = 0;
        desc_count = 0;
        bitmap_count = 0;
        bitmap_count = 0;
        gdp = NULL;
        gdp = NULL;
        for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
        for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) {
                gdp = get_group_desc (sb, i, NULL);
                gdp = get_group_desc (sb, i, NULL);
                desc_count += swab16(gdp->bg_free_inodes_count);
                desc_count += swab16(gdp->bg_free_inodes_count);
                bitmap_nr = load_inode_bitmap (sb, i);
                bitmap_nr = load_inode_bitmap (sb, i);
                if (bitmap_nr < 0)
                if (bitmap_nr < 0)
                        continue;
                        continue;
 
 
                x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
                x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr],
                                     EXT2_INODES_PER_GROUP(sb) / 8);
                                     EXT2_INODES_PER_GROUP(sb) / 8);
                if (swab16(gdp->bg_free_inodes_count) != x)
                if (swab16(gdp->bg_free_inodes_count) != x)
                        ext2_error (sb, "ext2_check_inodes_bitmap",
                        ext2_error (sb, "ext2_check_inodes_bitmap",
                                    "Wrong free inodes count in group %d, "
                                    "Wrong free inodes count in group %d, "
                                    "stored = %d, counted = %lu", i,
                                    "stored = %d, counted = %lu", i,
                                    swab16(gdp->bg_free_inodes_count), x);
                                    swab16(gdp->bg_free_inodes_count), x);
                bitmap_count += x;
                bitmap_count += x;
        }
        }
        if (swab32(es->s_free_inodes_count) != bitmap_count)
        if (swab32(es->s_free_inodes_count) != bitmap_count)
                ext2_error (sb, "ext2_check_inodes_bitmap",
                ext2_error (sb, "ext2_check_inodes_bitmap",
                            "Wrong free inodes count in super block, "
                            "Wrong free inodes count in super block, "
                            "stored = %lu, counted = %lu",
                            "stored = %lu, counted = %lu",
                            (unsigned long) swab32(es->s_free_inodes_count),
                            (unsigned long) swab32(es->s_free_inodes_count),
                            bitmap_count);
                            bitmap_count);
        unlock_super (sb);
        unlock_super (sb);
}
}
 
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.