Commit graph

2,976 commits

Author SHA1 Message Date
Andreas Gruenbacher
9468bcd92d gfs2: Don't start unnecessary transactions during log flush
[ Upstream commit 5a90f8d499 ]

Commit 8d391972ae ("gfs2: Remove __gfs2_writepage()") changed the log
flush code in gfs2_ail1_start_one() to call aops->writepages() instead
of aops->writepage().  For jdata inodes, this means that we will now try
to reserve log space and start a transaction before we can determine
that the pages in question have already been journaled.  When this
happens in the context of gfs2_logd(), it can now appear that not enough
log space is available for freeing up log space, and we will lock up.

Fix that by issuing journal writes directly instead of going through
aops->writepages() in the log flush code.

Fixes: 8d391972ae ("gfs2: Remove __gfs2_writepage()")
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:57 +02:00
Andreas Gruenbacher
519aed5bda gfs2: Move gfs2_trans_add_databufs
[ Upstream commit d50a64e3c5 ]

Move gfs2_trans_add_databufs() to trans.c.  Pass in a glock instead of
a gfs2_inode.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 5a90f8d499 ("gfs2: Don't start unnecessary transactions during log flush")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:57 +02:00
Andreas Gruenbacher
cde7f94078 gfs2: deallocate inodes in gfs2_create_inode
[ Upstream commit 2c63986dd3 ]

When creating and destroying inodes, we are relying on the inode hash
table to make sure that for a given inode number, only a single inode
will exist.  We then link that inode to its inode and iopen glock and
let those glocks point back at the inode.  However, when iget_failed()
is called, the inode is removed from the inode hash table before
gfs_evict_inode() is called, and uniqueness is no longer guaranteed.

Commit f1046a472b70 ("gfs2: gl_object races fix") was trying to work
around that problem by detaching the inode glock from the inode before
calling iget_failed(), but that broke the inode deallocation code in
gfs_evict_inode().

To fix that, deallocate partially created inodes in gfs2_create_inode()
instead of relying on gfs_evict_inode() for doing that.

This means that gfs2_evict_inode() and its helper functions will no
longer see partially created inodes, and so some simplifications are
possible there.

Fixes: 9ffa18884c ("gfs2: gl_object races fix")
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:56 +02:00
Andreas Gruenbacher
8e753fc3d5 gfs2: Move GIF_ALLOC_FAILED check out of gfs2_ea_dealloc
[ Upstream commit 0cc617a54d ]

Don't check for the GIF_ALLOC_FAILED flag in gfs2_ea_dealloc() and pass
that information explicitly instead.  This allows for a cleaner
follow-up patch.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 2c63986dd3 ("gfs2: deallocate inodes in gfs2_create_inode")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:56 +02:00
Andreas Gruenbacher
24ae2de15b gfs2: Move gfs2_dinode_dealloc
[ Upstream commit bcd18105fb ]

Move gfs2_dinode_dealloc() and its helper gfs2_final_release_pages()
from super.c to inode.c.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 2c63986dd3 ("gfs2: deallocate inodes in gfs2_create_inode")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:56 +02:00
Andreas Gruenbacher
4f66983aeb gfs2: Replace GIF_DEFER_DELETE with GLF_DEFER_DELETE
[ Upstream commit 3774f53d7f ]

Having this flag attached to the iopen glock instead of the inode is
much simpler; it eliminates a protential weird race in gfs2_try_evict().

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 2c63986dd3 ("gfs2: deallocate inodes in gfs2_create_inode")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:56 +02:00
Andreas Gruenbacher
7df46e6f88 gfs2: Add GLF_PENDING_REPLY flag
[ Upstream commit 8bbfde0875 ]

Introduce a new GLF_PENDING_REPLY flag to indicate that a reply from DLM
is expected.  Include that flag in glock dumps to show more clearly
what's going on.  (When the GLF_PENDING_REPLY flag is set, the GLF_LOCK
flag will also be set but the GLF_LOCK flag alone isn't sufficient to
tell that we are waiting for a DLM reply.)

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 2c63986dd3 ("gfs2: deallocate inodes in gfs2_create_inode")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:55 +02:00
Andreas Gruenbacher
fbb2d296d4 gfs2: Decode missing glock flags in tracepoints
[ Upstream commit 5788253392 ]

Add a number of glock flags are currently not shown in the text form of
glock tracepoints.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 2c63986dd3 ("gfs2: deallocate inodes in gfs2_create_inode")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:55 +02:00
Andreas Gruenbacher
9649fec0f9 gfs2: Prevent inode creation race
[ Upstream commit ffd1cf0443 ]

When a request to evict an inode comes in over the network, we are
trying to grab an inode reference via the iopen glock's gl_object
pointer.  There is a very small probability that by the time such a
request comes in, inode creation hasn't completed and the I_NEW flag is
still set.  To deal with that, wait for the inode and then check if
inode creation was successful.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 2c63986dd3 ("gfs2: deallocate inodes in gfs2_create_inode")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:55 +02:00
Andreas Gruenbacher
af2ce45c28 gfs2: Rename dinode_demise to evict_behavior
[ Upstream commit c79ba4be35 ]

Rename enum dinode_demise to evict_behavior and its items
SHOULD_DELETE_DINODE to EVICT_SHOULD_DELETE,
SHOULD_NOT_DELETE_DINODE to EVICT_SHOULD_SKIP_DELETE, and
SHOULD_DEFER_EVICTION to EVICT_SHOULD_DEFER_DELETE.

In gfs2_evict_inode(), add a separate variable of type enum
evict_behavior instead of implicitly casting to int.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 2c63986dd3 ("gfs2: deallocate inodes in gfs2_create_inode")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:55 +02:00
Andreas Gruenbacher
862ca0b49f gfs2: Rename GIF_{DEFERRED -> DEFER}_DELETE
[ Upstream commit 9fb794aac6 ]

The GIF_DEFERRED_DELETE flag indicates an action that gfs2_evict_inode()
should take, so rename the flag to GIF_DEFER_DELETE to clarify.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 2c63986dd3 ("gfs2: deallocate inodes in gfs2_create_inode")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:55 +02:00
Andreas Gruenbacher
170af4314e gfs2: Initialize gl_no_formal_ino earlier
[ Upstream commit 1072b3aa68 ]

Set gl_no_formal_ino of the iopen glock to the generation of the
associated inode (ip->i_no_formal_ino) as soon as that value is known.
This saves us from setting it later, possibly repeatedly, when queuing
GLF_VERIFY_DELETE work.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 2c63986dd3 ("gfs2: deallocate inodes in gfs2_create_inode")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-07-10 16:04:55 +02:00
Alexander Aring
f2cc87bf3e gfs2: move msleep to sleepable context
commit ac5ee087d3 upstream.

This patch moves the msleep_interruptible() out of the non-sleepable
context by moving the ls->ls_recover_spin spinlock around so
msleep_interruptible() will be called in a sleepable context.

Cc: stable@vger.kernel.org
Fixes: 4a7727725d ("GFS2: Fix recovery issues for spectators")
Suggested-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Alexander Aring <aahringo@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2025-06-27 11:11:12 +01:00
Andrew Price
da728507b0 gfs2: Don't clear sb->s_fs_info in gfs2_sys_fs_add
commit 9126d2754c upstream.

When gfs2_sys_fs_add() fails, it sets sb->s_fs_info to NULL on its error
path (see commit 0d515210b6 ("GFS2: Add kobject release method")).
The intention seems to be to prevent dereferencing sb->s_fs_info once
the object pointed to has been deallocated, but that would be better
achieved by setting the pointer to NULL in free_sbd().

As a consequence, when the call to gfs2_sys_fs_add() fails in
gfs2_fill_super(), sdp = GFS2_SB(inode) will evaluate to NULL in iput()
-> gfs2_drop_inode(), and accessing sdp->sd_flags will be a NULL pointer
dereference.

Fix that by only setting sb->s_fs_info to NULL when actually freeing the
object pointed to in free_sbd().

Fixes: ae9f3bd825 ("gfs2: replace sd_aspace with sd_inode")
Reported-by: syzbot+b12826218502df019f9d@syzkaller.appspotmail.com
Signed-off-by: Andrew Price <anprice@redhat.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2025-06-19 15:32:37 +02:00
Christian Brauner
7b4bf4d896 gfs2: pass through holder from the VFS for freeze/thaw
[ Upstream commit 62a2175ddf ]

The filesystem's freeze/thaw functions can be called from contexts where
the holder isn't userspace but the kernel, e.g., during systemd
suspend/hibernate. So pass through the freeze/thaw flags from the VFS
instead of hard-coding them.

Signed-off-by: Christian Brauner <brauner@kernel.org>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-06-19 15:32:32 +02:00
Andreas Gruenbacher
5cd98656bc gfs2: gfs2_create_inode error handling fix
[ Upstream commit af4044fd0b ]

When gfs2_create_inode() finds a directory, make sure to return -EISDIR.

Fixes: 571a4b5797 ("GFS2: bugger off early if O_CREAT open finds a directory")
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-06-19 15:31:26 +02:00
Andreas Gruenbacher
271e6bf41a gfs2: replace sd_aspace with sd_inode
[ Upstream commit ae9f3bd825 ]

Currently, sdp->sd_aspace and the per-inode metadata address spaces use
sb->s_bdev->bd_mapping->host as their ->host; folios in those address
spaces will thus appear to be on bdev rather than on gfs2 filesystems.
This is a problem because gfs2 doesn't support cgroup writeback
(SB_I_CGROUPWB), but bdev does.

Fix that by using a "dummy" gfs2 inode as ->host in those address
spaces.  When coming from a folio, folio->mapping->host->i_sb will then
be a gfs2 super block and the SB_I_CGROUPWB flag will not be set in
sb->s_iflags.

Based on a previous version from Bob Peterson from several years ago.
Thanks to Tetsuo Handa, Jan Kara, and Rafael Aquini for helping figure
this out.

Fixes: aaa2cacf81 ("writeback: add lockdep annotation to inode_to_wb()")
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-06-19 15:31:26 +02:00
Andreas Gruenbacher
53ce754286 gfs2: Check for empty queue in run_queue
[ Upstream commit d838605fea ]

In run_queue(), check if the queue of pending requests is empty instead
of blindly assuming that it won't be.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2025-05-29 11:02:24 +02:00
Andreas Gruenbacher
4516febe32 gfs2: Truncate address space when flipping GFS2_DIF_JDATA flag
commit 7c9d922380 upstream.

Truncate an inode's address space when flipping the GFS2_DIF_JDATA flag:
depending on that flag, the pages in the address space will either use
buffer heads or iomap_folio_state structs, and we cannot mix the two.

Reported-by: Kun Hu <huk23@m.fudan.edu.cn>, Jiaji Qin <jjtan24@m.fudan.edu.cn>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2025-02-01 18:39:37 +01:00
Qianqiang Liu
7e45af15cf KMSAN: uninit-value in inode_go_dump (5)
[ Upstream commit f9417fcfca ]

When mounting of a corrupted disk image fails, the error message printed
can reference uninitialized inode fields.  To prevent that from happening,
always initialize those fields.

Reported-by: syzbot+aa0730b0a42646eb1359@syzkaller.appspotmail.com
Signed-off-by: Qianqiang Liu <qianqiang.liu@163.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2024-12-14 20:04:03 +01:00
Andreas Gruenbacher
6752b6cc10 gfs2: Fix unlinked inode cleanup
[ Upstream commit 7c6f714d88 ]

Before commit f0e56edc2e ("gfs2: Split the two kinds of glock "delete"
work"), function delete_work_func() was used to trigger the eviction of
in-memory inodes from remote as well as deleting unlinked inodes at a
later point.  These two kinds of work were then split into two kinds of
work, and the two places in the code were deferred deletion of inodes is
required accidentally ended up queuing the wrong kind of work.  This
caused unlinked inodes to be left behind, which could in the worst case
fill up filesystems and require a filesystem check to recover.

Fix that by queuing the right kind of work in try_rgrp_unlink() and
gfs2_drop_inode().

Fixes: f0e56edc2e ("gfs2: Split the two kinds of glock "delete" work")
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
2024-12-05 14:02:18 +01:00
Andreas Gruenbacher
2a10074b46 gfs2: Allow immediate GLF_VERIFY_DELETE work
[ Upstream commit 160bc9555d ]

Add an argument to gfs2_queue_verify_delete() that allows it to queue
GLF_VERIFY_DELETE work for immediate execution.  This is used in the
next patch.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 7c6f714d88 ("gfs2: Fix unlinked inode cleanup")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2024-12-05 14:02:18 +01:00
Andreas Gruenbacher
85b6cc14de gfs2: Rename GLF_VERIFY_EVICT to GLF_VERIFY_DELETE
[ Upstream commit 820ce8ed53 ]

Rename the GLF_VERIFY_EVICT flag to GLF_VERIFY_DELETE: that flag
indicates that we want to delete an inode / verify that it has been
deleted.

To match, rename gfs2_queue_verify_evict() to
gfs2_queue_verify_delete().

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
Stable-dep-of: 7c6f714d88 ("gfs2: Fix unlinked inode cleanup")
Signed-off-by: Sasha Levin <sashal@kernel.org>
2024-12-05 14:02:17 +01:00
Linus Torvalds
721068dec4 gfs2 changes
- Eliminate the writepage address space operation (by Matthew Wilcox).
 
 - A syzkaller fix (by Julian Sun) and a minor cleanup (by Andreas
   Gruenbacher).
 -----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCAAyFiEEJZs3krPW0xkhLMTc1b+f6wMTZToFAmbwIfMUHGFncnVlbmJh
 QHJlZGhhdC5jb20ACgkQ1b+f6wMTZTqj/RAApBJf8Da7U9Qn3rMtCdV3HU8p9VSF
 Fwzr1qVgthNNfFGSaNhTQcTglSL0OLMg8rLaAFN8G0RJrOyJw9Q0GclhLR+wGy5F
 KpvpVczkYh+UphYJ7LhygUE9/cP2GZCSI5EbI+cIifnioY8rztt+e8QqteFpAoFA
 3asfynVWeAnYYh6qIjZBSvi77KWzaxk9Kyv8WScJ//FTNHYYXLMKUhZEXuh0gCdv
 r9VwCnRNTm8X9YtbeaRduC7mSRcVwtV+KCCJ0Lxw292a795g5oWvdwnx4DQg5120
 XvdcGkZOV/sjQE19vhfkJot6kLPhP9PofTWBIbwqMwV/lkxEKlQAPJ5+mnjg56eU
 JekZjibxEewSDkG4riWibBP2WgIfqHkryl8o9a4dZSIjeNfzJYbvhyL2NwPYfFOY
 43VeC6AB6K49gwUtD0gRTOKV/EKEFswRh1Cstvt+hPrpnF7Y/ZUjCptaEk/ZicyK
 qWG/6YVtjXz9HvOo/eojTTlZuwlmh2l63aWwW9s8/aMCei6V5Hs/S3gtuZSg7bKL
 AtfUmwlNLfNSh4VavO6W3SxuCp12OVwPYe0WQPccMshA6fVbsH1QV8LSUS5WKaE7
 TGsevEWEanAm85zlbar2BvIk1PaxRNvNJ7BgZ1LYUwdHvm9/h+JPMZUYqBUDYbZC
 Fz5wF5zjbmeR91k=
 =cuQP
 -----END PGP SIGNATURE-----

Merge tag 'gfs2-v6.10-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2

Pull gfs2 update from Andreas Gruenbacher:

 - Convert the writepage address space operation to writepages (Matthew
   Wilcox)

 - A syzkaller fix (by Julian Sun) and a minor cleanup (Andreas
   Gruenbacher)

* tag 'gfs2-v6.10-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/gfs2/linux-gfs2:
  gfs2: Remove gfs2_aspace_writepage()
  gfs2: Remove gfs2_jdata_writepage()
  gfs2: Remove __gfs2_writepage()
  gfs2: Add gfs2_aspace_writepages()
  gfs2: fix double destroy_workqueue error
  gfs2: Minor gfs2_glock_cb cleanup
2024-09-23 11:55:17 -07:00
Josef Bacik
31754ea6cb iomap: add a private argument for iomap_file_buffered_write
In order to switch fuse over to using iomap for buffered writes we need
to be able to have the struct file for the original write, in case we
have to read in the page to make it uptodate.  Handle this by using the
existing private field in the iomap_iter, and add the argument to
iomap_file_buffered_write.  This will allow us to pass the file in
through the iomap buffered write path, and is flexible for any other
file systems needs.

Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Link: https://lore.kernel.org/r/7f55c7c32275004ba00cddf862d970e6e633f750.1724755651.git.josef@toxicpanda.com
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Christian Brauner <brauner@kernel.org>
2024-09-03 15:01:23 +02:00
Matthew Wilcox (Oracle)
6888c1e85f gfs2: Remove gfs2_aspace_writepage()
There are no remaining callers of gfs2_aspace_writepage() other than
vmscan, which is known to do more harm than good.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-09-02 14:46:37 +02:00
Matthew Wilcox (Oracle)
e5ac171992 gfs2: Remove gfs2_jdata_writepage()
There are no remaining callers of gfs2_jdata_writepage() other than
vmscan, which is known to do more harm than good.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-09-02 14:46:33 +02:00
Matthew Wilcox (Oracle)
8d391972ae gfs2: Remove __gfs2_writepage()
Call aops->writepages() instead of using write_cache_pages() to call
aops->writepage.  Change the handling of -ENODATA to not set the
persistent error on the block device.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-09-02 14:46:29 +02:00
Matthew Wilcox (Oracle)
901849e707 gfs2: Add gfs2_aspace_writepages()
This saves one indirect function call per folio and gets us closer to
removing aops->writepage.

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-09-02 14:46:21 +02:00
Julian Sun
6cb9df81a2 gfs2: fix double destroy_workqueue error
When gfs2_fill_super() fails, destroy_workqueue() is called within
gfs2_gl_hash_clear(), and the subsequent code path calls
destroy_workqueue() on the same work queue again.

This issue can be fixed by setting the work queue pointer to NULL after
the first destroy_workqueue() call and checking for a NULL pointer
before attempting to destroy the work queue again.

Reported-by: syzbot+d34c2a269ed512c531b0@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=d34c2a269ed512c531b0
Fixes: 30e388d573 ("gfs2: Switch to a per-filesystem glock workqueue")
Cc: stable@vger.kernel.org
Signed-off-by: Julian Sun <sunjunchao2870@gmail.com>
Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-08-20 16:27:22 +02:00
Andreas Gruenbacher
4117efd5c9 gfs2: Minor gfs2_glock_cb cleanup
In gfs2_glock_cb(), we only need to calculate the glock hold time for
inode glocks; the value is unused otherwise.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-08-20 16:06:43 +02:00
Andreas Gruenbacher
f75efefb6d gfs2: Clean up glock demote logic
The logic for determining when to demote a glock in glock_work_func(),
introduced in commit 7cf8dcd3b6 ("GFS2: Automatically adjust glock min
hold time"), doesn't make sense: inode glocks have a minimum hold time
that delays demotion, while all other glocks are expected to be demoted
immediately.  Instead of demoting non-inode glocks immediately,
glock_work_func() schedules glock work for them to be demoted, however.
Get rid of that unnecessary indirection.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-07-09 10:40:03 +02:00
Andreas Gruenbacher
5a1906a476 gfs2: Revert "check for no eligible quota changes"
Since the previous commit, function gfs2_quota_sync() will not cause the
sync generation to creep forward by one every time the function is
called; this helps keep things a but more tidy.  We also don't care that
this function allocates a page of memory every time it is called, so no
good reason for keeping qd_changed() anymore, which just duplicates
qd_grab_sync().

This reverts commit 06aa6fd31a.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-20 16:38:15 +02:00
Andreas Gruenbacher
d9a75a6069 gfs2: Be more careful with the quota sync generation
The quota sync generation is only ever updated under sd_quota_sync_mutex
by gfs2_quota_sync(), but its current value is fetched ouside of that
mutex, so use WRITE_ONCE() and READ_ONCE() when accessing it without
holding that mutex.

Pass the current sync generation to do_sync() from its callers to ensure
that we're not recording the wrong generation when the syncing is
done.  Also, make sure that qd->qd_sync_gen only ever moves forward.

In gfs2_quota_sync(), only write the new sync generation when we know
that there are changes.  This eliminates the need for function
sd_changed(), which we will remove in the next commit.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-20 16:38:15 +02:00
Andreas Gruenbacher
8d89e068de gfs2: Get rid of some unnecessary quota locking
With the locking the previous patch has introduced for each struct
gfs2_quota_data object, sd_quota_mutex has become largely irrelevant.
By waiting on the buffer head instead of waiting on the mutex in
get_bh(), it becomes completely irrelevant and can be removed.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-20 16:38:13 +02:00
Andreas Gruenbacher
d5563f42f5 gfs2: Add some missing quota locking
The quota code is missing some locking between local quota changes and
syncing those quota changes to the global quota file (gfs2_quota_sync);
in particular, qd->qd_change needs to be kept in sync with the
QDF_CHANGE change flag and the number of references held.  Use the
qd->qd_lockref.lock spinlock for that.

With the qd->qd_lockref.lock spinlock held, we can no longer call
lockref_get(), so turn qd_hold() into a variant that assumes that the
lock is held.  This function is really supposed to take an additional
reference when one or more references are already held, so check for
that instead of checking if the lockref is dead.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-12 20:33:51 +02:00
Andreas Gruenbacher
614abc1187 gfs2: Fold qd_fish into gfs2_quota_sync
The split between qd_fish() and gfs2_quota_sync() is rather unfortunate
as qd_fish() is repeatedly called to scan sdp->sd_quota_list only to
find the next object to that needs syncing; if there are multiple
objects on the list that need syncing, it makes more sense to grab them
all in one go.  This is relatively easy to do when qd_fish() is folded
into gfs2_quota_sync().

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-08 02:35:16 +02:00
Andreas Gruenbacher
b510af07aa gfs2: quota need_sync cleanup
Rename variable 'value' to 'change' as it stores a change in value.

Add new 'value' and 'limit' variables for the current value and limit.

Only fetch the tuning parameters when we need them.

Get rid of unnecessary nesting.

No change in functionality.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-08 02:35:16 +02:00
Andreas Gruenbacher
7da4d6e178 gfs2: Fix and clean up function do_qc
Function do_qc() is supposed to be conceptually simple: it alters the
current in-memory and on-disk quota change values for a given uid/gid by
a given delta.  If the on-disk record isn't defined yet, a new record is
created.  If the on-disk record exists and the resulting change value is
zero, there no longer is a need for that record and so the record is
deleted.  On top of that, some reference counting is involved when
creating and deleting records.

Currently, instead of doing the above, do_qc() alters the on-disk value
and then it sets the in-memory value to the on-disk value.  This is
incorrect when the on-disk value differs from the in-memory value.  The
two values are allowed to differ when quota changes are synced to the
global quota file.  Fix by changing both values by the same amount.

In addition, do_qc() currently gets confused when the delta value is 0.
It isn't supposed to be called that way, but that assumption isn't
mentioned and it makes the code harder to read.  Make the code more
explicit.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-08 02:35:16 +02:00
Andreas Gruenbacher
ec4b5200c8 gfs2: Revert "Add quota_change type"
Commit 432928c937 ("gfs2: Add quota_change type") makes the incorrect
assertion that function do_qc() should behave differently in the two
contexts it is used in, but that isn't actually true.  In all cases,
do_qc() grabs a "reference" when it starts using a slot in the per-node
quota changes file, and it releases that "reference" when no more
residual changes remain.  Revert that broken commit.

There are some remaining issues with function do_qc() which are
addressed in the next commit.

This reverts commit 432928c937.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-08 02:35:09 +02:00
Andreas Gruenbacher
4b4b6374dc gfs2: Revert "ignore negated quota changes"
Commit 4c6a08125f ("gfs2: ignore negated quota changes") skips quota
changes with qd_change == 0 instead of writing them back, which leaves
behind non-zero qd_change values in the affected slots.  The kernel then
assumes that those slots are unused, while the qd_change values on disk
indicate that they are indeed still in use.  The next time the
filesystem is mounted, those invalid slots are read in from disk, which
will cause inconsistencies.

Revert that commit to avoid filesystem corruption.

This reverts commit 4c6a08125f.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-08 02:34:57 +02:00
Andreas Gruenbacher
59ebc33201 gfs2: qd_check_sync cleanups
Rename qd_check_sync() to qd_grab_sync() and make it return a bool.
Turn the sync_gen pointer into a regular u64 and pass in U64_MAX instead
of a NULL pointer when sync generation checking isn't needed.

Introduce a new qd_ungrab_sync() helper for undoing the effects of
qd_grab_sync() if the subsequent bh_get() on the qd object fails.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-08 02:34:56 +02:00
Andreas Gruenbacher
2aedfe847b gfs2: Revert "introduce qd_bh_get_or_undo"
The qd_bh_get_or_undo() helper introduced by that commit doesn't improve
the code much, so revert it and clean things up in a more useful way in
the next commit.

This reverts commit 7dbc6ae60d.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-08 02:34:40 +02:00
Andreas Gruenbacher
de0d95c26c gfs2: Check quota consistency on mount
In gfs2_quota_init(), make sure that the per-node "quota_change%u" file
doesn't contain duplicate uids/gids.  Those duplicates would cause us to
acquire the glock corresponding to those ids repeatedly, which the glock
code doesn't allow.

When finding inconsistencies, we wipe them out and ignore them.  The
resulting quotas will likely be inconsistent, and running quotacheck(1)
is advised.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-07 22:36:16 +02:00
Andreas Gruenbacher
51316523d1 gfs2: Minor gfs2_quota_init error path cleanup
Add a fail_brelse label and use it where useful.  Move variable bh out
of the loop to extend its visibility to the new label.  No functional
change.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-06-04 16:00:34 +02:00
Andreas Gruenbacher
713f883438 gfs2: Get rid of demote_ok checks
The demote_ok glock operation is only still used to prevent the inode
glocks of the "jindex" and "rindex" directories from getting recycled
while they are still referenced by sdp->sd_jindex and sdp->sd_rindex.
However, the LRU walking code will no longer recycle glocks which are
referenced, so the demote_ok glock operation is obsolete and can be
removed.

Each of a glock's holders in the gl_holders list is holding a reference
on the glock, so when the list of holders isn't empty in demote_ok(),
the existing reference count check will already prevent the glock from
getting released.  This means that demote_ok() is obsolete as well.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-05-29 15:34:55 +02:00
Andreas Gruenbacher
3f4475bf24 Revert "GFS2: Don't add all glocks to the lru"
This reverts commit e7ccaf5fe1.

Before commit e7ccaf5fe1, every time a resource group glock was
dequeued by gfs2_glock_dq(), it was added to the glock LRU list even
though the glock was still referenced by the resource group and could
never be evicted, anyway.  Commit e7ccaf5fe1 added a GLOF_LRU hack to
avoid that overhead for resource group glocks, and that hack was since
adopted for some other types of glocks as well.

We now no longer add glocks to the glock LRU list while they are still
referenced.  This solves the underlying problem, and obsoletes the
GLOF_LRU hack.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
(cherry picked from commit 3e5257c810cba91e274d07f3db5cf013c7c830be)
2024-05-29 15:34:55 +02:00
Andreas Gruenbacher
767fd5a016 gfs2: Revise glock reference counting model
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 <agruenba@redhat.com>
2024-05-29 15:34:55 +02:00
Andreas Gruenbacher
30e388d573 gfs2: Switch to a per-filesystem glock workqueue
Switch to a per-filesystem glock workqueue.  Additional workqueues are
cheap nowadays, and keeping separate workqueues allows to flush the work
of each filesystem without affecting the others.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-05-29 15:34:55 +02:00
Andreas Gruenbacher
51568ac2e9 gfs2: Report when glocks cannot be freed for a long time
When glocks cannot be freed for a long time, avoid the "task blocked for
more than N seconds" messages and report how many glocks are still
outstanding, instead.

Signed-off-by: Andreas Gruenbacher <agruenba@redhat.com>
2024-05-29 15:34:55 +02:00