erofs: fix refcount on the metabuf used for inode lookup
commit56ee7db311upstream. In erofs_find_target_block() when erofs_dirnamecmp() returns 0, we do not assign the target metabuf. This causes the caller erofs_namei()'s erofs_put_metabuf() at the end to be not effective leaving the refcount on the page. As the page from metabuf (buf->page) is never put, such page cannot be migrated or reclaimed. Fix it now by putting the metabuf from previous loop and assigning the current metabuf to target before returning so caller erofs_namei() can do the final put as it was intended. Fixes:500edd0956("erofs: use meta buffers for inode lookup") Cc: <stable@vger.kernel.org> # 5.18+ Signed-off-by: Sandeep Dhavale <dhavale@google.com> Reviewed-by: Gao Xiang <hsiangkao@linux.alibaba.com> Reviewed-by: Jingbo Xu <jefflexu@linux.alibaba.com> Reviewed-by: Chao Yu <chao@kernel.org> Link: https://lore.kernel.org/r/20240221210348.3667795-1-dhavale@google.com Signed-off-by: Gao Xiang <hsiangkao@linux.alibaba.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
943c8b1fcc
commit
d9d2426253
+14
-14
@@ -137,24 +137,24 @@ static void *find_target_block_classic(struct erofs_buf *target,
|
||||
/* string comparison without already matched prefix */
|
||||
diff = erofs_dirnamecmp(name, &dname, &matched);
|
||||
|
||||
if (!diff) {
|
||||
*_ndirents = 0;
|
||||
goto out;
|
||||
} else if (diff > 0) {
|
||||
head = mid + 1;
|
||||
startprfx = matched;
|
||||
|
||||
if (!IS_ERR(candidate))
|
||||
erofs_put_metabuf(target);
|
||||
*target = buf;
|
||||
candidate = de;
|
||||
*_ndirents = ndirents;
|
||||
} else {
|
||||
if (diff < 0) {
|
||||
erofs_put_metabuf(&buf);
|
||||
|
||||
back = mid - 1;
|
||||
endprfx = matched;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!IS_ERR(candidate))
|
||||
erofs_put_metabuf(target);
|
||||
*target = buf;
|
||||
if (!diff) {
|
||||
*_ndirents = 0;
|
||||
return de;
|
||||
}
|
||||
head = mid + 1;
|
||||
startprfx = matched;
|
||||
candidate = de;
|
||||
*_ndirents = ndirents;
|
||||
continue;
|
||||
}
|
||||
out: /* free if the candidate is valid */
|
||||
|
||||
Reference in New Issue
Block a user