一些结构

// kernle/file.h
// 文件控制块
struct file {
  enum { FD_NONE, FD_PIPE, FD_INODE, FD_DEVICE } type;
  int ref; // reference count
  char readable;
  char writable;
  struct pipe *pipe; // FD_PIPE
  struct inode *ip;  // FD_INODE and FD_DEVICE
  uint off;          // FD_INODE
  short major;       // FD_DEVICE
};
// kernel/fs.h
// 磁盘索引结点
struct dinode {
  short type;           // File type
  short major;          // Major device number (T_DEVICE only)
  short minor;          // Minor device number (T_DEVICE only)
  short nlink;          // Number of links to inode in file system
  uint size;            // Size of file (bytes)
  uint addrs[NDIRECT+1];   // Data block addresses
};
#define NDIRECT 12
// kernel/file.h
// 内存索引结点
struct inode {
  uint dev;           // Device number
  uint inum;          // Inode number
  int ref;            // Reference count
  struct sleeplock lock; // protects everything below here
  int valid;          // inode has been read from disk?

  short type;         // copy of disk inode
  short major;
  short minor;
  short nlink;
  uint size;
  uint addrs[NDIRECT+1];
};
// kernel/fs.h
// 目录项
struct dirent {
  ushort inum;
  char name[DIRSIZ];
};

addition

Major number (主设备号)

Traditionally, the major number identifies the driver associated with the device. A major number can also be shared by multiple device drivers.

Minor number (次设备号)

The major number is to identify the corresponding driver. Many devices may use the same major number. So we need to assign the number to each device that is using the same major number.

file_index

目录查询

dir_walk
// kernel/fs.c
static struct inode*
namex(char *path, int nameiparent, char *name)
{
  struct inode *ip, *next;

  if(*path == '/')
    ip = iget(ROOTDEV, ROOTINO);
  else
    ip = idup(myproc()->cwd);

  while((path = skipelem(path, name)) != 0){
    ilock(ip);
    if(ip->type != T_DIR){
      iunlockput(ip);
      return 0;
    }
    if(nameiparent && *path == '\0'){
      // Stop one level early.
      iunlock(ip);
      return ip;
    }
    if((next = dirlookup(ip, name, 0)) == 0){
      iunlockput(ip);
      return 0;
    }
    iunlockput(ip);
    ip = next;
  }
  if(nameiparent){
    iput(ip);
    return 0;
  }
  return ip;
}

open系统调用

open()

void
ls(char *path)
{
  char buf[512], *p;
  int fd;

  if((fd = open(path, 0)) < 0){
    fprintf(2, "ls: cannot open %s\n", path);
    return;
  }
  ...
}
int open(const char* file, int omode);
  • file: 文件名,相对路径和绝对路径

  • omode: 打开方式

    omodevalue描述
    O_RDONLY0只读
    O_WRONLY1<<0只写
    O_RDWR1<<1读写
    O_CREATE1<<9新建
    O_TRUNC1<<10删除
  • 返回值: 一个整数表示文件描述符,打开失败返回-1

sys_open()

// kernel/sysfile.c
uint64
sys_open(void)
{
  char path[MAXPATH];
  int fd, omode;
  struct file *f;
  struct inode *ip;
  int n;

  // 取参数
  argint(1, &omode);
  if((n = argstr(0, path, MAXPATH)) < 0)
    return -1;

  // 表示开始一个事务
  begin_op();

  if(omode & O_CREATE){
    ip = create(path, T_FILE, 0, 0);
    if(ip == 0){
      end_op();
      return -1;
    }
  } 
  // 不需要新建
  else {
    // 获取目标文件的inode
    if((ip = namei(path)) == 0){
      end_op();
      return -1;
    }
    ilock(ip);
    // 目录只能以只读方式打开
    if(ip->type == T_DIR && omode != O_RDONLY){
      iunlockput(ip);
      end_op();
      return -1;
    }
  }

  // 设备文件
  if(ip->type == T_DEVICE && (ip->major < 0 || ip->major >= NDEV)){
    iunlockput(ip);
    end_op();
    return -1;
  }

  // 分配文件控制块和文件描述符
  if((f = filealloc()) == 0 || (fd = fdalloc(f)) < 0){
    if(f)
      fileclose(f);
    iunlockput(ip);
    end_op();
    return -1;
  }

  // 设备文件
  if(ip->type == T_DEVICE){
    f->type = FD_DEVICE;
    f->major = ip->major;
  } 
  // 文件或目录
  else {
    f->type = FD_INODE;
    f->off = 0;
  }
  f->ip = ip;
  // 非只写
  f->readable = !(omode & O_WRONLY);
  // 只写或可读可写
  f->writable = (omode & O_WRONLY) || (omode & O_RDWR);
  
  // 删除文件
  if((omode & O_TRUNC) && ip->type == T_FILE){
    itrunc(ip);
  }

  iunlock(ip);
  // 结束一个事务
  end_op();
  
  // 返回文件描述符
  return fd;
}

create()

// kernel/sysfile.c
static struct inode*
create(char *path, short type, short major, short minor)
{
  struct inode *ip, *dp;
  char name[DIRSIZ];

  // struct inode* nameiparent(char *path, char *name)
  // 返回path的父目录的inode和目标文件的name
  // e.g., path="/etc/apt/config"
  // dp = inode("/etc/apt/")
  // name = "config"
  if((dp = nameiparent(path, name)) == 0)
    return 0;

  ilock(dp);

  // struct inode* dirlookup(struct inode *dp, char *name, uint *poff)
  // 查询dp目录下name文件的inode
  if((ip = dirlookup(dp, name, 0)) != 0){
    iunlockput(dp);
    ilock(ip);
    if(type == T_FILE && (ip->type == T_FILE || ip->type == T_DEVICE))
      return ip;
    iunlockput(ip);
    return 0;
  }

  // 若文件不存在
  // 分配inode
  if((ip = ialloc(dp->dev, type)) == 0){
    iunlockput(dp);
    return 0;
  }

  // 设置inode
  ilock(ip);
  ip->major = major;
  ip->minor = minor;
  ip->nlink = 1;
  // 将ip写入到磁盘
  iupdate(ip);

  // 目录文件
  if(type == T_DIR){  // Create . and .. entries.
    // No ip->nlink++ for ".": avoid cyclic ref count.
    if(dirlink(ip, ".", ip->inum) < 0 || dirlink(ip, "..", dp->inum) < 0)
      goto fail;
  }

  // 添加目录项
  if(dirlink(dp, name, ip->inum) < 0)
    goto fail;

  if(type == T_DIR){
    // now that success is guaranteed:
    dp->nlink++;  // for ".."
    iupdate(dp);
  }

  iunlockput(dp);

  // 未释放ip的锁
  return ip;

 fail:
  // something went wrong. de-allocate ip.
  ip->nlink = 0;
  iupdate(ip);
  iunlockput(ip);
  iunlockput(dp);
  return 0;
}

file descriptor (文件描述符)

// kernel/sysfile.c
static int
fdalloc(struct file *f)
{
  int fd;
  struct proc *p = myproc();

  // NOFILE: 每个进程最多打开文件数
  for(fd = 0; fd < NOFILE; fd++){
    if(p->ofile[fd] == 0){
      p->ofile[fd] = f;
      // 文件描述符即为下标
      return fd;
    }
  }
  return -1;
}
struct proc {
...
  int pid;                     // Process ID
  struct file *ofile[NOFILE];  // Open files
  struct inode *cwd;           // Current directory
...
};