Test patch for salinfo record injection

From: Keith Owens <kaos_at_sgi.com>
Date: 2005-12-01 15:11:26
This patch allows testing of salinfo record processing by injecting
records into the kernel.  It is not for inclusion in the base kernel,
there is no validation of the input record format so it is all too easy
to oops the kernel and/or prom.  Against 2.6.15-rc3, although salinfo.c
has not changed for some time.  Use by

  cat /var/log/salinfo/raw/2005-11-20-22_27_24-cpu0-mca.0 > /proc/sal/mca/inject

Index: linux/arch/ia64/kernel/salinfo.c
===================================================================
--- linux.orig/arch/ia64/kernel/salinfo.c	2005-12-01 13:19:38.859297686 +1100
+++ linux/arch/ia64/kernel/salinfo.c	2005-12-01 15:01:41.967970272 +1100
@@ -76,7 +76,7 @@ static char *salinfo_log_name[] = {
 static struct proc_dir_entry *salinfo_proc_entries[
 	ARRAY_SIZE(salinfo_entries) +			/* /proc/sal/bus_lock */
 	ARRAY_SIZE(salinfo_log_name) +			/* /proc/sal/{mca,...} */
-	(2 * ARRAY_SIZE(salinfo_log_name)) +		/* /proc/sal/mca/{event,data} */
+	(3 * ARRAY_SIZE(salinfo_log_name)) +		/* /proc/sal/mca/{event,data,inject} */
 	1];						/* /proc/sal */
 
 /* Some records we get ourselves, some are accessed as saved data in buffers
@@ -144,6 +144,7 @@ struct salinfo_data {
 	u8			padding;
 	int			cpu_check;	/* next CPU to check */
 	struct salinfo_data_saved data_saved[5];/* save last 5 records from mca.c, must be < 255 */
+	struct salinfo_data_saved inject;	/* data about injected record for testing */
 };
 
 static struct salinfo_data salinfo_data[ARRAY_SIZE(salinfo_log_name)];
@@ -241,6 +242,90 @@ salinfo_log_wakeup(int type, u8 *buffer,
 	}
 }
 
+/* The /proc/sal/{mca,..}/inject files are write only.  They allow user space
+ * to inject records of each type and have them processed as if the record was
+ * generated by SAL.  A record to be injected is written in raw format to the
+ * relevant inject file and stored via the salinfo_data.inject field.  When the
+ * inject file is closed, the record is processed as if it came from SAL,
+ * including driving the event and data files.
+ *
+ * Because this is a testing only patch, no verification is done on the record
+ * format, GIGO applies.  Multiple programs doing injection at the same time
+ * will create corrupted records and probably oops the kernel.  The records
+ * appear to come from various cpus, depending on which cpu the injection code
+ * runs on.  Seeking on the inject file is not supported, this code only
+ * handles sequential write.
+ */
+
+static DECLARE_MUTEX(inject_sem);
+
+static int
+salinfo_inject_open(struct inode *inode, struct file *file)
+{
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+	return 0;
+}
+
+static int
+salinfo_inject_release(struct inode *inode, struct file *file)
+{
+	struct proc_dir_entry *entry = PDE(inode);
+	struct salinfo_data *data = entry->data;
+	int irq_safe = data->type != SAL_INFO_TYPE_MCA;
+	down(&inject_sem);
+	if (!data->inject.size) {
+		vfree(data->inject.buffer);
+		data->inject.id = 0;
+	} else {
+		salinfo_log_wakeup(data->type, data->inject.buffer, data->inject.size, irq_safe);
+	}
+	up(&inject_sem);
+	return 0;
+}
+
+static ssize_t
+salinfo_inject_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+{
+	struct inode *inode = file->f_dentry->d_inode;
+	struct proc_dir_entry *entry = PDE(inode);
+	struct salinfo_data *data = entry->data;
+	int ret = 0;
+	down(&inject_sem);
+	/* Hack: reuse data->inject.id to hold the physical size of the buffer */
+	if (*ppos + count > data->inject.id) {
+		u64 new_size = *ppos + count;
+		u8* new_buffer;
+		new_buffer = vmalloc(new_size);
+		if (!new_buffer) {
+			ret = -ENOMEM;
+		} else {
+			memcpy(new_buffer, data->inject.buffer, data->inject.size);
+			vfree(data->inject.buffer);
+			data->inject.buffer = new_buffer;
+			data->inject.id = new_size;
+		}
+	}
+	if (!ret)
+		if ((ret = copy_from_user(data->inject.buffer + *ppos, buffer, count)))
+			ret = -EFAULT;
+
+	up(&inject_sem);
+	if (ret) {
+		return ret;
+	} else {
+		*ppos += count;
+		data->inject.size = *ppos;
+		return count;
+	}
+}
+
+static struct file_operations salinfo_inject_fops = {
+	.open    = salinfo_inject_open,
+	.release = salinfo_inject_release,
+	.write   = salinfo_inject_write,
+};
+
 /* Check for outstanding MCA/INIT records every minute (arbitrary) */
 #define SALINFO_TIMER_DELAY (60*HZ)
 static struct timer_list salinfo_timer;
@@ -410,6 +495,7 @@ salinfo_log_new_read(int cpu, struct sal
 	int saved_size = ARRAY_SIZE(data->data_saved);
 
 	data->saved_num = 0;
+	down(&inject_sem);
 	spin_lock_irqsave(&data_saved_lock, flags);
 retry:
 	for (i = 0, data_saved = data->data_saved; i < saved_size; ++i, ++data_saved) {
@@ -428,6 +514,7 @@ retry:
 		}
 	}
 	spin_unlock_irqrestore(&data_saved_lock, flags);
+	up(&inject_sem);
 
 	if (!data->saved_num)
 		call_on_cpu(cpu, salinfo_log_read_cpu, data);
@@ -590,6 +677,13 @@ salinfo_init(void)
 		entry->proc_fops = &salinfo_data_fops;
 		*sdir++ = entry;
 
+		entry = create_proc_entry("inject", S_IWUSR, dir);
+		if (!entry)
+			continue;
+		entry->data = data;
+		entry->proc_fops = &salinfo_inject_fops;
+		*sdir++ = entry;
+
 		/* we missed any events before now */
 		online = 0;
 		for_each_online_cpu(j) {

-
To unsubscribe from this list: send the line "unsubscribe linux-ia64" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Received on Thu Dec 01 15:12:12 2005

This archive was generated by hypermail 2.1.8 : 2005-12-01 15:12:18 EST