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

/* bitmap.c contains the code that handles the inode and block bitmaps */
/* bitmap.c дi ڵʹ̿λͼĴ */
#include <string.h>		// ַͷļҪһЩйַǶ뺯
// Ҫʹеmemset()
#include <linux/sched.h>	// ȳͷļṹtask_structʼ0 ݣ
// һЩйúͻȡǶʽຯ䡣
#include <linux/kernel.h>	// ںͷļһЩں˳úԭζ塣

//// ַָ(addr)һڴ㡣Ƕꡣ
// 룺eax = 0ecx = ݿСBLOCK_SIZE/4edi = addr
#define clear_block(addr) \
__asm__( "cld\n\t" \		// 巽λ
"rep\n\t" \			// ظִд洢ݣ0
"stosl"::"a" (0), "c" (BLOCK_SIZE / 4), "D" ((long) (addr)):"cx", "di")
//// λַָʼĵnr λƫƴıλ(nr Դ32)ԭλ0 1
// 룺%0 - eaxֵ)%1 - eax(0)%2 - nrλƫֵ%3 - (addr)addr ݡ
#define set_bit(nr,addr) ({\
register int res __asm__( "ax"); \
__asm__ __volatile__( "btsl %2,%3\n\tsetb %%al": \
"=a" (res): "" (0), "r" (nr), "m" (*(addr))); \
res;})
//// λַָʼĵnr λƫƴıλԭλķ루1 0
// 룺%0 - eaxֵ)%1 - eax(0)%2 - nrλƫֵ%3 - (addr)addr ݡ
#define clear_bit(nr,addr) ({\
register int res __asm__( "ax"); \
__asm__ __volatile__( "btrl %2,%3\n\tsetnb %%al": \
"=a" (res): "" (0), "r" (nr), "m" (*(addr))); \
res;})
//// addr ʼѰҵ1 0 ֵλ
// 룺%0 - ecx(ֵ)%1 - ecx(0)%2 - esi(addr)
// addr ַָʼλͼѰҵ1 0 ıλaddr ıλƫֵء
#define find_first_zero(addr) ({ \
int __res; \
__asm__( "cld\n" \		// 巽λ
  "1:\tlodsl\n\t" \		// ȡ[esi]??eax
  "notl %%eax\n\t" \		// eax ÿλȡ
  "bsfl %%eax,%%edx\n\t" \	// λ0 ɨeax 1 ĵ1 λƫֵ??edx
  "je 2f\n\t" \			// eax ȫ0ǰת2 (40 )
  "addl %%edx,%%ecx\n\t" \	// ƫֵecx(ecx λͼ׸0 ıλƫֵ)
  "jmp 3f\n" \			// ǰת3 
  "2:\taddl $32,%%ecx\n\t" \	// ûҵ0 λecx 1 ֵλƫ32
  "cmpl $8192,%%ecx\n\t" \	// Ѿɨ8192 λ1024 ֽڣ
  "jl 1b\n" \			// ûɨ1 ݣǰת1 
  "3:" \			// ʱecx λƫ
: "=c" (__res): "c" (0), "S" (addr):"ax", "dx", "si");
__res;
}

)
//// ͷ豸dev е߼block
// λָ߼block ߼λͼλ
// dev 豸ţblock ߼ţ̿ţ
     void free_block (int dev, int block)
     {
       struct super_block *sb;
       struct buffer_head *bh;

// ȡָ豸dev ĳ飬ָ豸ڣ
       if (!(sb = get_super (dev)))
	 panic ("trying to free block on nonexistent device");
// ߼С׸߼Żߴ豸߼
       if (block < sb->s_firstdatazone || block >= sb->s_nzones)
	 panic ("trying to free block not in datazone");
// hash ѰҸÿݡҵжЧԣ޸ĺ͸±־ͷŸݿ顣
// öδҪ;߼鵱ǰڸٻУͷŶӦĻ顣
       bh = get_hash_table (dev, block);
       if (bh)
	 {
	   if (bh->b_count != 1)
	     {
	       printk ("trying to free block (%04x:%d), count=%d\n",
		       dev, block, bh->b_count);
	       return;
	     }
	   bh->b_dirt = 0;	// λࣨ޸ģ־λ
	   bh->b_uptodate = 0;	// λ±־
	   brelse (bh);
	 }
// block ʼ߼ţ1 ʼȻ߼()λͼв
// λӦıλӦλԭ0
       block -= sb->s_firstdatazone - 1;	// block = block - ( -1) ;
       if (clear_bit (block & 8191, sb->s_zmap[block / 8192]->b_data))
	 {
	   printk ("block (%04x:%d) ", dev, block + sb->s_firstdatazone - 1);
	   panic ("free_block: bit already cleared");
	 }
// Ӧ߼λͼڻ޸ı־
       sb->s_zmap[block / 8192]->b_dirt = 1;
     }

////豸dev һ߼飨̿飬飩߼ţ̿ţ
// λָ߼block ߼λͼλ
int new_block (int dev)
{
  struct buffer_head *bh;
  struct super_block *sb;
  int i, j;

// 豸dev ȡ飬ָ豸ڣ
  if (!(sb = get_super (dev)))
    panic ("trying to get new block from nonexistant device");
// ɨ߼λͼѰ׸0 λѰҿ߼飬ȡø߼Ŀš
  j = 8192;
  for (i = 0; i < 8; i++)
    if (bh = sb->s_zmap[i])
      if ((j = find_first_zero (bh->b_data)) < 8192)
	break;
// ȫɨ껹ûҵ(i>=8 j>=8192)λͼڵĻЧ(bh=NULL) 0
// ˳ûп߼飩
  if (i >= 8 || !bh || j >= 8192)
    return 0;
// ߼Ӧ߼λͼеıλӦλѾλ
  if (set_bit (j, bh->b_data))
    panic ("new_block: bit already set");
// öӦ޸ı־߼ڸ豸ϵ߼˵ָ߼
// Ӧ豸ϲڡʧܣ0˳
  bh->b_dirt = 1;
  j += i * 8192 + sb->s_firstdatazone - 1;
  if (j >= sb->s_nzones)
    return 0;
// ȡ豸ϵĸ߼ݣ֤ʧ
  if (!(bh = getblk (dev, j)))
    panic ("new_block: cannot get block");
// ¿üӦΪ1
  if (bh->b_count != 1)
    panic ("new block: count is != 1");
// ߼㣬λ±־޸ı־ȻͷŶӦ߼š
  clear_block (bh->b_data);
  bh->b_uptodate = 1;
  bh->b_dirt = 1;
  brelse (bh);
  return j;
}

//// ͷָi ڵ㡣
// λӦi ڵλͼλ
void free_inode (struct m_inode *inode)
{
  struct super_block *sb;
  struct buffer_head *bh;

// i ڵָ=NULL˳
  if (!inode)
    return;
// i ڵϵ豸ֶΪ0˵ýڵã0 նӦi ڵռڴء
  if (!inode->i_dev)
    {
      memset (inode, 0, sizeof (*inode));
      return;
    }
// i ڵ㻹ãͷţ˵ں⣬
  if (inode->i_count > 1)
    {
      printk ("trying to free inode with count=%d\n", inode->i_count);
      panic ("free_inode");
    }
// ļĿ¼Ϊ0ʾļĿ¼ʹøýڵ㣬ӦͷţӦ÷Żصȡ
  if (inode->i_nlinks)
    panic ("trying to free inode with links");
// ȡi ڵ豸ĳ飬豸Ƿڡ
  if (!(sb = get_super (inode->i_dev)))
    panic ("trying to free inode on nonexistent device");
// i ڵ=0 ڸ豸i ڵ0 i ڵ㱣ûʹã
  if (inode->i_num < 1 || inode->i_num > sb->s_ninodes)
    panic ("trying to free inode 0 or nonexistant inode");
// i ڵӦĽڵλͼڣ
  if (!(bh = sb->s_imap[inode->i_num >> 13]))
    panic ("nonexistent imap in superblock");
// λi ڵӦĽڵλͼеıλñλѾ0
  if (clear_bit (inode->i_num & 8191, bh->b_data))
    printk ("free_inode: bit already cleared.\n\r");
// i ڵλͼڻ޸ı־ոi ڵṹռڴ
  bh->b_dirt = 1;
  memset (inode, 0, sizeof (*inode));
}

//// Ϊ豸dev һi ڵ㡣ظi ڵָ롣
// ڴi ڵлȡһi ڵi ڵλͼһi ڵ㡣
struct m_inode *new_inode (int dev)
{
  struct m_inode *inode;
  struct super_block *sb;
  struct buffer_head *bh;
  int i, j;

// ڴi ڵ(inode_table)лȡһi ڵ(inode)
  if (!(inode = get_empty_inode ()))
    return NULL;
// ȡָ豸ĳṹ
  if (!(sb = get_super (dev)))
    panic ("new_inode with unknown device");
// ɨi ڵλͼѰ׸0 λѰҿнڵ㣬ȡøi ڵĽڵš
  j = 8192;
  for (i = 0; i < 8; i++)
    if (bh = sb->s_imap[i])
      if ((j = find_first_zero (bh->b_data)) < 8192)
	break;
// ȫɨ껹ûҵλͼڵĻЧ(bh=NULL) 0˳ûпi ڵ㣩
  if (!bh || j >= 8192 || j + i * 8192 > sb->s_ninodes)
    {
      iput (inode);
      return NULL;
    }
// λӦi ڵi ڵλͼӦλѾλ
  if (set_bit (j, bh->b_data))
    panic ("new_inode: bit already set");
// i ڵλͼڻ޸ı־
  bh->b_dirt = 1;
// ʼi ڵṹ
  inode->i_count = 1;		// ü
  inode->i_nlinks = 1;		// ļĿ¼
  inode->i_dev = dev;		// i ڵڵ豸š
  inode->i_uid = current->euid;	// i ڵûid
  inode->i_gid = current->egid;	// id
  inode->i_dirt = 1;		// ޸ı־λ
  inode->i_num = j + i * 8192;	// Ӧ豸еi ڵš
  inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;	// ʱ䡣
  return inode;			// ظi ڵָ롣
}
