Skip to content

Commit 18e2bf0

Browse files
jdamato-fslydavem330
authored andcommitted
eventpoll: Add epoll ioctl for epoll_params
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 <[email protected]> Acked-by: Stanislav Fomichev <[email protected]> Reviewed-by: Jiri Slaby <[email protected]> Reviewed-by: Eric Dumazet <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent de57a25 commit 18e2bf0

File tree

3 files changed

+87
-0
lines changed

3 files changed

+87
-0
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ Code Seq# Include File Comments
309309
0x89 0B-DF linux/sockios.h
310310
0x89 E0-EF linux/sockios.h SIOCPROTOPRIVATE range
311311
0x89 F0-FF linux/sockios.h SIOCDEVPRIVATE range
312+
0x8A 00-1F linux/eventpoll.h
312313
0x8B all linux/wireless.h
313314
0x8C 00-3F WiNRADiO driver
314315
<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
/*
@@ -494,6 +495,49 @@ static inline void ep_set_busy_poll_napi_id(struct epitem *epi)
494495
ep->napi_id = napi_id;
495496
}
496497

498+
static long ep_eventpoll_bp_ioctl(struct file *file, unsigned int cmd,
499+
unsigned long arg)
500+
{
501+
struct eventpoll *ep = file->private_data;
502+
void __user *uarg = (void __user *)arg;
503+
struct epoll_params epoll_params;
504+
505+
switch (cmd) {
506+
case EPIOCSPARAMS:
507+
if (copy_from_user(&epoll_params, uarg, sizeof(epoll_params)))
508+
return -EFAULT;
509+
510+
/* pad byte must be zero */
511+
if (epoll_params.__pad)
512+
return -EINVAL;
513+
514+
if (epoll_params.busy_poll_usecs > S32_MAX)
515+
return -EINVAL;
516+
517+
if (epoll_params.prefer_busy_poll > 1)
518+
return -EINVAL;
519+
520+
if (epoll_params.busy_poll_budget > NAPI_POLL_WEIGHT &&
521+
!capable(CAP_NET_ADMIN))
522+
return -EPERM;
523+
524+
WRITE_ONCE(ep->busy_poll_usecs, epoll_params.busy_poll_usecs);
525+
WRITE_ONCE(ep->busy_poll_budget, epoll_params.busy_poll_budget);
526+
WRITE_ONCE(ep->prefer_busy_poll, epoll_params.prefer_busy_poll);
527+
return 0;
528+
case EPIOCGPARAMS:
529+
memset(&epoll_params, 0, sizeof(epoll_params));
530+
epoll_params.busy_poll_usecs = READ_ONCE(ep->busy_poll_usecs);
531+
epoll_params.busy_poll_budget = READ_ONCE(ep->busy_poll_budget);
532+
epoll_params.prefer_busy_poll = READ_ONCE(ep->prefer_busy_poll);
533+
if (copy_to_user(uarg, &epoll_params, sizeof(epoll_params)))
534+
return -EFAULT;
535+
return 0;
536+
default:
537+
return -ENOIOCTLCMD;
538+
}
539+
}
540+
497541
#else
498542

499543
static inline bool ep_busy_loop(struct eventpoll *ep, int nonblock)
@@ -505,6 +549,12 @@ static inline void ep_set_busy_poll_napi_id(struct epitem *epi)
505549
{
506550
}
507551

552+
static long ep_eventpoll_bp_ioctl(struct file *file, unsigned int cmd,
553+
unsigned long arg)
554+
{
555+
return -EOPNOTSUPP;
556+
}
557+
508558
#endif /* CONFIG_NET_RX_BUSY_POLL */
509559

510560
/*
@@ -864,6 +914,27 @@ static void ep_clear_and_put(struct eventpoll *ep)
864914
ep_free(ep);
865915
}
866916

917+
static long ep_eventpoll_ioctl(struct file *file, unsigned int cmd,
918+
unsigned long arg)
919+
{
920+
int ret;
921+
922+
if (!is_file_epoll(file))
923+
return -EINVAL;
924+
925+
switch (cmd) {
926+
case EPIOCSPARAMS:
927+
case EPIOCGPARAMS:
928+
ret = ep_eventpoll_bp_ioctl(file, cmd, arg);
929+
break;
930+
default:
931+
ret = -EINVAL;
932+
break;
933+
}
934+
935+
return ret;
936+
}
937+
867938
static int ep_eventpoll_release(struct inode *inode, struct file *file)
868939
{
869940
struct eventpoll *ep = file->private_data;
@@ -970,6 +1041,8 @@ static const struct file_operations eventpoll_fops = {
9701041
.release = ep_eventpoll_release,
9711042
.poll = ep_eventpoll_poll,
9721043
.llseek = noop_llseek,
1044+
.unlocked_ioctl = ep_eventpoll_ioctl,
1045+
.compat_ioctl = compat_ptr_ioctl,
9731046
};
9741047

9751048
/*

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)