aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorAndreas Gruenbacher <agruenba@redhat.com>2025-03-05 14:14:37 +0100
committerAndreas Gruenbacher <agruenba@redhat.com>2025-03-10 18:15:38 +0100
commit9136cad723ec3e5ab5ca85a839f151abf1c9a106 (patch)
tree803bfecde5e269993bf091c97109d485565d2830
parentgfs2: Fix additional unlikely request cancelation race (diff)
downloadwireguard-linux-9136cad723ec3e5ab5ca85a839f151abf1c9a106.tar.xz
wireguard-linux-9136cad723ec3e5ab5ca85a839f151abf1c9a106.zip
gfs2: Prevent inode creation race (2)
In gfs2_try_evict(), we try grabbing the inode to evict, we try to evict it, and then we try grabbing it again to see if it still exists. There is no guarantee that we will end up with the same inode both times; the inode validity check that commit ffd1cf0443a2 ("gfs2: Prevent inode creation race") added to the first grab is actually needed both times. (To avoid code duplication, add a grab_existing_inode() helper.) Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
-rw-r--r--fs/gfs2/glock.c40
1 files changed, 21 insertions, 19 deletions
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index ea98b8bc166a..3c26812b12a8 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -971,6 +971,25 @@ static void gfs2_glock_poke(struct gfs2_glock *gl)
gfs2_holder_uninit(&gh);
}
+static struct gfs2_inode *gfs2_grab_existing_inode(struct gfs2_glock *gl)
+{
+ struct gfs2_inode *ip;
+
+ spin_lock(&gl->gl_lockref.lock);
+ ip = gl->gl_object;
+ if (ip && !igrab(&ip->i_inode))
+ ip = NULL;
+ spin_unlock(&gl->gl_lockref.lock);
+ if (ip) {
+ wait_on_inode(&ip->i_inode);
+ if (is_bad_inode(&ip->i_inode)) {
+ iput(&ip->i_inode);
+ ip = NULL;
+ }
+ }
+ return ip;
+}
+
static void gfs2_try_evict(struct gfs2_glock *gl)
{
struct gfs2_inode *ip;
@@ -988,18 +1007,7 @@ static void gfs2_try_evict(struct gfs2_glock *gl)
* happened below. (Verification is triggered by the call to
* gfs2_queue_verify_delete() in gfs2_evict_inode().)
*/
- spin_lock(&gl->gl_lockref.lock);
- ip = gl->gl_object;
- if (ip && !igrab(&ip->i_inode))
- ip = NULL;
- spin_unlock(&gl->gl_lockref.lock);
- if (ip) {
- wait_on_inode(&ip->i_inode);
- if (is_bad_inode(&ip->i_inode)) {
- iput(&ip->i_inode);
- ip = NULL;
- }
- }
+ ip = gfs2_grab_existing_inode(gl);
if (ip) {
set_bit(GLF_DEFER_DELETE, &gl->gl_flags);
d_prune_aliases(&ip->i_inode);
@@ -1007,13 +1015,7 @@ static void gfs2_try_evict(struct gfs2_glock *gl)
clear_bit(GLF_DEFER_DELETE, &gl->gl_flags);
/* If the inode was evicted, gl->gl_object will now be NULL. */
- spin_lock(&gl->gl_lockref.lock);
- ip = gl->gl_object;
- if (ip) {
- if (!igrab(&ip->i_inode))
- ip = NULL;
- }
- spin_unlock(&gl->gl_lockref.lock);
+ ip = gfs2_grab_existing_inode(gl);
if (ip) {
gfs2_glock_poke(ip->i_gl);
iput(&ip->i_inode);