This converts bsg to use the generic ring buffer code. A new data structure, bsg_fd, is introduced to let each process to have its own ring buffers (that is, several ring buffer pairs could be attached to one bsg device). Signed-off-by: FUJITA Tomonori <fujita.tomonori@xxxxxxxxxxxxx> --- block/bsg.c | 252 ++++++++++++++++++++++++++-------------------------------- 1 files changed, 113 insertions(+), 139 deletions(-) diff --git a/block/bsg.c b/block/bsg.c index c85d961..1ce35d3 100644 --- a/block/bsg.c +++ b/block/bsg.c @@ -25,6 +25,8 @@ #include <linux/cdev.h> #include <linux/percpu.h> #include <linux/uio.h> #include <linux/bsg.h> +#include <linux/eventchannel.h> +#include <linux/eventchannel_if.h> #include <scsi/scsi.h> #include <scsi/scsi_ioctl.h> @@ -51,6 +53,11 @@ struct bsg_device { unsigned long flags; }; +struct bsg_fd { + struct bsg_device *bd; + struct ec_info *eci; +}; + enum { BSG_F_BLOCK = 1, BSG_F_WRITE_PERM = 2, @@ -418,7 +425,7 @@ static struct bsg_command *__bsg_get_don } static struct bsg_command * -bsg_get_done_cmd(struct bsg_device *bd, const struct iovec *iov) +bsg_get_done_cmd(struct bsg_device *bd) { return __bsg_get_done_cmd(bd, TASK_INTERRUPTIBLE); } @@ -519,46 +526,28 @@ static int bsg_complete_all_commands(str typedef struct bsg_command *(*bsg_command_callback)(struct bsg_device *bd, const struct iovec *iov); -static ssize_t -__bsg_read(char __user *buf, size_t count, bsg_command_callback get_bc, - struct bsg_device *bd, const struct iovec *iov, ssize_t *bytes_read) +static int bsg_send_response(struct file *file, char __user *buf) { + struct bsg_fd *bf = file->private_data; + struct bsg_device *bd = bf->bd; struct bsg_command *bc; - int nr_commands, ret; - - if (count % sizeof(struct sg_io_v4)) - return -EINVAL; - - ret = 0; - nr_commands = count / sizeof(struct sg_io_v4); - while (nr_commands) { - bc = get_bc(bd, iov); - if (IS_ERR(bc)) { - ret = PTR_ERR(bc); - break; - } - - /* - * this is the only case where we need to copy data back - * after completing the request. so do that here, - * bsg_complete_work() cannot do that for us - */ - ret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio); - - if (copy_to_user(buf, (char *) &bc->hdr, sizeof(bc->hdr))) - ret = -EFAULT; + int ret; - bsg_free_command(bc); + bc = bsg_get_done_cmd(bd); + if (IS_ERR(bc)) + return 1; - if (ret) - break; + /* + * this is the only case where we need to copy data back + * after completing the request. so do that here, + * bsg_complete_work() cannot do that for us + */ + ret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio); - buf += sizeof(struct sg_io_v4); - *bytes_read += sizeof(struct sg_io_v4); - nr_commands--; - } + ret = copy_to_user(buf, (char *) &bc->hdr, sizeof(bc->hdr)); - return ret; + bsg_free_command(bc); + return 0; } static inline void bsg_set_block(struct bsg_device *bd, struct file *file) @@ -585,107 +574,59 @@ static inline int err_block_err(int ret) return 0; } -static ssize_t -bsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) +static int bsg_prepare_send_response(struct file *file) { - struct bsg_device *bd = file->private_data; - int ret; - ssize_t bytes_read; + struct bsg_fd *bf = file->private_data; + struct bsg_device *bd = bf->bd; - dprintk("%s: read %Zd bytes\n", bd->name, count); + dprintk("%s: read\n", bd->name); bsg_set_block(bd, file); - bytes_read = 0; - ret = __bsg_read(buf, count, bsg_get_done_cmd, - bd, NULL, &bytes_read); - *ppos = bytes_read; - - if (!bytes_read || (bytes_read && err_block_err(ret))) - bytes_read = ret; - - return bytes_read; + return 0; } -static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf, - size_t count, ssize_t *bytes_read) +static int bsg_recv_request(struct file *file, char __user *buf) { + struct bsg_fd *bf = file->private_data; + struct bsg_device *bd = bf->bd; struct bsg_command *bc; struct request *rq; - int ret, nr_commands; - - if (count % sizeof(struct sg_io_v4)) - return -EINVAL; - - nr_commands = count / sizeof(struct sg_io_v4); - rq = NULL; - bc = NULL; - ret = 0; - while (nr_commands) { - request_queue_t *q = bd->queue; + request_queue_t *q = bd->queue; - bc = bsg_get_command(bd); - if (!bc) - break; - if (IS_ERR(bc)) { - ret = PTR_ERR(bc); - bc = NULL; - break; - } + bc = bsg_get_command(bd); + if (!bc) + return ENOMEM; - bc->uhdr = (struct sg_io_v4 __user *) buf; - if (copy_from_user(&bc->hdr, buf, sizeof(bc->hdr))) { - ret = -EFAULT; - break; - } + if (IS_ERR(bc)) + return PTR_ERR(bc); - /* - * get a request, fill in the blanks, and add to request queue - */ - rq = bsg_map_hdr(bd, &bc->hdr); - if (IS_ERR(rq)) { - ret = PTR_ERR(rq); - rq = NULL; - break; - } - - bsg_add_command(bd, q, bc, rq); - bc = NULL; - rq = NULL; - nr_commands--; - buf += sizeof(struct sg_io_v4); - *bytes_read += sizeof(struct sg_io_v4); + bc->uhdr = (struct sg_io_v4 __user *) buf; + if (copy_from_user(&bc->hdr, buf, sizeof(bc->hdr))) { + bsg_free_command(bc); + return EFAULT; } - if (bc) + rq = bsg_map_hdr(bd, &bc->hdr); + if (IS_ERR(rq)) { bsg_free_command(bc); + return PTR_ERR(rq); + } - return ret; + bsg_add_command(bd, q, bc, rq); + + return 0; } -static ssize_t -bsg_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) +static int bsg_prepare_recv_request(struct file *file) { - struct bsg_device *bd = file->private_data; - ssize_t bytes_read; - int ret; + struct bsg_fd *bf = file->private_data; + struct bsg_device *bd = bf->bd; - dprintk("%s: write %Zd bytes\n", bd->name, count); + dprintk("%s write\n", bd->name); bsg_set_block(bd, file); bsg_set_write_perm(bd, file); - - bytes_read = 0; - ret = __bsg_write(bd, buf, count, &bytes_read); - *ppos = bytes_read; - - /* - * return bytes written on non-fatal errors - */ - if (!bytes_read || (bytes_read && err_block_err(ret))) - bytes_read = ret; - - dprintk("%s: returning %Zd\n", bd->name, bytes_read); - return bytes_read; + return 0; } static struct bsg_device *bsg_alloc_device(void) @@ -822,46 +763,42 @@ static struct bsg_device *bsg_get_device static int bsg_open(struct inode *inode, struct file *file) { - struct bsg_device *bd = bsg_get_device(inode, file); + struct bsg_device *bd; + struct bsg_fd *bf; + + bf = kzalloc(sizeof(*bf), GFP_KERNEL); + if (!bf) + return -ENOMEM; - if (IS_ERR(bd)) + bd = bsg_get_device(inode, file); + if (IS_ERR(bd)) { + kfree(bf); return PTR_ERR(bd); + } - file->private_data = bd; + bf->bd = bd; + file->private_data = bf; return 0; } static int bsg_release(struct inode *inode, struct file *file) { - struct bsg_device *bd = file->private_data; + struct bsg_fd *bf = file->private_data; + struct bsg_device *bd = bf->bd; file->private_data = NULL; + if (bf->eci) + ec_info_free(bf->eci); + kfree(bf); return bsg_put_device(bd); } -static unsigned int bsg_poll(struct file *file, poll_table *wait) -{ - struct bsg_device *bd = file->private_data; - unsigned int mask = 0; - - poll_wait(file, &bd->wq_done, wait); - poll_wait(file, &bd->wq_free, wait); - - spin_lock_irq(&bd->lock); - if (!list_empty(&bd->done_list)) - mask |= POLLIN | POLLRDNORM; - if (bd->queued_cmds >= bd->max_queue) - mask |= POLLOUT; - spin_unlock_irq(&bd->lock); - - return mask; -} - static int bsg_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) { - struct bsg_device *bd = file->private_data; + struct bsg_fd *bf = file->private_data; + struct bsg_device *bd = bf->bd; int __user *uarg = (int __user *) arg; if (!bd) @@ -936,9 +873,6 @@ #endif } static struct file_operations bsg_fops = { - .read = bsg_read, - .write = bsg_write, - .poll = bsg_poll, .open = bsg_open, .release = bsg_release, .ioctl = bsg_ioctl, @@ -997,10 +931,50 @@ err: return -ENOMEM; } +static int bsg_ec_init(struct file *file, struct ec_ring __user *kupring, + struct ec_ring __user *ukpring, unsigned int num, + unsigned int flags) +{ + struct bsg_fd *bf = file->private_data; + struct bsg_device *bd = bf->bd; + struct ec_info *eci; + + if (bf->eci) + return -EINVAL; + + eci = ec_info_alloc(kupring, &bd->wq_done, &bd->done_cmds, + ukpring, NULL, NULL, + num, flags); + if (!eci) + return -ENOMEM; + + bf->eci = eci; + return 0; +} + +static struct ec_info *bsg_file_to_ecinfo(struct file *file) +{ + return ((struct bsg_fd *) (file->private_data))->eci; +} + +static struct ec_operations bsg_ec_ops = { + .ec_init = bsg_ec_init, + .file_to_ecinfo = bsg_file_to_ecinfo, + .prepare_send_event_to_user = bsg_prepare_send_response, + .send_event_to_user = bsg_send_response, + .prepare_recv_event_from_user = bsg_prepare_recv_request, + .recv_event_from_user = bsg_recv_request, +}; + static int __init bsg_init(void) { int ret, i; + ret = ec_register(EC_TYPE_BSG, sizeof(struct sg_io_v4), &bsg_ec_ops, + &bsg_fops); + if (ret) + return -EINVAL; + bsg_cmd_cachep = kmem_cache_create("bsg_cmd", sizeof(struct bsg_command), 0, 0, NULL, NULL); if (!bsg_cmd_cachep) { -- 1.4.3.2 - To unsubscribe from this list: send the line "unsubscribe linux-scsi" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html