mirror of
https://github.com/versity/scoutfs.git
synced 2026-08-20 14:16:49 +00:00
scoutfs: lock invalidate only syncs dirty
Lock invalidation has to make sure that changes are visible to future readers. It was syncing if the current transaction is dirty. This was never optimal, but it wasn't catastrophic when concurrent invalidation work could all block on one sync in progress. With the move to a single invalidation worker serially invalidating locks it became unacceptable. Invalidation happening in the presence of writers would constantly sync the current transaction while very old unused write locks were invalidated. Their changes had long since been committed in previous transactions. We add a lock field to remember the transaction sequence which could have been dirtied under the lock. If that transaction has already been comitted by the time we invalidate the lock it doesn't have to sync. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
+6
-6
@@ -160,15 +160,13 @@ static int lock_invalidate(struct super_block *sb, struct scoutfs_lock *lock,
|
||||
BUG_ON(!(prev == SCOUTFS_LOCK_WRITE && mode == SCOUTFS_LOCK_READ) &&
|
||||
mode != SCOUTFS_LOCK_NULL);
|
||||
|
||||
/* any transition from a mode allowed to dirty items has to write */
|
||||
if (lock_mode_can_write(prev) && scoutfs_trans_has_dirty(sb)) {
|
||||
/* sync when a write lock could have dirtied the current transaction */
|
||||
if (lock_mode_can_write(prev) &&
|
||||
(lock->dirty_trans_seq == scoutfs_trans_sample_seq(sb))) {
|
||||
scoutfs_inc_counter(sb, lock_invalidate_sync);
|
||||
ret = scoutfs_trans_sync(sb, 1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (ret > 0) {
|
||||
scoutfs_add_counter(sb, lock_invalidate_commit, ret);
|
||||
ret = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* have to invalidate if we're not in the only usable case */
|
||||
@@ -1273,6 +1271,8 @@ void scoutfs_unlock(struct super_block *sb, struct scoutfs_lock *lock, int mode)
|
||||
|
||||
lock_dec_count(lock->users, mode);
|
||||
extend_grace(sb, lock);
|
||||
if (lock_mode_can_write(mode))
|
||||
lock->dirty_trans_seq = scoutfs_trans_sample_seq(sb);
|
||||
|
||||
trace_scoutfs_lock_unlock(sb, lock);
|
||||
wake_up(&lock->waitq);
|
||||
|
||||
Reference in New Issue
Block a user