diff options
author | Tim Hockin <thockin@google.com> | 2007-07-21 11:10:35 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-21 21:37:10 -0400 |
commit | f528e7ba28492e363a64c80c414ded4cadf48f89 (patch) | |
tree | 2bf7371d9d5594581cb0b6b9a9b85b651f7d7e28 /arch/x86_64/kernel/mce.c | |
parent | a5ba7971045a90a36cef8f7d5a3075600b475b74 (diff) |
x86_64: O_EXCL on /dev/mcelog
Background:
/dev/mcelog is a clear-on-read interface. It is currently possible for
multiple users to open and read() the device. Users are protected from
each other during any one read, but not across reads.
Description:
This patch adds support for O_EXCL to /dev/mcelog. If a user opens the
device with O_EXCL, no other user may open the device (EBUSY). Likewise,
any user that tries to open the device with O_EXCL while another user has
the device will fail (EBUSY).
Result:
Applications can get exclusive access to /dev/mcelog. Applications that
do not care will be unchanged.
Alternatives:
A simpler choice would be to only allow one open() at all, regardless of
O_EXCL.
Testing:
I wrote an application that opens /dev/mcelog with O_EXCL and observed
that any other app that tried to open /dev/mcelog would fail until the
exclusive app had closed the device.
Caveats:
None.
Signed-off-by: Tim Hockin <thockin@google.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Andi Kleen <ak@suse.de>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86_64/kernel/mce.c')
-rw-r--r-- | arch/x86_64/kernel/mce.c | 36 |
1 files changed, 36 insertions, 0 deletions
diff --git a/arch/x86_64/kernel/mce.c b/arch/x86_64/kernel/mce.c index f3fb8174559e..77fee481be4f 100644 --- a/arch/x86_64/kernel/mce.c +++ b/arch/x86_64/kernel/mce.c | |||
@@ -465,6 +465,40 @@ void __cpuinit mcheck_init(struct cpuinfo_x86 *c) | |||
465 | * Character device to read and clear the MCE log. | 465 | * Character device to read and clear the MCE log. |
466 | */ | 466 | */ |
467 | 467 | ||
468 | static DEFINE_SPINLOCK(mce_state_lock); | ||
469 | static int open_count; /* #times opened */ | ||
470 | static int open_exclu; /* already open exclusive? */ | ||
471 | |||
472 | static int mce_open(struct inode *inode, struct file *file) | ||
473 | { | ||
474 | spin_lock(&mce_state_lock); | ||
475 | |||
476 | if (open_exclu || (open_count && (file->f_flags & O_EXCL))) { | ||
477 | spin_unlock(&mce_state_lock); | ||
478 | return -EBUSY; | ||
479 | } | ||
480 | |||
481 | if (file->f_flags & O_EXCL) | ||
482 | open_exclu = 1; | ||
483 | open_count++; | ||
484 | |||
485 | spin_unlock(&mce_state_lock); | ||
486 | |||
487 | return 0; | ||
488 | } | ||
489 | |||
490 | static int mce_release(struct inode *inode, struct file *file) | ||
491 | { | ||
492 | spin_lock(&mce_state_lock); | ||
493 | |||
494 | open_count--; | ||
495 | open_exclu = 0; | ||
496 | |||
497 | spin_unlock(&mce_state_lock); | ||
498 | |||
499 | return 0; | ||
500 | } | ||
501 | |||
468 | static void collect_tscs(void *data) | 502 | static void collect_tscs(void *data) |
469 | { | 503 | { |
470 | unsigned long *cpu_tsc = (unsigned long *)data; | 504 | unsigned long *cpu_tsc = (unsigned long *)data; |
@@ -555,6 +589,8 @@ static int mce_ioctl(struct inode *i, struct file *f,unsigned int cmd, unsigned | |||
555 | } | 589 | } |
556 | 590 | ||
557 | static const struct file_operations mce_chrdev_ops = { | 591 | static const struct file_operations mce_chrdev_ops = { |
592 | .open = mce_open, | ||
593 | .release = mce_release, | ||
558 | .read = mce_read, | 594 | .read = mce_read, |
559 | .ioctl = mce_ioctl, | 595 | .ioctl = mce_ioctl, |
560 | }; | 596 | }; |