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 | Q: http://patchwork.ozlabs.org/project/netdev/list/ | 6789 | Q: http://patchwork.ozlabs.org/project/netdev/list/ |
| 6790 | F: drivers/net/ethernet/mellanox/mlxsw/ | 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 | MEMORY MANAGEMENT | 6800 | MEMORY MANAGEMENT |
| 6793 | L: linux-mm@kvack.org | 6801 | L: linux-mm@kvack.org |
| 6794 | W: http://www.linux-mm.org | 6802 | W: http://www.linux-mm.org |
| @@ -381,3 +381,4 @@ · 380 unmodified lines | |||
| 381 | 372 i386 recvmsg sys_recvmsg compat_sys_recvmsg | 381 | 372 i386 recvmsg sys_recvmsg compat_sys_recvmsg |
| 382 | 373 i386 shutdown sys_shutdown | 382 | 373 i386 shutdown sys_shutdown |
| 383 | 374 i386 userfaultfd sys_userfaultfd | 383 | 374 i386 userfaultfd sys_userfaultfd |
| 384 | 375 i386 membarrier sys_membarrier | ||
| @@ -330,6 +330,7 @@ · 329 unmodified lines | |||
| 330 | 321 common bpf sys_bpf | 330 | 321 common bpf sys_bpf |
| 331 | 322 64 execveat stub_execveat | 331 | 322 64 execveat stub_execveat |
| 332 | 323 common userfaultfd sys_userfaultfd | 332 | 323 common userfaultfd sys_userfaultfd |
| 333 | 324 common membarrier sys_membarrier | ||
| 333 | 334 | ||
| 334 | # | 335 | # |
| 335 | # x32-specific system call numbers start at 512 to avoid cache impact | 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 | static ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, | 135 | static ssize_t iotlb_dump_cr(struct omap_iommu *obj, struct cr_regs *cr, |
| 136 | struct seq_file *s) | 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 | (cr->cam & MMU_CAM_P) ? 1 : 0); | 139 | (cr->cam & MMU_CAM_P) ? 1 : 0); |
| 140 | return 0; | ||
| 140 | } | 141 | } |
| 141 | 142 | ||
| 142 | static size_t omap_dump_tlb_entries(struct omap_iommu *obj, struct seq_file *s) | 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 | struct inode *inode = d_inode(dentry); | 142 | struct inode *inode = d_inode(dentry); |
| 143 | const struct proc_ns_operations *ns_ops = dentry->d_fsdata; | 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 | static const struct super_operations nsfs_ops = { | 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 | struct dlm_migratable_lockres *mres) | 1776 | struct dlm_migratable_lockres *mres) |
| 1777 | { | 1777 | { |
| 1778 | struct dlm_migratable_lock *ml; | 1778 | struct dlm_migratable_lock *ml; |
| 1779 | struct list_head *queue; | 1779 | struct list_head *queue, *iter; |
| 1780 | struct list_head *tmpq = NULL; | 1780 | struct list_head *tmpq = NULL; |
| 1781 | struct dlm_lock *newlock = NULL; | 1781 | struct dlm_lock *newlock = NULL; |
| 1782 | struct dlm_lockstatus *lksb = NULL; | 1782 | struct dlm_lockstatus *lksb = NULL; |
| @@ -1821,7 +1821,9 @@ static int dlm_process_recovery_data(struct dlm_ctxt *dlm, · 38 unmodified lines | |||
| 1821 | spin_lock(&res->spinlock); | 1821 | spin_lock(&res->spinlock); |
| 1822 | for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) { | 1822 | for (j = DLM_GRANTED_LIST; j <= DLM_BLOCKED_LIST; j++) { |
| 1823 | tmpq = dlm_list_idx_to_ptr(res, j); | 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 | if (lock->ml.cookie == ml->cookie) | 1827 | if (lock->ml.cookie == ml->cookie) |
| 1826 | break; | 1828 | break; |
| 1827 | lock = NULL; | 1829 | lock = NULL; |
| @@ -372,16 +372,16 @@ EXPORT_SYMBOL(seq_release); · 371 unmodified lines | |||
| 372 | * @esc: set of characters that need escaping | 372 | * @esc: set of characters that need escaping |
| 373 | * | 373 | * |
| 374 | * Puts string into buffer, replacing each occurrence of character from | 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 | 375 | * @esc with usual octal escape. |
| 376 | * case of overflow. | 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 | char *end = m->buf + m->size; | 380 | char *end = m->buf + m->size; |
| 381 | char *p; | 381 | char *p; |
| 382 | char c; | 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 | if (!strchr(esc, c)) { | 385 | if (!strchr(esc, c)) { |
| 386 | *p++ = c; | 386 | *p++ = c; |
| 387 | continue; | 387 | continue; |
| @@ -394,14 +394,13 @@ int seq_escape(struct seq_file *m, const char *s, const char *esc) · 6 unmodified lines | |||
| 394 | continue; | 394 | continue; |
| 395 | } | 395 | } |
| 396 | seq_set_overflow(m); | 396 | seq_set_overflow(m); |
| 397 | return -1; | 397 | return; |
| 398 | } | 398 | } |
| 399 | m->count = p - m->buf; | 399 | m->count = p - m->buf; |
| 400 | return 0; | ||
| 401 | } | 400 | } |
| 402 | EXPORT_SYMBOL(seq_escape); | 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 | int len; | 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 | len = vsnprintf(m->buf + m->count, m->size - m->count, f, args); | 408 | len = vsnprintf(m->buf + m->count, m->size - m->count, f, args); |
| 410 | if (m->count + len < m->size) { | 409 | if (m->count + len < m->size) { |
| 411 | m->count += len; | 410 | m->count += len; |
| 412 | return 0; | 411 | return; |
| 413 | } | 412 | } |
| 414 | } | 413 | } |
| 415 | seq_set_overflow(m); | 414 | seq_set_overflow(m); |
| 416 | return -1; | ||
| 417 | } | 415 | } |
| 418 | EXPORT_SYMBOL(seq_vprintf); | 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 | va_list args; | 420 | va_list args; |
| 424 | 421 | ||
| 425 | va_start(args, f); | 422 | va_start(args, f); |
| 426 | ret = seq_vprintf(m, f, args); | 423 | seq_vprintf(m, f, args); |
| 427 | va_end(args); | 424 | va_end(args); |
| 428 | |||
| 429 | return ret; | ||
| 430 | } | 425 | } |
| 431 | EXPORT_SYMBOL(seq_printf); | 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 | EXPORT_SYMBOL(seq_open_private); | 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) { | 664 | if (m->count >= m->size) |
| 670 | m->buf[m->count++] = c; | 665 | return; |
| 671 | return 0; | 666 | |
| 672 | } | 667 | m->buf[m->count++] = c; |
| 673 | return -1; | ||
| 674 | } | 668 | } |
| 675 | EXPORT_SYMBOL(seq_putc); | 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 | int len = strlen(s); | 673 | int len = strlen(s); |
| 680 | if (m->count + len < m->size) { | 674 | |
| 681 | memcpy(m->buf + m->count, s, len); | 675 | if (m->count + len >= m->size) { |
| 682 | m->count += len; | 676 | seq_set_overflow(m); |
| 683 | return 0; | 677 | return; |
| 684 | } | 678 | } |
| 685 | seq_set_overflow(m); | 679 | memcpy(m->buf + m->count, s, len); |
| 686 | return -1; | 680 | m->count += len; |
| 687 | } | 681 | } |
| 688 | EXPORT_SYMBOL(seq_puts); | 682 | EXPORT_SYMBOL(seq_puts); |
| 689 | 683 | ||
| @@ -694,8 +688,8 @@ EXPORT_SYMBOL(seq_puts); · 4 unmodified lines | |||
| 694 | * This routine is very quick when you show lots of numbers. | 688 | * This routine is very quick when you show lots of numbers. |
| 695 | * In usual cases, it will be better to use seq_printf(). It's easier to read. | 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, | 691 | void seq_put_decimal_ull(struct seq_file *m, char delimiter, |
| 698 | unsigned long long num) | 692 | unsigned long long num) |
| 699 | { | 693 | { |
| 700 | int len; | 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 | if (num < 10) { | 702 | if (num < 10) { |
| 709 | m->buf[m->count++] = num + '0'; | 703 | m->buf[m->count++] = num + '0'; |
| 710 | return 0; | 704 | return; |
| 711 | } | 705 | } |
| 712 | 706 | ||
| 713 | len = num_to_str(m->buf + m->count, m->size - m->count, num); | 707 | len = num_to_str(m->buf + m->count, m->size - m->count, num); |
| 714 | if (!len) | 708 | if (!len) |
| 715 | goto overflow; | 709 | goto overflow; |
| 716 | m->count += len; | 710 | m->count += len; |
| 717 | return 0; | 711 | return; |
| 712 | |||
| 718 | overflow: | 713 | overflow: |
| 719 | seq_set_overflow(m); | 714 | seq_set_overflow(m); |
| 720 | return -1; | ||
| 721 | } | 715 | } |
| 722 | EXPORT_SYMBOL(seq_put_decimal_ull); | 716 | EXPORT_SYMBOL(seq_put_decimal_ull); |
| 723 | 717 | ||
| 724 | int seq_put_decimal_ll(struct seq_file *m, char delimiter, | 718 | void seq_put_decimal_ll(struct seq_file *m, char delimiter, long long num) |
| 725 | long long num) | ||
| 726 | { | 719 | { |
| 727 | if (num < 0) { | 720 | if (num < 0) { |
| 728 | if (m->count + 3 >= m->size) { | 721 | if (m->count + 3 >= m->size) { |
| 729 | seq_set_overflow(m); | 722 | seq_set_overflow(m); |
| 730 | return -1; | 723 | return; |
| 731 | } | 724 | } |
| 732 | if (delimiter) | 725 | if (delimiter) |
| 733 | m->buf[m->count++] = delimiter; | 726 | m->buf[m->count++] = delimiter; |
| 734 | num = -num; | 727 | num = -num; |
| 735 | delimiter = '-'; | 728 | delimiter = '-'; |
| 736 | } | 729 | } |
| 737 | return seq_put_decimal_ull(m, delimiter, num); | 730 | seq_put_decimal_ull(m, delimiter, num); |
| 738 | |||
| 739 | } | 731 | } |
| 740 | EXPORT_SYMBOL(seq_put_decimal_ll); | 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 | ssize_t seq_read(struct file *, char __user *, size_t, loff_t *); | 114 | ssize_t seq_read(struct file *, char __user *, size_t, loff_t *); |
| 115 | loff_t seq_lseek(struct file *, loff_t, int); | 115 | loff_t seq_lseek(struct file *, loff_t, int); |
| 116 | int seq_release(struct inode *, struct file *); | 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 | int seq_write(struct seq_file *seq, const void *data, size_t len); | 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 *, ...); | 119 | __printf(2, 0) |
| 123 | __printf(2, 0) int seq_vprintf(struct seq_file *, const char *, va_list args); | 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 | void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type, | 130 | void seq_hex_dump(struct seq_file *m, const char *prefix_str, int prefix_type, |
| 126 | int rowsize, int groupsize, const void *buf, size_t len, | 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 | void *__seq_open_private(struct file *, const struct seq_operations *, int); | 143 | void *__seq_open_private(struct file *, const struct seq_operations *, int); |
| 139 | int seq_open_private(struct file *, const struct seq_operations *, int); | 144 | int seq_open_private(struct file *, const struct seq_operations *, int); |
| 140 | int seq_release_private(struct inode *, struct file *); | 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 | static inline struct user_namespace *seq_user_ns(struct seq_file *seq) | 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 | const char __user *const __user *argv, | 885 | const char __user *const __user *argv, |
| 886 | const char __user *const __user *envp, int flags); | 886 | const char __user *const __user *envp, int flags); |
| 887 | 887 | ||
| 888 | asmlinkage long sys_membarrier(int cmd, int flags); | ||
| 889 | |||
| 888 | #endif | 890 | #endif |
| @@ -709,9 +709,11 @@ __SYSCALL(__NR_memfd_create, sys_memfd_create) · 708 unmodified lines | |||
| 709 | __SYSCALL(__NR_bpf, sys_bpf) | 709 | __SYSCALL(__NR_bpf, sys_bpf) |
| 710 | #define __NR_execveat 281 | 710 | #define __NR_execveat 281 |
| 711 | __SC_COMP(__NR_execveat, sys_execveat, compat_sys_execveat) | 711 | __SC_COMP(__NR_execveat, sys_execveat, compat_sys_execveat) |
| 712 | #define __NR_membarrier 282 | ||
| 713 | __SYSCALL(__NR_membarrier, sys_membarrier) | ||
| 712 | 714 | ||
| 713 | #undef __NR_syscalls | 715 | #undef __NR_syscalls |
| 714 | #define __NR_syscalls 282 | 716 | #define __NR_syscalls 283 |
| 715 | 717 | ||
| 716 | /* | 718 | /* |
| 717 | * All syscalls below here should go away really, | 719 | * All syscalls below here should go away really, |
| @@ -252,6 +252,7 @@ header-y += mdio.h · 251 unmodified lines | |||
| 252 | header-y += media.h | 252 | header-y += media.h |
| 253 | header-y += media-bus-format.h | 253 | header-y += media-bus-format.h |
| 254 | header-y += mei.h | 254 | header-y += mei.h |
| 255 | header-y += membarrier.h | ||
| 255 | header-y += memfd.h | 256 | header-y += memfd.h |
| 256 | header-y += mempolicy.h | 257 | header-y += mempolicy.h |
| 257 | header-y += meye.h | 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 | bugs/quirks. Disable this only if your target machine is | 1602 | bugs/quirks. Disable this only if your target machine is |
| 1603 | unaffected by PCI quirks. | 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 | config EMBEDDED | 1617 | config EMBEDDED |
| 1606 | bool "Embedded system" | 1618 | bool "Embedded system" |
| 1607 | option allnoconfig_y | 1619 | option allnoconfig_y |
| @@ -100,6 +100,7 @@ obj-$(CONFIG_CRASH_DUMP) += crash_dump.o · 99 unmodified lines | |||
| 100 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o | 100 | obj-$(CONFIG_JUMP_LABEL) += jump_label.o |
| 101 | obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o | 101 | obj-$(CONFIG_CONTEXT_TRACKING) += context_tracking.o |
| 102 | obj-$(CONFIG_TORTURE_TEST) += torture.o | 102 | obj-$(CONFIG_TORTURE_TEST) += torture.o |
| 103 | obj-$(CONFIG_MEMBARRIER) += membarrier.o | ||
| 103 | 104 | ||
| 104 | obj-$(CONFIG_HAS_IOMEM) += memremap.o | 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 | /* execveat */ | 246 | /* execveat */ |
| 247 | cond_syscall(sys_execveat); | 247 | cond_syscall(sys_execveat); |
| 248 | |||
| 249 | /* membarrier */ | ||
| 250 | cond_syscall(sys_membarrier); | ||
| @@ -15,6 +15,7 @@ · 14 unmodified lines | |||
| 15 | #include <linux/mm.h> | 15 | #include <linux/mm.h> |
| 16 | #include <linux/vmalloc.h> | 16 | #include <linux/vmalloc.h> |
| 17 | #include <asm/fixmap.h> | 17 | #include <asm/fixmap.h> |
| 18 | #include <asm/early_ioremap.h> | ||
| 18 | 19 | ||
| 19 | #ifdef CONFIG_MMU | 20 | #ifdef CONFIG_MMU |
| 20 | static int early_ioremap_debug __initdata; | 21 | static int early_ioremap_debug __initdata; |
| @@ -86,7 +86,7 @@ static void write_cert(X509 *x509) · 85 unmodified lines | |||
| 86 | ERR(!wb, "%s", cert_dst); | 86 | ERR(!wb, "%s", cert_dst); |
| 87 | } | 87 | } |
| 88 | X509_NAME_oneline(X509_get_subject_name(x509), buf, sizeof(buf)); | 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 | if (kbuild_verbose) | 90 | if (kbuild_verbose) |
| 91 | fprintf(stderr, "Extracted cert: %s\n", buf); | 91 | fprintf(stderr, "Extracted cert: %s\n", buf); |
| 92 | } | 92 | } |
| @@ -6,6 +6,7 @@ TARGETS += firmware · 5 unmodified lines | |||
| 6 | TARGETS += ftrace | 6 | TARGETS += ftrace |
| 7 | TARGETS += futex | 7 | TARGETS += futex |
| 8 | TARGETS += kcmp | 8 | TARGETS += kcmp |
| 9 | TARGETS += membarrier | ||
| 9 | TARGETS += memfd | 10 | TARGETS += memfd |
| 10 | TARGETS += memory-hotplug | 11 | TARGETS += memory-hotplug |
| 11 | TARGETS += mount | 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 | } | ||