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 'for-6.6/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm

Pull device mapper fixes from Mike Snitzer:

- Fix DM core retrieve_deps() UAF race due to missing locking of a DM
table's list of devices that is managed using dm_{get,put}_device.

- Revert DM core's half-baked RCU optimization if IO submitter has set
REQ_NOWAIT. Can be revisited, and properly justified, after
comprehensively auditing all of DM to also pass GFP_NOWAIT for any
allocations if REQ_NOWAIT used.

* tag 'for-6.6/dm-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/device-mapper/linux-dm:
dm: don't attempt to queue IO under RCU protection
dm: fix a race condition in retrieve_deps

+33 -30
+1
drivers/md/dm-core.h
··· 214 214 215 215 /* a list of devices used by this table */ 216 216 struct list_head devices; 217 + struct rw_semaphore devices_lock; 217 218 218 219 /* events get handed up using this callback */ 219 220 void (*event_fn)(void *data);
+6 -1
drivers/md/dm-ioctl.c
··· 1630 1630 struct dm_dev_internal *dd; 1631 1631 struct dm_target_deps *deps; 1632 1632 1633 + down_read(&table->devices_lock); 1634 + 1633 1635 deps = get_result_buffer(param, param_size, &len); 1634 1636 1635 1637 /* ··· 1646 1644 needed = struct_size(deps, dev, count); 1647 1645 if (len < needed) { 1648 1646 param->flags |= DM_BUFFER_FULL_FLAG; 1649 - return; 1647 + goto out; 1650 1648 } 1651 1649 1652 1650 /* ··· 1658 1656 deps->dev[count++] = huge_encode_dev(dd->dm_dev->bdev->bd_dev); 1659 1657 1660 1658 param->data_size = param->data_start + needed; 1659 + 1660 + out: 1661 + up_read(&table->devices_lock); 1661 1662 } 1662 1663 1663 1664 static int table_deps(struct file *filp, struct dm_ioctl *param, size_t param_size)
+24 -8
drivers/md/dm-table.c
··· 135 135 return -ENOMEM; 136 136 137 137 INIT_LIST_HEAD(&t->devices); 138 + init_rwsem(&t->devices_lock); 138 139 139 140 if (!num_targets) 140 141 num_targets = KEYS_PER_NODE; ··· 360 359 if (dev == disk_devt(t->md->disk)) 361 360 return -EINVAL; 362 361 362 + down_write(&t->devices_lock); 363 + 363 364 dd = find_device(&t->devices, dev); 364 365 if (!dd) { 365 366 dd = kmalloc(sizeof(*dd), GFP_KERNEL); 366 - if (!dd) 367 - return -ENOMEM; 367 + if (!dd) { 368 + r = -ENOMEM; 369 + goto unlock_ret_r; 370 + } 368 371 369 372 r = dm_get_table_device(t->md, dev, mode, &dd->dm_dev); 370 373 if (r) { 371 374 kfree(dd); 372 - return r; 375 + goto unlock_ret_r; 373 376 } 374 377 375 378 refcount_set(&dd->count, 1); ··· 383 378 } else if (dd->dm_dev->mode != (mode | dd->dm_dev->mode)) { 384 379 r = upgrade_mode(dd, mode, t->md); 385 380 if (r) 386 - return r; 381 + goto unlock_ret_r; 387 382 } 388 383 refcount_inc(&dd->count); 389 384 out: 385 + up_write(&t->devices_lock); 390 386 *result = dd->dm_dev; 391 387 return 0; 388 + 389 + unlock_ret_r: 390 + up_write(&t->devices_lock); 391 + return r; 392 392 } 393 393 EXPORT_SYMBOL(dm_get_device); 394 394 ··· 429 419 void dm_put_device(struct dm_target *ti, struct dm_dev *d) 430 420 { 431 421 int found = 0; 432 - struct list_head *devices = &ti->table->devices; 422 + struct dm_table *t = ti->table; 423 + struct list_head *devices = &t->devices; 433 424 struct dm_dev_internal *dd; 425 + 426 + down_write(&t->devices_lock); 434 427 435 428 list_for_each_entry(dd, devices, list) { 436 429 if (dd->dm_dev == d) { ··· 443 430 } 444 431 if (!found) { 445 432 DMERR("%s: device %s not in table devices list", 446 - dm_device_name(ti->table->md), d->name); 447 - return; 433 + dm_device_name(t->md), d->name); 434 + goto unlock_ret; 448 435 } 449 436 if (refcount_dec_and_test(&dd->count)) { 450 - dm_put_table_device(ti->table->md, d); 437 + dm_put_table_device(t->md, d); 451 438 list_del(&dd->list); 452 439 kfree(dd); 453 440 } 441 + 442 + unlock_ret: 443 + up_write(&t->devices_lock); 454 444 } 455 445 EXPORT_SYMBOL(dm_put_device); 456 446
+2 -21
drivers/md/dm.c
··· 715 715 rcu_read_unlock(); 716 716 } 717 717 718 - static inline struct dm_table *dm_get_live_table_bio(struct mapped_device *md, 719 - int *srcu_idx, blk_opf_t bio_opf) 720 - { 721 - if (bio_opf & REQ_NOWAIT) 722 - return dm_get_live_table_fast(md); 723 - else 724 - return dm_get_live_table(md, srcu_idx); 725 - } 726 - 727 - static inline void dm_put_live_table_bio(struct mapped_device *md, int srcu_idx, 728 - blk_opf_t bio_opf) 729 - { 730 - if (bio_opf & REQ_NOWAIT) 731 - dm_put_live_table_fast(md); 732 - else 733 - dm_put_live_table(md, srcu_idx); 734 - } 735 - 736 718 static char *_dm_claim_ptr = "I belong to device-mapper"; 737 719 738 720 /* ··· 1815 1833 struct mapped_device *md = bio->bi_bdev->bd_disk->private_data; 1816 1834 int srcu_idx; 1817 1835 struct dm_table *map; 1818 - blk_opf_t bio_opf = bio->bi_opf; 1819 1836 1820 - map = dm_get_live_table_bio(md, &srcu_idx, bio_opf); 1837 + map = dm_get_live_table(md, &srcu_idx); 1821 1838 1822 1839 /* If suspended, or map not yet available, queue this IO for later */ 1823 1840 if (unlikely(test_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags)) || ··· 1832 1851 1833 1852 dm_split_and_process_bio(md, map, bio); 1834 1853 out: 1835 - dm_put_live_table_bio(md, srcu_idx, bio_opf); 1854 + dm_put_live_table(md, srcu_idx); 1836 1855 } 1837 1856 1838 1857 static bool dm_poll_dm_io(struct dm_io *io, struct io_comp_batch *iob,