Merge tag 'block-7.1-20260430' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux

Pull block fixes from Jens Axboe:

 - MD pull request via Yu:
      - Fix a raid5 UAF on IO across the reshape position
      - Avoid failing RAID1/RAID10 devices for invalid IO errors
      - Fix RAID10 divide-by-zero when far_copies is zero
      - Restore bitmap grow through sysfs
      - Use mddev_is_dm() instead of open-coding gendisk checks
      - Use ATTRIBUTE_GROUPS() for md default sysfs attributes
      - Replace open-coded wait loops with wait_event helpers

 - NVMe pull request via Keith:
      - Target data transfer size configuation (Aurelien)
      - Enable P2P for RDMA (Shivaji Kant)
      - TCP target updates (Maurizio, Alistair, Chaitanya, Shivam Kumar)
      - TCP host updates (Alistair, Chaitanya)
      - Authentication updates (Alistair, Daniel, Chris Leech)
      - Multipath fixes (John Garry)
      - New quirks (Alan Cui, Tao Jiang)
      - Apple driver fix (Fedor Pchelkin)
      - PCI admin doorbell update fix (Keith)

 - Properly propagate CDROM read-only state to the block layer

* tag 'block-7.1-20260430' of git://git.kernel.org/pub/scm/linux/kernel/git/axboe/linux: (35 commits)
  md: use ATTRIBUTE_GROUPS() for md default sysfs attributes
  md: use mddev_is_dm() instead of open-coding gendisk checks
  md/raid1: replace wait loop with wait_event_idle() in raid1_write_request()
  md/md-bitmap: add a none backend for bitmap grow
  md/md-bitmap: split bitmap sysfs groups
  md: factor bitmap creation away from sysfs handling
  md: use mddev_lock_nointr() in mddev_suspend_and_lock_nointr()
  md: replace wait loop with wait_event() in md_handle_request()
  md/raid10: fix divide-by-zero in setup_geo() with zero far_copies
  md/raid1,raid10: don't fail devices for invalid IO errors
  MAINTAINERS: Add Xiao Ni as md/raid reviewer
  md/raid5: Fix UAF on IO across the reshape position
  cdrom, scsi: sr: propagate read-only status to block layer via set_disk_ro()
  nvme-auth: Hash DH shared secret to create session key
  nvme-pci: fix missed admin queue sq doorbell write
  nvme-auth: Include SC_C in RVAL controller hash
  nvme-tcp: teardown circular locking fixes
  nvmet-tcp: Don't clear tls_key when freeing sq
  Revert "nvmet-tcp: Don't free SQ on authentication success"
  nvme: skip trace completion for host path errors
  ...
This commit is contained in:
Linus Torvalds
2026-05-01 11:26:15 -07:00
33 changed files with 588 additions and 276 deletions

View File

@@ -24798,6 +24798,7 @@ SOFTWARE RAID (Multiple Disks) SUPPORT
M: Song Liu <song@kernel.org>
M: Yu Kuai <yukuai@fnnas.com>
R: Li Nan <linan122@huawei.com>
R: Xiao Ni <xiao@kernel.org>
L: linux-raid@vger.kernel.org
S: Supported
Q: https://patchwork.kernel.org/project/linux-raid/list/

View File

@@ -631,6 +631,16 @@ int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi)
WARN_ON(!cdo->generic_packet);
/*
* Propagate the drive's write support to the block layer so BLKROGET
* reflects actual write capability. Drivers that use GET CONFIGURATION
* features (CDC_MRW_W, CDC_RAM) must have called
* cdrom_probe_write_features() before register_cdrom() so the mask is
* complete here.
*/
set_disk_ro(disk, !CDROM_CAN(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM |
CDC_CD_RW));
cd_dbg(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
mutex_lock(&cdrom_mutex);
list_add(&cdi->list, &cdrom_list);
@@ -742,6 +752,44 @@ static int cdrom_is_random_writable(struct cdrom_device_info *cdi, int *write)
return 0;
}
/*
* Probe write-related MMC features via GET CONFIGURATION and update
* cdi->mask accordingly. Drivers that populate cdi->mask from the MODE SENSE
* capabilities page (e.g. sr) should call this after those MODE SENSE bits
* have been set but before register_cdrom(), so that the full set of
* write-capability bits is known by the time register_cdrom() decides on the
* initial read-only state of the disk.
*/
void cdrom_probe_write_features(struct cdrom_device_info *cdi)
{
int mrw, mrw_write, ram_write;
mrw = 0;
if (!cdrom_is_mrw(cdi, &mrw_write))
mrw = 1;
if (CDROM_CAN(CDC_MO_DRIVE))
ram_write = 1;
else
(void) cdrom_is_random_writable(cdi, &ram_write);
if (mrw)
cdi->mask &= ~CDC_MRW;
else
cdi->mask |= CDC_MRW;
if (mrw_write)
cdi->mask &= ~CDC_MRW_W;
else
cdi->mask |= CDC_MRW_W;
if (ram_write)
cdi->mask &= ~CDC_RAM;
else
cdi->mask |= CDC_RAM;
}
EXPORT_SYMBOL(cdrom_probe_write_features);
static int cdrom_media_erasable(struct cdrom_device_info *cdi)
{
disc_information di;
@@ -894,33 +942,8 @@ static int cdrom_is_dvd_rw(struct cdrom_device_info *cdi)
*/
static int cdrom_open_write(struct cdrom_device_info *cdi)
{
int mrw, mrw_write, ram_write;
int ret = 1;
mrw = 0;
if (!cdrom_is_mrw(cdi, &mrw_write))
mrw = 1;
if (CDROM_CAN(CDC_MO_DRIVE))
ram_write = 1;
else
(void) cdrom_is_random_writable(cdi, &ram_write);
if (mrw)
cdi->mask &= ~CDC_MRW;
else
cdi->mask |= CDC_MRW;
if (mrw_write)
cdi->mask &= ~CDC_MRW_W;
else
cdi->mask |= CDC_MRW_W;
if (ram_write)
cdi->mask &= ~CDC_RAM;
else
cdi->mask |= CDC_RAM;
if (CDROM_CAN(CDC_MRW_W))
ret = cdrom_mrw_open_write(cdi);
else if (CDROM_CAN(CDC_DVD_RAM))

View File

@@ -216,6 +216,7 @@ struct bitmap {
};
static struct workqueue_struct *md_bitmap_wq;
static struct attribute_group md_bitmap_internal_group;
static int __bitmap_resize(struct bitmap *bitmap, sector_t blocks,
int chunksize, bool init);
@@ -2580,6 +2581,30 @@ static int bitmap_resize(struct mddev *mddev, sector_t blocks, int chunksize)
return __bitmap_resize(bitmap, blocks, chunksize, false);
}
static bool bitmap_none_enabled(void *data, bool flush)
{
return false;
}
static int bitmap_none_create(struct mddev *mddev)
{
return 0;
}
static int bitmap_none_load(struct mddev *mddev)
{
return 0;
}
static void bitmap_none_destroy(struct mddev *mddev)
{
}
static int bitmap_none_get_stats(void *data, struct md_bitmap_stats *stats)
{
return -ENOENT;
}
static ssize_t
location_show(struct mddev *mddev, char *page)
{
@@ -2618,7 +2643,11 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
goto out;
}
bitmap_destroy(mddev);
sysfs_unmerge_group(&mddev->kobj, &md_bitmap_internal_group);
md_bitmap_destroy_nosysfs(mddev);
mddev->bitmap_id = ID_BITMAP_NONE;
if (!mddev_set_bitmap_ops_nosysfs(mddev))
goto none_err;
mddev->bitmap_info.offset = 0;
if (mddev->bitmap_info.file) {
struct file *f = mddev->bitmap_info.file;
@@ -2654,16 +2683,25 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
}
mddev->bitmap_info.offset = offset;
rv = bitmap_create(mddev);
if (rv)
goto out;
md_bitmap_destroy_nosysfs(mddev);
mddev->bitmap_id = ID_BITMAP;
if (!mddev_set_bitmap_ops_nosysfs(mddev))
goto bitmap_err;
rv = bitmap_load(mddev);
rv = md_bitmap_create_nosysfs(mddev);
if (rv)
goto create_err;
rv = mddev->bitmap_ops->load(mddev);
if (rv) {
mddev->bitmap_info.offset = 0;
bitmap_destroy(mddev);
goto out;
goto load_err;
}
rv = sysfs_merge_group(&mddev->kobj,
&md_bitmap_internal_group);
if (rv)
goto merge_err;
}
}
if (!mddev->external) {
@@ -2679,6 +2717,22 @@ location_store(struct mddev *mddev, const char *buf, size_t len)
if (rv)
return rv;
return len;
merge_err:
mddev->bitmap_info.offset = 0;
load_err:
md_bitmap_destroy_nosysfs(mddev);
create_err:
mddev->bitmap_info.offset = 0;
mddev->bitmap_id = ID_BITMAP_NONE;
if (!mddev_set_bitmap_ops_nosysfs(mddev))
rv = -ENOENT;
goto out;
bitmap_err:
rv = -ENOENT;
none_err:
mddev->bitmap_info.offset = 0;
goto out;
}
static struct md_sysfs_entry bitmap_location =
@@ -2955,8 +3009,12 @@ static struct md_sysfs_entry max_backlog_used =
__ATTR(max_backlog_used, S_IRUGO | S_IWUSR,
behind_writes_used_show, behind_writes_used_reset);
static struct attribute *md_bitmap_attrs[] = {
static struct attribute *md_bitmap_common_attrs[] = {
&bitmap_location.attr,
NULL
};
static struct attribute *md_bitmap_internal_attrs[] = {
&bitmap_space.attr,
&bitmap_timeout.attr,
&bitmap_backlog.attr,
@@ -2967,9 +3025,41 @@ static struct attribute *md_bitmap_attrs[] = {
NULL
};
static struct attribute_group md_bitmap_group = {
static struct attribute_group md_bitmap_common_group = {
.name = "bitmap",
.attrs = md_bitmap_attrs,
.attrs = md_bitmap_common_attrs,
};
static struct attribute_group md_bitmap_internal_group = {
.name = "bitmap",
.attrs = md_bitmap_internal_attrs,
};
static const struct attribute_group *bitmap_groups[] = {
&md_bitmap_common_group,
&md_bitmap_internal_group,
NULL,
};
static const struct attribute_group *bitmap_none_groups[] = {
&md_bitmap_common_group,
NULL,
};
static struct bitmap_operations bitmap_none_ops = {
.head = {
.type = MD_BITMAP,
.id = ID_BITMAP_NONE,
.name = "none",
},
.enabled = bitmap_none_enabled,
.create = bitmap_none_create,
.load = bitmap_none_load,
.destroy = bitmap_none_destroy,
.get_stats = bitmap_none_get_stats,
.groups = bitmap_none_groups,
};
static struct bitmap_operations bitmap_ops = {
@@ -3013,21 +3103,38 @@ static struct bitmap_operations bitmap_ops = {
.set_pages = bitmap_set_pages,
.free = md_bitmap_free,
.group = &md_bitmap_group,
.groups = bitmap_groups,
};
int md_bitmap_init(void)
{
int err;
md_bitmap_wq = alloc_workqueue("md_bitmap", WQ_MEM_RECLAIM | WQ_UNBOUND,
0);
if (!md_bitmap_wq)
return -ENOMEM;
return register_md_submodule(&bitmap_ops.head);
err = register_md_submodule(&bitmap_none_ops.head);
if (err)
goto err_wq;
err = register_md_submodule(&bitmap_ops.head);
if (err)
goto err_none;
return 0;
err_none:
unregister_md_submodule(&bitmap_none_ops.head);
err_wq:
destroy_workqueue(md_bitmap_wq);
return err;
}
void md_bitmap_exit(void)
{
destroy_workqueue(md_bitmap_wq);
unregister_md_submodule(&bitmap_ops.head);
unregister_md_submodule(&bitmap_none_ops.head);
destroy_workqueue(md_bitmap_wq);
}

View File

@@ -125,7 +125,7 @@ struct bitmap_operations {
void (*set_pages)(void *data, unsigned long pages);
void (*free)(void *data);
struct attribute_group *group;
const struct attribute_group **groups;
};
/* the bitmap API */

View File

@@ -1738,6 +1738,11 @@ static struct attribute_group md_llbitmap_group = {
.attrs = md_llbitmap_attrs,
};
static const struct attribute_group *md_llbitmap_groups[] = {
&md_llbitmap_group,
NULL,
};
static struct bitmap_operations llbitmap_ops = {
.head = {
.type = MD_BITMAP,
@@ -1774,7 +1779,7 @@ static struct bitmap_operations llbitmap_ops = {
.dirty_bits = llbitmap_dirty_bits,
.write_all = llbitmap_write_all,
.group = &md_llbitmap_group,
.groups = md_llbitmap_groups,
};
int md_llbitmap_init(void)

View File

@@ -396,27 +396,19 @@ bool md_handle_request(struct mddev *mddev, struct bio *bio)
{
check_suspended:
if (is_suspended(mddev, bio)) {
DEFINE_WAIT(__wait);
/* Bail out if REQ_NOWAIT is set for the bio */
if (bio->bi_opf & REQ_NOWAIT) {
bio_wouldblock_error(bio);
return true;
}
for (;;) {
prepare_to_wait(&mddev->sb_wait, &__wait,
TASK_UNINTERRUPTIBLE);
if (!is_suspended(mddev, bio))
break;
schedule();
}
finish_wait(&mddev->sb_wait, &__wait);
wait_event(mddev->sb_wait, !is_suspended(mddev, bio));
}
if (!percpu_ref_tryget_live(&mddev->active_io))
goto check_suspended;
if (!mddev->pers->make_request(mddev, bio)) {
percpu_ref_put(&mddev->active_io);
if (!mddev->gendisk && mddev->pers->prepare_suspend)
if (mddev_is_dm(mddev) && mddev->pers->prepare_suspend)
return false;
goto check_suspended;
}
@@ -687,13 +679,38 @@ static void active_io_release(struct percpu_ref *ref)
static void no_op(struct percpu_ref *r) {}
static bool mddev_set_bitmap_ops(struct mddev *mddev)
static void md_bitmap_sysfs_add(struct mddev *mddev)
{
if (sysfs_update_groups(&mddev->kobj, mddev->bitmap_ops->groups))
pr_warn("md: cannot register extra bitmap attributes for %s\n",
mdname(mddev));
else
/*
* Inform user with KOBJ_CHANGE about new bitmap
* attributes.
*/
kobject_uevent(&mddev->kobj, KOBJ_CHANGE);
}
static void md_bitmap_sysfs_del(struct mddev *mddev)
{
int nr_groups = 0;
for (nr_groups = 0; mddev->bitmap_ops->groups[nr_groups]; nr_groups++)
;
while (--nr_groups >= 1)
sysfs_unmerge_group(&mddev->kobj,
mddev->bitmap_ops->groups[nr_groups]);
sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->groups[0]);
}
bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev)
{
struct bitmap_operations *old = mddev->bitmap_ops;
struct md_submodule_head *head;
if (mddev->bitmap_id == ID_BITMAP_NONE ||
(old && old->head.id == mddev->bitmap_id))
if (mddev->bitmap_ops &&
mddev->bitmap_ops->head.id == mddev->bitmap_id)
return true;
xa_lock(&md_submodule);
@@ -711,18 +728,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev)
mddev->bitmap_ops = (void *)head;
xa_unlock(&md_submodule);
if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) {
if (sysfs_create_group(&mddev->kobj, mddev->bitmap_ops->group))
pr_warn("md: cannot register extra bitmap attributes for %s\n",
mdname(mddev));
else
/*
* Inform user with KOBJ_CHANGE about new bitmap
* attributes.
*/
kobject_uevent(&mddev->kobj, KOBJ_CHANGE);
}
return true;
err:
@@ -730,15 +735,6 @@ static bool mddev_set_bitmap_ops(struct mddev *mddev)
return false;
}
static void mddev_clear_bitmap_ops(struct mddev *mddev)
{
if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
mddev->bitmap_ops->group)
sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group);
mddev->bitmap_ops = NULL;
}
int mddev_init(struct mddev *mddev)
{
int err = 0;
@@ -4279,7 +4275,7 @@ bitmap_type_show(struct mddev *mddev, char *page)
xa_lock(&md_submodule);
xa_for_each(&md_submodule, i, head) {
if (head->type != MD_BITMAP)
if (head->type != MD_BITMAP || head->id == ID_BITMAP_NONE)
continue;
if (mddev->bitmap_id == head->id)
@@ -6059,10 +6055,7 @@ static struct attribute *md_default_attrs[] = {
&md_logical_block_size.attr,
NULL,
};
static const struct attribute_group md_default_group = {
.attrs = md_default_attrs,
};
ATTRIBUTE_GROUPS(md_default);
static struct attribute *md_redundancy_attrs[] = {
&md_scan_mode.attr,
@@ -6087,11 +6080,6 @@ static const struct attribute_group md_redundancy_group = {
.attrs = md_redundancy_attrs,
};
static const struct attribute_group *md_attr_groups[] = {
&md_default_group,
NULL,
};
static ssize_t
md_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
{
@@ -6174,7 +6162,7 @@ static const struct sysfs_ops md_sysfs_ops = {
static const struct kobj_type md_ktype = {
.release = md_kobj_release,
.sysfs_ops = &md_sysfs_ops,
.default_groups = md_attr_groups,
.default_groups = md_default_groups,
};
int mdp_major = 0;
@@ -6539,7 +6527,7 @@ static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev)
return id;
}
static int md_bitmap_create(struct mddev *mddev)
int md_bitmap_create_nosysfs(struct mddev *mddev)
{
enum md_submodule_id orig_id = mddev->bitmap_id;
enum md_submodule_id sb_id;
@@ -6548,8 +6536,10 @@ static int md_bitmap_create(struct mddev *mddev)
if (mddev->bitmap_id == ID_BITMAP_NONE)
return -EINVAL;
if (!mddev_set_bitmap_ops(mddev))
if (!mddev_set_bitmap_ops_nosysfs(mddev)) {
mddev->bitmap_id = orig_id;
return -ENOENT;
}
err = mddev->bitmap_ops->create(mddev);
if (!err)
@@ -6560,37 +6550,72 @@ static int md_bitmap_create(struct mddev *mddev)
* doesn't match, and mdadm is not the latest version to set
* bitmap_type, set bitmap_ops based on the disk version.
*/
mddev_clear_bitmap_ops(mddev);
mddev->bitmap_ops = NULL;
sb_id = md_bitmap_get_id_from_sb(mddev);
if (sb_id == ID_BITMAP_NONE || sb_id == orig_id)
if (sb_id == ID_BITMAP_NONE || sb_id == orig_id) {
mddev->bitmap_id = orig_id;
return err;
}
pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n",
mdname(mddev), orig_id, sb_id);
mddev->bitmap_id = sb_id;
if (!mddev_set_bitmap_ops(mddev)) {
if (!mddev_set_bitmap_ops_nosysfs(mddev)) {
mddev->bitmap_id = orig_id;
return -ENOENT;
}
err = mddev->bitmap_ops->create(mddev);
if (err) {
mddev_clear_bitmap_ops(mddev);
mddev->bitmap_ops = NULL;
mddev->bitmap_id = orig_id;
}
return err;
}
static void md_bitmap_destroy(struct mddev *mddev)
static int md_bitmap_create(struct mddev *mddev)
{
int err;
err = md_bitmap_create_nosysfs(mddev);
if (err)
return err;
if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups)
md_bitmap_sysfs_add(mddev);
return 0;
}
void md_bitmap_destroy_nosysfs(struct mddev *mddev)
{
if (!md_bitmap_registered(mddev))
return;
mddev->bitmap_ops->destroy(mddev);
mddev_clear_bitmap_ops(mddev);
mddev->bitmap_ops = NULL;
}
static void md_bitmap_destroy(struct mddev *mddev)
{
if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
mddev->bitmap_ops->groups)
md_bitmap_sysfs_del(mddev);
md_bitmap_destroy_nosysfs(mddev);
}
static void md_bitmap_set_none(struct mddev *mddev)
{
mddev->bitmap_id = ID_BITMAP_NONE;
if (!mddev_set_bitmap_ops_nosysfs(mddev))
return;
if (!mddev_is_dm(mddev) && mddev->bitmap_ops->groups)
md_bitmap_sysfs_add(mddev);
}
int md_run(struct mddev *mddev)
@@ -6713,7 +6738,7 @@ int md_run(struct mddev *mddev)
}
/* dm-raid expect sync_thread to be frozen until resume */
if (mddev->gendisk)
if (!mddev_is_dm(mddev))
mddev->recovery = 0;
/* may be over-ridden by personality */
@@ -6802,6 +6827,10 @@ int md_run(struct mddev *mddev)
if (mddev->sb_flags)
md_update_sb(mddev, 0);
if (IS_ENABLED(CONFIG_MD_BITMAP) && !mddev->bitmap_info.file &&
!mddev->bitmap_info.offset)
md_bitmap_set_none(mddev);
md_new_event();
return 0;
@@ -7747,7 +7776,8 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
{
int err = 0;
if (!md_bitmap_registered(mddev))
if (!md_bitmap_registered(mddev) ||
mddev->bitmap_id == ID_BITMAP_NONE)
return -EINVAL;
if (mddev->pers) {
@@ -7812,10 +7842,12 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
if (err) {
md_bitmap_destroy(mddev);
md_bitmap_set_none(mddev);
fd = -1;
}
} else if (fd < 0) {
md_bitmap_destroy(mddev);
md_bitmap_set_none(mddev);
}
}
@@ -8122,12 +8154,16 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
mddev->bitmap_info.default_offset;
mddev->bitmap_info.space =
mddev->bitmap_info.default_space;
mddev->bitmap_id = ID_BITMAP;
rv = md_bitmap_create(mddev);
if (!rv)
rv = mddev->bitmap_ops->load(mddev);
if (rv)
if (rv) {
md_bitmap_destroy(mddev);
mddev->bitmap_info.offset = 0;
md_bitmap_set_none(mddev);
}
} else {
struct md_bitmap_stats stats;
@@ -8155,6 +8191,7 @@ static int update_array_info(struct mddev *mddev, mdu_array_info_t *info)
}
md_bitmap_destroy(mddev);
mddev->bitmap_info.offset = 0;
md_bitmap_set_none(mddev);
}
}
md_update_sb(mddev, 1);
@@ -9341,9 +9378,11 @@ static void md_bitmap_end(struct mddev *mddev, struct md_io_clone *md_io_clone)
static void md_end_clone_io(struct bio *bio)
{
struct md_io_clone *md_io_clone = bio->bi_private;
struct md_io_clone *md_io_clone = container_of(bio, struct md_io_clone,
bio_clone);
struct bio *orig_bio = md_io_clone->orig_bio;
struct mddev *mddev = md_io_clone->mddev;
struct completion *reshape_completion = bio->bi_private;
if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false))
md_bitmap_end(mddev, md_io_clone);
@@ -9355,7 +9394,10 @@ static void md_end_clone_io(struct bio *bio)
bio_end_io_acct(orig_bio, md_io_clone->start_time);
bio_put(bio);
bio_endio(orig_bio);
if (unlikely(reshape_completion))
complete(reshape_completion);
else
bio_endio(orig_bio);
percpu_ref_put(&mddev->active_io);
}
@@ -9380,7 +9422,7 @@ static void md_clone_bio(struct mddev *mddev, struct bio **bio)
}
clone->bi_end_io = md_end_clone_io;
clone->bi_private = md_io_clone;
clone->bi_private = NULL;
*bio = clone;
}
@@ -9391,26 +9433,6 @@ void md_account_bio(struct mddev *mddev, struct bio **bio)
}
EXPORT_SYMBOL_GPL(md_account_bio);
void md_free_cloned_bio(struct bio *bio)
{
struct md_io_clone *md_io_clone = bio->bi_private;
struct bio *orig_bio = md_io_clone->orig_bio;
struct mddev *mddev = md_io_clone->mddev;
if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false))
md_bitmap_end(mddev, md_io_clone);
if (bio->bi_status && !orig_bio->bi_status)
orig_bio->bi_status = bio->bi_status;
if (md_io_clone->start_time)
bio_end_io_acct(orig_bio, md_io_clone->start_time);
bio_put(bio);
percpu_ref_put(&mddev->active_io);
}
EXPORT_SYMBOL_GPL(md_free_cloned_bio);
/* md_allow_write(mddev)
* Calling this ensures that the array is marked 'active' so that writes
* may proceed without blocking. It is important to call this before

View File

@@ -920,7 +920,6 @@ extern void md_finish_reshape(struct mddev *mddev);
void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
struct bio *bio, sector_t start, sector_t size);
void md_account_bio(struct mddev *mddev, struct bio **bio);
void md_free_cloned_bio(struct bio *bio);
extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
void md_write_metadata(struct mddev *mddev, struct md_rdev *rdev,
@@ -935,6 +934,9 @@ extern void md_allow_write(struct mddev *mddev);
extern void md_wait_for_blocked_rdev(struct md_rdev *rdev, struct mddev *mddev);
extern void md_set_array_sectors(struct mddev *mddev, sector_t array_sectors);
extern int md_check_no_bitmap(struct mddev *mddev);
bool mddev_set_bitmap_ops_nosysfs(struct mddev *mddev);
int md_bitmap_create_nosysfs(struct mddev *mddev);
void md_bitmap_destroy_nosysfs(struct mddev *mddev);
extern int md_integrity_register(struct mddev *mddev);
extern int strict_strtoul_scaled(const char *cp, unsigned long *res, int scale);
@@ -1015,7 +1017,7 @@ static inline int mddev_suspend_and_lock(struct mddev *mddev)
static inline void mddev_suspend_and_lock_nointr(struct mddev *mddev)
{
mddev_suspend(mddev, false);
mutex_lock(&mddev->reconfig_mutex);
mddev_lock_nointr(mddev);
}
static inline void mddev_unlock_and_resume(struct mddev *mddev)

View File

@@ -293,8 +293,13 @@ static inline bool raid1_should_read_first(struct mddev *mddev,
* bio with REQ_RAHEAD or REQ_NOWAIT can fail at anytime, before such IO is
* submitted to the underlying disks, hence don't record badblocks or retry
* in this case.
*
* BLK_STS_INVAL means the bio was not valid for the underlying device. This
* is a user error, not a device failure, so retrying or recording bad blocks
* would be wrong.
*/
static inline bool raid1_should_handle_error(struct bio *bio)
{
return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT));
return !(bio->bi_opf & (REQ_RAHEAD | REQ_NOWAIT)) &&
bio->bi_status != BLK_STS_INVAL;
}

View File

@@ -1510,21 +1510,14 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
mddev->cluster_ops->area_resyncing(mddev, WRITE,
bio->bi_iter.bi_sector, bio_end_sector(bio))) {
DEFINE_WAIT(w);
if (bio->bi_opf & REQ_NOWAIT) {
bio_wouldblock_error(bio);
return;
}
for (;;) {
prepare_to_wait(&conf->wait_barrier,
&w, TASK_IDLE);
if (!mddev->cluster_ops->area_resyncing(mddev, WRITE,
bio->bi_iter.bi_sector,
bio_end_sector(bio)))
break;
schedule();
}
finish_wait(&conf->wait_barrier, &w);
wait_event_idle(conf->wait_barrier,
!mddev->cluster_ops->area_resyncing(mddev, WRITE,
bio->bi_iter.bi_sector,
bio_end_sector(bio)));
}
/*

View File

@@ -3791,6 +3791,8 @@ static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new)
nc = layout & 255;
fc = (layout >> 8) & 255;
fo = layout & (1<<16);
if (!nc || !fc)
return -1;
geo->raid_disks = disks;
geo->near_copies = nc;
geo->far_copies = fc;

View File

@@ -6217,7 +6217,12 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
mempool_free(ctx, conf->ctx_pool);
if (res == STRIPE_WAIT_RESHAPE) {
md_free_cloned_bio(bi);
DECLARE_COMPLETION_ONSTACK(done);
WRITE_ONCE(bi->bi_private, &done);
bio_endio(bi);
wait_for_completion(&done);
return false;
}

View File

@@ -351,18 +351,29 @@ struct nvme_dhchap_key *nvme_auth_transform_key(
}
EXPORT_SYMBOL_GPL(nvme_auth_transform_key);
/**
* nvme_auth_augmented_challenge() - Compute the augmented DH-HMAC-CHAP challenge
* @hmac_id: Hash algorithm identifier
* @skey: Session key
* @skey_len: Length of @skey
* @challenge: Challenge value
* @aug: Output buffer for the augmented challenge
* @hlen: Hash output length (length of @challenge and @aug)
*
* NVMe base specification 8.3.5.5.4: The augmented challenge is computed
* applying the HMAC function using the hash function H() selected by the
* HashID parameter ... with the hash of the ephemeral DH key ... as HMAC key
* to the challenge C (i.e., Ca = HMAC(H(g^xy mod p), C)).
*
* As the session key skey is already H(g^xy mod p) per section 8.3.5.5.9, use
* it directly as the HMAC key without additional hashing.
*
* Return: 0 on success, negative errno on failure.
*/
int nvme_auth_augmented_challenge(u8 hmac_id, const u8 *skey, size_t skey_len,
const u8 *challenge, u8 *aug, size_t hlen)
{
u8 hashed_key[NVME_AUTH_MAX_DIGEST_SIZE];
int ret;
ret = nvme_auth_hash(hmac_id, skey, skey_len, hashed_key);
if (ret)
return ret;
ret = nvme_auth_hmac(hmac_id, hashed_key, hlen, challenge, hlen, aug);
memzero_explicit(hashed_key, sizeof(hashed_key));
return ret;
return nvme_auth_hmac(hmac_id, skey, skey_len, challenge, hlen, aug);
}
EXPORT_SYMBOL_GPL(nvme_auth_augmented_challenge);
@@ -403,33 +414,76 @@ int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm,
}
EXPORT_SYMBOL_GPL(nvme_auth_gen_pubkey);
int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm,
const u8 *ctrl_key, size_t ctrl_key_len,
u8 *sess_key, size_t sess_key_len)
/**
* nvme_auth_gen_session_key() - Generate an ephemeral session key
* @dh_tfm: Diffie-Hellman transform with local private key already set
* @public_key: Peer's public key
* @public_key_len: Length of @public_key
* @sess_key: Output buffer for the session key
* @sess_key_len: Size of @sess_key buffer
* @hash_id: Hash algorithm identifier
*
* NVMe base specification 8.3.5.5.9: The session key Ks shall be computed from
* the ephemeral DH key (i.e., g^xy mod p) ... by applying the hash function
* H() selected by the HashID parameter ... (i.e., Ks = H(g^xy mod p)).
*
* Return: 0 on success, negative errno on failure.
*/
int nvme_auth_gen_session_key(struct crypto_kpp *dh_tfm,
const u8 *public_key, size_t public_key_len,
u8 *sess_key, size_t sess_key_len, u8 hash_id)
{
struct kpp_request *req;
struct crypto_wait wait;
struct scatterlist src, dst;
u8 *dh_secret;
size_t dh_secret_len, hash_len;
int ret;
req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
if (!req)
hash_len = nvme_auth_hmac_hash_len(hash_id);
if (!hash_len) {
pr_warn("%s: invalid hash algorithm %d\n", __func__, hash_id);
return -EINVAL;
}
if (sess_key_len != hash_len) {
pr_warn("%s: sess_key buffer missized (%zu != %zu)\n",
__func__, sess_key_len, hash_len);
return -EINVAL;
}
dh_secret_len = crypto_kpp_maxsize(dh_tfm);
dh_secret = kzalloc(dh_secret_len, GFP_KERNEL);
if (!dh_secret)
return -ENOMEM;
req = kpp_request_alloc(dh_tfm, GFP_KERNEL);
if (!req) {
ret = -ENOMEM;
goto out_free_secret;
}
crypto_init_wait(&wait);
sg_init_one(&src, ctrl_key, ctrl_key_len);
kpp_request_set_input(req, &src, ctrl_key_len);
sg_init_one(&dst, sess_key, sess_key_len);
kpp_request_set_output(req, &dst, sess_key_len);
sg_init_one(&src, public_key, public_key_len);
kpp_request_set_input(req, &src, public_key_len);
sg_init_one(&dst, dh_secret, dh_secret_len);
kpp_request_set_output(req, &dst, dh_secret_len);
kpp_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
crypto_req_done, &wait);
ret = crypto_wait_req(crypto_kpp_compute_shared_secret(req), &wait);
kpp_request_free(req);
if (ret)
goto out_free_secret;
ret = nvme_auth_hash(hash_id, dh_secret, dh_secret_len, sess_key);
out_free_secret:
kfree_sensitive(dh_secret);
return ret;
}
EXPORT_SYMBOL_GPL(nvme_auth_gen_shared_secret);
EXPORT_SYMBOL_GPL(nvme_auth_gen_session_key);
int nvme_auth_parse_key(const char *secret, struct nvme_dhchap_key **ret_key)
{

View File

@@ -1267,11 +1267,7 @@ static int apple_nvme_get_address(struct nvme_ctrl *ctrl, char *buf, int size)
static void apple_nvme_free_ctrl(struct nvme_ctrl *ctrl)
{
struct apple_nvme *anv = ctrl_to_apple_nvme(ctrl);
if (anv->ctrl.admin_q)
blk_put_queue(anv->ctrl.admin_q);
put_device(anv->dev);
put_device(ctrl->dev);
}
static const struct nvme_ctrl_ops nvme_ctrl_ops = {

View File

@@ -535,11 +535,12 @@ static int nvme_auth_dhchap_setup_ctrl_response(struct nvme_ctrl *ctrl,
put_unaligned_le16(chap->transaction, buf);
nvme_auth_hmac_update(&hmac, buf, 2);
memset(buf, 0, 4);
*buf = chap->sc_c;
nvme_auth_hmac_update(&hmac, buf, 1);
nvme_auth_hmac_update(&hmac, "Controller", 10);
nvme_auth_hmac_update(&hmac, ctrl->opts->subsysnqn,
strlen(ctrl->opts->subsysnqn));
memset(buf, 0, 4);
nvme_auth_hmac_update(&hmac, buf, 1);
nvme_auth_hmac_update(&hmac, ctrl->opts->host->nqn,
strlen(ctrl->opts->host->nqn));
@@ -587,7 +588,7 @@ static int nvme_auth_dhchap_exponential(struct nvme_ctrl *ctrl,
}
gen_sesskey:
chap->sess_key_len = chap->host_key_len;
chap->sess_key_len = chap->hash_len;
chap->sess_key = kmalloc(chap->sess_key_len, GFP_KERNEL);
if (!chap->sess_key) {
chap->sess_key_len = 0;
@@ -595,16 +596,17 @@ static int nvme_auth_dhchap_exponential(struct nvme_ctrl *ctrl,
return -ENOMEM;
}
ret = nvme_auth_gen_shared_secret(chap->dh_tfm,
chap->ctrl_key, chap->ctrl_key_len,
chap->sess_key, chap->sess_key_len);
ret = nvme_auth_gen_session_key(chap->dh_tfm,
chap->ctrl_key, chap->ctrl_key_len,
chap->sess_key, chap->sess_key_len,
chap->hash_id);
if (ret) {
dev_dbg(ctrl->device,
"failed to generate shared secret, error %d\n", ret);
"failed to generate session key, error %d\n", ret);
chap->status = NVME_AUTH_DHCHAP_FAILURE_INCORRECT_PAYLOAD;
return ret;
}
dev_dbg(ctrl->device, "shared secret %*ph\n",
dev_dbg(ctrl->device, "session key %*ph\n",
(int)chap->sess_key_len, chap->sess_key);
return 0;
}

View File

@@ -454,11 +454,10 @@ void nvme_end_req(struct request *req)
blk_mq_end_request(req, status);
}
void nvme_complete_rq(struct request *req)
static void __nvme_complete_rq(struct request *req)
{
struct nvme_ctrl *ctrl = nvme_req(req)->ctrl;
trace_nvme_complete_rq(req);
nvme_cleanup_cmd(req);
/*
@@ -493,6 +492,12 @@ void nvme_complete_rq(struct request *req)
return;
}
}
void nvme_complete_rq(struct request *req)
{
trace_nvme_complete_rq(req);
__nvme_complete_rq(req);
}
EXPORT_SYMBOL_GPL(nvme_complete_rq);
void nvme_complete_batch_req(struct request *req)
@@ -513,7 +518,7 @@ blk_status_t nvme_host_path_error(struct request *req)
{
nvme_req(req)->status = NVME_SC_HOST_PATH_ERROR;
blk_mq_set_request_complete(req);
nvme_complete_rq(req);
__nvme_complete_rq(req);
return BLK_STS_OK;
}
EXPORT_SYMBOL_GPL(nvme_host_path_error);
@@ -3044,7 +3049,7 @@ static const struct nvme_core_quirk_entry core_quirks[] = {
*
* The device is left in a state where it is also not possible
* to use "nvme set-feature" to disable APST, but booting with
* nvme_core.default_ps_max_latency=0 works.
* nvme_core.default_ps_max_latency_us=0 works.
*/
.vid = 0x1e0f,
.mn = "KCD6XVUL6T40",
@@ -4083,7 +4088,8 @@ static int nvme_init_ns_head(struct nvme_ns *ns, struct nvme_ns_info *info)
mutex_unlock(&ctrl->subsys->lock);
#ifdef CONFIG_NVME_MULTIPATH
cancel_delayed_work(&head->remove_work);
if (cancel_delayed_work(&head->remove_work))
module_put(THIS_MODULE);
#endif
return 0;

View File

@@ -3968,3 +3968,4 @@ module_exit(nvme_fc_exit_module);
MODULE_DESCRIPTION("NVMe host FC transport driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("nvme-fc");

View File

@@ -231,16 +231,12 @@ bool nvme_mpath_clear_current_path(struct nvme_ns *ns)
bool changed = false;
int node;
if (!head)
goto out;
for_each_node(node) {
if (ns == rcu_access_pointer(head->current_path[node])) {
rcu_assign_pointer(head->current_path[node], NULL);
changed = true;
}
}
out:
return changed;
}

View File

@@ -2241,6 +2241,7 @@ static int nvme_create_queue(struct nvme_queue *nvmeq, int qid, bool polled)
static const struct blk_mq_ops nvme_mq_admin_ops = {
.queue_rq = nvme_queue_rq,
.complete = nvme_pci_complete_rq,
.commit_rqs = nvme_commit_rqs,
.init_hctx = nvme_admin_init_hctx,
.init_request = nvme_pci_init_request,
.timeout = nvme_timeout,
@@ -4104,6 +4105,10 @@ static const struct pci_device_id nvme_id_table[] = {
.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
{ PCI_DEVICE(0x1c5f, 0x0540), /* Memblaze Pblaze4 adapter */
.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
{ PCI_DEVICE(0x1c5f, 0x0555), /* Memblaze Pblaze5 adapter */
.driver_data = NVME_QUIRK_NO_NS_DESC_LIST, },
{ PCI_DEVICE(0x144d, 0xa808), /* Samsung PM981/983 */
.driver_data = NVME_QUIRK_IGNORE_DEV_SUBNQN, },
{ PCI_DEVICE(0x144d, 0xa821), /* Samsung PM1725 */
.driver_data = NVME_QUIRK_DELAY_BEFORE_CHK_RDY, },
{ PCI_DEVICE(0x144d, 0xa822), /* Samsung PM1725a */

View File

@@ -2189,6 +2189,13 @@ static void nvme_rdma_reset_ctrl_work(struct work_struct *work)
nvme_rdma_reconnect_or_remove(ctrl, ret);
}
static bool nvme_rdma_supports_pci_p2pdma(struct nvme_ctrl *ctrl)
{
struct nvme_rdma_ctrl *r_ctrl = to_rdma_ctrl(ctrl);
return ib_dma_pci_p2p_dma_supported(r_ctrl->device->dev);
}
static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = {
.name = "rdma",
.module = THIS_MODULE,
@@ -2203,6 +2210,7 @@ static const struct nvme_ctrl_ops nvme_rdma_ctrl_ops = {
.get_address = nvmf_get_address,
.stop_ctrl = nvme_rdma_stop_ctrl,
.get_virt_boundary = nvme_get_virt_boundary,
.supports_pci_p2pdma = nvme_rdma_supports_pci_p2pdma,
};
/*
@@ -2432,3 +2440,4 @@ module_exit(nvme_rdma_cleanup_module);
MODULE_DESCRIPTION("NVMe host RDMA transport driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("nvme-rdma");

View File

@@ -883,10 +883,26 @@ static ssize_t tls_keyring_show(struct device *dev,
}
static DEVICE_ATTR_RO(tls_keyring);
static ssize_t tls_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct nvme_ctrl *ctrl = dev_get_drvdata(dev);
const char *mode;
if (ctrl->opts->tls)
mode = "tls";
else
mode = "concat";
return sysfs_emit(buf, "%s\n", mode);
}
static DEVICE_ATTR_RO(tls_mode);
static struct attribute *nvme_tls_attrs[] = {
&dev_attr_tls_key.attr,
&dev_attr_tls_configured_key.attr,
&dev_attr_tls_keyring.attr,
&dev_attr_tls_mode.attr,
NULL,
};
@@ -908,6 +924,9 @@ static umode_t nvme_tls_attrs_are_visible(struct kobject *kobj,
if (a == &dev_attr_tls_keyring.attr &&
!ctrl->opts->keyring)
return 0;
if (a == &dev_attr_tls_mode.attr &&
!ctrl->opts->tls && !ctrl->opts->concat)
return 0;
return a->mode;
}

View File

@@ -1438,18 +1438,32 @@ static void nvme_tcp_free_queue(struct nvme_ctrl *nctrl, int qid)
{
struct nvme_tcp_ctrl *ctrl = to_tcp_ctrl(nctrl);
struct nvme_tcp_queue *queue = &ctrl->queues[qid];
unsigned int noreclaim_flag;
unsigned int noio_flag;
if (!test_and_clear_bit(NVME_TCP_Q_ALLOCATED, &queue->flags))
return;
page_frag_cache_drain(&queue->pf_cache);
noreclaim_flag = memalloc_noreclaim_save();
/* ->sock will be released by fput() */
fput(queue->sock->file);
/**
* Prevent memory reclaim from triggering block I/O during socket
* teardown. The socket release path fput -> tcp_close ->
* tcp_disconnect -> tcp_send_active_reset may allocate memory, and
* allowing reclaim to issue I/O could deadlock if we're being called
* from block device teardown (e.g., del_gendisk -> elevator cleanup)
* which holds locks that the I/O completion path needs.
*/
noio_flag = memalloc_noio_save();
/**
* Release the socket synchronously. During reset in
* nvme_reset_ctrl_work(), queue teardown is immediately followed by
* re-allocation. fput() defers socket cleanup to delayed_fput_work
* in workqueue context, which can race with new queue setup.
*/
__fput_sync(queue->sock->file);
queue->sock = NULL;
memalloc_noreclaim_restore(noreclaim_flag);
memalloc_noio_restore(noio_flag);
kfree(queue->pdu);
mutex_destroy(&queue->send_mutex);
@@ -1901,8 +1915,8 @@ static int nvme_tcp_alloc_queue(struct nvme_ctrl *nctrl, int qid,
err_rcv_pdu:
kfree(queue->pdu);
err_sock:
/* ->sock will be released by fput() */
fput(queue->sock->file);
/* Use sync variant - see nvme_tcp_free_queue() for explanation */
__fput_sync(queue->sock->file);
queue->sock = NULL;
err_destroy_mutex:
mutex_destroy(&queue->send_mutex);
@@ -3071,3 +3085,4 @@ module_exit(nvme_tcp_cleanup_module);
MODULE_DESCRIPTION("NVMe host TCP transport driver");
MODULE_LICENSE("GPL v2");
MODULE_ALIAS("nvme-tcp");

View File

@@ -687,12 +687,8 @@ static void nvmet_execute_identify_ctrl(struct nvmet_req *req)
id->cmic = NVME_CTRL_CMIC_MULTI_PORT | NVME_CTRL_CMIC_MULTI_CTRL |
NVME_CTRL_CMIC_ANA;
/* Limit MDTS according to transport capability */
if (ctrl->ops->get_mdts)
id->mdts = ctrl->ops->get_mdts(ctrl);
else
id->mdts = 0;
/* Limit MDTS according to port config or transport capability */
id->mdts = nvmet_ctrl_mdts(req);
id->cntlid = cpu_to_le16(ctrl->cntlid);
id->ver = cpu_to_le32(ctrl->subsys->ver);

View File

@@ -229,9 +229,6 @@ u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, bool reset)
void nvmet_auth_sq_free(struct nvmet_sq *sq)
{
cancel_delayed_work(&sq->auth_expired_work);
#ifdef CONFIG_NVME_TARGET_TCP_TLS
sq->tls_key = NULL;
#endif
kfree(sq->dhchap_c1);
sq->dhchap_c1 = NULL;
kfree(sq->dhchap_c2);
@@ -402,11 +399,12 @@ int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response,
put_unaligned_le16(req->sq->dhchap_tid, buf);
nvme_auth_hmac_update(&hmac, buf, 2);
memset(buf, 0, 4);
*buf = req->sq->sc_c;
nvme_auth_hmac_update(&hmac, buf, 1);
nvme_auth_hmac_update(&hmac, "Controller", 10);
nvme_auth_hmac_update(&hmac, ctrl->subsys->subsysnqn,
strlen(ctrl->subsys->subsysnqn));
memset(buf, 0, 4);
nvme_auth_hmac_update(&hmac, buf, 1);
nvme_auth_hmac_update(&hmac, ctrl->hostnqn, strlen(ctrl->hostnqn));
nvme_auth_hmac_final(&hmac, response);
@@ -449,18 +447,19 @@ int nvmet_auth_ctrl_sesskey(struct nvmet_req *req,
struct nvmet_ctrl *ctrl = req->sq->ctrl;
int ret;
req->sq->dhchap_skey_len = ctrl->dh_keysize;
req->sq->dhchap_skey_len = nvme_auth_hmac_hash_len(ctrl->shash_id);
req->sq->dhchap_skey = kzalloc(req->sq->dhchap_skey_len, GFP_KERNEL);
if (!req->sq->dhchap_skey)
return -ENOMEM;
ret = nvme_auth_gen_shared_secret(ctrl->dh_tfm,
pkey, pkey_size,
req->sq->dhchap_skey,
req->sq->dhchap_skey_len);
ret = nvme_auth_gen_session_key(ctrl->dh_tfm,
pkey, pkey_size,
req->sq->dhchap_skey,
req->sq->dhchap_skey_len,
ctrl->shash_id);
if (ret)
pr_debug("failed to compute shared secret, err %d\n", ret);
pr_debug("failed to compute session key, err %d\n", ret);
else
pr_debug("%s: shared secret %*ph\n", __func__,
pr_debug("%s: session key %*ph\n", __func__,
(int)req->sq->dhchap_skey_len,
req->sq->dhchap_skey);

View File

@@ -301,6 +301,31 @@ static ssize_t nvmet_param_max_queue_size_store(struct config_item *item,
CONFIGFS_ATTR(nvmet_, param_max_queue_size);
static ssize_t nvmet_param_mdts_show(struct config_item *item, char *page)
{
struct nvmet_port *port = to_nvmet_port(item);
return snprintf(page, PAGE_SIZE, "%d\n", port->mdts);
}
static ssize_t nvmet_param_mdts_store(struct config_item *item,
const char *page, size_t count)
{
struct nvmet_port *port = to_nvmet_port(item);
int ret;
if (nvmet_is_port_enabled(port, __func__))
return -EACCES;
ret = kstrtoint(page, 0, &port->mdts);
if (ret) {
pr_err("Invalid value '%s' for mdts\n", page);
return -EINVAL;
}
return count;
}
CONFIGFS_ATTR(nvmet_, param_mdts);
#ifdef CONFIG_BLK_DEV_INTEGRITY
static ssize_t nvmet_param_pi_enable_show(struct config_item *item,
char *page)
@@ -1995,6 +2020,7 @@ static struct configfs_attribute *nvmet_port_attrs[] = {
&nvmet_attr_addr_tsas,
&nvmet_attr_param_inline_data_size,
&nvmet_attr_param_max_queue_size,
&nvmet_attr_param_mdts,
#ifdef CONFIG_BLK_DEV_INTEGRITY
&nvmet_attr_param_pi_enable,
#endif
@@ -2053,6 +2079,7 @@ static struct config_group *nvmet_ports_make(struct config_group *group,
INIT_LIST_HEAD(&port->referrals);
port->inline_data_size = -1; /* < 0 == let the transport choose */
port->max_queue_size = -1; /* < 0 == let the transport choose */
port->mdts = -1; /* < 0 == let the transport choose */
port->disc_addr.trtype = NVMF_TRTYPE_MAX;
port->disc_addr.portid = cpu_to_le16(portid);

View File

@@ -370,6 +370,14 @@ int nvmet_enable_port(struct nvmet_port *port)
NVMET_MIN_QUEUE_SIZE,
NVMET_MAX_QUEUE_SIZE);
/*
* If the transport didn't set the mdts properly, then clamp it to the
* target limits. Also set default values in case the transport didn't
* set it at all.
*/
if (port->mdts < 0 || port->mdts > NVMET_MAX_MDTS)
port->mdts = 0;
port->enabled = true;
port->tr_ops = ops;
return 0;
@@ -1743,7 +1751,7 @@ static void nvmet_ctrl_free(struct kref *ref)
nvmet_stop_keep_alive_timer(ctrl);
flush_work(&ctrl->async_event_work);
cancel_work_sync(&ctrl->async_event_work);
cancel_work_sync(&ctrl->fatal_err_work);
nvmet_destroy_auth(ctrl);

View File

@@ -395,10 +395,9 @@ void nvmet_execute_auth_send(struct nvmet_req *req)
goto complete;
}
/* Final states, clear up variables */
if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2) {
nvmet_auth_sq_free(req->sq);
nvmet_auth_sq_free(req->sq);
if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE2)
nvmet_ctrl_fatal_error(ctrl);
}
complete:
nvmet_req_complete(req, status);
@@ -574,7 +573,9 @@ void nvmet_execute_auth_receive(struct nvmet_req *req)
status = nvmet_copy_to_sgl(req, 0, d, al);
kfree(d);
done:
if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) {
if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_SUCCESS2)
nvmet_auth_sq_free(req->sq);
else if (req->sq->dhchap_step == NVME_AUTH_DHCHAP_MESSAGE_FAILURE1) {
nvmet_auth_sq_free(req->sq);
nvmet_ctrl_fatal_error(ctrl);
}

View File

@@ -214,6 +214,7 @@ struct nvmet_port {
bool enabled;
int inline_data_size;
int max_queue_size;
int mdts;
const struct nvmet_fabrics_ops *tr_ops;
bool pi_enable;
};
@@ -673,6 +674,7 @@ void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
#define NVMET_MAX_QUEUE_SIZE 1024
#define NVMET_NR_QUEUES 128
#define NVMET_MAX_CMD(ctrl) (NVME_CAP_MQES(ctrl->cap) + 1)
#define NVMET_MAX_MDTS 255
/*
* Nice round number that makes a list of nsids fit into a page.
@@ -761,6 +763,17 @@ static inline bool nvmet_is_pci_ctrl(struct nvmet_ctrl *ctrl)
return ctrl->port->disc_addr.trtype == NVMF_TRTYPE_PCI;
}
/* Limit MDTS according to port config or transport capability */
static inline u8 nvmet_ctrl_mdts(struct nvmet_req *req)
{
struct nvmet_ctrl *ctrl = req->sq->ctrl;
u8 mdts = req->port->mdts;
if (!ctrl->ops->get_mdts)
return mdts;
return min_not_zero(ctrl->ops->get_mdts(ctrl), mdts);
}
#ifdef CONFIG_NVME_TARGET_PASSTHRU
void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys);
int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys);

View File

@@ -349,9 +349,7 @@ static void nvmet_tcp_free_cmd_buffers(struct nvmet_tcp_cmd *cmd)
cmd->req.sg = NULL;
}
static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue);
static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
static int nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
{
struct bio_vec *iov = cmd->iov;
struct scatterlist *sg;
@@ -364,22 +362,19 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
offset = cmd->rbytes_done;
cmd->sg_idx = offset / PAGE_SIZE;
sg_offset = offset % PAGE_SIZE;
if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt) {
nvmet_tcp_fatal_error(cmd->queue);
return;
}
if (!cmd->req.sg_cnt || cmd->sg_idx >= cmd->req.sg_cnt)
return -EPROTO;
sg = &cmd->req.sg[cmd->sg_idx];
sg_remaining = cmd->req.sg_cnt - cmd->sg_idx;
while (length) {
if (!sg_remaining) {
nvmet_tcp_fatal_error(cmd->queue);
return;
}
if (!sg->length || sg->length <= sg_offset) {
nvmet_tcp_fatal_error(cmd->queue);
return;
}
if (!sg_remaining)
return -EPROTO;
if (!sg->length || sg->length <= sg_offset)
return -EPROTO;
u32 iov_len = min_t(u32, length, sg->length - sg_offset);
bvec_set_page(iov, sg_page(sg), iov_len,
@@ -394,24 +389,29 @@ static void nvmet_tcp_build_pdu_iovec(struct nvmet_tcp_cmd *cmd)
iov_iter_bvec(&cmd->recv_msg.msg_iter, ITER_DEST, cmd->iov,
nr_pages, cmd->pdu_len);
}
static void nvmet_tcp_fatal_error(struct nvmet_tcp_queue *queue)
{
queue->rcv_state = NVMET_TCP_RECV_ERR;
if (queue->nvme_sq.ctrl)
nvmet_ctrl_fatal_error(queue->nvme_sq.ctrl);
else
kernel_sock_shutdown(queue->sock, SHUT_RDWR);
return 0;
}
static void nvmet_tcp_socket_error(struct nvmet_tcp_queue *queue, int status)
{
/*
* Keep rcv_state at RECV_ERR even for the internal -ESHUTDOWN path.
* nvmet_tcp_handle_icreq() can return -ESHUTDOWN after the ICReq has
* already been consumed and queue teardown has started.
*
* If nvmet_tcp_data_ready() or nvmet_tcp_write_space() queues
* nvmet_tcp_io_work() again before nvmet_tcp_release_queue_work()
* cancels it, the queue must not keep that old receive state.
* Otherwise the next nvmet_tcp_io_work() run can reach
* nvmet_tcp_done_recv_pdu() and try to handle the same ICReq again.
*
* That is why queue->rcv_state needs to be updated before we return.
*/
queue->rcv_state = NVMET_TCP_RECV_ERR;
if (status == -EPIPE || status == -ECONNRESET)
if (status == -EPIPE || status == -ECONNRESET || !queue->nvme_sq.ctrl)
kernel_sock_shutdown(queue->sock, SHUT_RDWR);
else
nvmet_tcp_fatal_error(queue);
nvmet_ctrl_fatal_error(queue->nvme_sq.ctrl);
}
static int nvmet_tcp_map_data(struct nvmet_tcp_cmd *cmd)
@@ -887,7 +887,6 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)
if (le32_to_cpu(icreq->hdr.plen) != sizeof(struct nvme_tcp_icreq_pdu)) {
pr_err("bad nvme-tcp pdu length (%d)\n",
le32_to_cpu(icreq->hdr.plen));
nvmet_tcp_fatal_error(queue);
return -EPROTO;
}
@@ -922,16 +921,29 @@ static int nvmet_tcp_handle_icreq(struct nvmet_tcp_queue *queue)
iov.iov_len = sizeof(*icresp);
ret = kernel_sendmsg(queue->sock, &msg, &iov, 1, iov.iov_len);
if (ret < 0) {
spin_lock_bh(&queue->state_lock);
if (queue->state == NVMET_TCP_Q_DISCONNECTING) {
spin_unlock_bh(&queue->state_lock);
return -ESHUTDOWN;
}
queue->state = NVMET_TCP_Q_FAILED;
spin_unlock_bh(&queue->state_lock);
return ret; /* queue removal will cleanup */
}
spin_lock_bh(&queue->state_lock);
if (queue->state == NVMET_TCP_Q_DISCONNECTING) {
spin_unlock_bh(&queue->state_lock);
/* Tell nvmet_tcp_socket_error() teardown is in progress. */
return -ESHUTDOWN;
}
queue->state = NVMET_TCP_Q_LIVE;
spin_unlock_bh(&queue->state_lock);
nvmet_prepare_receive_pdu(queue);
return 0;
}
static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,
static int nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,
struct nvmet_tcp_cmd *cmd, struct nvmet_req *req)
{
size_t data_len = le32_to_cpu(req->cmd->common.dptr.sgl.length);
@@ -947,19 +959,22 @@ static void nvmet_tcp_handle_req_failure(struct nvmet_tcp_queue *queue,
if (!nvme_is_write(cmd->req.cmd) || !data_len ||
data_len > cmd->req.port->inline_data_size) {
nvmet_prepare_receive_pdu(queue);
return;
return 0;
}
ret = nvmet_tcp_map_data(cmd);
if (unlikely(ret)) {
pr_err("queue %d: failed to map data\n", queue->idx);
nvmet_tcp_fatal_error(queue);
return;
return -EPROTO;
}
queue->rcv_state = NVMET_TCP_RECV_DATA;
nvmet_tcp_build_pdu_iovec(cmd);
cmd->flags |= NVMET_TCP_F_INIT_FAILED;
ret = nvmet_tcp_build_pdu_iovec(cmd);
if (unlikely(ret))
pr_err("queue %d: failed to build PDU iovec\n", queue->idx);
return ret;
}
static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue)
@@ -1011,7 +1026,10 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue)
goto err_proto;
}
cmd->pdu_recv = 0;
nvmet_tcp_build_pdu_iovec(cmd);
if (unlikely(nvmet_tcp_build_pdu_iovec(cmd))) {
pr_err("queue %d: failed to build PDU iovec\n", queue->idx);
goto err_proto;
}
queue->cmd = cmd;
queue->rcv_state = NVMET_TCP_RECV_DATA;
@@ -1019,7 +1037,6 @@ static int nvmet_tcp_handle_h2c_data_pdu(struct nvmet_tcp_queue *queue)
err_proto:
/* FIXME: use proper transport errors */
nvmet_tcp_fatal_error(queue);
return -EPROTO;
}
@@ -1034,7 +1051,6 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)
if (hdr->type != nvme_tcp_icreq) {
pr_err("unexpected pdu type (%d) before icreq\n",
hdr->type);
nvmet_tcp_fatal_error(queue);
return -EPROTO;
}
return nvmet_tcp_handle_icreq(queue);
@@ -1043,7 +1059,6 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)
if (unlikely(hdr->type == nvme_tcp_icreq)) {
pr_err("queue %d: received icreq pdu in state %d\n",
queue->idx, queue->state);
nvmet_tcp_fatal_error(queue);
return -EPROTO;
}
@@ -1060,7 +1075,6 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)
pr_err("queue %d: out of commands (%d) send_list_len: %d, opcode: %d",
queue->idx, queue->nr_cmds, queue->send_list_len,
nvme_cmd->common.opcode);
nvmet_tcp_fatal_error(queue);
return -ENOMEM;
}
@@ -1074,17 +1088,16 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)
le32_to_cpu(req->cmd->common.dptr.sgl.length),
le16_to_cpu(req->cqe->status));
nvmet_tcp_handle_req_failure(queue, queue->cmd, req);
return 0;
return nvmet_tcp_handle_req_failure(queue, queue->cmd, req);
}
ret = nvmet_tcp_map_data(queue->cmd);
if (unlikely(ret)) {
pr_err("queue %d: failed to map data\n", queue->idx);
if (nvmet_tcp_has_inline_data(queue->cmd))
nvmet_tcp_fatal_error(queue);
else
nvmet_req_complete(req, ret);
return -EPROTO;
nvmet_req_complete(req, ret);
ret = -EAGAIN;
goto out;
}
@@ -1092,8 +1105,11 @@ static int nvmet_tcp_done_recv_pdu(struct nvmet_tcp_queue *queue)
if (nvmet_tcp_need_data_in(queue->cmd)) {
if (nvmet_tcp_has_inline_data(queue->cmd)) {
queue->rcv_state = NVMET_TCP_RECV_DATA;
nvmet_tcp_build_pdu_iovec(queue->cmd);
return 0;
ret = nvmet_tcp_build_pdu_iovec(queue->cmd);
if (unlikely(ret))
pr_err("queue %d: failed to build PDU iovec\n",
queue->idx);
return ret;
}
/* send back R2T */
nvmet_tcp_queue_response(&queue->cmd->req);
@@ -1204,7 +1220,6 @@ static int nvmet_tcp_try_recv_pdu(struct nvmet_tcp_queue *queue)
if (unlikely(!nvmet_tcp_pdu_valid(hdr->type))) {
pr_err("unexpected pdu type %d\n", hdr->type);
nvmet_tcp_fatal_error(queue);
return -EIO;
}
@@ -1218,16 +1233,12 @@ static int nvmet_tcp_try_recv_pdu(struct nvmet_tcp_queue *queue)
}
if (queue->hdr_digest &&
nvmet_tcp_verify_hdgst(queue, &queue->pdu, hdr->hlen)) {
nvmet_tcp_fatal_error(queue); /* fatal */
nvmet_tcp_verify_hdgst(queue, &queue->pdu, hdr->hlen))
return -EPROTO;
}
if (queue->data_digest &&
nvmet_tcp_check_ddgst(queue, &queue->pdu)) {
nvmet_tcp_fatal_error(queue); /* fatal */
nvmet_tcp_check_ddgst(queue, &queue->pdu))
return -EPROTO;
}
return nvmet_tcp_done_recv_pdu(queue);
}
@@ -1310,9 +1321,9 @@ static int nvmet_tcp_try_recv_ddgst(struct nvmet_tcp_queue *queue)
queue->idx, cmd->req.cmd->common.command_id,
queue->pdu.cmd.hdr.type, le32_to_cpu(cmd->recv_ddgst),
le32_to_cpu(cmd->exp_ddgst));
nvmet_req_uninit(&cmd->req);
if (!(cmd->flags & NVMET_TCP_F_INIT_FAILED))
nvmet_req_uninit(&cmd->req);
nvmet_tcp_free_cmd_buffers(cmd);
nvmet_tcp_fatal_error(queue);
ret = -EPROTO;
goto out;
}

View File

@@ -69,7 +69,6 @@ bool nvmet_bdev_zns_enable(struct nvmet_ns *ns)
void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req)
{
u8 zasl = req->sq->ctrl->subsys->zasl;
struct nvmet_ctrl *ctrl = req->sq->ctrl;
struct nvme_id_ctrl_zns *id;
u16 status;
@@ -79,10 +78,7 @@ void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req)
goto out;
}
if (ctrl->ops->get_mdts)
id->zasl = min_t(u8, ctrl->ops->get_mdts(ctrl), zasl);
else
id->zasl = zasl;
id->zasl = min_not_zero(nvmet_ctrl_mdts(req), zasl);
status = nvmet_copy_to_sgl(req, 0, id, sizeof(*id));

View File

@@ -395,7 +395,7 @@ static blk_status_t sr_init_command(struct scsi_cmnd *SCpnt)
switch (req_op(rq)) {
case REQ_OP_WRITE:
if (!cd->writeable)
if (get_disk_ro(cd->disk))
goto out;
SCpnt->cmnd[0] = WRITE_10;
cd->cdi.media_written = 1;
@@ -681,6 +681,7 @@ static int sr_probe(struct scsi_device *sdev)
error = -ENOMEM;
if (get_capabilities(cd))
goto fail_minor;
cdrom_probe_write_features(&cd->cdi);
sr_vendor_init(cd);
set_capacity(disk, cd->capacity);
@@ -899,14 +900,6 @@ static int get_capabilities(struct scsi_cd *cd)
/*else I don't think it can close its tray
cd->cdi.mask |= CDC_CLOSE_TRAY; */
/*
* if DVD-RAM, MRW-W or CD-RW, we are randomly writable
*/
if ((cd->cdi.mask & (CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) !=
(CDC_DVD_RAM | CDC_MRW_W | CDC_RAM | CDC_CD_RW)) {
cd->writeable = 1;
}
kfree(buffer);
return 0;
}

View File

@@ -35,7 +35,6 @@ typedef struct scsi_cd {
struct scsi_device *device;
unsigned int vendor; /* vendor code, see sr_vendor.c */
unsigned long ms_offset; /* for reading multisession-CD's */
unsigned writeable : 1;
unsigned use:1; /* is this device still supportable */
unsigned xa_flag:1; /* CD has XA sectors ? */
unsigned readcd_known:1; /* drive supports READ_CD (0xbe) */

View File

@@ -108,6 +108,7 @@ int cdrom_ioctl(struct cdrom_device_info *cdi, struct block_device *bdev,
extern unsigned int cdrom_check_events(struct cdrom_device_info *cdi,
unsigned int clearing);
extern void cdrom_probe_write_features(struct cdrom_device_info *cdi);
extern int register_cdrom(struct gendisk *disk, struct cdrom_device_info *cdi);
extern void unregister_cdrom(struct cdrom_device_info *cdi);

View File

@@ -49,9 +49,9 @@ int nvme_auth_augmented_challenge(u8 hmac_id, const u8 *skey, size_t skey_len,
int nvme_auth_gen_privkey(struct crypto_kpp *dh_tfm, u8 dh_gid);
int nvme_auth_gen_pubkey(struct crypto_kpp *dh_tfm,
u8 *host_key, size_t host_key_len);
int nvme_auth_gen_shared_secret(struct crypto_kpp *dh_tfm,
const u8 *ctrl_key, size_t ctrl_key_len,
u8 *sess_key, size_t sess_key_len);
int nvme_auth_gen_session_key(struct crypto_kpp *dh_tfm,
const u8 *public_key, size_t public_key_len,
u8 *sess_key, size_t sess_key_len, u8 hash_id);
int nvme_auth_generate_psk(u8 hmac_id, const u8 *skey, size_t skey_len,
const u8 *c1, const u8 *c2, size_t hash_len,
u8 **ret_psk, size_t *ret_len);