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

📄 nbd.c

📁 Linux块设备驱动源码
💻 C
📖 第 1 页 / 共 2 页
字号:
			}		}	}	return req;harderror:	lo->harderror = result;	return NULL;}static void nbd_do_it(struct nbd_device *lo){	struct request *req;	BUG_ON(lo->magic != LO_MAGIC);	while ((req = nbd_read_stat(lo)) != NULL)		nbd_end_request(req);	return;}static void nbd_clear_que(struct nbd_device *lo){	struct request *req;	BUG_ON(lo->magic != LO_MAGIC);	do {		req = NULL;		spin_lock(&lo->queue_lock);		if (!list_empty(&lo->queue_head)) {			req = list_entry(lo->queue_head.next, struct request, queuelist);			list_del_init(&req->queuelist);		}		spin_unlock(&lo->queue_lock);		if (req) {			req->errors++;			nbd_end_request(req);		}	} while (req);}/* * We always wait for result of write, for now. It would be nice to make it optional * in future * if ((req->cmd == WRITE) && (lo->flags & NBD_WRITE_NOCHK))  *   { printk( "Warning: Ignoring result!\n"); nbd_end_request( req ); } */static void do_nbd_request(request_queue_t * q){	struct request *req;		while ((req = elv_next_request(q)) != NULL) {		struct nbd_device *lo;		blkdev_dequeue_request(req);		dprintk(DBG_BLKDEV, "%s: request %p: dequeued (flags=%lx)\n",				req->rq_disk->disk_name, req, req->flags);		if (!(req->flags & REQ_CMD))			goto error_out;		lo = req->rq_disk->private_data;		BUG_ON(lo->magic != LO_MAGIC);		if (!lo->file) {			printk(KERN_ERR "%s: Request when not-ready\n",					lo->disk->disk_name);			goto error_out;		}		nbd_cmd(req) = NBD_CMD_READ;		if (rq_data_dir(req) == WRITE) {			nbd_cmd(req) = NBD_CMD_WRITE;			if (lo->flags & NBD_READ_ONLY) {				printk(KERN_ERR "%s: Write on read-only\n",						lo->disk->disk_name);				goto error_out;			}		}		req->errors = 0;		spin_unlock_irq(q->queue_lock);		spin_lock(&lo->queue_lock);		if (!lo->file) {			spin_unlock(&lo->queue_lock);			printk(KERN_ERR "%s: failed between accept and semaphore, file lost\n",					lo->disk->disk_name);			req->errors++;			nbd_end_request(req);			spin_lock_irq(q->queue_lock);			continue;		}		list_add(&req->queuelist, &lo->queue_head);		spin_unlock(&lo->queue_lock);		if (nbd_send_req(lo, req) != 0) {			printk(KERN_ERR "%s: Request send failed\n",					lo->disk->disk_name);			if (nbd_find_request(lo, (char *)&req) != NULL) {				/* we still own req */				req->errors++;				nbd_end_request(req);			} else /* we're racing with nbd_clear_que */				printk(KERN_DEBUG "nbd: can't find req\n");		}		spin_lock_irq(q->queue_lock);		continue;error_out:		req->errors++;		spin_unlock(q->queue_lock);		nbd_end_request(req);		spin_lock(q->queue_lock);	}	return;}static int nbd_ioctl(struct inode *inode, struct file *file,		     unsigned int cmd, unsigned long arg){	struct nbd_device *lo = inode->i_bdev->bd_disk->private_data;	int error;	struct request sreq ;	if (!capable(CAP_SYS_ADMIN))		return -EPERM;	BUG_ON(lo->magic != LO_MAGIC);	/* Anyone capable of this syscall can do *real bad* things */	dprintk(DBG_IOCTL, "%s: nbd_ioctl cmd=%s(0x%x) arg=%lu\n",			lo->disk->disk_name, ioctl_cmd_to_ascii(cmd), cmd, arg);	switch (cmd) {	case NBD_DISCONNECT:	        printk(KERN_INFO "%s: NBD_DISCONNECT\n", lo->disk->disk_name);		sreq.flags = REQ_SPECIAL;		nbd_cmd(&sreq) = NBD_CMD_DISC;		/*		 * Set these to sane values in case server implementation		 * fails to check the request type first and also to keep		 * debugging output cleaner.		 */		sreq.sector = 0;		sreq.nr_sectors = 0;                if (!lo->sock)			return -EINVAL;                nbd_send_req(lo, &sreq);                return 0; 	case NBD_CLEAR_SOCK:		error = 0;		down(&lo->tx_lock);		lo->sock = NULL;		up(&lo->tx_lock);		spin_lock(&lo->queue_lock);		file = lo->file;		lo->file = NULL;		spin_unlock(&lo->queue_lock);		nbd_clear_que(lo);		spin_lock(&lo->queue_lock);		if (!list_empty(&lo->queue_head)) {			printk(KERN_ERR "nbd: disconnect: some requests are in progress -> please try again.\n");			error = -EBUSY;		}		spin_unlock(&lo->queue_lock);		if (file)			fput(file);		return error;	case NBD_SET_SOCK:		if (lo->file)			return -EBUSY;		error = -EINVAL;		file = fget(arg);		if (file) {			inode = file->f_dentry->d_inode;			if (S_ISSOCK(inode->i_mode)) {				lo->file = file;				lo->sock = SOCKET_I(inode);				error = 0;			} else {				fput(file);			}		}		return error;	case NBD_SET_BLKSIZE:		lo->blksize = arg;		lo->bytesize &= ~(lo->blksize-1);		inode->i_bdev->bd_inode->i_size = lo->bytesize;		set_blocksize(inode->i_bdev, lo->blksize);		set_capacity(lo->disk, lo->bytesize >> 9);		return 0;	case NBD_SET_SIZE:		lo->bytesize = arg & ~(lo->blksize-1);		inode->i_bdev->bd_inode->i_size = lo->bytesize;		set_blocksize(inode->i_bdev, lo->blksize);		set_capacity(lo->disk, lo->bytesize >> 9);		return 0;	case NBD_SET_SIZE_BLOCKS:		lo->bytesize = ((u64) arg) * lo->blksize;		inode->i_bdev->bd_inode->i_size = lo->bytesize;		set_blocksize(inode->i_bdev, lo->blksize);		set_capacity(lo->disk, lo->bytesize >> 9);		return 0;	case NBD_DO_IT:		if (!lo->file)			return -EINVAL;		nbd_do_it(lo);		/* on return tidy up in case we have a signal */		/* Forcibly shutdown the socket causing all listeners		 * to error		 *		 * FIXME: This code is duplicated from sys_shutdown, but		 * there should be a more generic interface rather than		 * calling socket ops directly here */		down(&lo->tx_lock);		if (lo->sock) {			printk(KERN_WARNING "%s: shutting down socket\n",				lo->disk->disk_name);			lo->sock->ops->shutdown(lo->sock,				SEND_SHUTDOWN|RCV_SHUTDOWN);			lo->sock = NULL;		}		up(&lo->tx_lock);		spin_lock(&lo->queue_lock);		file = lo->file;		lo->file = NULL;		spin_unlock(&lo->queue_lock);		nbd_clear_que(lo);		printk(KERN_WARNING "%s: queue cleared\n", lo->disk->disk_name);		if (file)			fput(file);		return lo->harderror;	case NBD_CLEAR_QUE:		down(&lo->tx_lock);		if (lo->sock) {			up(&lo->tx_lock);			return 0; /* probably should be error, but that would				   * break "nbd-client -d", so just return 0 */		}		up(&lo->tx_lock);		nbd_clear_que(lo);		return 0;	case NBD_PRINT_DEBUG:		printk(KERN_INFO "%s: next = %p, prev = %p, head = %p\n",			inode->i_bdev->bd_disk->disk_name,			lo->queue_head.next, lo->queue_head.prev,			&lo->queue_head);		return 0;	}	return -EINVAL;}static struct block_device_operations nbd_fops ={	.owner =	THIS_MODULE,	.ioctl =	nbd_ioctl,};/* * And here should be modules and kernel interface  *  (Just smiley confuses emacs :-) */static int __init nbd_init(void){	int err = -ENOMEM;	int i;	if (sizeof(struct nbd_request) != 28) {		printk(KERN_CRIT "nbd: sizeof nbd_request needs to be 28 in order to work!\n" );		return -EIO;	}	if (nbds_max > MAX_NBD) {		printk(KERN_CRIT "nbd: cannot allocate more than %u nbds; %u requested.\n", MAX_NBD,				nbds_max);		return -EINVAL;	}	for (i = 0; i < nbds_max; i++) {		struct gendisk *disk = alloc_disk(1);		if (!disk)			goto out;		nbd_dev[i].disk = disk;		/*		 * The new linux 2.5 block layer implementation requires		 * every gendisk to have its very own request_queue struct.		 * These structs are big so we dynamically allocate them.		 */		disk->queue = blk_init_queue(do_nbd_request, &nbd_lock);		if (!disk->queue) {			put_disk(disk);			goto out;		}	}	if (register_blkdev(NBD_MAJOR, "nbd")) {		err = -EIO;		goto out;	}	printk(KERN_INFO "nbd: registered device at major %d\n", NBD_MAJOR);	dprintk(DBG_INIT, "nbd: debugflags=0x%x\n", debugflags);	devfs_mk_dir("nbd");	for (i = 0; i < nbds_max; i++) {		struct gendisk *disk = nbd_dev[i].disk;		nbd_dev[i].file = NULL;		nbd_dev[i].magic = LO_MAGIC;		nbd_dev[i].flags = 0;		spin_lock_init(&nbd_dev[i].queue_lock);		INIT_LIST_HEAD(&nbd_dev[i].queue_head);		init_MUTEX(&nbd_dev[i].tx_lock);		nbd_dev[i].blksize = 1024;		nbd_dev[i].bytesize = 0x7ffffc00ULL << 10; /* 2TB */		disk->major = NBD_MAJOR;		disk->first_minor = i;		disk->fops = &nbd_fops;		disk->private_data = &nbd_dev[i];		disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;		sprintf(disk->disk_name, "nbd%d", i);		sprintf(disk->devfs_name, "nbd/%d", i);		set_capacity(disk, 0x7ffffc00ULL << 1); /* 2 TB */		add_disk(disk);	}	return 0;out:	while (i--) {		blk_cleanup_queue(nbd_dev[i].disk->queue);		put_disk(nbd_dev[i].disk);	}	return err;}static void __exit nbd_cleanup(void){	int i;	for (i = 0; i < nbds_max; i++) {		struct gendisk *disk = nbd_dev[i].disk;		nbd_dev[i].magic = 0;		if (disk) {			del_gendisk(disk);			blk_cleanup_queue(disk->queue);			put_disk(disk);		}	}	devfs_remove("nbd");	unregister_blkdev(NBD_MAJOR, "nbd");	printk(KERN_INFO "nbd: unregistered device at major %d\n", NBD_MAJOR);}module_init(nbd_init);module_exit(nbd_cleanup);MODULE_DESCRIPTION("Network Block Device");MODULE_LICENSE("GPL");module_param(nbds_max, int, 0444);MODULE_PARM_DESC(nbds_max, "How many network block devices to initialize.");#ifndef NDEBUGmodule_param(debugflags, int, 0644);MODULE_PARM_DESC(debugflags, "flags for controlling debug output");#endif

⌨️ 快捷键说明

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