mirror of
https://github.com/versity/scoutfs.git
synced 2026-09-01 21:57:10 +00:00
Fix unlocked pt_excl in scoutfs_readahead
This caller of scoutfs_get_block is now actively used in el10 and the WARN_ON_ONCE(!lock) in data.c:567 triggers. Add the scoutfs_per_task_add_excl/del calls in scoutfs_readpage, scoutfs_readpages, and scoutfs_readahead to register the cluster lock for scoutfs_get_block_read. Add unconditionally rather than guarded by the add_excl return, since these methods can be reached reentrantly from a top-level read that already added the entry. Skipping the I/O in that case left BUG_ON(!list_empty(pages)) in scoutfs_readpages and the page locked in scoutfs_readpage. Move scoutfs_per_task_del before scoutfs_unlock to match the ordering used by file.c read/write paths. Signed-off-by: Auke Kok <auke.kok@versity.com>
This commit is contained in:
+28
-18
@@ -726,24 +726,24 @@ static int scoutfs_readpage(struct file *file, struct page *page)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock)) {
|
||||
ret = scoutfs_data_wait_check(inode, page_offset(page),
|
||||
PAGE_SIZE, SEF_OFFLINE,
|
||||
SCOUTFS_IOC_DWO_READ, &dw,
|
||||
inode_lock);
|
||||
if (ret != 0) {
|
||||
unlock_page(page);
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
if (ret > 0) {
|
||||
ret = scoutfs_data_wait(inode, &dw);
|
||||
if (ret == 0)
|
||||
ret = AOP_TRUNCATED_PAGE;
|
||||
}
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock);
|
||||
|
||||
ret = scoutfs_data_wait_check(inode, page_offset(page),
|
||||
PAGE_SIZE, SEF_OFFLINE,
|
||||
SCOUTFS_IOC_DWO_READ, &dw,
|
||||
inode_lock);
|
||||
if (ret != 0) {
|
||||
unlock_page(page);
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
if (ret > 0) {
|
||||
ret = scoutfs_data_wait(inode, &dw);
|
||||
if (ret == 0)
|
||||
ret = AOP_TRUNCATED_PAGE;
|
||||
}
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
#ifdef KC_MPAGE_READ_FOLIO
|
||||
ret = mpage_read_folio(folio, scoutfs_get_block_read);
|
||||
@@ -751,8 +751,8 @@ static int scoutfs_readpage(struct file *file, struct page *page)
|
||||
ret = mpage_readpage(page, scoutfs_get_block_read);
|
||||
#endif
|
||||
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -770,8 +770,10 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping,
|
||||
struct list_head *pages, unsigned nr_pages)
|
||||
{
|
||||
struct inode *inode = file->f_inode;
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
struct page *page;
|
||||
struct page *tmp;
|
||||
int ret;
|
||||
@@ -781,6 +783,8 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock);
|
||||
|
||||
list_for_each_entry_safe(page, tmp, pages, lru) {
|
||||
ret = scoutfs_data_wait_check(inode, page_offset(page),
|
||||
PAGE_SIZE, SEF_OFFLINE,
|
||||
@@ -800,6 +804,7 @@ static int scoutfs_readpages(struct file *file, struct address_space *mapping,
|
||||
|
||||
ret = mpage_readpages(mapping, pages, nr_pages, scoutfs_get_block_read);
|
||||
out:
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
BUG_ON(!list_empty(pages));
|
||||
return ret;
|
||||
@@ -808,8 +813,10 @@ out:
|
||||
static void scoutfs_readahead(struct readahead_control *rac)
|
||||
{
|
||||
struct inode *inode = rac->file->f_inode;
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
int ret;
|
||||
|
||||
ret = scoutfs_lock_inode(sb, SCOUTFS_LOCK_READ,
|
||||
@@ -817,6 +824,8 @@ static void scoutfs_readahead(struct readahead_control *rac)
|
||||
if (ret)
|
||||
return;
|
||||
|
||||
scoutfs_per_task_add_excl(&si->pt_data_lock, &pt_ent, inode_lock);
|
||||
|
||||
ret = scoutfs_data_wait_check(inode, readahead_pos(rac),
|
||||
readahead_length(rac), SEF_OFFLINE,
|
||||
SCOUTFS_IOC_DWO_READ, NULL,
|
||||
@@ -824,6 +833,7 @@ static void scoutfs_readahead(struct readahead_control *rac)
|
||||
if (ret == 0)
|
||||
mpage_readahead(rac, scoutfs_get_block_read);
|
||||
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, SCOUTFS_LOCK_READ);
|
||||
}
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user