📄 files.txt
字号:
File management in the Linux kernel-----------------------------------This document describes how locking for files (struct file)and file descriptor table (struct files) works.Up until 2.6.12, the file descriptor table has been protectedwith a lock (files->file_lock) and reference count (files->count).->file_lock protected accesses to all the file related fieldsof the table. ->count was used for sharing the file descriptortable between tasks cloned with CLONE_FILES flag. Typicallythis would be the case for posix threads. As with the commonrefcounting model in the kernel, the last task doinga put_files_struct() frees the file descriptor (fd) table.The files (struct file) themselves are protected usingreference count (->f_count).In the new lock-free model of file descriptor management,the reference counting is similar, but the locking isbased on RCU. The file descriptor table contains multipleelements - the fd sets (open_fds and close_on_exec, thearray of file pointers, the sizes of the sets and the arrayetc.). In order for the updates to appear atomic toa lock-free reader, all the elements of the file descriptortable are in a separate structure - struct fdtable.files_struct contains a pointer to struct fdtable throughwhich the actual fd table is accessed. Initially thefdtable is embedded in files_struct itself. On a subsequentexpansion of fdtable, a new fdtable structure is allocatedand files->fdtab points to the new structure. The fdtablestructure is freed with RCU and lock-free readers eithersee the old fdtable or the new fdtable making the updateappear atomic. Here are the locking rules forthe fdtable structure -1. All references to the fdtable must be done through the files_fdtable() macro : struct fdtable *fdt; rcu_read_lock(); fdt = files_fdtable(files); .... if (n <= fdt->max_fds) .... ... rcu_read_unlock(); files_fdtable() uses rcu_dereference() macro which takes care of the memory barrier requirements for lock-free dereference. The fdtable pointer must be read within the read-side critical section.2. Reading of the fdtable as described above must be protected by rcu_read_lock()/rcu_read_unlock().3. For any update to the fd table, files->file_lock must be held.4. To look up the file structure given an fd, a reader must use either fcheck() or fcheck_files() APIs. These take care of barrier requirements due to lock-free lookup. An example : struct file *file; rcu_read_lock(); file = fcheck(fd); if (file) { ... } .... rcu_read_unlock();5. Handling of the file structures is special. Since the look-up of the fd (fget()/fget_light()) are lock-free, it is possible that look-up may race with the last put() operation on the file structure. This is avoided using atomic_inc_not_zero() on ->f_count : rcu_read_lock(); file = fcheck_files(files, fd); if (file) { if (atomic_inc_not_zero(&file->f_count)) *fput_needed = 1; else /* Didn't get the reference, someone's freed */ file = NULL; } rcu_read_unlock(); .... return file; atomic_inc_not_zero() detects if refcounts is already zero or goes to zero during increment. If it does, we fail fget()/fget_light().6. Since both fdtable and file structures can be looked up lock-free, they must be installed using rcu_assign_pointer() API. If they are looked up lock-free, rcu_dereference() must be used. However it is advisable to use files_fdtable() and fcheck()/fcheck_files() which take care of these issues.7. While updating, the fdtable pointer must be looked up while holding files->file_lock. If ->file_lock is dropped, then another thread expand the files thereby creating a new fdtable and making the earlier fdtable pointer stale. For example : spin_lock(&files->file_lock); fd = locate_fd(files, file, start); if (fd >= 0) { /* locate_fd() may have expanded fdtable, load the ptr */ fdt = files_fdtable(files); FD_SET(fd, fdt->open_fds); FD_CLR(fd, fdt->close_on_exec); spin_unlock(&files->file_lock); ..... Since locate_fd() can drop ->file_lock (and reacquire ->file_lock), the fdtable pointer (fdt) must be loaded after locate_fd().
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -