“本文档描述了锁定文件(结构文件)和文件描述符表(结构文件)的工作方式。”
![ed1ecc50c4c94ddb2cafa5ad0885b0c1.png](https://img-blog.csdnimg.cn/img_convert/ed1ecc50c4c94ddb2cafa5ad0885b0c1.png)
struct fdtable *fdt;rcu_read_lock();fdt = files_fdtable(files);....if (n <= fdt->max_fds) .......rcu_read_unlock();
files_fdtable()使用
rcu_dereference()
宏,该宏负责无锁解除引用的内存屏障要求。fdtable指针必须在读取侧关键部分内读取。
如上所述,必须通过
rcu_read_lock()
/ 保护fdtable的读取
rcu_read_unlock()
。
对于fd表的任何更新,必须保留files-> file_lock。
要查找给定fd的文件结构,读者必须使用fcheck()或fcheck_files()API。由于无锁查找,这些功能可满足对屏障的要求。
一个例子:
struct file *file;rcu_read_lock();file = fcheck(fd);if (file) { ...}....rcu_read_unlock();
文件结构的处理很特殊。
由于fd(fget()/ fget_light())的查找是无锁的,因此查找可能与文件结构上的最后一次put()操作竞争。
使用-> f_count上的atomic_long_inc_not_zero()可以避免这种情况:
rcu_read_lock();file = fcheck_files(files, fd);if (file) { if (atomic_long_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_long_inc_not_zero()检测引用计数是否已经为零或在递增期间变为零。如果是这样,我们将使fget()/ fget_light()失败。
由于fdtable和文件结构都可以无锁查找,因此必须使用
rcu_assign_pointer()
API 进行安装。如果查找它们是无锁的,则
rcu_dereference()
必须使用。但是,建议使用files_fdtable()和fcheck()/ fcheck_files()来解决这些问题。
更新时,必须在按住files-> file_lock的同时查找fdtable指针。如果删除了-> file_lock,则另一个线程将扩展文件,从而创建新的fdtable并使较早的fdtable指针失效。
例如:
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); __set_open_fd(fd, fdt); __clear_close_on_exec(fd, fdt); spin_unlock(&files->file_lock);.....
由于locate_fd()可以删除-> file_lock(并重新获取-> file_lock),因此必须在locate_fd()之后加载fdtable指针(fdt)。