]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
seastore : add protected write to NVMeDevice class
authorJinyong Ha <jy200.ha@samsung.com>
Fri, 8 Oct 2021 05:48:55 +0000 (14:48 +0900)
committermyoungwon oh <ohmyoungwon@gmail.com>
Fri, 12 Nov 2021 04:28:21 +0000 (13:28 +0900)
Integrate protected_write()/read() to normal write()/read()
interfaces. Normal write()/read() interfaces utilize protection feature
if the feature is available.

To support data protection, SSD needs to change LBA format from 512
bytes to 520 bytes which contains additional 8 bytes metadata.
Additional metadata can be utilized as user-specific usage or used by
SSD for data protection. It means that all IOs should be aligned with
520 bytes without protection or 512 bytes with protection. Current Linux
and Ceph does not support 520 bytes LBA. So the only method can be
chosen is 512 bytes with protection. It is why explicit
protected_write()/read() interfaces are integrated to normal
write()/read() interfaces.

Signed-off-by: Jinyong Ha <jy200.ha@samsung.com>
src/crimson/os/seastore/random_block_manager/nvmedevice.cc
src/crimson/os/seastore/random_block_manager/nvmedevice.h

index 4402c85c8477b9ef7ac4c8af2b81608c618dbbbb..ac3e81c56ca26c239298a7480b09c88a357519f7 100644 (file)
@@ -29,7 +29,17 @@ open_ertr::future<> PosixNVMeDevice::open(
       return seastar::open_file_dma(in_path, mode).then([=](auto file) {
         this->device = file;
         logger().debug("open");
-        return seastar::now();
+        // Get SSD's features from identify_controller and namespace command.
+        // Do identify_controller first, and then identify_namespace.
+        return identify_controller().safe_then([this](auto id_controller_data) {
+          support_multistream = id_controller_data.oacs.support_directives;
+          return identify_namespace().safe_then([this] (auto id_namespace_data) {
+            block_size = (1 << id_namespace_data.lbaf0.lbads);
+            data_protection_type = id_namespace_data.dps.protection_type;
+            data_protection_enabled = (data_protection_type > 0);
+            return seastar::now();
+          });
+        });
       });
     }).handle_exception([](auto e) -> open_ertr::future<> {
       logger().error("open: got error{}", e);
@@ -49,11 +59,10 @@ write_ertr::future<> PosixNVMeDevice::write(
   auto length = bptr.length();
 
   assert((length % block_size) == 0);
-
   return device.dma_write(offset, bptr.c_str(), length).handle_exception(
     [](auto e) -> write_ertr::future<size_t> {
       logger().error("write: dma_write got error{}", e);
-      return crimson::ct_error::input_output_error::make();
+        return crimson::ct_error::input_output_error::make();
     }).then([length](auto result) -> write_ertr::future<> {
       if (result != length) {
         logger().error("write: dma_write got error with not proper length");
index 81c65d1a152f1ccd3c482d416c1f4b09136e7a39..a16cde8b9a0d54252615399d0c70b42329bc7e96 100644 (file)
@@ -58,7 +58,93 @@ struct nvme_admin_command_t {
   static const uint8_t OPCODE_IDENTIFY = 0x06;
 };
 
-using NVMePassThroughCommand = nvme_passthru_cmd;
+// Optional Admin Command Support (OACS)
+// Indicates optional commands are supported by SSD or not 
+struct oacs_t {
+  uint16_t unused : 5;
+  uint16_t support_directives : 1; // Support multi-stream
+  uint16_t unused2 : 10;
+};
+
+struct nvme_identify_controller_data_t {
+  union {
+    struct {
+      uint8_t unused[256];
+      oacs_t oacs;
+    };
+    uint8_t raw[4096];
+  };
+};
+
+// End-to-end Data Protection Capabilities (DPC)
+// Indicates type of E2E data protection supported by SSD
+struct dpc_t {
+  uint8_t support_type1 : 1;
+  uint8_t support_type2 : 1;
+  uint8_t support_type3 : 1;
+  uint8_t support_first_meta : 1;
+  uint8_t support_last_meta : 1;
+  uint8_t reserved : 3;
+};
+
+// End-to-end Data Protection Type Settings (DPS)
+// Indicates enabled type of E2E data protection
+struct dps_t {
+  uint8_t protection_type : 3;
+  uint8_t protection_info : 1;
+  uint8_t reserved : 4;
+};
+
+// LBA Format (LBAF)
+// Indicates LBA format (metadata size, data size, performance)
+struct lbaf_t {
+  uint32_t ms : 16;
+  uint32_t lbads : 8;
+  uint32_t rp : 2;
+  uint32_t reserved : 6;
+};
+
+struct nvme_identify_namespace_data_t {
+  union {
+    struct {
+      uint8_t unused[28];   // [27:0]
+      dpc_t dpc;            // [28]
+      dps_t dps;            // [29]
+      uint8_t unused2[98];  // [127:30]
+      lbaf_t lbaf0;         // [131:128]
+    };
+    uint8_t raw[4096];
+  };
+};
+
+struct nvme_rw_command_t {
+  uint32_t common_dw[10];
+
+  uint64_t s_lba;
+
+  uint32_t nlb : 16; // 0's based value
+  uint32_t reserved : 4;
+  uint32_t d_type : 4;
+  uint32_t reserved2 : 2;
+  uint32_t prinfo_prchk : 3;
+  uint32_t prinfo_pract : 1;
+  uint32_t fua : 1;
+  uint32_t lr : 1;
+
+  uint32_t reserved3 : 16;
+  uint32_t dspec : 16;
+
+  static const uint32_t DTYPE_STREAM = 1;
+};
+
+struct nvme_io_command_t {
+  union {
+    nvme_passthru_cmd common;
+    nvme_rw_command_t rw;
+  };
+  static const uint8_t OPCODE_WRITE = 0x01;
+  static const uint8_t OPCODE_READ = 0x01;
+};
 
 using read_ertr = crimson::errorator<
   crimson::ct_error::input_output_error,
@@ -107,6 +193,8 @@ protected:
   uint64_t write_granularity = 4096;
   uint64_t write_alignment = 4096;
 
+  bool data_protection_enabled = false;
+
 public:
   NVMeBlockDevice() {}
   virtual ~NVMeBlockDevice() = default;
@@ -174,16 +262,11 @@ public:
    * End-to-End Data Protection
    *
    * NVMe device keeps track of data integrity similar with checksum. Client can
-   * offload checksuming to NVMe device to reduce its CPU utilization
+   * offload checksuming to NVMe device to reduce its CPU utilization. If data
+   * protection is enabled, checksum is calculated on every write and used to
+   * verify data on every read.
    */
-   virtual write_ertr::future<> protected_write(
-    uint64_t offset,
-    bufferptr &bptr,
-    uint16_t stream = 0) { return write_ertr::now(); }
-
-   virtual read_ertr::future<> protected_read(
-    uint64_t offset,
-    bufferptr &bptr) { return read_ertr::now(); }
+   bool is_data_protection_enabled() const { return data_protection_enabled; }
 
   /*
    * Data Health
@@ -243,10 +326,14 @@ public:
 
   seastar::future<> close() override;
 
-  // TODO Servicing NVMe features (multi-stream, protected write etc..) should
-  // be followed by upstreaming ioctl to seastar.
-
 private:
+  // identify_controller/namespace are used to get SSD internal information such
+  // as supported features
+  uint8_t data_protection_type = 0;
+
+  nvme_command_ertr::future<nvme_identify_controller_data_t> identify_controller();
+  nvme_command_ertr::future<nvme_identify_namespace_data_t> identify_namespace();
+  nvme_command_ertr::future<int> get_nsid();
   seastar::file device;
 };