2019-02-18 11:36:11 +01:00
|
|
|
/* SPDX-License-Identifier: GPL-2.0 */
|
2016-06-21 18:04:20 +02:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2015-2016 HGST, a Western Digital Company.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef _NVMET_H
|
|
|
|
#define _NVMET_H
|
|
|
|
|
|
|
|
#include <linux/dma-mapping.h>
|
|
|
|
#include <linux/types.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/kref.h>
|
|
|
|
#include <linux/percpu-refcount.h>
|
|
|
|
#include <linux/list.h>
|
|
|
|
#include <linux/mutex.h>
|
2017-05-17 09:54:27 +02:00
|
|
|
#include <linux/uuid.h>
|
2016-06-21 18:04:20 +02:00
|
|
|
#include <linux/nvme.h>
|
|
|
|
#include <linux/configfs.h>
|
|
|
|
#include <linux/rcupdate.h>
|
|
|
|
#include <linux/blkdev.h>
|
2018-10-04 15:27:47 -06:00
|
|
|
#include <linux/radix-tree.h>
|
2020-05-19 17:05:57 +03:00
|
|
|
#include <linux/t10-pi.h>
|
2024-11-06 15:34:46 +08:00
|
|
|
#include <linux/kfifo.h>
|
2016-06-21 18:04:20 +02:00
|
|
|
|
2024-11-04 14:29:45 -08:00
|
|
|
#define NVMET_DEFAULT_VS NVME_VS(2, 1, 0)
|
2020-07-24 11:25:18 -06:00
|
|
|
|
nvmet-loop: avoid using mutex in IO hotpath
Using mutex lock in IO hot path causes the kernel BUG sleeping while
atomic. Shinichiro[1], first encountered this issue while running blktest
nvme/052 shown below:
BUG: sleeping function called from invalid context at kernel/locking/mutex.c:585
in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 996, name: (udev-worker)
preempt_count: 0, expected: 0
RCU nest depth: 1, expected: 0
2 locks held by (udev-worker)/996:
#0: ffff8881004570c8 (mapping.invalidate_lock){.+.+}-{3:3}, at: page_cache_ra_unbounded+0x155/0x5c0
#1: ffffffff8607eaa0 (rcu_read_lock){....}-{1:2}, at: blk_mq_flush_plug_list+0xa75/0x1950
CPU: 2 UID: 0 PID: 996 Comm: (udev-worker) Not tainted 6.12.0-rc3+ #339
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-2.fc40 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x6a/0x90
__might_resched.cold+0x1f7/0x23d
? __pfx___might_resched+0x10/0x10
? vsnprintf+0xdeb/0x18f0
__mutex_lock+0xf4/0x1220
? nvmet_subsys_nsid_exists+0xb9/0x150 [nvmet]
? __pfx_vsnprintf+0x10/0x10
? __pfx___mutex_lock+0x10/0x10
? snprintf+0xa5/0xe0
? xas_load+0x1ce/0x3f0
? nvmet_subsys_nsid_exists+0xb9/0x150 [nvmet]
nvmet_subsys_nsid_exists+0xb9/0x150 [nvmet]
? __pfx_nvmet_subsys_nsid_exists+0x10/0x10 [nvmet]
nvmet_req_find_ns+0x24e/0x300 [nvmet]
nvmet_req_init+0x694/0xd40 [nvmet]
? blk_mq_start_request+0x11c/0x750
? nvme_setup_cmd+0x369/0x990 [nvme_core]
nvme_loop_queue_rq+0x2a7/0x7a0 [nvme_loop]
? __pfx___lock_acquire+0x10/0x10
? __pfx_nvme_loop_queue_rq+0x10/0x10 [nvme_loop]
__blk_mq_issue_directly+0xe2/0x1d0
? __pfx___blk_mq_issue_directly+0x10/0x10
? blk_mq_request_issue_directly+0xc2/0x140
blk_mq_plug_issue_direct+0x13f/0x630
? lock_acquire+0x2d/0xc0
? blk_mq_flush_plug_list+0xa75/0x1950
blk_mq_flush_plug_list+0xa9d/0x1950
? __pfx_blk_mq_flush_plug_list+0x10/0x10
? __pfx_mpage_readahead+0x10/0x10
__blk_flush_plug+0x278/0x4d0
? __pfx___blk_flush_plug+0x10/0x10
? lock_release+0x460/0x7a0
blk_finish_plug+0x4e/0x90
read_pages+0x51b/0xbc0
? __pfx_read_pages+0x10/0x10
? lock_release+0x460/0x7a0
page_cache_ra_unbounded+0x326/0x5c0
force_page_cache_ra+0x1ea/0x2f0
filemap_get_pages+0x59e/0x17b0
? __pfx_filemap_get_pages+0x10/0x10
? lock_is_held_type+0xd5/0x130
? __pfx___might_resched+0x10/0x10
? find_held_lock+0x2d/0x110
filemap_read+0x317/0xb70
? up_write+0x1ba/0x510
? __pfx_filemap_read+0x10/0x10
? inode_security+0x54/0xf0
? selinux_file_permission+0x36d/0x420
blkdev_read_iter+0x143/0x3b0
vfs_read+0x6ac/0xa20
? __pfx_vfs_read+0x10/0x10
? __pfx_vm_mmap_pgoff+0x10/0x10
? __pfx___seccomp_filter+0x10/0x10
ksys_read+0xf7/0x1d0
? __pfx_ksys_read+0x10/0x10
do_syscall_64+0x93/0x180
? lockdep_hardirqs_on_prepare+0x16d/0x400
? do_syscall_64+0x9f/0x180
? lockdep_hardirqs_on+0x78/0x100
? do_syscall_64+0x9f/0x180
? lockdep_hardirqs_on_prepare+0x16d/0x400
entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0033:0x7f565bd1ce11
Code: 00 48 8b 15 09 90 0d 00 f7 d8 64 89 02 b8 ff ff ff ff eb bd e8 d0 ad 01 00 f3 0f 1e fa 80 3d 35 12 0e 00 00 74 13 31 c0 0f 05 <48> 3d 00 f0 ff ff 77 4f c3 66 0f 1f 44 00 00 55 48 89 e5 48 83 ec
RSP: 002b:00007ffd6e7a20c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
RAX: ffffffffffffffda RBX: 0000000000001000 RCX: 00007f565bd1ce11
RDX: 0000000000001000 RSI: 00007f565babb000 RDI: 0000000000000014
RBP: 00007ffd6e7a2130 R08: 00000000ffffffff R09: 0000000000000000
R10: 0000556000bfa610 R11: 0000000000000246 R12: 000000003ffff000
R13: 0000556000bfa5b0 R14: 0000000000000e00 R15: 0000556000c07328
</TASK>
Apparently, the above issue is caused due to using mutex lock while
we're in IO hot path. It's a regression caused with commit 505363957fad
("nvmet: fix nvme status code when namespace is disabled"). The mutex
->su_mutex is used to find whether a disabled nsid exists in the config
group or not. This is to differentiate between a nsid that is disabled
vs non-existent.
To mitigate the above issue, we've worked upon a fix[2] where we now
insert nsid in subsys Xarray as soon as it's created under config group
and later when that nsid is enabled, we add an Xarray mark on it and set
ns->enabled to true. The Xarray mark is useful while we need to loop
through all enabled namepsaces under a subsystem using xa_for_each_marked()
API. If later a nsid is disabled then we clear Xarray mark from it and also
set ns->enabled to false. It's only when nsid is deleted from the config
group we delete it from the Xarray.
So with this change, now we could easily differentiate a nsid is disabled
(i.e. Xarray entry for ns exists but ns->enabled is set to false) vs non-
existent (i.e.Xarray entry for ns doesn't exist).
Link: https://lore.kernel.org/linux-nvme/20241022070252.GA11389@lst.de/ [2]
Reported-by: Shinichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Closes: https://lore.kernel.org/linux-nvme/tqcy3sveity7p56v7ywp7ssyviwcb3w4623cnxj3knoobfcanq@yxgt2mjkbkam/ [1]
Fixes: 505363957fad ("nvmet: fix nvme status code when namespace is disabled")
Fix-suggested-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2024-12-11 14:28:06 +05:30
|
|
|
#define NVMET_NS_ENABLED XA_MARK_1
|
2016-06-21 18:04:20 +02:00
|
|
|
#define NVMET_ASYNC_EVENTS 4
|
|
|
|
#define NVMET_ERROR_LOG_SLOTS 128
|
2018-12-17 18:35:29 -08:00
|
|
|
#define NVMET_NO_ERROR_LOC ((u16)-1)
|
2020-01-30 10:29:32 -08:00
|
|
|
#define NVMET_DEFAULT_CTRL_MODEL "Linux"
|
2021-03-15 14:56:11 +00:00
|
|
|
#define NVMET_MN_MAX_SIZE 40
|
2021-06-07 12:23:21 +03:00
|
|
|
#define NVMET_SN_MAX_SIZE 20
|
2022-11-15 14:58:10 +03:00
|
|
|
#define NVMET_FR_MAX_SIZE 8
|
2024-11-06 15:34:46 +08:00
|
|
|
#define NVMET_PR_LOG_QUEUE_SIZE 64
|
2016-06-21 18:04:20 +02:00
|
|
|
|
nvmet-loop: avoid using mutex in IO hotpath
Using mutex lock in IO hot path causes the kernel BUG sleeping while
atomic. Shinichiro[1], first encountered this issue while running blktest
nvme/052 shown below:
BUG: sleeping function called from invalid context at kernel/locking/mutex.c:585
in_atomic(): 0, irqs_disabled(): 0, non_block: 0, pid: 996, name: (udev-worker)
preempt_count: 0, expected: 0
RCU nest depth: 1, expected: 0
2 locks held by (udev-worker)/996:
#0: ffff8881004570c8 (mapping.invalidate_lock){.+.+}-{3:3}, at: page_cache_ra_unbounded+0x155/0x5c0
#1: ffffffff8607eaa0 (rcu_read_lock){....}-{1:2}, at: blk_mq_flush_plug_list+0xa75/0x1950
CPU: 2 UID: 0 PID: 996 Comm: (udev-worker) Not tainted 6.12.0-rc3+ #339
Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.16.3-2.fc40 04/01/2014
Call Trace:
<TASK>
dump_stack_lvl+0x6a/0x90
__might_resched.cold+0x1f7/0x23d
? __pfx___might_resched+0x10/0x10
? vsnprintf+0xdeb/0x18f0
__mutex_lock+0xf4/0x1220
? nvmet_subsys_nsid_exists+0xb9/0x150 [nvmet]
? __pfx_vsnprintf+0x10/0x10
? __pfx___mutex_lock+0x10/0x10
? snprintf+0xa5/0xe0
? xas_load+0x1ce/0x3f0
? nvmet_subsys_nsid_exists+0xb9/0x150 [nvmet]
nvmet_subsys_nsid_exists+0xb9/0x150 [nvmet]
? __pfx_nvmet_subsys_nsid_exists+0x10/0x10 [nvmet]
nvmet_req_find_ns+0x24e/0x300 [nvmet]
nvmet_req_init+0x694/0xd40 [nvmet]
? blk_mq_start_request+0x11c/0x750
? nvme_setup_cmd+0x369/0x990 [nvme_core]
nvme_loop_queue_rq+0x2a7/0x7a0 [nvme_loop]
? __pfx___lock_acquire+0x10/0x10
? __pfx_nvme_loop_queue_rq+0x10/0x10 [nvme_loop]
__blk_mq_issue_directly+0xe2/0x1d0
? __pfx___blk_mq_issue_directly+0x10/0x10
? blk_mq_request_issue_directly+0xc2/0x140
blk_mq_plug_issue_direct+0x13f/0x630
? lock_acquire+0x2d/0xc0
? blk_mq_flush_plug_list+0xa75/0x1950
blk_mq_flush_plug_list+0xa9d/0x1950
? __pfx_blk_mq_flush_plug_list+0x10/0x10
? __pfx_mpage_readahead+0x10/0x10
__blk_flush_plug+0x278/0x4d0
? __pfx___blk_flush_plug+0x10/0x10
? lock_release+0x460/0x7a0
blk_finish_plug+0x4e/0x90
read_pages+0x51b/0xbc0
? __pfx_read_pages+0x10/0x10
? lock_release+0x460/0x7a0
page_cache_ra_unbounded+0x326/0x5c0
force_page_cache_ra+0x1ea/0x2f0
filemap_get_pages+0x59e/0x17b0
? __pfx_filemap_get_pages+0x10/0x10
? lock_is_held_type+0xd5/0x130
? __pfx___might_resched+0x10/0x10
? find_held_lock+0x2d/0x110
filemap_read+0x317/0xb70
? up_write+0x1ba/0x510
? __pfx_filemap_read+0x10/0x10
? inode_security+0x54/0xf0
? selinux_file_permission+0x36d/0x420
blkdev_read_iter+0x143/0x3b0
vfs_read+0x6ac/0xa20
? __pfx_vfs_read+0x10/0x10
? __pfx_vm_mmap_pgoff+0x10/0x10
? __pfx___seccomp_filter+0x10/0x10
ksys_read+0xf7/0x1d0
? __pfx_ksys_read+0x10/0x10
do_syscall_64+0x93/0x180
? lockdep_hardirqs_on_prepare+0x16d/0x400
? do_syscall_64+0x9f/0x180
? lockdep_hardirqs_on+0x78/0x100
? do_syscall_64+0x9f/0x180
? lockdep_hardirqs_on_prepare+0x16d/0x400
entry_SYSCALL_64_after_hwframe+0x76/0x7e
RIP: 0033:0x7f565bd1ce11
Code: 00 48 8b 15 09 90 0d 00 f7 d8 64 89 02 b8 ff ff ff ff eb bd e8 d0 ad 01 00 f3 0f 1e fa 80 3d 35 12 0e 00 00 74 13 31 c0 0f 05 <48> 3d 00 f0 ff ff 77 4f c3 66 0f 1f 44 00 00 55 48 89 e5 48 83 ec
RSP: 002b:00007ffd6e7a20c8 EFLAGS: 00000246 ORIG_RAX: 0000000000000000
RAX: ffffffffffffffda RBX: 0000000000001000 RCX: 00007f565bd1ce11
RDX: 0000000000001000 RSI: 00007f565babb000 RDI: 0000000000000014
RBP: 00007ffd6e7a2130 R08: 00000000ffffffff R09: 0000000000000000
R10: 0000556000bfa610 R11: 0000000000000246 R12: 000000003ffff000
R13: 0000556000bfa5b0 R14: 0000000000000e00 R15: 0000556000c07328
</TASK>
Apparently, the above issue is caused due to using mutex lock while
we're in IO hot path. It's a regression caused with commit 505363957fad
("nvmet: fix nvme status code when namespace is disabled"). The mutex
->su_mutex is used to find whether a disabled nsid exists in the config
group or not. This is to differentiate between a nsid that is disabled
vs non-existent.
To mitigate the above issue, we've worked upon a fix[2] where we now
insert nsid in subsys Xarray as soon as it's created under config group
and later when that nsid is enabled, we add an Xarray mark on it and set
ns->enabled to true. The Xarray mark is useful while we need to loop
through all enabled namepsaces under a subsystem using xa_for_each_marked()
API. If later a nsid is disabled then we clear Xarray mark from it and also
set ns->enabled to false. It's only when nsid is deleted from the config
group we delete it from the Xarray.
So with this change, now we could easily differentiate a nsid is disabled
(i.e. Xarray entry for ns exists but ns->enabled is set to false) vs non-
existent (i.e.Xarray entry for ns doesn't exist).
Link: https://lore.kernel.org/linux-nvme/20241022070252.GA11389@lst.de/ [2]
Reported-by: Shinichiro Kawasaki <shinichiro.kawasaki@wdc.com>
Closes: https://lore.kernel.org/linux-nvme/tqcy3sveity7p56v7ywp7ssyviwcb3w4623cnxj3knoobfcanq@yxgt2mjkbkam/ [1]
Fixes: 505363957fad ("nvmet: fix nvme status code when namespace is disabled")
Fix-suggested-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Hannes Reinecke <hare@suse.de>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Nilay Shroff <nilay@linux.ibm.com>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2024-12-11 14:28:06 +05:30
|
|
|
#define nvmet_for_each_ns(xa, index, entry) \
|
|
|
|
xa_for_each(xa, index, entry)
|
|
|
|
|
|
|
|
#define nvmet_for_each_enabled_ns(xa, index, entry) \
|
|
|
|
xa_for_each_marked(xa, index, entry, NVMET_NS_ENABLED)
|
|
|
|
|
2018-05-30 15:04:47 +02:00
|
|
|
/*
|
|
|
|
* Supported optional AENs:
|
|
|
|
*/
|
|
|
|
#define NVMET_AEN_CFG_OPTIONAL \
|
2018-06-01 08:59:25 +02:00
|
|
|
(NVME_AEN_CFG_NS_ATTR | NVME_AEN_CFG_ANA_CHANGE)
|
2018-11-12 13:56:37 -08:00
|
|
|
#define NVMET_DISC_AEN_CFG_OPTIONAL \
|
|
|
|
(NVME_AEN_CFG_DISC_CHANGE)
|
2018-05-30 15:04:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Plus mandatory SMART AENs (we'll never send them, but allow enabling them):
|
|
|
|
*/
|
|
|
|
#define NVMET_AEN_CFG_ALL \
|
|
|
|
(NVME_SMART_CRIT_SPARE | NVME_SMART_CRIT_TEMPERATURE | \
|
|
|
|
NVME_SMART_CRIT_RELIABILITY | NVME_SMART_CRIT_MEDIA | \
|
|
|
|
NVME_SMART_CRIT_VOLATILE_MEMORY | NVMET_AEN_CFG_OPTIONAL)
|
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
/* Helper Macros when NVMe error is NVME_SC_CONNECT_INVALID_PARAM
|
|
|
|
* The 16 bit shift is to set IATTR bit to 1, which means offending
|
|
|
|
* offset starts in the data section of connect()
|
|
|
|
*/
|
|
|
|
#define IPO_IATTR_CONNECT_DATA(x) \
|
|
|
|
(cpu_to_le32((1 << 16) | (offsetof(struct nvmf_connect_data, x))))
|
|
|
|
#define IPO_IATTR_CONNECT_SQE(x) \
|
|
|
|
(cpu_to_le32(offsetof(struct nvmf_connect_command, x)))
|
|
|
|
|
2024-11-06 15:34:46 +08:00
|
|
|
struct nvmet_pr_registrant {
|
|
|
|
u64 rkey;
|
|
|
|
uuid_t hostid;
|
|
|
|
enum nvme_pr_type rtype;
|
|
|
|
struct list_head entry;
|
|
|
|
struct rcu_head rcu;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct nvmet_pr {
|
|
|
|
bool enable;
|
|
|
|
unsigned long notify_mask;
|
|
|
|
atomic_t generation;
|
|
|
|
struct nvmet_pr_registrant __rcu *holder;
|
|
|
|
/*
|
|
|
|
* During the execution of the reservation command, mutual
|
|
|
|
* exclusion is required throughout the process. However,
|
|
|
|
* while waiting asynchronously for the 'per controller
|
|
|
|
* percpu_ref' to complete before the 'preempt and abort'
|
|
|
|
* command finishes, a semaphore is needed to ensure mutual
|
|
|
|
* exclusion instead of a mutex.
|
|
|
|
*/
|
|
|
|
struct semaphore pr_sem;
|
|
|
|
struct list_head registrant_list;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct nvmet_pr_per_ctrl_ref {
|
|
|
|
struct percpu_ref ref;
|
|
|
|
struct completion free_done;
|
|
|
|
struct completion confirm_done;
|
|
|
|
uuid_t hostid;
|
|
|
|
};
|
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
struct nvmet_ns {
|
|
|
|
struct percpu_ref ref;
|
2024-01-23 14:26:32 +01:00
|
|
|
struct file *bdev_file;
|
2016-06-21 18:04:20 +02:00
|
|
|
struct block_device *bdev;
|
2018-05-23 00:34:39 -04:00
|
|
|
struct file *file;
|
2018-08-07 23:01:07 -07:00
|
|
|
bool readonly;
|
2016-06-21 18:04:20 +02:00
|
|
|
u32 nsid;
|
|
|
|
u32 blksize_shift;
|
|
|
|
loff_t size;
|
|
|
|
u8 nguid[16];
|
2017-06-07 11:45:32 +02:00
|
|
|
uuid_t uuid;
|
2018-07-19 07:35:20 -07:00
|
|
|
u32 anagrpid;
|
2016-06-21 18:04:20 +02:00
|
|
|
|
2018-06-20 00:01:41 -04:00
|
|
|
bool buffered_io;
|
2016-10-30 10:35:15 +02:00
|
|
|
bool enabled;
|
2016-06-21 18:04:20 +02:00
|
|
|
struct nvmet_subsys *subsys;
|
|
|
|
const char *device_path;
|
|
|
|
|
|
|
|
struct config_group device_group;
|
|
|
|
struct config_group group;
|
|
|
|
|
|
|
|
struct completion disable_done;
|
2018-05-23 00:34:39 -04:00
|
|
|
mempool_t *bvec_pool;
|
2018-10-04 15:27:47 -06:00
|
|
|
|
|
|
|
struct pci_dev *p2p_dev;
|
2023-04-27 21:47:45 +02:00
|
|
|
int use_p2pmem;
|
2020-05-19 17:05:57 +03:00
|
|
|
int pi_type;
|
|
|
|
int metadata_size;
|
2021-06-09 18:32:51 -07:00
|
|
|
u8 csi;
|
2024-11-06 15:34:46 +08:00
|
|
|
struct nvmet_pr pr;
|
|
|
|
struct xarray pr_per_ctrl_refs;
|
2016-06-21 18:04:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct nvmet_ns *to_nvmet_ns(struct config_item *item)
|
|
|
|
{
|
|
|
|
return container_of(to_config_group(item), struct nvmet_ns, group);
|
|
|
|
}
|
|
|
|
|
2018-10-04 15:27:47 -06:00
|
|
|
static inline struct device *nvmet_ns_dev(struct nvmet_ns *ns)
|
|
|
|
{
|
|
|
|
return ns->bdev ? disk_to_dev(ns->bdev->bd_disk) : NULL;
|
|
|
|
}
|
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
struct nvmet_cq {
|
nvmet: cq: prepare for completion queue sharing
For the PCI transport, the NVMe specification allows submission queues
to share completion queues, however, this is not supported in the
current NVMe target implementation. This is a preparatory patch to allow
for completion queue (CQ) sharing between different submission queues
(SQ).
To support queue sharing, reference counting completion queues is
required. This patch adds the refcount_t field ref to struct nvmet_cq
coupled with respective nvmet_cq_init(), nvmet_cq_get(), nvmet_cq_put(),
nvmet_cq_is_deletable() and nvmet_cq_destroy() functions.
A CQ reference count is initialized with nvmet_cq_init() when a CQ is
created. Using nvmet_cq_get(), a reference to a CQ is taken when an SQ is
created that uses the respective CQ. Similarly. when an SQ is destroyed,
the reference count to the respective CQ from the SQ being destroyed is
decremented with nvmet_cq_put(). The last reference to a CQ is dropped
on a CQ deletion using nvmet_cq_put(), which invokes nvmet_cq_destroy()
to fully cleanup after the CQ. The helper function nvmet_cq_in_use() is
used to determine if any SQs are still using the CQ pending deletion.
In which case, the CQ must not be deleted. This should protect scenarios
where a bad host may attempt to delete a CQ without first having deleted
SQ(s) using that CQ.
Additionally, this patch adds an array of struct nvmet_cq to the
nvmet_ctrl structure. This allows for the controller to keep track of CQs
as they are created and destroyed, similar to the current tracking done
for SQs. The memory for this array is freed when the controller is freed.
A struct nvmet_ctrl reference is also added to the nvmet_cq structure to
allow for CQs to be removed from the controller whilst keeping the new
API similar to the existing API for SQs.
Sample callchain with CQ refcounting for the PCI endpoint target
(pci-epf):
i. nvmet_execute_create_cq -> nvmet_pci_epf_create_cq
-> nvmet_cq_create -> nvmet_cq_init [cq refcount=1]
ii. nvmet_execute_create_sq -> nvmet_pci_epf_create_sq
-> nvmet_sq_create -> nvmet_sq_init -> nvmet_cq_get [cq refcount=2]
iii. nvmet_execute_delete_sq - > nvmet_pci_epf_delete_sq ->
-> nvmet_sq_destroy -> nvmet_cq_put [cq refcount 1]
iv. nvmet_execute_delete_cq -> nvmet_pci_epf_delete_cq
-> nvmet_cq_put [cq refcount 0]
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
2025-04-24 15:13:50 +10:00
|
|
|
struct nvmet_ctrl *ctrl;
|
2016-06-21 18:04:20 +02:00
|
|
|
u16 qid;
|
|
|
|
u16 size;
|
nvmet: cq: prepare for completion queue sharing
For the PCI transport, the NVMe specification allows submission queues
to share completion queues, however, this is not supported in the
current NVMe target implementation. This is a preparatory patch to allow
for completion queue (CQ) sharing between different submission queues
(SQ).
To support queue sharing, reference counting completion queues is
required. This patch adds the refcount_t field ref to struct nvmet_cq
coupled with respective nvmet_cq_init(), nvmet_cq_get(), nvmet_cq_put(),
nvmet_cq_is_deletable() and nvmet_cq_destroy() functions.
A CQ reference count is initialized with nvmet_cq_init() when a CQ is
created. Using nvmet_cq_get(), a reference to a CQ is taken when an SQ is
created that uses the respective CQ. Similarly. when an SQ is destroyed,
the reference count to the respective CQ from the SQ being destroyed is
decremented with nvmet_cq_put(). The last reference to a CQ is dropped
on a CQ deletion using nvmet_cq_put(), which invokes nvmet_cq_destroy()
to fully cleanup after the CQ. The helper function nvmet_cq_in_use() is
used to determine if any SQs are still using the CQ pending deletion.
In which case, the CQ must not be deleted. This should protect scenarios
where a bad host may attempt to delete a CQ without first having deleted
SQ(s) using that CQ.
Additionally, this patch adds an array of struct nvmet_cq to the
nvmet_ctrl structure. This allows for the controller to keep track of CQs
as they are created and destroyed, similar to the current tracking done
for SQs. The memory for this array is freed when the controller is freed.
A struct nvmet_ctrl reference is also added to the nvmet_cq structure to
allow for CQs to be removed from the controller whilst keeping the new
API similar to the existing API for SQs.
Sample callchain with CQ refcounting for the PCI endpoint target
(pci-epf):
i. nvmet_execute_create_cq -> nvmet_pci_epf_create_cq
-> nvmet_cq_create -> nvmet_cq_init [cq refcount=1]
ii. nvmet_execute_create_sq -> nvmet_pci_epf_create_sq
-> nvmet_sq_create -> nvmet_sq_init -> nvmet_cq_get [cq refcount=2]
iii. nvmet_execute_delete_sq - > nvmet_pci_epf_delete_sq ->
-> nvmet_sq_destroy -> nvmet_cq_put [cq refcount 1]
iv. nvmet_execute_delete_cq -> nvmet_pci_epf_delete_cq
-> nvmet_cq_put [cq refcount 0]
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
2025-04-24 15:13:50 +10:00
|
|
|
refcount_t ref;
|
2016-06-21 18:04:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct nvmet_sq {
|
|
|
|
struct nvmet_ctrl *ctrl;
|
|
|
|
struct percpu_ref ref;
|
2025-04-24 15:13:52 +10:00
|
|
|
struct nvmet_cq *cq;
|
2016-06-21 18:04:20 +02:00
|
|
|
u16 qid;
|
|
|
|
u16 size;
|
2017-10-18 14:33:59 -07:00
|
|
|
u32 sqhd;
|
2018-11-19 14:11:12 -08:00
|
|
|
bool sqhd_disabled;
|
2022-06-27 11:52:05 +02:00
|
|
|
#ifdef CONFIG_NVME_TARGET_AUTH
|
|
|
|
bool authenticated;
|
2023-05-01 14:40:25 +02:00
|
|
|
struct delayed_work auth_expired_work;
|
2022-06-27 11:52:05 +02:00
|
|
|
u16 dhchap_tid;
|
2024-04-30 15:19:25 +02:00
|
|
|
u8 dhchap_status;
|
|
|
|
u8 dhchap_step;
|
2022-06-27 11:52:05 +02:00
|
|
|
u8 *dhchap_c1;
|
|
|
|
u8 *dhchap_c2;
|
|
|
|
u32 dhchap_s1;
|
|
|
|
u32 dhchap_s2;
|
|
|
|
u8 *dhchap_skey;
|
|
|
|
int dhchap_skey_len;
|
2025-02-24 13:38:17 +01:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_NVME_TARGET_TCP_TLS
|
|
|
|
struct key *tls_key;
|
2022-06-27 11:52:05 +02:00
|
|
|
#endif
|
2016-06-21 18:04:20 +02:00
|
|
|
struct completion free_done;
|
2017-03-06 18:46:20 +02:00
|
|
|
struct completion confirm_done;
|
2016-06-21 18:04:20 +02:00
|
|
|
};
|
|
|
|
|
2018-06-01 08:59:25 +02:00
|
|
|
struct nvmet_ana_group {
|
|
|
|
struct config_group group;
|
|
|
|
struct nvmet_port *port;
|
|
|
|
u32 grpid;
|
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct nvmet_ana_group *to_ana_group(struct config_item *item)
|
|
|
|
{
|
|
|
|
return container_of(to_config_group(item), struct nvmet_ana_group,
|
|
|
|
group);
|
|
|
|
}
|
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
/**
|
|
|
|
* struct nvmet_port - Common structure to keep port
|
|
|
|
* information for the target.
|
2018-05-26 14:11:25 +02:00
|
|
|
* @entry: Entry into referrals or transport list.
|
2016-06-21 18:04:20 +02:00
|
|
|
* @disc_addr: Address information is stored in a format defined
|
|
|
|
* for a discovery log page entry.
|
|
|
|
* @group: ConfigFS group for this element's folder.
|
|
|
|
* @priv: Private data for the transport.
|
|
|
|
*/
|
|
|
|
struct nvmet_port {
|
|
|
|
struct list_head entry;
|
|
|
|
struct nvmf_disc_rsp_page_entry disc_addr;
|
|
|
|
struct config_group group;
|
|
|
|
struct config_group subsys_group;
|
|
|
|
struct list_head subsystems;
|
|
|
|
struct config_group referrals_group;
|
|
|
|
struct list_head referrals;
|
2018-11-12 13:56:40 -08:00
|
|
|
struct list_head global_entry;
|
2018-06-01 08:59:25 +02:00
|
|
|
struct config_group ana_groups_group;
|
|
|
|
struct nvmet_ana_group ana_default_group;
|
2018-07-19 07:35:20 -07:00
|
|
|
enum nvme_ana_state *ana_state;
|
2023-08-24 16:39:23 +02:00
|
|
|
struct key *keyring;
|
2016-06-21 18:04:20 +02:00
|
|
|
void *priv;
|
|
|
|
bool enabled;
|
nvmet-rdma: support max(16KB, PAGE_SIZE) inline data
The patch enables inline data sizes using up to 4 recv sges, and capping
the size at 16KB or at least 1 page size. So on a 4K page system, up to
16KB is supported, and for a 64K page system 1 page of 64KB is supported.
We avoid > 0 order page allocations for the inline buffers by using
multiple recv sges, one for each page. If the device cannot support
the configured inline data size due to lack of enough recv sges, then
log a warning and reduce the inline size.
Add a new configfs port attribute, called param_inline_data_size,
to allow configuring the size of inline data for a given nvmf port.
The maximum size allowed is still enforced by nvmet-rdma with
NVMET_RDMA_MAX_INLINE_DATA_SIZE, which is now max(16KB, PAGE_SIZE).
And the default size, if not specified via configfs, is still PAGE_SIZE.
This preserves the existing behavior, but allows larger inline sizes
for small page systems. If the configured inline data size exceeds
NVMET_RDMA_MAX_INLINE_DATA_SIZE, a warning is logged and the size is
reduced. If param_inline_data_size is set to 0, then inline data is
disabled for that nvmf port.
Reviewed-by: Sagi Grimberg <sagi@grimberg.me>
Reviewed-by: Max Gurtovoy <maxg@mellanox.com>
Signed-off-by: Steve Wise <swise@opengridcomputing.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
2018-06-20 07:15:10 -07:00
|
|
|
int inline_data_size;
|
2024-01-23 16:40:31 +02:00
|
|
|
int max_queue_size;
|
2019-05-14 14:58:02 -07:00
|
|
|
const struct nvmet_fabrics_ops *tr_ops;
|
2020-05-19 17:06:01 +03:00
|
|
|
bool pi_enable;
|
2016-06-21 18:04:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct nvmet_port *to_nvmet_port(struct config_item *item)
|
|
|
|
{
|
|
|
|
return container_of(to_config_group(item), struct nvmet_port,
|
|
|
|
group);
|
|
|
|
}
|
|
|
|
|
2018-06-01 08:59:25 +02:00
|
|
|
static inline struct nvmet_port *ana_groups_to_port(
|
|
|
|
struct config_item *item)
|
|
|
|
{
|
|
|
|
return container_of(to_config_group(item), struct nvmet_port,
|
|
|
|
ana_groups_group);
|
|
|
|
}
|
|
|
|
|
2023-08-24 16:39:22 +02:00
|
|
|
static inline u8 nvmet_port_disc_addr_treq_secure_channel(struct nvmet_port *port)
|
|
|
|
{
|
|
|
|
return (port->disc_addr.treq & NVME_TREQ_SECURE_CHANNEL_MASK);
|
|
|
|
}
|
|
|
|
|
2023-08-24 16:39:25 +02:00
|
|
|
static inline bool nvmet_port_secure_channel_required(struct nvmet_port *port)
|
|
|
|
{
|
|
|
|
return nvmet_port_disc_addr_treq_secure_channel(port) == NVMF_TREQ_REQUIRED;
|
|
|
|
}
|
|
|
|
|
2024-11-06 15:34:46 +08:00
|
|
|
struct nvmet_pr_log_mgr {
|
|
|
|
struct mutex lock;
|
|
|
|
u64 lost_count;
|
|
|
|
u64 counter;
|
|
|
|
DECLARE_KFIFO(log_queue, struct nvme_pr_log, NVMET_PR_LOG_QUEUE_SIZE);
|
|
|
|
};
|
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
struct nvmet_ctrl {
|
|
|
|
struct nvmet_subsys *subsys;
|
|
|
|
struct nvmet_sq **sqs;
|
nvmet: cq: prepare for completion queue sharing
For the PCI transport, the NVMe specification allows submission queues
to share completion queues, however, this is not supported in the
current NVMe target implementation. This is a preparatory patch to allow
for completion queue (CQ) sharing between different submission queues
(SQ).
To support queue sharing, reference counting completion queues is
required. This patch adds the refcount_t field ref to struct nvmet_cq
coupled with respective nvmet_cq_init(), nvmet_cq_get(), nvmet_cq_put(),
nvmet_cq_is_deletable() and nvmet_cq_destroy() functions.
A CQ reference count is initialized with nvmet_cq_init() when a CQ is
created. Using nvmet_cq_get(), a reference to a CQ is taken when an SQ is
created that uses the respective CQ. Similarly. when an SQ is destroyed,
the reference count to the respective CQ from the SQ being destroyed is
decremented with nvmet_cq_put(). The last reference to a CQ is dropped
on a CQ deletion using nvmet_cq_put(), which invokes nvmet_cq_destroy()
to fully cleanup after the CQ. The helper function nvmet_cq_in_use() is
used to determine if any SQs are still using the CQ pending deletion.
In which case, the CQ must not be deleted. This should protect scenarios
where a bad host may attempt to delete a CQ without first having deleted
SQ(s) using that CQ.
Additionally, this patch adds an array of struct nvmet_cq to the
nvmet_ctrl structure. This allows for the controller to keep track of CQs
as they are created and destroyed, similar to the current tracking done
for SQs. The memory for this array is freed when the controller is freed.
A struct nvmet_ctrl reference is also added to the nvmet_cq structure to
allow for CQs to be removed from the controller whilst keeping the new
API similar to the existing API for SQs.
Sample callchain with CQ refcounting for the PCI endpoint target
(pci-epf):
i. nvmet_execute_create_cq -> nvmet_pci_epf_create_cq
-> nvmet_cq_create -> nvmet_cq_init [cq refcount=1]
ii. nvmet_execute_create_sq -> nvmet_pci_epf_create_sq
-> nvmet_sq_create -> nvmet_sq_init -> nvmet_cq_get [cq refcount=2]
iii. nvmet_execute_delete_sq - > nvmet_pci_epf_delete_sq ->
-> nvmet_sq_destroy -> nvmet_cq_put [cq refcount 1]
iv. nvmet_execute_delete_cq -> nvmet_pci_epf_delete_cq
-> nvmet_cq_put [cq refcount 0]
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
2025-04-24 15:13:50 +10:00
|
|
|
struct nvmet_cq **cqs;
|
2016-06-21 18:04:20 +02:00
|
|
|
|
2025-01-04 13:59:38 +09:00
|
|
|
void *drvdata;
|
|
|
|
|
2021-05-25 08:49:05 -07:00
|
|
|
bool reset_tbkas;
|
2018-11-02 10:28:13 -07:00
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
struct mutex lock;
|
|
|
|
u64 cap;
|
|
|
|
u32 cc;
|
|
|
|
u32 csts;
|
|
|
|
|
2017-08-30 15:22:59 +03:00
|
|
|
uuid_t hostid;
|
2016-06-21 18:04:20 +02:00
|
|
|
u16 cntlid;
|
|
|
|
u32 kato;
|
|
|
|
|
2018-06-07 15:09:50 +02:00
|
|
|
struct nvmet_port *port;
|
|
|
|
|
2018-05-30 15:04:47 +02:00
|
|
|
u32 aen_enabled;
|
2018-05-30 15:05:09 +02:00
|
|
|
unsigned long aen_masked;
|
2016-06-21 18:04:20 +02:00
|
|
|
struct nvmet_req *async_event_cmds[NVMET_ASYNC_EVENTS];
|
|
|
|
unsigned int nr_async_event_cmds;
|
|
|
|
struct list_head async_events;
|
|
|
|
struct work_struct async_event_work;
|
|
|
|
|
|
|
|
struct list_head subsys_entry;
|
|
|
|
struct kref ref;
|
|
|
|
struct delayed_work ka_work;
|
|
|
|
struct work_struct fatal_err_work;
|
|
|
|
|
2018-03-20 20:41:35 +01:00
|
|
|
const struct nvmet_fabrics_ops *ops;
|
2016-06-21 18:04:20 +02:00
|
|
|
|
2018-05-25 17:16:09 +02:00
|
|
|
__le32 *changed_ns_list;
|
|
|
|
u32 nr_changed_ns;
|
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
char subsysnqn[NVMF_NQN_FIELD_LEN];
|
|
|
|
char hostnqn[NVMF_NQN_FIELD_LEN];
|
2018-10-04 15:27:47 -06:00
|
|
|
|
2018-11-19 15:16:39 -08:00
|
|
|
struct device *p2p_client;
|
|
|
|
struct radix_tree_root p2p_ns_map;
|
2024-05-27 07:15:19 +02:00
|
|
|
#ifdef CONFIG_NVME_TARGET_DEBUGFS
|
|
|
|
struct dentry *debugfs_dir;
|
|
|
|
#endif
|
2018-12-12 15:11:39 -08:00
|
|
|
spinlock_t error_lock;
|
|
|
|
u64 err_counter;
|
|
|
|
struct nvme_error_slot slots[NVMET_ERROR_LOG_SLOTS];
|
2020-05-19 17:06:01 +03:00
|
|
|
bool pi_support;
|
2025-02-24 13:38:17 +01:00
|
|
|
bool concat;
|
2022-06-27 11:52:05 +02:00
|
|
|
#ifdef CONFIG_NVME_TARGET_AUTH
|
|
|
|
struct nvme_dhchap_key *host_key;
|
|
|
|
struct nvme_dhchap_key *ctrl_key;
|
|
|
|
u8 shash_id;
|
2022-06-27 11:52:06 +02:00
|
|
|
struct crypto_kpp *dh_tfm;
|
|
|
|
u8 dh_gid;
|
|
|
|
u8 *dh_key;
|
|
|
|
size_t dh_keysize;
|
2025-02-24 13:38:17 +01:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_NVME_TARGET_TCP_TLS
|
|
|
|
struct key *tls_key;
|
2022-06-27 11:52:05 +02:00
|
|
|
#endif
|
2024-11-06 15:34:46 +08:00
|
|
|
struct nvmet_pr_log_mgr pr_log_mgr;
|
2016-06-21 18:04:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
struct nvmet_subsys {
|
|
|
|
enum nvme_subsys_type type;
|
|
|
|
|
|
|
|
struct mutex lock;
|
|
|
|
struct kref ref;
|
|
|
|
|
nvmet: use xarray for ctrl ns storing
This patch replaces the ctrl->namespaces tracking from linked list to
xarray and improves the performance when accessing one namespce :-
XArray vs Default:-
IOPS and BW (more the better) increase BW (~1.8%):-
---------------------------------------------------
XArray :-
read: IOPS=160k, BW=626MiB/s (656MB/s)(18.3GiB/30001msec)
read: IOPS=160k, BW=626MiB/s (656MB/s)(18.3GiB/30001msec)
read: IOPS=162k, BW=631MiB/s (662MB/s)(18.5GiB/30001msec)
Default:-
read: IOPS=156k, BW=609MiB/s (639MB/s)(17.8GiB/30001msec)
read: IOPS=157k, BW=613MiB/s (643MB/s)(17.0GiB/30001msec)
read: IOPS=160k, BW=626MiB/s (656MB/s)(18.3GiB/30001msec)
Submission latency (less the better) decrease (~8.3%):-
-------------------------------------------------------
XArray:-
slat (usec): min=7, max=8386, avg=11.19, stdev=5.96
slat (usec): min=7, max=441, avg=11.09, stdev=4.48
slat (usec): min=7, max=1088, avg=11.21, stdev=4.54
Default :-
slat (usec): min=8, max=2826.5k, avg=23.96, stdev=3911.50
slat (usec): min=8, max=503, avg=12.52, stdev=5.07
slat (usec): min=8, max=2384, avg=12.50, stdev=5.28
CPU Usage (less the better) decrease (~5.2%):-
----------------------------------------------
XArray:-
cpu : usr=1.84%, sys=18.61%, ctx=949471, majf=0, minf=250
cpu : usr=1.83%, sys=18.41%, ctx=950262, majf=0, minf=237
cpu : usr=1.82%, sys=18.82%, ctx=957224, majf=0, minf=234
Default:-
cpu : usr=1.70%, sys=19.21%, ctx=858196, majf=0, minf=251
cpu : usr=1.82%, sys=19.98%, ctx=929720, majf=0, minf=227
cpu : usr=1.83%, sys=20.33%, ctx=947208, majf=0, minf=235.
Signed-off-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
2020-07-19 20:32:02 -07:00
|
|
|
struct xarray namespaces;
|
2018-05-13 19:00:13 +02:00
|
|
|
unsigned int nr_namespaces;
|
2021-06-13 18:58:48 -07:00
|
|
|
u32 max_nsid;
|
2020-01-30 10:29:31 -08:00
|
|
|
u16 cntlid_min;
|
|
|
|
u16 cntlid_max;
|
2016-06-21 18:04:20 +02:00
|
|
|
|
|
|
|
struct list_head ctrls;
|
|
|
|
|
|
|
|
struct list_head hosts;
|
|
|
|
bool allow_any_host;
|
2024-05-27 07:15:19 +02:00
|
|
|
#ifdef CONFIG_NVME_TARGET_DEBUGFS
|
|
|
|
struct dentry *debugfs_dir;
|
|
|
|
#endif
|
2016-06-21 18:04:20 +02:00
|
|
|
u16 max_qid;
|
|
|
|
|
|
|
|
u64 ver;
|
2021-06-07 12:23:21 +03:00
|
|
|
char serial[NVMET_SN_MAX_SIZE];
|
2021-06-07 12:23:22 +03:00
|
|
|
bool subsys_discovered;
|
2016-06-21 18:04:20 +02:00
|
|
|
char *subsysnqn;
|
2020-05-19 17:06:01 +03:00
|
|
|
bool pi_support;
|
2016-06-21 18:04:20 +02:00
|
|
|
|
|
|
|
struct config_group group;
|
|
|
|
|
|
|
|
struct config_group namespaces_group;
|
|
|
|
struct config_group allowed_hosts_group;
|
2020-01-30 10:29:32 -08:00
|
|
|
|
2025-01-04 13:59:35 +09:00
|
|
|
u16 vendor_id;
|
|
|
|
u16 subsys_vendor_id;
|
2021-02-17 17:19:40 +00:00
|
|
|
char *model_number;
|
2022-11-15 14:58:09 +03:00
|
|
|
u32 ieee_oui;
|
2022-11-15 14:58:10 +03:00
|
|
|
char *firmware_rev;
|
2020-07-24 11:25:17 -06:00
|
|
|
|
|
|
|
#ifdef CONFIG_NVME_TARGET_PASSTHRU
|
|
|
|
struct nvme_ctrl *passthru_ctrl;
|
2020-07-24 11:25:18 -06:00
|
|
|
char *passthru_ctrl_path;
|
2020-07-24 11:25:19 -06:00
|
|
|
struct config_group passthru_group;
|
2020-11-09 16:33:43 -08:00
|
|
|
unsigned int admin_timeout;
|
2020-11-09 16:33:44 -08:00
|
|
|
unsigned int io_timeout;
|
2022-06-27 16:25:43 -07:00
|
|
|
unsigned int clear_ids;
|
2020-07-24 11:25:17 -06:00
|
|
|
#endif /* CONFIG_NVME_TARGET_PASSTHRU */
|
2021-06-09 18:32:52 -07:00
|
|
|
|
|
|
|
#ifdef CONFIG_BLK_DEV_ZONED
|
|
|
|
u8 zasl;
|
|
|
|
#endif /* CONFIG_BLK_DEV_ZONED */
|
2016-06-21 18:04:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct nvmet_subsys *to_subsys(struct config_item *item)
|
|
|
|
{
|
|
|
|
return container_of(to_config_group(item), struct nvmet_subsys, group);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline struct nvmet_subsys *namespaces_to_subsys(
|
|
|
|
struct config_item *item)
|
|
|
|
{
|
|
|
|
return container_of(to_config_group(item), struct nvmet_subsys,
|
|
|
|
namespaces_group);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct nvmet_host {
|
|
|
|
struct config_group group;
|
2022-06-27 11:52:05 +02:00
|
|
|
u8 *dhchap_secret;
|
|
|
|
u8 *dhchap_ctrl_secret;
|
|
|
|
u8 dhchap_key_hash;
|
|
|
|
u8 dhchap_ctrl_key_hash;
|
|
|
|
u8 dhchap_hash_id;
|
|
|
|
u8 dhchap_dhgroup_id;
|
2016-06-21 18:04:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
static inline struct nvmet_host *to_host(struct config_item *item)
|
|
|
|
{
|
|
|
|
return container_of(to_config_group(item), struct nvmet_host, group);
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline char *nvmet_host_name(struct nvmet_host *host)
|
|
|
|
{
|
|
|
|
return config_item_name(&host->group.cg_item);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct nvmet_host_link {
|
|
|
|
struct list_head entry;
|
|
|
|
struct nvmet_host *host;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct nvmet_subsys_link {
|
|
|
|
struct list_head entry;
|
|
|
|
struct nvmet_subsys *subsys;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct nvmet_req;
|
|
|
|
struct nvmet_fabrics_ops {
|
|
|
|
struct module *owner;
|
|
|
|
unsigned int type;
|
|
|
|
unsigned int msdbd;
|
2020-06-02 16:15:46 +03:00
|
|
|
unsigned int flags;
|
|
|
|
#define NVMF_KEYED_SGLS (1 << 0)
|
|
|
|
#define NVMF_METADATA_SUPPORTED (1 << 1)
|
2016-06-21 18:04:20 +02:00
|
|
|
void (*queue_response)(struct nvmet_req *req);
|
|
|
|
int (*add_port)(struct nvmet_port *port);
|
|
|
|
void (*remove_port)(struct nvmet_port *port);
|
|
|
|
void (*delete_ctrl)(struct nvmet_ctrl *ctrl);
|
2018-01-24 20:27:10 +02:00
|
|
|
void (*disc_traddr)(struct nvmet_req *req,
|
|
|
|
struct nvmet_port *port, char *traddr);
|
2024-05-27 07:15:20 +02:00
|
|
|
ssize_t (*host_traddr)(struct nvmet_ctrl *ctrl,
|
|
|
|
char *traddr, size_t traddr_len);
|
2018-12-03 17:52:11 -08:00
|
|
|
u16 (*install_queue)(struct nvmet_sq *nvme_sq);
|
2019-05-14 14:58:02 -07:00
|
|
|
void (*discovery_chg)(struct nvmet_port *port);
|
2020-03-08 12:55:03 +02:00
|
|
|
u8 (*get_mdts)(const struct nvmet_ctrl *ctrl);
|
2021-09-23 00:55:36 +03:00
|
|
|
u16 (*get_max_queue_size)(const struct nvmet_ctrl *ctrl);
|
2025-01-04 13:59:43 +09:00
|
|
|
|
|
|
|
/* Operations mandatory for PCI target controllers */
|
2025-04-24 15:13:52 +10:00
|
|
|
u16 (*create_sq)(struct nvmet_ctrl *ctrl, u16 sqid, u16 cqid, u16 flags,
|
2025-01-04 13:59:43 +09:00
|
|
|
u16 qsize, u64 prp1);
|
|
|
|
u16 (*delete_sq)(struct nvmet_ctrl *ctrl, u16 sqid);
|
|
|
|
u16 (*create_cq)(struct nvmet_ctrl *ctrl, u16 cqid, u16 flags,
|
|
|
|
u16 qsize, u64 prp1, u16 irq_vector);
|
|
|
|
u16 (*delete_cq)(struct nvmet_ctrl *ctrl, u16 cqid);
|
2025-01-04 13:59:45 +09:00
|
|
|
u16 (*set_feature)(const struct nvmet_ctrl *ctrl, u8 feat,
|
|
|
|
void *feat_data);
|
|
|
|
u16 (*get_feature)(const struct nvmet_ctrl *ctrl, u8 feat,
|
|
|
|
void *feat_data);
|
2016-06-21 18:04:20 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
#define NVMET_MAX_INLINE_BIOVEC 8
|
2018-09-28 15:40:43 -07:00
|
|
|
#define NVMET_MAX_INLINE_DATA_LEN NVMET_MAX_INLINE_BIOVEC * PAGE_SIZE
|
2016-06-21 18:04:20 +02:00
|
|
|
|
|
|
|
struct nvmet_req {
|
|
|
|
struct nvme_command *cmd;
|
2019-04-08 18:39:59 +03:00
|
|
|
struct nvme_completion *cqe;
|
2016-06-21 18:04:20 +02:00
|
|
|
struct nvmet_sq *sq;
|
|
|
|
struct nvmet_cq *cq;
|
|
|
|
struct nvmet_ns *ns;
|
|
|
|
struct scatterlist *sg;
|
2020-05-19 17:06:02 +03:00
|
|
|
struct scatterlist *metadata_sg;
|
2016-06-21 18:04:20 +02:00
|
|
|
struct bio_vec inline_bvec[NVMET_MAX_INLINE_BIOVEC];
|
2018-05-23 00:34:39 -04:00
|
|
|
union {
|
|
|
|
struct {
|
|
|
|
struct bio inline_bio;
|
|
|
|
} b;
|
|
|
|
struct {
|
|
|
|
bool mpool_alloc;
|
|
|
|
struct kiocb iocb;
|
|
|
|
struct bio_vec *bvec;
|
|
|
|
struct work_struct work;
|
|
|
|
} f;
|
2020-07-24 11:25:17 -06:00
|
|
|
struct {
|
2020-11-09 18:24:05 -08:00
|
|
|
struct bio inline_bio;
|
2020-07-24 11:25:17 -06:00
|
|
|
struct request *rq;
|
|
|
|
struct work_struct work;
|
|
|
|
bool use_workqueue;
|
|
|
|
} p;
|
2021-06-09 18:32:52 -07:00
|
|
|
#ifdef CONFIG_BLK_DEV_ZONED
|
|
|
|
struct {
|
|
|
|
struct bio inline_bio;
|
|
|
|
struct work_struct zmgmt_work;
|
|
|
|
} z;
|
|
|
|
#endif /* CONFIG_BLK_DEV_ZONED */
|
2024-11-06 15:34:46 +08:00
|
|
|
struct {
|
|
|
|
struct work_struct abort_work;
|
|
|
|
} r;
|
2018-05-23 00:34:39 -04:00
|
|
|
};
|
2016-06-21 18:04:20 +02:00
|
|
|
int sg_cnt;
|
2020-05-19 17:06:02 +03:00
|
|
|
int metadata_sg_cnt;
|
2017-11-09 14:29:58 +01:00
|
|
|
/* data length as parsed from the SGL descriptor: */
|
|
|
|
size_t transfer_len;
|
2020-05-19 17:06:02 +03:00
|
|
|
size_t metadata_len;
|
2016-06-21 18:04:20 +02:00
|
|
|
|
|
|
|
struct nvmet_port *port;
|
|
|
|
|
|
|
|
void (*execute)(struct nvmet_req *req);
|
2018-03-20 20:41:35 +01:00
|
|
|
const struct nvmet_fabrics_ops *ops;
|
2018-10-04 15:27:47 -06:00
|
|
|
|
2018-11-19 15:16:39 -08:00
|
|
|
struct pci_dev *p2p_dev;
|
|
|
|
struct device *p2p_client;
|
2018-12-12 15:11:39 -08:00
|
|
|
u16 error_loc;
|
|
|
|
u64 error_slba;
|
2024-11-06 15:34:46 +08:00
|
|
|
struct nvmet_pr_per_ctrl_ref *pc_ref;
|
2016-06-21 18:04:20 +02:00
|
|
|
};
|
|
|
|
|
2022-11-07 14:01:24 +01:00
|
|
|
#define NVMET_MAX_MPOOL_BVEC 16
|
|
|
|
extern struct kmem_cache *nvmet_bvec_cache;
|
2018-06-20 00:01:41 -04:00
|
|
|
extern struct workqueue_struct *buffered_io_wq;
|
2021-06-09 18:32:52 -07:00
|
|
|
extern struct workqueue_struct *zbd_wq;
|
2022-03-21 13:57:27 +02:00
|
|
|
extern struct workqueue_struct *nvmet_wq;
|
2018-06-20 00:01:41 -04:00
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
static inline void nvmet_set_result(struct nvmet_req *req, u32 result)
|
|
|
|
{
|
2019-04-08 18:39:59 +03:00
|
|
|
req->cqe->result.u32 = cpu_to_le32(result);
|
2016-06-21 18:04:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* NVMe command writes actually are DMA reads for us on the target side.
|
|
|
|
*/
|
|
|
|
static inline enum dma_data_direction
|
|
|
|
nvmet_data_dir(struct nvmet_req *req)
|
|
|
|
{
|
|
|
|
return nvme_is_write(req->cmd) ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct nvmet_async_event {
|
|
|
|
struct list_head entry;
|
|
|
|
u8 event_type;
|
|
|
|
u8 event_info;
|
|
|
|
u8 log_page;
|
|
|
|
};
|
|
|
|
|
2018-11-12 13:56:34 -08:00
|
|
|
static inline void nvmet_clear_aen_bit(struct nvmet_req *req, u32 bn)
|
2018-11-12 13:56:33 -08:00
|
|
|
{
|
2018-12-12 15:11:37 -08:00
|
|
|
int rae = le32_to_cpu(req->cmd->common.cdw10) & 1 << 15;
|
2018-11-12 13:56:33 -08:00
|
|
|
|
|
|
|
if (!rae)
|
2018-11-12 13:56:34 -08:00
|
|
|
clear_bit(bn, &req->sq->ctrl->aen_masked);
|
2018-11-12 13:56:33 -08:00
|
|
|
}
|
|
|
|
|
2018-11-12 13:56:34 -08:00
|
|
|
static inline bool nvmet_aen_bit_disabled(struct nvmet_ctrl *ctrl, u32 bn)
|
2018-11-12 13:56:33 -08:00
|
|
|
{
|
2018-11-12 13:56:34 -08:00
|
|
|
if (!(READ_ONCE(ctrl->aen_enabled) & (1 << bn)))
|
2018-11-12 13:56:33 -08:00
|
|
|
return true;
|
2018-11-12 13:56:34 -08:00
|
|
|
return test_and_set_bit(bn, &ctrl->aen_masked);
|
2018-11-12 13:56:33 -08:00
|
|
|
}
|
|
|
|
|
2018-11-12 13:56:36 -08:00
|
|
|
void nvmet_get_feat_kato(struct nvmet_req *req);
|
|
|
|
void nvmet_get_feat_async_event(struct nvmet_req *req);
|
|
|
|
u16 nvmet_set_feat_kato(struct nvmet_req *req);
|
|
|
|
u16 nvmet_set_feat_async_event(struct nvmet_req *req, u32 mask);
|
|
|
|
void nvmet_execute_async_event(struct nvmet_req *req);
|
2020-09-16 20:47:20 +03:00
|
|
|
void nvmet_start_keep_alive_timer(struct nvmet_ctrl *ctrl);
|
|
|
|
void nvmet_stop_keep_alive_timer(struct nvmet_ctrl *ctrl);
|
2018-11-12 13:56:36 -08:00
|
|
|
|
2017-02-27 23:21:33 -06:00
|
|
|
u16 nvmet_parse_connect_cmd(struct nvmet_req *req);
|
2025-01-04 13:59:41 +09:00
|
|
|
u32 nvmet_connect_cmd_data_len(struct nvmet_req *req);
|
2019-06-28 09:53:30 -07:00
|
|
|
void nvmet_bdev_set_limits(struct block_device *bdev, struct nvme_id_ns *id);
|
2018-05-23 00:34:39 -04:00
|
|
|
u16 nvmet_bdev_parse_io_cmd(struct nvmet_req *req);
|
|
|
|
u16 nvmet_file_parse_io_cmd(struct nvmet_req *req);
|
2021-06-09 18:32:52 -07:00
|
|
|
u16 nvmet_bdev_zns_parse_io_cmd(struct nvmet_req *req);
|
2025-01-04 13:59:41 +09:00
|
|
|
u32 nvmet_admin_cmd_data_len(struct nvmet_req *req);
|
2017-02-27 23:21:33 -06:00
|
|
|
u16 nvmet_parse_admin_cmd(struct nvmet_req *req);
|
2025-01-04 13:59:41 +09:00
|
|
|
u32 nvmet_discovery_cmd_data_len(struct nvmet_req *req);
|
2017-02-27 23:21:33 -06:00
|
|
|
u16 nvmet_parse_discovery_cmd(struct nvmet_req *req);
|
2022-06-27 11:52:04 +02:00
|
|
|
u16 nvmet_parse_fabrics_admin_cmd(struct nvmet_req *req);
|
2025-01-04 13:59:41 +09:00
|
|
|
u32 nvmet_fabrics_admin_cmd_data_len(struct nvmet_req *req);
|
2022-06-27 11:52:04 +02:00
|
|
|
u16 nvmet_parse_fabrics_io_cmd(struct nvmet_req *req);
|
2025-01-04 13:59:41 +09:00
|
|
|
u32 nvmet_fabrics_io_cmd_data_len(struct nvmet_req *req);
|
2016-06-21 18:04:20 +02:00
|
|
|
|
2025-04-24 15:13:53 +10:00
|
|
|
bool nvmet_req_init(struct nvmet_req *req, struct nvmet_sq *sq,
|
|
|
|
const struct nvmet_fabrics_ops *ops);
|
2017-05-08 16:38:35 -07:00
|
|
|
void nvmet_req_uninit(struct nvmet_req *req);
|
2025-01-04 13:59:41 +09:00
|
|
|
size_t nvmet_req_transfer_len(struct nvmet_req *req);
|
2020-05-19 17:05:59 +03:00
|
|
|
bool nvmet_check_transfer_len(struct nvmet_req *req, size_t len);
|
2020-01-26 23:23:28 -08:00
|
|
|
bool nvmet_check_data_len_lte(struct nvmet_req *req, size_t data_len);
|
2016-06-21 18:04:20 +02:00
|
|
|
void nvmet_req_complete(struct nvmet_req *req, u16 status);
|
2020-05-19 17:06:02 +03:00
|
|
|
int nvmet_req_alloc_sgls(struct nvmet_req *req);
|
|
|
|
void nvmet_req_free_sgls(struct nvmet_req *req);
|
2016-06-21 18:04:20 +02:00
|
|
|
|
2020-07-24 11:25:17 -06:00
|
|
|
void nvmet_execute_set_features(struct nvmet_req *req);
|
|
|
|
void nvmet_execute_get_features(struct nvmet_req *req);
|
2018-11-12 13:56:35 -08:00
|
|
|
void nvmet_execute_keep_alive(struct nvmet_req *req);
|
|
|
|
|
nvmet: cq: prepare for completion queue sharing
For the PCI transport, the NVMe specification allows submission queues
to share completion queues, however, this is not supported in the
current NVMe target implementation. This is a preparatory patch to allow
for completion queue (CQ) sharing between different submission queues
(SQ).
To support queue sharing, reference counting completion queues is
required. This patch adds the refcount_t field ref to struct nvmet_cq
coupled with respective nvmet_cq_init(), nvmet_cq_get(), nvmet_cq_put(),
nvmet_cq_is_deletable() and nvmet_cq_destroy() functions.
A CQ reference count is initialized with nvmet_cq_init() when a CQ is
created. Using nvmet_cq_get(), a reference to a CQ is taken when an SQ is
created that uses the respective CQ. Similarly. when an SQ is destroyed,
the reference count to the respective CQ from the SQ being destroyed is
decremented with nvmet_cq_put(). The last reference to a CQ is dropped
on a CQ deletion using nvmet_cq_put(), which invokes nvmet_cq_destroy()
to fully cleanup after the CQ. The helper function nvmet_cq_in_use() is
used to determine if any SQs are still using the CQ pending deletion.
In which case, the CQ must not be deleted. This should protect scenarios
where a bad host may attempt to delete a CQ without first having deleted
SQ(s) using that CQ.
Additionally, this patch adds an array of struct nvmet_cq to the
nvmet_ctrl structure. This allows for the controller to keep track of CQs
as they are created and destroyed, similar to the current tracking done
for SQs. The memory for this array is freed when the controller is freed.
A struct nvmet_ctrl reference is also added to the nvmet_cq structure to
allow for CQs to be removed from the controller whilst keeping the new
API similar to the existing API for SQs.
Sample callchain with CQ refcounting for the PCI endpoint target
(pci-epf):
i. nvmet_execute_create_cq -> nvmet_pci_epf_create_cq
-> nvmet_cq_create -> nvmet_cq_init [cq refcount=1]
ii. nvmet_execute_create_sq -> nvmet_pci_epf_create_sq
-> nvmet_sq_create -> nvmet_sq_init -> nvmet_cq_get [cq refcount=2]
iii. nvmet_execute_delete_sq - > nvmet_pci_epf_delete_sq ->
-> nvmet_sq_destroy -> nvmet_cq_put [cq refcount 1]
iv. nvmet_execute_delete_cq -> nvmet_pci_epf_delete_cq
-> nvmet_cq_put [cq refcount 0]
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
2025-04-24 15:13:50 +10:00
|
|
|
u16 nvmet_check_cqid(struct nvmet_ctrl *ctrl, u16 cqid, bool create);
|
|
|
|
u16 nvmet_check_io_cqid(struct nvmet_ctrl *ctrl, u16 cqid, bool create);
|
|
|
|
void nvmet_cq_init(struct nvmet_cq *cq);
|
2016-06-21 18:04:20 +02:00
|
|
|
void nvmet_cq_setup(struct nvmet_ctrl *ctrl, struct nvmet_cq *cq, u16 qid,
|
|
|
|
u16 size);
|
2025-01-04 13:59:42 +09:00
|
|
|
u16 nvmet_cq_create(struct nvmet_ctrl *ctrl, struct nvmet_cq *cq, u16 qid,
|
|
|
|
u16 size);
|
nvmet: cq: prepare for completion queue sharing
For the PCI transport, the NVMe specification allows submission queues
to share completion queues, however, this is not supported in the
current NVMe target implementation. This is a preparatory patch to allow
for completion queue (CQ) sharing between different submission queues
(SQ).
To support queue sharing, reference counting completion queues is
required. This patch adds the refcount_t field ref to struct nvmet_cq
coupled with respective nvmet_cq_init(), nvmet_cq_get(), nvmet_cq_put(),
nvmet_cq_is_deletable() and nvmet_cq_destroy() functions.
A CQ reference count is initialized with nvmet_cq_init() when a CQ is
created. Using nvmet_cq_get(), a reference to a CQ is taken when an SQ is
created that uses the respective CQ. Similarly. when an SQ is destroyed,
the reference count to the respective CQ from the SQ being destroyed is
decremented with nvmet_cq_put(). The last reference to a CQ is dropped
on a CQ deletion using nvmet_cq_put(), which invokes nvmet_cq_destroy()
to fully cleanup after the CQ. The helper function nvmet_cq_in_use() is
used to determine if any SQs are still using the CQ pending deletion.
In which case, the CQ must not be deleted. This should protect scenarios
where a bad host may attempt to delete a CQ without first having deleted
SQ(s) using that CQ.
Additionally, this patch adds an array of struct nvmet_cq to the
nvmet_ctrl structure. This allows for the controller to keep track of CQs
as they are created and destroyed, similar to the current tracking done
for SQs. The memory for this array is freed when the controller is freed.
A struct nvmet_ctrl reference is also added to the nvmet_cq structure to
allow for CQs to be removed from the controller whilst keeping the new
API similar to the existing API for SQs.
Sample callchain with CQ refcounting for the PCI endpoint target
(pci-epf):
i. nvmet_execute_create_cq -> nvmet_pci_epf_create_cq
-> nvmet_cq_create -> nvmet_cq_init [cq refcount=1]
ii. nvmet_execute_create_sq -> nvmet_pci_epf_create_sq
-> nvmet_sq_create -> nvmet_sq_init -> nvmet_cq_get [cq refcount=2]
iii. nvmet_execute_delete_sq - > nvmet_pci_epf_delete_sq ->
-> nvmet_sq_destroy -> nvmet_cq_put [cq refcount 1]
iv. nvmet_execute_delete_cq -> nvmet_pci_epf_delete_cq
-> nvmet_cq_put [cq refcount 0]
Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com>
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Damien Le Moal <dlemoal@kernel.org>
Signed-off-by: Christoph Hellwig <hch@lst.de>
2025-04-24 15:13:50 +10:00
|
|
|
void nvmet_cq_destroy(struct nvmet_cq *cq);
|
|
|
|
bool nvmet_cq_get(struct nvmet_cq *cq);
|
|
|
|
void nvmet_cq_put(struct nvmet_cq *cq);
|
|
|
|
bool nvmet_cq_in_use(struct nvmet_cq *cq);
|
2025-01-04 13:59:42 +09:00
|
|
|
u16 nvmet_check_sqid(struct nvmet_ctrl *ctrl, u16 sqid, bool create);
|
2016-06-21 18:04:20 +02:00
|
|
|
void nvmet_sq_setup(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq, u16 qid,
|
|
|
|
u16 size);
|
2025-04-24 15:13:52 +10:00
|
|
|
u16 nvmet_sq_create(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq,
|
|
|
|
struct nvmet_cq *cq, u16 qid, u16 size);
|
2016-06-21 18:04:20 +02:00
|
|
|
void nvmet_sq_destroy(struct nvmet_sq *sq);
|
2025-04-24 15:13:52 +10:00
|
|
|
int nvmet_sq_init(struct nvmet_sq *sq, struct nvmet_cq *cq);
|
2016-06-21 18:04:20 +02:00
|
|
|
|
|
|
|
void nvmet_ctrl_fatal_error(struct nvmet_ctrl *ctrl);
|
|
|
|
|
|
|
|
void nvmet_update_cc(struct nvmet_ctrl *ctrl, u32 new);
|
nvmet: Improve nvmet_alloc_ctrl() interface and implementation
Introduce struct nvmet_alloc_ctrl_args to define the arguments for
the function nvmet_alloc_ctrl() to avoid the need for passing a pointer
to a struct nvmet_req as an argument. This new data structure aggregates
together the arguments that were passed to nvmet_alloc_ctrl()
(subsysnqn, hostnqn and kato), together with the struct nvmet_req fields
used by nvmet_alloc_ctrl(), that is, the fields port, p2p_client, and
ops as input and the result and error_loc fields as output, as well as a
status field. nvmet_alloc_ctrl() is also changed to return a pointer
to the allocated and initialized controller structure instead of a
status code, as the status is now returned through the status field of
struct nvmet_alloc_ctrl_args.
The function nvmet_setup_p2p_ns_map() is changed to not take a pointer
to a struct nvmet_req as argument, instead, directly specify the
p2p_client device pointer needed as argument.
The code in nvmet_execute_admin_connect() that initializes a new target
controller after allocating it is moved into nvmet_alloc_ctrl().
The code that sets up an admin queue for the controller (and the call
to nvmet_install_queue()) remains in nvmet_execute_admin_connect().
Finally, nvmet_alloc_ctrl() is also exported to allow target drivers to
use this function directly to allocate and initialize a new controller
structure without the need to rely on a fabrics connect command request.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
Tested-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2025-01-04 13:59:40 +09:00
|
|
|
|
|
|
|
struct nvmet_alloc_ctrl_args {
|
|
|
|
struct nvmet_port *port;
|
2025-02-24 13:38:16 +01:00
|
|
|
struct nvmet_sq *sq;
|
nvmet: Improve nvmet_alloc_ctrl() interface and implementation
Introduce struct nvmet_alloc_ctrl_args to define the arguments for
the function nvmet_alloc_ctrl() to avoid the need for passing a pointer
to a struct nvmet_req as an argument. This new data structure aggregates
together the arguments that were passed to nvmet_alloc_ctrl()
(subsysnqn, hostnqn and kato), together with the struct nvmet_req fields
used by nvmet_alloc_ctrl(), that is, the fields port, p2p_client, and
ops as input and the result and error_loc fields as output, as well as a
status field. nvmet_alloc_ctrl() is also changed to return a pointer
to the allocated and initialized controller structure instead of a
status code, as the status is now returned through the status field of
struct nvmet_alloc_ctrl_args.
The function nvmet_setup_p2p_ns_map() is changed to not take a pointer
to a struct nvmet_req as argument, instead, directly specify the
p2p_client device pointer needed as argument.
The code in nvmet_execute_admin_connect() that initializes a new target
controller after allocating it is moved into nvmet_alloc_ctrl().
The code that sets up an admin queue for the controller (and the call
to nvmet_install_queue()) remains in nvmet_execute_admin_connect().
Finally, nvmet_alloc_ctrl() is also exported to allow target drivers to
use this function directly to allocate and initialize a new controller
structure without the need to rely on a fabrics connect command request.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
Tested-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2025-01-04 13:59:40 +09:00
|
|
|
char *subsysnqn;
|
|
|
|
char *hostnqn;
|
|
|
|
uuid_t *hostid;
|
|
|
|
const struct nvmet_fabrics_ops *ops;
|
|
|
|
struct device *p2p_client;
|
|
|
|
u32 kato;
|
2025-01-28 08:55:33 +01:00
|
|
|
__le32 result;
|
nvmet: Improve nvmet_alloc_ctrl() interface and implementation
Introduce struct nvmet_alloc_ctrl_args to define the arguments for
the function nvmet_alloc_ctrl() to avoid the need for passing a pointer
to a struct nvmet_req as an argument. This new data structure aggregates
together the arguments that were passed to nvmet_alloc_ctrl()
(subsysnqn, hostnqn and kato), together with the struct nvmet_req fields
used by nvmet_alloc_ctrl(), that is, the fields port, p2p_client, and
ops as input and the result and error_loc fields as output, as well as a
status field. nvmet_alloc_ctrl() is also changed to return a pointer
to the allocated and initialized controller structure instead of a
status code, as the status is now returned through the status field of
struct nvmet_alloc_ctrl_args.
The function nvmet_setup_p2p_ns_map() is changed to not take a pointer
to a struct nvmet_req as argument, instead, directly specify the
p2p_client device pointer needed as argument.
The code in nvmet_execute_admin_connect() that initializes a new target
controller after allocating it is moved into nvmet_alloc_ctrl().
The code that sets up an admin queue for the controller (and the call
to nvmet_install_queue()) remains in nvmet_execute_admin_connect().
Finally, nvmet_alloc_ctrl() is also exported to allow target drivers to
use this function directly to allocate and initialize a new controller
structure without the need to rely on a fabrics connect command request.
Signed-off-by: Damien Le Moal <dlemoal@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Tested-by: Rick Wertenbroek <rick.wertenbroek@gmail.com>
Tested-by: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
Signed-off-by: Keith Busch <kbusch@kernel.org>
2025-01-04 13:59:40 +09:00
|
|
|
u16 error_loc;
|
|
|
|
u16 status;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct nvmet_ctrl *nvmet_alloc_ctrl(struct nvmet_alloc_ctrl_args *args);
|
2021-03-09 17:16:32 -08:00
|
|
|
struct nvmet_ctrl *nvmet_ctrl_find_get(const char *subsysnqn,
|
|
|
|
const char *hostnqn, u16 cntlid,
|
|
|
|
struct nvmet_req *req);
|
2016-06-21 18:04:20 +02:00
|
|
|
void nvmet_ctrl_put(struct nvmet_ctrl *ctrl);
|
2021-02-24 17:56:40 -08:00
|
|
|
u16 nvmet_check_ctrl_status(struct nvmet_req *req);
|
2024-05-27 07:15:20 +02:00
|
|
|
ssize_t nvmet_ctrl_host_traddr(struct nvmet_ctrl *ctrl,
|
|
|
|
char *traddr, size_t traddr_len);
|
2016-06-21 18:04:20 +02:00
|
|
|
|
|
|
|
struct nvmet_subsys *nvmet_subsys_alloc(const char *subsysnqn,
|
|
|
|
enum nvme_subsys_type type);
|
|
|
|
void nvmet_subsys_put(struct nvmet_subsys *subsys);
|
2016-11-27 22:29:17 +02:00
|
|
|
void nvmet_subsys_del_ctrls(struct nvmet_subsys *subsys);
|
2016-06-21 18:04:20 +02:00
|
|
|
|
2021-02-09 21:47:54 -08:00
|
|
|
u16 nvmet_req_find_ns(struct nvmet_req *req);
|
2016-06-21 18:04:20 +02:00
|
|
|
void nvmet_put_namespace(struct nvmet_ns *ns);
|
|
|
|
int nvmet_ns_enable(struct nvmet_ns *ns);
|
|
|
|
void nvmet_ns_disable(struct nvmet_ns *ns);
|
|
|
|
struct nvmet_ns *nvmet_ns_alloc(struct nvmet_subsys *subsys, u32 nsid);
|
|
|
|
void nvmet_ns_free(struct nvmet_ns *ns);
|
|
|
|
|
2018-06-01 08:59:25 +02:00
|
|
|
void nvmet_send_ana_event(struct nvmet_subsys *subsys,
|
|
|
|
struct nvmet_port *port);
|
|
|
|
void nvmet_port_send_ana_event(struct nvmet_port *port);
|
|
|
|
|
2018-03-20 20:41:35 +01:00
|
|
|
int nvmet_register_transport(const struct nvmet_fabrics_ops *ops);
|
|
|
|
void nvmet_unregister_transport(const struct nvmet_fabrics_ops *ops);
|
2016-06-21 18:04:20 +02:00
|
|
|
|
2019-07-31 17:35:31 -06:00
|
|
|
void nvmet_port_del_ctrls(struct nvmet_port *port,
|
|
|
|
struct nvmet_subsys *subsys);
|
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
int nvmet_enable_port(struct nvmet_port *port);
|
|
|
|
void nvmet_disable_port(struct nvmet_port *port);
|
|
|
|
|
|
|
|
void nvmet_referral_enable(struct nvmet_port *parent, struct nvmet_port *port);
|
2018-11-12 13:56:40 -08:00
|
|
|
void nvmet_referral_disable(struct nvmet_port *parent, struct nvmet_port *port);
|
2016-06-21 18:04:20 +02:00
|
|
|
|
|
|
|
u16 nvmet_copy_to_sgl(struct nvmet_req *req, off_t off, const void *buf,
|
|
|
|
size_t len);
|
|
|
|
u16 nvmet_copy_from_sgl(struct nvmet_req *req, off_t off, void *buf,
|
|
|
|
size_t len);
|
2018-05-22 11:10:02 +02:00
|
|
|
u16 nvmet_zero_sgl(struct nvmet_req *req, off_t off, size_t len);
|
2016-06-21 18:04:20 +02:00
|
|
|
|
|
|
|
u32 nvmet_get_log_page_len(struct nvme_command *cmd);
|
2019-04-09 10:03:59 -06:00
|
|
|
u64 nvmet_get_log_page_offset(struct nvme_command *cmd);
|
2016-06-21 18:04:20 +02:00
|
|
|
|
2018-11-12 13:56:40 -08:00
|
|
|
extern struct list_head *nvmet_ports;
|
|
|
|
void nvmet_port_disc_changed(struct nvmet_port *port,
|
|
|
|
struct nvmet_subsys *subsys);
|
|
|
|
void nvmet_subsys_disc_changed(struct nvmet_subsys *subsys,
|
|
|
|
struct nvmet_host *host);
|
|
|
|
void nvmet_add_async_event(struct nvmet_ctrl *ctrl, u8 event_type,
|
|
|
|
u8 event_info, u8 log_page);
|
|
|
|
|
2024-01-23 16:40:31 +02:00
|
|
|
#define NVMET_MIN_QUEUE_SIZE 16
|
|
|
|
#define NVMET_MAX_QUEUE_SIZE 1024
|
2017-09-11 16:14:50 -07:00
|
|
|
#define NVMET_NR_QUEUES 128
|
2024-01-23 16:40:27 +02:00
|
|
|
#define NVMET_MAX_CMD(ctrl) (NVME_CAP_MQES(ctrl->cap) + 1)
|
2018-05-13 19:00:13 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Nice round number that makes a list of nsids fit into a page.
|
|
|
|
* Should become tunable at some point in the future.
|
|
|
|
*/
|
|
|
|
#define NVMET_MAX_NAMESPACES 1024
|
|
|
|
|
2018-07-19 07:35:20 -07:00
|
|
|
/*
|
|
|
|
* 0 is not a valid ANA group ID, so we start numbering at 1.
|
|
|
|
*
|
|
|
|
* ANA Group 1 exists without manual intervention, has namespaces assigned to it
|
|
|
|
* by default, and is available in an optimized state through all ports.
|
|
|
|
*/
|
2018-06-01 08:59:25 +02:00
|
|
|
#define NVMET_MAX_ANAGRPS 128
|
2018-07-19 07:35:20 -07:00
|
|
|
#define NVMET_DEFAULT_ANA_GRPID 1
|
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
#define NVMET_KAS 10
|
2018-11-12 13:56:35 -08:00
|
|
|
#define NVMET_DISC_KATO_MS 120000
|
2016-06-21 18:04:20 +02:00
|
|
|
|
|
|
|
int __init nvmet_init_configfs(void);
|
|
|
|
void __exit nvmet_exit_configfs(void);
|
|
|
|
|
|
|
|
int __init nvmet_init_discovery(void);
|
|
|
|
void nvmet_exit_discovery(void);
|
|
|
|
|
|
|
|
extern struct nvmet_subsys *nvmet_disc_subsys;
|
|
|
|
extern struct rw_semaphore nvmet_config_sem;
|
|
|
|
|
2018-07-19 07:35:20 -07:00
|
|
|
extern u32 nvmet_ana_group_enabled[NVMET_MAX_ANAGRPS + 1];
|
|
|
|
extern u64 nvmet_ana_chgcnt;
|
|
|
|
extern struct rw_semaphore nvmet_ana_sem;
|
|
|
|
|
2018-11-12 13:56:39 -08:00
|
|
|
bool nvmet_host_allowed(struct nvmet_subsys *subsys, const char *hostnqn);
|
2016-06-21 18:04:20 +02:00
|
|
|
|
2018-05-23 00:34:39 -04:00
|
|
|
int nvmet_bdev_ns_enable(struct nvmet_ns *ns);
|
|
|
|
int nvmet_file_ns_enable(struct nvmet_ns *ns);
|
|
|
|
void nvmet_bdev_ns_disable(struct nvmet_ns *ns);
|
|
|
|
void nvmet_file_ns_disable(struct nvmet_ns *ns);
|
2018-08-07 23:01:07 -07:00
|
|
|
u16 nvmet_bdev_flush(struct nvmet_req *req);
|
|
|
|
u16 nvmet_file_flush(struct nvmet_req *req);
|
|
|
|
void nvmet_ns_changed(struct nvmet_subsys *subsys, u32 nsid);
|
2020-04-19 16:48:50 -07:00
|
|
|
void nvmet_bdev_ns_revalidate(struct nvmet_ns *ns);
|
2022-02-02 01:04:44 -08:00
|
|
|
void nvmet_file_ns_revalidate(struct nvmet_ns *ns);
|
2022-03-15 08:13:04 +01:00
|
|
|
bool nvmet_ns_revalidate(struct nvmet_ns *ns);
|
2021-06-09 18:32:52 -07:00
|
|
|
u16 blk_to_nvme_status(struct nvmet_req *req, blk_status_t blk_sts);
|
|
|
|
|
|
|
|
bool nvmet_bdev_zns_enable(struct nvmet_ns *ns);
|
2023-03-15 19:59:38 +09:00
|
|
|
void nvmet_execute_identify_ctrl_zns(struct nvmet_req *req);
|
2023-03-15 15:14:31 +01:00
|
|
|
void nvmet_execute_identify_ns_zns(struct nvmet_req *req);
|
2021-06-09 18:32:52 -07:00
|
|
|
void nvmet_bdev_execute_zone_mgmt_recv(struct nvmet_req *req);
|
|
|
|
void nvmet_bdev_execute_zone_mgmt_send(struct nvmet_req *req);
|
|
|
|
void nvmet_bdev_execute_zone_append(struct nvmet_req *req);
|
2018-05-23 00:34:39 -04:00
|
|
|
|
2020-05-19 17:05:58 +03:00
|
|
|
static inline u32 nvmet_rw_data_len(struct nvmet_req *req)
|
2018-05-23 00:34:39 -04:00
|
|
|
{
|
|
|
|
return ((u32)le16_to_cpu(req->cmd->rw.length) + 1) <<
|
|
|
|
req->ns->blksize_shift;
|
|
|
|
}
|
2018-12-12 15:11:43 -08:00
|
|
|
|
2020-05-19 17:06:01 +03:00
|
|
|
static inline u32 nvmet_rw_metadata_len(struct nvmet_req *req)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY))
|
|
|
|
return 0;
|
|
|
|
return ((u32)le16_to_cpu(req->cmd->rw.length) + 1) *
|
|
|
|
req->ns->metadata_size;
|
|
|
|
}
|
|
|
|
|
2019-10-23 10:35:43 -06:00
|
|
|
static inline u32 nvmet_dsm_len(struct nvmet_req *req)
|
|
|
|
{
|
|
|
|
return (le32_to_cpu(req->cmd->dsm.nr) + 1) *
|
|
|
|
sizeof(struct nvme_dsm_range);
|
|
|
|
}
|
|
|
|
|
2021-02-09 21:48:01 -08:00
|
|
|
static inline struct nvmet_subsys *nvmet_req_subsys(struct nvmet_req *req)
|
|
|
|
{
|
|
|
|
return req->sq->ctrl->subsys;
|
|
|
|
}
|
|
|
|
|
2021-09-22 08:35:21 +02:00
|
|
|
static inline bool nvmet_is_disc_subsys(struct nvmet_subsys *subsys)
|
|
|
|
{
|
2021-10-18 17:21:36 +02:00
|
|
|
return subsys->type != NVME_NQN_NVME;
|
2021-09-22 08:35:21 +02:00
|
|
|
}
|
|
|
|
|
2025-01-04 13:59:39 +09:00
|
|
|
static inline bool nvmet_is_pci_ctrl(struct nvmet_ctrl *ctrl)
|
|
|
|
{
|
|
|
|
return ctrl->port->disc_addr.trtype == NVMF_TRTYPE_PCI;
|
|
|
|
}
|
|
|
|
|
2020-07-24 11:25:17 -06:00
|
|
|
#ifdef CONFIG_NVME_TARGET_PASSTHRU
|
2020-07-24 11:25:18 -06:00
|
|
|
void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys);
|
|
|
|
int nvmet_passthru_ctrl_enable(struct nvmet_subsys *subsys);
|
|
|
|
void nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys);
|
2020-07-24 11:25:17 -06:00
|
|
|
u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req);
|
|
|
|
u16 nvmet_parse_passthru_io_cmd(struct nvmet_req *req);
|
2021-08-27 08:11:12 +02:00
|
|
|
static inline bool nvmet_is_passthru_subsys(struct nvmet_subsys *subsys)
|
2020-07-24 11:25:17 -06:00
|
|
|
{
|
|
|
|
return subsys->passthru_ctrl;
|
|
|
|
}
|
|
|
|
#else /* CONFIG_NVME_TARGET_PASSTHRU */
|
2020-07-24 11:25:18 -06:00
|
|
|
static inline void nvmet_passthru_subsys_free(struct nvmet_subsys *subsys)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
static inline void nvmet_passthru_ctrl_disable(struct nvmet_subsys *subsys)
|
|
|
|
{
|
|
|
|
}
|
2020-07-24 11:25:17 -06:00
|
|
|
static inline u16 nvmet_parse_passthru_admin_cmd(struct nvmet_req *req)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
static inline u16 nvmet_parse_passthru_io_cmd(struct nvmet_req *req)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2021-08-27 08:11:12 +02:00
|
|
|
static inline bool nvmet_is_passthru_subsys(struct nvmet_subsys *subsys)
|
2020-07-24 11:25:17 -06:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
#endif /* CONFIG_NVME_TARGET_PASSTHRU */
|
|
|
|
|
2021-08-27 08:11:12 +02:00
|
|
|
static inline bool nvmet_is_passthru_req(struct nvmet_req *req)
|
2020-07-24 11:25:17 -06:00
|
|
|
{
|
2021-08-27 08:11:12 +02:00
|
|
|
return nvmet_is_passthru_subsys(nvmet_req_subsys(req));
|
2020-07-24 11:25:17 -06:00
|
|
|
}
|
|
|
|
|
2021-08-26 21:15:45 +00:00
|
|
|
void nvmet_passthrough_override_cap(struct nvmet_ctrl *ctrl);
|
|
|
|
|
2018-12-12 15:11:43 -08:00
|
|
|
u16 errno_to_nvme_status(struct nvmet_req *req, int errno);
|
2021-02-09 21:47:56 -08:00
|
|
|
u16 nvmet_report_invalid_opcode(struct nvmet_req *req);
|
2019-06-28 09:53:30 -07:00
|
|
|
|
2025-01-04 13:59:36 +09:00
|
|
|
static inline bool nvmet_cc_en(u32 cc)
|
|
|
|
{
|
2025-02-13 15:50:00 +09:00
|
|
|
return (cc & NVME_CC_ENABLE) >> NVME_CC_EN_SHIFT;
|
2025-01-04 13:59:36 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8 nvmet_cc_css(u32 cc)
|
|
|
|
{
|
2025-02-13 15:50:00 +09:00
|
|
|
return (cc & NVME_CC_CSS_MASK) >> NVME_CC_CSS_SHIFT;
|
2025-01-04 13:59:36 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8 nvmet_cc_mps(u32 cc)
|
|
|
|
{
|
2025-02-13 15:50:00 +09:00
|
|
|
return (cc & NVME_CC_MPS_MASK) >> NVME_CC_MPS_SHIFT;
|
2025-01-04 13:59:36 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8 nvmet_cc_ams(u32 cc)
|
|
|
|
{
|
2025-02-13 15:50:00 +09:00
|
|
|
return (cc & NVME_CC_AMS_MASK) >> NVME_CC_AMS_SHIFT;
|
2025-01-04 13:59:36 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8 nvmet_cc_shn(u32 cc)
|
|
|
|
{
|
2025-02-13 15:50:00 +09:00
|
|
|
return (cc & NVME_CC_SHN_MASK) >> NVME_CC_SHN_SHIFT;
|
2025-01-04 13:59:36 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8 nvmet_cc_iosqes(u32 cc)
|
|
|
|
{
|
2025-02-13 15:50:00 +09:00
|
|
|
return (cc & NVME_CC_IOSQES_MASK) >> NVME_CC_IOSQES_SHIFT;
|
2025-01-04 13:59:36 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline u8 nvmet_cc_iocqes(u32 cc)
|
|
|
|
{
|
2025-02-13 15:50:00 +09:00
|
|
|
return (cc & NVME_CC_IOCQES_MASK) >> NVME_CC_IOCQES_SHIFT;
|
2025-01-04 13:59:36 +09:00
|
|
|
}
|
|
|
|
|
2019-06-28 09:53:30 -07:00
|
|
|
/* Convert a 32-bit number to a 16-bit 0's based number */
|
|
|
|
static inline __le16 to0based(u32 a)
|
|
|
|
{
|
2025-03-20 15:53:00 +08:00
|
|
|
return cpu_to_le16(clamp(a, 1U, 1U << 16) - 1);
|
2019-06-28 09:53:30 -07:00
|
|
|
}
|
|
|
|
|
2020-05-19 17:06:01 +03:00
|
|
|
static inline bool nvmet_ns_has_pi(struct nvmet_ns *ns)
|
|
|
|
{
|
|
|
|
if (!IS_ENABLED(CONFIG_BLK_DEV_INTEGRITY))
|
|
|
|
return false;
|
|
|
|
return ns->pi_type && ns->metadata_size == sizeof(struct t10_pi_tuple);
|
|
|
|
}
|
|
|
|
|
2021-01-11 20:26:16 -08:00
|
|
|
static inline __le64 nvmet_sect_to_lba(struct nvmet_ns *ns, sector_t sect)
|
|
|
|
{
|
|
|
|
return cpu_to_le64(sect >> (ns->blksize_shift - SECTOR_SHIFT));
|
|
|
|
}
|
|
|
|
|
|
|
|
static inline sector_t nvmet_lba_to_sect(struct nvmet_ns *ns, __le64 lba)
|
|
|
|
{
|
|
|
|
return le64_to_cpu(lba) << (ns->blksize_shift - SECTOR_SHIFT);
|
|
|
|
}
|
|
|
|
|
2021-05-06 18:51:35 -07:00
|
|
|
static inline bool nvmet_use_inline_bvec(struct nvmet_req *req)
|
|
|
|
{
|
|
|
|
return req->transfer_len <= NVMET_MAX_INLINE_DATA_LEN &&
|
|
|
|
req->sg_cnt <= NVMET_MAX_INLINE_BIOVEC;
|
|
|
|
}
|
|
|
|
|
2021-06-09 18:32:50 -07:00
|
|
|
static inline void nvmet_req_bio_put(struct nvmet_req *req, struct bio *bio)
|
|
|
|
{
|
|
|
|
if (bio != &req->b.inline_bio)
|
|
|
|
bio_put(bio);
|
2025-06-25 14:45:33 +03:00
|
|
|
else
|
|
|
|
bio_uninit(bio);
|
2021-06-09 18:32:50 -07:00
|
|
|
}
|
|
|
|
|
2025-02-24 13:38:17 +01:00
|
|
|
#ifdef CONFIG_NVME_TARGET_TCP_TLS
|
|
|
|
static inline key_serial_t nvmet_queue_tls_keyid(struct nvmet_sq *sq)
|
|
|
|
{
|
|
|
|
return sq->tls_key ? key_serial(sq->tls_key) : 0;
|
|
|
|
}
|
|
|
|
static inline void nvmet_sq_put_tls_key(struct nvmet_sq *sq)
|
|
|
|
{
|
|
|
|
if (sq->tls_key) {
|
|
|
|
key_put(sq->tls_key);
|
|
|
|
sq->tls_key = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static inline key_serial_t nvmet_queue_tls_keyid(struct nvmet_sq *sq) { return 0; }
|
|
|
|
static inline void nvmet_sq_put_tls_key(struct nvmet_sq *sq) {}
|
|
|
|
#endif
|
2022-06-27 11:52:05 +02:00
|
|
|
#ifdef CONFIG_NVME_TARGET_AUTH
|
2025-01-04 13:59:41 +09:00
|
|
|
u32 nvmet_auth_send_data_len(struct nvmet_req *req);
|
2022-06-27 11:52:05 +02:00
|
|
|
void nvmet_execute_auth_send(struct nvmet_req *req);
|
2025-01-04 13:59:41 +09:00
|
|
|
u32 nvmet_auth_receive_data_len(struct nvmet_req *req);
|
2022-06-27 11:52:05 +02:00
|
|
|
void nvmet_execute_auth_receive(struct nvmet_req *req);
|
|
|
|
int nvmet_auth_set_key(struct nvmet_host *host, const char *secret,
|
|
|
|
bool set_ctrl);
|
|
|
|
int nvmet_auth_set_host_hash(struct nvmet_host *host, const char *hash);
|
2025-02-24 13:38:16 +01:00
|
|
|
u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq);
|
2022-09-20 15:37:18 +02:00
|
|
|
void nvmet_auth_sq_init(struct nvmet_sq *sq);
|
2022-06-27 11:52:05 +02:00
|
|
|
void nvmet_destroy_auth(struct nvmet_ctrl *ctrl);
|
|
|
|
void nvmet_auth_sq_free(struct nvmet_sq *sq);
|
2022-06-27 11:52:06 +02:00
|
|
|
int nvmet_setup_dhgroup(struct nvmet_ctrl *ctrl, u8 dhgroup_id);
|
2022-06-27 11:52:05 +02:00
|
|
|
bool nvmet_check_auth_status(struct nvmet_req *req);
|
|
|
|
int nvmet_auth_host_hash(struct nvmet_req *req, u8 *response,
|
|
|
|
unsigned int hash_len);
|
|
|
|
int nvmet_auth_ctrl_hash(struct nvmet_req *req, u8 *response,
|
|
|
|
unsigned int hash_len);
|
2025-02-24 13:38:17 +01:00
|
|
|
static inline bool nvmet_has_auth(struct nvmet_ctrl *ctrl, struct nvmet_sq *sq)
|
2022-06-27 11:52:05 +02:00
|
|
|
{
|
2025-02-24 13:38:17 +01:00
|
|
|
return ctrl->host_key != NULL && !nvmet_queue_tls_keyid(sq);
|
2022-06-27 11:52:05 +02:00
|
|
|
}
|
2022-06-27 11:52:06 +02:00
|
|
|
int nvmet_auth_ctrl_exponential(struct nvmet_req *req,
|
|
|
|
u8 *buf, int buf_size);
|
|
|
|
int nvmet_auth_ctrl_sesskey(struct nvmet_req *req,
|
|
|
|
u8 *buf, int buf_size);
|
2025-02-24 13:38:17 +01:00
|
|
|
void nvmet_auth_insert_psk(struct nvmet_sq *sq);
|
2022-06-27 11:52:05 +02:00
|
|
|
#else
|
2025-02-24 13:38:16 +01:00
|
|
|
static inline u8 nvmet_setup_auth(struct nvmet_ctrl *ctrl,
|
|
|
|
struct nvmet_sq *sq)
|
2022-06-27 11:52:05 +02:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
2022-09-20 15:37:18 +02:00
|
|
|
static inline void nvmet_auth_sq_init(struct nvmet_sq *sq)
|
|
|
|
{
|
|
|
|
}
|
2022-06-27 11:52:05 +02:00
|
|
|
static inline void nvmet_destroy_auth(struct nvmet_ctrl *ctrl) {};
|
|
|
|
static inline void nvmet_auth_sq_free(struct nvmet_sq *sq) {};
|
|
|
|
static inline bool nvmet_check_auth_status(struct nvmet_req *req)
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
2025-02-24 13:38:17 +01:00
|
|
|
static inline bool nvmet_has_auth(struct nvmet_ctrl *ctrl,
|
|
|
|
struct nvmet_sq *sq)
|
2022-06-27 11:52:05 +02:00
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
static inline const char *nvmet_dhchap_dhgroup_name(u8 dhgid) { return NULL; }
|
2025-02-24 13:38:17 +01:00
|
|
|
static inline void nvmet_auth_insert_psk(struct nvmet_sq *sq) {};
|
2022-06-27 11:52:05 +02:00
|
|
|
#endif
|
|
|
|
|
2024-11-06 15:34:46 +08:00
|
|
|
int nvmet_pr_init_ns(struct nvmet_ns *ns);
|
|
|
|
u16 nvmet_parse_pr_cmd(struct nvmet_req *req);
|
|
|
|
u16 nvmet_pr_check_cmd_access(struct nvmet_req *req);
|
|
|
|
int nvmet_ctrl_init_pr(struct nvmet_ctrl *ctrl);
|
|
|
|
void nvmet_ctrl_destroy_pr(struct nvmet_ctrl *ctrl);
|
|
|
|
void nvmet_pr_exit_ns(struct nvmet_ns *ns);
|
|
|
|
void nvmet_execute_get_log_page_resv(struct nvmet_req *req);
|
|
|
|
u16 nvmet_set_feat_resv_notif_mask(struct nvmet_req *req, u32 mask);
|
|
|
|
u16 nvmet_get_feat_resv_notif_mask(struct nvmet_req *req);
|
|
|
|
u16 nvmet_pr_get_ns_pc_ref(struct nvmet_req *req);
|
|
|
|
static inline void nvmet_pr_put_ns_pc_ref(struct nvmet_pr_per_ctrl_ref *pc_ref)
|
|
|
|
{
|
|
|
|
percpu_ref_put(&pc_ref->ref);
|
|
|
|
}
|
2025-01-04 13:59:47 +09:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Data for the get_feature() and set_feature() operations of PCI target
|
|
|
|
* controllers.
|
|
|
|
*/
|
|
|
|
struct nvmet_feat_irq_coalesce {
|
|
|
|
u8 thr;
|
|
|
|
u8 time;
|
|
|
|
};
|
|
|
|
|
2025-01-04 13:59:48 +09:00
|
|
|
struct nvmet_feat_irq_config {
|
|
|
|
u16 iv;
|
|
|
|
bool cd;
|
|
|
|
};
|
|
|
|
|
2025-01-04 13:59:49 +09:00
|
|
|
struct nvmet_feat_arbitration {
|
|
|
|
u8 hpw;
|
|
|
|
u8 mpw;
|
|
|
|
u8 lpw;
|
|
|
|
u8 ab;
|
|
|
|
};
|
|
|
|
|
2016-06-21 18:04:20 +02:00
|
|
|
#endif /* _NVMET_H */
|