aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/md
diff options
context:
space:
mode:
authorMikulas Patocka <mpatocka@redhat.com>2015-02-13 08:25:59 -0500
committerMike Snitzer <snitzer@redhat.com>2015-02-16 11:11:14 -0500
commitdc2676210c425ee8e5cb1bec5bc84d004ddf4179 (patch)
tree2d38e1d74895e7cf419a0408805ed73673d69425 /drivers/md
parent94f5e0243c48aa01441c987743dc468e2d6eaca2 (diff)
dm crypt: offload writes to thread
Submitting write bios directly in the encryption thread caused serious performance degradation. On a multiprocessor machine, encryption requests finish in a different order than they were submitted. Consequently, write requests would be submitted in a different order and it could cause severe performance degradation. Move the submission of write requests to a separate thread so that the requests can be sorted before submitting. But this commit improves dm-crypt performance even without having dm-crypt perform request sorting (in particular it enables IO schedulers like CFQ to sort more effectively). Note: it is required that a previous commit ("dm crypt: don't allocate pages for a partial request") be applied before applying this patch. Otherwise, this commit could introduce a crash. Signed-off-by: Mikulas Patocka <mpatocka@redhat.com> Signed-off-by: Mike Snitzer <snitzer@redhat.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/dm-crypt.c114
1 files changed, 94 insertions, 20 deletions
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index c29daf417aaf..8c0e36b1d0ed 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -18,6 +18,7 @@
18#include <linux/slab.h> 18#include <linux/slab.h>
19#include <linux/crypto.h> 19#include <linux/crypto.h>
20#include <linux/workqueue.h> 20#include <linux/workqueue.h>
21#include <linux/kthread.h>
21#include <linux/backing-dev.h> 22#include <linux/backing-dev.h>
22#include <linux/atomic.h> 23#include <linux/atomic.h>
23#include <linux/scatterlist.h> 24#include <linux/scatterlist.h>
@@ -58,6 +59,8 @@ struct dm_crypt_io {
58 atomic_t io_pending; 59 atomic_t io_pending;
59 int error; 60 int error;
60 sector_t sector; 61 sector_t sector;
62
63 struct list_head list;
61} CRYPTO_MINALIGN_ATTR; 64} CRYPTO_MINALIGN_ATTR;
62 65
63struct dm_crypt_request { 66struct dm_crypt_request {
@@ -128,6 +131,10 @@ struct crypt_config {
128 struct workqueue_struct *io_queue; 131 struct workqueue_struct *io_queue;
129 struct workqueue_struct *crypt_queue; 132 struct workqueue_struct *crypt_queue;
130 133
134 struct task_struct *write_thread;
135 wait_queue_head_t write_thread_wait;
136 struct list_head write_thread_list;
137
131 char *cipher; 138 char *cipher;
132 char *cipher_string; 139 char *cipher_string;
133 140
@@ -1136,37 +1143,89 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
1136 return 0; 1143 return 0;
1137} 1144}
1138 1145
1146static void kcryptd_io_read_work(struct work_struct *work)
1147{
1148 struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
1149
1150 crypt_inc_pending(io);
1151 if (kcryptd_io_read(io, GFP_NOIO))
1152 io->error = -ENOMEM;
1153 crypt_dec_pending(io);
1154}
1155
1156static void kcryptd_queue_read(struct dm_crypt_io *io)
1157{
1158 struct crypt_config *cc = io->cc;
1159
1160 INIT_WORK(&io->work, kcryptd_io_read_work);
1161 queue_work(cc->io_queue, &io->work);
1162}
1163
1139static void kcryptd_io_write(struct dm_crypt_io *io) 1164static void kcryptd_io_write(struct dm_crypt_io *io)
1140{ 1165{
1141 struct bio *clone = io->ctx.bio_out; 1166 struct bio *clone = io->ctx.bio_out;
1167
1142 generic_make_request(clone); 1168 generic_make_request(clone);
1143} 1169}
1144 1170
1145static void kcryptd_io(struct work_struct *work) 1171static int dmcrypt_write(void *data)
1146{ 1172{
1147 struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work); 1173 struct crypt_config *cc = data;
1174 while (1) {
1175 struct list_head local_list;
1176 struct blk_plug plug;
1148 1177
1149 if (bio_data_dir(io->base_bio) == READ) { 1178 DECLARE_WAITQUEUE(wait, current);
1150 crypt_inc_pending(io);
1151 if (kcryptd_io_read(io, GFP_NOIO))
1152 io->error = -ENOMEM;
1153 crypt_dec_pending(io);
1154 } else
1155 kcryptd_io_write(io);
1156}
1157 1179
1158static void kcryptd_queue_io(struct dm_crypt_io *io) 1180 spin_lock_irq(&cc->write_thread_wait.lock);
1159{ 1181continue_locked:
1160 struct crypt_config *cc = io->cc;
1161 1182
1162 INIT_WORK(&io->work, kcryptd_io); 1183 if (!list_empty(&cc->write_thread_list))
1163 queue_work(cc->io_queue, &io->work); 1184 goto pop_from_list;
1185
1186 __set_current_state(TASK_INTERRUPTIBLE);
1187 __add_wait_queue(&cc->write_thread_wait, &wait);
1188
1189 spin_unlock_irq(&cc->write_thread_wait.lock);
1190
1191 if (unlikely(kthread_should_stop())) {
1192 set_task_state(current, TASK_RUNNING);
1193 remove_wait_queue(&cc->write_thread_wait, &wait);
1194 break;
1195 }
1196
1197 schedule();
1198
1199 set_task_state(current, TASK_RUNNING);
1200 spin_lock_irq(&cc->write_thread_wait.lock);
1201 __remove_wait_queue(&cc->write_thread_wait, &wait);
1202 goto continue_locked;
1203
1204pop_from_list:
1205 local_list = cc->write_thread_list;
1206 local_list.next->prev = &local_list;
1207 local_list.prev->next = &local_list;
1208 INIT_LIST_HEAD(&cc->write_thread_list);
1209
1210 spin_unlock_irq(&cc->write_thread_wait.lock);
1211
1212 blk_start_plug(&plug);
1213 do {
1214 struct dm_crypt_io *io = container_of(local_list.next,
1215 struct dm_crypt_io, list);
1216 list_del(&io->list);
1217 kcryptd_io_write(io);
1218 } while (!list_empty(&local_list));
1219 blk_finish_plug(&plug);
1220 }
1221 return 0;
1164} 1222}
1165 1223
1166static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async) 1224static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
1167{ 1225{
1168 struct bio *clone = io->ctx.bio_out; 1226 struct bio *clone = io->ctx.bio_out;
1169 struct crypt_config *cc = io->cc; 1227 struct crypt_config *cc = io->cc;
1228 unsigned long flags;
1170 1229
1171 if (unlikely(io->error < 0)) { 1230 if (unlikely(io->error < 0)) {
1172 crypt_free_buffer_pages(cc, clone); 1231 crypt_free_buffer_pages(cc, clone);
@@ -1180,10 +1239,10 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
1180 1239
1181 clone->bi_iter.bi_sector = cc->start + io->sector; 1240 clone->bi_iter.bi_sector = cc->start + io->sector;
1182 1241
1183 if (async) 1242 spin_lock_irqsave(&cc->write_thread_wait.lock, flags);
1184 kcryptd_queue_io(io); 1243 list_add_tail(&io->list, &cc->write_thread_list);
1185 else 1244 wake_up_locked(&cc->write_thread_wait);
1186 generic_make_request(clone); 1245 spin_unlock_irqrestore(&cc->write_thread_wait.lock, flags);
1187} 1246}
1188 1247
1189static void kcryptd_crypt_write_convert(struct dm_crypt_io *io) 1248static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
@@ -1426,6 +1485,9 @@ static void crypt_dtr(struct dm_target *ti)
1426 if (!cc) 1485 if (!cc)
1427 return; 1486 return;
1428 1487
1488 if (cc->write_thread)
1489 kthread_stop(cc->write_thread);
1490
1429 if (cc->io_queue) 1491 if (cc->io_queue)
1430 destroy_workqueue(cc->io_queue); 1492 destroy_workqueue(cc->io_queue);
1431 if (cc->crypt_queue) 1493 if (cc->crypt_queue)
@@ -1764,6 +1826,18 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
1764 goto bad; 1826 goto bad;
1765 } 1827 }
1766 1828
1829 init_waitqueue_head(&cc->write_thread_wait);
1830 INIT_LIST_HEAD(&cc->write_thread_list);
1831
1832 cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write");
1833 if (IS_ERR(cc->write_thread)) {
1834 ret = PTR_ERR(cc->write_thread);
1835