Skip to content

Commit

Permalink
Enforce request limits on zvols
Browse files Browse the repository at this point in the history
ZVOLs do not handle heavy random IO works loads. ZVOLs
should limit the number of outstanding in-flight IO requests.
This should improve performance.

Signed-off-by: Giuseppe Di Natale <[email protected]>
  • Loading branch information
dinatale2 committed Jul 10, 2017
1 parent 817b1b6 commit f61d640
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 0 deletions.
6 changes: 6 additions & 0 deletions include/linux/blkdev_compat.h
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,12 @@ blk_queue_set_read_ahead(struct request_queue *q, unsigned long ra_pages)
#endif
}

static inline unsigned long
blk_queue_nr_requests(struct request_queue *q)
{
return (q->nr_requests);
}

#ifndef HAVE_GET_DISK_RO
static inline int
get_disk_ro(struct gendisk *disk)
Expand Down
40 changes: 40 additions & 0 deletions module/zfs/zvol.c
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ struct zvol_state {
kmutex_t zv_state_lock; /* protects zvol_state_t */
atomic_t zv_suspend_ref; /* refcount for suspend */
krwlock_t zv_suspend_lock; /* suspend lock */
kcondvar_t zv_write_cv; /* write queue wait */
unsigned long zv_writes; /* in-flight writes */
kcondvar_t zv_read_cv; /* read queue wait */
unsigned long zv_reads; /* in-flight reads */
};

typedef enum {
Expand Down Expand Up @@ -783,6 +787,11 @@ zvol_write(void *arg)
generic_end_io_acct(WRITE, &zv->zv_disk->part0, start_jif);
BIO_END_IO(bio, -error);
kmem_free(zvr, sizeof (zv_request_t));

mutex_enter(&zv->zv_state_lock);
zv->zv_writes--;
cv_signal(&zv->zv_write_cv);
mutex_exit(&zv->zv_state_lock);
}

/*
Expand Down Expand Up @@ -865,6 +874,11 @@ zvol_discard(void *arg)
generic_end_io_acct(WRITE, &zv->zv_disk->part0, start_jif);
BIO_END_IO(bio, -error);
kmem_free(zvr, sizeof (zv_request_t));

mutex_enter(&zv->zv_state_lock);
zv->zv_writes--;
cv_signal(&zv->zv_write_cv);
mutex_exit(&zv->zv_state_lock);
}

static void
Expand Down Expand Up @@ -906,6 +920,11 @@ zvol_read(void *arg)
generic_end_io_acct(READ, &zv->zv_disk->part0, start_jif);
BIO_END_IO(bio, -error);
kmem_free(zvr, sizeof (zv_request_t));

mutex_enter(&zv->zv_state_lock);
zv->zv_reads--;
cv_signal(&zv->zv_read_cv);
mutex_exit(&zv->zv_state_lock);
}

static MAKE_REQUEST_FN_RET
Expand Down Expand Up @@ -952,6 +971,12 @@ zvol_request(struct request_queue *q, struct bio *bio)
goto out;
}

mutex_enter(&zv->zv_state_lock);
while (zv->zv_writes >= blk_queue_nr_requests(zv->zv_queue))
cv_wait(&zv->zv_write_cv, &zv->zv_state_lock);
zv->zv_writes++;
mutex_exit(&zv->zv_state_lock);

zvr = kmem_alloc(sizeof (zv_request_t), KM_SLEEP);
zvr->zv = zv;
zvr->bio = bio;
Expand All @@ -973,6 +998,12 @@ zvol_request(struct request_queue *q, struct bio *bio)
zvol_write(zvr);
}
} else {
mutex_enter(&zv->zv_state_lock);
while (zv->zv_reads >= blk_queue_nr_requests(zv->zv_queue))
cv_wait(&zv->zv_read_cv, &zv->zv_state_lock);
zv->zv_reads++;
mutex_exit(&zv->zv_state_lock);

zvr = kmem_alloc(sizeof (zv_request_t), KM_SLEEP);
zvr->zv = zv;
zvr->bio = bio;
Expand Down Expand Up @@ -1601,6 +1632,10 @@ zvol_alloc(dev_t dev, const char *name)
list_link_init(&zv->zv_next);

mutex_init(&zv->zv_state_lock, NULL, MUTEX_DEFAULT, NULL);
cv_init(&zv->zv_write_cv, NULL, CV_DEFAULT, NULL);
cv_init(&zv->zv_read_cv, NULL, CV_DEFAULT, NULL);
zv->zv_reads = 0;
zv->zv_writes = 0;

zv->zv_queue = blk_alloc_queue(GFP_ATOMIC);
if (zv->zv_queue == NULL)
Expand Down Expand Up @@ -1671,7 +1706,12 @@ zvol_free(void *arg)

ida_simple_remove(&zvol_ida, MINOR(zv->zv_dev) >> ZVOL_MINOR_BITS);

ASSERT0(zv->zv_reads);
ASSERT0(zv->zv_writes);

mutex_destroy(&zv->zv_state_lock);
cv_destroy(&zv->zv_write_cv);
cv_destroy(&zv->zv_read_cv);

kmem_free(zv, sizeof (zvol_state_t));
}
Expand Down

0 comments on commit f61d640

Please sign in to comment.