设为首页 收藏本站
查看: 277|回复: 0

[经验分享] linux 0.11 内核学习 -- bitmap.c

[复制链接]

尚未签到

发表于 2016-2-22 08:50:57 | 显示全部楼层 |阅读模式
  
  /*
  * linux/fs/bitmap.c
  *
  * (C) 1991 Linus Torvalds
  */
  
  /* bitmap.c contains the code that handles the inode and block bitmaps */
  #include <string.h>
  
  #include <linux/sched.h>
  #include <linux/kernel.h>// 一些内核常用函数的原形定义
  
  /* 将指定地址(addr)处的一块内存清零 */
  #define clear_block(addr) /
  __asm__("cld/n/t" /
  "rep/n/t" /
  "stosl" /
  ::"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di")
  
  /* 置位指定地址开始的第nr 个位偏移处的比特位 */
  #define set_bit(nr,addr) ({/
  register int res __asm__("ax"); /
  __asm__ __volatile__("btsl %2,%3/n/tsetb %%al": /
  "=a" (res):"0" (0),"r" (nr),"m" (*(addr))); /
  res;})
  
  /* 复位指定地址addr开始的第nr 位偏移处的比特位 */
  #define clear_bit(nr,addr) ({/
  register int res __asm__("ax"); /
  __asm__ __volatile__("btrl %2,%3/n/tsetnb %%al": /
  "=a" (res):"0" (0),"r" (nr),"m" (*(addr))); /
  res;})
  
  /* 从addr 开始寻找第1 个0 值比特位,并将其距离addr 的比特位偏移值返回 */
  #define find_first_zero(addr) ({ /
  int __res; /
  __asm__("cld/n" /
  "1:/tlodsl/n/t" /
  "notl %%eax/n/t" /
  "bsfl %%eax,%%edx/n/t" /
  "je 2f/n/t" /
  "addl %%edx,%%ecx/n/t" /
  "jmp 3f/n" /
  "2:/taddl $32,%%ecx/n/t" /
  "cmpl $8192,%%ecx/n/t" /
  "jl 1b/n" /
  "3:" /
  :"=c" (__res):"c" (0),"S" (addr):"ax","dx","si"); /
  __res;})
  
  /* 复位指定逻辑块block (相对于磁盘而言)的逻辑块位图比特位 */
  void free_block(int dev, int block)
  {
  struct super_block * sb;
  struct buffer_head * bh;
  
  if (!(sb = get_super(dev)))// 取指定设备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");
  bh = get_hash_table(dev,block);// 从hash 表中寻找该块数据
  if (bh)// 合法?
  {
  if (bh->b_count != 1) // 只有该进程占据block
  {
  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);
  }
  /*
   * 磁盘的结构如下:
   * |---|----|----|-----------------------* * *----------|
   *  |  |   |            |
   * 引导块超级块i节点          数据
   * 在磁盘被mount上之后,linux会首先读取super block,填充super
   * block,而super block就是整个磁盘信息的缩影。系统在需要磁盘
   * 操作时,首先需要参考该结构。在函数read_super中读取磁盘上的
   * super block。注意的是磁盘上的i节点位图和逻辑块位图都加在到
   * 内存中的缓冲区中(是由buffer.c来维护)
   *
   */
  /*
   * 到目前为止,应该对超级块,i节点,逻辑块,缓冲块有了一定的
   * 认识了。设备上的物理部分都有内存的表示,比如超级块在内存中
   * 有超级块数组 super_block[NR_SUPER],i节点和逻辑块位图有s_imap
   * [8]和s_zmap[8]指向的缓冲区表示,i节点在内存中有i节点数组
   * inode_table[NR_INODE],逻辑块有缓冲区中的缓冲块。分配inode和
   * 逻辑块只需要分配内存中保留的空闲块,并设置对应位图和修改位,
   * 内核会在适当时间刷新到设备上。inode只是在读取该文件时读取该
   * inode到内存中去
   */
  // 计算block 在数据区开始算起的数据逻辑块号(从1 开始计数)
  block -= sb->s_firstdatazone - 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 申请一个逻辑块(盘块,区块)。返回逻辑块号(盘块号) */
  int new_block(int dev)
  {
  struct buffer_head * bh;
  struct super_block * sb;
  int i,j;
  
  if (!(sb = get_super(dev)))// 从设备dev 取超级块
  panic("trying to get new block from nonexistant device");
  j = 8192;
  /*
   * block map
   *        /- b_data
   * buffer_head[8] -- * * *
   *        /- b_data
   */
  for (i=0 ; i<8 ; i++)
  if (bh=sb->s_zmap)
  if ((j=find_first_zero(bh->b_data))<8192)
  break;
  // 全部扫描完还没找到)或者位图所在的缓冲块无效
  if (i>=8 || !bh || j>=8192)
  return 0;
  if (set_bit(j,bh->b_data))// 逻辑块对应逻辑块位图中的比特位置位
  panic("new_block: bit already set");
  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 节点 */
  void free_inode(struct m_inode * inode)
  {
  struct super_block * sb;
  struct buffer_head * bh;
  
  if (!inode)// 如果i 节点指针=NULL?
  return;
  if (!inode->i_dev) // 该节点无用
  {
  memset(inode,0,sizeof(*inode));// 用0 清空对应i 节点所占内存区
  return;
  }
  if (inode->i_count>1) // 此i 节点还有其它程序引用,则不能释放
  {
  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");// 不应释放
  if (!(sb = get_super(inode->i_dev)))// 取i 节点所在设备的超级块
  panic("trying to free inode on nonexistent device");// 设备不存在
  // // 如果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 节点对应的节点位图中的比特位
  if (clear_bit(inode->i_num&8191,bh->b_data))
  // 该比特位已经等于0,则出错
  printk("free_inode: bit already cleared./n/r");
  bh->b_dirt = 1;// 置i 节点位图所在缓冲区已修改标志
  memset(inode,0,sizeof(*inode));// 清空该i 节点结构所占内存区
  }
  
  /* 为设备dev 建立一个新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 比特位
  j = 8192;
  for (i=0 ; i<8 ; i++)
  if (bh=sb->s_imap)
  if ((j=find_first_zero(bh->b_data))<8192)
  break;
  // // 如果全部扫描完还没找到,或者位图所在的缓冲块无效(bh=NULL)则 返回0,退出
  if (!bh || j >= 8192 || j+i*8192 > sb->s_ninodes)
  {
  iput(inode);
  return NULL;
  }
  if (set_bit(j,bh->b_data))// 置位对应新i 节点的i 节点位图相应比特位
  panic("new_inode: bit already set");
  bh->b_dirt = 1;// // 置i 节点位图所在缓冲区已修改标志
  // // 初始化该i 节点结构(内存数组中的结构)
  inode->i_count=1;
  inode->i_nlinks=1;
  inode->i_dev=dev;
  inode->i_uid=current->euid;
  inode->i_gid=current->egid;
  inode->i_dirt=1;
  inode->i_num = j + i*8192;
  inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
  
  return inode;// // 返回该i 节点指针
  }
  
  /*
  * 该文件主要是负责维护bitmap位图。文件主要实现的是四个函数
  * free_block,new_block,new_inode,free_inode。函数free_block
  * 主要实现的是对于逻辑块的位图指定位复位,由于修改了内存中的
  * 逻辑块位图所占据的内存区域,所以需要将该区域设置成ditry。其
  * 他的几个函数同理。
  */
  
  参考《linux内核完全注释》和网上相关文章

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-181100-1-1.html 上篇帖子: Linux下的逻辑卷和grub 下篇帖子: Linux集群的安装与并行计算
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表