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

📄 dcssblk.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 2 页
字号:
	}	dev_info->gd->major = dcssblk_major;	dev_info->gd->fops = &dcssblk_devops;	dev_info->dcssblk_queue = blk_alloc_queue(GFP_KERNEL);	dev_info->gd->queue = dev_info->dcssblk_queue;	dev_info->gd->private_data = dev_info;	dev_info->gd->driverfs_dev = &dev_info->dev;	/*	 * load the segment	 */	rc = segment_load(local_buf, SEGMENT_SHARED,				&dev_info->start, &dev_info->end);	if (rc < 0) {		dcssblk_segment_warn(rc, dev_info->segment_name);		goto dealloc_gendisk;	}	seg_byte_size = (dev_info->end - dev_info->start + 1);	set_capacity(dev_info->gd, seg_byte_size >> 9); // size in sectors	PRINT_INFO("Loaded segment %s, size = %lu Byte, "		   "capacity = %lu (512 Byte) sectors\n", local_buf,		   seg_byte_size, seg_byte_size >> 9);	dev_info->segment_type = rc;	dev_info->save_pending = 0;	dev_info->is_shared = 1;	dev_info->dev.parent = dcssblk_root_dev;	/*	 * get minor, add to list	 */	down_write(&dcssblk_devices_sem);	rc = dcssblk_assign_free_minor(dev_info);	if (rc) {		up_write(&dcssblk_devices_sem);		PRINT_ERR("No free minor number available! "			  "Unloading segment...\n");		goto unload_seg;	}	sprintf(dev_info->gd->disk_name, "dcssblk%d",		dev_info->gd->first_minor);	list_add_tail(&dev_info->lh, &dcssblk_devices);	if (!try_module_get(THIS_MODULE)) {		rc = -ENODEV;		goto list_del;	}	/*	 * register the device	 */	rc = device_register(&dev_info->dev);	if (rc) {		PRINT_ERR("Segment %s could not be registered RC=%d\n",				local_buf, rc);		module_put(THIS_MODULE);		goto list_del;	}	get_device(&dev_info->dev);	rc = device_create_file(&dev_info->dev, &dev_attr_shared);	if (rc)		goto unregister_dev;	rc = device_create_file(&dev_info->dev, &dev_attr_save);	if (rc)		goto unregister_dev;	add_disk(dev_info->gd);	blk_queue_make_request(dev_info->dcssblk_queue, dcssblk_make_request);	blk_queue_hardsect_size(dev_info->dcssblk_queue, 4096);	switch (dev_info->segment_type) {		case SEG_TYPE_SR:		case SEG_TYPE_ER:		case SEG_TYPE_SC:			set_disk_ro(dev_info->gd,1);			break;		default:			set_disk_ro(dev_info->gd,0);			break;	}	PRINT_DEBUG("Segment %s loaded successfully\n", local_buf);	up_write(&dcssblk_devices_sem);	rc = count;	goto out;unregister_dev:	PRINT_ERR("device_create_file() failed!\n");	list_del(&dev_info->lh);	blk_put_queue(dev_info->dcssblk_queue);	dev_info->gd->queue = NULL;	put_disk(dev_info->gd);	device_unregister(&dev_info->dev);	segment_unload(dev_info->segment_name);	put_device(&dev_info->dev);	up_write(&dcssblk_devices_sem);	goto out;list_del:	list_del(&dev_info->lh);	up_write(&dcssblk_devices_sem);unload_seg:	segment_unload(local_buf);dealloc_gendisk:	blk_put_queue(dev_info->dcssblk_queue);	dev_info->gd->queue = NULL;	put_disk(dev_info->gd);free_dev_info:	kfree(dev_info);out:	kfree(local_buf);out_nobuf:	return rc;}/* * device attribute for removing devices */static ssize_tdcssblk_remove_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count){	struct dcssblk_dev_info *dev_info;	int rc, i;	char *local_buf;	if (dev != dcssblk_root_dev) {		return -EINVAL;	}	local_buf = kmalloc(count + 1, GFP_KERNEL);	if (local_buf == NULL) {		return -ENOMEM;	}	/*	 * parse input	 */	for (i = 0; ((*(buf+i)!='\0') && (*(buf+i)!='\n') && i < count); i++) {		local_buf[i] = toupper(buf[i]);	}	local_buf[i] = '\0';	if ((i == 0) || (i > 8)) {		rc = -ENAMETOOLONG;		goto out_buf;	}	down_write(&dcssblk_devices_sem);	dev_info = dcssblk_get_device_by_name(local_buf);	if (dev_info == NULL) {		up_write(&dcssblk_devices_sem);		PRINT_WARN("Segment %s is not loaded!\n", local_buf);		rc = -ENODEV;		goto out_buf;	}	if (atomic_read(&dev_info->use_count) != 0) {		up_write(&dcssblk_devices_sem);		PRINT_WARN("Segment %s is in use!\n", local_buf);		rc = -EBUSY;		goto out_buf;	}	list_del(&dev_info->lh);	del_gendisk(dev_info->gd);	blk_put_queue(dev_info->dcssblk_queue);	dev_info->gd->queue = NULL;	put_disk(dev_info->gd);	device_unregister(&dev_info->dev);	segment_unload(dev_info->segment_name);	PRINT_DEBUG("Segment %s unloaded successfully\n",			dev_info->segment_name);	put_device(&dev_info->dev);	up_write(&dcssblk_devices_sem);	rc = count;out_buf:	kfree(local_buf);	return rc;}static intdcssblk_open(struct inode *inode, struct file *filp){	struct dcssblk_dev_info *dev_info;	int rc;	dev_info = inode->i_bdev->bd_disk->private_data;	if (NULL == dev_info) {		rc = -ENODEV;		goto out;	}	atomic_inc(&dev_info->use_count);	inode->i_bdev->bd_block_size = 4096;	rc = 0;out:	return rc;}static intdcssblk_release(struct inode *inode, struct file *filp){	struct dcssblk_dev_info *dev_info;	int rc;	dev_info = inode->i_bdev->bd_disk->private_data;	if (NULL == dev_info) {		rc = -ENODEV;		goto out;	}	down_write(&dcssblk_devices_sem);	if (atomic_dec_and_test(&dev_info->use_count)	    && (dev_info->save_pending)) {		PRINT_INFO("Segment %s became idle and is being saved now\n",			    dev_info->segment_name);		segment_save(dev_info->segment_name);		dev_info->save_pending = 0;	}	up_write(&dcssblk_devices_sem);	rc = 0;out:	return rc;}static intdcssblk_make_request(request_queue_t *q, struct bio *bio){	struct dcssblk_dev_info *dev_info;	struct bio_vec *bvec;	unsigned long index;	unsigned long page_addr;	unsigned long source_addr;	unsigned long bytes_done;	int i;	bytes_done = 0;	dev_info = bio->bi_bdev->bd_disk->private_data;	if (dev_info == NULL)		goto fail;	if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0)		/* Request is not page-aligned. */		goto fail;	if (((bio->bi_size >> 9) + bio->bi_sector)			> get_capacity(bio->bi_bdev->bd_disk)) {		/* Request beyond end of DCSS segment. */		goto fail;	}	/* verify data transfer direction */	if (dev_info->is_shared) {		switch (dev_info->segment_type) {		case SEG_TYPE_SR:		case SEG_TYPE_ER:		case SEG_TYPE_SC:			/* cannot write to these segments */			if (bio_data_dir(bio) == WRITE) {				PRINT_WARN("rejecting write to ro segment %s\n", dev_info->dev.bus_id);				goto fail;			}		}	}	index = (bio->bi_sector >> 3);	bio_for_each_segment(bvec, bio, i) {		page_addr = (unsigned long)			page_address(bvec->bv_page) + bvec->bv_offset;		source_addr = dev_info->start + (index<<12) + bytes_done;		if (unlikely(page_addr & 4095) != 0 || (bvec->bv_len & 4095) != 0)			// More paranoia.			goto fail;		if (bio_data_dir(bio) == READ) {			memcpy((void*)page_addr, (void*)source_addr,				bvec->bv_len);		} else {			memcpy((void*)source_addr, (void*)page_addr,				bvec->bv_len);		}		bytes_done += bvec->bv_len;	}	bio_endio(bio, bytes_done, 0);	return 0;fail:	bio_io_error(bio, bio->bi_size);	return 0;}static intdcssblk_direct_access (struct block_device *bdev, sector_t secnum,			unsigned long *data){	struct dcssblk_dev_info *dev_info;	unsigned long pgoff;	dev_info = bdev->bd_disk->private_data;	if (!dev_info)		return -ENODEV;	if (secnum % (PAGE_SIZE/512))		return -EINVAL;	pgoff = secnum / (PAGE_SIZE / 512);	if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)		return -ERANGE;	*data = (unsigned long) (dev_info->start+pgoff*PAGE_SIZE);	return 0;}static voiddcssblk_check_params(void){	int rc, i, j, k;	char buf[9];	struct dcssblk_dev_info *dev_info;	for (i = 0; (i < DCSSBLK_PARM_LEN) && (dcssblk_segments[i] != '\0');	     i++) {		for (j = i; (dcssblk_segments[j] != ',')  &&			    (dcssblk_segments[j] != '\0') &&			    (dcssblk_segments[j] != '(')  &&			    (j - i) < 8; j++)		{			buf[j-i] = dcssblk_segments[j];		}		buf[j-i] = '\0';		rc = dcssblk_add_store(dcssblk_root_dev, NULL, buf, j-i);		if ((rc >= 0) && (dcssblk_segments[j] == '(')) {			for (k = 0; buf[k] != '\0'; k++)				buf[k] = toupper(buf[k]);			if (!strncmp(&dcssblk_segments[j], "(local)", 7)) {				down_read(&dcssblk_devices_sem);				dev_info = dcssblk_get_device_by_name(buf);				up_read(&dcssblk_devices_sem);				if (dev_info)					dcssblk_shared_store(&dev_info->dev,							     NULL, "0\n", 2);			}		}		while ((dcssblk_segments[j] != ',') &&		       (dcssblk_segments[j] != '\0'))		{			j++;		}		if (dcssblk_segments[j] == '\0')			break;		i = j;	}}/* * The init/exit functions. */static void __exitdcssblk_exit(void){	int rc;	PRINT_DEBUG("DCSSBLOCK EXIT...\n");	s390_root_dev_unregister(dcssblk_root_dev);	rc = unregister_blkdev(dcssblk_major, DCSSBLK_NAME);	if (rc) {		PRINT_ERR("unregister_blkdev() failed!\n");	}	PRINT_DEBUG("...finished!\n");}static int __initdcssblk_init(void){	int rc;	PRINT_DEBUG("DCSSBLOCK INIT...\n");	dcssblk_root_dev = s390_root_dev_register("dcssblk");	if (IS_ERR(dcssblk_root_dev)) {		PRINT_ERR("device_register() failed!\n");		return PTR_ERR(dcssblk_root_dev);	}	rc = device_create_file(dcssblk_root_dev, &dev_attr_add);	if (rc) {		PRINT_ERR("device_create_file(add) failed!\n");		s390_root_dev_unregister(dcssblk_root_dev);		return rc;	}	rc = device_create_file(dcssblk_root_dev, &dev_attr_remove);	if (rc) {		PRINT_ERR("device_create_file(remove) failed!\n");		s390_root_dev_unregister(dcssblk_root_dev);		return rc;	}	rc = register_blkdev(0, DCSSBLK_NAME);	if (rc < 0) {		PRINT_ERR("Can't get dynamic major!\n");		s390_root_dev_unregister(dcssblk_root_dev);		return rc;	}	dcssblk_major = rc;	init_rwsem(&dcssblk_devices_sem);	dcssblk_check_params();	PRINT_DEBUG("...finished!\n");	return 0;}module_init(dcssblk_init);module_exit(dcssblk_exit);module_param_string(segments, dcssblk_segments, DCSSBLK_PARM_LEN, 0444);MODULE_PARM_DESC(segments, "Name of DCSS segment(s) to be loaded, "		 "comma-separated list, each name max. 8 chars.\n"		 "Adding \"(local)\" to segment name equals echoing 0 to "		 "/sys/devices/dcssblk/<segment name>/shared after loading "		 "the segment - \n"		 "e.g. segments=\"mydcss1,mydcss2,mydcss3(local)\"");MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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