当前位置: 首页 > news >正文

(done) 整理 xv6 文件系统 inode 层函数

url1: https://www.bilibili.com/video/BV138xuevELE?spm_id_from=333.788.videopod.sections&vd_source=7a1a0bc74158c6993c7355c5490fc600&p=31

url2: https://www.bilibili.com/video/BV138xuevELE?spm_id_from=333.788.videopod.sections&vd_source=7a1a0bc74158c6993c7355c5490fc600&p=32

url3: https://www.bilibili.com/video/BV138xuevELE?spm_id_from=333.788.videopod.sections&vd_source=7a1a0bc74158c6993c7355c5490fc600&p=33


dinode 结构体
nlink:这个 inode 拥有的硬链接数量

// On-disk inode structure
struct dinode {short type;           // File typeshort major;          // Major device number (T_DEVICE only)short minor;          // Minor device number (T_DEVICE only)short nlink;          // Number of links to inode in file systemuint size;            // Size of file (bytes)uint addrs[NDIRECT+2];   // Data block addresses
};

itable 结构体
这其实是一个 inode cache,类似 buffer cache。

struct {struct spinlock lock;struct inode inode[NINODE];
} itable;

inode 结构体:每一个 inode 结构体都是磁盘上 inode 的缓存
dev, inum 表示这是哪个设备上的哪个 inode 的缓存
ref 表示 xv6 系统中一共有几个线程/任务正在使用这个 inode
lock 用来保护 inode 竞争
valid 表示数据是否有效

// in-memory copy of an inode
struct inode {uint dev;           // Device numberuint inum;          // Inode numberint ref;            // Reference countstruct sleeplock lock; // protects everything below hereint valid;          // inode has been read from disk?short type;         // copy of disk inodeshort major;short minor;short nlink;uint size;uint addrs[NDIRECT+2];
};

根目录 inode 号为1

#define ROOTINO  1   // root i-number

iinit: 初始化 inode cache
fsinit: 接收设备号,初始化相关内容,这里会调用 readsb
readsb: 读取超级块
bzero: 往一个指定的块写入 0
balloc: 在位图中搜索空闲块,在位图标识空闲块为 “在使用”,随后返回这个块
bfree: 在位图中把一个 “在使用” 的块标识为空闲块

ialloc: 读取磁盘,获取一个未被使用的 inode,设置这个 inode 的类型,调用 iget

// Allocate an inode on device dev.
// Mark it as allocated by  giving it type type.
// Returns an unlocked but allocated and referenced inode,
// or NULL if there is no free inode.
struct inode*
ialloc(uint dev, short type)
{int inum;struct buf *bp;struct dinode *dip;// inum 范围 1 ~ sb.ninodes, sb.ninodes 是超级块记录的 inode 数量for(inum = 1; inum < sb.ninodes; inum++){bp = bread(dev, IBLOCK(inum, sb));dip = (struct dinode*)bp->data + inum%IPB;// 找到空闲的 dinode 后,设置 type,然后释放,再调用 iget 获取 inode 结构体if(dip->type == 0){  // a free inodememset(dip, 0, sizeof(*dip));dip->type = type;log_write(bp);   // mark it allocated on the diskbrelse(bp);return iget(dev, inum);}brelse(bp);}printf("ialloc: no inodes\n");return 0;
}

iget: 在 inode cache 中挑一个 inode,这里会提升 inode->ref

// Find the inode with number inum on device dev
// and return the in-memory copy. Does not lock
// the inode and does not read it from disk.
static struct inode*
iget(uint dev, uint inum)
{struct inode *ip, *empty;acquire(&itable.lock);// Is the inode already in the table?// 遍历整个 itable(inode cache),若找到 dev 和 inum 一致的 inode,直接返回这个 inode// 若没找到, empty 记录了一个空闲的 inode cacheempty = 0;for(ip = &itable.inode[0]; ip < &itable.inode[NINODE]; ip++){if(ip->ref > 0 && ip->dev == dev && ip->inum == inum){ip->ref++;release(&itable.lock);return ip;}if(empty == 0 && ip->ref == 0)    // Remember empty slot.empty = ip;}// Recycle an inode entry. (执行到这里说明 inode 不足)if(empty == 0)panic("iget: no inodes");// 该 inode 的 addrs 还没有被写入,无效ip = empty;ip->dev = dev;ip->inum = inum;ip->ref = 1;ip->valid = 0;release(&itable.lock);return ip;
}

ilock: 给 inode 加睡眠锁、从磁盘读取 inode

// Lock the given inode.
// Reads the inode from disk if necessary.
void
ilock(struct inode *ip)
{struct buf *bp;struct dinode *dip;if(ip == 0 || ip->ref < 1)panic("ilock");// 加睡眠所acquiresleep(&ip->lock);// 若 valid == False, 那么根据 inum 从磁盘读取 dinode,覆盖数据给 inumif(ip->valid == 0){bp = bread(ip->dev, IBLOCK(ip->inum, sb));dip = (struct dinode*)bp->data + ip->inum%IPB;ip->type = dip->type;ip->major = dip->major;ip->minor = dip->minor;ip->nlink = dip->nlink;ip->size = dip->size;memmove(ip->addrs, dip->addrs, sizeof(ip->addrs));brelse(bp);ip->valid = 1;if(ip->type == 0)panic("ilock: no type");}
}

iunlock: 解锁 inode

// Unlock the given inode.
void
iunlock(struct inode *ip)
{if(ip == 0 || !holdingsleep(&ip->lock) || ip->ref < 1)panic("iunlock");releasesleep(&ip->lock);
}

iupdate: 把内存 inode 写回磁盘 (写到相应的 buffer 里)
(事实上,iupdate 会在很多地方被调用。你可能觉得这里有 redudant work,但请记住,我们使用的是磁盘日志系统,iupdate 在更新日志,只有最终 end_op() 时才会把日志上的内容更新到磁盘数据块里)

// Copy a modified in-memory inode to disk.
// Must be called after every change to an ip->xxx field
// that lives on disk.
// Caller must hold ip->lock.
void
iupdate(struct inode *ip)
{struct buf *bp;struct dinode *dip;bp = bread(ip->dev, IBLOCK(ip->inum, sb));dip = (struct dinode*)bp->data + ip->inum%IPB;dip->type = ip->type;dip->major = ip->major;dip->minor = ip->minor;dip->nlink = ip->nlink;dip->size = ip->size;memmove(dip->addrs, ip->addrs, sizeof(ip->addrs));log_write(bp);brelse(bp);
}

idup: 让 inode->ref +1

// Increment reference count for ip.
// Returns ip to enable ip = idup(ip1) idiom.
struct inode*
idup(struct inode *ip)
{acquire(&itable.lock);ip->ref++;release(&itable.lock);return ip;
}

iput: 让 inode->ref -1。若-1后 ref == 0 且 nlink == 0,清除这个内存 inode,同时调用 iupdate 同步到磁盘 inode 上。

// Drop a reference to an in-memory inode.
// If that was the last reference, the inode table entry can
// be recycled.
// If that was the last reference and the inode has no links
// to it, free the inode (and its content) on disk.
// All calls to iput() must be inside a transaction in
// case it has to free the inode.
void
iput(struct inode *ip)
{acquire(&itable.lock);if(ip->ref == 1 && ip->valid && ip->nlink == 0){// inode has no links and no other references: truncate and free.// ip->ref == 1 means no other process can have ip locked,// so this acquiresleep() won't block (or deadlock).acquiresleep(&ip->lock);release(&itable.lock);itrunc(ip);ip->type = 0;iupdate(ip);ip->valid = 0;releasesleep(&ip->lock);acquire(&itable.lock);}ip->ref--;release(&itable.lock);
}

iunlockput: 先调用 iunlock, 在调用 iput

itrunc: 清除内存 inode 的数据块,设置 inode->size = 0,最后调用 iupdate 同步到磁盘 inode 上

stati: 拷贝 inode 的数据到一个指定地点,这让用户态程序能够了解一个文件的 inode 信息

readi: 从 inode 代表的文件中读取数据

writei:往 inode 代表的文件写入数据

dirlookup: 在一个目录下根据文件名查找指定文件,若找到,调用 iget 返回文件 inode

dirlink: 用来往目录添加文件

skipelem: 传入一个路径字符串,获取第一个目录,比如传入 “a/b/c”,这个函数会返回 a

namei: 根据路径名返回 inode

nameiparent: 返回路径所代表的最终文件的所在的目录的 inode。比如传入路径 “a/b/c”,这个函数会返回 b 的 inode

namex: 做 namei 和 nameiparent 所做的事情

TODO: here

相关文章:

  • android zxing QrCode 库集成转竖屏适配问题
  • 访问者模式(Visitor Pattern)
  • 【Springboot知识】Springboot计划任务Schedule详解
  • Dify - Embedding Rerank
  • 第六章 流量特征分析-蚁剑流量分析(玄机靶场系列)
  • 基于YOLOv8与LSKNet的遥感图像旋转目标检测新框架 —LSKblock注意力机制在小目标检测中的性能优化与SOTA探索
  • TCP/IP, CAN,LIN,SOCKET
  • 学习黑客Nmap 实战
  • Python字符串全面指南:从基础到高级操作
  • 代码随想录算法训练营Day45
  • MCP原理详解及实战案例(动嘴出UI稿、3D建模)
  • GESP2024年3月认证C++八级( 第二部分判断题(6-10))
  • 用Python打造自己的专属命令行工具
  • AI融合SEO关键词优化
  • BC35 判断字母
  • 【AI论文】KeySync:一种在高分辨率下实现无泄漏唇形同步的稳健方法
  • 【day03】简写单词 | dd爱框框 | 除2!
  • WebAssembly(Wasm):现代Web开发的超级加速器
  • 网星安全AWS攻防方案,重磅发布!
  • PCI/PCIe Error?设备总线?Bus?
  • 五一假期上海境外来沪消费4.55亿元,同比增长211.6%
  • 多地政府机关食堂迎来大客流,重庆荣昌区委书记给厨师们鼓劲
  • 立夏的野火饭
  • 蓝佛安主持东盟与中日韩财长和央行行长系列会议并举行多场双边会见
  • 科普|“小石头,大麻烦”,出现输尿管结石如何应对?
  • 426.8万人次!长三角铁路创单日客发量历史新高