brintos

brintos / linux-shallow public Read only

0
0
Text · 20.6 KiB · bd5cecc Raw
862 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 *	character device driver for reading z/VM system service records4 *5 *6 *	Copyright IBM Corp. 2004, 20097 *	character device driver for reading z/VM system service records,8 *	Version 1.09 *	Author(s): Xenia Tkatschow <xenia@us.ibm.com>10 *		   Stefan Weinhuber <wein@de.ibm.com>11 *12 */13 14#define KMSG_COMPONENT "vmlogrdr"15#define pr_fmt(fmt) KMSG_COMPONENT ": " fmt16 17#include <linux/module.h>18#include <linux/init.h>19#include <linux/slab.h>20#include <linux/errno.h>21#include <linux/types.h>22#include <linux/interrupt.h>23#include <linux/spinlock.h>24#include <linux/atomic.h>25#include <linux/uaccess.h>26#include <asm/cpcmd.h>27#include <asm/debug.h>28#include <asm/ebcdic.h>29#include <net/iucv/iucv.h>30#include <linux/kmod.h>31#include <linux/cdev.h>32#include <linux/device.h>33#include <linux/string.h>34 35MODULE_AUTHOR36	("(C) 2004 IBM Corporation by Xenia Tkatschow (xenia@us.ibm.com)\n"37	 "                            Stefan Weinhuber (wein@de.ibm.com)");38MODULE_DESCRIPTION ("Character device driver for reading z/VM "39		    "system service records.");40MODULE_LICENSE("GPL");41 42 43/*44 * The size of the buffer for iucv data transfer is one page,45 * but in addition to the data we read from iucv we also46 * place an integer and some characters into that buffer,47 * so the maximum size for record data is a little less then48 * one page.49 */50#define NET_BUFFER_SIZE	(PAGE_SIZE - sizeof(int) - sizeof(FENCE))51 52/*53 * The elements that are concurrently accessed by bottom halves are54 * connection_established, iucv_path_severed, local_interrupt_buffer55 * and receive_ready. The first three can be protected by56 * priv_lock.  receive_ready is atomic, so it can be incremented and57 * decremented without holding a lock.58 * The variable dev_in_use needs to be protected by the lock, since59 * it's a flag used by open to make sure that the device is opened only60 * by one user at the same time.61 */62struct vmlogrdr_priv_t {63	char system_service[8];64	char internal_name[8];65	char recording_name[8];66	struct iucv_path *path;67	int connection_established;68	int iucv_path_severed;69	struct iucv_message local_interrupt_buffer;70	atomic_t receive_ready;71	int minor_num;72	char * buffer;73	char * current_position;74	int remaining;75	ulong residual_length;76	int buffer_free;77	int dev_in_use; /* 1: already opened, 0: not opened*/78	spinlock_t priv_lock;79	struct device  *device;80	struct device  *class_device;81	int autorecording;82	int autopurge;83};84 85 86/*87 * File operation structure for vmlogrdr devices88 */89static int vmlogrdr_open(struct inode *, struct file *);90static int vmlogrdr_release(struct inode *, struct file *);91static ssize_t vmlogrdr_read (struct file *filp, char __user *data,92			      size_t count, loff_t * ppos);93 94static const struct file_operations vmlogrdr_fops = {95	.owner   = THIS_MODULE,96	.open    = vmlogrdr_open,97	.release = vmlogrdr_release,98	.read    = vmlogrdr_read,99};100 101 102static void vmlogrdr_iucv_path_complete(struct iucv_path *, u8 *ipuser);103static void vmlogrdr_iucv_path_severed(struct iucv_path *, u8 *ipuser);104static void vmlogrdr_iucv_message_pending(struct iucv_path *,105					  struct iucv_message *);106 107 108static struct iucv_handler vmlogrdr_iucv_handler = {109	.path_complete	 = vmlogrdr_iucv_path_complete,110	.path_severed	 = vmlogrdr_iucv_path_severed,111	.message_pending = vmlogrdr_iucv_message_pending,112};113 114 115static DECLARE_WAIT_QUEUE_HEAD(conn_wait_queue);116static DECLARE_WAIT_QUEUE_HEAD(read_wait_queue);117 118/*119 * pointer to system service private structure120 * minor number 0 --> logrec121 * minor number 1 --> account122 * minor number 2 --> symptom123 */124 125static struct vmlogrdr_priv_t sys_ser[] = {126	{ .system_service = "*LOGREC ",127	  .internal_name  = "logrec",128	  .recording_name = "EREP",129	  .minor_num      = 0,130	  .buffer_free    = 1,131	  .priv_lock	  = __SPIN_LOCK_UNLOCKED(sys_ser[0].priv_lock),132	  .autorecording  = 1,133	  .autopurge      = 1,134	},135	{ .system_service = "*ACCOUNT",136	  .internal_name  = "account",137	  .recording_name = "ACCOUNT",138	  .minor_num      = 1,139	  .buffer_free    = 1,140	  .priv_lock	  = __SPIN_LOCK_UNLOCKED(sys_ser[1].priv_lock),141	  .autorecording  = 1,142	  .autopurge      = 1,143	},144	{ .system_service = "*SYMPTOM",145	  .internal_name  = "symptom",146	  .recording_name = "SYMPTOM",147	  .minor_num      = 2,148	  .buffer_free    = 1,149	  .priv_lock	  = __SPIN_LOCK_UNLOCKED(sys_ser[2].priv_lock),150	  .autorecording  = 1,151	  .autopurge      = 1,152	}153};154 155#define MAXMINOR  ARRAY_SIZE(sys_ser)156 157static char FENCE[] = {"EOR"};158static int vmlogrdr_major = 0;159static struct cdev  *vmlogrdr_cdev = NULL;160static int recording_class_AB;161 162 163static void vmlogrdr_iucv_path_complete(struct iucv_path *path, u8 *ipuser)164{165	struct vmlogrdr_priv_t * logptr = path->private;166 167	spin_lock(&logptr->priv_lock);168	logptr->connection_established = 1;169	spin_unlock(&logptr->priv_lock);170	wake_up(&conn_wait_queue);171}172 173 174static void vmlogrdr_iucv_path_severed(struct iucv_path *path, u8 *ipuser)175{176	struct vmlogrdr_priv_t * logptr = path->private;177	u8 reason = (u8) ipuser[8];178 179	pr_err("vmlogrdr: connection severed with reason %i\n", reason);180 181	iucv_path_sever(path, NULL);182	kfree(path);183	logptr->path = NULL;184 185	spin_lock(&logptr->priv_lock);186	logptr->connection_established = 0;187	logptr->iucv_path_severed = 1;188	spin_unlock(&logptr->priv_lock);189 190	wake_up(&conn_wait_queue);191	/* just in case we're sleeping waiting for a record */192	wake_up_interruptible(&read_wait_queue);193}194 195 196static void vmlogrdr_iucv_message_pending(struct iucv_path *path,197					  struct iucv_message *msg)198{199	struct vmlogrdr_priv_t * logptr = path->private;200 201	/*202	 * This function is the bottom half so it should be quick.203	 * Copy the external interrupt data into our local eib and increment204	 * the usage count205	 */206	spin_lock(&logptr->priv_lock);207	memcpy(&logptr->local_interrupt_buffer, msg, sizeof(*msg));208	atomic_inc(&logptr->receive_ready);209	spin_unlock(&logptr->priv_lock);210	wake_up_interruptible(&read_wait_queue);211}212 213 214static int vmlogrdr_get_recording_class_AB(void)215{216	static const char cp_command[] = "QUERY COMMAND RECORDING ";217	char cp_response[80];218	char *tail;219	int len,i;220 221	cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);222	len = strnlen(cp_response,sizeof(cp_response));223	// now the parsing224	tail=strnchr(cp_response,len,'=');225	if (!tail)226		return 0;227	tail++;228	if (!strncmp("ANY",tail,3))229		return 1;230	if (!strncmp("NONE",tail,4))231		return 0;232	/*233	 * expect comma separated list of classes here, if one of them234	 * is A or B return 1 otherwise 0235	 */236        for (i=tail-cp_response; i<len; i++)237		if ( cp_response[i]=='A' || cp_response[i]=='B' )238			return 1;239	return 0;240}241 242 243static int vmlogrdr_recording(struct vmlogrdr_priv_t * logptr,244			      int action, int purge)245{246 247	char cp_command[80];248	char cp_response[160];249	char *onoff, *qid_string;250	int rc;251 252	onoff = ((action == 1) ? "ON" : "OFF");253	qid_string = ((recording_class_AB == 1) ? " QID * " : "");254 255	/*256	 * The recording commands needs to be called with option QID257	 * for guests that have previlege classes A or B.258	 * Purging has to be done as separate step, because recording259	 * can't be switched on as long as records are on the queue.260	 * Doing both at the same time doesn't work.261	 */262	if (purge && (action == 1)) {263		memset(cp_command, 0x00, sizeof(cp_command));264		memset(cp_response, 0x00, sizeof(cp_response));265		snprintf(cp_command, sizeof(cp_command),266			 "RECORDING %s PURGE %s",267			 logptr->recording_name,268			 qid_string);269		cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);270	}271 272	memset(cp_command, 0x00, sizeof(cp_command));273	memset(cp_response, 0x00, sizeof(cp_response));274	snprintf(cp_command, sizeof(cp_command), "RECORDING %s %s %s",275		logptr->recording_name,276		onoff,277		qid_string);278	cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);279	/* The recording command will usually answer with 'Command complete'280	 * on success, but when the specific service was never connected281	 * before then there might be an additional informational message282	 * 'HCPCRC8072I Recording entry not found' before the283	 * 'Command complete'. So I use strstr rather then the strncmp.284	 */285	if (strstr(cp_response,"Command complete"))286		rc = 0;287	else288		rc = -EIO;289	/*290	 * If we turn recording off, we have to purge any remaining records291	 * afterwards, as a large number of queued records may impact z/VM292	 * performance.293	 */294	if (purge && (action == 0)) {295		memset(cp_command, 0x00, sizeof(cp_command));296		memset(cp_response, 0x00, sizeof(cp_response));297		snprintf(cp_command, sizeof(cp_command),298			 "RECORDING %s PURGE %s",299			 logptr->recording_name,300			 qid_string);301		cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);302	}303 304	return rc;305}306 307 308static int vmlogrdr_open (struct inode *inode, struct file *filp)309{310	int dev_num = 0;311	struct vmlogrdr_priv_t * logptr = NULL;312	int connect_rc = 0;313	int ret;314 315	dev_num = iminor(inode);316	if (dev_num >= MAXMINOR)317		return -ENODEV;318	logptr = &sys_ser[dev_num];319 320	/*321	 * only allow for blocking reads to be open322	 */323	if (filp->f_flags & O_NONBLOCK)324		return -EOPNOTSUPP;325 326	/* Besure this device hasn't already been opened */327	spin_lock_bh(&logptr->priv_lock);328	if (logptr->dev_in_use)	{329		spin_unlock_bh(&logptr->priv_lock);330		return -EBUSY;331	}332	logptr->dev_in_use = 1;333	logptr->connection_established = 0;334	logptr->iucv_path_severed = 0;335	atomic_set(&logptr->receive_ready, 0);336	logptr->buffer_free = 1;337	spin_unlock_bh(&logptr->priv_lock);338 339	/* set the file options */340	filp->private_data = logptr;341 342	/* start recording for this service*/343	if (logptr->autorecording) {344		ret = vmlogrdr_recording(logptr,1,logptr->autopurge);345		if (ret)346			pr_warn("vmlogrdr: failed to start recording automatically\n");347	}348 349	/* create connection to the system service */350	logptr->path = iucv_path_alloc(10, 0, GFP_KERNEL);351	if (!logptr->path)352		goto out_dev;353	connect_rc = iucv_path_connect(logptr->path, &vmlogrdr_iucv_handler,354				       logptr->system_service, NULL, NULL,355				       logptr);356	if (connect_rc) {357		pr_err("vmlogrdr: iucv connection to %s "358		       "failed with rc %i \n",359		       logptr->system_service, connect_rc);360		goto out_path;361	}362 363	/* We've issued the connect and now we must wait for a364	 * ConnectionComplete or ConnectinSevered Interrupt365	 * before we can continue to process.366	 */367	wait_event(conn_wait_queue, (logptr->connection_established)368		   || (logptr->iucv_path_severed));369	if (logptr->iucv_path_severed)370		goto out_record;371	nonseekable_open(inode, filp);372	return 0;373 374out_record:375	if (logptr->autorecording)376		vmlogrdr_recording(logptr,0,logptr->autopurge);377out_path:378	kfree(logptr->path);	/* kfree(NULL) is ok. */379	logptr->path = NULL;380out_dev:381	logptr->dev_in_use = 0;382	return -EIO;383}384 385 386static int vmlogrdr_release (struct inode *inode, struct file *filp)387{388	int ret;389 390	struct vmlogrdr_priv_t * logptr = filp->private_data;391 392	iucv_path_sever(logptr->path, NULL);393	kfree(logptr->path);394	logptr->path = NULL;395	if (logptr->autorecording) {396		ret = vmlogrdr_recording(logptr,0,logptr->autopurge);397		if (ret)398			pr_warn("vmlogrdr: failed to stop recording automatically\n");399	}400	logptr->dev_in_use = 0;401 402	return 0;403}404 405 406static int vmlogrdr_receive_data(struct vmlogrdr_priv_t *priv)407{408	int rc, *temp;409	/* we need to keep track of two data sizes here:410	 * The number of bytes we need to receive from iucv and411	 * the total number of bytes we actually write into the buffer.412	 */413	int user_data_count, iucv_data_count;414	char * buffer;415 416	if (atomic_read(&priv->receive_ready)) {417		spin_lock_bh(&priv->priv_lock);418		if (priv->residual_length){419			/* receive second half of a record */420			iucv_data_count = priv->residual_length;421			user_data_count = 0;422			buffer = priv->buffer;423		} else {424			/* receive a new record:425			 * We need to return the total length of the record426                         * + size of FENCE in the first 4 bytes of the buffer.427		         */428			iucv_data_count = priv->local_interrupt_buffer.length;429			user_data_count = sizeof(int);430			temp = (int*)priv->buffer;431			*temp= iucv_data_count + sizeof(FENCE);432			buffer = priv->buffer + sizeof(int);433		}434		/*435		 * If the record is bigger than our buffer, we receive only436		 * a part of it. We can get the rest later.437		 */438		if (iucv_data_count > NET_BUFFER_SIZE)439			iucv_data_count = NET_BUFFER_SIZE;440		rc = iucv_message_receive(priv->path,441					  &priv->local_interrupt_buffer,442					  0, buffer, iucv_data_count,443					  &priv->residual_length);444		spin_unlock_bh(&priv->priv_lock);445		/* An rc of 5 indicates that the record was bigger than446		 * the buffer, which is OK for us. A 9 indicates that the447		 * record was purged befor we could receive it.448		 */449		if (rc == 5)450			rc = 0;451		if (rc == 9)452			atomic_set(&priv->receive_ready, 0);453	} else {454		rc = 1;455	}456	if (!rc) {457		priv->buffer_free = 0;458 		user_data_count += iucv_data_count;459		priv->current_position = priv->buffer;460		if (priv->residual_length == 0){461			/* the whole record has been captured,462			 * now add the fence */463			atomic_dec(&priv->receive_ready);464			buffer = priv->buffer + user_data_count;465			memcpy(buffer, FENCE, sizeof(FENCE));466			user_data_count += sizeof(FENCE);467		}468		priv->remaining = user_data_count;469	}470 471	return rc;472}473 474 475static ssize_t vmlogrdr_read(struct file *filp, char __user *data,476			     size_t count, loff_t * ppos)477{478	int rc;479	struct vmlogrdr_priv_t * priv = filp->private_data;480 481	while (priv->buffer_free) {482		rc = vmlogrdr_receive_data(priv);483		if (rc) {484			rc = wait_event_interruptible(read_wait_queue,485					atomic_read(&priv->receive_ready));486			if (rc)487				return rc;488		}489	}490	/* copy only up to end of record */491	if (count > priv->remaining)492		count = priv->remaining;493 494	if (copy_to_user(data, priv->current_position, count))495		return -EFAULT;496 497	*ppos += count;498	priv->current_position += count;499	priv->remaining -= count;500 501	/* if all data has been transferred, set buffer free */502	if (priv->remaining == 0)503		priv->buffer_free = 1;504 505	return count;506}507 508static ssize_t vmlogrdr_autopurge_store(struct device * dev,509					struct device_attribute *attr,510					const char * buf, size_t count)511{512	struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);513	ssize_t ret = count;514 515	switch (buf[0]) {516	case '0':517		priv->autopurge=0;518		break;519	case '1':520		priv->autopurge=1;521		break;522	default:523		ret = -EINVAL;524	}525	return ret;526}527 528 529static ssize_t vmlogrdr_autopurge_show(struct device *dev,530				       struct device_attribute *attr,531				       char *buf)532{533	struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);534	return sprintf(buf, "%u\n", priv->autopurge);535}536 537 538static DEVICE_ATTR(autopurge, 0644, vmlogrdr_autopurge_show,539		   vmlogrdr_autopurge_store);540 541 542static ssize_t vmlogrdr_purge_store(struct device * dev,543				    struct device_attribute *attr,544				    const char * buf, size_t count)545{546 547	char cp_command[80];548	char cp_response[80];549	struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);550 551	if (buf[0] != '1')552		return -EINVAL;553 554	memset(cp_command, 0x00, sizeof(cp_command));555	memset(cp_response, 0x00, sizeof(cp_response));556 557        /*558	 * The recording command needs to be called with option QID559	 * for guests that have previlege classes A or B.560	 * Other guests will not recognize the command and we have to561	 * issue the same command without the QID parameter.562	 */563 564	if (recording_class_AB)565		snprintf(cp_command, sizeof(cp_command),566			 "RECORDING %s PURGE QID * ",567			 priv->recording_name);568	else569		snprintf(cp_command, sizeof(cp_command),570			 "RECORDING %s PURGE ",571			 priv->recording_name);572 573	cpcmd(cp_command, cp_response, sizeof(cp_response), NULL);574 575	return count;576}577 578 579static DEVICE_ATTR(purge, 0200, NULL, vmlogrdr_purge_store);580 581 582static ssize_t vmlogrdr_autorecording_store(struct device *dev,583					    struct device_attribute *attr,584					    const char *buf, size_t count)585{586	struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);587	ssize_t ret = count;588 589	switch (buf[0]) {590	case '0':591		priv->autorecording=0;592		break;593	case '1':594		priv->autorecording=1;595		break;596	default:597		ret = -EINVAL;598	}599	return ret;600}601 602 603static ssize_t vmlogrdr_autorecording_show(struct device *dev,604					   struct device_attribute *attr,605					   char *buf)606{607	struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);608	return sprintf(buf, "%u\n", priv->autorecording);609}610 611 612static DEVICE_ATTR(autorecording, 0644, vmlogrdr_autorecording_show,613		   vmlogrdr_autorecording_store);614 615 616static ssize_t vmlogrdr_recording_store(struct device * dev,617					struct device_attribute *attr,618					const char * buf, size_t count)619{620	struct vmlogrdr_priv_t *priv = dev_get_drvdata(dev);621	ssize_t ret;622 623	switch (buf[0]) {624	case '0':625		ret = vmlogrdr_recording(priv,0,0);626		break;627	case '1':628		ret = vmlogrdr_recording(priv,1,0);629		break;630	default:631		ret = -EINVAL;632	}633	if (ret)634		return ret;635	else636		return count;637 638}639 640 641static DEVICE_ATTR(recording, 0200, NULL, vmlogrdr_recording_store);642 643 644static ssize_t recording_status_show(struct device_driver *driver, char *buf)645{646	static const char cp_command[] = "QUERY RECORDING ";647	int len;648 649	cpcmd(cp_command, buf, 4096, NULL);650	len = strlen(buf);651	return len;652}653static DRIVER_ATTR_RO(recording_status);654static struct attribute *vmlogrdr_drv_attrs[] = {655	&driver_attr_recording_status.attr,656	NULL,657};658static struct attribute_group vmlogrdr_drv_attr_group = {659	.attrs = vmlogrdr_drv_attrs,660};661static const struct attribute_group *vmlogrdr_drv_attr_groups[] = {662	&vmlogrdr_drv_attr_group,663	NULL,664};665 666static struct attribute *vmlogrdr_attrs[] = {667	&dev_attr_autopurge.attr,668	&dev_attr_purge.attr,669	&dev_attr_autorecording.attr,670	&dev_attr_recording.attr,671	NULL,672};673static struct attribute_group vmlogrdr_attr_group = {674	.attrs = vmlogrdr_attrs,675};676static const struct attribute_group *vmlogrdr_attr_groups[] = {677	&vmlogrdr_attr_group,678	NULL,679};680 681static const struct class vmlogrdr_class = {682	.name = "vmlogrdr_class",683};684static struct device_driver vmlogrdr_driver = {685	.name = "vmlogrdr",686	.bus  = &iucv_bus,687	.groups = vmlogrdr_drv_attr_groups,688};689 690static int vmlogrdr_register_driver(void)691{692	int ret;693 694	/* Register with iucv driver */695	ret = iucv_register(&vmlogrdr_iucv_handler, 1);696	if (ret)697		goto out;698 699	ret = driver_register(&vmlogrdr_driver);700	if (ret)701		goto out_iucv;702 703	ret = class_register(&vmlogrdr_class);704	if (ret)705		goto out_driver;706	return 0;707 708out_driver:709	driver_unregister(&vmlogrdr_driver);710out_iucv:711	iucv_unregister(&vmlogrdr_iucv_handler, 1);712out:713	return ret;714}715 716 717static void vmlogrdr_unregister_driver(void)718{719	class_unregister(&vmlogrdr_class);720	driver_unregister(&vmlogrdr_driver);721	iucv_unregister(&vmlogrdr_iucv_handler, 1);722}723 724 725static int vmlogrdr_register_device(struct vmlogrdr_priv_t *priv)726{727	struct device *dev;728	int ret;729 730	dev = iucv_alloc_device(vmlogrdr_attr_groups, &vmlogrdr_driver,731				priv, priv->internal_name);732	if (!dev)733		return -ENOMEM;734	ret = device_register(dev);735	if (ret) {736		put_device(dev);737		return ret;738	}739 740	priv->class_device = device_create(&vmlogrdr_class, dev,741					   MKDEV(vmlogrdr_major,742						 priv->minor_num),743					   priv, "%s", dev_name(dev));744	if (IS_ERR(priv->class_device)) {745		ret = PTR_ERR(priv->class_device);746		priv->class_device=NULL;747		device_unregister(dev);748		return ret;749	}750	priv->device = dev;751	return 0;752}753 754 755static int vmlogrdr_unregister_device(struct vmlogrdr_priv_t *priv)756{757	device_destroy(&vmlogrdr_class, MKDEV(vmlogrdr_major, priv->minor_num));758	if (priv->device != NULL) {759		device_unregister(priv->device);760		priv->device=NULL;761	}762	return 0;763}764 765 766static int vmlogrdr_register_cdev(dev_t dev)767{768	int rc = 0;769	vmlogrdr_cdev = cdev_alloc();770	if (!vmlogrdr_cdev) {771		return -ENOMEM;772	}773	vmlogrdr_cdev->owner = THIS_MODULE;774	vmlogrdr_cdev->ops = &vmlogrdr_fops;775	rc = cdev_add(vmlogrdr_cdev, dev, MAXMINOR);776	if (!rc)777		return 0;778 779	// cleanup: cdev is not fully registered, no cdev_del here!780	kobject_put(&vmlogrdr_cdev->kobj);781	vmlogrdr_cdev=NULL;782	return rc;783}784 785 786static void vmlogrdr_cleanup(void)787{788        int i;789 790	if (vmlogrdr_cdev) {791		cdev_del(vmlogrdr_cdev);792		vmlogrdr_cdev=NULL;793	}794	for (i=0; i < MAXMINOR; ++i ) {795		vmlogrdr_unregister_device(&sys_ser[i]);796		free_page((unsigned long)sys_ser[i].buffer);797	}798	vmlogrdr_unregister_driver();799	if (vmlogrdr_major) {800		unregister_chrdev_region(MKDEV(vmlogrdr_major, 0), MAXMINOR);801		vmlogrdr_major=0;802	}803}804 805 806static int __init vmlogrdr_init(void)807{808	int rc;809	int i;810	dev_t dev;811 812	if (! MACHINE_IS_VM) {813		pr_err("not running under VM, driver not loaded.\n");814		return -ENODEV;815	}816 817        recording_class_AB = vmlogrdr_get_recording_class_AB();818 819	rc = alloc_chrdev_region(&dev, 0, MAXMINOR, "vmlogrdr");820	if (rc)821		return rc;822	vmlogrdr_major = MAJOR(dev);823 824	rc=vmlogrdr_register_driver();825	if (rc)826		goto cleanup;827 828	for (i=0; i < MAXMINOR; ++i ) {829		sys_ser[i].buffer = (char *) get_zeroed_page(GFP_KERNEL | GFP_DMA);830		if (!sys_ser[i].buffer) {831			rc = -ENOMEM;832			break;833		}834		sys_ser[i].current_position = sys_ser[i].buffer;835		rc=vmlogrdr_register_device(&sys_ser[i]);836		if (rc)837			break;838	}839	if (rc)840		goto cleanup;841 842	rc = vmlogrdr_register_cdev(dev);843	if (rc)844		goto cleanup;845	return 0;846 847cleanup:848	vmlogrdr_cleanup();849	return rc;850}851 852 853static void __exit vmlogrdr_exit(void)854{855	vmlogrdr_cleanup();856	return;857}858 859 860module_init(vmlogrdr_init);861module_exit(vmlogrdr_exit);862