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
Unified · Split
| @@ -6789,6 +6789,14 @@ W: http://www.mellanox.com · 6788 unmodified lines | ||
| 6789 | 6789 | Q: http://patchwork.ozlabs.org/project/netdev/list/ |
| 6790 | 6790 | F: drivers/net/ethernet/mellanox/mlxsw/ |
| 6791 | 6791 | |
| 6792 | +MEMBARRIER SUPPORT | |
| 6793 | +M: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
| 6794 | +M: "Paul E. McKenney" <paulmck@linux.vnet.ibm.com> | |
| 6795 | +L: linux-kernel@vger.kernel.org | |
| 6796 | +S: Supported | |
| 6797 | +F: kernel/membarrier.c | |
| 6798 | +F: include/uapi/linux/membarrier.h | |
| 6799 | + | |
| 6792 | 6800 | MEMORY MANAGEMENT |
| 6793 | 6801 | L: linux-mm@kvack.org |
| 6794 | 6802 | W: http://www.linux-mm.org |
| @@ -381,3 +381,4 @@ · 380 unmodified lines | ||
| 381 | 381 | 372 i386 recvmsg sys_recvmsg compat_sys_recvmsg |
| 382 | 382 | 373 i386 shutdown sys_shutdown |
| 383 | 383 | 374 i386 userfaultfd sys_userfaultfd |
| 384 | +375 i386 membarrier sys_membarrier | |
| @@ -330,6 +330,7 @@ · 329 unmodified lines | ||
| 330 | 330 | 321 common bpf sys_bpf |
| 331 | 331 | 322 64 execveat stub_execveat |
| 332 | 332 | 323 common userfaultfd sys_userfaultfd |
| 333 | +324 common membarrier sys_membarrier | |
| 333 | 334 | |
| 334 | 335 | # |
| 335 | 336 | # 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) · 134 unmodified lines | ||
| 135 | 135 | static ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, |
| 136 | 136 | struct seq_file *s) |
| 137 | 137 | { |
| 138 | − return seq_printf(s, "%08x %08x %01x\n", cr->cam, cr->ram, | |
| 138 | + seq_printf(s, "%08x %08x %01x\n", cr->cam, cr->ram, | |
| 139 | 139 | (cr->cam & MMU_CAM_P) ? 1 : 0); |
| 140 | + return 0; | |
| 140 | 141 | } |
| 141 | 142 | |
| 142 | 143 | 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) · 141 unmodified lines | ||
| 142 | 142 | struct inode *inode = d_inode(dentry); |
| 143 | 143 | const struct proc_ns_operations *ns_ops = dentry->d_fsdata; |
| 144 | 144 | |
| 145 | − return seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino); | |
| 145 | + seq_printf(seq, "%s:[%lu]", ns_ops->name, inode->i_ino); | |
| 146 | + return 0; | |
| 146 | 147 | } |
| 147 | 148 | |
| 148 | 149 | static const struct super_operations nsfs_ops = { |
| @@ -1776,7 +1776,7 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, · 1775 unmodified lines | ||
| 1776 | 1776 | struct dlm_migratable_lockres *mres) |
| 1777 | 1777 | { |
| 1778 | 1778 | struct dlm_migratable_lock *ml; |
| 1779 | − struct list_head *queue; | |
| 1779 | + struct list_head *queue, *iter; | |
| 1780 | 1780 | struct list_head *tmpq = NULL; |
| 1781 | 1781 | struct dlm_lock *newlock = NULL; |
| 1782 | 1782 | struct dlm_lockstatus *lksb = NULL; |
| @@ -1821,7 +1821,9 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, · 38 unmodified lines | ||
| 1821 | 1821 | spin_lock(&res->spinlock); |
| 1822 | 1822 | for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) { |
| 1823 | 1823 | tmpq = dlm_list_idx_to_ptr(res, j); |
| 1824 | − list_for_each_entry(lock, tmpq, list) { | |
| 1824 | + list_for_each(iter, tmpq) { | |
| 1825 | + lock = list_entry(iter, | |
| 1826 | + struct dlm_lock, list); | |
| 1825 | 1827 | if (lock->ml.cookie == ml->cookie) |
| 1826 | 1828 | break; |
| 1827 | 1829 | lock = NULL; |
| @@ -372,16 +372,16 @@ EXPORT_SYMBOL(seq_release); · 371 unmodified lines | ||
| 372 | 372 | * @esc: set of characters that need escaping |
| 373 | 373 | * |
| 374 | 374 | * Puts string into buffer, replacing each occurrence of character from |
| 375 | − * @esc with usual octal escape. Returns 0 in case of success, -1 - in | |
| 376 | − * case of overflow. | |
| 375 | + * @esc with usual octal escape. | |
| 376 | + * Use seq_has_overflowed() to check for errors. | |
| 377 | 377 | */ |
| 378 | −int seq_escape(struct seq_file *m, const char *s, const char *esc) | |
| 378 | +void seq_escape(struct seq_file *m, const char *s, const char *esc) | |
| 379 | 379 | { |
| 380 | 380 | char *end = m->buf + m->size; |
| 381 | − char *p; | |
| 381 | + char *p; | |
| 382 | 382 | char c; |
| 383 | 383 | |
| 384 | − for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) { | |
| 384 | + for (p = m->buf + m->count; (c = *s) != '\0' && p < end; s++) { | |
| 385 | 385 | if (!strchr(esc, c)) { |
| 386 | 386 | *p++ = c; |
| 387 | 387 | continue; |
| @@ -394,14 +394,13 @@ int seq_escape(struct seq_file *m, const char *s, const char *esc) · 6 unmodified lines | ||
| 394 | 394 | continue; |
| 395 | 395 | } |
| 396 | 396 | seq_set_overflow(m); |
| 397 | − return -1; | |
| 398 | − } | |
| 397 | + return; | |
| 398 | + } | |
| 399 | 399 | m->count = p - m->buf; |
| 400 | − return 0; | |
| 401 | 400 | } |
| 402 | 401 | EXPORT_SYMBOL(seq_escape); |
| 403 | 402 | |
| 404 | −int seq_vprintf(struct seq_file *m, const char *f, va_list args) | |
| 403 | +void seq_vprintf(struct seq_file *m, const char *f, va_list args) | |
| 405 | 404 | { |
| 406 | 405 | int len; |
| 407 | 406 | |
| @@ -409,24 +408,20 @@ int seq_vprintf(struct seq_file *m, const char *f, va_list args) · 1 unmodified line | ||
| 409 | 408 | len = vsnprintf(m->buf + m->count, m->size - m->count, f, args); |
| 410 | 409 | if (m->count + len < m->size) { |
| 411 | 410 | m->count += len; |
| 412 | − return 0; | |
| 411 | + return; | |
| 413 | 412 | } |
| 414 | 413 | } |
| 415 | 414 | seq_set_overflow(m); |
| 416 | − return -1; | |
| 417 | 415 | } |
| 418 | 416 | EXPORT_SYMBOL(seq_vprintf); |
| 419 | 417 | |
| 420 | −int seq_printf(struct seq_file *m, const char *f, ...) | |
| 418 | +void seq_printf(struct seq_file *m, const char *f, ...) | |
| 421 | 419 | { |
| 422 | − int ret; | |
| 423 | 420 | va_list args; |
| 424 | 421 | |
| 425 | 422 | va_start(args, f); |
| 426 | − ret = seq_vprintf(m, f, args); | |
| 423 | + seq_vprintf(m, f, args); | |
| 427 | 424 | va_end(args); |
| 428 | − | |
| 429 | − return ret; | |
| 430 | 425 | } |
| 431 | 426 | EXPORT_SYMBOL(seq_printf); |
| 432 | 427 | |
| @@ -664,26 +659,25 @@ int seq_open_private(struct file *filp, const struct seq_operations *ops, · 231 unmodified lines | ||
| 664 | 659 | } |
| 665 | 660 | EXPORT_SYMBOL(seq_open_private); |
| 666 | 661 | |
| 667 | −int seq_putc(struct seq_file *m, char c) | |
| 662 | +void seq_putc(struct seq_file *m, char c) | |
| 668 | 663 | { |
| 669 | − if (m->count < m->size) { | |
| 670 | − m->buf[m->count++] = c; | |
| 671 | − return 0; | |
| 672 | − } | |
| 673 | − return -1; | |
| 664 | + if (m->count >= m->size) | |
| 665 | + return; | |
| 666 | + | |
| 667 | + m->buf[m->count++] = c; | |
| 674 | 668 | } |
| 675 | 669 | EXPORT_SYMBOL(seq_putc); |
| 676 | 670 | |
| 677 | −int seq_puts(struct seq_file *m, const char *s) | |
| 671 | +void seq_puts(struct seq_file *m, const char *s) | |
| 678 | 672 | { |
| 679 | 673 | int len = strlen(s); |
| 680 | − if (m->count + len < m->size) { | |
| 681 | − memcpy(m->buf + m->count, s, len); | |
| 682 | − m->count += len; | |
| 683 | − return 0; | |
| 674 | + | |
| 675 | + if (m->count + len >= m->size) { | |
| 676 | + seq_set_overflow(m); | |
| 677 | + return; | |
| 684 | 678 | } |
| 685 | − seq_set_overflow(m); | |
| 686 | − return -1; | |
| 679 | + memcpy(m->buf + m->count, s, len); | |
| 680 | + m->count += len; | |
| 687 | 681 | } |
| 688 | 682 | EXPORT_SYMBOL(seq_puts); |
| 689 | 683 | |
| @@ -694,8 +688,8 @@ EXPORT_SYMBOL(seq_puts); · 4 unmodified lines | ||
| 694 | 688 | * This routine is very quick when you show lots of numbers. |
| 695 | 689 | * In usual cases, it will be better to use seq_printf(). It's easier to read. |
| 696 | 690 | */ |
| 697 | −int seq_put_decimal_ull(struct seq_file *m, char delimiter, | |
| 698 | − unsigned long long num) | |
| 691 | +void seq_put_decimal_ull(struct seq_file *m, char delimiter, | |
| 692 | + unsigned long long num) | |
| 699 | 693 | { |
| 700 | 694 | int len; |
| 701 | 695 | |
| @@ -707,35 +701,33 @@ int seq_put_decimal_ull(struct seq_file *m, char delimiter, · 5 unmodified lines | ||
| 707 | 701 | |
| 708 | 702 | if (num < 10) { |
| 709 | 703 | m->buf[m->count++] = num + '0'; |
| 710 | − return 0; | |
| 704 | + return; | |
| 711 | 705 | } |
| 712 | 706 | |
| 713 | 707 | len = num_to_str(m->buf + m->count, m->size - m->count, num); |
| 714 | 708 | if (!len) |
| 715 | 709 | goto overflow; |
| 716 | 710 | m->count += len; |
| 717 | − return 0; | |
| 711 | + return; | |
| 712 | + | |
| 718 | 713 | overflow: |
| 719 | 714 | seq_set_overflow(m); |
| 720 | − return -1; | |
| 721 | 715 | } |
| 722 | 716 | EXPORT_SYMBOL(seq_put_decimal_ull); |
| 723 | 717 | |
| 724 | −int seq_put_decimal_ll(struct seq_file *m, char delimiter, | |
| 725 | − long long num) | |
| 718 | +void seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num) | |
| 726 | 719 | { |
| 727 | 720 | if (num < 0) { |
| 728 | 721 | if (m->count + 3 >= m->size) { |
| 729 | 722 | seq_set_overflow(m); |
| 730 | − return -1; | |
| 723 | + return; | |
| 731 | 724 | } |
| 732 | 725 | if (delimiter) |
| 733 | 726 | m->buf[m->count++] = delimiter; |
| 734 | 727 | num = -num; |
| 735 | 728 | delimiter = '-'; |
| 736 | 729 | } |
| 737 | − return seq_put_decimal_ull(m, delimiter, num); | |
| 738 | − | |
| 730 | + seq_put_decimal_ull(m, delimiter, num); | |
| 739 | 731 | } |
| 740 | 732 | EXPORT_SYMBOL(seq_put_decimal_ll); |
| 741 | 733 | |
| @@ -114,13 +114,18 @@ int seq_open(struct file *, const struct seq_operations *); · 113 unmodified lines | ||
| 114 | 114 | ssize_t seq_read(struct file *, char __user *, size_t, loff_t *); |
| 115 | 115 | loff_t seq_lseek(struct file *, loff_t, int); |
| 116 | 116 | int seq_release(struct inode *, struct file *); |
| 117 | −int seq_escape(struct seq_file *, const char *, const char *); | |
| 118 | −int seq_putc(struct seq_file *m, char c); | |
| 119 | −int seq_puts(struct seq_file *m, const char *s); | |
| 120 | 117 | int seq_write(struct seq_file *seq, const void *data, size_t len); |
| 121 | 118 | |
| 122 | −__printf(2, 3) int seq_printf(struct seq_file *, const char *, ...); | |
| 123 | −__printf(2, 0) int seq_vprintf(struct seq_file *, const char *, va_list args); | |
| 119 | +__printf(2, 0) | |
| 120 | +void seq_vprintf(struct seq_file *m, const char *fmt, va_list args); | |
| 121 | +__printf(2, 3) | |
| 122 | +void seq_printf(struct seq_file *m, const char *fmt, ...); | |
| 123 | +void seq_putc(struct seq_file *m, char c); | |
| 124 | +void seq_puts(struct seq_file *m, const char *s); | |
| 125 | +void seq_put_decimal_ull(struct seq_file *m, char delimiter, | |
| 126 | + unsigned long long num); | |
| 127 | +void seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num); | |
| 128 | +void seq_escape(struct seq_file *m, const char *s, const char *esc); | |
| 124 | 129 | |
| 125 | 130 | void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type, |
| 126 | 131 | int rowsize, int groupsize, const void *buf, size_t len, |
| @@ -138,10 +143,6 @@ int single_release(struct inode *, struct file *); · 11 unmodified lines | ||
| 138 | 143 | void *__seq_open_private(struct file *, const struct seq_operations *, int); |
| 139 | 144 | int seq_open_private(struct file *, const struct seq_operations *, int); |
| 140 | 145 | int seq_release_private(struct inode *, struct file *); |
| 141 | −int seq_put_decimal_ull(struct seq_file *m, char delimiter, | |
| 142 | − unsigned long long num); | |
| 143 | −int seq_put_decimal_ll(struct seq_file *m, char delimiter, | |
| 144 | − long long num); | |
| 145 | 146 | |
| 146 | 147 | static inline struct user_namespace *seq_user_ns(struct seq_file *seq) |
| 147 | 148 | { |
| @@ -885,4 +885,6 @@ asmlinkage long sys_execveat(int dfd, const char __user *filename, · 884 unmodified lines | ||
| 885 | 885 | const char __user *const __user *argv, |
| 886 | 886 | const char __user *const __user *envp, int flags); |
| 887 | 887 | |
| 888 | +asmlinkage long sys_membarrier(int cmd, int flags); | |
| 889 | + | |
| 888 | 890 | #endif |
| @@ -709,9 +709,11 @@ __SYSCALL(__NR_memfd_create, sys_memfd_create) · 708 unmodified lines | ||
| 709 | 709 | __SYSCALL(__NR_bpf, sys_bpf) |
| 710 | 710 | #define __NR_execveat 281 |
| 711 | 711 | __SC_COMP(__NR_execveat, sys_execveat, compat_sys_execveat) |
| 712 | +#define __NR_membarrier 282 | |
| 713 | +__SYSCALL(__NR_membarrier, sys_membarrier) | |
| 712 | 714 | |
| 713 | 715 | #undef __NR_syscalls |
| 714 | −#define __NR_syscalls 282 | |
| 716 | +#define __NR_syscalls 283 | |
| 715 | 717 | |
| 716 | 718 | /* |
| 717 | 719 | * All syscalls below here should go away really, |
| @@ -252,6 +252,7 @@ header-y += mdio.h · 251 unmodified lines | ||
| 252 | 252 | header-y += media.h |
| 253 | 253 | header-y += media-bus-format.h |
| 254 | 254 | header-y += mei.h |
| 255 | +header-y += membarrier.h | |
| 255 | 256 | header-y += memfd.h |
| 256 | 257 | header-y += mempolicy.h |
| 257 | 258 | header-y += meye.h |
| @@ -0,0 +1,53 @@ | ||
| 1 | +#ifndef _UAPI_LINUX_MEMBARRIER_H | |
| 2 | +#define _UAPI_LINUX_MEMBARRIER_H | |
| 3 | + | |
| 4 | +/* | |
| 5 | + * linux/membarrier.h | |
| 6 | + * | |
| 7 | + * membarrier system call API | |
| 8 | + * | |
| 9 | + * Copyright (c) 2010, 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
| 10 | + * | |
| 11 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | |
| 12 | + * of this software and associated documentation files (the "Software"), to deal | |
| 13 | + * in the Software without restriction, including without limitation the rights | |
| 14 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
| 15 | + * copies of the Software, and to permit persons to whom the Software is | |
| 16 | + * furnished to do so, subject to the following conditions: | |
| 17 | + * | |
| 18 | + * The above copyright notice and this permission notice shall be included in | |
| 19 | + * all copies or substantial portions of the Software. | |
| 20 | + * | |
| 21 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| 22 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| 23 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
| 24 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
| 25 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
| 26 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
| 27 | + * SOFTWARE. | |
| 28 | + */ | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * enum membarrier_cmd - membarrier system call command | |
| 32 | + * @MEMBARRIER_CMD_QUERY: Query the set of supported commands. It returns | |
| 33 | + * a bitmask of valid commands. | |
| 34 | + * @MEMBARRIER_CMD_SHARED: Execute a memory barrier on all running threads. | |
| 35 | + * Upon return from system call, the caller thread | |
| 36 | + * is ensured that all running threads have passed | |
| 37 | + * through a state where all memory accesses to | |
| 38 | + * user-space addresses match program order between | |
| 39 | + * entry to and return from the system call | |
| 40 | + * (non-running threads are de facto in such a | |
| 41 | + * state). This covers threads from all processes | |
| 42 | + * running on the system. This command returns 0. | |
| 43 | + * | |
| 44 | + * Command to be passed to the membarrier system call. The commands need to | |
| 45 | + * be a single bit each, except for MEMBARRIER_CMD_QUERY which is assigned to | |
| 46 | + * the value 0. | |
| 47 | + */ | |
| 48 | +enum membarrier_cmd { | |
| 49 | + MEMBARRIER_CMD_QUERY = 0, | |
| 50 | + MEMBARRIER_CMD_SHARED = (1 << 0), | |
| 51 | +}; | |
| 52 | + | |
| 53 | +#endif /* _UAPI_LINUX_MEMBARRIER_H */ | |
| @@ -1602,6 +1602,18 @@ config PCI_QUIRKS · 1601 unmodified lines | ||
| 1602 | 1602 | bugs/quirks. Disable this only if your target machine is |
| 1603 | 1603 | unaffected by PCI quirks. |
| 1604 | 1604 | |
| 1605 | +config MEMBARRIER | |
| 1606 | + bool "Enable membarrier() system call" if EXPERT | |
| 1607 | + default y | |
| 1608 | + help | |
| 1609 | + Enable the membarrier() system call that allows issuing memory | |
| 1610 | + barriers across all running threads, which can be used to distribute | |
| 1611 | + the cost of user-space memory barriers asymmetrically by transforming | |
| 1612 | + pairs of memory barriers into pairs consisting of membarrier() and a | |
| 1613 | + compiler barrier. | |
| 1614 | + | |
| 1615 | + If unsure, say Y. | |
| 1616 | + | |
| 1605 | 1617 | config EMBEDDED |
| 1606 | 1618 | bool "Embedded system" |
| 1607 | 1619 | option allnoconfig_y |
| @@ -100,6 +100,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o · 99 unmodified lines | ||
| 100 | 100 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o |
| 101 | 101 | obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o |
| 102 | 102 | obj-$(CONFIG_TORTURE_TEST) += torture.o |
| 103 | +obj-$(CONFIG_MEMBARRIER) += membarrier.o | |
| 103 | 104 | |
| 104 | 105 | obj-$(CONFIG_HAS_IOMEM) += memremap.o |
| 105 | 106 | |
| @@ -0,0 +1,66 @@ | ||
| 1 | +/* | |
| 2 | + * Copyright (C) 2010, 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com> | |
| 3 | + * | |
| 4 | + * membarrier system call | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify | |
| 7 | + * it under the terms of the GNU General Public License as published by | |
| 8 | + * the Free Software Foundation; either version 2 of the License, or | |
| 9 | + * (at your option) any later version. | |
| 10 | + * | |
| 11 | + * This program is distributed in the hope that it will be useful, | |
| 12 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 13 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 14 | + * GNU General Public License for more details. | |
| 15 | + */ | |
| 16 | + | |
| 17 | +#include <linux/syscalls.h> | |
| 18 | +#include <linux/membarrier.h> | |
| 19 | + | |
| 20 | +/* | |
| 21 | + * Bitmask made from a "or" of all commands within enum membarrier_cmd, | |
| 22 | + * except MEMBARRIER_CMD_QUERY. | |
| 23 | + */ | |
| 24 | +#define MEMBARRIER_CMD_BITMASK (MEMBARRIER_CMD_SHARED) | |
| 25 | + | |
| 26 | +/** | |
| 27 | + * sys_membarrier - issue memory barriers on a set of threads | |
| 28 | + * @cmd: Takes command values defined in enum membarrier_cmd. | |
| 29 | + * @flags: Currently needs to be 0. For future extensions. | |
| 30 | + * | |
| 31 | + * If this system call is not implemented, -ENOSYS is returned. If the | |
| 32 | + * command specified does not exist, or if the command argument is invalid, | |
| 33 | + * this system call returns -EINVAL. For a given command, with flags argument | |
| 34 | + * set to 0, this system call is guaranteed to always return the same value | |
| 35 | + * until reboot. | |
| 36 | + * | |
| 37 | + * All memory accesses performed in program order from each targeted thread | |
| 38 | + * is guaranteed to be ordered with respect to sys_membarrier(). If we use | |
| 39 | + * the semantic "barrier()" to represent a compiler barrier forcing memory | |
| 40 | + * accesses to be performed in program order across the barrier, and | |
| 41 | + * smp_mb() to represent explicit memory barriers forcing full memory | |
| 42 | + * ordering across the barrier, we have the following ordering table for | |
| 43 | + * each pair of barrier(), sys_membarrier() and smp_mb(): | |
| 44 | + * | |
| 45 | + * The pair ordering is detailed as (O: ordered, X: not ordered): | |
| 46 | + * | |
| 47 | + * barrier() smp_mb() sys_membarrier() | |
| 48 | + * barrier() X X O | |
| 49 | + * smp_mb() X O O | |
| 50 | + * sys_membarrier() O O O | |
| 51 | + */ | |
| 52 | +SYSCALL_DEFINE2(membarrier, int, cmd, int, flags) | |
| 53 | +{ | |
| 54 | + if (unlikely(flags)) | |
| 55 | + return -EINVAL; | |
| 56 | + switch (cmd) { | |
| 57 | + case MEMBARRIER_CMD_QUERY: | |
| 58 | + return MEMBARRIER_CMD_BITMASK; | |
| 59 | + case MEMBARRIER_CMD_SHARED: | |
| 60 | + if (num_online_cpus() > 1) | |
| 61 | + synchronize_sched(); | |
| 62 | + return 0; | |
| 63 | + default: | |
| 64 | + return -EINVAL; | |
| 65 | + } | |
| 66 | +} | |
| @@ -245,3 +245,6 @@ cond_syscall(sys_bpf); · 244 unmodified lines | ||
| 245 | 245 | |
| 246 | 246 | /* execveat */ |
| 247 | 247 | cond_syscall(sys_execveat); |
| 248 | + | |
| 249 | +/* membarrier */ | |
| 250 | +cond_syscall(sys_membarrier); | |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | ||
| 15 | 15 | #include <linux/mm.h> |
| 16 | 16 | #include <linux/vmalloc.h> |
| 17 | 17 | #include <asm/fixmap.h> |
| 18 | +#include <asm/early_ioremap.h> | |
| 18 | 19 | |
| 19 | 20 | #ifdef CONFIG_MMU |
| 20 | 21 | static int early_ioremap_debug __initdata; |
| @@ -86,7 +86,7 @@ static void write_cert(X509 *x509) · 85 unmodified lines | ||
| 86 | 86 | ERR(!wb, "%s", cert_dst); |
| 87 | 87 | } |
| 88 | 88 | X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); |
| 89 | − ERR(!i2d_X509_bio(wb, x509), cert_dst); | |
| 89 | + ERR(!i2d_X509_bio(wb, x509), "%s", cert_dst); | |
| 90 | 90 | if (kbuild_verbose) |
| 91 | 91 | fprintf(stderr, "Extracted cert: %s\n", buf); |
| 92 | 92 | } |
| @@ -6,6 +6,7 @@ TARGETS += firmware · 5 unmodified lines | ||
| 6 | 6 | TARGETS += ftrace |
| 7 | 7 | TARGETS += futex |
| 8 | 8 | TARGETS += kcmp |
| 9 | +TARGETS += membarrier | |
| 9 | 10 | TARGETS += memfd |
| 10 | 11 | TARGETS += memory-hotplug |
| 11 | 12 | TARGETS += mount |
| @@ -0,0 +1 @@ | ||
| 1 | +membarrier_test | |
| @@ -0,0 +1,11 @@ | ||
| 1 | +CFLAGS += -g -I../../../../usr/include/ | |
| 2 | + | |
| 3 | +all: | |
| 4 | + $(CC) $(CFLAGS) membarrier_test.c -o membarrier_test | |
| 5 | + | |
| 6 | +TEST_PROGS := membarrier_test | |
| 7 | + | |
| 8 | +include ../lib.mk | |
| 9 | + | |
| 10 | +clean: | |
| 11 | + $(RM) membarrier_test | |
| @@ -0,0 +1,121 @@ | ||
| 1 | +#define _GNU_SOURCE | |
| 2 | +#define __EXPORTED_HEADERS__ | |
| 3 | + | |
| 4 | +#include <linux/membarrier.h> | |
| 5 | +#include <asm-generic/unistd.h> | |
| 6 | +#include <sys/syscall.h> | |
| 7 | +#include <stdio.h> | |
| 8 | +#include <errno.h> | |
| 9 | +#include <string.h> | |
| 10 | + | |
| 11 | +#include "../kselftest.h" | |
| 12 | + | |
| 13 | +enum test_membarrier_status { | |
| 14 | + TEST_MEMBARRIER_PASS = 0, | |
| 15 | + TEST_MEMBARRIER_FAIL, | |
| 16 | + TEST_MEMBARRIER_SKIP, | |
| 17 | +}; | |
| 18 | + | |
| 19 | +static int sys_membarrier(int cmd, int flags) | |
| 20 | +{ | |
| 21 | + return syscall(__NR_membarrier, cmd, flags); | |
| 22 | +} | |
| 23 | + | |
| 24 | +static enum test_membarrier_status test_membarrier_cmd_fail(void) | |
| 25 | +{ | |
| 26 | + int cmd = -1, flags = 0; | |
| 27 | + | |
| 28 | + if (sys_membarrier(cmd, flags) != -1) { | |
| 29 | + printf("membarrier: Wrong command should fail but passed.\n"); | |
| 30 | + return TEST_MEMBARRIER_FAIL; | |
| 31 | + } | |
| 32 | + return TEST_MEMBARRIER_PASS; | |
| 33 | +} | |
| 34 | + | |
| 35 | +static enum test_membarrier_status test_membarrier_flags_fail(void) | |
| 36 | +{ | |
| 37 | + int cmd = MEMBARRIER_CMD_QUERY, flags = 1; | |
| 38 | + | |
| 39 | + if (sys_membarrier(cmd, flags) != -1) { | |
| 40 | + printf("membarrier: Wrong flags should fail but passed.\n"); | |
| 41 | + return TEST_MEMBARRIER_FAIL; | |
| 42 | + } | |
| 43 | + return TEST_MEMBARRIER_PASS; | |
| 44 | +} | |
| 45 | + | |
| 46 | +static enum test_membarrier_status test_membarrier_success(void) | |
| 47 | +{ | |
| 48 | + int cmd = MEMBARRIER_CMD_SHARED, flags = 0; | |
| 49 | + | |
| 50 | + if (sys_membarrier(cmd, flags) != 0) { | |
| 51 | + printf("membarrier: Executing MEMBARRIER_CMD_SHARED failed. %s.\n", | |
| 52 | + strerror(errno)); | |
| 53 | + return TEST_MEMBARRIER_FAIL; | |
| 54 | + } | |
| 55 | + | |
| 56 | + printf("membarrier: MEMBARRIER_CMD_SHARED success.\n"); | |
| 57 | + return TEST_MEMBARRIER_PASS; | |
| 58 | +} | |
| 59 | + | |
| 60 | +static enum test_membarrier_status test_membarrier(void) | |
| 61 | +{ | |
| 62 | + enum test_membarrier_status status; | |
| 63 | + | |
| 64 | + status = test_membarrier_cmd_fail(); | |
| 65 | + if (status) | |
| 66 | + return status; | |
| 67 | + status = test_membarrier_flags_fail(); | |
| 68 | + if (status) | |
| 69 | + return status; | |
| 70 | + status = test_membarrier_success(); | |
| 71 | + if (status) | |
| 72 | + return status; | |
| 73 | + return TEST_MEMBARRIER_PASS; | |
| 74 | +} | |
| 75 | + | |
| 76 | +static enum test_membarrier_status test_membarrier_query(void) | |
| 77 | +{ | |
| 78 | + int flags = 0, ret; | |
| 79 | + | |
| 80 | + printf("membarrier MEMBARRIER_CMD_QUERY "); | |
| 81 | + ret = sys_membarrier(MEMBARRIER_CMD_QUERY, flags); | |
| 82 | + if (ret < 0) { | |
| 83 | + printf("failed. %s.\n", strerror(errno)); | |
| 84 | + switch (errno) { | |
| 85 | + case ENOSYS: | |
| 86 | + /* | |
| 87 | + * It is valid to build a kernel with | |
| 88 | + * CONFIG_MEMBARRIER=n. However, this skips the tests. | |
| 89 | + */ | |
| 90 | + return TEST_MEMBARRIER_SKIP; | |
| 91 | + case EINVAL: | |
| 92 | + default: | |
| 93 | + return TEST_MEMBARRIER_FAIL; | |
| 94 | + } | |
| 95 | + } | |
| 96 | + if (!(ret & MEMBARRIER_CMD_SHARED)) { | |
| 97 | + printf("command MEMBARRIER_CMD_SHARED is not supported.\n"); | |
| 98 | + return TEST_MEMBARRIER_FAIL; | |
| 99 | + } | |
| 100 | + printf("syscall available.\n"); | |
| 101 | + return TEST_MEMBARRIER_PASS; | |
| 102 | +} | |
| 103 | + | |
| 104 | +int main(int argc, char **argv) | |
| 105 | +{ | |
| 106 | + switch (test_membarrier_query()) { | |
| 107 | + case TEST_MEMBARRIER_FAIL: | |
| 108 | + return ksft_exit_fail(); | |
| 109 | + case TEST_MEMBARRIER_SKIP: | |
| 110 | + return ksft_exit_skip(); | |
| 111 | + } | |
| 112 | + switch (test_membarrier()) { | |
| 113 | + case TEST_MEMBARRIER_FAIL: | |
| 114 | + return ksft_exit_fail(); | |
| 115 | + case TEST_MEMBARRIER_SKIP: | |
| 116 | + return ksft_exit_skip(); | |
| 117 | + } | |
| 118 | + | |
| 119 | + printf("membarrier: tests done!\n"); | |
| 120 | + return ksft_exit_pass(); | |
| 121 | +} | |