• Bug#1105129: Please backport ntsync driver from Linux-6.14 to trixie (8

    From Piotr Morgwai Kotarbinski@1:229/2 to All on Sun May 11 22:50:01 2025
    [continued from previous message]

    +static int read_mutex_state(int mutex, __u32 *count, __u32 *owner)
    +{
    + struct ntsync_mutex_args args;
    + int ret;
    +
    + memset(&args, 0xcc, sizeof(args));
    + ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &args);
    + *count = args.count;
    + *owner = args.owner;
    + return ret;
    +}
    +
    +#define check_mutex_state(mutex, count, owner) \
    + ({ \
    + __u32 __count, __owner; \
    + int ret = read_mutex_state((mutex), &__count, &__owner); \
    + EXPECT_EQ(0, ret); \
    + EXPECT_EQ((count), __count); \
    + EXPECT_EQ((owner), __owner); \
    + })
    +
    +static int unlock_mutex(int mutex, __u32 owner, __u32 *count)
    +{
    + struct ntsync_mutex_args args;
    + int ret;
    +
    + args.owner = owner;
    + args.count = 0xdeadbeef;
    + ret = ioctl(mutex, NTSYNC_IOC_MUTEX_UNLOCK, &args);
    + *count = args.count;
    + return ret;
    +}
    +
    +static int read_event_state(int event, __u32 *signaled, __u32 *manual)
    +{
    + struct ntsync_event_args args;
    + int ret;
    +
    + memset(&args, 0xcc, sizeof(args));
    + ret = ioctl(event, NTSYNC_IOC_EVENT_READ, &args);
    + *signaled = args.signaled;
    + *manual = args.manual;
    + return ret;
    +}
    +
    +#define check_event_state(event, signaled, manual) \
    + ({ \
    + __u32 __signaled, __manual; \
    + int ret = read_event_state((event), &__signaled, &__manual); \ + EXPECT_EQ(0, ret); \
    + EXPECT_EQ((signaled), __signaled); \
    + EXPECT_EQ((manual), __manual); \
    + })
    +
    +static int wait_objs(int fd, unsigned long request, __u32 count,
    + const int *objs, __u32 owner, int alert, __u32 *index)
    +{
    + struct ntsync_wait_args args = {0};
    + struct timespec timeout;
    + int ret;
    +
    + clock_gettime(CLOCK_MONOTONIC, &timeout);
    +
    + args.timeout = timeout.tv_sec * 1000000000 + timeout.tv_nsec;
    + args.count = count;
    + args.objs = (uintptr_t)objs;
    + args.owner = owner;
    + args.index = 0xdeadbeef;
    + args.alert = alert;
    + ret = ioctl(fd, request, &args);
    + *index = args.index;
    + return ret;
    +}
    +
    +static int wait_any(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)
    +{
    + return wait_objs(fd, NTSYNC_IOC_WAIT_ANY, count, objs, owner, 0, index);
    +}
    +
    +static int wait_all(int fd, __u32 count, const int *objs, __u32 owner, __u32 *index)
    +{
    + return wait_objs(fd, NTSYNC_IOC_WAIT_ALL, count, objs, owner, 0, index);
    +}
    +
    +static int wait_any_alert(int fd, __u32 count, const int *objs,
    + __u32 owner, int alert, __u32 *index)
    +{
    + return wait_objs(fd, NTSYNC_IOC_WAIT_ANY,
    + count, objs, owner, alert, index);
    +}
    +
    +static int wait_all_alert(int fd, __u32 count, const int *objs,
    + __u32 owner, int alert, __u32 *index)
    +{
    + return wait_objs(fd, NTSYNC_IOC_WAIT_ALL,
    + count, objs, owner, alert, index);
    +}
    +
    +TEST(semaphore_state)
    +{
    + struct ntsync_sem_args sem_args;
    + struct timespec timeout;
    + __u32 count, index;
    + int fd, ret, sem;
    +
    + clock_gettime(CLOCK_MONOTONIC, &timeout);
    +
    + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
    + ASSERT_LE(0, fd);
    +
    + sem_args.count = 3;
    + sem_args.max = 2;
    + sem = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
    + EXPECT_EQ(-1, sem);
    + EXPECT_EQ(EINVAL, errno);
    +
    + sem_args.count = 2;
    + sem_args.max = 2;
    + sem = ioctl(fd, NTSYNC_IOC_CREATE_SEM, &sem_args);
    + EXPECT_LE(0, sem);
    + check_sem_state(sem, 2, 2);
    +
    + count = 0;
    + ret = release_sem(sem, &count);
    + EXPECT_EQ(0, ret);
    + EXPECT_EQ(2, count);
    + check_sem_state(sem, 2, 2);
    +
    + count = 1;
    + ret = release_sem(sem, &count);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EOVERFLOW, errno);
    + check_sem_state(sem, 2, 2);
    +
    + ret = wait_any(fd, 1, &sem, 123, &index);
    + EXPECT_EQ(0, ret);
    + EXPECT_EQ(0, index);
    + check_sem_state(sem, 1, 2);
    +
    + ret = wait_any(fd, 1, &sem, 123, &index);
    + EXPECT_EQ(0, ret);
    + EXPECT_EQ(0, index);
    + check_sem_state(sem, 0, 2);
    +
    + ret = wait_any(fd, 1, &sem, 123, &index);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(ETIMEDOUT, errno);
    +
    + count = 3;
    + ret = release_sem(sem, &count);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EOVERFLOW, errno);
    + check_sem_state(sem, 0, 2);
    +
    + count = 2;
    + ret = release_sem(sem, &count);
    + EXPECT_EQ(0, ret);
    + EXPECT_EQ(0, count);
    + check_sem_state(sem, 2, 2);
    +
    + ret = wait_any(fd, 1, &sem, 123, &index);
    + EXPECT_EQ(0, ret);
    + ret = wait_any(fd, 1, &sem, 123, &index);
    + EXPECT_EQ(0, ret);
    +
    + count = 1;
    + ret = release_sem(sem, &count);
    + EXPECT_EQ(0, ret);
    + EXPECT_EQ(0, count);
    + check_sem_state(sem, 1, 2);
    +
    + count = ~0u;
    + ret = release_sem(sem, &count);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EOVERFLOW, errno);
    + check_sem_state(sem, 1, 2);
    +
    + close(sem);
    +
    + close(fd);
    +}
    +
    +TEST(mutex_state)
    +{
    + struct ntsync_mutex_args mutex_args;
    + __u32 owner, count, index;
    + struct timespec timeout;
    + int fd, ret, mutex;
    +
    + clock_gettime(CLOCK_MONOTONIC, &timeout);
    +
    + fd = open("/dev/ntsync", O_CLOEXEC | O_RDONLY);
    + ASSERT_LE(0, fd);
    +
    + mutex_args.owner = 123;
    + mutex_args.count = 0;
    + mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
    + EXPECT_EQ(-1, mutex);
    + EXPECT_EQ(EINVAL, errno);
    +
    + mutex_args.owner = 0;
    + mutex_args.count = 2;
    + mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
    + EXPECT_EQ(-1, mutex);
    + EXPECT_EQ(EINVAL, errno);
    +
    + mutex_args.owner = 123;
    + mutex_args.count = 2;
    + mutex = ioctl(fd, NTSYNC_IOC_CREATE_MUTEX, &mutex_args);
    + EXPECT_LE(0, mutex);
    + check_mutex_state(mutex, 2, 123);
    +
    + ret = unlock_mutex(mutex, 0, &count);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EINVAL, errno);
    +
    + ret = unlock_mutex(mutex, 456, &count);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EPERM, errno);
    + check_mutex_state(mutex, 2, 123);
    +
    + ret = unlock_mutex(mutex, 123, &count);
    + EXPECT_EQ(0, ret);
    + EXPECT_EQ(2, count);
    + check_mutex_state(mutex, 1, 123);
    +
    + ret = unlock_mutex(mutex, 123, &count);
    + EXPECT_EQ(0, ret);
    + EXPECT_EQ(1, count);
    + check_mutex_state(mutex, 0, 0);
    +
    + ret = unlock_mutex(mutex, 123, &count);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EPERM, errno);
    +
    + ret = wait_any(fd, 1, &mutex, 456, &index);
    + EXPECT_EQ(0, ret);
    + EXPECT_EQ(0, index);
    + check_mutex_state(mutex, 1, 456);
    +
    + ret = wait_any(fd, 1, &mutex, 456, &index);
    + EXPECT_EQ(0, ret);
    + EXPECT_EQ(0, index);
    + check_mutex_state(mutex, 2, 456);
    +
    + ret = unlock_mutex(mutex, 456, &count);
    + EXPECT_EQ(0, ret);
    + EXPECT_EQ(2, count);
    + check_mutex_state(mutex, 1, 456);
    +
    + ret = wait_any(fd, 1, &mutex, 123, &index);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(ETIMEDOUT, errno);
    +
    + owner = 0;
    + ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EINVAL, errno);
    +
    + owner = 123;
    + ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EPERM, errno);
    + check_mutex_state(mutex, 1, 456);
    +
    + owner = 456;
    + ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);
    + EXPECT_EQ(0, ret);
    +
    + memset(&mutex_args, 0xcc, sizeof(mutex_args));
    + ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EOWNERDEAD, errno);
    + EXPECT_EQ(0, mutex_args.count);
    + EXPECT_EQ(0, mutex_args.owner);
    +
    + memset(&mutex_args, 0xcc, sizeof(mutex_args));
    + ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EOWNERDEAD, errno);
    + EXPECT_EQ(0, mutex_args.count);
    + EXPECT_EQ(0, mutex_args.owner);
    +
    + ret = wait_any(fd, 1, &mutex, 123, &index);
    + EXPECT_EQ(-1, ret);
    + EXPECT_EQ(EOWNERDEAD, errno);
    + EXPECT_EQ(0, index);
    + check_mutex_state(mutex, 1, 123);
    +
    + owner = 123;
    + ret = ioctl(mutex, NTSYNC_IOC_MUTEX_KILL, &owner);
    + EXPECT_EQ(0, ret);
    +
    + memset(&mutex_args, 0xcc, sizeof(mutex_args));
    + ret = ioctl(mutex, NTSYNC_IOC_MUTEX_READ, &mutex_args);
    + EXPECT_EQ(-1, ret);

    [continued in next message]

    --- SoupGate-Win32 v1.05
    * Origin: you cannot sedate... all the things you hate (1:229/2)