* [PATCH] erofs: fix two loop issues when read page beyond EOF
@ 2023-07-08 6:24 Chunhai Guo
2023-07-08 9:00 ` Gao Xiang
0 siblings, 1 reply; 7+ messages in thread
From: Chunhai Guo @ 2023-07-08 6:24 UTC (permalink / raw)
To: xiang, chao; +Cc: huyue2, jefflexu, linux-erofs, linux-kernel, Chunhai Guo
When z_erofs_read_folio() reads a page with an offset far beyond EOF, two
issues may occur:
- z_erofs_pcluster_readmore() may take a long time to loop when the offset
is big enough, which is unnecessary.
- For example, it will loop 4691368 times and take about 27 seconds
with following case.
- offset = 19217289215
- inode_size = 1442672
- z_erofs_do_read_page() may loop infinitely due to the inappropriate
truncation in the below statement. Since the offset is 64 bits and
min_t() truncates the result to 32 bits. The solution is to replace
unsigned int with another 64-bit type, such as erofs_off_t.
cur = end - min_t(unsigned int, offset + end - map->m_la, end);
- For example:
- offset = 0x400160000
- end = 0x370
- map->m_la = 0x160370
- offset + end - map->m_la = 0x400000000
- offset + end - map->m_la = 0x00000000 (truncated as unsigned int)
- Expected result:
- cur = 0
- Actual result:
- cur = 0x370
Signed-off-by: Chunhai Guo <guochunhai@vivo.com>
---
fs/erofs/zdata.c | 13 ++++++++++---
1 file changed, 10 insertions(+), 3 deletions(-)
diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c
index 5f1890e309c6..6abbd4510076 100644
--- a/fs/erofs/zdata.c
+++ b/fs/erofs/zdata.c
@@ -972,7 +972,8 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
struct erofs_map_blocks *const map = &fe->map;
const loff_t offset = page_offset(page);
bool tight = true, exclusive;
- unsigned int cur, end, spiltted;
+ erofs_off_t cur, end;
+ unsigned int spiltted;
int err = 0;
/* register locked file pages as online pages in pack */
@@ -1035,7 +1036,7 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe,
*/
tight &= (fe->mode > Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE);
- cur = end - min_t(unsigned int, offset + end - map->m_la, end);
+ cur = end - min_t(erofs_off_t, offset + end - map->m_la, end);
if (!(map->m_flags & EROFS_MAP_MAPPED)) {
zero_user_segment(page, cur, end);
goto next_part;
@@ -1841,7 +1842,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f,
}
cur = map->m_la + map->m_llen - 1;
- while (cur >= end) {
+ while ((cur >= end) && (cur < i_size_read(inode))) {
pgoff_t index = cur >> PAGE_SHIFT;
struct page *page;
@@ -1876,6 +1877,12 @@ static int z_erofs_read_folio(struct file *file, struct folio *folio)
trace_erofs_readpage(page, false);
f.headoffset = (erofs_off_t)page->index << PAGE_SHIFT;
+ /* when trying to read beyond EOF, return zero page directly */
+ if (f.headoffset >= i_size_read(inode)) {
+ zero_user_segment(page, 0, PAGE_SIZE);
+ return 0;
+ }
+
z_erofs_pcluster_readmore(&f, NULL, true);
err = z_erofs_do_read_page(&f, page);
z_erofs_pcluster_readmore(&f, NULL, false);
--
2.25.1
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH] erofs: fix two loop issues when read page beyond EOF 2023-07-08 6:24 [PATCH] erofs: fix two loop issues when read page beyond EOF Chunhai Guo @ 2023-07-08 9:00 ` Gao Xiang 2023-07-10 3:32 ` Chunhai Guo 0 siblings, 1 reply; 7+ messages in thread From: Gao Xiang @ 2023-07-08 9:00 UTC (permalink / raw) To: Chunhai Guo, xiang, chao; +Cc: huyue2, jefflexu, linux-erofs, linux-kernel Hi Chunhai, On 2023/7/8 14:24, Chunhai Guo wrote: > When z_erofs_read_folio() reads a page with an offset far beyond EOF, two > issues may occur: > - z_erofs_pcluster_readmore() may take a long time to loop when the offset > is big enough, which is unnecessary. > - For example, it will loop 4691368 times and take about 27 seconds > with following case. > - offset = 19217289215 > - inode_size = 1442672 > - z_erofs_do_read_page() may loop infinitely due to the inappropriate > truncation in the below statement. Since the offset is 64 bits and > min_t() truncates the result to 32 bits. The solution is to replace > unsigned int with another 64-bit type, such as erofs_off_t. > cur = end - min_t(unsigned int, offset + end - map->m_la, end); > - For example: > - offset = 0x400160000 > - end = 0x370 > - map->m_la = 0x160370 > - offset + end - map->m_la = 0x400000000 > - offset + end - map->m_la = 0x00000000 (truncated as unsigned int) Thanks for the catch! Could you split these two into two patches? how about using: cur = end - min_t(erofs_off_t, offend + end - map->m_la, end) for this? since cur and end are all [0, PAGE_SIZE - 1] for now, and folio_size() later. > - Expected result: > - cur = 0 > - Actual result: > - cur = 0x370 > > Signed-off-by: Chunhai Guo <guochunhai@vivo.com> > --- > fs/erofs/zdata.c | 13 ++++++++++--- > 1 file changed, 10 insertions(+), 3 deletions(-) > > diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c > index 5f1890e309c6..6abbd4510076 100644 > --- a/fs/erofs/zdata.c > +++ b/fs/erofs/zdata.c > @@ -972,7 +972,8 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, > struct erofs_map_blocks *const map = &fe->map; > const loff_t offset = page_offset(page); > bool tight = true, exclusive; > - unsigned int cur, end, spiltted; > + erofs_off_t cur, end; > + unsigned int spiltted; > int err = 0; > > /* register locked file pages as online pages in pack */ > @@ -1035,7 +1036,7 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, > */ > tight &= (fe->mode > Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE); > > - cur = end - min_t(unsigned int, offset + end - map->m_la, end); > + cur = end - min_t(erofs_off_t, offset + end - map->m_la, end); > if (!(map->m_flags & EROFS_MAP_MAPPED)) { > zero_user_segment(page, cur, end); > goto next_part; > @@ -1841,7 +1842,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f, > } > > cur = map->m_la + map->m_llen - 1; > - while (cur >= end) { > + while ((cur >= end) && (cur < i_size_read(inode))) { > pgoff_t index = cur >> PAGE_SHIFT; > struct page *page; > > @@ -1876,6 +1877,12 @@ static int z_erofs_read_folio(struct file *file, struct folio *folio) > trace_erofs_readpage(page, false); > f.headoffset = (erofs_off_t)page->index << PAGE_SHIFT; > > + /* when trying to read beyond EOF, return zero page directly */ > + if (f.headoffset >= i_size_read(inode)) { > + zero_user_segment(page, 0, PAGE_SIZE); > + return 0; > + } Do we really need to optimize this rare case? I guess the follow readmore fix is enough, thoughts? Thanks, Gao Xiang ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] erofs: fix two loop issues when read page beyond EOF 2023-07-08 9:00 ` Gao Xiang @ 2023-07-10 3:32 ` Chunhai Guo 2023-07-10 3:37 ` Gao Xiang 0 siblings, 1 reply; 7+ messages in thread From: Chunhai Guo @ 2023-07-10 3:32 UTC (permalink / raw) To: Gao Xiang, xiang@kernel.org, chao@kernel.org Cc: huyue2@coolpad.com, jefflexu@linux.alibaba.com, linux-erofs@lists.ozlabs.org, linux-kernel@vger.kernel.org Hi Xiang, On 2023/7/8 17:00, Gao Xiang wrote: > Hi Chunhai, > > On 2023/7/8 14:24, Chunhai Guo wrote: >> When z_erofs_read_folio() reads a page with an offset far beyond EOF, two >> issues may occur: >> - z_erofs_pcluster_readmore() may take a long time to loop when the offset >> is big enough, which is unnecessary. >> - For example, it will loop 4691368 times and take about 27 seconds >> with following case. >> - offset = 19217289215 >> - inode_size = 1442672 >> - z_erofs_do_read_page() may loop infinitely due to the inappropriate >> truncation in the below statement. Since the offset is 64 bits and >> min_t() truncates the result to 32 bits. The solution is to replace >> unsigned int with another 64-bit type, such as erofs_off_t. >> cur = end - min_t(unsigned int, offset + end - map->m_la, end); >> - For example: >> - offset = 0x400160000 >> - end = 0x370 >> - map->m_la = 0x160370 >> - offset + end - map->m_la = 0x400000000 >> - offset + end - map->m_la = 0x00000000 (truncated as unsigned int) > > Thanks for the catch! > > Could you split these two into two patches? > > how about using: > cur = end - min_t(erofs_off_t, offend + end - map->m_la, end) > for this? > > since cur and end are all [0, PAGE_SIZE - 1] for now, and > folio_size() later. OK. I will split the patch. Sorry that I can not understand what is 'offend' refer to and what do you mean. Could you please describe it more clearly? >> - Expected result: >> - cur = 0 >> - Actual result: >> - cur = 0x370 >> >> Signed-off-by: Chunhai Guo <guochunhai@vivo.com> >> --- >> fs/erofs/zdata.c | 13 ++++++++++--- >> 1 file changed, 10 insertions(+), 3 deletions(-) >> >> diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c >> index 5f1890e309c6..6abbd4510076 100644 >> --- a/fs/erofs/zdata.c >> +++ b/fs/erofs/zdata.c >> @@ -972,7 +972,8 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, >> struct erofs_map_blocks *const map = &fe->map; >> const loff_t offset = page_offset(page); >> bool tight = true, exclusive; >> - unsigned int cur, end, spiltted; >> + erofs_off_t cur, end; >> + unsigned int spiltted; >> int err = 0; >> >> /* register locked file pages as online pages in pack */ >> @@ -1035,7 +1036,7 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, >> */ >> tight &= (fe->mode > Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE); >> >> - cur = end - min_t(unsigned int, offset + end - map->m_la, end); >> + cur = end - min_t(erofs_off_t, offset + end - map->m_la, end); >> if (!(map->m_flags & EROFS_MAP_MAPPED)) { >> zero_user_segment(page, cur, end); >> goto next_part; >> @@ -1841,7 +1842,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f, >> } >> >> cur = map->m_la + map->m_llen - 1; >> - while (cur >= end) { >> + while ((cur >= end) && (cur < i_size_read(inode))) { >> pgoff_t index = cur >> PAGE_SHIFT; >> struct page *page; >> >> @@ -1876,6 +1877,12 @@ static int z_erofs_read_folio(struct file *file, struct folio *folio) >> trace_erofs_readpage(page, false); >> f.headoffset = (erofs_off_t)page->index << PAGE_SHIFT; >> >> + /* when trying to read beyond EOF, return zero page directly */ >> + if (f.headoffset >= i_size_read(inode)) { >> + zero_user_segment(page, 0, PAGE_SIZE); >> + return 0; >> + } > Do we really need to optimize this rare case? > I guess the follow readmore fix is enough, thoughts? > > Thanks, > Gao Xiang Since the code is constantly being updated and someone may encounter this bug again, I think we had better fix it if possible. Thanks. Guo Chunhai ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] erofs: fix two loop issues when read page beyond EOF 2023-07-10 3:32 ` Chunhai Guo @ 2023-07-10 3:37 ` Gao Xiang 2023-07-10 4:35 ` Chunhai Guo 0 siblings, 1 reply; 7+ messages in thread From: Gao Xiang @ 2023-07-10 3:37 UTC (permalink / raw) To: Chunhai Guo, xiang@kernel.org, chao@kernel.org Cc: huyue2@coolpad.com, jefflexu@linux.alibaba.com, linux-erofs@lists.ozlabs.org, linux-kernel@vger.kernel.org On 2023/7/10 11:32, Chunhai Guo wrote: > Hi Xiang, > > On 2023/7/8 17:00, Gao Xiang wrote: >> Hi Chunhai, >> >> On 2023/7/8 14:24, Chunhai Guo wrote: >>> When z_erofs_read_folio() reads a page with an offset far beyond EOF, two >>> issues may occur: >>> - z_erofs_pcluster_readmore() may take a long time to loop when the offset >>> is big enough, which is unnecessary. >>> - For example, it will loop 4691368 times and take about 27 seconds >>> with following case. >>> - offset = 19217289215 >>> - inode_size = 1442672 >>> - z_erofs_do_read_page() may loop infinitely due to the inappropriate >>> truncation in the below statement. Since the offset is 64 bits and >>> min_t() truncates the result to 32 bits. The solution is to replace >>> unsigned int with another 64-bit type, such as erofs_off_t. >>> cur = end - min_t(unsigned int, offset + end - map->m_la, end); >>> - For example: >>> - offset = 0x400160000 >>> - end = 0x370 >>> - map->m_la = 0x160370 >>> - offset + end - map->m_la = 0x400000000 >>> - offset + end - map->m_la = 0x00000000 (truncated as unsigned int) >> >> Thanks for the catch! >> >> Could you split these two into two patches? >> >> how about using: >> cur = end - min_t(erofs_off_t, offend + end - map->m_la, end) >> for this? >> >> since cur and end are all [0, PAGE_SIZE - 1] for now, and >> folio_size() later. > > OK. I will split the patch. > > Sorry that I can not understand what is 'offend' refer to and what do you mean. Could you please describe it more clearly? Sorry, there is a typo here, I meant 'offset'. `cur` and `end` both are not exceed 4096 if your page_size is 4096. Does cur = end - min_t(erofs_off_t, offset + end - map->m_la, end) fix your issue? > >>> - Expected result: >>> - cur = 0 >>> - Actual result: >>> - cur = 0x370 >>> >>> Signed-off-by: Chunhai Guo <guochunhai@vivo.com> >>> --- >>> fs/erofs/zdata.c | 13 ++++++++++--- >>> 1 file changed, 10 insertions(+), 3 deletions(-) >>> >>> diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c >>> index 5f1890e309c6..6abbd4510076 100644 >>> --- a/fs/erofs/zdata.c >>> +++ b/fs/erofs/zdata.c >>> @@ -972,7 +972,8 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, >>> struct erofs_map_blocks *const map = &fe->map; >>> const loff_t offset = page_offset(page); >>> bool tight = true, exclusive; >>> - unsigned int cur, end, spiltted; >>> + erofs_off_t cur, end; >>> + unsigned int spiltted; >>> int err = 0; >>> /* register locked file pages as online pages in pack */ >>> @@ -1035,7 +1036,7 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, >>> */ >>> tight &= (fe->mode > Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE); >>> - cur = end - min_t(unsigned int, offset + end - map->m_la, end); >>> + cur = end - min_t(erofs_off_t, offset + end - map->m_la, end); >>> if (!(map->m_flags & EROFS_MAP_MAPPED)) { >>> zero_user_segment(page, cur, end); >>> goto next_part; >>> @@ -1841,7 +1842,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f, >>> } >>> cur = map->m_la + map->m_llen - 1; >>> - while (cur >= end) { >>> + while ((cur >= end) && (cur < i_size_read(inode))) { >>> pgoff_t index = cur >> PAGE_SHIFT; >>> struct page *page; >>> @@ -1876,6 +1877,12 @@ static int z_erofs_read_folio(struct file *file, struct folio *folio) >>> trace_erofs_readpage(page, false); >>> f.headoffset = (erofs_off_t)page->index << PAGE_SHIFT; >>> + /* when trying to read beyond EOF, return zero page directly */ >>> + if (f.headoffset >= i_size_read(inode)) { >>> + zero_user_segment(page, 0, PAGE_SIZE); >>> + return 0; >>> + } >> Do we really need to optimize this rare case? >> I guess the follow readmore fix is enough, thoughts? > >> Thanks, >> Gao Xiang > > Since the code is constantly being updated and someone may encounter this bug again, I think we had better fix it if possible. z_erofs_do_read_page() already covers this case so I'm not sure why we need to add another logic here. Thanks, Gao Xiang > > Thanks. > Guo Chunhai ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] erofs: fix two loop issues when read page beyond EOF 2023-07-10 3:37 ` Gao Xiang @ 2023-07-10 4:35 ` Chunhai Guo 2023-07-10 5:02 ` Gao Xiang 0 siblings, 1 reply; 7+ messages in thread From: Chunhai Guo @ 2023-07-10 4:35 UTC (permalink / raw) To: Gao Xiang, xiang@kernel.org, chao@kernel.org Cc: huyue2@coolpad.com, jefflexu@linux.alibaba.com, linux-erofs@lists.ozlabs.org, linux-kernel@vger.kernel.org On 2023/7/10 11:37, Gao Xiang wrote: > > > On 2023/7/10 11:32, Chunhai Guo wrote: >> Hi Xiang, >> >> On 2023/7/8 17:00, Gao Xiang wrote: >>> Hi Chunhai, >>> >>> On 2023/7/8 14:24, Chunhai Guo wrote: >>>> When z_erofs_read_folio() reads a page with an offset far beyond EOF, two >>>> issues may occur: >>>> - z_erofs_pcluster_readmore() may take a long time to loop when the offset >>>> is big enough, which is unnecessary. >>>> - For example, it will loop 4691368 times and take about 27 seconds >>>> with following case. >>>> - offset = 19217289215 >>>> - inode_size = 1442672 >>>> - z_erofs_do_read_page() may loop infinitely due to the inappropriate >>>> truncation in the below statement. Since the offset is 64 bits and >>>> min_t() truncates the result to 32 bits. The solution is to replace >>>> unsigned int with another 64-bit type, such as erofs_off_t. >>>> cur = end - min_t(unsigned int, offset + end - map->m_la, end); >>>> - For example: >>>> - offset = 0x400160000 >>>> - end = 0x370 >>>> - map->m_la = 0x160370 >>>> - offset + end - map->m_la = 0x400000000 >>>> - offset + end - map->m_la = 0x00000000 (truncated as unsigned int) >>> >>> Thanks for the catch! >>> >>> Could you split these two into two patches? >>> >>> how about using: >>> cur = end - min_t(erofs_off_t, offend + end - map->m_la, end) >>> for this? >>> >>> since cur and end are all [0, PAGE_SIZE - 1] for now, and >>> folio_size() later. >> >> OK. I will split the patch. >> >> Sorry that I can not understand what is 'offend' refer to and what do you mean. Could you please describe it more clearly? > > Sorry, there is a typo here, I meant 'offset'. > > `cur` and `end` both are not exceed 4096 if your page_size > is 4096. > > Does > cur = end - min_t(erofs_off_t, offset + end - map->m_la, end) > > fix your issue? Yes. I think this will fix this issue. Do you mean the below change is unncessary? >>>> - unsigned int cur, end, spiltted; >>>> + erofs_off_t cur, end; >>>> + unsigned int spiltted; > >> >>>> - Expected result: >>>> - cur = 0 >>>> - Actual result: >>>> - cur = 0x370 >>>> >>>> Signed-off-by: Chunhai Guo <guochunhai@vivo.com> >>>> --- >>>> fs/erofs/zdata.c | 13 ++++++++++--- >>>> 1 file changed, 10 insertions(+), 3 deletions(-) >>>> >>>> diff --git a/fs/erofs/zdata.c b/fs/erofs/zdata.c >>>> index 5f1890e309c6..6abbd4510076 100644 >>>> --- a/fs/erofs/zdata.c >>>> +++ b/fs/erofs/zdata.c >>>> @@ -972,7 +972,8 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, >>>> struct erofs_map_blocks *const map = &fe->map; >>>> const loff_t offset = page_offset(page); >>>> bool tight = true, exclusive; >>>> - unsigned int cur, end, spiltted; >>>> + erofs_off_t cur, end; >>>> + unsigned int spiltted; >>>> int err = 0; >>>> /* register locked file pages as online pages in pack */ >>>> @@ -1035,7 +1036,7 @@ static int z_erofs_do_read_page(struct z_erofs_decompress_frontend *fe, >>>> */ >>>> tight &= (fe->mode > Z_EROFS_PCLUSTER_FOLLOWED_NOINPLACE); >>>> - cur = end - min_t(unsigned int, offset + end - map->m_la, end); >>>> + cur = end - min_t(erofs_off_t, offset + end - map->m_la, end); >>>> if (!(map->m_flags & EROFS_MAP_MAPPED)) { >>>> zero_user_segment(page, cur, end); >>>> goto next_part; >>>> @@ -1841,7 +1842,7 @@ static void z_erofs_pcluster_readmore(struct z_erofs_decompress_frontend *f, >>>> } >>>> cur = map->m_la + map->m_llen - 1; >>>> - while (cur >= end) { >>>> + while ((cur >= end) && (cur < i_size_read(inode))) { >>>> pgoff_t index = cur >> PAGE_SHIFT; >>>> struct page *page; >>>> @@ -1876,6 +1877,12 @@ static int z_erofs_read_folio(struct file *file, struct folio *folio) >>>> trace_erofs_readpage(page, false); >>>> f.headoffset = (erofs_off_t)page->index << PAGE_SHIFT; >>>> + /* when trying to read beyond EOF, return zero page directly */ >>>> + if (f.headoffset >= i_size_read(inode)) { >>>> + zero_user_segment(page, 0, PAGE_SIZE); >>>> + return 0; >>>> + } >>> Do we really need to optimize this rare case? >>> I guess the follow readmore fix is enough, thoughts? > >>> Thanks, >>> Gao Xiang >> >> Since the code is constantly being updated and someone may encounter this bug again, I think we had better fix it if possible. > > z_erofs_do_read_page() already covers this case so I'm > not sure why we need to add another logic here. You are right. I have removed this logic and sent the patch. > > Thanks, > Gao Xiang > >> >> Thanks. >> Guo Chunhai ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] erofs: fix two loop issues when read page beyond EOF 2023-07-10 4:35 ` Chunhai Guo @ 2023-07-10 5:02 ` Gao Xiang 2023-07-10 9:37 ` Chunhai Guo 0 siblings, 1 reply; 7+ messages in thread From: Gao Xiang @ 2023-07-10 5:02 UTC (permalink / raw) To: Chunhai Guo, xiang@kernel.org, chao@kernel.org Cc: huyue2@coolpad.com, jefflexu@linux.alibaba.com, linux-erofs@lists.ozlabs.org, linux-kernel@vger.kernel.org On 2023/7/10 12:35, Chunhai Guo wrote: > > > On 2023/7/10 11:37, Gao Xiang wrote: >> >> >> On 2023/7/10 11:32, Chunhai Guo wrote: >>> Hi Xiang, >>> >>> On 2023/7/8 17:00, Gao Xiang wrote: >>>> Hi Chunhai, >>>> >>>> On 2023/7/8 14:24, Chunhai Guo wrote: >>>>> When z_erofs_read_folio() reads a page with an offset far beyond EOF, two >>>>> issues may occur: >>>>> - z_erofs_pcluster_readmore() may take a long time to loop when the offset >>>>> is big enough, which is unnecessary. >>>>> - For example, it will loop 4691368 times and take about 27 seconds >>>>> with following case. >>>>> - offset = 19217289215 >>>>> - inode_size = 1442672 >>>>> - z_erofs_do_read_page() may loop infinitely due to the inappropriate >>>>> truncation in the below statement. Since the offset is 64 bits and >>>>> min_t() truncates the result to 32 bits. The solution is to replace >>>>> unsigned int with another 64-bit type, such as erofs_off_t. >>>>> cur = end - min_t(unsigned int, offset + end - map->m_la, end); >>>>> - For example: >>>>> - offset = 0x400160000 >>>>> - end = 0x370 >>>>> - map->m_la = 0x160370 >>>>> - offset + end - map->m_la = 0x400000000 >>>>> - offset + end - map->m_la = 0x00000000 (truncated as unsigned int) >>>> >>>> Thanks for the catch! >>>> >>>> Could you split these two into two patches? >>>> >>>> how about using: >>>> cur = end - min_t(erofs_off_t, offend + end - map->m_la, end) >>>> for this? >>>> >>>> since cur and end are all [0, PAGE_SIZE - 1] for now, and >>>> folio_size() later. >>> >>> OK. I will split the patch. >>> >>> Sorry that I can not understand what is 'offend' refer to and what do you mean. Could you please describe it more clearly? >> >> Sorry, there is a typo here, I meant 'offset'. >> >> `cur` and `end` both are not exceed 4096 if your page_size >> is 4096. >> >> Does >> cur = end - min_t(erofs_off_t, offset + end - map->m_la, end) >> >> fix your issue? > > Yes. I think this will fix this issue. Do you mean the below change is unncessary? > >>>> - unsigned int cur, end, spiltted; > >>>> + erofs_off_t cur, end; > >>>> + unsigned int spiltted; Yes, please help send a fix for this! Thanks, Gao Xiang ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH] erofs: fix two loop issues when read page beyond EOF 2023-07-10 5:02 ` Gao Xiang @ 2023-07-10 9:37 ` Chunhai Guo 0 siblings, 0 replies; 7+ messages in thread From: Chunhai Guo @ 2023-07-10 9:37 UTC (permalink / raw) To: Gao Xiang, xiang@kernel.org, chao@kernel.org Cc: huyue2@coolpad.com, jefflexu@linux.alibaba.com, linux-erofs@lists.ozlabs.org, linux-kernel@vger.kernel.org On 2023/7/10 13:02, Gao Xiang wrote: > > > On 2023/7/10 12:35, Chunhai Guo wrote: >> >> >> On 2023/7/10 11:37, Gao Xiang wrote: >>> >>> >>> On 2023/7/10 11:32, Chunhai Guo wrote: >>>> Hi Xiang, >>>> >>>> On 2023/7/8 17:00, Gao Xiang wrote: >>>>> Hi Chunhai, >>>>> >>>>> On 2023/7/8 14:24, Chunhai Guo wrote: >>>>>> When z_erofs_read_folio() reads a page with an offset far beyond EOF, two >>>>>> issues may occur: >>>>>> - z_erofs_pcluster_readmore() may take a long time to loop when the offset >>>>>> is big enough, which is unnecessary. >>>>>> - For example, it will loop 4691368 times and take about 27 seconds >>>>>> with following case. >>>>>> - offset = 19217289215 >>>>>> - inode_size = 1442672 >>>>>> - z_erofs_do_read_page() may loop infinitely due to the inappropriate >>>>>> truncation in the below statement. Since the offset is 64 bits and >>>>>> min_t() truncates the result to 32 bits. The solution is to replace >>>>>> unsigned int with another 64-bit type, such as erofs_off_t. >>>>>> cur = end - min_t(unsigned int, offset + end - map->m_la, end); >>>>>> - For example: >>>>>> - offset = 0x400160000 >>>>>> - end = 0x370 >>>>>> - map->m_la = 0x160370 >>>>>> - offset + end - map->m_la = 0x400000000 >>>>>> - offset + end - map->m_la = 0x00000000 (truncated as unsigned int) >>>>> >>>>> Thanks for the catch! >>>>> >>>>> Could you split these two into two patches? >>>>> >>>>> how about using: >>>>> cur = end - min_t(erofs_off_t, offend + end - map->m_la, end) >>>>> for this? >>>>> >>>>> since cur and end are all [0, PAGE_SIZE - 1] for now, and >>>>> folio_size() later. >>>> >>>> OK. I will split the patch. >>>> >>>> Sorry that I can not understand what is 'offend' refer to and what do you mean. Could you please describe it more clearly? >>> >>> Sorry, there is a typo here, I meant 'offset'. >>> >>> `cur` and `end` both are not exceed 4096 if your page_size >>> is 4096. >>> >>> Does >>> cur = end - min_t(erofs_off_t, offset + end - map->m_la, end) >>> >>> fix your issue? >> >> Yes. I think this will fix this issue. Do you mean the below change is unncessary? >> >>>> - unsigned int cur, end, spiltted; >> >>>> + erofs_off_t cur, end; >> >>>> + unsigned int spiltted; > > Yes, please help send a fix for this! > > Thanks, > Gao Xiang > Got it. I have sent the patch. Please have a check. Thanks, Guo Chunhai ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2023-07-10 9:41 UTC | newest] Thread overview: 7+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-07-08 6:24 [PATCH] erofs: fix two loop issues when read page beyond EOF Chunhai Guo 2023-07-08 9:00 ` Gao Xiang 2023-07-10 3:32 ` Chunhai Guo 2023-07-10 3:37 ` Gao Xiang 2023-07-10 4:35 ` Chunhai Guo 2023-07-10 5:02 ` Gao Xiang 2023-07-10 9:37 ` Chunhai Guo
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox