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

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'iomap-5.5-merge-14' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux

Pull iomap fixes from Darrick Wong:
"Fix a race condition and a use-after-free error:

- Fix a UAF when reporting writeback errors

- Fix a race condition when handling page uptodate on fragmented file
with blocksize < pagesize"

* tag 'iomap-5.5-merge-14' of git://git.kernel.org/pub/scm/fs/xfs/xfs-linux:
iomap: stop using ioend after it's been freed in iomap_finish_ioend()
iomap: fix sub-page uptodate handling

+28 -12
+28 -12
fs/iomap/buffered-io.c
··· 28 28 struct iomap_page { 29 29 atomic_t read_count; 30 30 atomic_t write_count; 31 + spinlock_t uptodate_lock; 31 32 DECLARE_BITMAP(uptodate, PAGE_SIZE / 512); 32 33 }; 33 34 ··· 52 51 iop = kmalloc(sizeof(*iop), GFP_NOFS | __GFP_NOFAIL); 53 52 atomic_set(&iop->read_count, 0); 54 53 atomic_set(&iop->write_count, 0); 54 + spin_lock_init(&iop->uptodate_lock); 55 55 bitmap_zero(iop->uptodate, PAGE_SIZE / SECTOR_SIZE); 56 56 57 57 /* ··· 141 139 } 142 140 143 141 static void 144 - iomap_set_range_uptodate(struct page *page, unsigned off, unsigned len) 142 + iomap_iop_set_range_uptodate(struct page *page, unsigned off, unsigned len) 145 143 { 146 144 struct iomap_page *iop = to_iomap_page(page); 147 145 struct inode *inode = page->mapping->host; 148 146 unsigned first = off >> inode->i_blkbits; 149 147 unsigned last = (off + len - 1) >> inode->i_blkbits; 150 - unsigned int i; 151 148 bool uptodate = true; 149 + unsigned long flags; 150 + unsigned int i; 152 151 153 - if (iop) { 154 - for (i = 0; i < PAGE_SIZE / i_blocksize(inode); i++) { 155 - if (i >= first && i <= last) 156 - set_bit(i, iop->uptodate); 157 - else if (!test_bit(i, iop->uptodate)) 158 - uptodate = false; 159 - } 152 + spin_lock_irqsave(&iop->uptodate_lock, flags); 153 + for (i = 0; i < PAGE_SIZE / i_blocksize(inode); i++) { 154 + if (i >= first && i <= last) 155 + set_bit(i, iop->uptodate); 156 + else if (!test_bit(i, iop->uptodate)) 157 + uptodate = false; 160 158 } 161 159 162 - if (uptodate && !PageError(page)) 160 + if (uptodate) 161 + SetPageUptodate(page); 162 + spin_unlock_irqrestore(&iop->uptodate_lock, flags); 163 + } 164 + 165 + static void 166 + iomap_set_range_uptodate(struct page *page, unsigned off, unsigned len) 167 + { 168 + if (PageError(page)) 169 + return; 170 + 171 + if (page_has_private(page)) 172 + iomap_iop_set_range_uptodate(page, off, len); 173 + else 163 174 SetPageUptodate(page); 164 175 } 165 176 ··· 1143 1128 struct bio *bio = &ioend->io_inline_bio; 1144 1129 struct bio *last = ioend->io_bio, *next; 1145 1130 u64 start = bio->bi_iter.bi_sector; 1131 + loff_t offset = ioend->io_offset; 1146 1132 bool quiet = bio_flagged(bio, BIO_QUIET); 1147 1133 1148 1134 for (bio = &ioend->io_inline_bio; bio; bio = next) { ··· 1164 1148 iomap_finish_page_writeback(inode, bv->bv_page, error); 1165 1149 bio_put(bio); 1166 1150 } 1151 + /* The ioend has been freed by bio_put() */ 1167 1152 1168 1153 if (unlikely(error && !quiet)) { 1169 1154 printk_ratelimited(KERN_ERR 1170 1155 "%s: writeback error on inode %lu, offset %lld, sector %llu", 1171 - inode->i_sb->s_id, inode->i_ino, ioend->io_offset, 1172 - start); 1156 + inode->i_sb->s_id, inode->i_ino, offset, start); 1173 1157 } 1174 1158 } 1175 1159