home *** CD-ROM | disk | FTP | other *** search
- /*
- * linux/fs/sysv/ialloc.c
- *
- * minix/bitmap.c
- * Copyright (C) 1991, 1992 Linus Torvalds
- *
- * ext/freelists.c
- * Copyright (C) 1992 Remy Card (card@masi.ibp.fr)
- *
- * xenix/alloc.c
- * Copyright (C) 1992 Doug Evans
- *
- * coh/alloc.c
- * Copyright (C) 1993 Pascal Haible, Bruno Haible
- *
- * sysv/ialloc.c
- * Copyright (C) 1993 Bruno Haible
- *
- * This file contains code for allocating/freeing inodes.
- */
-
- #include <linux/sched.h>
- #include <linux/kernel.h>
- #include <linux/fs.h>
- #include <linux/sysv_fs.h>
- #include <linux/stat.h>
- #include <linux/string.h>
- #include <linux/locks.h>
-
- /* We don't trust the value of
- sb->sv_sbd->s_tinode = *sb->sv_sb_total_free_inodes
- but we nevertheless keep it up to date. */
-
- /* An inode on disk is considered free if both i_mode == 0 and i_nlink == 0. */
-
- void sysv_free_inode(struct inode * inode)
- {
- struct super_block * sb;
- unsigned int ino;
- struct buffer_head * bh;
- char * bh_data;
- struct sysv_inode * raw_inode;
-
- if (!inode)
- return;
- if (!inode->i_dev) {
- printk("sysv_free_inode: inode has no device\n");
- return;
- }
- if (inode->i_count != 1) {
- printk("sysv_free_inode: inode has count=%d\n", inode->i_count);
- return;
- }
- if (inode->i_nlink) {
- printk("sysv_free_inode: inode has nlink=%d\n", inode->i_nlink);
- return;
- }
- if (!(sb = inode->i_sb)) {
- printk("sysv_free_inode: inode on nonexistent device\n");
- return;
- }
- ino = inode->i_ino;
- if (ino <= SYSV_ROOT_INO || ino > sb->sv_ninodes) {
- printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n");
- return;
- }
- if (!(bh = sysv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits), &bh_data))) {
- printk("sysv_free_inode: unable to read inode block on device %d/%d\n",MAJOR(inode->i_dev),MINOR(inode->i_dev));
- clear_inode(inode);
- return;
- }
- raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1);
- lock_super(sb);
- if (*sb->sv_sb_fic_count < sb->sv_fic_size)
- sb->sv_sb_fic_inodes[(*sb->sv_sb_fic_count)++] = ino;
- (*sb->sv_sb_total_free_inodes)++;
- sb->sv_bh->b_dirt = 1; /* super-block has been modified */
- sb->s_dirt = 1; /* and needs time stamp */
- memset(raw_inode, 0, sizeof(struct sysv_inode));
- bh->b_dirt = 1;
- unlock_super(sb);
- brelse(bh);
- clear_inode(inode);
- }
-
- struct inode * sysv_new_inode(const struct inode * dir)
- {
- struct inode * inode;
- struct super_block * sb;
- struct buffer_head * bh;
- char * bh_data;
- struct sysv_inode * raw_inode;
- int i,j,ino,block;
-
- if (!dir || !(inode = get_empty_inode()))
- return NULL;
- sb = dir->i_sb;
- inode->i_sb = sb;
- inode->i_flags = inode->i_sb->s_flags;
- lock_super(sb); /* protect against task switches */
- if ((*sb->sv_sb_fic_count == 0)
- || (sb->sv_sb_fic_inodes[(*sb->sv_sb_fic_count)-1] == 0) /* Applies only to SystemV2 FS */
- ) {
- /* Rebuild cache of free inodes: */
- /* i : index into cache slot being filled */
- /* ino : inode we are trying */
- /* block : firstinodezone + (ino-1)/inodes_per_block */
- /* j : (ino-1)%inodes_per_block */
- /* bh : buffer for block */
- /* raw_inode : pointer to inode ino in the block */
- for (i = 0, ino = SYSV_ROOT_INO+1, block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; i < sb->sv_fic_size && block < sb->sv_firstdatazone ; block++, j = 0) {
- if (!(bh = sysv_bread(sb, sb->s_dev, block, &bh_data))) {
- printk("sysv_new_inode: unable to read inode table\n");
- break; /* go with what we've got */
- /* FIXME: Perhaps try the next block? */
- }
- raw_inode = (struct sysv_inode *) bh_data + j;
- for (; j < sb->sv_inodes_per_block && i < sb->sv_fic_size; ino++, j++, raw_inode++) {
- if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0)
- sb->sv_sb_fic_inodes[i++] = ino;
- }
- brelse(bh);
- }
- if (i == 0) {
- iput(inode);
- unlock_super(sb);
- return NULL; /* no inodes available */
- }
- *sb->sv_sb_fic_count = i;
- }
- /* Now *sb->sv_sb_fic_count > 0. */
- ino = sb->sv_sb_fic_inodes[--(*sb->sv_sb_fic_count)];
- sb->sv_bh->b_dirt = 1; /* super-block has been modified */
- sb->s_dirt = 1; /* and needs time stamp */
- inode->i_count = 1;
- inode->i_nlink = 1;
- inode->i_dev = sb->s_dev;
- inode->i_uid = current->euid;
- inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->egid;
- inode->i_dirt = 1;
- inode->i_ino = ino;
- inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
- inode->i_op = NULL;
- inode->i_blocks = inode->i_blksize = 0;
- inode->u.sysv_i.i_lock = 0; inode->u.sysv_i.i_wait = NULL;
- insert_inode_hash(inode);
- /* Change directory entry: */
- inode->i_mode = 0; /* for sysv_write_inode() */
- inode->i_size = 0; /* ditto */
- sysv_write_inode(inode); /* ensure inode not allocated again */
- /* FIXME: caller may call this too. */
- inode->i_dirt = 1; /* cleared by sysv_write_inode() */
- /* That's it. */
- (*sb->sv_sb_total_free_inodes)--;
- sb->sv_bh->b_dirt = 1; /* super-block has been modified again */
- sb->s_dirt = 1; /* and needs time stamp again */
- unlock_super(sb);
- return inode;
- }
-
- unsigned long sysv_count_free_inodes(struct super_block * sb)
- {
- #if 1 /* test */
- struct buffer_head * bh;
- char * bh_data;
- struct sysv_inode * raw_inode;
- int j,block,count;
-
- /* this causes a lot of disk traffic ... */
- count = 0;
- lock_super(sb);
- /* i : index into cache slot being filled */
- /* ino : inode we are trying */
- /* block : firstinodezone + (ino-1)/inodes_per_block */
- /* j : (ino-1)%inodes_per_block */
- /* bh : buffer for block */
- /* raw_inode : pointer to inode ino in the block */
- for (block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; block < sb->sv_firstdatazone ; block++, j = 0) {
- if (!(bh = sysv_bread(sb, sb->s_dev, block, &bh_data))) {
- printk("sysv_count_free_inodes: unable to read inode table\n");
- break; /* go with what we've got */
- /* FIXME: Perhaps try the next block? */
- }
- raw_inode = (struct sysv_inode *) bh_data + j;
- for (; j < sb->sv_inodes_per_block ; j++, raw_inode++)
- if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0)
- count++;
- brelse(bh);
- }
- if (count != *sb->sv_sb_total_free_inodes) {
- printk("sysv_count_free_inodes: free inode count was %d, correcting to %d\n",(short)(*sb->sv_sb_total_free_inodes),count);
- if (!(sb->s_flags & MS_RDONLY)) {
- *sb->sv_sb_total_free_inodes = count;
- sb->sv_bh->b_dirt = 1; /* super-block has been modified */
- sb->s_dirt = 1; /* and needs time stamp */
- }
- }
- unlock_super(sb);
- return count;
- #else
- return *sb->sv_sb_total_free_inodes;
- #endif
- }
-
-