我已经在linux内核4.4.0-57-generic的内核源代码中查看,并且在writev()
源writev()
不到任何锁。 有什么我失踪? 我没有看到writev()
是如何primefaces或线程安全的。
不是这里的核心专家,但我会分享我的观点。 随时发现任何错误。
浏览内核(v4.9虽然我不希望它是如此不同),并试图跟踪writev(2)
系统调用,我可以观察到后续的函数调用,创建以下路径:
SYSCALL_DEFINE3(writev, ..)
do_writev(..)
vfs_writev(..)
do_readv_writev(..)
现在路径分支,取决于是否实现了write_iter
方法,并挂钩在系统调用所引用的struct file
的struct file_operations
字段上。
NULL
,路径是: 5A。 do_iter_readv_writev(..)
,此时调用方法filp->f_op->write_iter(..)
。
NULL
,路径是: 5B。 do_loop_readv_writev(..)
,在这个循环中重复调用filp->f_op->write
方法。
所以,就我所知, writev()
系统调用与底层的write()
(或write_iter()
)是线程安全的,当然可以用各种方式实现,例如在设备驱动程序中或根据其需要和设计可能不使用锁。
编辑 :
在内核v4.4中,路径看起来非常相似:
SYSCALL_DEFINE3(writev, ..)
vfs_writev(..)
do_readv_writev(..)
然后取决于struct file
struct file_operations
中的write_iter
方法是否为NULL
,就像上面描述的v4.9中的情况一样。
VFS(虚拟文件系统) 本身不保证 writev()
调用的原子性 。 它只是调用struct file_operations
的特定.write_iter
文件系统的.write_iter
方法。
make方法对文件进行原子写入是特定文件系统实现的责任 。
例如,在ext4文件系统函数ext4_file_write_iter中使用
mutex_lock(&inode->i_mutex);
为了使写作原子。
在fs.h找到它:
static inline void file_start_write(struct file *file) { if (!S_ISREG(file_inode(file)->i_mode)) return; __sb_start_write(file_inode(file)->i_sb, SB_FREEZE_WRITE, true); }
然后在super.c中:
/* * This is an internal function, please use sb_start_{write,pagefault,intwrite} * instead. */ int __sb_start_write(struct super_block *sb, int level, bool wait) { bool force_trylock = false; int ret = 1; #ifdef CONFIG_LOCKDEP /* * We want lockdep to tell us about possible deadlocks with freezing * but it's it bit tricky to properly instrument it. Getting a freeze * protection works as getting a read lock but there are subtle * problems. XFS for example gets freeze protection on internal level * twice in some cases, which is OK only because we already hold a * freeze protection also on higher level. Due to these cases we have * to use wait == F (trylock mode) which must not fail. */ if (wait) { int i; for (i = 0; i < level - 1; i++) if (percpu_rwsem_is_held(sb->s_writers.rw_sem + i)) { force_trylock = true; break; } } #endif if (wait && !force_trylock) percpu_down_read(sb->s_writers.rw_sem + level-1); else ret = percpu_down_read_trylock(sb->s_writers.rw_sem + level-1); WARN_ON(force_trylock & !ret); return ret; } EXPORT_SYMBOL(__sb_start_write);
再次感谢。