バインドマウントの「umount -R」は無視できないほど時間がかかります。なぜですか?

バインドマウントの「umount -R」は無視できないほど時間がかかります。なぜですか?

umount -Rバインドマウントされたサブツリーをアンマウントするのに0.2秒かかるのはなぜですか?サブツリーのマウントには0.02秒、電波フラグの変更には0.00秒しかかかりません。

(現在のインストールセットをサブディレクトリに複製して変更し、スイッチを使用してそのディレクトリに切り替えようとしていますpivot_mountが、私が観察した待ち時間は実際にはこの目的には許容できません。)

この演習では、/サブマウントが共有マウントであると仮定します。 Linuxはデフォルトではこれを行いませんが、システムする。

# mkdir /mnt/a
# mount --bind /mnt/a /mnt/a --make-private
# time mount --rbind / /mnt/a
0.00user 0.00system 0:00.02elapsed 9%CPU (0avgtext+0avgdata 3020maxresident)k
0inputs+0outputs (0major+135minor)pagefaults 0swaps
# time mount --make-rprivate /mnt/a
0.00user 0.00system 0:00.00elapsed 100%CPU (0avgtext+0avgdata 3184maxresident)k
0inputs+0outputs (0major+136minor)pagefaults 0swaps
# time umount -R /mnt/a
0.00user 0.00system 0:00.19elapsed 9%CPU (0avgtext+0avgdata 3392maxresident)k
0inputs+0outputs (0major+194minor)pagefaults 0swaps

追加テスト

strace -cwショーで実行

% time     seconds  usecs/call     calls    errors syscall
------ ----------- ----------- --------- --------- ----------------
 90.44    0.180113        5297        34           umount2
 ...

umount2()したがって、最後のタスクには34個の個別の呼び出しが必要でしたが、他のタスクはMS_REC(再帰)フラグを使用するペアへの1回の呼び出しだけで構成されていることを指摘する以外はmount()それほど理解するのが難しいです。ヘッダーデータと同様に、time今は壁時計の時間です。 strace -cシステム時間(つまり、カーネルが費やしたCPU時間)を表示すると、合計0.009秒です。

それでもいくつかの興味深い点を指摘しています。代わりに使用すると、umount -l /mnt/a合計時間が0.02秒に短縮されます。これは単一のumount2()呼び出しを使用してサブツリーを分離し、バック/mnt/aグラウンドでクリーンアップを実行します。

単一の呼び出しを見ると、単一のstrace -ttt -T -e trace=umount2 umount -R /mnt/a呼び出し数は0.002秒から0.012秒の間で比較的均等に分布していますが、明確なパターンはなく、繰り返しはパターンが一貫していないようです。


umount -R実行後perf record -a、およびに複数のホットスポットperf reportが表示されます。そのプロセスはまったく出てこない。これは、カーネルまたはユーザースペースで費やされたCPU時間が無視できる理由を説明できます。gsd-housekeepinggvfs-udisks2-volume-monitorsystemdumounttimeumount

(テスト中に各プロセスのCPU使用率を集計するより包括的な方法がある人がいる場合は非常に興味深いでしょう。)

他のプロセスは、各インストールイベントに応じていくつかの処理を実行できます。

たとえば、0.4秒かかった実行では、systemdは私の4つのCPUのうちの1つを使用して0.13秒を担当しているようです。

# systemctl set-property init.scope CPUAccounting=yes
# systemctl show --property CPUUsageNSec init.scope; time umount -R /mnt/a ; systemctl show --property CPUUsageNSec init.scope
CPUUsageNSec=2403124481

real    0m0.408s
user    0m0.015s
sys 0m0.020s
CPUUsageNSec=2534058385

# echo $(( 2534058385 - 2403124481 ))
130933904

ただし、これはプライベートマウントネームスペースで実行すると同じ遅延が発生するため、正しい説明ではないようです。この場合、perf record -a他のプロセスは表示されず、umountプロセス(およびパフォーマンス自体)のみが表示されます。

# unshare -m
# time mount --rbind / /mnt/a

real    0m0.005s
user    0m0.003s
sys 0m0.002s
# time mount --make-rprivate /mnt/a

real    0m0.005s
user    0m0.003s
sys 0m0.002s
# systemctl show --property CPUUsageNSec init.scope; time umount -R /mnt/a ; systemctl show --property CPUUsageNSec init.scope
CPUUsageNSec=3637792026

real    0m0.381s
user    0m0.026s
sys 0m0.018s
CPUUsageNSec=3645973005
# echo $((3645973005-3637792026))
8180979

この場合、CPUは関連性がないようです。 2.3Ghzで実行できるCPUコアは4つですが、perf stat -a全体的にCPU使用率は5%未満です。 (「CPUの使用は無視してください。-a使用すると常にプール値を表示していると思います)。

# time perf stat -a umount -R /mnt/a

 Performance counter stats for 'system wide':

       2079.333650      cpu-clock (msec)          #    3.998 CPUs utilized          
               635      context-switches          #    0.305 K/sec                  
                23      cpu-migrations            #    0.011 K/sec                  
               333      page-faults               #    0.160 K/sec                  
       198,278,822      cycles                    #    0.095 GHz                    
       138,734,277      instructions              #    0.70  insn per cycle         
        31,401,067      branches                  #   15.102 M/sec                  
           934,327      branch-misses             #    2.98% of all branches        

       0.520083596 seconds time elapsed


real    0m0.543s
user    0m0.038s
sys 0m0.043s

ただし、一部のプロセスはまだこのイベントに応答します。 umountはまだシステムログに78行のメッセージをトリガーします。

Feb 07 10:34:26 alan-laptop systemd[1]: proc-sys-fs-binfmt_misc.automount: Got automount request for /proc/sys/fs/binfmt_misc, triggered by 6040 (umount)
Feb 07 10:34:26 alan-laptop systemd[1]: proc-sys-fs-binfmt_misc.automount: Automount point already active?
Feb 07 10:34:26 alan-laptop systemd[1]: proc-sys-fs-binfmt_misc.automount: Got automount request for /proc/sys/fs/binfmt_misc, triggered by 6040 (umount)
Feb 07 10:34:26 alan-laptop systemd[1]: proc-sys-fs-binfmt_misc.automount: Automount point already active?

findmntたとえば、次回これを実行すると、ひどい再帰などの電波が発生するのを防ぎます--make-rprivate

findmnt -o TARGET,PROPAGATION
TARGET                                          PROPAGATION
/                                               shared
├─/sys                                          shared
│ ├─/sys/kernel/security                        shared
│ ├─/sys/fs/cgroup                              shared
│ │ ├─/sys/fs/cgroup/unified                    shared
│ │ ├─/sys/fs/cgroup/systemd                    shared
│ │ ├─/sys/fs/cgroup/net_cls,net_prio           shared
│ │ ├─/sys/fs/cgroup/cpu,cpuacct                shared
│ │ ├─/sys/fs/cgroup/devices                    shared
│ │ ├─/sys/fs/cgroup/freezer                    shared
│ │ ├─/sys/fs/cgroup/perf_event                 shared
│ │ ├─/sys/fs/cgroup/hugetlb                    shared
│ │ ├─/sys/fs/cgroup/memory                     shared
│ │ ├─/sys/fs/cgroup/blkio                      shared
│ │ ├─/sys/fs/cgroup/cpuset                     shared
│ │ └─/sys/fs/cgroup/pids                       shared
│ ├─/sys/fs/pstore                              shared
│ ├─/sys/fs/selinux                             shared
│ ├─/sys/kernel/debug                           shared
│ └─/sys/kernel/config                          shared
├─/proc                                         shared
│ └─/proc/sys/fs/binfmt_misc                    shared
├─/dev                                          shared
│ ├─/dev/shm                                    shared
│ ├─/dev/pts                                    shared
│ ├─/dev/mqueue                                 shared
│ └─/dev/hugepages                              shared
├─/run                                          shared
│ ├─/run/user/1000                              shared
│ └─/run/user/42                                shared
├─/usr                                          shared
├─/tmp                                          shared
├─/boot                                         shared
└─/mnt/a                                        private
  └─/mnt/a                                      private
    ├─/mnt/a/usr                                private
    ├─/mnt/a/sys                                private
    │ ├─/mnt/a/sys/kernel/security              private
    │ ├─/mnt/a/sys/fs/cgroup                    private
    │ │ ├─/mnt/a/sys/fs/cgroup/unified          private
    │ │ ├─/mnt/a/sys/fs/cgroup/systemd          private
    │ │ ├─/mnt/a/sys/fs/cgroup/net_cls,net_prio private
    │ │ ├─/mnt/a/sys/fs/cgroup/cpu,cpuacct      private
    │ │ ├─/mnt/a/sys/fs/cgroup/devices          private
    │ │ ├─/mnt/a/sys/fs/cgroup/freezer          private
    │ │ ├─/mnt/a/sys/fs/cgroup/perf_event       private
    │ │ ├─/mnt/a/sys/fs/cgroup/hugetlb          private
    │ │ ├─/mnt/a/sys/fs/cgroup/memory           private
    │ │ ├─/mnt/a/sys/fs/cgroup/blkio            private
    │ │ ├─/mnt/a/sys/fs/cgroup/cpuset           private
    │ │ └─/mnt/a/sys/fs/cgroup/pids             private
    │ ├─/mnt/a/sys/fs/pstore                    private
    │ ├─/mnt/a/sys/kernel/config                private
    │ ├─/mnt/a/sys/fs/selinux                   private
    │ └─/mnt/a/sys/kernel/debug                 private
    ├─/mnt/a/dev                                private
    │ ├─/mnt/a/dev/shm                          private
    │ ├─/mnt/a/dev/pts                          private
    │ ├─/mnt/a/dev/mqueue                       private
    │ └─/mnt/a/dev/hugepages                    private
    ├─/mnt/a/run                                private
    │ ├─/mnt/a/run/user/1000                    private
    │ └─/mnt/a/run/user/42                      private
    ├─/mnt/a/proc                               private
    │ └─/mnt/a/proc/sys/fs/binfmt_misc          private
    ├─/mnt/a/tmp                                private
    ├─/mnt/a/boot                               private
    └─/mnt/a/mnt/a                              private

ベストアンサー1

したがって、何かを待つのに時間を費やしていると思いますumount(CPU時間が非常に少なくなったり出たりするためですusersys。なぜ待っているのか見てみましょう...

# perf trace -g -e sched:* umount2 -R /mnt/a

perf recordいくつかのスケジューラ追跡ポイントが表示され、最も目立つものですsched:sched_switch

Samples: 21  of event 'sched:sched_switch', Event count (approx.): 21
  Children      Self  Trace output                                                                                                                   ▒
-  100.00%   100.00%  umount:1888 [120] D ==> swapper/3:0 [120]                                                                                      ▒
     0                                                                                                                                               ▒
     __umount2                                                                                                                                       ▒
     entry_SYSCALL_64_fastpath                                                                                                                       ▒
     sys_umount                                                                                                                                      ▒
     do_umount                                                                                                                                       ▒
     namespace_unlock                                                                                                                                ▒
     synchronize_sched                                                                                                                               ▒
     __wait_rcu_gp                                                                                                                                   ▒
     wait_for_completion                                                                                                                             ▒
     schedule_timeout                                                                                                                                ▒
     schedule                                                                                                                                        ▒
     __schedule                                                                                                                                      ▒
     __schedule   

__wait_rcu_gp()RCU猶予期間を示します。 namespace_unlock()inは、fs/namespace.c以下を含む一種のグローバル同期ですsynchronize_rcu()みんな「現在実行中のRCUリード側の重要な部分が完了しました。」 「RCU猶予期間が数ミリ秒延長されました...この状況は、経験的に読取り指向の状況でRCUを使用する主な理由です」名前空間をマウントすることは「デフォルトの読み取り」と見なされます。

この「数ミリ秒」は、34の呼び出しごとに5ミリ秒の平均待ち時間を占めるようですumount2()

おすすめ記事