mirror of
https://github.com/AuxXxilium/linux_dsm_epyc7002.git
synced 2024-11-24 15:31:14 +07:00
Merge branch 'akpm' (patches from Andrew)
Merge fourth patch-bomb from Andrew Morton: - sys_membarier syscall - seq_file interface changes - a few misc fixups * emailed patches from Andrew Morton <akpm@linux-foundation.org>: revert "ocfs2/dlm: use list_for_each_entry instead of list_for_each" mm/early_ioremap: add explicit #include of asm/early_ioremap.h fs/seq_file: convert int seq_vprint/seq_printf/etc... returns to void selftests: enhance membarrier syscall test selftests: add membarrier syscall test sys_membarrier(): system-wide memory barrier (generic, x86) MODSIGN: fix a compilation warning in extract-cert
This commit is contained in:
commit
01b0c014ee
@ -6789,6 +6789,14 @@ W: http://www.mellanox.com
|
||||
Q: http://patchwork.ozlabs.org/project/netdev/list/
|
||||
F: drivers/net/ethernet/mellanox/mlxsw/
|
||||
|
||||
MEMBARRIER SUPPORT
|
||||
M: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
||||
M: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
|
||||
L: linux-kernel@vger.kernel.org
|
||||
S: Supported
|
||||
F: kernel/membarrier.c
|
||||
F: include/uapi/linux/membarrier.h
|
||||
|
||||
MEMORY MANAGEMENT
|
||||
L: linux-mm@kvack.org
|
||||
W: http://www.linux-mm.org
|
||||
|
@ -381,3 +381,4 @@
|
||||
372 i386 recvmsg sys_recvmsg compat_sys_recvmsg
|
||||
373 i386 shutdown sys_shutdown
|
||||
374 i386 userfaultfd sys_userfaultfd
|
||||
375 i386 membarrier sys_membarrier
|
||||
|
@ -330,6 +330,7 @@
|
||||
321 common bpf sys_bpf
|
||||
322 64 execveat stub_execveat
|
||||
323 common userfaultfd sys_userfaultfd
|
||||
324 common membarrier sys_membarrier
|
||||
|
||||
#
|
||||
# x32-specific system call numbers start at 512 to avoid cache impact
|
||||
|
@ -135,8 +135,9 @@ __dump_tlb_entries(struct omap_iommu *obj, struct cr_regs *crs, int num)
|
||||
static ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr,
|
||||
struct seq_file *s)
|
||||
{
|
||||
return seq_printf(s, "%08x %08x %01x\n", cr->cam, cr->ram,
|
||||
seq_printf(s, "%08x %08x %01x\n", cr->cam, cr->ram,
|
||||
(cr->cam & MMU_CAM_P) ? 1 : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t omap_dump_tlb_entries(struct omap_iommu *obj, struct seq_file *s)
|
||||
|
@ -142,7 +142,8 @@ static int nsfs_show_path(struct seq_file *seq, struct dentry *dentry)
|
||||
struct inode *inode = d_inode(dentry);
|
||||
const struct proc_ns_operations *ns_ops = dentry->d_fsdata;
|
||||
|
||||
return seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino);
|
||||
seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct super_operations nsfs_ops = {
|
||||
|
@ -1776,7 +1776,7 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
|
||||
struct dlm_migratable_lockres *mres)
|
||||
{
|
||||
struct dlm_migratable_lock *ml;
|
||||
struct list_head *queue;
|
||||
struct list_head *queue, *iter;
|
||||
struct list_head *tmpq = NULL;
|
||||
struct dlm_lock *newlock = NULL;
|
||||
struct dlm_lockstatus *lksb = NULL;
|
||||
@ -1821,7 +1821,9 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm,
|
||||
spin_lock(&res->spinlock);
|
||||
for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) {
|
||||
tmpq = dlm_list_idx_to_ptr(res, j);
|
||||
list_for_each_entry(lock, tmpq, list) {
|
||||
list_for_each(iter, tmpq) {
|
||||
lock = list_entry(iter,
|
||||
struct dlm_lock, list);
|
||||
if (lock->ml.cookie == ml->cookie)
|
||||
break;
|
||||
lock = NULL;
|
||||
|
@ -372,16 +372,16 @@ EXPORT_SYMBOL(seq_release);
|
||||
* @esc: set of characters that need escaping
|
||||
*
|
||||
* Puts string into buffer, replacing each occurrence of character from
|
||||
* @esc with usual octal escape. Returns 0 in case of success, -1 - in
|
||||
* case of overflow.
|
||||
* @esc with usual octal escape.
|
||||
* Use seq_has_overflowed() to check for errors.
|
||||
*/
|
||||
int seq_escape(struct seq_file *m, const char *s, const char *esc)
|
||||
void seq_escape(struct seq_file *m, const char *s, const char *esc)
|
||||
{
|
||||
char *end = m->buf + m->size;
|
||||
char *p;
|
||||
char *p;
|
||||
char c;
|
||||
|
||||
for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
|
||||
for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) {
|
||||
if (!strchr(esc, c)) {
|
||||
*p++ = c;
|
||||
continue;
|
||||
@ -394,14 +394,13 @@ int seq_escape(struct seq_file *m, const char *s, const char *esc)
|
||||
continue;
|
||||
}
|
||||
seq_set_overflow(m);
|
||||
return -1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
m->count = p - m->buf;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(seq_escape);
|
||||
|
||||
int seq_vprintf(struct seq_file *m, const char *f, va_list args)
|
||||
void seq_vprintf(struct seq_file *m, const char *f, va_list args)
|
||||
{
|
||||
int len;
|
||||
|
||||
@ -409,24 +408,20 @@ int seq_vprintf(struct seq_file *m, const char *f, va_list args)
|
||||
len = vsnprintf(m->buf + m->count, m->size - m->count, f, args);
|
||||
if (m->count + len < m->size) {
|
||||
m->count += len;
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
seq_set_overflow(m);
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(seq_vprintf);
|
||||
|
||||
int seq_printf(struct seq_file *m, const char *f, ...)
|
||||
void seq_printf(struct seq_file *m, const char *f, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list args;
|
||||
|
||||
va_start(args, f);
|
||||
ret = seq_vprintf(m, f, args);
|
||||
seq_vprintf(m, f, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(seq_printf);
|
||||
|
||||
@ -664,26 +659,25 @@ int seq_open_private(struct file *filp, const struct seq_operations *ops,
|
||||
}
|
||||
EXPORT_SYMBOL(seq_open_private);
|
||||
|
||||
int seq_putc(struct seq_file *m, char c)
|
||||
void seq_putc(struct seq_file *m, char c)
|
||||
{
|
||||
if (m->count < m->size) {
|
||||
m->buf[m->count++] = c;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
if (m->count >= m->size)
|
||||
return;
|
||||
|
||||
m->buf[m->count++] = c;
|
||||
}
|
||||
EXPORT_SYMBOL(seq_putc);
|
||||
|
||||
int seq_puts(struct seq_file *m, const char *s)
|
||||
void seq_puts(struct seq_file *m, const char *s)
|
||||
{
|
||||
int len = strlen(s);
|
||||
if (m->count + len < m->size) {
|
||||
memcpy(m->buf + m->count, s, len);
|
||||
m->count += len;
|
||||
return 0;
|
||||
|
||||
if (m->count + len >= m->size) {
|
||||
seq_set_overflow(m);
|
||||
return;
|
||||
}
|
||||
seq_set_overflow(m);
|
||||
return -1;
|
||||
memcpy(m->buf + m->count, s, len);
|
||||
m->count += len;
|
||||
}
|
||||
EXPORT_SYMBOL(seq_puts);
|
||||
|
||||
@ -694,8 +688,8 @@ EXPORT_SYMBOL(seq_puts);
|
||||
* This routine is very quick when you show lots of numbers.
|
||||
* In usual cases, it will be better to use seq_printf(). It's easier to read.
|
||||
*/
|
||||
int seq_put_decimal_ull(struct seq_file *m, char delimiter,
|
||||
unsigned long long num)
|
||||
void seq_put_decimal_ull(struct seq_file *m, char delimiter,
|
||||
unsigned long long num)
|
||||
{
|
||||
int len;
|
||||
|
||||
@ -707,35 +701,33 @@ int seq_put_decimal_ull(struct seq_file *m, char delimiter,
|
||||
|
||||
if (num < 10) {
|
||||
m->buf[m->count++] = num + '0';
|
||||
return 0;
|
||||
return;
|
||||
}
|
||||
|
||||
len = num_to_str(m->buf + m->count, m->size - m->count, num);
|
||||
if (!len)
|
||||
goto overflow;
|
||||
m->count += len;
|
||||
return 0;
|
||||
return;
|
||||
|
||||
overflow:
|
||||
seq_set_overflow(m);
|
||||
return -1;
|
||||
}
|
||||
EXPORT_SYMBOL(seq_put_decimal_ull);
|
||||
|
||||
int seq_put_decimal_ll(struct seq_file *m, char delimiter,
|
||||
long long num)
|
||||
void seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num)
|
||||
{
|
||||
if (num < 0) {
|
||||
if (m->count + 3 >= m->size) {
|
||||
seq_set_overflow(m);
|
||||
return -1;
|
||||
return;
|
||||
}
|
||||
if (delimiter)
|
||||
m->buf[m->count++] = delimiter;
|
||||
num = -num;
|
||||
delimiter = '-';
|
||||
}
|
||||
return seq_put_decimal_ull(m, delimiter, num);
|
||||
|
||||
seq_put_decimal_ull(m, delimiter, num);
|
||||
}
|
||||
EXPORT_SYMBOL(seq_put_decimal_ll);
|
||||
|
||||
|
@ -114,13 +114,18 @@ int seq_open(struct file *, const struct seq_operations *);
|
||||
ssize_t seq_read(struct file *, char __user *, size_t, loff_t *);
|
||||
loff_t seq_lseek(struct file *, loff_t, int);
|
||||
int seq_release(struct inode *, struct file *);
|
||||
int seq_escape(struct seq_file *, const char *, const char *);
|
||||
int seq_putc(struct seq_file *m, char c);
|
||||
int seq_puts(struct seq_file *m, const char *s);
|
||||
int seq_write(struct seq_file *seq, const void *data, size_t len);
|
||||
|
||||
__printf(2, 3) int seq_printf(struct seq_file *, const char *, ...);
|
||||
__printf(2, 0) int seq_vprintf(struct seq_file *, const char *, va_list args);
|
||||
__printf(2, 0)
|
||||
void seq_vprintf(struct seq_file *m, const char *fmt, va_list args);
|
||||
__printf(2, 3)
|
||||
void seq_printf(struct seq_file *m, const char *fmt, ...);
|
||||
void seq_putc(struct seq_file *m, char c);
|
||||
void seq_puts(struct seq_file *m, const char *s);
|
||||
void seq_put_decimal_ull(struct seq_file *m, char delimiter,
|
||||
unsigned long long num);
|
||||
void seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num);
|
||||
void seq_escape(struct seq_file *m, const char *s, const char *esc);
|
||||
|
||||
void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type,
|
||||
int rowsize, int groupsize, const void *buf, size_t len,
|
||||
@ -138,10 +143,6 @@ int single_release(struct inode *, struct file *);
|
||||
void *__seq_open_private(struct file *, const struct seq_operations *, int);
|
||||
int seq_open_private(struct file *, const struct seq_operations *, int);
|
||||
int seq_release_private(struct inode *, struct file *);
|
||||
int seq_put_decimal_ull(struct seq_file *m, char delimiter,
|
||||
unsigned long long num);
|
||||
int seq_put_decimal_ll(struct seq_file *m, char delimiter,
|
||||
long long num);
|
||||
|
||||
static inline struct user_namespace *seq_user_ns(struct seq_file *seq)
|
||||
{
|
||||
|
@ -885,4 +885,6 @@ asmlinkage long sys_execveat(int dfd, const char __user *filename,
|
||||
const char __user *const __user *argv,
|
||||
const char __user *const __user *envp, int flags);
|
||||
|
||||
asmlinkage long sys_membarrier(int cmd, int flags);
|
||||
|
||||
#endif
|
||||
|
@ -709,9 +709,11 @@ __SYSCALL(__NR_memfd_create, sys_memfd_create)
|
||||
__SYSCALL(__NR_bpf, sys_bpf)
|
||||
#define __NR_execveat 281
|
||||
__SC_COMP(__NR_execveat, sys_execveat, compat_sys_execveat)
|
||||
#define __NR_membarrier 282
|
||||
__SYSCALL(__NR_membarrier, sys_membarrier)
|
||||
|
||||
#undef __NR_syscalls
|
||||
#define __NR_syscalls 282
|
||||
#define __NR_syscalls 283
|
||||
|
||||
/*
|
||||
* All syscalls below here should go away really,
|
||||
|
@ -252,6 +252,7 @@ header-y += mdio.h
|
||||
header-y += media.h
|
||||
header-y += media-bus-format.h
|
||||
header-y += mei.h
|
||||
header-y += membarrier.h
|
||||
header-y += memfd.h
|
||||
header-y += mempolicy.h
|
||||
header-y += meye.h
|
||||
|
53
include/uapi/linux/membarrier.h
Normal file
53
include/uapi/linux/membarrier.h
Normal file
@ -0,0 +1,53 @@
|
||||
#ifndef _UAPI_LINUX_MEMBARRIER_H
|
||||
#define _UAPI_LINUX_MEMBARRIER_H
|
||||
|
||||
/*
|
||||
* linux/membarrier.h
|
||||
*
|
||||
* membarrier system call API
|
||||
*
|
||||
* Copyright (c) 2010, 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
/**
|
||||
* enum membarrier_cmd - membarrier system call command
|
||||
* @MEMBARRIER_CMD_QUERY: Query the set of supported commands. It returns
|
||||
* a bitmask of valid commands.
|
||||
* @MEMBARRIER_CMD_SHARED: Execute a memory barrier on all running threads.
|
||||
* Upon return from system call, the caller thread
|
||||
* is ensured that all running threads have passed
|
||||
* through a state where all memory accesses to
|
||||
* user-space addresses match program order between
|
||||
* entry to and return from the system call
|
||||
* (non-running threads are de facto in such a
|
||||
* state). This covers threads from all processes
|
||||
* running on the system. This command returns 0.
|
||||
*
|
||||
* Command to be passed to the membarrier system call. The commands need to
|
||||
* be a single bit each, except for MEMBARRIER_CMD_QUERY which is assigned to
|
||||
* the value 0.
|
||||
*/
|
||||
enum membarrier_cmd {
|
||||
MEMBARRIER_CMD_QUERY = 0,
|
||||
MEMBARRIER_CMD_SHARED = (1 << 0),
|
||||
};
|
||||
|
||||
#endif /* _UAPI_LINUX_MEMBARRIER_H */
|
12
init/Kconfig
12
init/Kconfig
@ -1602,6 +1602,18 @@ config PCI_QUIRKS
|
||||
bugs/quirks. Disable this only if your target machine is
|
||||
unaffected by PCI quirks.
|
||||
|
||||
config MEMBARRIER
|
||||
bool "Enable membarrier() system call" if EXPERT
|
||||
default y
|
||||
help
|
||||
Enable the membarrier() system call that allows issuing memory
|
||||
barriers across all running threads, which can be used to distribute
|
||||
the cost of user-space memory barriers asymmetrically by transforming
|
||||
pairs of memory barriers into pairs consisting of membarrier() and a
|
||||
compiler barrier.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
config EMBEDDED
|
||||
bool "Embedded system"
|
||||
option allnoconfig_y
|
||||
|
@ -100,6 +100,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o
|
||||
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
|
||||
obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o
|
||||
obj-$(CONFIG_TORTURE_TEST) += torture.o
|
||||
obj-$(CONFIG_MEMBARRIER) += membarrier.o
|
||||
|
||||
obj-$(CONFIG_HAS_IOMEM) += memremap.o
|
||||
|
||||
|
66
kernel/membarrier.c
Normal file
66
kernel/membarrier.c
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (C) 2010, 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
|
||||
*
|
||||
* membarrier system call
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/membarrier.h>
|
||||
|
||||
/*
|
||||
* Bitmask made from a "or" of all commands within enum membarrier_cmd,
|
||||
* except MEMBARRIER_CMD_QUERY.
|
||||
*/
|
||||
#define MEMBARRIER_CMD_BITMASK (MEMBARRIER_CMD_SHARED)
|
||||
|
||||
/**
|
||||
* sys_membarrier - issue memory barriers on a set of threads
|
||||
* @cmd: Takes command values defined in enum membarrier_cmd.
|
||||
* @flags: Currently needs to be 0. For future extensions.
|
||||
*
|
||||
* If this system call is not implemented, -ENOSYS is returned. If the
|
||||
* command specified does not exist, or if the command argument is invalid,
|
||||
* this system call returns -EINVAL. For a given command, with flags argument
|
||||
* set to 0, this system call is guaranteed to always return the same value
|
||||
* until reboot.
|
||||
*
|
||||
* All memory accesses performed in program order from each targeted thread
|
||||
* is guaranteed to be ordered with respect to sys_membarrier(). If we use
|
||||
* the semantic "barrier()" to represent a compiler barrier forcing memory
|
||||
* accesses to be performed in program order across the barrier, and
|
||||
* smp_mb() to represent explicit memory barriers forcing full memory
|
||||
* ordering across the barrier, we have the following ordering table for
|
||||
* each pair of barrier(), sys_membarrier() and smp_mb():
|
||||
*
|
||||
* The pair ordering is detailed as (O: ordered, X: not ordered):
|
||||
*
|
||||
* barrier() smp_mb() sys_membarrier()
|
||||
* barrier() X X O
|
||||
* smp_mb() X O O
|
||||
* sys_membarrier() O O O
|
||||
*/
|
||||
SYSCALL_DEFINE2(membarrier, int, cmd, int, flags)
|
||||
{
|
||||
if (unlikely(flags))
|
||||
return -EINVAL;
|
||||
switch (cmd) {
|
||||
case MEMBARRIER_CMD_QUERY:
|
||||
return MEMBARRIER_CMD_BITMASK;
|
||||
case MEMBARRIER_CMD_SHARED:
|
||||
if (num_online_cpus() > 1)
|
||||
synchronize_sched();
|
||||
return 0;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
@ -245,3 +245,6 @@ cond_syscall(sys_bpf);
|
||||
|
||||
/* execveat */
|
||||
cond_syscall(sys_execveat);
|
||||
|
||||
/* membarrier */
|
||||
cond_syscall(sys_membarrier);
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/early_ioremap.h>
|
||||
|
||||
#ifdef CONFIG_MMU
|
||||
static int early_ioremap_debug __initdata;
|
||||
|
@ -86,7 +86,7 @@ static void write_cert(X509 *x509)
|
||||
ERR(!wb, "%s", cert_dst);
|
||||
}
|
||||
X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf));
|
||||
ERR(!i2d_X509_bio(wb, x509), cert_dst);
|
||||
ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst);
|
||||
if (kbuild_verbose)
|
||||
fprintf(stderr, "Extracted cert: %s\n", buf);
|
||||
}
|
||||
|
@ -6,6 +6,7 @@ TARGETS += firmware
|
||||
TARGETS += ftrace
|
||||
TARGETS += futex
|
||||
TARGETS += kcmp
|
||||
TARGETS += membarrier
|
||||
TARGETS += memfd
|
||||
TARGETS += memory-hotplug
|
||||
TARGETS += mount
|
||||
|
1
tools/testing/selftests/membarrier/.gitignore
vendored
Normal file
1
tools/testing/selftests/membarrier/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
membarrier_test
|
11
tools/testing/selftests/membarrier/Makefile
Normal file
11
tools/testing/selftests/membarrier/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
CFLAGS += -g -I../../../../usr/include/
|
||||
|
||||
all:
|
||||
$(CC) $(CFLAGS) membarrier_test.c -o membarrier_test
|
||||
|
||||
TEST_PROGS := membarrier_test
|
||||
|
||||
include ../lib.mk
|
||||
|
||||
clean:
|
||||
$(RM) membarrier_test
|
121
tools/testing/selftests/membarrier/membarrier_test.c
Normal file
121
tools/testing/selftests/membarrier/membarrier_test.c
Normal file
@ -0,0 +1,121 @@
|
||||
#define _GNU_SOURCE
|
||||
#define __EXPORTED_HEADERS__
|
||||
|
||||
#include <linux/membarrier.h>
|
||||
#include <asm-generic/unistd.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../kselftest.h"
|
||||
|
||||
enum test_membarrier_status {
|
||||
TEST_MEMBARRIER_PASS = 0,
|
||||
TEST_MEMBARRIER_FAIL,
|
||||
TEST_MEMBARRIER_SKIP,
|
||||
};
|
||||
|
||||
static int sys_membarrier(int cmd, int flags)
|
||||
{
|
||||
return syscall(__NR_membarrier, cmd, flags);
|
||||
}
|
||||
|
||||
static enum test_membarrier_status test_membarrier_cmd_fail(void)
|
||||
{
|
||||
int cmd = -1, flags = 0;
|
||||
|
||||
if (sys_membarrier(cmd, flags) != -1) {
|
||||
printf("membarrier: Wrong command should fail but passed.\n");
|
||||
return TEST_MEMBARRIER_FAIL;
|
||||
}
|
||||
return TEST_MEMBARRIER_PASS;
|
||||
}
|
||||
|
||||
static enum test_membarrier_status test_membarrier_flags_fail(void)
|
||||
{
|
||||
int cmd = MEMBARRIER_CMD_QUERY, flags = 1;
|
||||
|
||||
if (sys_membarrier(cmd, flags) != -1) {
|
||||
printf("membarrier: Wrong flags should fail but passed.\n");
|
||||
return TEST_MEMBARRIER_FAIL;
|
||||
}
|
||||
return TEST_MEMBARRIER_PASS;
|
||||
}
|
||||
|
||||
static enum test_membarrier_status test_membarrier_success(void)
|
||||
{
|
||||
int cmd = MEMBARRIER_CMD_SHARED, flags = 0;
|
||||
|
||||
if (sys_membarrier(cmd, flags) != 0) {
|
||||
printf("membarrier: Executing MEMBARRIER_CMD_SHARED failed. %s.\n",
|
||||
strerror(errno));
|
||||
return TEST_MEMBARRIER_FAIL;
|
||||
}
|
||||
|
||||
printf("membarrier: MEMBARRIER_CMD_SHARED success.\n");
|
||||
return TEST_MEMBARRIER_PASS;
|
||||
}
|
||||
|
||||
static enum test_membarrier_status test_membarrier(void)
|
||||
{
|
||||
enum test_membarrier_status status;
|
||||
|
||||
status = test_membarrier_cmd_fail();
|
||||
if (status)
|
||||
return status;
|
||||
status = test_membarrier_flags_fail();
|
||||
if (status)
|
||||
return status;
|
||||
status = test_membarrier_success();
|
||||
if (status)
|
||||
return status;
|
||||
return TEST_MEMBARRIER_PASS;
|
||||
}
|
||||
|
||||
static enum test_membarrier_status test_membarrier_query(void)
|
||||
{
|
||||
int flags = 0, ret;
|
||||
|
||||
printf("membarrier MEMBARRIER_CMD_QUERY ");
|
||||
ret = sys_membarrier(MEMBARRIER_CMD_QUERY, flags);
|
||||
if (ret < 0) {
|
||||
printf("failed. %s.\n", strerror(errno));
|
||||
switch (errno) {
|
||||
case ENOSYS:
|
||||
/*
|
||||
* It is valid to build a kernel with
|
||||
* CONFIG_MEMBARRIER=n. However, this skips the tests.
|
||||
*/
|
||||
return TEST_MEMBARRIER_SKIP;
|
||||
case EINVAL:
|
||||
default:
|
||||
return TEST_MEMBARRIER_FAIL;
|
||||
}
|
||||
}
|
||||
if (!(ret & MEMBARRIER_CMD_SHARED)) {
|
||||
printf("command MEMBARRIER_CMD_SHARED is not supported.\n");
|
||||
return TEST_MEMBARRIER_FAIL;
|
||||
}
|
||||
printf("syscall available.\n");
|
||||
return TEST_MEMBARRIER_PASS;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
switch (test_membarrier_query()) {
|
||||
case TEST_MEMBARRIER_FAIL:
|
||||
return ksft_exit_fail();
|
||||
case TEST_MEMBARRIER_SKIP:
|
||||
return ksft_exit_skip();
|
||||
}
|
||||
switch (test_membarrier()) {
|
||||
case TEST_MEMBARRIER_FAIL:
|
||||
return ksft_exit_fail();
|
||||
case TEST_MEMBARRIER_SKIP:
|
||||
return ksft_exit_skip();
|
||||
}
|
||||
|
||||
printf("membarrier: tests done!\n");
|
||||
return ksft_exit_pass();
|
||||
}
|
Loading…
Reference in New Issue
Block a user