summaryrefslogtreecommitdiffstats
path: root/patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch')
-rw-r--r--patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch158
1 files changed, 158 insertions, 0 deletions
diff --git a/patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch b/patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch
new file mode 100644
index 0000000..7d0def8
--- /dev/null
+++ b/patches/boot_time_opt/0112-fs-ext4-fsync-optimize-double-fsync-a-bunch.patch
@@ -0,0 +1,158 @@
1From 3152053ea1ea3aa77bcc7e990d48ef84621ff6c9 Mon Sep 17 00:00:00 2001
2From: Arjan van de Ven <arjan@linux.intel.com>
3Date: Sat, 9 Apr 2016 22:41:37 +0000
4Subject: [PATCH 112/124] fs: ext4: fsync: optimize double-fsync() a bunch
5
6There are cases where EXT4 is a bit too conservative sending barriers down to the disk;
7there are cases where the transaction in progress is not the one that sent the barrier
8(in other words: the fsync is for a file for which the IO happened more time ago
9and all data was already sent to the disk). For that case, a more performing tradeoff
10can be made on SSD devices (which have the ability to flush their dram caches in a hurry
11on a power fail event) where the barrier gets sent to the disk, but we don't need to wait
12for the barrier to complete. Any consecutive IO will block on the barrier correctly.
13---
14 block/bio.c | 20 ++++++++++++++++++++
15 block/blk-flush.c | 41 +++++++++++++++++++++++++++++++++++++++++
16 fs/ext4/fsync.c | 6 +++++-
17 include/linux/bio.h | 1 +
18 include/linux/blkdev.h | 5 +++++
19 5 files changed, 72 insertions(+), 1 deletion(-)
20
21diff --git a/block/bio.c b/block/bio.c
22index db85c5753a76..80f5ab6b536a 100644
23--- a/block/bio.c
24+++ b/block/bio.c
25@@ -882,6 +882,26 @@ int submit_bio_wait(struct bio *bio)
26 }
27 EXPORT_SYMBOL(submit_bio_wait);
28
29+static void submit_bio_nowait_endio(struct bio *bio)
30+{
31+ bio_put(bio);
32+}
33+
34+/**
35+ * submit_bio_nowait - submit a bio for fire-and-forget
36+ * @rw: whether to %READ or %WRITE, or maybe to %READA (read ahead)
37+ * @bio: The &struct bio which describes the I/O
38+ *
39+ * Simple wrapper around submit_bio() that takes care of bio_put() on completion
40+ */
41+void submit_bio_nowait(struct bio *bio)
42+{
43+ bio->bi_end_io = submit_bio_nowait_endio;
44+ bio->bi_opf |= REQ_SYNC;
45+ submit_bio(bio);
46+}
47+EXPORT_SYMBOL(submit_bio_nowait);
48+
49 /**
50 * bio_advance - increment/complete a bio by some number of bytes
51 * @bio: bio to advance
52diff --git a/block/blk-flush.c b/block/blk-flush.c
53index 3c882cbc7541..b2dfcfe01ed7 100644
54--- a/block/blk-flush.c
55+++ b/block/blk-flush.c
56@@ -530,6 +530,47 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
57 }
58 EXPORT_SYMBOL(blkdev_issue_flush);
59
60+/**
61+ * blkdev_issue_flush_nowait - queue a flush
62+ * @bdev: blockdev to issue flush for
63+ * @gfp_mask: memory allocation flags (for bio_alloc)
64+ * @error_sector: error sector
65+ *
66+ * Description:
67+ * Issue a flush for the block device in question. Caller can supply
68+ * room for storing the error offset in case of a flush error, if they
69+ * wish to. If WAIT flag is not passed then caller may check only what
70+ * request was pushed in some internal queue for later handling.
71+ */
72+void blkdev_issue_flush_nowait(struct block_device *bdev, gfp_t gfp_mask)
73+{
74+ struct request_queue *q;
75+ struct bio *bio;
76+
77+ if (bdev->bd_disk == NULL)
78+ return;
79+
80+ q = bdev_get_queue(bdev);
81+ if (!q)
82+ return;
83+
84+ /*
85+ * some block devices may not have their queue correctly set up here
86+ * (e.g. loop device without a backing file) and so issuing a flush
87+ * here will panic. Ensure there is a request function before issuing
88+ * the flush.
89+ */
90+ if (!q->make_request_fn)
91+ return;
92+
93+ bio = bio_alloc(gfp_mask, 0);
94+ bio->bi_bdev = bdev;
95+ bio_set_op_attrs(bio, REQ_OP_WRITE, WRITE_FLUSH);
96+
97+ submit_bio_nowait(bio);
98+}
99+EXPORT_SYMBOL(blkdev_issue_flush_nowait);
100+
101 struct blk_flush_queue *blk_alloc_flush_queue(struct request_queue *q,
102 int node, int cmd_size)
103 {
104diff --git a/fs/ext4/fsync.c b/fs/ext4/fsync.c
105index 88effb1053c7..a58966c18172 100644
106--- a/fs/ext4/fsync.c
107+++ b/fs/ext4/fsync.c
108@@ -150,7 +150,11 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
109 ret = jbd2_complete_transaction(journal, commit_tid);
110 if (needs_barrier) {
111 issue_flush:
112- err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
113+ err = 0;
114+ if (!blk_queue_nonrot(bdev_get_queue(inode->i_sb->s_bdev)))
115+ err = blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
116+ else
117+ blkdev_issue_flush_nowait(inode->i_sb->s_bdev, GFP_KERNEL);
118 if (!ret)
119 ret = err;
120 }
121diff --git a/include/linux/bio.h b/include/linux/bio.h
122index 97cb48f03dc7..3f055e6541e0 100644
123--- a/include/linux/bio.h
124+++ b/include/linux/bio.h
125@@ -421,6 +421,7 @@ struct request_queue;
126 extern int bio_phys_segments(struct request_queue *, struct bio *);
127
128 extern int submit_bio_wait(struct bio *bio);
129+extern void submit_bio_nowait(struct bio *bio);
130 extern void bio_advance(struct bio *, unsigned);
131
132 extern void bio_init(struct bio *);
133diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
134index f6a816129856..727684abf21e 100644
135--- a/include/linux/blkdev.h
136+++ b/include/linux/blkdev.h
137@@ -1144,6 +1144,7 @@ static inline struct request *blk_map_queue_find_tag(struct blk_queue_tag *bqt,
138 #define BLKDEV_DISCARD_ZERO (1 << 1) /* must reliably zero data */
139
140 extern int blkdev_issue_flush(struct block_device *, gfp_t, sector_t *);
141+extern void blkdev_issue_flush_nowait(struct block_device *, gfp_t);
142 extern int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
143 sector_t nr_sects, gfp_t gfp_mask, unsigned long flags);
144 extern int __blkdev_issue_discard(struct block_device *bdev, sector_t sector,
145@@ -1745,6 +1746,10 @@ static inline int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
146 return 0;
147 }
148
149+static inline void blkdev_issue_flush_nowait(struct block_device *bdev, gfp_t gfp_mask)
150+{
151+}
152+
153 #endif /* CONFIG_BLOCK */
154
155 #endif
156--
1572.11.1
158