On Fri, Nov 05, 2021 at 08:01:13AM +0800, Qu Wenruo wrote: > [snip] > > > BTW, I also thought that part can be suspicious, as it keeps the page mapped > (unlike all other call sites), thus I tried the following diff, but no > difference for the leakage: I just saw this thread and I was wondering why can't kmap_local_page() be used? I know we are trying to remove highmem from the kernel but the DAX stray write protection I've been working on depends on the kmap interface to ensure that DAX pages are properly accessed.[1] Also there are a couple of new helpers which could be used instead of the changes below. I know this does not solve the problem Linus is seeing and DAX is not yet supported on btrfs but I know there has been some effort to get it working and things like commit ... 8c945d32e604 ("btrfs: compression: drop kmap/kunmap from lzo") ... would break that support. > > diff --git a/fs/btrfs/lzo.c b/fs/btrfs/lzo.c > index 65cb0766e62d..0648acc48310 100644 > --- a/fs/btrfs/lzo.c > +++ b/fs/btrfs/lzo.c > @@ -151,6 +151,7 @@ static int copy_compressed_data_to_page(char > *compressed_data, > kaddr = kmap(cur_page); > write_compress_length(kaddr + offset_in_page(*cur_out), > compressed_size); > + kunmap(cur_page); > *cur_out += LZO_LEN; > > orig_out = *cur_out; > @@ -160,7 +161,6 @@ static int copy_compressed_data_to_page(char > *compressed_data, > u32 copy_len = min_t(u32, sectorsize - *cur_out % sectorsize, > orig_out + compressed_size - *cur_out); > > - kunmap(cur_page); > cur_page = out_pages[*cur_out / PAGE_SIZE]; > /* Allocate a new page */ > if (!cur_page) { > @@ -173,6 +173,7 @@ static int copy_compressed_data_to_page(char > *compressed_data, > > memcpy(kaddr + offset_in_page(*cur_out), > compressed_data + *cur_out - orig_out, copy_len); > + kunmap(cur_page); memcpy_to_page()? > > *cur_out += copy_len; > } > @@ -186,12 +187,15 @@ static int copy_compressed_data_to_page(char > *compressed_data, > goto out; > > /* The remaining size is not enough, pad it with zeros */ > + cur_page = out_pages[*cur_out / PAGE_SIZE]; > + ASSERT(cur_page); > + kmap(cur_page); > memset(kaddr + offset_in_page(*cur_out), 0, > sector_bytes_left); > + kunmap(cur_page); memzero_page()? Just my $0.02 given I've been trying to remove kmap() uses and btrfs remains one of the big users of kmap(). Thanks, Ira [1] https://lore.kernel.org/lkml/20210804043231.2655537-16-ira.weiny@xxxxxxxxx/ > *cur_out += sector_bytes_left; > > out: > - kunmap(cur_page); > return 0; > } > > Thanks, > Qu > > > > In particular, what if "offset_in_page(*cur_out)" is very close to the > > end of the page? > > > > That write_compress_length() always writes out a word-sized length (ie > > LZO_LEN bytes), and the above pattern seems to have no model to handle > > the "oh, this 4-byte write crosses a page boundary" > > > > The other writes in that function seem to do it properly, and you have > > > > u32 copy_len = min_t(u32, sectorsize - *cur_out % sectorsize, > > orig_out + compressed_size - *cur_out); > > > > so doing the memcpy() of size 'copy_len' should never cross a page > > boundary as long as sectorsize is a power-of-2 smaller or equal to a > > page size. But those 4-byte length writes seem like they could be page > > crossers. > > > > The same situation exists on the reading side, I think. > > > > Maybe there's some reason why the read/write_compress_length() can > > never cross a page boundary, but it did strike me as odd. > > > > Linus > > > >