bsg: fix a blocking read bug
This patch fixes a bug that read() returns ENODATA even with a blocking file descriptor when there are no commands pending. This also includes some cleanups. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> Signed-off-by: Jens Axboe <jens.axboe@oracle.com>
This commit is contained in:
parent
4cf0723ac8
commit
e7d7217324
1 changed files with 23 additions and 61 deletions
84
block/bsg.c
84
block/bsg.c
|
@ -115,9 +115,9 @@ static void bsg_free_command(struct bsg_command *bc)
|
||||||
wake_up(&bd->wq_free);
|
wake_up(&bd->wq_free);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bsg_command *__bsg_alloc_command(struct bsg_device *bd)
|
static struct bsg_command *bsg_alloc_command(struct bsg_device *bd)
|
||||||
{
|
{
|
||||||
struct bsg_command *bc = NULL;
|
struct bsg_command *bc = ERR_PTR(-EINVAL);
|
||||||
|
|
||||||
spin_lock_irq(&bd->lock);
|
spin_lock_irq(&bd->lock);
|
||||||
|
|
||||||
|
@ -131,6 +131,7 @@ static struct bsg_command *__bsg_alloc_command(struct bsg_device *bd)
|
||||||
if (unlikely(!bc)) {
|
if (unlikely(!bc)) {
|
||||||
spin_lock_irq(&bd->lock);
|
spin_lock_irq(&bd->lock);
|
||||||
bd->queued_cmds--;
|
bd->queued_cmds--;
|
||||||
|
bc = ERR_PTR(-ENOMEM);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -198,30 +199,6 @@ static inline int bsg_io_schedule(struct bsg_device *bd, int state)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* get a new free command, blocking if needed and specified
|
|
||||||
*/
|
|
||||||
static struct bsg_command *bsg_get_command(struct bsg_device *bd)
|
|
||||||
{
|
|
||||||
struct bsg_command *bc;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
do {
|
|
||||||
bc = __bsg_alloc_command(bd);
|
|
||||||
if (bc)
|
|
||||||
break;
|
|
||||||
|
|
||||||
ret = bsg_io_schedule(bd, TASK_INTERRUPTIBLE);
|
|
||||||
if (ret) {
|
|
||||||
bc = ERR_PTR(ret);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
} while (1);
|
|
||||||
|
|
||||||
return bc;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int blk_fill_sgv4_hdr_rq(request_queue_t *q, struct request *rq,
|
static int blk_fill_sgv4_hdr_rq(request_queue_t *q, struct request *rq,
|
||||||
struct sg_io_v4 *hdr, int has_write_perm)
|
struct sg_io_v4 *hdr, int has_write_perm)
|
||||||
{
|
{
|
||||||
|
@ -397,7 +374,7 @@ static inline struct bsg_command *bsg_next_done_cmd(struct bsg_device *bd)
|
||||||
/*
|
/*
|
||||||
* Get a finished command from the done list
|
* Get a finished command from the done list
|
||||||
*/
|
*/
|
||||||
static struct bsg_command *__bsg_get_done_cmd(struct bsg_device *bd, int state)
|
static struct bsg_command *bsg_get_done_cmd(struct bsg_device *bd)
|
||||||
{
|
{
|
||||||
struct bsg_command *bc;
|
struct bsg_command *bc;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -407,9 +384,14 @@ static struct bsg_command *__bsg_get_done_cmd(struct bsg_device *bd, int state)
|
||||||
if (bc)
|
if (bc)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
ret = bsg_io_schedule(bd, state);
|
if (!test_bit(BSG_F_BLOCK, &bd->flags)) {
|
||||||
|
bc = ERR_PTR(-EAGAIN);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = wait_event_interruptible(bd->wq_done, bd->done_cmds);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
bc = ERR_PTR(ret);
|
bc = ERR_PTR(-ERESTARTSYS);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while (1);
|
} while (1);
|
||||||
|
@ -419,18 +401,6 @@ static struct bsg_command *__bsg_get_done_cmd(struct bsg_device *bd, int state)
|
||||||
return bc;
|
return bc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct bsg_command *
|
|
||||||
bsg_get_done_cmd(struct bsg_device *bd, const struct iovec *iov)
|
|
||||||
{
|
|
||||||
return __bsg_get_done_cmd(bd, TASK_INTERRUPTIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct bsg_command *
|
|
||||||
bsg_get_done_cmd_nosignals(struct bsg_device *bd)
|
|
||||||
{
|
|
||||||
return __bsg_get_done_cmd(bd, TASK_UNINTERRUPTIBLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
|
static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
|
||||||
struct bio *bio)
|
struct bio *bio)
|
||||||
{
|
{
|
||||||
|
@ -496,19 +466,16 @@ static int bsg_complete_all_commands(struct bsg_device *bd)
|
||||||
*/
|
*/
|
||||||
ret = 0;
|
ret = 0;
|
||||||
do {
|
do {
|
||||||
bc = bsg_get_done_cmd_nosignals(bd);
|
spin_lock_irq(&bd->lock);
|
||||||
|
if (!bd->queued_cmds) {
|
||||||
/*
|
spin_unlock_irq(&bd->lock);
|
||||||
* we _must_ complete before restarting, because
|
|
||||||
* bsg_release can't handle this failing.
|
|
||||||
*/
|
|
||||||
if (PTR_ERR(bc) == -ERESTARTSYS)
|
|
||||||
continue;
|
|
||||||
if (IS_ERR(bc)) {
|
|
||||||
ret = PTR_ERR(bc);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bc = bsg_get_done_cmd(bd);
|
||||||
|
if (IS_ERR(bc))
|
||||||
|
break;
|
||||||
|
|
||||||
tret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio);
|
tret = blk_complete_sgv4_hdr_rq(bc->rq, &bc->hdr, bc->bio);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
ret = tret;
|
ret = tret;
|
||||||
|
@ -519,11 +486,9 @@ static int bsg_complete_all_commands(struct bsg_device *bd)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct bsg_command *(*bsg_command_callback)(struct bsg_device *bd, const struct iovec *iov);
|
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
__bsg_read(char __user *buf, size_t count, bsg_command_callback get_bc,
|
__bsg_read(char __user *buf, size_t count, struct bsg_device *bd,
|
||||||
struct bsg_device *bd, const struct iovec *iov, ssize_t *bytes_read)
|
const struct iovec *iov, ssize_t *bytes_read)
|
||||||
{
|
{
|
||||||
struct bsg_command *bc;
|
struct bsg_command *bc;
|
||||||
int nr_commands, ret;
|
int nr_commands, ret;
|
||||||
|
@ -534,7 +499,7 @@ __bsg_read(char __user *buf, size_t count, bsg_command_callback get_bc,
|
||||||
ret = 0;
|
ret = 0;
|
||||||
nr_commands = count / sizeof(struct sg_io_v4);
|
nr_commands = count / sizeof(struct sg_io_v4);
|
||||||
while (nr_commands) {
|
while (nr_commands) {
|
||||||
bc = get_bc(bd, iov);
|
bc = bsg_get_done_cmd(bd);
|
||||||
if (IS_ERR(bc)) {
|
if (IS_ERR(bc)) {
|
||||||
ret = PTR_ERR(bc);
|
ret = PTR_ERR(bc);
|
||||||
break;
|
break;
|
||||||
|
@ -598,8 +563,7 @@ bsg_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
|
||||||
|
|
||||||
bsg_set_block(bd, file);
|
bsg_set_block(bd, file);
|
||||||
bytes_read = 0;
|
bytes_read = 0;
|
||||||
ret = __bsg_read(buf, count, bsg_get_done_cmd,
|
ret = __bsg_read(buf, count, bd, NULL, &bytes_read);
|
||||||
bd, NULL, &bytes_read);
|
|
||||||
*ppos = bytes_read;
|
*ppos = bytes_read;
|
||||||
|
|
||||||
if (!bytes_read || (bytes_read && err_block_err(ret)))
|
if (!bytes_read || (bytes_read && err_block_err(ret)))
|
||||||
|
@ -625,9 +589,7 @@ static ssize_t __bsg_write(struct bsg_device *bd, const char __user *buf,
|
||||||
while (nr_commands) {
|
while (nr_commands) {
|
||||||
request_queue_t *q = bd->queue;
|
request_queue_t *q = bd->queue;
|
||||||
|
|
||||||
bc = bsg_get_command(bd);
|
bc = bsg_alloc_command(bd);
|
||||||
if (!bc)
|
|
||||||
break;
|
|
||||||
if (IS_ERR(bc)) {
|
if (IS_ERR(bc)) {
|
||||||
ret = PTR_ERR(bc);
|
ret = PTR_ERR(bc);
|
||||||
bc = NULL;
|
bc = NULL;
|
||||||
|
|
Loading…
Reference in a new issue