/*
* linux/fs/super.c
*
* (C) 1991 Linus Torvalds
*/

/*
* super.c contains code to handle the super-block tables.
*/
#include <linux/config.h>	// ںͷļԺӲͣHD_TYPEѡ
#include <linux/sched.h>	// ȳͷļṹtask_structʼ0 ݣ
// һЩйúͻȡǶʽຯ䡣
#include <linux/kernel.h>	// ںͷļһЩں˳úԭζ塣
#include <asm/system.h>		// ϵͳͷļû޸/жŵȵǶʽꡣ

#include <errno.h>		// ͷļϵͳиֳš(Linus minix )
#include <sys/stat.h>		// ļ״̬ͷļļļϵͳ״̬ṹstat{}ͳ

int sync_dev (int dev);		// ָ豸ִиٻ豸ݵͬ(fs/buffer.c,59)
void wait_for_keypress (void);	// ȴ(kernel/chr_drv/tty_io.c, 140)

/* set_bit uses setb, as gas doesn't recognize setc */
/* set_bit()ʹsetb ָΪgas ʶָsetc */
//// ָλƫƴλֵ(0 1)ظñλֵ(ӦȡΪtest_bit())
mount_root
   i  ڵṹ32  ֽڶļ64 
  гʼļϵͳ̵Ļʾ̣سʼ飨8
   ȡ豸ϵĳ͸i  ڵṹϢøi  ڵôΪ4 
  Ϊ1  ĵǰĿ¼͸Ŀ¼i 
  ڵ㡣߼λͼͳƿ̿ʾi  ڵλͼͳƿi 
  ڵʾ
// Ƕʽꡣbitnr Ǳλƫֵaddr ǲԱλʼַ
// %0 - ax(__res)%1 - 0%2 - bitnr%3 - addr
#define set_bit(bitnr,addr) ({ \
register int __res __asm__( "ax"); \
__asm__( "bt %2,%3;setb %%al": "=a" (__res): "a" (0), "r" (bitnr), "m" (*(addr))); \
__res; })
struct super_block super_block[NR_SUPER];	// ṹ飨8 
/* this is initialized in init/main.c */
/* ROOT_DEV init/main.c бʼ */
int ROOT_DEV = 0;

//// ָĳ顣
static void
lock_super (struct super_block *sb)
{
  cli ();			// жϡ
  while (sb->s_lock)		// óѾ˯ߵȴ
    sleep_on (&(sb->s_wait));
  sb->s_lock = 1;		// ó־
  sti ();			// жϡ
}

//// ָʹulock_super 
static void
free_super (struct super_block *sb)
{
  cli ();			// жϡ
  sb->s_lock = 0;		// λ־
  wake_up (&(sb->s_wait));	// ѵȴóĽ̡
  sti ();			// жϡ
}

//// ˯ߵȴ
static void
wait_on_super (struct super_block *sb)
{
  cli ();			// жϡ
  while (sb->s_lock)		// Ѿ˯ߵȴ
    sleep_on (&(sb->s_wait));
  sti ();			// жϡ
}

//// ȡָ豸ĳ顣ظóṹָ롣
struct super_block *
get_super (int dev)
{
  struct super_block *s;

// ûָ豸򷵻ؿָ롣
  if (!dev)
    return NULL;
// s ָ򳬼鿪ʼ飬Ѱָ豸ĳ顣
  s = 0 + super_block;
  while (s < NR_SUPER + super_block)
// ǰָ豸ĳ飬ȵȴóѾĻ
// ڵȴڼ䣬óпܱ豸ʹã˴ʱжһǷָ豸ĳ飬
// 򷵻ظóָ롣¶Գһ飬s ָ򳬼
// ʼ
    if (s->s_dev == dev)
      {
	wait_on_super (s);
	if (s->s_dev == dev)
	  return s;
	s = 0 + super_block;
// ǰǣһûҵָĳ飬򷵻ؿָ롣
      }
    else
      s++;
  return NULL;
}

//// ͷָ豸ĳ顣
// ͷ豸ʹõĳs_dev=0ͷŸ豸i ڵλͼ߼λͼռ
// ĸٻ顣ӦļϵͳǸļϵͳi ڵѾװļ
// ϵͳͷŸó顣
void
put_super (int dev)
{
  struct super_block *sb;
  struct m_inode *inode;
  int i;

// ָ豸Ǹļϵͳ豸ʾϢϵͳ̸ıˣ׼սɡء
  if (dev == ROOT_DEV)
    {
      printk ("root diskette changed: prepare for armageddon\n\r");
      return;
    }
// Ҳָ豸ĳ飬򷵻ء
  if (!(sb = get_super (dev)))
    return;
// óָļϵͳi ڵϰװļϵͳʾϢء
  if (sb->s_imount)
    {
      printk ("Mounted disk changed - tssk, tssk\n\r");
      return;
    }
// ҵָ豸ĳó飬ȻøóӦ豸ֶΪ0Ҳ
// ó顣
  lock_super (sb);
  sb->s_dev = 0;
// ȻͷŸ豸i ڵλͼ߼λͼڻռõĻ顣
  for (i = 0; i < I_MAP_SLOTS; i++)
    brelse (sb->s_imap[i]);
  for (i = 0; i < Z_MAP_SLOTS; i++)
    brelse (sb->s_zmap[i]);
// Ըóء
  free_super (sb);
  return;
}

//// 豸϶ȡ鵽С
// 豸ĳѾڸٻвЧֱӷظóָ롣
static struct super_block *
read_super (int dev)
{
  struct super_block *s;
  struct buffer_head *bh;
  int i, block;

// ûָ豸򷵻ؿָ롣
  if (!dev)
    return NULL;
// ȼ豸ǷɸƬҲǷ豸̣ٻйظ
// 豸лʧЧҪʧЧͷԭصļϵͳ
  check_disk_change (dev);
// 豸ĳѾڸٻУֱӷظóָ롣
  if (s = get_super (dev))
    return s;
// ڳҳһ(Ҳs_dev=0 )Ѿռ򷵻ؿָ롣
  for (s = 0 + super_block;; s++)
    {
      if (s >= NR_SUPER + super_block)
	return NULL;
      if (!s->s_dev)
	break;
    }
// ҵ󣬾ͽóָ豸Ըóڴвֳʼ
  s->s_dev = dev;
  s->s_isup = NULL;
  s->s_imount = NULL;
  s->s_time = 0;
  s->s_rd_only = 0;
  s->s_dirt = 0;
// Ȼó飬豸϶ȡϢbh ָĻСʧܣ
// ͷѡĳеؿָ˳
  lock_super (s);
  if (!(bh = bread (dev, 1)))
    {
      s->s_dev = 0;
      free_super (s);
      return NULL;
    }
// 豸϶ȡĳϢƵӦṹСͷŴŶȡϢĸٻ顣
  *((struct d_super_block *) s) = *((struct d_super_block *) bh->b_data);
  brelse (bh);
// ȡĳļϵͳħֶݲԣ˵豸ϲȷļϵͳͬ
// һͷѡĳеؿָ˳
// ڸðlinux ںˣֻ֧minix ļϵͳ汾1.0ħ0x137f
  if (s->s_magic != SUPER_MAGIC)
    {
      s->s_dev = 0;
      free_super (s);
      return NULL;
    }
// 濪ʼȡ豸i ڵλͼ߼λͼݡȳʼڴ泬ṹλͼռ䡣
  for (i = 0; i < I_MAP_SLOTS; i++)
    s->s_imap[i] = NULL;
  for (i = 0; i < Z_MAP_SLOTS; i++)
    s->s_zmap[i] = NULL;
// Ȼ豸϶ȡi ڵλͼ߼λͼϢڳӦֶС
  block = 2;
  for (i = 0; i < s->s_imap_blocks; i++)
    if (s->s_imap[i] = bread (dev, block))
      block++;
    else
      break;
  for (i = 0; i < s->s_zmap_blocks; i++)
    if (s->s_zmap[i] = bread (dev, block))
      block++;
    else
      break;
// λͼ߼λͼӦռе߼˵ļϵͳλͼϢ⣬
// ʼʧܡֻͷǰԴؿָ벢˳
  if (block != 2 + s->s_imap_blocks + s->s_zmap_blocks)
    {
// ͷi ڵλͼ߼λͼռõĸٻ
      for (i = 0; i < I_MAP_SLOTS; i++)
	brelse (s->s_imap[i]);
      for (i = 0; i < Z_MAP_SLOTS; i++)
	brelse (s->s_zmap[i]);
//ͷѡĳеóؿָ˳
      s->s_dev = 0;
      free_super (s);
      return NULL;
    }
// һгɹi ڵĺ豸еi ڵѾȫʹã
// ᷵0 ֵ0 i ڵǲõģｫλͼеλΪ1Էֹļ
// ϵͳ0 i ڵ㡣ͬĵҲ߼λͼλΪ1
  s->s_imap[0]->b_data[0] |= 1;
  s->s_zmap[0]->b_data[0] |= 1;
// ó飬سָ롣
  free_super (s);
  return s;
}

//// жļϵͳϵͳú
// dev_name 豸ļ
int
sys_umount (char *dev_name)
{
  struct m_inode *inode;
  struct super_block *sb;
  int dev;

// ȸ豸ļҵӦi ڵ㣬ȡе豸š
  if (!(inode = namei (dev_name)))
    return -ENOENT;
  dev = inode->i_zone[0];
// ǿ豸ļͷŸi ڵdev_iس롣
  if (!S_ISBLK (inode->i_mode))
    {
      iput (inode);
      return -ENOTBLK;
    }
// ͷ豸ļi ڵ㡣
  iput (inode);
// 豸Ǹļϵͳܱжأسš
  if (dev == ROOT_DEV)
    return -EBUSY;
// ȡ豸ĳʧܣ߸豸ļϵͳûаװ򷵻س롣
  if (!(sb = get_super (dev)) || !(sb->s_imount))
    return -ENOENT;
// ָıװi ڵûλ䰲װ־ʾϢ
  if (!sb->s_imount->i_mount)
    printk ("Mounted inode has i_mount=0\n");
// i ڵǷнʹø豸ϵļ򷵻æ롣
  for (inode = inode_table + 0; inode < inode_table + NR_INODE; inode++)
    if (inode->i_dev == dev && inode->i_count)
      return -EBUSY;
// λװi ڵİװ־ͷŸi ڵ㡣
  sb->s_imount->i_mount = 0;
  iput (sb->s_imount);
// óбװi ڵֶΪգͷ豸ļϵͳĸi ڵ㣬óбװϵͳ
// i ڵָΪա
  sb->s_imount = NULL;
  iput (sb->s_isup);
  sb->s_isup = NULL;
// ͷŸ豸ĳԼλͼռõĻ飬Ը豸ִиٻ豸ݵͬ
  put_super (dev);
  sync_dev (dev);
  return 0;
}

//// װļϵͳú
// dev_name 豸ļdir_name ǰװĿ¼rw_flag װļĶд־
// صĵطһĿ¼ҶӦi ڵûбռá
int
sys_mount (char *dev_name, char *dir_name, int rw_flag)
{
  struct m_inode *dev_i, *dir_i;
  struct super_block *sb;
  int dev;

// ȸ豸ļҵӦi ڵ㣬ȡе豸š
// ڿ豸ļ豸i ڵi_zone[0]С
  if (!(dev_i = namei (dev_name)))
    return -ENOENT;
  dev = dev_i->i_zone[0];
// ǿ豸ļͷŸȡõi ڵdev_iس롣
  if (!S_ISBLK (dev_i->i_mode))
    {
      iput (dev_i);
      return -EPERM;
    }
// ͷŸ豸ļi ڵdev_i
  iput (dev_i);
// ݸĿ¼ļҵӦi ڵdir_i
  if (!(dir_i = namei (dir_name)))
    return -ENOENT;
// i ڵüΪ1ã߸i ڵĽڵǸļϵͳĽڵ
// 1ͷŸi ڵ㣬س롣
  if (dir_i->i_count != 1 || dir_i->i_num == ROOT_INO)
    {
      iput (dir_i);
      return -EBUSY;
    }
// ýڵ㲻һĿ¼ļڵ㣬ҲͷŸi ڵ㣬س롣
  if (!S_ISDIR (dir_i->i_mode))
    {
      iput (dir_i);
      return -EPERM;
    }
// ȡװļϵͳĳ飬ʧҲͷŸi ڵ㣬س롣
  if (!(sb = read_super (dev)))
    {
      iput (dir_i);
      return -EBUSY;
    }
// ҪװļϵͳѾװطͷŸi ڵ㣬س롣
  if (sb->s_imount)
    {
      iput (dir_i);
      return -EBUSY;
    }
// Ҫװi ڵѾװļϵͳ(װ־Ѿλ)ͷŸi ڵ㣬س롣
  if (dir_i->i_mount)
    {
      iput (dir_i);
      return -EPERM;
    }
// װļϵͳġװi ڵ㡱ֶָװĿ¼i ڵ㡣
  sb->s_imount = dir_i;
// ðװλi ڵİװ־ͽڵ޸ı־/* ע⣡ûiput(dir_i) */
  dir_i->i_mount = 1;		/* ⽫umount ڲ */
  dir_i->i_dirt = 1;		/* NOTE! we don't iput(dir_i) */
  return 0;			/* we do that in umount */
}

//// װļϵͳ
// úϵͳʼʱ(sys_setup())õġ( kernel/blk_drv/hd.c, 157 )
void
mount_root (void)
{
  int i, free;
  struct super_block *p;
  struct m_inode *mi;

// i ڵṹ32 ֽڣжڷֹ޸ԴʱĲһԡ
  if (32 != sizeof (struct d_inode))
    panic ("bad i-node size");
// ʼļ飨64 Ҳϵͳͬʱֻܴ64 ļļṹеü
// Ϊ0[??Ϊʲôʼ]
  for (i = 0; i < NR_FILE; i++)
    file_table[i].f_count = 0;
// ļϵͳ豸̵Ļʾļϵͳ̣سȴ
  if (MAJOR (ROOT_DEV) == 2)
    {
      printk ("Insert root floppy and press ENTER");
      wait_for_keypress ();
    }
// ʼ飨8 
  for (p = &super_block[0]; p < &super_block[NR_SUPER]; p++)
    {
      p->s_dev = 0;
      p->s_lock = 0;
      p->s_wait = NULL;
    }
// 豸ϳʧܣʾϢ
  if (!(p = read_super (ROOT_DEV)))
    panic ("Unable to mount root");
//豸϶ȡļϵͳĸi ڵ(1)ʧʾϢ
  if (!(mi = iget (ROOT_DEV, ROOT_INO)))
    panic ("Unable to read root i-node");
// i ڵô3 ΡΪ266-268 Ҳ˸i ڵ㡣
  mi->i_count += 3;		/* NOTE! it is logically used 4 times, not 1 */
/* ע⣡߼Ͻѱ4 Σ1  */
// øóıװļϵͳi ڵͱװi ڵΪi ڵ㡣
  p->s_isup = p->s_imount = mi;
// õǰ̵ĵǰĿ¼͸Ŀ¼i ڵ㡣ʱǰ1 Ž̡
  current->pwd = mi;
  current->root = mi;
// ͳƸ豸Ͽпi ڳб豸߼
  free = 0;
  i = p->s_nzones;
// Ȼ߼λͼӦλռͳƳп꺯set_bit()ֻڲ
// λñλ"i&8191"ȡi ڵڵǰеƫֵ"i>>13"ǽi 
// 8192Ҳһ̿ıλ
  while (--i >= 0)
    if (!set_bit (i & 8191, p->s_zmap[i >> 13]->b_data))
      free++;
// ʾ豸Ͽ߼/߼
  printk ("%d/%d free blocks\n\r", free, p->s_nzones);
// ͳ豸Ͽi ڵi ڳб豸i ڵ+11 ǽ0 ڵ
// Ҳͳƽȥ
  free = 0;
  i = p->s_ninodes + 1;
// Ȼi ڵλͼӦλռi ڵ
  while (--i >= 0)
    if (!set_bit (i & 8191, p->s_imap[i >> 13]->b_data))
      free++;
// ʾ豸ϿõĿi ڵ/i ڵ
  printk ("%d/%d free inodes\n\r", free, p->s_ninodes);
}
