[PATCH 5.9 26/75] gfs2: Upgrade shared glocks for atime updates

From: Greg Kroah-Hartman
Date: Thu Dec 10 2020 - 09:45:28 EST


From: Andreas Gruenbacher <agruenba@xxxxxxxxxx>

commit 82e938bd5382b322ce81e6cb8fd030987f2da022 upstream.

Commit 20f829999c38 ("gfs2: Rework read and page fault locking") lifted
the glock lock taking from the low-level ->readpage and ->readahead
address space operations to the higher-level ->read_iter file and
->fault vm operations. The glocks are still taken in LM_ST_SHARED mode
only. On filesystems mounted without the noatime option, ->read_iter
sometimes needs to update the atime as well, though. Right now, this
leads to a failed locking mode assertion in gfs2_dirty_inode.

Fix that by introducing a new update_time inode operation. There, if
the glock is held non-exclusively, upgrade it to an exclusive lock.

Reported-by: Alexander Aring <aahringo@xxxxxxxxxx>
Fixes: 20f829999c38 ("gfs2: Rework read and page fault locking")
Cc: stable@xxxxxxxxxxxxxxx # v5.8+
Signed-off-by: Andreas Gruenbacher <agruenba@xxxxxxxxxx>
Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>

---
fs/gfs2/inode.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)

--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -2116,6 +2116,25 @@ loff_t gfs2_seek_hole(struct file *file,
return vfs_setpos(file, ret, inode->i_sb->s_maxbytes);
}

+static int gfs2_update_time(struct inode *inode, struct timespec64 *time,
+ int flags)
+{
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_glock *gl = ip->i_gl;
+ struct gfs2_holder *gh;
+ int error;
+
+ gh = gfs2_glock_is_locked_by_me(gl);
+ if (gh && !gfs2_glock_is_held_excl(gl)) {
+ gfs2_glock_dq(gh);
+ gfs2_holder_reinit(LM_ST_EXCLUSIVE, 0, gh);
+ error = gfs2_glock_nq(gh);
+ if (error)
+ return error;
+ }
+ return generic_update_time(inode, time, flags);
+}
+
const struct inode_operations gfs2_file_iops = {
.permission = gfs2_permission,
.setattr = gfs2_setattr,
@@ -2124,6 +2143,7 @@ const struct inode_operations gfs2_file_
.fiemap = gfs2_fiemap,
.get_acl = gfs2_get_acl,
.set_acl = gfs2_set_acl,
+ .update_time = gfs2_update_time,
};

const struct inode_operations gfs2_dir_iops = {
@@ -2143,6 +2163,7 @@ const struct inode_operations gfs2_dir_i
.fiemap = gfs2_fiemap,
.get_acl = gfs2_get_acl,
.set_acl = gfs2_set_acl,
+ .update_time = gfs2_update_time,
.atomic_open = gfs2_atomic_open,
};