Don't check meta seq before locking

The block lock functions were trying to compare the block header seq and
the super seq to decide if the block is stable and if it should lock, or
not.  Readers trying to lock races with transaction commits.
Transaction commit can update the super after the reader locks and
before it unlocks.  The unlock will then fail the test and fail to
unlock.  fsstress triggered this in xfstests generic/013.

Instead we can always acquire the read lock on stable blocks.  We'll be
bouncing the rwsem cacheline around like the refcount cacheline.  If
this is a problem we can carefully maintain bits in the block to safely
indicate if it should be locked or unlocked but let's not go there if we
don't have to.

Signed-off-by: Zach Brown <zab@versity.com>
Reviewed-by: Mark Fasheh <mfasheh@versity.com>
This commit is contained in:
Zach Brown
2016-11-09 13:46:39 -08:00
parent 0c67dd51ef
commit d71f7a24ec

View File

@@ -641,28 +641,18 @@ void scoutfs_block_set_lock_class(struct scoutfs_block *bl,
void scoutfs_block_lock(struct scoutfs_block *bl, bool write, int subclass)
{
struct scoutfs_block_header *hdr = scoutfs_block_data(bl);
struct scoutfs_sb_info *sbi = SCOUTFS_SB(bl->sb);
if (hdr->seq == sbi->super.hdr.seq) {
if (write)
down_write_nested(&bl->rwsem, subclass);
else
down_read_nested(&bl->rwsem, subclass);
}
if (write)
down_write_nested(&bl->rwsem, subclass);
else
down_read_nested(&bl->rwsem, subclass);
}
void scoutfs_block_unlock(struct scoutfs_block *bl, bool write)
{
struct scoutfs_block_header *hdr = scoutfs_block_data(bl);
struct scoutfs_sb_info *sbi = SCOUTFS_SB(bl->sb);
if (hdr->seq == sbi->super.hdr.seq) {
if (write)
up_write(&bl->rwsem);
else
up_read(&bl->rwsem);
}
if (write)
up_write(&bl->rwsem);
else
up_read(&bl->rwsem);
}
void *scoutfs_block_data(struct scoutfs_block *bl)