Skip to content

Commit 60f2249

Browse files
committed
gfs2: Revise glock reference counting model
jira LE-3201 Rebuild_History Non-Buildable kernel-rt-4.18.0-553.32.1.rt7.373.el8_10 commit-author Andreas Gruenbacher <[email protected]> commit 767fd5a Empty-Commit: Cherry-Pick Conflicts during history rebuild. Will be included in final tarball splat. Ref for failed cherry-pick at: ciq/ciq_backports/kernel-rt-4.18.0-553.32.1.rt7.373.el8_10/767fd5a0.failed In the current glock reference counting model, a bias of one is added to a glock's refcount when it is locked (gl->gl_state != LM_ST_UNLOCKED). A glock is removed from the lru_list when it is enqueued, and added back when it is dequeued. This isn't a very appropriate model because most glocks are held for long periods of time (for example, the inode "owns" references to its inode and iopen glocks as long as the inode is cached even when the glock state changes to LM_ST_UNLOCKED), and they can only be freed when they are no longer referenced, anyway. Fix this by getting rid of the refcount bias for locked glocks. That way, we can use lockref_put_or_lock() to efficiently drop all but the last glock reference, and put the glock onto the lru_list when the last reference is dropped. When find_insert_glock() returns a reference to a cached glock, it removes the glock from the lru_list. Dumping the "glocks" and "glstats" debugfs files also takes glock references, but instead of removing the glocks from the lru_list in that case as well, we leave them on the list. This ensures that dumping those files won't perturb the order of the glocks on the lru_list. In addition, when the last reference to an *unlocked* glock is dropped, we immediately free it; this preserves the preexisting behavior. If it later turns out that caching unlocked glocks is useful in some situations, we can change the caching strategy. It is currently unclear if a glock that has no active references can have the GLF_LFLUSH flag set. To make sure that such a glock won't accidentally be evicted due to memory pressure, we add a GLF_LFLUSH check to gfs2_dispose_glock_lru(). Signed-off-by: Andreas Gruenbacher <[email protected]> (cherry picked from commit 767fd5a) Signed-off-by: Jonathan Maple <[email protected]> # Conflicts: # fs/gfs2/glock.c # fs/gfs2/glock.h
1 parent 0df8553 commit 60f2249

File tree

1 file changed

+247
-0
lines changed

1 file changed

+247
-0
lines changed
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
gfs2: Revise glock reference counting model
2+
3+
jira LE-3201
4+
Rebuild_History Non-Buildable kernel-rt-4.18.0-553.32.1.rt7.373.el8_10
5+
commit-author Andreas Gruenbacher <[email protected]>
6+
commit 767fd5a0160774178a597b7a7b6e07915fe00efa
7+
Empty-Commit: Cherry-Pick Conflicts during history rebuild.
8+
Will be included in final tarball splat. Ref for failed cherry-pick at:
9+
ciq/ciq_backports/kernel-rt-4.18.0-553.32.1.rt7.373.el8_10/767fd5a0.failed
10+
11+
In the current glock reference counting model, a bias of one is added to
12+
a glock's refcount when it is locked (gl->gl_state != LM_ST_UNLOCKED).
13+
A glock is removed from the lru_list when it is enqueued, and added back
14+
when it is dequeued. This isn't a very appropriate model because most
15+
glocks are held for long periods of time (for example, the inode "owns"
16+
references to its inode and iopen glocks as long as the inode is cached
17+
even when the glock state changes to LM_ST_UNLOCKED), and they can only
18+
be freed when they are no longer referenced, anyway.
19+
20+
Fix this by getting rid of the refcount bias for locked glocks. That
21+
way, we can use lockref_put_or_lock() to efficiently drop all but the
22+
last glock reference, and put the glock onto the lru_list when the last
23+
reference is dropped. When find_insert_glock() returns a reference to a
24+
cached glock, it removes the glock from the lru_list.
25+
26+
Dumping the "glocks" and "glstats" debugfs files also takes glock
27+
references, but instead of removing the glocks from the lru_list in that
28+
case as well, we leave them on the list. This ensures that dumping
29+
those files won't perturb the order of the glocks on the lru_list.
30+
31+
In addition, when the last reference to an *unlocked* glock is dropped,
32+
we immediately free it; this preserves the preexisting behavior. If it
33+
later turns out that caching unlocked glocks is useful in some
34+
situations, we can change the caching strategy.
35+
36+
It is currently unclear if a glock that has no active references can
37+
have the GLF_LFLUSH flag set. To make sure that such a glock won't
38+
accidentally be evicted due to memory pressure, we add a GLF_LFLUSH
39+
check to gfs2_dispose_glock_lru().
40+
41+
Signed-off-by: Andreas Gruenbacher <[email protected]>
42+
(cherry picked from commit 767fd5a0160774178a597b7a7b6e07915fe00efa)
43+
Signed-off-by: Jonathan Maple <[email protected]>
44+
45+
# Conflicts:
46+
# fs/gfs2/glock.c
47+
# fs/gfs2/glock.h
48+
diff --cc fs/gfs2/glock.c
49+
index 54811d4dae86,e2a72c21194a..000000000000
50+
--- a/fs/gfs2/glock.c
51+
+++ b/fs/gfs2/glock.c
52+
@@@ -310,12 -305,18 +310,27 @@@ static void __gfs2_glock_put(struct gfs
53+
sdp->sd_lockstruct.ls_ops->lm_put_lock(gl);
54+
}
55+
56+
++<<<<<<< HEAD
57+
+/*
58+
+ * Cause the glock to be put in work queue context.
59+
+ */
60+
+void gfs2_glock_queue_put(struct gfs2_glock *gl)
61+
+{
62+
+ gfs2_glock_queue_work(gl, 0);
63+
++=======
64+
+ static bool __gfs2_glock_put_or_lock(struct gfs2_glock *gl)
65+
+ {
66+
+ if (lockref_put_or_lock(&gl->gl_lockref))
67+
+ return true;
68+
+ GLOCK_BUG_ON(gl, gl->gl_lockref.count != 1);
69+
+ if (gl->gl_state != LM_ST_UNLOCKED) {
70+
+ gl->gl_lockref.count--;
71+
+ gfs2_glock_add_to_lru(gl);
72+
+ spin_unlock(&gl->gl_lockref.lock);
73+
+ return true;
74+
+ }
75+
+ return false;
76+
++>>>>>>> 767fd5a01607 (gfs2: Revise glock reference counting model)
77+
}
78+
79+
/**
80+
@@@ -332,6 -333,22 +347,25 @@@ void gfs2_glock_put(struct gfs2_glock *
81+
__gfs2_glock_put(gl);
82+
}
83+
84+
++<<<<<<< HEAD
85+
++=======
86+
+ /*
87+
+ * gfs2_glock_put_async - Decrement reference count without sleeping
88+
+ * @gl: The glock to put
89+
+ *
90+
+ * Decrement the reference count on glock immediately unless it is the last
91+
+ * reference. Defer putting the last reference to work queue context.
92+
+ */
93+
+ void gfs2_glock_put_async(struct gfs2_glock *gl)
94+
+ {
95+
+ if (__gfs2_glock_put_or_lock(gl))
96+
+ return;
97+
+
98+
+ gfs2_glock_queue_work(gl, 0);
99+
+ spin_unlock(&gl->gl_lockref.lock);
100+
+ }
101+
+
102+
++>>>>>>> 767fd5a01607 (gfs2: Revise glock reference counting model)
103+
/**
104+
* may_grant - check if it's ok to grant a new lock
105+
* @gl: The glock
106+
@@@ -1057,18 -1136,18 +1079,26 @@@ static void glock_work_func(struct work
107+
drop_refs--;
108+
if (gl->gl_name.ln_type != LM_TYPE_INODE)
109+
delay = 0;
110+
- gfs2_glock_queue_work(gl, delay);
111+
+ __gfs2_glock_queue_work(gl, delay);
112+
}
113+
114+
++<<<<<<< HEAD
115+
+ /*
116+
+ * Drop the remaining glock references manually here. (Mind that
117+
+ * __gfs2_glock_queue_work depends on the lockref spinlock begin held
118+
+ * here as well.)
119+
+ */
120+
++=======
121+
+ /* Drop the remaining glock references manually. */
122+
+ GLOCK_BUG_ON(gl, gl->gl_lockref.count < drop_refs);
123+
++>>>>>>> 767fd5a01607 (gfs2: Revise glock reference counting model)
124+
gl->gl_lockref.count -= drop_refs;
125+
if (!gl->gl_lockref.count) {
126+
- __gfs2_glock_put(gl);
127+
- return;
128+
+ if (gl->gl_state == LM_ST_UNLOCKED) {
129+
+ __gfs2_glock_put(gl);
130+
+ return;
131+
+ }
132+
+ gfs2_glock_add_to_lru(gl);
133+
}
134+
spin_unlock(&gl->gl_lockref.lock);
135+
}
136+
@@@ -1535,8 -1614,24 +1567,29 @@@ int gfs2_glock_nq(struct gfs2_holder *g
137+
if (glock_blocked_by_withdraw(gl) && !(gh->gh_flags & LM_FLAG_NOEXP))
138+
return -EIO;
139+
140+
++<<<<<<< HEAD
141+
+ if (test_bit(GLF_LRU, &gl->gl_flags))
142+
+ gfs2_glock_remove_from_lru(gl);
143+
++=======
144+
+ if (gh->gh_flags & GL_NOBLOCK) {
145+
+ struct gfs2_holder *current_gh;
146+
+
147+
+ error = -ECHILD;
148+
+ spin_lock(&gl->gl_lockref.lock);
149+
+ if (find_last_waiter(gl))
150+
+ goto unlock;
151+
+ current_gh = find_first_holder(gl);
152+
+ if (!may_grant(gl, current_gh, gh))
153+
+ goto unlock;
154+
+ set_bit(HIF_HOLDER, &gh->gh_iflags);
155+
+ list_add_tail(&gh->gh_list, &gl->gl_holders);
156+
+ trace_gfs2_promote(gh);
157+
+ error = 0;
158+
+ unlock:
159+
+ spin_unlock(&gl->gl_lockref.lock);
160+
+ return error;
161+
+ }
162+
++>>>>>>> 767fd5a01607 (gfs2: Revise glock reference counting model)
163+
164+
gh->gh_error = 0;
165+
spin_lock(&gl->gl_lockref.lock);
166+
@@@ -2085,9 -2180,10 +2137,10 @@@ static void thaw_glock(struct gfs2_gloc
167+
if (!lockref_get_not_dead(&gl->gl_lockref))
168+
return;
169+
170+
+ gfs2_glock_remove_from_lru(gl);
171+
spin_lock(&gl->gl_lockref.lock);
172+
- set_bit(GLF_HAVE_REPLY, &gl->gl_flags);
173+
- gfs2_glock_queue_work(gl, 0);
174+
+ set_bit(GLF_REPLY_PENDING, &gl->gl_flags);
175+
+ __gfs2_glock_queue_work(gl, 0);
176+
spin_unlock(&gl->gl_lockref.lock);
177+
}
178+
179+
diff --cc fs/gfs2/glock.h
180+
index be4bc9edf46d,adf0091cc98f..000000000000
181+
--- a/fs/gfs2/glock.h
182+
+++ b/fs/gfs2/glock.h
183+
@@@ -252,29 -242,27 +252,42 @@@ static inline int gfs2_glock_nq_init(st
184+
return error;
185+
}
186+
187+
++<<<<<<< HEAD
188+
+extern void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state);
189+
+extern void gfs2_glock_complete(struct gfs2_glock *gl, int ret);
190+
+extern bool gfs2_queue_try_to_evict(struct gfs2_glock *gl);
191+
+extern bool gfs2_queue_verify_delete(struct gfs2_glock *gl);
192+
+extern void gfs2_cancel_delete_work(struct gfs2_glock *gl);
193+
+extern void gfs2_flush_delete_work(struct gfs2_sbd *sdp);
194+
+extern void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
195+
+extern void gfs2_gl_dq_holders(struct gfs2_sbd *sdp);
196+
+extern void gfs2_glock_thaw(struct gfs2_sbd *sdp);
197+
+extern void gfs2_glock_add_to_lru(struct gfs2_glock *gl);
198+
+extern void gfs2_glock_free(struct gfs2_glock *gl);
199+
+extern void gfs2_glock_free_later(struct gfs2_glock *gl);
200+
++=======
201+
+ void gfs2_glock_cb(struct gfs2_glock *gl, unsigned int state);
202+
+ void gfs2_glock_complete(struct gfs2_glock *gl, int ret);
203+
+ bool gfs2_queue_try_to_evict(struct gfs2_glock *gl);
204+
+ void gfs2_cancel_delete_work(struct gfs2_glock *gl);
205+
+ void gfs2_flush_delete_work(struct gfs2_sbd *sdp);
206+
+ void gfs2_gl_hash_clear(struct gfs2_sbd *sdp);
207+
+ void gfs2_gl_dq_holders(struct gfs2_sbd *sdp);
208+
+ void gfs2_glock_thaw(struct gfs2_sbd *sdp);
209+
+ void gfs2_glock_free(struct gfs2_glock *gl);
210+
+ void gfs2_glock_free_later(struct gfs2_glock *gl);
211+
++>>>>>>> 767fd5a01607 (gfs2: Revise glock reference counting model)
212+
213+
-int __init gfs2_glock_init(void);
214+
-void gfs2_glock_exit(void);
215+
+extern int __init gfs2_glock_init(void);
216+
+extern void gfs2_glock_exit(void);
217+
218+
-void gfs2_create_debugfs_file(struct gfs2_sbd *sdp);
219+
-void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp);
220+
-void gfs2_register_debugfs(void);
221+
-void gfs2_unregister_debugfs(void);
222+
+extern void gfs2_create_debugfs_file(struct gfs2_sbd *sdp);
223+
+extern void gfs2_delete_debugfs_file(struct gfs2_sbd *sdp);
224+
+extern void gfs2_register_debugfs(void);
225+
+extern void gfs2_unregister_debugfs(void);
226+
227+
-void glock_set_object(struct gfs2_glock *gl, void *object);
228+
-void glock_clear_object(struct gfs2_glock *gl, void *object);
229+
+extern void glock_set_object(struct gfs2_glock *gl, void *object);
230+
+extern void glock_clear_object(struct gfs2_glock *gl, void *object);
231+
232+
extern const struct lm_lockops gfs2_dlm_ops;
233+
234+
* Unmerged path fs/gfs2/glock.c
235+
* Unmerged path fs/gfs2/glock.h
236+
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
237+
index a0ec4e506f04..9438aeb6ca90 100644
238+
--- a/fs/gfs2/super.c
239+
+++ b/fs/gfs2/super.c
240+
@@ -1574,7 +1574,6 @@ static void gfs2_evict_inode(struct inode *inode)
241+
if (ip->i_gl) {
242+
glock_clear_object(ip->i_gl, ip);
243+
wait_on_bit_io(&ip->i_flags, GIF_GLOP_PENDING, TASK_UNINTERRUPTIBLE);
244+
- gfs2_glock_add_to_lru(ip->i_gl);
245+
gfs2_glock_put_eventually(ip->i_gl);
246+
ip->i_gl = NULL;
247+
}

0 commit comments

Comments
 (0)