?? 9.html
字號:
---------------------------------------------------------------------------------------------------<p>Here the cached_lookup() tries to find the given dentry in a cache of recently used dentries. If it is not found, the real_lookup() goes to the filesystem, which probably goes to disk, and actually finds the thing.After path_walk() is done, the nd argument contains the required dentry,which in turn has the inode information on the file. Finally we do dentry_open() that initializes a file struct:<p>---------------------------------------------------------------------------------------------------<br>struct file *<br>dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags) {<br> struct file *f = get_empty_filp();<br> f->f_dentry = dentry;<br> f->f_vfsmnt = mnt;<br> f->f_pos = 0;<br> f->f_op = dentry->d_inode->i_fop;<br> ...<br> return f;<br>}<br>---------------------------------------------------------------------------------------------------<p>So far the open. In short: walk the tree, for each component hope the information is in cache, and if not ask the file system. How does this work? Each file system type provides structs super_operations,file_operations, inode_operations, address_space_operations that contain the addresses of the routines that can do stuff. And thus<p>---------------------------------------------------------------------------------------------------<br>struct dentry *real_lookup(struct dentry *parent, struct qstr *name, int flags) {<br> struct dentry *dentry = d_alloc(parent, name);<br> parent->d_inode->i_op->lookup(dir, dentry);<br> return dentry;<br>}<br>---------------------------------------------------------------------------------------------------<p>calls on the lookup routine for the specific fiilesystem, as found in the struct inode_operations in the inode of the dentry for the directory in which we do the lookup.<p>And this file system specific routine must read the disk data and search the directory for the file we are looking for. Good examples of file systems are minix and romfs because they are simple and small. For example,in fs/romfs/inode.c:<p>---------------------------------------------------------------------------------------------------<br>romfs_lookup(struct inode *dir, struct dentry *dentry) {<br> const char *name = dentry->d_name.name;<br> int len = dentry->d_name.len;<br> char fsname[ROMFS_MAXFN];<br> struct romfs_inode ri;<br> unsigned long offset = dir->i_ino & ROMFH_MASK;<br> for (;;) {<br> romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE);<br> romfs_copyfrom(dir, fsname, offset+ROMFH_SIZE, len+1);<br> if (strncmp (name, fsname, len) == 0)<br> break;<br> /* next entry */<br> offset = ntohl(ri.next) & ROMFH_MASK;<br> }<br> inode = iget(dir->i_sb, offset);<br> d_add (dentry, inode);<br> return 0;<br>}<p>romfs_copyfrom(struct inode *i, void *dest,<br> unsigned long offset, unsigned long count) {<br> struct buffer_head *bh;<p> bh = bread(i->i_dev, offset>>ROMBSBITS, ROMBSIZE);<br> memcpy(dest, ((char *)bh->b_data) + (offset & ROMBMASK), count);<br> brelse(bh);<br>}<br>(All complications, all locking, and all error handling deleted.)<br>---------------------------------------------------------------------------------------------------<p><p><center><A HREF="#Content">[目錄]</A></center><hr><br><A NAME="I483" ID="I483"></A><center><b><font size=+2>read</font></b></center><br>Given a file descriptor (that keeps the inode and the file position of the file) we want to read. In fs/read_write.c we find:<p>---------------------------------------------------------------------------------------------------<br>ssize_t sys_read(unsigned int fd, char *buf, size_t count) {<br> struct file *file = fget(fd);<br> return file->f_op->read(file, buf, count, &file->f_pos);<br>}<br>---------------------------------------------------------------------------------------------------<p>That is, the read system call asks the file system to do the reading,starting at the current file position. The f_op field was filled in the dentry_open() routine above with the i_fop field of an inode.<p>For romfs the struct file_operations is assigned in romfs_read_inode(). For a regular file (case 2) it assigns generic_ro_fops. For a block special file (case 4) it calls init_special_inode() (see devices.c) which assigns<br>def_blk_fops.<p>How come romfs_read_inode() was ever called? When the filesystem was mounted, the routine romfs_read_super() was called, and it assigned romfs_ops to the s_op field of the superblock struct.<p>---------------------------------------------------------------------------------------------------<br>struct super_operations romfs_ops = {<br> read_inode: romfs_read_inode,<br> statfs: romfs_statfs,<br>};<br>---------------------------------------------------------------------------------------------------<p>And the iget() that was skipped over in the discussion above (in romfs_lookup()) finds the inode with given number ino in a cache, and if it cannot be found there creates a new inode struct by calling get_new_inode()(see fs/inode.c):<p>---------------------------------------------------------------------------------------------------<p>struct inode * iget(struct super_block *sb, unsigned long ino) {<br> struct list_head * head = inode_hashtable + hash(sb,ino);<br> struct inode *inode = find_inode(sb, ino, head);<br> if (inode) {<br> wait_on_inode(inode);<br> return inode;<br> }<br> return get_new_inode(sb, ino, head);<br>}<p>struct inode *<br>get_new_inode(struct super_block *sb, unsigned long ino,<br> struct list_head *head) {<br> struct inode *inode = alloc_inode();<br> inode->i_sb = sb;<br> inode->i_dev = sb->s_dev;<br> inode->i_ino = ino;<br> ...<br> sb->s_op->read_inode(inode);<br>}<br>---------------------------------------------------------------------------------------------------<p>So that is how the inode was filled, and we find that in our case (/dev/hda is a block special file) the routine that is called by sys_read is def_blk_fops.read, and inspection of block_dev.c shows that that is the routine block_read():<br>---------------------------------------------------------------------------------------------------<p>ssize_t block_read(struct file *filp, char *buf, size_t count, loff_t *ppos) {<br> struct inode *inode = filp->f_dentry->d_inode;<br> kdev_t dev = inode->i_rdev;<br> ssize_t blocksize = blksize_size[MAJOR(dev)][MINOR(dev)];<br> loff_t offset = *ppos;<br> ssize_t read = 0;<br> size_t left, block, blocks;<br> struct buffer_head *bhreq[NBUF];<br> struct buffer_head *buflist[NBUF];<br> struct buffer_head **bh;<p> left = count; /* bytes to read */<br> block = offset / blocksize; /* first block */<br> offset &= (blocksize-1); /* starting offset in block */<br> blocks = (left + offset + blocksize - 1) / blocksize;<p> bh = buflist;<br> do {<br> while (blocks) {<br> --blocks;<br> *bh = getblk(dev, block++, blocksize);<br> if (*bh && !buffer_uptodate(*bh))<br> bhreq[bhrequest++] = *bh;<br> }<br> if (bhrequest)<br> ll_rw_block(READ, bhrequest, bhreq);<br> /* wait for I/O to complete,<br> copy result to user space,<br> increment read and *ppos, decrement left */<br> } while (left > 0);<br> return read;<br>}<br>---------------------------------------------------------------------------------------------------<p>So the building blocks here are getblk(), ll_rw_block(), and wait_on_buffer().<p>The first of these lives in fs/buffer.c. It finds the buffer that already contains the required data if we are lucky, and otherwise a buffer that is going to be used.<p>---------------------------------------------------------------------------------------------------<br>struct buffer_head * getblk(kdev_t dev, int block, int size) {<br> struct buffer_head *bh;<br> int isize;<p>try_again:<br> bh = __get_hash_table(dev, block, size);<br> if (bh)<br> return bh;<br> isize = BUFSIZE_INDEX(size);<br> bh = free_list[isize].list;<br> if (bh) {<br> __remove_from_free_list(bh);<br> init_buffer(bh);<br>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -