Skip to content

Commit 5370b11

Browse files
jdamato-fslyopsiff
authored andcommitted
eventpoll: Add epoll ioctl for epoll_params
mainline inclusion from mainline-v6.9-rc1 category: feature Add an ioctl for getting and setting epoll_params. User programs can use this ioctl to get and set the busy poll usec time, packet budget, and prefer busy poll params for a specific epoll context. Parameters are limited: - busy_poll_usecs is limited to <= s32_max - busy_poll_budget is limited to <= NAPI_POLL_WEIGHT by unprivileged users (!capable(CAP_NET_ADMIN)) - prefer_busy_poll must be 0 or 1 - __pad must be 0 Signed-off-by: Joe Damato <jdamato@fastly.com> Acked-by: Stanislav Fomichev <sdf@google.com> Reviewed-by: Jiri Slaby <jirislaby@kernel.org> Reviewed-by: Eric Dumazet <edumazet@google.com> Signed-off-by: David S. Miller <davem@davemloft.net> (cherry picked from commit 18e2bf0) Signed-off-by: Wentao Guan <guanwentao@uniontech.com>
1 parent a14cd83 commit 5370b11

3 files changed

Lines changed: 87 additions & 0 deletions

File tree

Documentation/userspace-api/ioctl/ioctl-number.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,7 @@ Code Seq# Include File Comments
310310
0x89 0B-DF linux/sockios.h
311311
0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range
312312
0x89 F0-FF linux/sockios.h SIOCDEVPRIVATE range
313+
0x8A 00-1F linux/eventpoll.h
313314
0x8B all linux/wireless.h
314315
0x8C 00-3F WiNRADiO driver
315316
<http://www.winradio.com.au/>

fs/eventpoll.c

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <linux/seq_file.h>
3838
#include <linux/compat.h>
3939
#include <linux/rculist.h>
40+
#include <linux/capability.h>
4041
#include <net/busy_poll.h>
4142

4243
/*
@@ -456,6 +457,49 @@ static inline void ep_set_busy_poll_napi_id(struct epitem *epi)
456457
ep->napi_id = napi_id;
457458
}
458459

460+
static long ep_eventpoll_bp_ioctl(struct file *file, unsigned int cmd,
461+
unsigned long arg)
462+
{
463+
struct eventpoll *ep = file->private_data;
464+
void __user *uarg = (void __user *)arg;
465+
struct epoll_params epoll_params;
466+
467+
switch (cmd) {
468+
case EPIOCSPARAMS:
469+
if (copy_from_user(&epoll_params, uarg, sizeof(epoll_params)))
470+
return -EFAULT;
471+
472+
/* pad byte must be zero */
473+
if (epoll_params.__pad)
474+
return -EINVAL;
475+
476+
if (epoll_params.busy_poll_usecs > S32_MAX)
477+
return -EINVAL;
478+
479+
if (epoll_params.prefer_busy_poll > 1)
480+
return -EINVAL;
481+
482+
if (epoll_params.busy_poll_budget > NAPI_POLL_WEIGHT &&
483+
!capable(CAP_NET_ADMIN))
484+
return -EPERM;
485+
486+
WRITE_ONCE(ep->busy_poll_usecs, epoll_params.busy_poll_usecs);
487+
WRITE_ONCE(ep->busy_poll_budget, epoll_params.busy_poll_budget);
488+
WRITE_ONCE(ep->prefer_busy_poll, epoll_params.prefer_busy_poll);
489+
return 0;
490+
case EPIOCGPARAMS:
491+
memset(&epoll_params, 0, sizeof(epoll_params));
492+
epoll_params.busy_poll_usecs = READ_ONCE(ep->busy_poll_usecs);
493+
epoll_params.busy_poll_budget = READ_ONCE(ep->busy_poll_budget);
494+
epoll_params.prefer_busy_poll = READ_ONCE(ep->prefer_busy_poll);
495+
if (copy_to_user(uarg, &epoll_params, sizeof(epoll_params)))
496+
return -EFAULT;
497+
return 0;
498+
default:
499+
return -ENOIOCTLCMD;
500+
}
501+
}
502+
459503
#else
460504

461505
static inline bool ep_busy_loop(struct eventpoll *ep, int nonblock)
@@ -467,6 +511,12 @@ static inline void ep_set_busy_poll_napi_id(struct epitem *epi)
467511
{
468512
}
469513

514+
static long ep_eventpoll_bp_ioctl(struct file *file, unsigned int cmd,
515+
unsigned long arg)
516+
{
517+
return -EOPNOTSUPP;
518+
}
519+
470520
#endif /* CONFIG_NET_RX_BUSY_POLL */
471521

472522
/*
@@ -827,6 +877,27 @@ static void ep_clear_and_put(struct eventpoll *ep)
827877
ep_free(ep);
828878
}
829879

880+
static long ep_eventpoll_ioctl(struct file *file, unsigned int cmd,
881+
unsigned long arg)
882+
{
883+
int ret;
884+
885+
if (!is_file_epoll(file))
886+
return -EINVAL;
887+
888+
switch (cmd) {
889+
case EPIOCSPARAMS:
890+
case EPIOCGPARAMS:
891+
ret = ep_eventpoll_bp_ioctl(file, cmd, arg);
892+
break;
893+
default:
894+
ret = -EINVAL;
895+
break;
896+
}
897+
898+
return ret;
899+
}
900+
830901
static int ep_eventpoll_release(struct inode *inode, struct file *file)
831902
{
832903
struct eventpoll *ep = file->private_data;
@@ -969,6 +1040,8 @@ static const struct file_operations eventpoll_fops = {
9691040
.release = ep_eventpoll_release,
9701041
.poll = ep_eventpoll_poll,
9711042
.llseek = noop_llseek,
1043+
.unlocked_ioctl = ep_eventpoll_ioctl,
1044+
.compat_ioctl = compat_ptr_ioctl,
9721045
};
9731046

9741047
/*

include/uapi/linux/eventpoll.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,4 +85,17 @@ struct epoll_event {
8585
__u64 data;
8686
} EPOLL_PACKED;
8787

88+
struct epoll_params {
89+
__u32 busy_poll_usecs;
90+
__u16 busy_poll_budget;
91+
__u8 prefer_busy_poll;
92+
93+
/* pad the struct to a multiple of 64bits */
94+
__u8 __pad;
95+
};
96+
97+
#define EPOLL_IOC_TYPE 0x8A
98+
#define EPIOCSPARAMS _IOW(EPOLL_IOC_TYPE, 0x01, struct epoll_params)
99+
#define EPIOCGPARAMS _IOR(EPOLL_IOC_TYPE, 0x02, struct epoll_params)
100+
88101
#endif /* _UAPI_LINUX_EVENTPOLL_H */

0 commit comments

Comments
 (0)