⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vmur.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
		}		res = 0;		copied += len;	} while (copied != count);	*offs += copied;	rc = copied;fail:	free_page((unsigned long) buf);	return rc;}static ssize_t ur_read(struct file *file, char __user *ubuf, size_t count,		       loff_t *offs){	struct urdev *urd;	int rc;	TRACE("ur_read: count=%zu ppos=%li\n", count, (unsigned long) *offs);	if (count == 0)		return 0;	urd = ((struct urfile *) file->private_data)->urd;	rc = mutex_lock_interruptible(&urd->io_mutex);	if (rc)		return rc;	rc = diag14_read(file, ubuf, count, offs);	mutex_unlock(&urd->io_mutex);	return rc;}/* * diagnose code 0x14 subcode 0x0fff - retrieve next file descriptor * cc=0  normal completion * cc=1  no files on reader queue or no subsequent file * cc=2  spid specified is invalid */static int diag_read_next_file_info(struct file_control_block *buf, int spid){	int cc;	cc = diag14((unsigned long) buf, spid, 0xfff);	switch (cc) {	case 0:		return 0;	default:		return -ENODATA;	}}static int verify_uri_device(struct urdev *urd){	struct file_control_block *fcb;	char *buf;	int rc;	fcb = kmalloc(sizeof(*fcb), GFP_KERNEL | GFP_DMA);	if (!fcb)		return -ENOMEM;	/* check for empty reader device (beginning of chain) */	rc = diag_read_next_file_info(fcb, 0);	if (rc)		goto fail_free_fcb;	/* if file is in hold status, we do not read it */	if (fcb->file_stat & (FLG_SYSTEM_HOLD | FLG_USER_HOLD)) {		rc = -EPERM;		goto fail_free_fcb;	}	/* open file on virtual reader	*/	buf = (char *) __get_free_page(GFP_KERNEL | GFP_DMA);	if (!buf) {		rc = -ENOMEM;		goto fail_free_fcb;	}	rc = diag_read_file(urd->dev_id.devno, buf);	if ((rc != 0) && (rc != -ENODATA)) /* EOF does not hurt */		goto fail_free_buf;	/* check if the file on top of the queue is open now */	rc = diag_read_next_file_info(fcb, 0);	if (rc)		goto fail_free_buf;	if (!(fcb->file_stat & FLG_IN_USE)) {		rc = -EMFILE;		goto fail_free_buf;	}	rc = 0;fail_free_buf:	free_page((unsigned long) buf);fail_free_fcb:	kfree(fcb);	return rc;}static int verify_device(struct urdev *urd){	switch (urd->class) {	case DEV_CLASS_UR_O:		return 0; /* no check needed here */	case DEV_CLASS_UR_I:		return verify_uri_device(urd);	default:		return -ENOTSUPP;	}}static int get_uri_file_reclen(struct urdev *urd){	struct file_control_block *fcb;	int rc;	fcb = kmalloc(sizeof(*fcb), GFP_KERNEL | GFP_DMA);	if (!fcb)		return -ENOMEM;	rc = diag_read_next_file_info(fcb, 0);	if (rc)		goto fail_free;	if (fcb->file_stat & FLG_CP_DUMP)		rc = 0;	else		rc = fcb->rec_len;fail_free:	kfree(fcb);	return rc;}static int get_file_reclen(struct urdev *urd){	switch (urd->class) {	case DEV_CLASS_UR_O:		return 0;	case DEV_CLASS_UR_I:		return get_uri_file_reclen(urd);	default:		return -ENOTSUPP;	}}static int ur_open(struct inode *inode, struct file *file){	u16 devno;	struct urdev *urd;	struct urfile *urf;	unsigned short accmode;	int rc;	accmode = file->f_flags & O_ACCMODE;	if (accmode == O_RDWR)		return -EACCES;	/*	 * We treat the minor number as the devno of the ur device	 * to find in the driver tree.	 */	devno = MINOR(file->f_dentry->d_inode->i_rdev);	urd = urdev_get_from_devno(devno);	if (!urd)		return -ENXIO;	if (file->f_flags & O_NONBLOCK) {		if (!mutex_trylock(&urd->open_mutex)) {			rc = -EBUSY;			goto fail_put;		}	} else {		if (mutex_lock_interruptible(&urd->open_mutex)) {			rc = -ERESTARTSYS;			goto fail_put;		}	}	TRACE("ur_open\n");	if (((accmode == O_RDONLY) && (urd->class != DEV_CLASS_UR_I)) ||	    ((accmode == O_WRONLY) && (urd->class != DEV_CLASS_UR_O))) {		TRACE("ur_open: unsupported dev class (%d)\n", urd->class);		rc = -EACCES;		goto fail_unlock;	}	rc = verify_device(urd);	if (rc)		goto fail_unlock;	urf = urfile_alloc(urd);	if (!urf) {		rc = -ENOMEM;		goto fail_unlock;	}	urf->dev_reclen = urd->reclen;	rc = get_file_reclen(urd);	if (rc < 0)		goto fail_urfile_free;	urf->file_reclen = rc;	file->private_data = urf;	return 0;fail_urfile_free:	urfile_free(urf);fail_unlock:	mutex_unlock(&urd->open_mutex);fail_put:	urdev_put(urd);	return rc;}static int ur_release(struct inode *inode, struct file *file){	struct urfile *urf = file->private_data;	TRACE("ur_release\n");	mutex_unlock(&urf->urd->open_mutex);	urdev_put(urf->urd);	urfile_free(urf);	return 0;}static loff_t ur_llseek(struct file *file, loff_t offset, int whence){	loff_t newpos;	if ((file->f_flags & O_ACCMODE) != O_RDONLY)		return -ESPIPE; /* seek allowed only for reader */	if (offset % PAGE_SIZE)		return -ESPIPE; /* only multiples of 4K allowed */	switch (whence) {	case 0: /* SEEK_SET */		newpos = offset;		break;	case 1: /* SEEK_CUR */		newpos = file->f_pos + offset;		break;	default:		return -EINVAL;	}	file->f_pos = newpos;	return newpos;}static struct file_operations ur_fops = {	.owner	 = THIS_MODULE,	.open	 = ur_open,	.release = ur_release,	.read	 = ur_read,	.write	 = ur_write,	.llseek  = ur_llseek,};/* * ccw_device infrastructure: *     ur_probe creates the struct urdev (with refcount = 1), the device *     attributes, sets up the interrupt handler and validates the virtual *     unit record device. *     ur_remove removes the device attributes and drops the reference to *     struct urdev. * *     ur_probe, ur_remove, ur_set_online and ur_set_offline are serialized *     by the vmur_mutex lock. * *     urd->char_device is used as indication that the online function has *     been completed successfully. */static int ur_probe(struct ccw_device *cdev){	struct urdev *urd;	int rc;	TRACE("ur_probe: cdev=%p\n", cdev);	mutex_lock(&vmur_mutex);	urd = urdev_alloc(cdev);	if (!urd) {		rc = -ENOMEM;		goto fail_unlock;	}	rc = ur_create_attributes(&cdev->dev);	if (rc) {		rc = -ENOMEM;		goto fail_urdev_put;	}	cdev->handler = ur_int_handler;	/* validate virtual unit record device */	urd->class = get_urd_class(urd);	if (urd->class < 0) {		rc = urd->class;		goto fail_remove_attr;	}	if ((urd->class != DEV_CLASS_UR_I) && (urd->class != DEV_CLASS_UR_O)) {		rc = -ENOTSUPP;		goto fail_remove_attr;	}	spin_lock_irq(get_ccwdev_lock(cdev));	cdev->dev.driver_data = urd;	spin_unlock_irq(get_ccwdev_lock(cdev));	mutex_unlock(&vmur_mutex);	return 0;fail_remove_attr:	ur_remove_attributes(&cdev->dev);fail_urdev_put:	urdev_put(urd);fail_unlock:	mutex_unlock(&vmur_mutex);	return rc;}static int ur_set_online(struct ccw_device *cdev){	struct urdev *urd;	int minor, major, rc;	char node_id[16];	TRACE("ur_set_online: cdev=%p\n", cdev);	mutex_lock(&vmur_mutex);	urd = urdev_get_from_cdev(cdev);	if (!urd) {		/* ur_remove already deleted our urd */		rc = -ENODEV;		goto fail_unlock;	}	if (urd->char_device) {		/* Another ur_set_online was faster */		rc = -EBUSY;		goto fail_urdev_put;	}	minor = urd->dev_id.devno;	major = MAJOR(ur_first_dev_maj_min);	urd->char_device = cdev_alloc();	if (!urd->char_device) {		rc = -ENOMEM;		goto fail_urdev_put;	}	cdev_init(urd->char_device, &ur_fops);	urd->char_device->dev = MKDEV(major, minor);	urd->char_device->owner = ur_fops.owner;	rc = cdev_add(urd->char_device, urd->char_device->dev, 1);	if (rc)		goto fail_free_cdev;	if (urd->cdev->id.cu_type == READER_PUNCH_DEVTYPE) {		if (urd->class == DEV_CLASS_UR_I)			sprintf(node_id, "vmrdr-%s", cdev->dev.bus_id);		if (urd->class == DEV_CLASS_UR_O)			sprintf(node_id, "vmpun-%s", cdev->dev.bus_id);	} else if (urd->cdev->id.cu_type == PRINTER_DEVTYPE) {		sprintf(node_id, "vmprt-%s", cdev->dev.bus_id);	} else {		rc = -ENOTSUPP;		goto fail_free_cdev;	}	urd->device = device_create(vmur_class, NULL, urd->char_device->dev,					"%s", node_id);	if (IS_ERR(urd->device)) {		rc = PTR_ERR(urd->device);		TRACE("ur_set_online: device_create rc=%d\n", rc);		goto fail_free_cdev;	}	urdev_put(urd);	mutex_unlock(&vmur_mutex);	return 0;fail_free_cdev:	cdev_del(urd->char_device);	urd->char_device = NULL;fail_urdev_put:	urdev_put(urd);fail_unlock:	mutex_unlock(&vmur_mutex);	return rc;}static int ur_set_offline_force(struct ccw_device *cdev, int force){	struct urdev *urd;	int rc;	TRACE("ur_set_offline: cdev=%p\n", cdev);	urd = urdev_get_from_cdev(cdev);	if (!urd)		/* ur_remove already deleted our urd */		return -ENODEV;	if (!urd->char_device) {		/* Another ur_set_offline was faster */		rc = -EBUSY;		goto fail_urdev_put;	}	if (!force && (atomic_read(&urd->ref_count) > 2)) {		/* There is still a user of urd (e.g. ur_open) */		TRACE("ur_set_offline: BUSY\n");		rc = -EBUSY;		goto fail_urdev_put;	}	device_destroy(vmur_class, urd->char_device->dev);	cdev_del(urd->char_device);	urd->char_device = NULL;	rc = 0;fail_urdev_put:	urdev_put(urd);	return rc;}static int ur_set_offline(struct ccw_device *cdev){	int rc;	mutex_lock(&vmur_mutex);	rc = ur_set_offline_force(cdev, 0);	mutex_unlock(&vmur_mutex);	return rc;}static void ur_remove(struct ccw_device *cdev){	unsigned long flags;	TRACE("ur_remove\n");	mutex_lock(&vmur_mutex);	if (cdev->online)		ur_set_offline_force(cdev, 1);	ur_remove_attributes(&cdev->dev);	spin_lock_irqsave(get_ccwdev_lock(cdev), flags);	urdev_put(cdev->dev.driver_data);	cdev->dev.driver_data = NULL;	spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);	mutex_unlock(&vmur_mutex);}/* * Module initialisation and cleanup */static int __init ur_init(void){	int rc;	dev_t dev;	if (!MACHINE_IS_VM) {		PRINT_ERR("%s is only available under z/VM.\n", ur_banner);		return -ENODEV;	}	vmur_dbf = debug_register("vmur", 4, 1, 4 * sizeof(long));	if (!vmur_dbf)		return -ENOMEM;	rc = debug_register_view(vmur_dbf, &debug_sprintf_view);	if (rc)		goto fail_free_dbf;	debug_set_level(vmur_dbf, 6);	rc = ccw_driver_register(&ur_driver);	if (rc)		goto fail_free_dbf;	rc = alloc_chrdev_region(&dev, 0, NUM_MINORS, "vmur");	if (rc) {		PRINT_ERR("alloc_chrdev_region failed: err = %d\n", rc);		goto fail_unregister_driver;	}	ur_first_dev_maj_min = MKDEV(MAJOR(dev), 0);	vmur_class = class_create(THIS_MODULE, "vmur");	if (IS_ERR(vmur_class)) {		rc = PTR_ERR(vmur_class);		goto fail_unregister_region;	}	PRINT_INFO("%s loaded.\n", ur_banner);	return 0;fail_unregister_region:	unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS);fail_unregister_driver:	ccw_driver_unregister(&ur_driver);fail_free_dbf:	debug_unregister(vmur_dbf);	return rc;}static void __exit ur_exit(void){	class_destroy(vmur_class);	unregister_chrdev_region(ur_first_dev_maj_min, NUM_MINORS);	ccw_driver_unregister(&ur_driver);	debug_unregister(vmur_dbf);	PRINT_INFO("%s unloaded.\n", ur_banner);}module_init(ur_init);module_exit(ur_exit);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -