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

nvme: Add pr_ops read_reservation support

This patch adds support for the pr_ops read_reservation callout by
calling the NVMe Reservation Report helper. It then parses that info to
detect if there is a reservation and if there is then convert the
returned info to a pr_ops pr_held_reservation struct.

Signed-off-by: Mike Christie <michael.christie@oracle.com>
Link: https://lore.kernel.org/r/20230407200551.12660-14-michael.christie@oracle.com
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
Reviewed-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>

authored by

Mike Christie and committed by
Martin K. Petersen
28c97ba3 be1a7cd2

+83
+83
drivers/nvme/host/pr.c
··· 29 29 return 0; 30 30 } 31 31 32 + static enum pr_type block_pr_type_from_nvme(enum nvme_pr_type type) 33 + { 34 + switch (type) { 35 + case NVME_PR_WRITE_EXCLUSIVE: 36 + return PR_WRITE_EXCLUSIVE; 37 + case NVME_PR_EXCLUSIVE_ACCESS: 38 + return PR_EXCLUSIVE_ACCESS; 39 + case NVME_PR_WRITE_EXCLUSIVE_REG_ONLY: 40 + return PR_WRITE_EXCLUSIVE_REG_ONLY; 41 + case NVME_PR_EXCLUSIVE_ACCESS_REG_ONLY: 42 + return PR_EXCLUSIVE_ACCESS_REG_ONLY; 43 + case NVME_PR_WRITE_EXCLUSIVE_ALL_REGS: 44 + return PR_WRITE_EXCLUSIVE_ALL_REGS; 45 + case NVME_PR_EXCLUSIVE_ACCESS_ALL_REGS: 46 + return PR_EXCLUSIVE_ACCESS_ALL_REGS; 47 + } 48 + 49 + return 0; 50 + } 51 + 32 52 static int nvme_send_ns_head_pr_command(struct block_device *bdev, 33 53 struct nvme_command *c, void *data, unsigned int data_len) 34 54 { ··· 242 222 return ret; 243 223 } 244 224 225 + static int nvme_pr_read_reservation(struct block_device *bdev, 226 + struct pr_held_reservation *resv) 227 + { 228 + struct nvme_reservation_status_ext tmp_rse, *rse; 229 + int ret, i, num_regs; 230 + u32 rse_len; 231 + bool eds; 232 + 233 + get_num_regs: 234 + /* 235 + * Get the number of registrations so we know how big to allocate 236 + * the response buffer. 237 + */ 238 + ret = nvme_pr_resv_report(bdev, &tmp_rse, sizeof(tmp_rse), &eds); 239 + if (ret) 240 + return ret; 241 + 242 + num_regs = get_unaligned_le16(&tmp_rse.regctl); 243 + if (!num_regs) { 244 + resv->generation = le32_to_cpu(tmp_rse.gen); 245 + return 0; 246 + } 247 + 248 + rse_len = struct_size(rse, regctl_eds, num_regs); 249 + rse = kzalloc(rse_len, GFP_KERNEL); 250 + if (!rse) 251 + return -ENOMEM; 252 + 253 + ret = nvme_pr_resv_report(bdev, rse, rse_len, &eds); 254 + if (ret) 255 + goto free_rse; 256 + 257 + if (num_regs != get_unaligned_le16(&rse->regctl)) { 258 + kfree(rse); 259 + goto get_num_regs; 260 + } 261 + 262 + resv->generation = le32_to_cpu(rse->gen); 263 + resv->type = block_pr_type_from_nvme(rse->rtype); 264 + 265 + for (i = 0; i < num_regs; i++) { 266 + if (eds) { 267 + if (rse->regctl_eds[i].rcsts) { 268 + resv->key = le64_to_cpu(rse->regctl_eds[i].rkey); 269 + break; 270 + } 271 + } else { 272 + struct nvme_reservation_status *rs; 273 + 274 + rs = (struct nvme_reservation_status *)rse; 275 + if (rs->regctl_ds[i].rcsts) { 276 + resv->key = le64_to_cpu(rs->regctl_ds[i].rkey); 277 + break; 278 + } 279 + } 280 + } 281 + 282 + free_rse: 283 + kfree(rse); 284 + return ret; 285 + } 286 + 245 287 const struct pr_ops nvme_pr_ops = { 246 288 .pr_register = nvme_pr_register, 247 289 .pr_reserve = nvme_pr_reserve, ··· 311 229 .pr_preempt = nvme_pr_preempt, 312 230 .pr_clear = nvme_pr_clear, 313 231 .pr_read_keys = nvme_pr_read_keys, 232 + .pr_read_reservation = nvme_pr_read_reservation, 314 233 };