Merge branch 'akpm' (patches from Andrew)
Merge more updates from Andrew Morton: - the rest of MM - KASAN updates - procfs updates - exit, fork updates - printk updates - lib/ updates - radix-tree testsuite updates - checkpatch updates - kprobes updates - a few other misc bits * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (162 commits) samples/kprobes: print out the symbol name for the hooks samples/kprobes: add a new module parameter kprobes: add the "tls" argument for j_do_fork init/main.c: simplify initcall_blacklisted() fs/efs/super.c: fix return value checkpatch: improve --git <commit-count> shortcut checkpatch: reduce number of `git log` calls with --git checkpatch: add support to check already applied git commits checkpatch: add --list-types to show message types to show or ignore checkpatch: advertise the --fix and --fix-inplace options more checkpatch: whine about ACCESS_ONCE checkpatch: add test for keywords not starting on tabstops checkpatch: improve CONSTANT_COMPARISON test for structure members checkpatch: add PREFER_IS_ENABLED test lib/GCD.c: use binary GCD algorithm instead of Euclidean radix-tree: free up the bottom bit of exceptional entries for reuse dax: move RADIX_DAX_ definitions to dax.c radix-tree: make radix_tree_descend() more useful radix-tree: introduce radix_tree_replace_clear_tags() radix-tree: tidy up __radix_tree_create() ...
This commit is contained in:
@@ -746,7 +746,7 @@ void do_exit(long code)
|
||||
disassociate_ctty(1);
|
||||
exit_task_namespaces(tsk);
|
||||
exit_task_work(tsk);
|
||||
exit_thread();
|
||||
exit_thread(tsk);
|
||||
|
||||
/*
|
||||
* Flush inherited counters to the parent - before the parent
|
||||
|
@@ -699,6 +699,26 @@ void __mmdrop(struct mm_struct *mm)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(__mmdrop);
|
||||
|
||||
static inline void __mmput(struct mm_struct *mm)
|
||||
{
|
||||
VM_BUG_ON(atomic_read(&mm->mm_users));
|
||||
|
||||
uprobe_clear_state(mm);
|
||||
exit_aio(mm);
|
||||
ksm_exit(mm);
|
||||
khugepaged_exit(mm); /* must run before exit_mmap */
|
||||
exit_mmap(mm);
|
||||
set_mm_exe_file(mm, NULL);
|
||||
if (!list_empty(&mm->mmlist)) {
|
||||
spin_lock(&mmlist_lock);
|
||||
list_del(&mm->mmlist);
|
||||
spin_unlock(&mmlist_lock);
|
||||
}
|
||||
if (mm->binfmt)
|
||||
module_put(mm->binfmt->module);
|
||||
mmdrop(mm);
|
||||
}
|
||||
|
||||
/*
|
||||
* Decrement the use count and release all resources for an mm.
|
||||
*/
|
||||
@@ -706,25 +726,25 @@ void mmput(struct mm_struct *mm)
|
||||
{
|
||||
might_sleep();
|
||||
|
||||
if (atomic_dec_and_test(&mm->mm_users)) {
|
||||
uprobe_clear_state(mm);
|
||||
exit_aio(mm);
|
||||
ksm_exit(mm);
|
||||
khugepaged_exit(mm); /* must run before exit_mmap */
|
||||
exit_mmap(mm);
|
||||
set_mm_exe_file(mm, NULL);
|
||||
if (!list_empty(&mm->mmlist)) {
|
||||
spin_lock(&mmlist_lock);
|
||||
list_del(&mm->mmlist);
|
||||
spin_unlock(&mmlist_lock);
|
||||
}
|
||||
if (mm->binfmt)
|
||||
module_put(mm->binfmt->module);
|
||||
mmdrop(mm);
|
||||
}
|
||||
if (atomic_dec_and_test(&mm->mm_users))
|
||||
__mmput(mm);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mmput);
|
||||
|
||||
static void mmput_async_fn(struct work_struct *work)
|
||||
{
|
||||
struct mm_struct *mm = container_of(work, struct mm_struct, async_put_work);
|
||||
__mmput(mm);
|
||||
}
|
||||
|
||||
void mmput_async(struct mm_struct *mm)
|
||||
{
|
||||
if (atomic_dec_and_test(&mm->mm_users)) {
|
||||
INIT_WORK(&mm->async_put_work, mmput_async_fn);
|
||||
schedule_work(&mm->async_put_work);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set_mm_exe_file - change a reference to the mm's executable file
|
||||
*
|
||||
@@ -1470,7 +1490,7 @@ static struct task_struct *copy_process(unsigned long clone_flags,
|
||||
pid = alloc_pid(p->nsproxy->pid_ns_for_children);
|
||||
if (IS_ERR(pid)) {
|
||||
retval = PTR_ERR(pid);
|
||||
goto bad_fork_cleanup_io;
|
||||
goto bad_fork_cleanup_thread;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1632,6 +1652,8 @@ bad_fork_cancel_cgroup:
|
||||
bad_fork_free_pid:
|
||||
if (pid != &init_struct_pid)
|
||||
free_pid(pid);
|
||||
bad_fork_cleanup_thread:
|
||||
exit_thread(p);
|
||||
bad_fork_cleanup_io:
|
||||
if (p->io_context)
|
||||
exit_io_context(p);
|
||||
|
@@ -139,12 +139,7 @@ void irq_domain_remove(struct irq_domain *domain)
|
||||
{
|
||||
mutex_lock(&irq_domain_mutex);
|
||||
|
||||
/*
|
||||
* radix_tree_delete() takes care of destroying the root
|
||||
* node when all entries are removed. Shout if there are
|
||||
* any mappings left.
|
||||
*/
|
||||
WARN_ON(domain->revmap_tree.height);
|
||||
WARN_ON(!radix_tree_empty(&domain->revmap_tree));
|
||||
|
||||
list_del(&domain->link);
|
||||
|
||||
|
@@ -893,6 +893,7 @@ void crash_kexec(struct pt_regs *regs)
|
||||
old_cpu = atomic_cmpxchg(&panic_cpu, PANIC_CPU_INVALID, this_cpu);
|
||||
if (old_cpu == PANIC_CPU_INVALID) {
|
||||
/* This is the 1st CPU which comes here, so go ahead. */
|
||||
printk_nmi_flush_on_panic();
|
||||
__crash_kexec(regs);
|
||||
|
||||
/*
|
||||
|
@@ -160,8 +160,10 @@ void panic(const char *fmt, ...)
|
||||
*
|
||||
* Bypass the panic_cpu check and call __crash_kexec directly.
|
||||
*/
|
||||
if (!crash_kexec_post_notifiers)
|
||||
if (!crash_kexec_post_notifiers) {
|
||||
printk_nmi_flush_on_panic();
|
||||
__crash_kexec(NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* Note smp_send_stop is the usual smp shutdown function, which
|
||||
@@ -176,6 +178,8 @@ void panic(const char *fmt, ...)
|
||||
*/
|
||||
atomic_notifier_call_chain(&panic_notifier_list, 0, buf);
|
||||
|
||||
/* Call flush even twice. It tries harder with a single online CPU */
|
||||
printk_nmi_flush_on_panic();
|
||||
kmsg_dump(KMSG_DUMP_PANIC);
|
||||
|
||||
/*
|
||||
|
@@ -1,2 +1,3 @@
|
||||
obj-y = printk.o
|
||||
obj-$(CONFIG_PRINTK_NMI) += nmi.o
|
||||
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
|
||||
|
57
kernel/printk/internal.h
Normal file
57
kernel/printk/internal.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* internal.h - printk internal definitions
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <linux/percpu.h>
|
||||
|
||||
typedef __printf(1, 0) int (*printk_func_t)(const char *fmt, va_list args);
|
||||
|
||||
int __printf(1, 0) vprintk_default(const char *fmt, va_list args);
|
||||
|
||||
#ifdef CONFIG_PRINTK_NMI
|
||||
|
||||
extern raw_spinlock_t logbuf_lock;
|
||||
|
||||
/*
|
||||
* printk() could not take logbuf_lock in NMI context. Instead,
|
||||
* it temporary stores the strings into a per-CPU buffer.
|
||||
* The alternative implementation is chosen transparently
|
||||
* via per-CPU variable.
|
||||
*/
|
||||
DECLARE_PER_CPU(printk_func_t, printk_func);
|
||||
static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
|
||||
{
|
||||
return this_cpu_read(printk_func)(fmt, args);
|
||||
}
|
||||
|
||||
extern atomic_t nmi_message_lost;
|
||||
static inline int get_nmi_message_lost(void)
|
||||
{
|
||||
return atomic_xchg(&nmi_message_lost, 0);
|
||||
}
|
||||
|
||||
#else /* CONFIG_PRINTK_NMI */
|
||||
|
||||
static inline __printf(1, 0) int vprintk_func(const char *fmt, va_list args)
|
||||
{
|
||||
return vprintk_default(fmt, args);
|
||||
}
|
||||
|
||||
static inline int get_nmi_message_lost(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PRINTK_NMI */
|
260
kernel/printk/nmi.c
Normal file
260
kernel/printk/nmi.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* nmi.c - Safe printk in NMI context
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/preempt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/debug_locks.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/irq_work.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/*
|
||||
* printk() could not take logbuf_lock in NMI context. Instead,
|
||||
* it uses an alternative implementation that temporary stores
|
||||
* the strings into a per-CPU buffer. The content of the buffer
|
||||
* is later flushed into the main ring buffer via IRQ work.
|
||||
*
|
||||
* The alternative implementation is chosen transparently
|
||||
* via @printk_func per-CPU variable.
|
||||
*
|
||||
* The implementation allows to flush the strings also from another CPU.
|
||||
* There are situations when we want to make sure that all buffers
|
||||
* were handled or when IRQs are blocked.
|
||||
*/
|
||||
DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
|
||||
static int printk_nmi_irq_ready;
|
||||
atomic_t nmi_message_lost;
|
||||
|
||||
#define NMI_LOG_BUF_LEN ((1 << CONFIG_NMI_LOG_BUF_SHIFT) - \
|
||||
sizeof(atomic_t) - sizeof(struct irq_work))
|
||||
|
||||
struct nmi_seq_buf {
|
||||
atomic_t len; /* length of written data */
|
||||
struct irq_work work; /* IRQ work that flushes the buffer */
|
||||
unsigned char buffer[NMI_LOG_BUF_LEN];
|
||||
};
|
||||
static DEFINE_PER_CPU(struct nmi_seq_buf, nmi_print_seq);
|
||||
|
||||
/*
|
||||
* Safe printk() for NMI context. It uses a per-CPU buffer to
|
||||
* store the message. NMIs are not nested, so there is always only
|
||||
* one writer running. But the buffer might get flushed from another
|
||||
* CPU, so we need to be careful.
|
||||
*/
|
||||
static int vprintk_nmi(const char *fmt, va_list args)
|
||||
{
|
||||
struct nmi_seq_buf *s = this_cpu_ptr(&nmi_print_seq);
|
||||
int add = 0;
|
||||
size_t len;
|
||||
|
||||
again:
|
||||
len = atomic_read(&s->len);
|
||||
|
||||
if (len >= sizeof(s->buffer)) {
|
||||
atomic_inc(&nmi_message_lost);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Make sure that all old data have been read before the buffer was
|
||||
* reseted. This is not needed when we just append data.
|
||||
*/
|
||||
if (!len)
|
||||
smp_rmb();
|
||||
|
||||
add = vsnprintf(s->buffer + len, sizeof(s->buffer) - len, fmt, args);
|
||||
|
||||
/*
|
||||
* Do it once again if the buffer has been flushed in the meantime.
|
||||
* Note that atomic_cmpxchg() is an implicit memory barrier that
|
||||
* makes sure that the data were written before updating s->len.
|
||||
*/
|
||||
if (atomic_cmpxchg(&s->len, len, len + add) != len)
|
||||
goto again;
|
||||
|
||||
/* Get flushed in a more safe context. */
|
||||
if (add && printk_nmi_irq_ready) {
|
||||
/* Make sure that IRQ work is really initialized. */
|
||||
smp_rmb();
|
||||
irq_work_queue(&s->work);
|
||||
}
|
||||
|
||||
return add;
|
||||
}
|
||||
|
||||
/*
|
||||
* printk one line from the temporary buffer from @start index until
|
||||
* and including the @end index.
|
||||
*/
|
||||
static void print_nmi_seq_line(struct nmi_seq_buf *s, int start, int end)
|
||||
{
|
||||
const char *buf = s->buffer + start;
|
||||
|
||||
/*
|
||||
* The buffers are flushed in NMI only on panic. The messages must
|
||||
* go only into the ring buffer at this stage. Consoles will get
|
||||
* explicitly called later when a crashdump is not generated.
|
||||
*/
|
||||
if (in_nmi())
|
||||
printk_deferred("%.*s", (end - start) + 1, buf);
|
||||
else
|
||||
printk("%.*s", (end - start) + 1, buf);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Flush data from the associated per_CPU buffer. The function
|
||||
* can be called either via IRQ work or independently.
|
||||
*/
|
||||
static void __printk_nmi_flush(struct irq_work *work)
|
||||
{
|
||||
static raw_spinlock_t read_lock =
|
||||
__RAW_SPIN_LOCK_INITIALIZER(read_lock);
|
||||
struct nmi_seq_buf *s = container_of(work, struct nmi_seq_buf, work);
|
||||
unsigned long flags;
|
||||
size_t len, size;
|
||||
int i, last_i;
|
||||
|
||||
/*
|
||||
* The lock has two functions. First, one reader has to flush all
|
||||
* available message to make the lockless synchronization with
|
||||
* writers easier. Second, we do not want to mix messages from
|
||||
* different CPUs. This is especially important when printing
|
||||
* a backtrace.
|
||||
*/
|
||||
raw_spin_lock_irqsave(&read_lock, flags);
|
||||
|
||||
i = 0;
|
||||
more:
|
||||
len = atomic_read(&s->len);
|
||||
|
||||
/*
|
||||
* This is just a paranoid check that nobody has manipulated
|
||||
* the buffer an unexpected way. If we printed something then
|
||||
* @len must only increase.
|
||||
*/
|
||||
if (i && i >= len)
|
||||
pr_err("printk_nmi_flush: internal error: i=%d >= len=%zu\n",
|
||||
i, len);
|
||||
|
||||
if (!len)
|
||||
goto out; /* Someone else has already flushed the buffer. */
|
||||
|
||||
/* Make sure that data has been written up to the @len */
|
||||
smp_rmb();
|
||||
|
||||
size = min(len, sizeof(s->buffer));
|
||||
last_i = i;
|
||||
|
||||
/* Print line by line. */
|
||||
for (; i < size; i++) {
|
||||
if (s->buffer[i] == '\n') {
|
||||
print_nmi_seq_line(s, last_i, i);
|
||||
last_i = i + 1;
|
||||
}
|
||||
}
|
||||
/* Check if there was a partial line. */
|
||||
if (last_i < size) {
|
||||
print_nmi_seq_line(s, last_i, size - 1);
|
||||
pr_cont("\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that nothing has got added in the meantime and truncate
|
||||
* the buffer. Note that atomic_cmpxchg() is an implicit memory
|
||||
* barrier that makes sure that the data were copied before
|
||||
* updating s->len.
|
||||
*/
|
||||
if (atomic_cmpxchg(&s->len, len, 0) != len)
|
||||
goto more;
|
||||
|
||||
out:
|
||||
raw_spin_unlock_irqrestore(&read_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* printk_nmi_flush - flush all per-cpu nmi buffers.
|
||||
*
|
||||
* The buffers are flushed automatically via IRQ work. This function
|
||||
* is useful only when someone wants to be sure that all buffers have
|
||||
* been flushed at some point.
|
||||
*/
|
||||
void printk_nmi_flush(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu)
|
||||
__printk_nmi_flush(&per_cpu(nmi_print_seq, cpu).work);
|
||||
}
|
||||
|
||||
/**
|
||||
* printk_nmi_flush_on_panic - flush all per-cpu nmi buffers when the system
|
||||
* goes down.
|
||||
*
|
||||
* Similar to printk_nmi_flush() but it can be called even in NMI context when
|
||||
* the system goes down. It does the best effort to get NMI messages into
|
||||
* the main ring buffer.
|
||||
*
|
||||
* Note that it could try harder when there is only one CPU online.
|
||||
*/
|
||||
void printk_nmi_flush_on_panic(void)
|
||||
{
|
||||
/*
|
||||
* Make sure that we could access the main ring buffer.
|
||||
* Do not risk a double release when more CPUs are up.
|
||||
*/
|
||||
if (in_nmi() && raw_spin_is_locked(&logbuf_lock)) {
|
||||
if (num_online_cpus() > 1)
|
||||
return;
|
||||
|
||||
debug_locks_off();
|
||||
raw_spin_lock_init(&logbuf_lock);
|
||||
}
|
||||
|
||||
printk_nmi_flush();
|
||||
}
|
||||
|
||||
void __init printk_nmi_init(void)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
struct nmi_seq_buf *s = &per_cpu(nmi_print_seq, cpu);
|
||||
|
||||
init_irq_work(&s->work, __printk_nmi_flush);
|
||||
}
|
||||
|
||||
/* Make sure that IRQ works are initialized before enabling. */
|
||||
smp_wmb();
|
||||
printk_nmi_irq_ready = 1;
|
||||
|
||||
/* Flush pending messages that did not have scheduled IRQ works. */
|
||||
printk_nmi_flush();
|
||||
}
|
||||
|
||||
void printk_nmi_enter(void)
|
||||
{
|
||||
this_cpu_write(printk_func, vprintk_nmi);
|
||||
}
|
||||
|
||||
void printk_nmi_exit(void)
|
||||
{
|
||||
this_cpu_write(printk_func, vprintk_default);
|
||||
}
|
@@ -55,6 +55,7 @@
|
||||
|
||||
#include "console_cmdline.h"
|
||||
#include "braille.h"
|
||||
#include "internal.h"
|
||||
|
||||
int console_printk[4] = {
|
||||
CONSOLE_LOGLEVEL_DEFAULT, /* console_loglevel */
|
||||
@@ -244,7 +245,7 @@ __packed __aligned(4)
|
||||
* within the scheduler's rq lock. It must be released before calling
|
||||
* console_unlock() or anything else that might wake up a process.
|
||||
*/
|
||||
static DEFINE_RAW_SPINLOCK(logbuf_lock);
|
||||
DEFINE_RAW_SPINLOCK(logbuf_lock);
|
||||
|
||||
#ifdef CONFIG_PRINTK
|
||||
DECLARE_WAIT_QUEUE_HEAD(log_wait);
|
||||
@@ -1616,6 +1617,7 @@ asmlinkage int vprintk_emit(int facility, int level,
|
||||
unsigned long flags;
|
||||
int this_cpu;
|
||||
int printed_len = 0;
|
||||
int nmi_message_lost;
|
||||
bool in_sched = false;
|
||||
/* cpu currently holding logbuf_lock in this function */
|
||||
static unsigned int logbuf_cpu = UINT_MAX;
|
||||
@@ -1666,6 +1668,15 @@ asmlinkage int vprintk_emit(int facility, int level,
|
||||
strlen(recursion_msg));
|
||||
}
|
||||
|
||||
nmi_message_lost = get_nmi_message_lost();
|
||||
if (unlikely(nmi_message_lost)) {
|
||||
text_len = scnprintf(textbuf, sizeof(textbuf),
|
||||
"BAD LUCK: lost %d message(s) from NMI context!",
|
||||
nmi_message_lost);
|
||||
printed_len += log_store(0, 2, LOG_PREFIX|LOG_NEWLINE, 0,
|
||||
NULL, 0, textbuf, text_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* The printf needs to come first; we need the syslog
|
||||
* prefix which might be passed-in as a parameter.
|
||||
@@ -1807,14 +1818,6 @@ int vprintk_default(const char *fmt, va_list args)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(vprintk_default);
|
||||
|
||||
/*
|
||||
* This allows printk to be diverted to another function per cpu.
|
||||
* This is useful for calling printk functions from within NMI
|
||||
* without worrying about race conditions that can lock up the
|
||||
* box.
|
||||
*/
|
||||
DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
|
||||
|
||||
/**
|
||||
* printk - print a kernel message
|
||||
* @fmt: format string
|
||||
@@ -1838,21 +1841,11 @@ DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
|
||||
*/
|
||||
asmlinkage __visible int printk(const char *fmt, ...)
|
||||
{
|
||||
printk_func_t vprintk_func;
|
||||
va_list args;
|
||||
int r;
|
||||
|
||||
va_start(args, fmt);
|
||||
|
||||
/*
|
||||
* If a caller overrides the per_cpu printk_func, then it needs
|
||||
* to disable preemption when calling printk(). Otherwise
|
||||
* the printk_func should be set to the default. No need to
|
||||
* disable preemption here.
|
||||
*/
|
||||
vprintk_func = this_cpu_read(printk_func);
|
||||
r = vprintk_func(fmt, args);
|
||||
|
||||
va_end(args);
|
||||
|
||||
return r;
|
||||
|
@@ -13,6 +13,7 @@
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/uuid.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/compat.h>
|
||||
|
||||
@@ -1117,9 +1118,8 @@ static ssize_t bin_uuid(struct file *file,
|
||||
|
||||
/* Only supports reads */
|
||||
if (oldval && oldlen) {
|
||||
char buf[40], *str = buf;
|
||||
unsigned char uuid[16];
|
||||
int i;
|
||||
char buf[UUID_STRING_LEN + 1];
|
||||
uuid_be uuid;
|
||||
|
||||
result = kernel_read(file, 0, buf, sizeof(buf) - 1);
|
||||
if (result < 0)
|
||||
@@ -1127,24 +1127,15 @@ static ssize_t bin_uuid(struct file *file,
|
||||
|
||||
buf[result] = '\0';
|
||||
|
||||
/* Convert the uuid to from a string to binary */
|
||||
for (i = 0; i < 16; i++) {
|
||||
result = -EIO;
|
||||
if (!isxdigit(str[0]) || !isxdigit(str[1]))
|
||||
goto out;
|
||||
|
||||
uuid[i] = (hex_to_bin(str[0]) << 4) |
|
||||
hex_to_bin(str[1]);
|
||||
str += 2;
|
||||
if (*str == '-')
|
||||
str++;
|
||||
}
|
||||
result = -EIO;
|
||||
if (uuid_be_to_bin(buf, &uuid))
|
||||
goto out;
|
||||
|
||||
if (oldlen > 16)
|
||||
oldlen = 16;
|
||||
|
||||
result = -EFAULT;
|
||||
if (copy_to_user(oldval, uuid, oldlen))
|
||||
if (copy_to_user(oldval, &uuid, oldlen))
|
||||
goto out;
|
||||
|
||||
copied = oldlen;
|
||||
|
Reference in New Issue
Block a user