[GIT PULL 04/37] lightnvm: pblk: check data lines version on recovery

2018-03-29 Thread Matias Bjørling
From: Hans Holmberg 

As a preparation for future bumps of data line persistent storage
versions, we need to start checking the emeta line version during
recovery. Also slit up the current emeta/smeta version into two
bytes (major,minor).

Recovering lines with the same major number as the current pblk data
line version must succeed. This means that any changes in the
persistent format must be:

 (1) Backward compatible: if we switch back to and older
 kernel, recovery of lines stored with major == current_major
 and minor > current_minor must succeed.

 (2) Forward compatible: switching to a newer kernel,
 recovery of lines stored with major=current_major and
 minor < minor must handle the data format differences
 gracefully(i.e. initialize new data structures to default values).

If we detect lines that have a different major number than
the current we must abort recovery. The user must manually
migrate the data in this case.

Previously the version stored in the emeta header was copied
from smeta, which has version 1, so we need to set the minor
version to 1.

Signed-off-by: Hans Holmberg 
Signed-off-by: Javier González 
Signed-off-by: Matias Bjørling 
---
 drivers/lightnvm/pblk-core.c |  9 -
 drivers/lightnvm/pblk-recovery.c | 26 --
 drivers/lightnvm/pblk.h  | 16 ++--
 3 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 9027cf2ed1d8..155e42a26293 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -975,7 +975,8 @@ static int pblk_line_init_metadata(struct pblk *pblk, 
struct pblk_line *line,
memcpy(smeta_buf->header.uuid, pblk->instance_uuid, 16);
smeta_buf->header.id = cpu_to_le32(line->id);
smeta_buf->header.type = cpu_to_le16(line->type);
-   smeta_buf->header.version = SMETA_VERSION;
+   smeta_buf->header.version_major = SMETA_VERSION_MAJOR;
+   smeta_buf->header.version_minor = SMETA_VERSION_MINOR;
 
/* Start metadata */
smeta_buf->seq_nr = cpu_to_le64(line->seq_nr);
@@ -998,6 +999,12 @@ static int pblk_line_init_metadata(struct pblk *pblk, 
struct pblk_line *line,
/* End metadata */
memcpy(_buf->header, _buf->header,
sizeof(struct line_header));
+
+   emeta_buf->header.version_major = EMETA_VERSION_MAJOR;
+   emeta_buf->header.version_minor = EMETA_VERSION_MINOR;
+   emeta_buf->header.crc = cpu_to_le32(
+   pblk_calc_meta_header_crc(pblk, _buf->header));
+
emeta_buf->seq_nr = cpu_to_le64(line->seq_nr);
emeta_buf->nr_lbas = cpu_to_le64(line->sec_in_line);
emeta_buf->nr_valid_lbas = cpu_to_le64(0);
diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c
index 1d5e961bf5e0..a30fe203d454 100644
--- a/drivers/lightnvm/pblk-recovery.c
+++ b/drivers/lightnvm/pblk-recovery.c
@@ -826,6 +826,25 @@ static u64 pblk_line_emeta_start(struct pblk *pblk, struct 
pblk_line *line)
return emeta_start;
 }
 
+static int pblk_recov_check_line_version(struct pblk *pblk,
+struct line_emeta *emeta)
+{
+   struct line_header *header = >header;
+
+   if (header->version_major != EMETA_VERSION_MAJOR) {
+   pr_err("pblk: line major version mismatch: %d, expected: %d\n",
+  header->version_major, EMETA_VERSION_MAJOR);
+   return 1;
+   }
+
+#ifdef NVM_DEBUG
+   if (header->version_minor > EMETA_VERSION_MINOR)
+   pr_info("pblk: newer line minor version found: %d\n", line_v);
+#endif
+
+   return 0;
+}
+
 struct pblk_line *pblk_recov_l2p(struct pblk *pblk)
 {
struct pblk_line_meta *lm = >lm;
@@ -873,9 +892,9 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk)
if (le32_to_cpu(smeta_buf->header.identifier) != PBLK_MAGIC)
continue;
 
-   if (smeta_buf->header.version != SMETA_VERSION) {
+   if (smeta_buf->header.version_major != SMETA_VERSION_MAJOR) {
pr_err("pblk: found incompatible line version %u\n",
-   le16_to_cpu(smeta_buf->header.version));
+   smeta_buf->header.version_major);
return ERR_PTR(-EINVAL);
}
 
@@ -943,6 +962,9 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk)
goto next;
}
 
+   if (pblk_recov_check_line_version(pblk, line->emeta->buf))
+   return ERR_PTR(-EINVAL);
+
if (pblk_recov_l2p_from_emeta(pblk, line))
pblk_recov_l2p_from_oob(pblk, line);
 
diff --git a/drivers/lightnvm/pblk.h 

[GIT PULL 04/37] lightnvm: pblk: check data lines version on recovery

2018-03-29 Thread Matias Bjørling
From: Hans Holmberg 

As a preparation for future bumps of data line persistent storage
versions, we need to start checking the emeta line version during
recovery. Also slit up the current emeta/smeta version into two
bytes (major,minor).

Recovering lines with the same major number as the current pblk data
line version must succeed. This means that any changes in the
persistent format must be:

 (1) Backward compatible: if we switch back to and older
 kernel, recovery of lines stored with major == current_major
 and minor > current_minor must succeed.

 (2) Forward compatible: switching to a newer kernel,
 recovery of lines stored with major=current_major and
 minor < minor must handle the data format differences
 gracefully(i.e. initialize new data structures to default values).

If we detect lines that have a different major number than
the current we must abort recovery. The user must manually
migrate the data in this case.

Previously the version stored in the emeta header was copied
from smeta, which has version 1, so we need to set the minor
version to 1.

Signed-off-by: Hans Holmberg 
Signed-off-by: Javier González 
Signed-off-by: Matias Bjørling 
---
 drivers/lightnvm/pblk-core.c |  9 -
 drivers/lightnvm/pblk-recovery.c | 26 --
 drivers/lightnvm/pblk.h  | 16 ++--
 3 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/drivers/lightnvm/pblk-core.c b/drivers/lightnvm/pblk-core.c
index 9027cf2ed1d8..155e42a26293 100644
--- a/drivers/lightnvm/pblk-core.c
+++ b/drivers/lightnvm/pblk-core.c
@@ -975,7 +975,8 @@ static int pblk_line_init_metadata(struct pblk *pblk, 
struct pblk_line *line,
memcpy(smeta_buf->header.uuid, pblk->instance_uuid, 16);
smeta_buf->header.id = cpu_to_le32(line->id);
smeta_buf->header.type = cpu_to_le16(line->type);
-   smeta_buf->header.version = SMETA_VERSION;
+   smeta_buf->header.version_major = SMETA_VERSION_MAJOR;
+   smeta_buf->header.version_minor = SMETA_VERSION_MINOR;
 
/* Start metadata */
smeta_buf->seq_nr = cpu_to_le64(line->seq_nr);
@@ -998,6 +999,12 @@ static int pblk_line_init_metadata(struct pblk *pblk, 
struct pblk_line *line,
/* End metadata */
memcpy(_buf->header, _buf->header,
sizeof(struct line_header));
+
+   emeta_buf->header.version_major = EMETA_VERSION_MAJOR;
+   emeta_buf->header.version_minor = EMETA_VERSION_MINOR;
+   emeta_buf->header.crc = cpu_to_le32(
+   pblk_calc_meta_header_crc(pblk, _buf->header));
+
emeta_buf->seq_nr = cpu_to_le64(line->seq_nr);
emeta_buf->nr_lbas = cpu_to_le64(line->sec_in_line);
emeta_buf->nr_valid_lbas = cpu_to_le64(0);
diff --git a/drivers/lightnvm/pblk-recovery.c b/drivers/lightnvm/pblk-recovery.c
index 1d5e961bf5e0..a30fe203d454 100644
--- a/drivers/lightnvm/pblk-recovery.c
+++ b/drivers/lightnvm/pblk-recovery.c
@@ -826,6 +826,25 @@ static u64 pblk_line_emeta_start(struct pblk *pblk, struct 
pblk_line *line)
return emeta_start;
 }
 
+static int pblk_recov_check_line_version(struct pblk *pblk,
+struct line_emeta *emeta)
+{
+   struct line_header *header = >header;
+
+   if (header->version_major != EMETA_VERSION_MAJOR) {
+   pr_err("pblk: line major version mismatch: %d, expected: %d\n",
+  header->version_major, EMETA_VERSION_MAJOR);
+   return 1;
+   }
+
+#ifdef NVM_DEBUG
+   if (header->version_minor > EMETA_VERSION_MINOR)
+   pr_info("pblk: newer line minor version found: %d\n", line_v);
+#endif
+
+   return 0;
+}
+
 struct pblk_line *pblk_recov_l2p(struct pblk *pblk)
 {
struct pblk_line_meta *lm = >lm;
@@ -873,9 +892,9 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk)
if (le32_to_cpu(smeta_buf->header.identifier) != PBLK_MAGIC)
continue;
 
-   if (smeta_buf->header.version != SMETA_VERSION) {
+   if (smeta_buf->header.version_major != SMETA_VERSION_MAJOR) {
pr_err("pblk: found incompatible line version %u\n",
-   le16_to_cpu(smeta_buf->header.version));
+   smeta_buf->header.version_major);
return ERR_PTR(-EINVAL);
}
 
@@ -943,6 +962,9 @@ struct pblk_line *pblk_recov_l2p(struct pblk *pblk)
goto next;
}
 
+   if (pblk_recov_check_line_version(pblk, line->emeta->buf))
+   return ERR_PTR(-EINVAL);
+
if (pblk_recov_l2p_from_emeta(pblk, line))
pblk_recov_l2p_from_oob(pblk, line);
 
diff --git a/drivers/lightnvm/pblk.h b/drivers/lightnvm/pblk.h
index 8c357fb6538e..fae2526f80b2 100644
--- a/drivers/lightnvm/pblk.h
+++