aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/vdev_disk.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/vdev_disk.c')
-rw-r--r--module/zfs/vdev_disk.c43
1 files changed, 41 insertions, 2 deletions
diff --git a/module/zfs/vdev_disk.c b/module/zfs/vdev_disk.c
index ce65760ee..67759d021 100644
--- a/module/zfs/vdev_disk.c
+++ b/module/zfs/vdev_disk.c
@@ -30,6 +30,7 @@
#include <sys/spa.h>
#include <sys/vdev_disk.h>
#include <sys/vdev_impl.h>
+#include <sys/abd.h>
#include <sys/fs/zfs.h>
#include <sys/zio.h>
#include <sys/sunldi.h>
@@ -42,6 +43,7 @@ static void *zfs_vdev_holder = VDEV_HOLDER;
*/
typedef struct dio_request {
zio_t *dr_zio; /* Parent ZIO */
+ void *dr_loanbuf; /* borrowed abd buffer */
atomic_t dr_ref; /* References */
int dr_error; /* Bio error */
int dr_bio_count; /* Count of bio's */
@@ -402,6 +404,7 @@ vdev_disk_dio_put(dio_request_t *dr)
*/
if (rc == 0) {
zio_t *zio = dr->dr_zio;
+ void *loanbuf = dr->dr_loanbuf;
int error = dr->dr_error;
vdev_disk_dio_free(dr);
@@ -411,6 +414,15 @@ vdev_disk_dio_put(dio_request_t *dr)
ASSERT3S(zio->io_error, >=, 0);
if (zio->io_error)
vdev_disk_error(zio);
+ /* ABD placeholder */
+ if (loanbuf != NULL) {
+ if (zio->io_type == ZIO_TYPE_READ) {
+ abd_copy_from_buf(zio->io_abd, loanbuf,
+ zio->io_size);
+ }
+ zio_buf_free(loanbuf, zio->io_size);
+ }
+
zio_delay_interrupt(zio);
}
}
@@ -547,7 +559,30 @@ retry:
* their volume block size to match the maximum request size and
* the common case will be one bio per vdev IO request.
*/
- bio_ptr = kbuf_ptr;
+ if (zio != NULL) {
+ abd_t *abd = zio->io_abd;
+
+ /*
+ * ABD placeholder
+ * We can't use abd_borrow_buf routines here since our
+ * completion context is interrupt and abd refcounts
+ * take a mutex (in debug mode).
+ */
+ if (abd_is_linear(abd)) {
+ bio_ptr = abd_to_buf(abd);
+ dr->dr_loanbuf = NULL;
+ } else {
+ bio_ptr = zio_buf_alloc(zio->io_size);
+ dr->dr_loanbuf = bio_ptr;
+ if (zio->io_type != ZIO_TYPE_READ)
+ abd_copy_to_buf(bio_ptr, abd, zio->io_size);
+
+ }
+ } else {
+ bio_ptr = kbuf_ptr;
+ dr->dr_loanbuf = NULL;
+ }
+
bio_offset = kbuf_offset;
bio_size = kbuf_size;
for (i = 0; i <= dr->dr_bio_count; i++) {
@@ -562,6 +597,8 @@ retry:
* are needed we allocate a larger dio and warn the user.
*/
if (dr->dr_bio_count == i) {
+ if (dr->dr_loanbuf)
+ zio_buf_free(dr->dr_loanbuf, zio->io_size);
vdev_disk_dio_free(dr);
bio_count *= 2;
goto retry;
@@ -571,6 +608,8 @@ retry:
dr->dr_bio[i] = bio_alloc(GFP_NOIO,
MIN(bio_nr_pages(bio_ptr, bio_size), BIO_MAX_PAGES));
if (unlikely(dr->dr_bio[i] == NULL)) {
+ if (dr->dr_loanbuf)
+ zio_buf_free(dr->dr_loanbuf, zio->io_size);
vdev_disk_dio_free(dr);
return (ENOMEM);
}
@@ -730,7 +769,7 @@ vdev_disk_io_start(zio_t *zio)
}
zio->io_target_timestamp = zio_handle_io_delay(zio);
- error = __vdev_disk_physio(vd->vd_bdev, zio, zio->io_data,
+ error = __vdev_disk_physio(vd->vd_bdev, zio, NULL,
zio->io_size, zio->io_offset, rw, flags);
if (error) {
zio->io_error = error;