바인드 마운트의 "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(재귀) 플래그를 사용하는 쌍에 대한 한 번의 호출로만 구성되었다는 점을 지적하는 것 외에는 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는 내 CPU 4개 중 하나를 사용하여 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 시간이 매우 적게 걸리거나 나가기 때문입니다 user) sys. 왜 기다리고 있는지 알아봅시다...

# 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().

관련 정보