|
@@ -465,6 +465,40 @@ void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
|
|
|
* Character device to read and clear the MCE log.
|
|
|
*/
|
|
|
|
|
|
+static DEFINE_SPINLOCK(mce_state_lock);
|
|
|
+static int open_count; /* #times opened */
|
|
|
+static int open_exclu; /* already open exclusive? */
|
|
|
+
|
|
|
+static int mce_open(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ spin_lock(&mce_state_lock);
|
|
|
+
|
|
|
+ if (open_exclu || (open_count && (file->f_flags & O_EXCL))) {
|
|
|
+ spin_unlock(&mce_state_lock);
|
|
|
+ return -EBUSY;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (file->f_flags & O_EXCL)
|
|
|
+ open_exclu = 1;
|
|
|
+ open_count++;
|
|
|
+
|
|
|
+ spin_unlock(&mce_state_lock);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int mce_release(struct inode *inode, struct file *file)
|
|
|
+{
|
|
|
+ spin_lock(&mce_state_lock);
|
|
|
+
|
|
|
+ open_count--;
|
|
|
+ open_exclu = 0;
|
|
|
+
|
|
|
+ spin_unlock(&mce_state_lock);
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
static void collect_tscs(void *data)
|
|
|
{
|
|
|
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
|
|
|
}
|
|
|
|
|
|
static const struct file_operations mce_chrdev_ops = {
|
|
|
+ .open = mce_open,
|
|
|
+ .release = mce_release,
|
|
|
.read = mce_read,
|
|
|
.ioctl = mce_ioctl,
|
|
|
};
|