mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-05-16 04:21:09 -04:00
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:
@@ -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/
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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)
|
||||
|
||||
182
drivers/md/md.c
182
drivers/md/md.c
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)));
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user