操作系统真象还原中文件系统部分的一个实现错误

file_table是file类型. 如下:

struct file {
   uint32_t fd_pos;
   uint32_t fd_flag;
   struct inode* fd_inode;
};

file没有引用计数字段. 实际上应该有引用计数字段. 为什么需要引用计数字段, 这要到实现fork时才有清晰的原因.
sys_fork调用了fork, fork调用了copy_process, 在copy_process中, 有update_inode_open_cnts, 这个函数干的事情是

static void update_inode_open_cnts(struct task_struct* thread) {
   int32_t local_fd = 3, global_fd = 0;
   while (local_fd < MAX_FILES_OPEN_PER_PROC) {
      global_fd = thread->fd_table[local_fd];
      ASSERT(global_fd < MAX_FILE_OPEN);
      if (global_fd != -1) {
	 file_table[global_fd].fd_inode->i_open_cnts++;
      }
      local_fd++;
   }
}

再看看sys_close的实现

int32_t sys_close(int32_t fd) {
   int32_t ret = -1;
   if (fd > 2) {
      uint32_t _fd = fd_local2global(fd);
      ret = file_close(&file_table[_fd]);
      running_thread()->fd_table[fd] = -1;
   }
   return ret;
}

file_close是:

int32_t file_close(struct file* file) {
   if (file == NULL) {
      return -1;
   }
   file->fd_inode->write_deny = false;
   inode_close(file->fd_inode);
   file->fd_inode = NULL; // 这一行使file_table中的项失效
   return 0;
}

现在来举出一个场景. 父进程fork出子进程, 子进程sys_close了一个文件, 看看上面的实现, file_table中的项必然失效了. 父进程即时不调用sys_close, 也会失效(因为子进程和父进程共用file_table). 其实书里也是有意识要解决这个问题的, 做的事就是前面列出过的update_inode_open_cnts, 但是那只是inode的引用计数++, 没有用. 我认为inode的引用计数不应该++, 应该在struct file中加上引用计数字段.

原文地址:https://www.cnblogs.com/Tokubara/p/15152442.html