- 论坛徽章:
- 2
|
Museless 发表于 2015-09-19 01:12 ![]()
write执行后,返回前,就会把fd的文件位移给进行向后移,写和移位不是原子操作,非线程安全是因为这里。你可 ...
这是sys_write源码, 内核版本4.2:- SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf, size_t, count)
- 579 {
- 580 struct fd f = fdget_pos(fd);
- 581 ssize_t ret = -EBADF;
- 582
- 583 if (f.file) {
- 584 loff_t pos = file_pos_read(f.file); // 获得文件指针的位置
- 585 ret = vfs_write(f.file, buf, count, &pos); // 从文件指针处开始写文件
- 586 if (ret >= 0) // 接下来3行,用来更新文件指针
- 587 file_pos_write(f.file, pos);
- 588 fdput_pos(f);
- 589 }
- 590
- 591 return ret;
- 592 }
复制代码 从源码可以看到sys_write函数中, 获得文件指针,写文件,更新文件指针 3个操作是非原子的.
下面是vfs_write函数的源码, 这两个函数值得注意: file_start_write(), file_end_write()- ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_t *pos)
- 524 {
- 525 ssize_t ret;
- 526
- 527 if (!(file->f_mode & FMODE_WRITE))
- 528 return -EBADF;
- 529 if (!(file->f_mode & FMODE_CAN_WRITE))
- 530 return -EINVAL;
- 531 if (unlikely(!access_ok(VERIFY_READ, buf, count)))
- 532 return -EFAULT;
- 533
- 534 ret = rw_verify_area(WRITE, file, pos, count);
- 535 if (ret >= 0) {
- 536 count = ret;
- 537 file_start_write(file); // 我推测该函数的功能是上锁
- 538 ret = __vfs_write(file, buf, count, pos); // 从文件指针处开始写文件
- 539 if (ret > 0) {
- 540 fsnotify_modify(file);
- 541 add_wchar(current, ret);
- 542 }
- 543 inc_syscw(current);
- 544 file_end_write(file); // 我推测该函数的功能是释放锁
- 545 }
- 546
- 547 return ret;
- 548 }
复制代码 最后是file_end_write函数的源码:- static inline void file_end_write(struct file *file)
- 2476 {
- 2477 if (!S_ISREG(file_inode(file)->i_mode)) // 判断是否是常规文件, 若不是常规文件, 直接返回
- 2478 return;
- 2479 __sb_end_write(file_inode(file)->i_sb, SB_FREEZE_WRITE); // 该函数的实现在下一个函数中
- 2480 }
复制代码- void __sb_end_write(struct super_block *sb, int level)
- 1163 {
- 1164 percpu_up_read(sb->s_writers.rw_sem + level-1); // 该函数实现在下一个函数中
- 1165 }
复制代码- void percpu_up_read(struct percpu_rw_semaphore *brw)
- 105 {
- 106 rwsem_release(&brw->rw_sem.dep_map, 1, _RET_IP_); // 函数名中的 rwsem 表示 "读写信号量", 从函数名可以推测该函数功能是释放锁
- 107
- 108 if (likely(update_fast_ctr(brw, -1)))
- 109 return;
- 110
- 111 /* false-positive is possible but harmless */
- 112 if (atomic_dec_and_test(&brw->slow_read_ctr))
- 113 wake_up_all(&brw->write_waitq); // **等待队列
- 114 }
复制代码 我对源码的理解可以用一个流程来说明:- sys_write (file):
- 1. 获得文件指针的位置
- 2. 从文件指针处开始写入
- 2.1 对常规文件加锁, 对非常规文件不加锁
- 2.2 写文件
- 2.3 对常规文件解锁, 对非常规文件不解锁
- 3. 更新文件指针的位置
复制代码 不知道我对源码的解读是否正确, 欢迎大家来拍砖 |
|