mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02: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
					
				
					 22 changed files with 336 additions and 54 deletions
				
			
		| 
						 | 
				
			
			@ -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 a new issue