Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

block: Simplify bsg complete all

It took me a few tries to figure out what this code did; lets rewrite
it into a more regular form.

The thing that makes this one 'special' is the BSG_F_BLOCK flag, if
that is not set we're not supposed/allowed to block and should spin
wait for completion.

The (new) io_wait_event() will never see a false condition in case of
the spinning and we will therefore not block.

Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Jens Axboe <axboe@fb.com>

authored by

Peter Zijlstra and committed by
Jens Axboe
2c561246 b7f120b2

+40 -47
+25 -47
block/bsg.c
··· 136 136 return &bsg_device_list[index & (BSG_LIST_ARRAY_SIZE - 1)]; 137 137 } 138 138 139 - static int bsg_io_schedule(struct bsg_device *bd) 140 - { 141 - DEFINE_WAIT(wait); 142 - int ret = 0; 143 - 144 - spin_lock_irq(&bd->lock); 145 - 146 - BUG_ON(bd->done_cmds > bd->queued_cmds); 147 - 148 - /* 149 - * -ENOSPC or -ENODATA? I'm going for -ENODATA, meaning "I have no 150 - * work to do", even though we return -ENOSPC after this same test 151 - * during bsg_write() -- there, it means our buffer can't have more 152 - * bsg_commands added to it, thus has no space left. 153 - */ 154 - if (bd->done_cmds == bd->queued_cmds) { 155 - ret = -ENODATA; 156 - goto unlock; 157 - } 158 - 159 - if (!test_bit(BSG_F_BLOCK, &bd->flags)) { 160 - ret = -EAGAIN; 161 - goto unlock; 162 - } 163 - 164 - prepare_to_wait(&bd->wq_done, &wait, TASK_UNINTERRUPTIBLE); 165 - spin_unlock_irq(&bd->lock); 166 - io_schedule(); 167 - finish_wait(&bd->wq_done, &wait); 168 - 169 - return ret; 170 - unlock: 171 - spin_unlock_irq(&bd->lock); 172 - return ret; 173 - } 174 - 175 139 static int blk_fill_sgv4_hdr_rq(struct request_queue *q, struct request *rq, 176 140 struct sg_io_v4 *hdr, struct bsg_device *bd, 177 141 fmode_t has_write_perm) ··· 446 482 return ret; 447 483 } 448 484 485 + static bool bsg_complete(struct bsg_device *bd) 486 + { 487 + bool ret = false; 488 + bool spin; 489 + 490 + do { 491 + spin_lock_irq(&bd->lock); 492 + 493 + BUG_ON(bd->done_cmds > bd->queued_cmds); 494 + 495 + /* 496 + * All commands consumed. 497 + */ 498 + if (bd->done_cmds == bd->queued_cmds) 499 + ret = true; 500 + 501 + spin = !test_bit(BSG_F_BLOCK, &bd->flags); 502 + 503 + spin_unlock_irq(&bd->lock); 504 + } while (!ret && spin); 505 + 506 + return ret; 507 + } 508 + 449 509 static int bsg_complete_all_commands(struct bsg_device *bd) 450 510 { 451 511 struct bsg_command *bc; ··· 480 492 /* 481 493 * wait for all commands to complete 482 494 */ 483 - ret = 0; 484 - do { 485 - ret = bsg_io_schedule(bd); 486 - /* 487 - * look for -ENODATA specifically -- we'll sometimes get 488 - * -ERESTARTSYS when we've taken a signal, but we can't 489 - * return until we're done freeing the queue, so ignore 490 - * it. The signal will get handled when we're done freeing 491 - * the bsg_device. 492 - */ 493 - } while (ret != -ENODATA); 495 + io_wait_event(bd->wq_done, bsg_complete(bd)); 494 496 495 497 /* 496 498 * discard done commands
+15
include/linux/wait.h
··· 267 267 __wait_event(wq, condition); \ 268 268 } while (0) 269 269 270 + #define __io_wait_event(wq, condition) \ 271 + (void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0, \ 272 + io_schedule()) 273 + 274 + /* 275 + * io_wait_event() -- like wait_event() but with io_schedule() 276 + */ 277 + #define io_wait_event(wq, condition) \ 278 + do { \ 279 + might_sleep(); \ 280 + if (condition) \ 281 + break; \ 282 + __io_wait_event(wq, condition); \ 283 + } while (0) 284 + 270 285 #define __wait_event_freezable(wq, condition) \ 271 286 ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \ 272 287 schedule(); try_to_freeze())