On 03/06/2024 10:18, Hannes Reinecke wrote: > On 5/30/24 15:26, Ofir Gal wrote: >> Network drivers are using sendpage_ok() to check the first page of an >> iterator in order to disable MSG_SPLICE_PAGES. The iterator can >> represent list of contiguous pages. >> >> When MSG_SPLICE_PAGES is enabled skb_splice_from_iter() is being used, >> it requires all pages in the iterator to be sendable. Therefore it needs >> to check that each page is sendable. >> >> The patch introduces a helper sendpages_ok(), it returns true if all the >> contiguous pages are sendable. >> >> Drivers who want to send contiguous pages with MSG_SPLICE_PAGES may use >> this helper to check whether the page list is OK. If the helper does not >> return true, the driver should remove MSG_SPLICE_PAGES flag. >> >> Signed-off-by: Ofir Gal <ofir.gal@xxxxxxxxxxx> >> --- >> include/linux/net.h | 20 ++++++++++++++++++++ >> 1 file changed, 20 insertions(+) >> >> diff --git a/include/linux/net.h b/include/linux/net.h >> index 688320b79fcc..b33bdc3e2031 100644 >> --- a/include/linux/net.h >> +++ b/include/linux/net.h >> @@ -322,6 +322,26 @@ static inline bool sendpage_ok(struct page *page) >> return !PageSlab(page) && page_count(page) >= 1; >> } >> +/* >> + * Check sendpage_ok on contiguous pages. >> + */ >> +static inline bool sendpages_ok(struct page *page, size_t len, size_t offset) >> +{ >> + unsigned int pagecount; >> + size_t page_offset; >> + int k; >> + >> + page = page + offset / PAGE_SIZE; >> + page_offset = offset % PAGE_SIZE; >> + pagecount = DIV_ROUND_UP(len + page_offset, PAGE_SIZE); >> + > Don't we miss the first page for offset > PAGE_SIZE? > I'd rather check for all pages from 'page' up to (offset + len), just > to be on the safe side. We do, I copied the logic from iov_iter_extract_bvec_pages() to be aligned with how skb_splice_from_iter() splits the pages. I don't think we need to check a page we won't send, but I don't mind to be on the safeside. >> + for (k = 0; k < pagecount; k++) >> + if (!sendpage_ok(page + k)) >> + return false; >> + >> + return true; >> +} >> + >> int kernel_sendmsg(struct socket *sock, struct msghdr *msg, struct kvec *vec, >> size_t num, size_t len); >> int kernel_sendmsg_locked(struct sock *sk, struct msghdr *msg, > > Cheers, > > Hannes