xzy610030

一起探讨,一起进步,一起分享!

linux open 系统调用过程

0
阅读(3038)
linux中系统掉用内核部分会调用sys_***(open ,read, write ,close.......)
sys_open是linux系统调用open的内核部部分的函数。
asmlinkage long sys_open(const char __user *filename, int flags, int mode)
{
 if (force_o_largefile())
  flags |= O_LARGEFILE;
 return do_sys_open(filename, flags, mode);
}
long do_sys_open(const char __user *filename, int flags, int mode)
{
 char *tmp = getname(filename);
 int fd = PTR_ERR(tmp);
 if (!IS_ERR(tmp)) {
  fd = get_unused_fd();
  if (fd >= 0) {
   struct file *f = filp_open(tmp, flags, mode);
   if (IS_ERR(f)) {
    put_unused_fd(fd);
    fd = PTR_ERR(f);
   } else {
    fsnotify_open(f->f_dentry);
    fd_install(fd, f); //将 fd 与file结构关联,以便 read write 等系统调用使用!  《1》
   }
  }
  putname(tmp);
 }
 return fd;
}
struct file *filp_open(const char * filename, int flags, int mode)
{
 int namei_flags, error;
 struct nameidata nd;
 struct file *f;
 namei_flags = flags;
 if ((namei_flags+1) & O_ACCMODE)
  namei_flags++;
 if (namei_flags & O_TRUNC)
  namei_flags |= 2;
 error = -ENFILE;
 f = get_empty_filp(); //为每个打开的文件分配一个file结构
 if (f == NULL)
  return ERR_PTR(error);
 error = open_namei(filename, namei_flags, mode, &nd);
 if (!error)
  return __dentry_open(nd.dentry, nd.mnt, flags, f);
 put_filp(f);
 return ERR_PTR(error);
}
static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,
     int flags, struct file *f)
{
 struct inode *inode;
 int error;
 f->f_flags = flags;
 f->f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK |
    FMODE_PREAD | FMODE_PWRITE;
 inode = dentry->d_inode;
 if (f->f_mode & FMODE_WRITE) {
  error = get_write_access(inode);
  if (error)
   goto cleanup_file;
 }
 f->f_mapping = inode->i_mapping;
 f->f_dentry = dentry;
 f->f_vfsmnt = mnt;
 f->f_pos = 0;
 f->f_op = fops_get(inode->i_fop);//从inode节点中找出对应文件的file_opereations(可见每打开一次文件就有一个file 结构被创建而无论这个文件有多少个进程打开打都指向同一个inode)
 file_move(f, &inode->i_sb->s_files);
 if (f->f_op && f->f_op->open) {
  error = f->f_op->open(inode,f); //在这里调用驱动程序中的open函数
  if (error)
   goto cleanup_all;
 }
 f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
 file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
 /* NB: we're sure to have correct a_ops only after f_op->open */
 if (f->f_flags & O_DIRECT) {
  if (!f->f_mapping->a_ops ||
      ((!f->f_mapping->a_ops->direct_IO) &&
      (!f->f_mapping->a_ops->get_xip_page))) {
   fput(f);
   f = ERR_PTR(-EINVAL);
  }
 }
 return f;
cleanup_all:
 fops_put(f->f_op);
 if (f->f_mode & FMODE_WRITE)
  put_write_access(inode);
 file_kill(f);
 f->f_dentry = NULL;
 f->f_vfsmnt = NULL;
cleanup_file:
 put_filp(f);
 dput(dentry);
 mntput(mnt);
 return ERR_PTR(error);
}
 
 
《1》
/*
 * Install a file pointer in the fd array.  
 *
 * The VFS is full of places where we drop the files lock between
 * setting the open_fds bitmap and installing the file in the file
 * array.  At any such point, we are vulnerable to a dup2() race
 * installing a file in the array before us.  We need to detect this and
 * fput() the struct file we are about to overwrite in this case.
 *
 * It should never happen - if we allow dup2() do it, _really_ bad things
 * will follow.
 */
void fastcall fd_install(unsigned int fd, struct file * file)
{
 struct files_struct *files = current->files;
 struct fdtable *fdt;
 spin_lock(&files->file_lock);
 fdt = files_fdtable(files);
 BUG_ON(fdt->fd[fd] != NULL);
 rcu_assign_pointer(fdt->fd[fd], file);
 spin_unlock(&files->file_lock);
}