On Wed, Jun 1, 2022 at 9:08 AM Phillip Lougher <phillip@xxxxxxxxxxxxxxx> wrote: > > On 31/05/2022 21:47, Andrew Morton wrote: > > On Mon, 23 May 2022 14:59:13 +0800 Hsin-Yi Wang <hsinyi@xxxxxxxxxxxx> wrote: > > > >> Implement readahead callback for squashfs. It will read datablocks > >> which cover pages in readahead request. For a few cases it will > >> not mark page as uptodate, including: > >> - file end is 0. > >> - zero filled blocks. > >> - current batch of pages isn't in the same datablock or not enough in a > >> datablock. > >> - decompressor error. > >> Otherwise pages will be marked as uptodate. The unhandled pages will be > >> updated by readpage later. > >> > >> ... > >> > > > > The choice of types seems somewhat confused. > > > >> @@ -495,7 +496,95 @@ static int squashfs_read_folio(struct file *file, struct folio *folio) > >> return 0; > >> } > >> > >> +static void squashfs_readahead(struct readahead_control *ractl) > >> +{ > >> + struct inode *inode = ractl->mapping->host; > >> + struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info; > >> + size_t mask = (1UL << msblk->block_log) - 1; > >> + size_t shift = msblk->block_log - PAGE_SHIFT; > > > > block_log is unsigned short. Why size_t? Will update in the next version. > > > >> + loff_t start = readahead_pos(ractl) &~ mask; > >> + size_t len = readahead_length(ractl) + readahead_pos(ractl) - start; > >> + struct squashfs_page_actor *actor; > >> + unsigned int nr_pages = 0; > > > > OK. > > > >> + struct page **pages; > >> + u64 block = 0; > >> + int bsize, res, i, index, bytes, expected; > > > > `res' could be local to the inner loop. > > > > `i' is used in situations where an unsigned type would be more > > appropriate. If it is made unsigned then `i' is no longer a suitable > > identifier. Doesn't matter much. > > > > `index' is from page.index, which is pgoff_t. > > > > `bytes' could be local to the innermost loop. > > > > `expected' is inappropriately a signed type and could be local to the > > inner loop. Will update them in the next version. > > > >> + int file_end = i_size_read(inode) >> msblk->block_log; > >> + unsigned int max_pages = 1UL << shift; > >> + void *pageaddr; > >> + > > pageaddr could be made local to the innermost scope. > Will update them in the next version. Thanks for your comments. > Apart from that the patch and updated error handling looks > good. > > Phillip > > >> + readahead_expand(ractl, start, (len | mask) + 1); > >> + > >> + if (file_end == 0) > >> + return; > >> + > >> + pages = kmalloc_array(max_pages, sizeof(void *), GFP_KERNEL); > >> + if (!pages) > >> + return; > >> + > >> + actor = squashfs_page_actor_init_special(pages, max_pages, 0); > >> + if (!actor) > >> + goto out; > >> + > >> + for (;;) { > >> + nr_pages = __readahead_batch(ractl, pages, max_pages); > >> + if (!nr_pages) > >> + break; > >> + > >> + if (readahead_pos(ractl) >= i_size_read(inode) || > >> + nr_pages < max_pages) > >> + goto skip_pages; > >> + > >> + index = pages[0]->index >> shift; > >> + if ((pages[nr_pages - 1]->index >> shift) != index) > >> + goto skip_pages; > >> + > >> + expected = index == file_end ? > >> + (i_size_read(inode) & (msblk->block_size - 1)) : > >> + msblk->block_size; > >> + > >> + bsize = read_blocklist(inode, index, &block); > >> + if (bsize == 0) > >> + goto skip_pages; > >> + > >> + res = squashfs_read_data(inode->i_sb, block, bsize, NULL, > >> + actor); > >> + > >> + if (res == expected) { > >> + /* Last page may have trailing bytes not filled */ > >> + bytes = res % PAGE_SIZE; > >> + if (bytes) { > >> + pageaddr = kmap_atomic(pages[nr_pages - 1]); > >> + memset(pageaddr + bytes, 0, PAGE_SIZE - bytes); > >> + kunmap_atomic(pageaddr); > >> + } > >> + > >> + for (i = 0; i < nr_pages; i++) > >> + SetPageUptodate(pages[i]); > >> + } > > > > res == -EIO is unhandled? > > > >> + for (i = 0; i < nr_pages; i++) { > >> + unlock_page(pages[i]); > >> + put_page(pages[i]); > >> + } > >> + } > >> + > >> + kfree(actor); > >> + kfree(pages); > >> + return; > >> + > >> +skip_pages: > >> + for (i = 0; i < nr_pages; i++) { > >> + unlock_page(pages[i]); > >> + put_page(pages[i]); > >> + } > >> + > >> + kfree(actor); > >> +out: > >> + kfree(pages); > >> +} > >> > >> const struct address_space_operations squashfs_aops = { > >> - .read_folio = squashfs_read_folio > >> + .read_folio = squashfs_read_folio, > >> + .readahead = squashfs_readahead > >> }; > > >