Linux kernel Source-code scenario analysis-Opening of a file

Source: Internet
Author: User
Tags goto

the system call for opening the file is open (), implemented in the kernel via Sys_open (), assuming that filename is "/usr/local/hello.c", and assuming that the file already exists, the code is as follows:

Asmlinkage Long Sys_open (const char * filename, int flags, int mode) {char * tmp;int fd, error; #if bits_per_long! = 32flags |= o_largefile; #endiftmp = getname (filename);//Copy the path name of the file from user space to system space FD = PTR_ERR (TMP); if (!is_err (tmp)) {FD = Get_unused_ FD ();//A free table entry is found in the Open File table of the current process, and the subscript of the table entry is "Open file number" if (FD >= 0) {struct file *f = Filp_open (TMP, flags, mode);// Gets the file structure of an associated document error = Ptr_err (f), if (Is_err (f)) Goto Out_error;fd_install (FD, f);//The pointer to the new file data structure is "installed" to the file_ of the current process }out:putname (TMP) in struct structure;} Return fd;//last return file number out_error:put_unused_fd (FD); fd = Error;goto out;}


GET_UNUSED_FD, an idle table entry is found in the Open File table of the current process, and the subscript for the table entry is "Open file Number", as shown in the following code:
int get_unused_fd (void) {struct files_struct * files = current->files;int fd, error; Error =-emfile;write_lock (&files->file_lock); repeat:fd = Find_next_zero_bit (Files->open_fds, files-> Max_fdset, FILES->NEXT_FD);//In Open_fds, find the free open file number */* n.b. For clone tasks sharing a files structure, this test * would limit the total number of files The can is opened. */if (fd >= current->rlim[rlimit_nofile].rlim_cur) goto out;/* Do we need to expand the Fdset array? */if (FD >= files->max_fdset) {//if bitmap capacity is insufficient, the extension error = Expand_fdset (files, fd); if (!error) {error =-emfile;goto Repea t;} Goto out;} /* * Check Whether we need to expand the FD array. */if (FD >= Files->max_fds) {//If the file structure pointer array has insufficient capacity, then the extension error = Expand_fd_array (files, fd); if (!error) {error =-emfile ; goto repeat;} Goto out;} Fd_set (FD, FILES->OPEN_FDS);//Set, next time can not find the FD_CLR (FD, files->close_on_exec); files->next_fd = fd + 1;// Next Open file number plus 1 #if 1/* sanity check */if (FILES->FD[FD]! = NULL) {PRINTK ("get_Unused_fd:slot%d not null!\n ", FD); FILES->FD[FD] = NULL;} #endiferror = Fd;out:write_unlock (&files->file_lock); return error;}
struct Files_struct {atomic_t count;rwlock_t file_lock;int Max_fds;//The capacity of the current file structure pointer array int max_fdset;//the capacity of the bitmap int next_fd; The next open file number struct file * * fd;//points to fd_arrayfd_set *close_on_exec; pointed to the Close_on_exec_initfd_set *open_fds;      Point to Open_fds_initfd_set close_on_exec_init;fd_set open_fds_init;struct file * Fd_array[nr_open_default];};


After the open file number has been obtained, Filp_open to obtain a document structure, first listing the file structure as follows:

struct file {struct list_headf_list;struct dentry*f_dentry;//pointer to the DENTRY structure of the file f_dentrystruct vfsmount         *f_vfsmnt ;//Pointer to the VFSMNT structure that installs the file's device in the file system struct file_operations*f_op;atomic_tf_count;unsigned int f_flags;mode_tf_mode; loff_tf_pos;//current Read and write location unsigned long f_reada, F_ramax, F_raend, F_ralen, f_rawin;struct fown_structf_owner;unsigned intf _uid, f_gid;intf_error;unsigned longf_version;/* needed for TTY driver, and maybe others */void*private_data;};
File_open, the code is as follows:

struct file * Filp_open (const char * filename, int flags, int mode) {int namei_flags, error;struct nameidata nd;namei_flags = Flags;if (( namei_flags+1) & O_accmode) namei_flags++;if (Namei_flags & O_trunc) namei_flags |= 2;error = Open_namei (filename , namei_flags, mode, &nd);//Get Nd->dentry structure if (!error) return dentry_open  (Nd.dentry, nd.mnt, flags);//Fill the file structure with Nd->dentry structure return err_ptr (error);} 
int Open_namei (const char * pathname, int flag, int mode, struct nameidata *nd) {int Acc_mode, error = 0;struct inode *inod E;struct dentry *dentry;struct dentry *dir;int count = 0;acc_mode = Acc_mode (flag);/* * The simplest case-just a plain l Ookup. */IF (! ( Flag & O_creat)) {//assuming flag is o_create, if the file does not exist create if (Path_init (pathname, lookup_flags (flag), ND)) error = Path_walk ( pathname, ND); if (error) return error;dentry = Nd->dentry;goto OK;} /* * Create-we need to know the parent. */if (Path_init (Pathname, lookup_parent, nd)) error = Path_walk (pathname, ND);//Find parent node if (error) return error;/* * We have th E parent and last component. First of all, check * This we is not asked to creat (2) An obvious directory-that * won't do. */error =-eisdir;if (nd->last_type! = Last_norm | | nd->last.name[nd->last.len])//Although nd-> Dentry saves the dentry structure of the parent node, and Nd->last holds the name of the last node, Nd->last_type is the type of the last node, which ensures Last_type is Last_norm, And last node name must end with/0 goto Exit;dir = Nd->dentry;down (&DIR->D_INODE->I_SEM);d entry = Lookup_hash (&nd->last, nd->dentry);//Find the dentry structure of the last node Do_last:error = ptr_ ERR (Dentry), if (Is_err (dentry)) {up (&dir->d_inode->i_sem); goto exit;} /* Negative dentry, just create the file */if (!dentry->d_inode) {//We assume the last node exists, that is, the inode structure exists error = Vfs_create (DIR-&G T;d_inode, Dentry, mode), Up (&DIR->D_INODE->I_SEM);dp ut (nd->dentry); nd->dentry = dentry;if (Error) Goto exit;/* don ' t check for write permission, don ' t truncate */acc_mode = 0;flag &= ~o_trunc;goto OK;} /* * It already exists. */up (&dir->d_inode->i_sem); error =-EEXIST;IF (flag & O_EXCL) goto exit_dput;if (D_mountpoint (dentry)) {/ /is mount point error =-ELOOP;IF (flag & O_nofollow) goto Exit_dput;do __follow_down (&nd->mnt,&dentry); while (D_mountpoint (Dentry));} Error =-enoent;if (!dentry->d_inode) goto exit_dput;if (Dentry->d_inode->i_op && dentry->d_inode- >i_op->follow_link) Goto do_link;dput (nd->dentry); Nd->dentry = dentry;//The dentry structure of the last node is saved in nd->dentry error =-eisdir;if (Dentry->d_inode && s_isdir (dentry->d _inode->i_mode) Goto Exit;ok:error =-enoent;//down temporarily does not care about inode = dentry->d_inode;if (!inode) goto exit;error =-ELOOP; if (S_islnk (Inode->i_mode)) goto Exit;error =-eisdir;if (S_isdir (inode->i_mode) && (Flag & Fmode_  WRITE) Goto Exit;error = permission (Inode,acc_mode); if (error) goto exit;/* * FIFO ' s, sockets and device files are special: They don ' t * actually live on the filesystem itself, and as such you * can write to them even if the filesystem is Read-o Nly. */if (S_isfifo (inode->i_mode) | | S_issock (Inode->i_mode)) {flag &= ~o_trunc;} else if (s_isblk (inode->i_mode) | | S_ISCHR (Inode->i_mode)) {error =-eacces;if (Is_nodev (inode)) goto Exit;flag &= ~o_trunc;} else {error =-erofs;if ( Is_rdonly (inode) && (flag & 2) goto exit;} /* * An append-only file must is opened in append mode for writing. */error =-eperm;if (is_apPEND (Inode)) {if (flag & Fmode_write) &&! ( Flag & O_append) Goto exit;if (flag & O_trunc) goto exit; /* * Ensure there is no outstanding leases on the file. */error = Get_lease (inode, Flag), if (Error) Goto EXIT;IF (flag & o_trunc) {error = get_write_access (inode); if (error) go To exit;/* * Refuse to truncate files with mandatory locks held on them. */error = locks_verify_locked (inode), if (!error) {dquot_init (inode); error = Do_truncate (dentry, 0);} Put_write_access (Inode); if (error) goto exit;} ElseIf (Flag & Fmode_write) Dquot_init (inode); return 0;exit_dput:dput (Dentry); exit:path_release (ND); return error ;d o_link:error =-eloop;if (flag & O_nofollow) Goto exit_dput;/* * This is subtle. Instead of calling Do_follow_link () we do the * thing by hands. The reason is, this, we have a zero link_count * and Path_walk () (called from->follow_link) honoring Lookup_paren T. * After then we have the parent and last component, i.e. * we is in the same situation as After the first path_walk (). * Well, almost-if the last component is normal we get it copy * stored in Nd->last.name and we'll have to Putname ( It when we * is done. Procfs-like symlinks just set last_bind. */update_atime (dentry->d_inode); error = Dentry->d_inode->i_op->follow_link (dentry, ND);dp ut (dentry); if (error) return error;if (Nd->last_type = = last_bind) {dentry = Nd->dentry;goto OK;} Error =-eisdir;if (nd->last_type! = last_norm) goto exit;if (Nd->last.name[nd->last.len]) {Putname (nd-> Last.name); goto exit;} if (count++==32) {dentry = Nd->dentry;putname (nd->last.name); goto OK;} dir = Nd->dentry;down (&dir->d_inode->i_sem);d entry = Lookup_hash (&nd->last, nd->dentry); Putname (nd->last.name); goto Do_last;}

Return to File_open and continue with Dentry_open to populate the file structure with the following code:

struct file *dentry_open (struct dentry *dentry, struct vfsmount *mnt, int flags) {struct file * f;struct inode *inode;int E Rror;error =-enfile;f = Get_empty_filp ();//Allocate an idle file data structure if (!f) goto cleanup_dentry;f->f_flags = flags;f->f_ mode = (flags+1) & o_accmode;inode = Dentry->d_inode;if (F->f_mode & fmode_write) {error = Get_write_access ( Inode); if (error) goto Cleanup_file;} F->f_dentry = dentry;//The dentry structure of the node f->f_vfsmnt = mnt;//The vfsmount structure of the node F->f_pos = 0;f->f_reada = 0;f->f_ op = fops_get (INODE->I_FOP);//f->f_op is assigned Inode_i_fopif (INODE->I_SB) File_move (F, &inode->i_sb-> S_files)///Remove it from the middle queue and hang it into the file structure queue S_filesif (f->f_op && f->f_op->open) in the super_block structure of the device in which it resides {error = F->f_op->open (inode,f); if (error) goto Cleanup_all;} F->f_flags &= ~ (o_creat | O_excl | O_noctty | O_trunc), return F;cleanup_all:fops_put (F->F_OP), if (F->f_mode & Fmode_write) put_write_access (inode); f >f_dentry = null;f->f_vfsmnt = Null;cleanup_file:put_filp (f); Cleanup_dentry:dput (dentry); Mntput (MNT); return err_ptr (Error);} 
Get_empty_filp, allocates a free file data structure. There is a queue free_list in the kernel that has a free file structure that takes a file structure from the queue and temporarily hangs it into an intermediate queue anon_list. After confirming that the file can be written, the idle file structure is initialized. The file structure queue S_files in the super_block structure of the device in which it is located is then hung from the middle queue by File_move ().
struct file * Get_empty_filp (void) {static int old_max = 0;struct file * F;file_list_lock (); if (Files_stat.nr_free_files &G T Nr_reserved_files) {used_one:f = List_entry (free_list.next, struct file, f_list); List_del (&f->f_list);// There is a queue free_list in the kernel that has a free file structure, and a files_stat.nr_free_files--;new_one:memset (f, 0, sizeof (*F)) is removed from the queue when the file structure is required; atomic _set (&f->f_count,1); f->f_version = ++event;f->f_uid = Current->fsuid;f->f_gid = Current->fsgid ; List_add (&f->f_list, &anon_list);//and temporarily hang it into an intermediate queue anon_listfile_list_unlock (); return f;} /* * Use a reserved one if we ' re the Superuser */if (files_stat.nr_free_files &&!current->euid) goto used_one;/ * * Allocate A new one if we ' re below the limit. */if (Files_stat.nr_files < Files_stat.max_files) {file_list_unlock (); f = Kmem_cache_alloc (Filp_cachep, SLAB_ KERNEL); File_list_lock (); if (f) {Files_stat.nr_files++;goto new_one;} /* Big problems ... */printk ("Vfs:filp allocation failed\n");} else if (Files_stat.max_files > Old_max) {printk ("Vfs:file-max limit%d reached\n", files_stat.max_files); Old_max = Files_stat.max_files;} File_list_unlock (); return NULL;}
At this point, filp_open analysis is complete, return to Sys_open, execute Fd_install, the pointer to the new file data structure is "installed" into the file_struct structure of the current process, the code is as follows:

static inline void fd_install (unsigned int fd, struct file * file) {struct Files_struct *files = Current->files;write_lo CK (&files->file_lock), if (FILES->FD[FD]) BUG (); FILES->FD[FD] = File;write_unlock (&files->file_ Lock);}

Linux kernel Source-code scenario analysis-Opening of a file

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.