栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

Linux Kernal VFS-Open()(2)

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Linux Kernal VFS-Open()(2)

2021SC@SDUSC

Now we've known what fd is, how does fd function remains unseen.Start with function open(), we shall discuss about how actually those operations to files finally happens.

Open()

We might write some code to open a file in linux that is:

#include                                                        
using namespace std;
int main()
{
    off_t fd;
    fd=open("rd.in",O_RDONLY);
    cout< 

fd will be given an number which is unsigned integer that we've talked about.Usually the number is larger than 3 because 0,1,2 have been used as stdin, stdout and stderr.

Do_sys_open

How does the kernal get such fd?Go back to functions to see.When users' process call open() to open a file, kernal VFS will call sys_open()->do_sys_open() to function.Here's part of the code.

long do_sys_open(int dfd, const char __user *filename, int flags, int mode)
 
{
 
         char *tmp = getname(filename);    //copy filename and other messages to the kernal space.
         int fd = PTR_ERR(tmp);
         if (!IS_ERR(tmp)) {
                   fd = get_unused_fd_flags(flags);   //get an unused fd flag.
                   if (fd >= 0) { 
                            struct file *f = do_filp_open(dfd, tmp, flags, mode);  //new file struct
                            if (IS_ERR(f)) {
 
                                     put_unused_fd(fd);   //if err, release fd for others.
 
                                     fd = PTR_ERR(f);
 
                            } else {
 
                                    fsnotify_open(f->f_path.dentry);
                                    fd_install(fd, f);    // install the file(use fd)into the fd list of the processes.
                            }
 
                   }
                   putname(tmp);
         }
         return fd; //that is the fd we needed.
}

Filename(route) is copied to the kernal space, and with the route the kernal manage to find the dentry in the file system through which we could find the inode which point at the operations towards the file.Although through we could check the inode for each file, the user's process will only need to know fd to open the file and read the inside data.

Do_filp_open

Then the function do_flip_open initialize a struct file, which also is a bridge between file and process.This function also finished most of the word in opening a file.This function is defined in fs/namei.c

 

struct file *do_filp_open(int dfd, struct filename *pathname,
		const struct open_flags *op)
{
	struct nameidata nd;
	int flags = op->lookup_flags;
	struct file *filp;

	set_nameidata(&nd, dfd, pathname, NULL);
	filp = path_openat(&nd, op, flags | LOOKUP_RCU);
	if (unlikely(filp == ERR_PTR(-ECHILD)))
		filp = path_openat(&nd, op, flags);
	if (unlikely(filp == ERR_PTR(-ESTALE)))
		filp = path_openat(&nd, op, flags | LOOKUP_Reval);
	restore_nameidata();
	return filp;
}

The lower 2 bits in parameter open_flag show the permission to the file, which means:

        00 - read-only
        01 - write-only
        10 - read-only
        11 - special

The permission will soon be saved to flag.

Now we mainly care about how the pathname is caculated.In function path_init, nd(nameidata, a pointer to struct nameidata) will be filled.So what will be done to fill the nd?Let's dive into the function path_openat which turns out to be the most necessary part.Well firstly what function unlikely and likely actually mean?

 

Likely and unlikely

Unlikely() and likely() is macros defined in include/linux/compiler.h:

#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)

Note:You may use __builtin_expect to provide the compiler with branch prediction information. In general, you should prefer to use actual profile feedback for this (‘-fprofile-arcs’), as programmers are notoriously bad at predicting how their programs actually perform. However, there are applications in which this data is hard to collect.The return value is the value of exp, which should be an integral expression. The semantics of the built-in are that it is expected that exp == c.

The explaination means that something is 'likely' to happen, which means the if case often occurs.Unlikely(), of course, means the opposite way that is the else case is most likely to happen.So if likely() appears, the cpu will compile the if case forward to increase the efficiency.

Unlikely() and likely() will not effect the correctness of the program, but will fastern the running speed.

So as we see the code above, we could say that filp==ERR_PTR(_ECHILD) is not likely to happen.

nameidata(nd)

nameidata is a struct to save the context and result in path_walking procedure.

struct nameidata {
    struct path path;       
    struct qstr last;       
    struct path root;       
    struct inode    *inode; 
    unsigned int    flags;  
    unsigned    seq;        
    int     last_type;      
    unsigned    depth;      
    char *saved_names[MAX_NESTED_linkS + 1]; 
};

The next blog we'll analyse how path_openat works and the role nd played in it.

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/599999.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号