generic_perform_write()

先來看下ftrace, 時間基本上花在了ocfs2_write_begin()函數中。node

 1)               |  generic_perform_write() {
 1) ! 12184.13 us |    ocfs2_write_begin();
 1)   0.341 us    |    iov_iter_copy_from_user_atomic();
 1) + 11.759 us   |    ocfs2_write_end();
 1) ! 12198.37 us |  }

再做簡單分析:併發

2577 static ssize_t generic_perform_write(struct file *file,
2578                 struct iov_iter *i, loff_t pos)
2579 {
2580     struct address_space *mapping = file->f_mapping;
2581     const struct address_space_operations *a_ops = mapping->a_ops;
2582     long status = 0;
2583     ssize_t written = 0;
2584     unsigned int flags = 0;
2585 
//請無視
2586     /*
2587      * Copies from kernel address space cannot fail (NFSD is a big user).
2588      */
2589     if (segment_eq(get_fs(), KERNEL_DS))
2590         flags |= AOP_FLAG_UNINTERRUPTIBLE;
2591 
// do{}while()裏面確定是規律性重複
2592     do {
2593         struct page *page;
2594         unsigned long offset;   /* Offset into pagecache page */
2595         unsigned long bytes;    /* Bytes to write to page */
2596         size_t copied;      /* Bytes copied from user */
2597         void *fsdata;
2598 
//offset: pos是文件指針(這裏指針意思是「位置」),若以頁大小爲單位來看待文件,offset即最後一頁中文件
//的末尾;
//bytes: 這一次迭代,打算寫入的字節數,若是最後一頁空閒部分放不下iovec第一個份量,就先把尾頁填滿;
2599         offset = (pos & (PAGE_CACHE_SIZE - 1));
2600         bytes = min_t(unsigned long, PAGE_CACHE_SIZE - offset,
2601                         iov_iter_count(i));
2602 
2603 again:
2604 
2605         /*
2606          * Bring in the user page that we will copy from _first_.
2607          * Otherwise there's a nasty deadlock on copying from the
2608          * same page as we're writing to, without it being marked
2609          * up-to-date.
2610          *
2611          * Not only is this an optimisation, but it is also required
2612          * to check that the address is actually valid, when atomic
2613          * usercopies are used, below.
2614          */
//掠過全部unlikely ;-)
2615         if (unlikely(iov_iter_fault_in_readable(i, bytes))) {
2616             status = -EFAULT;
2617             break;
2618         }
2619 
//write_begin()之後單獨分析,先簡單說幾句。write_begin回調ocfs2_write_begin(),ocfs2_*
//調用ocfs2_inode_lock加EX鎖,這個鎖很厲害,會致使其餘節點inode pagecache失效;down_write ip_alloc_sem
//防止在接下來ocfs2_write()中,->readpage()和空間分配併發執行。
2620         status = a_ops->write_begin(file, mapping, pos, bytes, flags,
2621                         &page, &fsdata);
2622         if (unlikely(status))
2623             break;
2624 
//若是用戶進程調用mmap()對文件作了shared映射,剛好操做的是同一個page,就先的刷下pagecache;
//刷page cache前,先把data cache刷新到內存;
2625         if (mapping_writably_mapped(mapping))
2626             flush_dcache_page(page);
2627 
//copy from user;-)
2628         pagefault_disable();
2629         copied = iov_iter_copy_from_user_atomic(page, i, offset, bytes);
2630         pagefault_enable();
2631         flush_dcache_page(page);
2632 
2633         mark_page_accessed(page);
//與write_begin相反,調用block_commit_write()向塊層發送寫請求,更新inode,dinode統計量,
//ocfs2_commit_trans()提交事物,銷燬寫輔助結構體
2634         status = a_ops->write_end(file, mapping, pos, bytes, copied,
2635                         page, fsdata);
2636         if (unlikely(status < 0))
2637             break;
2638         copied = status;
2639 
2640         cond_resched();
2641 
2642         iov_iter_advance(i, copied);
2643         if (unlikely(copied == 0)) {
2644             /*
2645              * If we were unable to copy any data at all, we must
2646              * fall back to a single segment length write.
2647              *
2648              * If we didn't fallback here, we could livelock
2649              * because not all segments in the iov can be copied at
2650              * once without a pagefault.
2651              */
2652             bytes = min_t(unsigned long, PAGE_CACHE_SIZE - offset,
2653                         iov_iter_single_seg_count(i));
2654             goto again;
2655         }
2656         pos += copied;
2657         written += copied;
2658 
//這個函數調用了balance_dirty_pages_ratelimited_cr(mapping, 1); 從這個1看出來,while循環
//一次只處理一個page; 這個函數會週期性檢查內存dirty程度,發起write back;
2659         balance_dirty_pages_ratelimited(mapping);
2660 
2661     } while (iov_iter_count(i));
2662 
2663     return written ? written : status;
2664 }
本站公眾號
   歡迎關注本站公眾號,獲取更多信息