xref: /linux/Documentation/translations/zh_CN/filesystems/gfs2-glocks.rst (revision f96163865a1346b199cc38e827269296f0f24ab0)
1.. SPDX-License-Identifier: GPL-2.0
2
3.. include:: ../disclaimer-zh_CN.rst
4
5:Original: Documentation/filesystems/gfs2-glocks.rst
6
7:翻译:
8
9 邵明寅 Shao Mingyin <shao.mingyin@zte.com.cn>
10
11:校译:
12
13 杨涛 yang tao <yang.tao172@zte.com.cn>
14
15==================
16Glock 内部加锁规则
17==================
18
19本文档阐述 glock 状态机内部运作的基本原理。每个 glock(即
20fs/gfs2/incore.h 中的 struct gfs2_glock)包含两把主要的内部锁:
21
22 1. 自旋锁(gl_lockref.lock):用于保护内部状态(如
23    gl_state、gl_target)和持有者列表(gl_holders)
24 2. 非阻塞的位锁(GLF_LOCK):用于防止其他线程同时调用
25    DLM 等操作。若某线程获取此锁,则在释放时必须调用
26    run_queue(通常通过工作队列),以确保所有待处理任务
27    得以完成。
28
29gl_holders 列表包含与该 glock 关联的所有排队锁请求(不
30仅是持有者)。若存在已持有的锁,它们将位于列表开头的连
31续条目中。锁的授予严格遵循排队顺序。
32
33glock 层用户可请求三种锁状态:共享(SH)、延迟(DF)和
34排他(EX)。它们对应以下 DLM 锁模式:
35
36==========	====== =====================================================
37Glock 模式       DLM    锁模式
38==========	====== =====================================================
39    UN          IV/NL  未加锁(无关联的 DLM 锁)或 NL
40    SH          PR     受保护读(Protected read)
41    DF          CW     并发写(Concurrent write)
42    EX          EX     排他(Exclusive)
43==========	====== =====================================================
44
45因此,DF 本质上是一种与“常规”共享锁模式(SH)互斥的共
46享模式。在 GFS2 中,DF 模式专用于直接 I/O 操作。Glock
47本质上是锁加缓存管理例程的组合,其缓存规则如下:
48
49==========      ==============   ==========   ==========   ==============
50Glock 模式      缓存元数据       缓存数据      脏数据        脏元数据
51==========      ==============   ==========   ==========   ==============
52    UN               否            否           否            否
53    DF               是            否           否            否
54    SH               是            是           否            否
55    EX               是            是           是            是
56==========      ==============   ==========   ==========   ==============
57
58这些规则通过为每种 glock 定义的操作函数实现。并非所有
59glock 类型都使用全部的模式,例如仅 inode glock 使用 DF 模
60式。
61
62glock 操作函数及类型常量说明表:
63
64==============     ========================================================
65字段                用途
66==============     ========================================================
67go_sync            远程状态变更前调用(如同步脏数据)
68go_xmote_bh        远程状态变更后调用(如刷新缓存)
69go_inval           远程状态变更需使缓存失效时调用
70go_instantiate     获取 glock 时调用
71go_held            每次获取 glock 持有者时调用
72go_dump            为 debugfs 文件打印对象内容,或出错时将 glock 转储至日志
73go_callback        若 DLM 发送回调以释放此锁时调用
74go_unlocked        当 glock 解锁时调用(dlm_unlock())
75go_type            glock 类型,``LM_TYPE_*``
76go_flags           若 glock 关联地址空间,则设置GLOF_ASPACE 标志
77==============     ========================================================
78
79每种锁的最短持有时间是指在远程锁授予后忽略远程降级请求
80的时间段。此举旨在防止锁在集群节点间持续弹跳而无实质进
81展的情况,此现象常见于多节点写入的共享内存映射文件。通
82过延迟响应远程回调的降级操作,为用户空间程序争取页面取
83消映射前的处理时间。
84
85未来计划将 glock 的 "EX" 模式设为本地共享,使本地锁通
86过 i_mutex 实现而非 glock。
87
88glock 操作函数的加锁规则:
89
90==============   ======================    =============================
91操作              GLF_LOCK 位锁持有          gl_lockref.lock 自旋锁持有
92==============   ======================    =============================
93go_sync              是                         否
94go_xmote_bh          是                         否
95go_inval             是                         否
96go_instantiate       否                         否
97go_held              否                         否
98go_dump              有时                       是
99go_callback          有时(N/A)                 是
100go_unlocked          是                         否
101==============   ======================    =============================
102
103.. Note::
104
105   若入口处持有锁则操作期间不得释放位锁或自旋锁。
106   go_dump 和 do_demote_ok 严禁阻塞。
107   仅当 glock 状态指示其缓存最新数据时才会调用 go_dump。
108
109GFS2 内部的 glock 加锁顺序:
110
111 1. i_rwsem(如需要)
112 2. 重命名 glock(仅用于重命名)
113 3. Inode glock
114    (父级优先于子级,同级 inode 按锁编号排序)
115 4. Rgrp glock(用于(反)分配操作)
116 5. 事务 glock(通过 gfs2_trans_begin,非读操作)
117 6. i_rw_mutex(如需要)
118 7. 页锁(始终最后,至关重要!)
119
120每个 inode 对应两把 glock:一把管理 inode 本身(加锁顺
121序如上),另一把(称为 iopen glock)结合 inode 的
122i_nlink 字段决定 inode 生命周期。inode 加锁基于单个
123inode,rgrp 加锁基于单个 rgrp。通常优先获取本地锁再获
124取集群锁。
125
126Glock 统计
127----------
128
129统计分为两类:超级块相关统计和单个 glock 相关统计。超级
130块统计按每 CPU 执行以减少收集开销,并进一步按 glock 类
131型细分。所有时间单位为纳秒。
132
133超级块和 glock 统计收集相同信息。超级块时序统计为 glock
134时序统计提供默认值,使新建 glock 具有合理的初始值。每个
135glock 的计数器在创建时初始化为零,当 glock 从内存移除时
136统计丢失。
137
138统计包含三组均值/方差对及两个计数器。均值/方差对为平滑
139指数估计,算法与网络代码中的往返时间计算类似(参见《
140TCP/IP详解 卷1》第21.3节及《卷2》第25.10节)。与 TCP/IP
141案例不同,此处均值/方差未缩放且单位为整数纳秒。
142
143三组均值/方差对测量以下内容:
144
145 1. DLM 锁时间(非阻塞请求)
146 2. DLM 锁时间(阻塞请求)
147 3. 请求间隔时间(指向 DLM)
148
149非阻塞请求指无论目标 DLM 锁处于何种状态均能立即完成的请求。
150当前满足条件的请求包括:(a)锁当前状态为互斥(如锁降级)、
151(b)请求状态为空置或解锁(同样如锁降级)、或(c)设置"try lock"
152标志的请求。其余锁请求均属阻塞请求。
153
154两个计数器分别统计:
155 1. 锁请求总数(决定均值/方差计算的数据量)
156 2. glock 代码顶层的持有者排队数(通常远大于 DLM 锁请求数)
157
158为什么收集这些统计数据?我们需深入分析时序参数的动因如下:
159
1601. 更精准设置 glock "最短持有时间"
1612. 快速识别性能问题
1623. 改进资源组分配算法(基于锁等待时间而非盲目 "try lock")
163
164因平滑更新的特性,采样量的阶跃变化需经 8 次采样(方差需
1654 次)才能完全体现,解析结果时需审慎考虑。
166
167通过锁请求完成时间和 glock 平均锁请求间隔时间,可计算节
168点使用 glock 时长与集群共享时长的占比,对设置锁最短持有
169时间至关重要。
170
171我们已采取严谨措施,力求精准测量目标量值。任何测量系统均
172存在误差,但我期望当前方案已达到合理精度极限。
173
174超级块状态统计路径::
175
176    /sys/kernel/debug/gfs2/<fsname>/sbstats
177
178Glock 状态统计路径::
179
180    /sys/kernel/debug/gfs2/<fsname>/glstats
181
182(假设 debugfs 挂载于 /sys/kernel/debug,且 <fsname> 替
183换为对应 GFS2 文件系统名)
184
185输出缩写说明:
186
187=========  ============================================
188srtt       非阻塞 DLM 请求的平滑往返时间
189srttvar    srtt 的方差估计
190srttb      (潜在)阻塞 DLM 请求的平滑往返时间
191srttvarb   srttb 的方差估计
192sirt       DLM 请求的平滑请求间隔时间
193sirtvar    sirt 的方差估计
194dlm        DLM 请求数(glstats 文件中的 dcnt)
195queue      排队的 glock 请求数(glstats 文件中的 qcnt)
196=========  ============================================
197
198sbstats文件按glock类型(每种类型8行)和CPU核心(每CPU一列)
199记录统计数据集。glstats文件则为每个glock提供统计集,其格式
200与glocks文件类似,但所有时序统计量均采用均值/方差格式存储。
201
202gfs2_glock_lock_time 跟踪点实时输出目标 glock 的当前统计
203值,并附带每次接收到的dlm响应附加信息:
204
205======   ============
206status   DLM 请求状态
207flags    DLM 请求标志
208tdiff    该请求的耗时
209======   ============
210
211(其余字段同上表)
212