text: /*
   *  linux/fs/inode.c
   *
   *  (C) 1991  Linus Torvalds
   */
  
  #include <string.h> 
  #include <sys/stat.h>
  
  #include <linux/sched.h>
  #include <linux/kernel.h>
  #include <linux/mm.h>
  #include <asm/system.h>
  
  struct m_inode inode_table[NR_INODE]={{0,},};
  
  static void read_inode(struct m_inode * inode);
  static void write_inode(struct m_inode * inode);
  
  static inline void wait_on_inode(struct m_inode * inode)
  {
  	cli();
  	while (inode->i_lock)
  		sleep_on(&inode->i_wait);
  	sti();
  }
  
  static inline void lock_inode(struct m_inode * inode)
  {
  	cli();
  	while (inode->i_lock)
  		sleep_on(&inode->i_wait);
  	inode->i_lock=1;
  	sti();
  }
  
  static inline void unlock_inode(struct m_inode * inode)
  {
  	inode->i_lock=0;
  	wake_up(&inode->i_wait);
  }
  
  void invalidate_inodes(int dev)
  {
  	int i;
  	struct m_inode * inode;
  
  	inode = 0+inode_table;
  	for(i=0 ; i<NR_INODE ; i++,inode++) {
  		wait_on_inode(inode);
  		if (inode->i_dev == dev) {
  			if (inode->i_count)
  				printk("inode in use on removed disk\n\r");
  			inode->i_dev = inode->i_dirt = 0;
  		}
  	}
  }
  
  void sync_inodes(void)
  {
  	int i;
  	struct m_inode * inode;
  
  	inode = 0+inode_table;
  	for(i=0 ; i<NR_INODE ; i++,inode++) {
  		wait_on_inode(inode);
  		if (inode->i_dirt && !inode->i_pipe)
  			write_inode(inode);
  	}
  }
  
  static int _bmap(struct m_inode * inode,int block,int create)
  {
  	struct buffer_head * bh;
  	int i;
  
  	if (block<0)
  		panic("_bmap: block<0");
  	if (block >= 7+512+512*512)
  		panic("_bmap: block>big");
  	if (block<7) {
  		if (create && !inode->i_zone[block])
  			if ((inode->i_zone[block]=new_block(inode->i_dev))) {
  				inode->i_ctime=CURRENT_TIME;
  				inode->i_dirt=1;
  			}
  		return inode->i_zone[block];
  	}
  	block -= 7;
  	if (block<512) {
  		if (create && !inode->i_zone[7])
  			if ((inode->i_zone[7]=new_block(inode->i_dev))) {
  				inode->i_dirt=1;
  				inode->i_ctime=CURRENT_TIME;
  			}
  		if (!inode->i_zone[7])
  			return 0;
  		if (!(bh = bread(inode->i_dev,inode->i_zone[7])))
  			return 0;
  		i = ((unsigned short *) (bh->b_data))[block];
  		if (create && !i)
  			if ((i=new_block(inode->i_dev))) {
  				((unsigned short *) (bh->b_data))[block]=i;
  				bh->b_dirt=1;
  			}
  		brelse(bh);
  		return i;
  	}
  	block -= 512;
  	if (create && !inode->i_zone[8])
  		if ((inode->i_zone[8]=new_block(inode->i_dev))) {
  			inode->i_dirt=1;
  			inode->i_ctime=CURRENT_TIME;
  		}
  	if (!inode->i_zone[8])
  		return 0;
  	if (!(bh=bread(inode->i_dev,inode->i_zone[8])))
  		return 0;
  	i = ((unsigned short *)bh->b_data)[block>>9];
  	if (create && !i)
  		if ((i=new_block(inode->i_dev))) {
  			((unsigned short *) (bh->b_data))[block>>9]=i;
  			bh->b_dirt=1;
  		}
  	brelse(bh);
  	if (!i)
  		return 0;
  	if (!(bh=bread(inode->i_dev,i)))
  		return 0;
  	i = ((unsigned short *)bh->b_data)[block&511];
  	if (create && !i)
  		if ((i=new_block(inode->i_dev))) {
  			((unsigned short *) (bh->b_data))[block&511]=i;
  			bh->b_dirt=1;
  		}
  	brelse(bh);
  	return i;
  }
  
  int bmap(struct m_inode * inode,int block)
  {
  	return _bmap(inode,block,0);
  }
  
  int create_block(struct m_inode * inode, int block)
  {
  	return _bmap(inode,block,1);
  }
  		
  void iput(struct m_inode * inode)
  {
  	if (!inode)
  		return;
  	wait_on_inode(inode);
  	if (!inode->i_count)
  		panic("iput: trying to free free inode");
  	if (inode->i_pipe) {
  		wake_up(&inode->i_wait);
  		if (--inode->i_count)
  			return;
  		free_page(inode->i_size);
  		inode->i_count=0;
  		inode->i_dirt=0;
  		inode->i_pipe=0;
  		return;
  	}
  	if (!inode->i_dev) {
  		inode->i_count--;
  		return;
  	}
  	if (S_ISBLK(inode->i_mode)) {
  		sync_dev(inode->i_zone[0]);
  		wait_on_inode(inode);
  	}
  repeat:
  	if (inode->i_count>1) {
  		inode->i_count--;
  		return;
  	}
  	if (!inode->i_nlinks) {
  		truncate(inode);
  		free_inode(inode);
  		return;
  	}
  	if (inode->i_dirt) {
  		write_inode(inode);	/* we can sleep - so do again */
  		wait_on_inode(inode);
  		goto repeat;
  	}
  	inode->i_count--;
  	return;
  }
  
  struct m_inode * get_empty_inode(void)
  {
  	struct m_inode * inode;
  	static struct m_inode * last_inode = inode_table;
  	int i;
  
  	do {
  		inode = NULL;
  		for (i = NR_INODE; i ; i--) {
  			if (++last_inode >= inode_table + NR_INODE)
  				last_inode = inode_table;
  			if (!last_inode->i_count) {
  				inode = last_inode;
  				if (!inode->i_dirt && !inode->i_lock)
  					break;
  			}
  		}
  		if (!inode) {
  			for (i=0 ; i<NR_INODE ; i++)
  				printk("%04x: %6d\t",inode_table[i].i_dev,
  					inode_table[i].i_num);
  			panic("No free inodes in mem");
  		}
  		wait_on_inode(inode);
  		while (inode->i_dirt) {
  			write_inode(inode);
  			wait_on_inode(inode);
  		}
  	} while (inode->i_count);
  	memset(inode,0,sizeof(*inode));
  	inode->i_count = 1;
  	return inode;
  }
  
  struct m_inode * get_pipe_inode(void)
  {
  	struct m_inode * inode;
  
  	if (!(inode = get_empty_inode()))
  		return NULL;
  	if (!(inode->i_size=get_free_page())) {
  		inode->i_count = 0;
  		return NULL;
  	}
  	inode->i_count = 2;	/* sum of readers/writers */
  	PIPE_HEAD(*inode) = PIPE_TAIL(*inode) = 0;
  	inode->i_pipe = 1;
  	return inode;
  }
  
  struct m_inode * iget(int dev,int nr)
  {
  	struct m_inode * inode, * empty;
  
  	if (!dev)
  		panic("iget with dev==0");
  	empty = get_empty_inode();
  	inode = inode_table;
  	while (inode < NR_INODE+inode_table) {
  		if (inode->i_dev != dev || inode->i_num != nr) {
  			inode++;
  			continue;
  		}
  		wait_on_inode(inode);
  		if (inode->i_dev != dev || inode->i_num != nr) {
  			inode = inode_table;
  			continue;
  		}
  		inode->i_count++;
  		if (inode->i_mount) {
  			int i;
  
  			for (i = 0 ; i<NR_SUPER ; i++)
  				if (super_block[i].s_imount==inode)
  					break;
  			if (i >= NR_SUPER) {
  				printk("Mounted inode hasn't got sb\n");
  				if (empty)
  					iput(empty);
  				return inode;
  			}
  			iput(inode);
  			dev = super_block[i].s_dev;
  			nr = ROOT_INO;
  			inode = inode_table;
  			continue;
  		}
  		if (empty)
  			iput(empty);
  		return inode;
  	}
  	if (!empty)
  		return (NULL);
  	inode=empty;
  	inode->i_dev = dev;
  	inode->i_num = nr;
  	read_inode(inode);
  	return inode;
  }
  
  static void read_inode(struct m_inode * inode)
  {
  	struct super_block * sb;
  	struct buffer_head * bh;
  	int block;
  
  	lock_inode(inode);
  	if (!(sb=get_super(inode->i_dev)))
  		panic("trying to read inode without dev");
  	block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
  		(inode->i_num-1)/INODES_PER_BLOCK;
  	if (!(bh=bread(inode->i_dev,block)))
  		panic("unable to read i-node block");
  	*(struct d_inode *)inode =
  		((struct d_inode *)bh->b_data)
  			[(inode->i_num-1)%INODES_PER_BLOCK];
  	brelse(bh);
  	unlock_inode(inode);
  }
  
  static void write_inode(struct m_inode * inode)
  {
  	struct super_block * sb;
  	struct buffer_head * bh;
  	int block;
  
  	lock_inode(inode);
  	if (!inode->i_dirt || !inode->i_dev) {
  		unlock_inode(inode);
  		return;
  	}
  	if (!(sb=get_super(inode->i_dev)))
  		panic("trying to write inode without device");
  	block = 2 + sb->s_imap_blocks + sb->s_zmap_blocks +
  		(inode->i_num-1)/INODES_PER_BLOCK;
  	if (!(bh=bread(inode->i_dev,block)))
  		panic("unable to read i-node block");
  	((struct d_inode *)bh->b_data)
  		[(inode->i_num-1)%INODES_PER_BLOCK] =
  			*(struct d_inode *)inode;
  	bh->b_dirt=1;
  	inode->i_dirt=0;
  	brelse(bh);
  	unlock_inode(inode);
  }
  