patch-2.4.6 linux/fs/sysv/ialloc.c
Next file: linux/fs/sysv/inode.c
Previous file: linux/fs/sysv/fsync.c
Back to the patch index
Back to the overall index
- Lines: 281
- Date:
Mon Jul 2 14:03:04 2001
- Orig file:
v2.4.5/linux/fs/sysv/ialloc.c
- Orig date:
Fri Nov 17 11:35:27 2000
diff -u --recursive --new-file v2.4.5/linux/fs/sysv/ialloc.c linux/fs/sysv/ialloc.c
@@ -19,7 +19,6 @@
* 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>
@@ -35,7 +34,8 @@
/* An inode on disk is considered free if both i_mode == 0 and i_nlink == 0. */
/* return &sb->sv_sb_fic_inodes[i] = &sbd->s_inode[i]; */
-static inline sysv_ino_t * sv_sb_fic_inode (struct super_block * sb, unsigned int i)
+static inline sysv_ino_t *
+sv_sb_fic_inode(struct super_block * sb, unsigned int i)
{
if (sb->sv_bh1 == sb->sv_bh2)
return &sb->sv_sb_fic_inodes[i];
@@ -49,12 +49,55 @@
}
}
+struct sysv_inode *
+sysv_raw_inode(struct super_block *sb, unsigned ino, struct buffer_head **bh)
+{
+ struct sysv_inode *res;
+ int block = sb->sv_firstinodezone + sb->sv_block_base;
+ block += (ino-1) >> sb->sv_inodes_per_block_bits;
+ *bh = bread(sb->s_dev, block, sb->s_blocksize);
+ if (!*bh)
+ return NULL;
+ res = (struct sysv_inode *) (*bh)->b_data;
+ return res + ((ino-1) & sb->sv_inodes_per_block_1);
+}
+
+static int refill_free_cache(struct super_block *sb)
+{
+ struct buffer_head * bh;
+ struct sysv_inode * raw_inode;
+ int i = 0, ino;
+
+ ino = SYSV_ROOT_INO+1;
+ raw_inode = sysv_raw_inode(sb, ino, &bh);
+ if (!raw_inode)
+ goto out;
+ while (ino <= sb->sv_ninodes) {
+ if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) {
+ *sv_sb_fic_inode(sb,i++) = cpu_to_fs16(sb, ino);
+ if (i == sb->sv_fic_size)
+ break;
+ }
+ if ((ino++ & sb->sv_inodes_per_block_1) == 0) {
+ brelse(bh);
+ raw_inode = sysv_raw_inode(sb, ino, &bh);
+ if (!raw_inode)
+ goto out;
+ } else
+ raw_inode++;
+ }
+ brelse(bh);
+out:
+ return i;
+}
+
void sysv_free_inode(struct inode * inode)
{
struct super_block * sb;
unsigned int ino;
struct buffer_head * bh;
struct sysv_inode * raw_inode;
+ unsigned count;
sb = inode->i_sb;
ino = inode->i_ino;
@@ -62,137 +105,119 @@
printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n");
return;
}
- if (!(bh = sv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits)))) {
+ raw_inode = sysv_raw_inode(sb, ino, &bh);
+ clear_inode(inode);
+ if (!raw_inode) {
printk("sysv_free_inode: unable to read inode block on device "
- "%s\n", kdevname(inode->i_dev));
- clear_inode(inode);
+ "%s\n", bdevname(inode->i_dev));
return;
}
- raw_inode = (struct sysv_inode *) bh->b_data + ((ino-1) & sb->sv_inodes_per_block_1);
- clear_inode(inode);
lock_super(sb);
- if (*sb->sv_sb_fic_count < sb->sv_fic_size)
- *sv_sb_fic_inode(sb,(*sb->sv_sb_fic_count)++) = ino;
- (*sb->sv_sb_total_free_inodes)++;
- mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
- if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
- sb->s_dirt = 1; /* and needs time stamp */
+ count = fs16_to_cpu(sb, *sb->sv_sb_fic_count);
+ if (count < sb->sv_fic_size) {
+ *sv_sb_fic_inode(sb,count++) = cpu_to_fs16(sb, ino);
+ *sb->sv_sb_fic_count = cpu_to_fs16(sb, count);
+ }
+ fs16_add(sb, sb->sv_sb_total_free_inodes, 1);
+ dirty_sb(sb);
memset(raw_inode, 0, sizeof(struct sysv_inode));
mark_buffer_dirty(bh);
unlock_super(sb);
brelse(bh);
}
-struct inode * sysv_new_inode(const struct inode * dir)
+struct inode * sysv_new_inode(const struct inode * dir, mode_t mode)
{
struct inode * inode;
struct super_block * sb;
- struct buffer_head * bh;
- struct sysv_inode * raw_inode;
- int i,j,ino,block;
+ u16 ino;
+ unsigned count;
- if (!dir)
- return NULL;
sb = dir->i_sb;
inode = new_inode(sb);
if (!inode)
return NULL;
- lock_super(sb); /* protect against task switches */
- if ((*sb->sv_sb_fic_count == 0)
- || (*sv_sb_fic_inode(sb,(*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 = sv_bread(sb, sb->s_dev, block))) {
- 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->b_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)
- *sv_sb_fic_inode(sb,i++) = ino;
- }
- brelse(bh);
- }
- if (i == 0) {
+ lock_super(sb);
+ count = fs16_to_cpu(sb, *sb->sv_sb_fic_count);
+ if (count == 0 || (*sv_sb_fic_inode(sb,count-1) == 0)) {
+ count = refill_free_cache(sb);
+ if (count == 0) {
iput(inode);
unlock_super(sb);
- return NULL; /* no inodes available */
+ return NULL;
}
- *sb->sv_sb_fic_count = i;
}
- /* Now *sb->sv_sb_fic_count > 0. */
- ino = *sv_sb_fic_inode(sb,--(*sb->sv_sb_fic_count));
- mark_buffer_dirty(sb->sv_bh1); /* super-block has been modified */
- if (sb->sv_bh1 != sb->sv_bh2) mark_buffer_dirty(sb->sv_bh2);
- sb->s_dirt = 1; /* and needs time stamp */
+ /* Now count > 0. */
+ ino = *sv_sb_fic_inode(sb,--count);
+ *sb->sv_sb_fic_count = cpu_to_fs16(sb, count);
+ fs16_add(sb, sb->sv_sb_total_free_inodes, -1);
+ dirty_sb(sb);
inode->i_uid = current->fsuid;
inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
- inode->i_ino = ino;
+ inode->i_ino = fs16_to_cpu(sb, ino);
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
inode->i_blocks = inode->i_blksize = 0;
insert_inode_hash(inode);
mark_inode_dirty(inode);
- /* Change directory entry: */
- inode->i_mode = 0; /* for sysv_write_inode() */
+ inode->i_mode = mode; /* for sysv_write_inode() */
sysv_write_inode(inode, 0); /* ensure inode not allocated again */
/* FIXME: caller may call this too. */
mark_inode_dirty(inode); /* cleared by sysv_write_inode() */
/* That's it. */
- (*sb->sv_sb_total_free_inodes)--;
- mark_buffer_dirty(sb->sv_bh2); /* 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;
struct sysv_inode * raw_inode;
- int j,block,count;
+ int ino, count, sb_count;
+
+ lock_super(sb);
+
+ sb_count = fs16_to_cpu(sb, *sb->sv_sb_total_free_inodes);
+
+ if (0)
+ goto trust_sb;
/* 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 = sv_bread(sb, sb->s_dev, block))) {
- 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->b_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;
- mark_buffer_dirty(sb->sv_bh2); /* super-block has been modified */
- sb->s_dirt = 1; /* and needs time stamp */
- }
+ ino = SYSV_ROOT_INO+1;
+ raw_inode = sysv_raw_inode(sb, ino, &bh);
+ if (!raw_inode)
+ goto Eio;
+ while (ino <= sb->sv_ninodes) {
+ if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0)
+ count++;
+ if ((ino++ & sb->sv_inodes_per_block_1) == 0) {
+ brelse(bh);
+ raw_inode = sysv_raw_inode(sb, ino, &bh);
+ if (!raw_inode)
+ goto Eio;
+ } else
+ raw_inode++;
}
+ brelse(bh);
+ if (count != sb_count)
+ goto Einval;
+out:
unlock_super(sb);
return count;
-#else
- return *sb->sv_sb_total_free_inodes;
-#endif
-}
+Einval:
+ printk("sysv_count_free_inodes: "
+ "free inode count was %d, correcting to %d\n",
+ sb_count, count);
+ if (!(sb->s_flags & MS_RDONLY)) {
+ *sb->sv_sb_total_free_inodes = cpu_to_fs16(sb, count);
+ dirty_sb(sb);
+ }
+ goto out;
+
+Eio:
+ printk("sysv_count_free_inodes: unable to read inode table\n");
+trust_sb:
+ count = sb_count;
+ goto out;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)