On 11/05/2024 02:21, Mina Almasry wrote:
Add an interface for the user to notify the kernel that it is done reading the devmem dmabuf frags returned as cmsg. The kernel will drop the reference on the frags to make them available for reuse.
Signed-off-by: Willem de Bruijn willemb@google.com Signed-off-by: Kaiyuan Zhang kaiyuanz@google.com Signed-off-by: Mina Almasry almasrymina@google.com
v7:
- Updated SO_DEVMEM_* uapi to use the next available entry (Arnd).
v6:
- Squash in locking optimizations from edumazet@google.com. With his changes we lock the xarray once per sock_devmem_dontneed operation rather than once per frag.
Changes in v1:
- devmemtoken -> dmabuf_token (David).
- Use napi_pp_put_page() for refcounting (Yunsheng).
- Fix build error with missing socket options on other asms.
arch/alpha/include/uapi/asm/socket.h | 1 + arch/mips/include/uapi/asm/socket.h | 1 + arch/parisc/include/uapi/asm/socket.h | 1 + arch/sparc/include/uapi/asm/socket.h | 1 + include/uapi/asm-generic/socket.h | 1 + include/uapi/linux/uio.h | 4 ++ net/core/sock.c | 61 +++++++++++++++++++++++++++ 7 files changed, 70 insertions(+)
[snip]
diff --git a/net/core/sock.c b/net/core/sock.c index 8d6e638b5426d..2edb988259e8d 100644 --- a/net/core/sock.c +++ b/net/core/sock.c @@ -124,6 +124,7 @@ #include <linux/netdevice.h> #include <net/protocol.h> #include <linux/skbuff.h> +#include <linux/skbuff_ref.h> #include <net/net_namespace.h> #include <net/request_sock.h> #include <net/sock.h> @@ -1049,6 +1050,62 @@ static int sock_reserve_memory(struct sock *sk, int bytes) return 0; } +#ifdef CONFIG_PAGE_POOL +static noinline_for_stack int +sock_devmem_dontneed(struct sock *sk, sockptr_t optval, unsigned int optlen) +{
- unsigned int num_tokens, i, j, k, netmem_num = 0;
- struct dmabuf_token *tokens;
- netmem_ref netmems[16];
- int ret;
- if (sk->sk_type != SOCK_STREAM || sk->sk_protocol != IPPROTO_TCP)
return -EBADF;
- if (optlen % sizeof(struct dmabuf_token) ||
optlen > sizeof(*tokens) * 128)
return -EINVAL;
- tokens = kvmalloc_array(128, sizeof(*tokens), GFP_KERNEL);
- if (!tokens)
return -ENOMEM;
- num_tokens = optlen / sizeof(struct dmabuf_token);
- if (copy_from_sockptr(tokens, optval, optlen))
return -EFAULT;
tokens isn't freed in this error case
- ret = 0;
- xa_lock_bh(&sk->sk_user_frags);
- for (i = 0; i < num_tokens; i++) {
for (j = 0; j < tokens[i].token_count; j++) {
netmem_ref netmem = (__force netmem_ref)__xa_erase(
&sk->sk_user_frags, tokens[i].token_start + j);
if (netmem &&
!WARN_ON_ONCE(!netmem_is_net_iov(netmem))) {
netmems[netmem_num++] = netmem;
if (netmem_num == ARRAY_SIZE(netmems)) {
xa_unlock_bh(&sk->sk_user_frags);
for (k = 0; k < netmem_num; k++)
WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
netmem_num = 0;
xa_lock_bh(&sk->sk_user_frags);
}
ret++;
}
}
- }
- xa_unlock_bh(&sk->sk_user_frags);
- for (k = 0; k < netmem_num; k++)
WARN_ON_ONCE(!napi_pp_put_page(netmems[k]));
- kvfree(tokens);
- return ret;
+} +#endif
void sockopt_lock_sock(struct sock *sk) { /* When current->bpf_ctx is set, the setsockopt is called from @@ -1200,6 +1257,10 @@ int sk_setsockopt(struct sock *sk, int level, int optname, ret = -EOPNOTSUPP; return ret; } +#ifdef CONFIG_PAGE_POOL
- case SO_DEVMEM_DONTNEED:
return sock_devmem_dontneed(sk, optval, optlen);
+#endif } sockopt_lock_sock(sk);