veeam / veeamsnap

Veeam Agent for Linux kernel module

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Linux 5.6: failed to compile

k0ste opened this issue · comments

Making all...
ccflags-y= -O2 -Wno-multichar -DDISTRIB_NAME_ARCH -DDISTRIB_VERSION_1=1
make -C /lib/modules/5.6.2-arch1-2/build M=/tmp/veeamsnap/source modules
make[1]: Entering directory '/usr/lib/modules/5.6.2-arch1-2/build'
  CC [M]  /tmp/veeamsnap/source/log.o
In file included from /tmp/veeamsnap/source/stdafx.h:39,
                 from /tmp/veeamsnap/source/log.c:1:
/tmp/veeamsnap/source/log.h:25:80: error: unknown type name ‘time_t’
   25 | void log_s_sec(const char* section, const unsigned level, const char* s, const time_t totalsecs);
      |                                                                                ^~~~~~
/tmp/veeamsnap/source/log.c:43:21: error: field ‘m_time’ has incomplete type
   43 |     struct timespec m_time;
      |                     ^~~~~~
/tmp/veeamsnap/source/log.c:68:21: error: field ‘m_modify_time’ has incomplete type
   68 |     struct timespec m_modify_time;
      |                     ^~~~~~~~~~~~~
/tmp/veeamsnap/source/log.c: In function ‘_logging_filename_create’:
/tmp/veeamsnap/source/log.c:187:9: error: implicit declaration of function ‘getnstimeofday’ [-Werror=implicit-function-declaration]
  187 |         getnstimeofday(&logging->m_modify_time);
      |         ^~~~~~~~~~~~~~
/tmp/veeamsnap/source/log.c: In function ‘_logging_check_renew’:
/tmp/veeamsnap/source/log.c:224:21: error: storage size of ‘_time’ isn’t known
  224 |     struct timespec _time;
      |                     ^~~~~
/tmp/veeamsnap/source/log.c:224:21: warning: unused variable ‘_time’ [-Wunused-variable]
/tmp/veeamsnap/source/log.c: In function ‘logging_init’:
/tmp/veeamsnap/source/log.c:454:49: error: invalid application of ‘sizeof’ to incomplete type ‘struct timespec’
  454 |     memset( &logging->m_modify_time, 0, sizeof( struct timespec ) );
      |                                                 ^~~~~~
/tmp/veeamsnap/source/log.c: At top level:
/tmp/veeamsnap/source/log.c:692:80: error: unknown type name ‘time_t’
  692 | void log_s_sec(const char* section, const unsigned level, const char* s, const time_t totalsecs)
      |                                                                                ^~~~~~
cc1: some warnings being treated as errors
make[2]: *** [scripts/Makefile.build:268: /tmp/veeamsnap/source/log.o] Error 1
make[1]: *** [Makefile:1683: /tmp/veeamsnap/source] Error 2
make[1]: Leaving directory '/usr/lib/modules/5.6.2-arch1-2/build'
make: *** [Makefile:77: all] Error 2

I think it's due to kernel 5.6 resolved time bug.
I got it to compile by basically changing time_t to uint64_t, timespec to timespec64 and getnstimeofday to ktime_get_ts64 in log.h, log.c, cbt_storage.h and cbt_storage.c:

--- Downloads/veeamsnap-master/source/log.h	2020-02-18 12:26:51.000000000 +0100
+++ /usr/src/veeamsnap-4.0.0.1961/log.h	2020-04-08 10:53:55.915475583 +0200
@@ -24,3 +24,3 @@
 void log_format( const char* section, const int level, const char* frm, ... );
-void log_s_sec(const char* section, const unsigned level, const char* s, const time_t totalsecs);
+void log_s_sec(const char* section, const unsigned level, const char* s, const uint64_t totalsecs);
 ///////////////////////////////////////////////////////////////////////////////


--- Downloads/veeamsnap-master/source/log.c	2020-02-18 12:26:51.000000000 +0100
+++ /usr/src/veeamsnap-4.0.0.1961/log.c	2020-04-08 11:09:09.264306329 +0200
@@ -42,3 +42,3 @@
 
-    struct timespec m_time;
+    struct timespec64 m_time;
     pid_t m_pid;
@@ -67,3 +67,3 @@
     char m_filepath[MAX_FILENAME_SIZE];
-    struct timespec m_modify_time;
+    struct timespec64 m_modify_time;
 
@@ -186,3 +186,3 @@
         struct tm modify_time;
-        getnstimeofday(&logging->m_modify_time);
+        ktime_get_ts64(&logging->m_modify_time);
 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)
@@ -223,3 +223,3 @@
     loff_t sz = 0;
-    struct timespec _time;
+    struct timespec64 _time;
     struct tm current_time;
@@ -232,3 +232,3 @@
 
-    getnstimeofday( &_time );
+    ktime_get_ts64( &_time );
 #if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)
@@ -453,3 +453,3 @@
     logging->m_filp = NULL;
-    memset( &logging->m_modify_time, 0, sizeof( struct timespec ) );
+    memset( &logging->m_modify_time, 0, sizeof( struct timespec64 ) );
     logging->m_state = LOGGING_STATE_READY;
@@ -509,3 +509,3 @@
     rq->m_pid = get_current( )->pid;
-    getnstimeofday( &rq->m_time );
+    ktime_get_ts64( &rq->m_time );
     
@@ -691,3 +691,3 @@
 
-void log_s_sec(const char* section, const unsigned level, const char* s, const time_t totalsecs)
+void log_s_sec(const char* section, const unsigned level, const char* s, const uint64_t totalsecs)
 {


--- Downloads/veeamsnap-master/source/cbt_storage.h	2020-02-18 12:26:51.000000000 +0100
+++ /usr/src/veeamsnap-4.0.0.1961/cbt_storage.h	2020-04-08 11:10:45.846700785 +0200
@@ -1,49 +1,49 @@
-#pragma once
-#ifdef PERSISTENT_CBT
-
-#define CBT_STORAGE_MAGIC "vcbtdata"
-
-typedef struct cbt_storage_page_s
-{
-    char magic[8];
-    uint32_t crc;
-    uint32_t number;
-    uint64_t tv_sec;    // seconds
-    uint32_t tv_nsec;    // nanoseconds
-    uint32_t padding0;
-    unsigned char data[0];
-} cbt_storage_page_t;
-
-#define CBT_PAGE_DATA_SIZE (PAGE_SIZE - offsetof(cbt_storage_page_t, data))
-
-typedef struct cbt_storage_accessor_s
-{
-    struct block_device* device;
-    rangevector_t* rangevector;
-
-    struct timespec time;//cbt data time marker
-
-    struct page* pg;
-    cbt_storage_page_t* page;
-
-    unsigned long long page_count;
-    unsigned long long page_number;
-    unsigned long long used_page_count;
-    size_t page_offset;
-
-}cbt_storage_accessor_t;
-
-
-int cbt_storage_open(cbt_persistent_parameters_t* params, cbt_storage_accessor_t* accessor);
-void cbt_storage_close(cbt_storage_accessor_t* accessor);
-
-int cbt_storage_check(cbt_storage_accessor_t* accessor);
-
-int cbt_storage_prepare4read(cbt_storage_accessor_t* accessor);
-int cbt_storage_prepare4write(cbt_storage_accessor_t* accessor);
-
-int cbt_storage_read(cbt_storage_accessor_t* accessor, void* dst, size_t sz);
-int cbt_storage_write(cbt_storage_accessor_t* accessor, void* src, size_t sz);
-int cbt_storage_write_finish(cbt_storage_accessor_t* accessor);
-
-#endif//PERSISTENT_CBT
+#pragma once
+#ifdef PERSISTENT_CBT
+
+#define CBT_STORAGE_MAGIC "vcbtdata"
+
+typedef struct cbt_storage_page_s
+{
+    char magic[8];
+    uint32_t crc;
+    uint32_t number;
+    uint64_t tv_sec;    // seconds
+    uint32_t tv_nsec;    // nanoseconds
+    uint32_t padding0;
+    unsigned char data[0];
+} cbt_storage_page_t;
+
+#define CBT_PAGE_DATA_SIZE (PAGE_SIZE - offsetof(cbt_storage_page_t, data))
+
+typedef struct cbt_storage_accessor_s
+{
+    struct block_device* device;
+    rangevector_t* rangevector;
+
+    struct timespec64 time;//cbt data time marker
+
+    struct page* pg;
+    cbt_storage_page_t* page;
+
+    unsigned long long page_count;
+    unsigned long long page_number;
+    unsigned long long used_page_count;
+    size_t page_offset;
+
+}cbt_storage_accessor_t;
+
+
+int cbt_storage_open(cbt_persistent_parameters_t* params, cbt_storage_accessor_t* accessor);
+void cbt_storage_close(cbt_storage_accessor_t* accessor);
+
+int cbt_storage_check(cbt_storage_accessor_t* accessor);
+
+int cbt_storage_prepare4read(cbt_storage_accessor_t* accessor);
+int cbt_storage_prepare4write(cbt_storage_accessor_t* accessor);
+
+int cbt_storage_read(cbt_storage_accessor_t* accessor, void* dst, size_t sz);
+int cbt_storage_write(cbt_storage_accessor_t* accessor, void* src, size_t sz);
+int cbt_storage_write_finish(cbt_storage_accessor_t* accessor);
+
+#endif//PERSISTENT_CBT


--- Downloads/veeamsnap-master/source/cbt_storage.c	2020-02-18 12:26:51.000000000 +0100
+++ /usr/src/veeamsnap-4.0.0.1961/cbt_storage.c	2020-04-08 11:17:04.156543224 +0200
@@ -1,460 +1,460 @@
-#include "stdafx.h"
-#ifdef PERSISTENT_CBT
-
-#include "rangevector.h"
-#include "cbt_params.h"
-#include "cbt_storage.h"
-#include "sector.h"
-#include "blk_direct.h"
-#include <linux/crc32.h>
-
-#define SECTION "cbt_store "
-#include "log_format.h"
-
-
-static int _cbt_storage_read_page(cbt_storage_accessor_t* accessor)
-{
-    int res;
-    sector_t phys_offset = 0;
-    sector_t phys_length = 0;
-    uint32_t crc;
-
-    res = rangevector_v2p(accessor->rangevector, accessor->page_number * sector_from_uint(PAGE_SIZE), sector_from_uint(PAGE_SIZE), &phys_offset, &phys_length);
-    if (res != SUCCESS){
-        log_err("Failed to get real disk offset for persistent CBT data");
-        return res;
-    }
-
-    if (phys_length != sector_from_uint(PAGE_SIZE)){
-        log_err_sect("Unordered range size: ", phys_length);
-        log_err("Range is not ordered by PAGE_SIZE");
-        return -EINVAL;
-    }
-
-    res = blk_direct_submit_page(accessor->device, READ_SYNC, phys_offset, accessor->pg);
-    if (res != SUCCESS){
-        log_err("Failed to read device");
-        log_err_sect("Real device offset: ", phys_offset);
-        return res;
-    }
-
-    //check magic
-    if (0 != memcmp(accessor->page->magic, CBT_STORAGE_MAGIC, 8)){
-        log_err("Invalid CBT data header. Magic mismatch.");
-        log_err_sect("device offset=", phys_offset);
-        log_err_sect("avaliable sectors=", phys_length);
-        log_err("Page header:");
-        log_err_bytes((unsigned char*)accessor->page, sizeof(cbt_storage_page_t));
-        return -EINVAL;
-    }
-
-    //chech CRC32
-    crc = crc32(~0, (void*)(accessor->page) + offsetof(cbt_storage_page_t, number), PAGE_SIZE - offsetof(cbt_storage_page_t, number));
-    if (crc != accessor->page->crc){
-        log_err_lld("Invalid CRC32 on page #", accessor->page_number);
-        log_err_sect("Physical offset on block device: ", phys_offset);
-        log_err_lx("Expected crc=", crc);
-        log_err_lx("Read crc=", accessor->page->crc);
-        return -EINVAL;
-    }
-
-    if (accessor->page_number != accessor->page->number){
-        log_err("Invalid cbt data page number");
-        log_err_lld("Expected=", accessor->page_number);
-        log_err_lld("Read=", accessor->page->number);
-        return -EINVAL;
-    }
-
-    return SUCCESS;
-}
-
-static int _cbt_storage_write_page(cbt_storage_accessor_t* accessor, struct timespec* optional_time)
-{
-    int res;
-    sector_t phys_offset = 0;
-    sector_t phys_length = 0;
-
-    log_tr_d("DEBUG! write page# ", accessor->page_number);
-
-    //set magic
-    memcpy(accessor->page->magic, CBT_STORAGE_MAGIC, 8);
-    //set number
-    accessor->page->number = accessor->page_number;
-    //set time marker
-    if (optional_time){
-        accessor->page->tv_sec = optional_time->tv_sec;
-        accessor->page->tv_nsec = optional_time->tv_nsec;
-    }
-    else{
-        accessor->page->tv_sec = accessor->time.tv_sec;
-        accessor->page->tv_nsec = accessor->time.tv_nsec;
-    }
-    //calculate CRC32
-    accessor->page->crc = crc32(~0, (void*)(accessor->page) + offsetof(cbt_storage_page_t, number), PAGE_SIZE - offsetof(cbt_storage_page_t, number));
-
-    res = rangevector_v2p(accessor->rangevector, accessor->page_number * sector_from_uint(PAGE_SIZE), sector_from_uint(PAGE_SIZE), &phys_offset, &phys_length);
-    if (res != SUCCESS){
-        log_err("Failed to get real disk offset for persistent CBT data");
-        return res;
-    }
-
-    if (phys_length != sector_from_uint(PAGE_SIZE)){
-        log_err_sect("Unordered range size: ", phys_length);
-        log_err("Range is not ordered by PAGE_SIZE");
-        return -EINVAL;
-    }
-
-    //write page
-    log_tr_sect("DEBUG! offset= ", phys_offset);
-    res = blk_direct_submit_page(accessor->device, WRITE_SYNC, phys_offset, accessor->pg);
-    if (res != SUCCESS){
-        log_err("Failed to read device");
-        log_err_sect("Real device offset: ", phys_offset);
-        return res;
-    }
-
-    return SUCCESS;
-}
-
-int cbt_storage_open(cbt_persistent_parameters_t* params, cbt_storage_accessor_t* accessor)
-{
-    int res = SUCCESS;
-    log_tr_dev_t("Open persistent CBT storage device ",params->dev_id);
-
-    res = blk_dev_open(params->dev_id, &accessor->device);
-    if (res != SUCCESS){
-        log_err_dev_t("Failed to open device ", params->dev_id);
-        return res;
-    }
-    do{
-        if (0 == rangevector_cnt(&params->rangevector)){
-            log_err("No range for reading");
-            res = -EINVAL;
-            break;
-        }
-
-        //allocate page
-        if (NULL == (accessor->pg = alloc_page(GFP_KERNEL))){
-            log_err("Failed to allocate page");
-            res = -ENOMEM;
-            break;
-        }
-        accessor->page = (cbt_storage_page_t*)page_address(accessor->pg);
-
-        accessor->rangevector = &params->rangevector;
-        accessor->page_count = rangevector_length(accessor->rangevector) / sector_from_uint(PAGE_SIZE);
-        accessor->page_number = 0;
-        accessor->used_page_count = accessor->page_count;
-        accessor->page_offset = offsetof(cbt_storage_page_t, data);
-
-    } while (false);
-    if (res != SUCCESS)
-        cbt_storage_close(accessor);
-    return res;
-}
-
-void cbt_storage_close(cbt_storage_accessor_t* accessor)
-{
-    if (accessor->pg != NULL){
-        __free_page(accessor->pg);
-        accessor->pg = NULL;
-        accessor->page = NULL;
-    }
-    if (accessor->device != NULL){
-        log_tr("Close persistent CBT storage device ");
-
-        blk_dev_close(accessor->device);
-        accessor->device = NULL;
-    }
-    accessor->rangevector = NULL;
-}
-
-int cbt_storage_check(cbt_storage_accessor_t* accessor)
-{
-    int res = SUCCESS;
-    //check all pages
-
-    //log_tr("[TBD] Checking CRC32 for all pages:");
-    accessor->page_number = 0;
-    accessor->used_page_count = accessor->page_count;
-    res = _cbt_storage_read_page(accessor);
-    if (res != SUCCESS){
-        log_err("Failed to get first page ");
-        return res;
-    }
-    //get time from first page
-    accessor->time.tv_sec = accessor->page->tv_sec;
-    accessor->time.tv_nsec = accessor->page->tv_nsec;
-
-    if (accessor->time.tv_sec == 0ull){
-        log_tr("Persistent CBT data is empty");
-        accessor->used_page_count = 0;
-    }
-
-    for (accessor->page_number = 1; accessor->page_number < accessor->page_count; ++accessor->page_number){
-        res = _cbt_storage_read_page(accessor);
-        if (res != SUCCESS){
-            log_err_lld("Failed to get page #", accessor->page_number);
-            break;
-        }
-        if (accessor->time.tv_sec != 0ull){
-            if (accessor->page->tv_sec == 0ull){
-                //unused page found
-                if (accessor->used_page_count == accessor->page_count){
-                    accessor->used_page_count = accessor->page_number;
-                    log_tr_lld("Found first unused page #", accessor->page_number);
-                }
-            }
-            else{
-                if ((accessor->time.tv_sec != accessor->page->tv_sec) && (accessor->time.tv_nsec != accessor->page->tv_nsec))
-                {
-                    log_err_lld("Invalid time marker on page #", accessor->page_number);
-                    log_err_llx("Expected=", accessor->time.tv_sec);
-                    log_err_llx("Read=", accessor->page->tv_sec);
-
-                    //cbt data skipped
-                    accessor->time.tv_sec = 0ull;
-                    accessor->time.tv_nsec = 0ul;
-
-                    break;
-                }
-            }
-        }
-    }
-
-    if (res != SUCCESS){
-        log_err("Check failed");
-        return res;
-    }
-
-    if (accessor->time.tv_sec != 0ull){
-        //show time
-        struct tm modify_time;
-#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)
-        time_to_tm(accessor->time.tv_sec, 0, &modify_time);
-#else
-        time64_to_tm(accessor->time.tv_sec, 0, &modify_time);
-#endif
-        log_tr_format("Persistent CBT data from %04ld.%02d.%02d %02ld:%02d:%02d %d",
-            modify_time.tm_year + 1900,
-            modify_time.tm_mon + 1,
-            modify_time.tm_mday,
-            modify_time.tm_hour,
-            modify_time.tm_min,
-            modify_time.tm_sec,
-            accessor->time.tv_nsec);
-    }
-
-    return res;
-}
-
-
-int cbt_storage_prepare4read(cbt_storage_accessor_t* accessor)
-{
-    int res = SUCCESS;
-
-    //set position to first page
-    accessor->page_number = 0;
-    accessor->page_offset = 0;
-
-    res = _cbt_storage_read_page(accessor);
-    if (res != SUCCESS){
-        log_err("Failed to get first page ");
-        return res;
-    }
-    //check time from fisrt page
-    accessor->time.tv_sec = accessor->page->tv_sec;
-    accessor->time.tv_nsec = accessor->page->tv_nsec;
-
-    if (accessor->time.tv_sec == 0ull)
-        return ENODATA;
-
-    //set CBT data empty
-    {
-        struct timespec tm = {0}; //
-        res = _cbt_storage_write_page(accessor, &tm);
-        if (res != SUCCESS){
-            log_err("Failed to write first page ");
-            return res;
-        }
-    }
-
-    return res;
-}
-
-int cbt_storage_prepare4write(cbt_storage_accessor_t* accessor)
-{
-    int res = SUCCESS;
-    //set position to first page
-    accessor->page_number = 0;
-    accessor->page_offset = 0;
-
-    res = _cbt_storage_read_page(accessor);
-    if (res != SUCCESS){
-        log_err("Failed to get first page ");
-        return res;
-    }
-    //get time
-    getnstimeofday(&accessor->time);
-
-    return res;
-}
-
-int cbt_storage_read(cbt_storage_accessor_t* accessor, void* dst, size_t sz)
-{
-    int res = SUCCESS;
-    size_t ofs = 0;
-    size_t can_be_read;
-    if (accessor->page_number == accessor->page_count){
-        log_err_lld("EOF reached, page number ", accessor->page_number);
-        return -ENODATA;
-    }
-
-    can_be_read = min(CBT_PAGE_DATA_SIZE - accessor->page_offset, sz - ofs);
-    memcpy(dst, accessor->page->data + accessor->page_offset, can_be_read);
-    accessor->page_offset += can_be_read;
-    ofs += can_be_read;
-
-    do{
-        if (accessor->page_offset == CBT_PAGE_DATA_SIZE) {
-            accessor->page_number++;
-            accessor->page_offset = 0;
-        }
-
-        if (accessor->page_number == accessor->page_count){
-            if (ofs < sz){
-                log_err_lld("EOF reached, page number= ", accessor->page_number);
-                res = -ENODATA;
-            }
-            else{
-                log_tr("Reached EOF");
-                res = SUCCESS;
-            }
-            break;
-        }
-
-        //read next page
-        res = _cbt_storage_read_page(accessor);
-        if (res != SUCCESS){
-            log_err_lld("Failed to get page #", accessor->page_number);
-            return res;
-        }
-
-        if (ofs == sz)
-            break;//reading is complete 
-
-        can_be_read = min(CBT_PAGE_DATA_SIZE - accessor->page_offset, sz - ofs);
-        memcpy(dst, accessor->page->data + accessor->page_offset, can_be_read);
-        accessor->page_offset += can_be_read;
-        ofs += can_be_read;
-
-    } while (true);
-    return res;
-}
-
-int cbt_storage_write(cbt_storage_accessor_t* accessor, void* src, size_t sz)
-{
-    int res = SUCCESS;
-    size_t ofs = 0;
-    size_t can_be_write;
-
-    if (accessor->page_number == accessor->page_count){
-        log_err_lld("Reached EOF, page number= ", accessor->page_number);
-        return -ENODATA;
-    }
-
-    can_be_write = min(CBT_PAGE_DATA_SIZE - accessor->page_offset, sz - ofs);
-    log_tr_sz("DEBUG! can_be_write=", can_be_write);
-    if (can_be_write == 0){
-        log_tr_format("can_be_write is zero. sz=%lu, ofs=%lu page_offset=%lu", (unsigned long)(sz), (unsigned long)(ofs), (unsigned long)(accessor->page_offset));
-        return -EFAULT;
-    }
-    
-    memcpy(accessor->page->data + accessor->page_offset, src + ofs, can_be_write);
-    accessor->page_offset += can_be_write;
-    ofs += can_be_write;
-
-    do{
-        if (accessor->page_offset == CBT_PAGE_DATA_SIZE){
-            //write current page
-            res = _cbt_storage_write_page(accessor, NULL);
-            if (res != SUCCESS){
-                log_err_lld("Failed to get page #", accessor->page_number);
-                return res;
-            }
-
-            accessor->page_number++;
-            accessor->page_offset = 0;
-        }
-
-        if (accessor->page_number == accessor->page_count){
-            if (ofs < sz){
-                log_err_lld("Reached EOF, page number= ", accessor->page_number);
-                res = -ENODATA;
-            }
-            else{
-                log_tr("Reached EOF");
-                res = SUCCESS;
-            }
-            break;
-        }
-
-        if (ofs == sz)
-            break;//writing is complete 
-
-        can_be_write = min(CBT_PAGE_DATA_SIZE - accessor->page_offset, sz - ofs);
-        log_tr_sz("DEBUG! can_be_write=", can_be_write);
-        if (can_be_write == 0){
-            log_tr_format("can_be_write is zero. sz=%lu, ofs=%lu page_offset=%lu", (unsigned long)sz, (unsigned long)ofs, (unsigned long)accessor->page_offset);
-            return -EFAULT;
-        }
-        memcpy(accessor->page->data + accessor->page_offset, src + ofs, can_be_write);
-        accessor->page_offset += can_be_write;
-        ofs += can_be_write;
-
-    } while (true);
-
-    return res;
-}
-
-int cbt_storage_write_finish(cbt_storage_accessor_t* accessor)
-{
-    int res = SUCCESS;
-
-    if (accessor->page_number == accessor->page_count)
-        return SUCCESS;
-
-    //write last page
-    log_tr_lld("DEBUG! write last page #", accessor->page_number);
-
-    res = _cbt_storage_write_page(accessor, NULL);
-    if (res != SUCCESS){
-        log_err_lld("Failed to get page #", accessor->page_number);
-        return res;
-    }
-
-    accessor->page_number++;
-    accessor->page_offset = 0;
-
-    {//store empty unused pages
-        struct timespec tm = {0}; 
-        memset(accessor->page->data, 0, CBT_PAGE_DATA_SIZE);
-
-        while (accessor->page_number < accessor->page_count){
-
-            accessor->page->number = accessor->page_number;
-
-            //log_tr_lld("DEBUG! write empty page #", accessor->page_number);
-            res = _cbt_storage_write_page(accessor, &tm);
-            if (res != SUCCESS){
-                log_err_lld("Failed to get page #", accessor->page_number);
-                break;
-            }
-            accessor->page_number++;
-        }
-    }
-    return res;
-}
-
-
-#endif//PERSISTENT_CBT
+#include "stdafx.h"
+#ifdef PERSISTENT_CBT
+
+#include "rangevector.h"
+#include "cbt_params.h"
+#include "cbt_storage.h"
+#include "sector.h"
+#include "blk_direct.h"
+#include <linux/crc32.h>
+
+#define SECTION "cbt_store "
+#include "log_format.h"
+
+
+static int _cbt_storage_read_page(cbt_storage_accessor_t* accessor)
+{
+    int res;
+    sector_t phys_offset = 0;
+    sector_t phys_length = 0;
+    uint32_t crc;
+
+    res = rangevector_v2p(accessor->rangevector, accessor->page_number * sector_from_uint(PAGE_SIZE), sector_from_uint(PAGE_SIZE), &phys_offset, &phys_length);
+    if (res != SUCCESS){
+        log_err("Failed to get real disk offset for persistent CBT data");
+        return res;
+    }
+
+    if (phys_length != sector_from_uint(PAGE_SIZE)){
+        log_err_sect("Unordered range size: ", phys_length);
+        log_err("Range is not ordered by PAGE_SIZE");
+        return -EINVAL;
+    }
+
+    res = blk_direct_submit_page(accessor->device, READ_SYNC, phys_offset, accessor->pg);
+    if (res != SUCCESS){
+        log_err("Failed to read device");
+        log_err_sect("Real device offset: ", phys_offset);
+        return res;
+    }
+
+    //check magic
+    if (0 != memcmp(accessor->page->magic, CBT_STORAGE_MAGIC, 8)){
+        log_err("Invalid CBT data header. Magic mismatch.");
+        log_err_sect("device offset=", phys_offset);
+        log_err_sect("avaliable sectors=", phys_length);
+        log_err("Page header:");
+        log_err_bytes((unsigned char*)accessor->page, sizeof(cbt_storage_page_t));
+        return -EINVAL;
+    }
+
+    //chech CRC32
+    crc = crc32(~0, (void*)(accessor->page) + offsetof(cbt_storage_page_t, number), PAGE_SIZE - offsetof(cbt_storage_page_t, number));
+    if (crc != accessor->page->crc){
+        log_err_lld("Invalid CRC32 on page #", accessor->page_number);
+        log_err_sect("Physical offset on block device: ", phys_offset);
+        log_err_lx("Expected crc=", crc);
+        log_err_lx("Read crc=", accessor->page->crc);
+        return -EINVAL;
+    }
+
+    if (accessor->page_number != accessor->page->number){
+        log_err("Invalid cbt data page number");
+        log_err_lld("Expected=", accessor->page_number);
+        log_err_lld("Read=", accessor->page->number);
+        return -EINVAL;
+    }
+
+    return SUCCESS;
+}
+
+static int _cbt_storage_write_page(cbt_storage_accessor_t* accessor, struct timespec64* optional_time)
+{
+    int res;
+    sector_t phys_offset = 0;
+    sector_t phys_length = 0;
+
+    log_tr_d("DEBUG! write page# ", accessor->page_number);
+
+    //set magic
+    memcpy(accessor->page->magic, CBT_STORAGE_MAGIC, 8);
+    //set number
+    accessor->page->number = accessor->page_number;
+    //set time marker
+    if (optional_time){
+        accessor->page->tv_sec = optional_time->tv_sec;
+        accessor->page->tv_nsec = optional_time->tv_nsec;
+    }
+    else{
+        accessor->page->tv_sec = accessor->time.tv_sec;
+        accessor->page->tv_nsec = accessor->time.tv_nsec;
+    }
+    //calculate CRC32
+    accessor->page->crc = crc32(~0, (void*)(accessor->page) + offsetof(cbt_storage_page_t, number), PAGE_SIZE - offsetof(cbt_storage_page_t, number));
+
+    res = rangevector_v2p(accessor->rangevector, accessor->page_number * sector_from_uint(PAGE_SIZE), sector_from_uint(PAGE_SIZE), &phys_offset, &phys_length);
+    if (res != SUCCESS){
+        log_err("Failed to get real disk offset for persistent CBT data");
+        return res;
+    }
+
+    if (phys_length != sector_from_uint(PAGE_SIZE)){
+        log_err_sect("Unordered range size: ", phys_length);
+        log_err("Range is not ordered by PAGE_SIZE");
+        return -EINVAL;
+    }
+
+    //write page
+    log_tr_sect("DEBUG! offset= ", phys_offset);
+    res = blk_direct_submit_page(accessor->device, WRITE_SYNC, phys_offset, accessor->pg);
+    if (res != SUCCESS){
+        log_err("Failed to read device");
+        log_err_sect("Real device offset: ", phys_offset);
+        return res;
+    }
+
+    return SUCCESS;
+}
+
+int cbt_storage_open(cbt_persistent_parameters_t* params, cbt_storage_accessor_t* accessor)
+{
+    int res = SUCCESS;
+    log_tr_dev_t("Open persistent CBT storage device ",params->dev_id);
+
+    res = blk_dev_open(params->dev_id, &accessor->device);
+    if (res != SUCCESS){
+        log_err_dev_t("Failed to open device ", params->dev_id);
+        return res;
+    }
+    do{
+        if (0 == rangevector_cnt(&params->rangevector)){
+            log_err("No range for reading");
+            res = -EINVAL;
+            break;
+        }
+
+        //allocate page
+        if (NULL == (accessor->pg = alloc_page(GFP_KERNEL))){
+            log_err("Failed to allocate page");
+            res = -ENOMEM;
+            break;
+        }
+        accessor->page = (cbt_storage_page_t*)page_address(accessor->pg);
+
+        accessor->rangevector = &params->rangevector;
+        accessor->page_count = rangevector_length(accessor->rangevector) / sector_from_uint(PAGE_SIZE);
+        accessor->page_number = 0;
+        accessor->used_page_count = accessor->page_count;
+        accessor->page_offset = offsetof(cbt_storage_page_t, data);
+
+    } while (false);
+    if (res != SUCCESS)
+        cbt_storage_close(accessor);
+    return res;
+}
+
+void cbt_storage_close(cbt_storage_accessor_t* accessor)
+{
+    if (accessor->pg != NULL){
+        __free_page(accessor->pg);
+        accessor->pg = NULL;
+        accessor->page = NULL;
+    }
+    if (accessor->device != NULL){
+        log_tr("Close persistent CBT storage device ");
+
+        blk_dev_close(accessor->device);
+        accessor->device = NULL;
+    }
+    accessor->rangevector = NULL;
+}
+
+int cbt_storage_check(cbt_storage_accessor_t* accessor)
+{
+    int res = SUCCESS;
+    //check all pages
+
+    //log_tr("[TBD] Checking CRC32 for all pages:");
+    accessor->page_number = 0;
+    accessor->used_page_count = accessor->page_count;
+    res = _cbt_storage_read_page(accessor);
+    if (res != SUCCESS){
+        log_err("Failed to get first page ");
+        return res;
+    }
+    //get time from first page
+    accessor->time.tv_sec = accessor->page->tv_sec;
+    accessor->time.tv_nsec = accessor->page->tv_nsec;
+
+    if (accessor->time.tv_sec == 0ull){
+        log_tr("Persistent CBT data is empty");
+        accessor->used_page_count = 0;
+    }
+
+    for (accessor->page_number = 1; accessor->page_number < accessor->page_count; ++accessor->page_number){
+        res = _cbt_storage_read_page(accessor);
+        if (res != SUCCESS){
+            log_err_lld("Failed to get page #", accessor->page_number);
+            break;
+        }
+        if (accessor->time.tv_sec != 0ull){
+            if (accessor->page->tv_sec == 0ull){
+                //unused page found
+                if (accessor->used_page_count == accessor->page_count){
+                    accessor->used_page_count = accessor->page_number;
+                    log_tr_lld("Found first unused page #", accessor->page_number);
+                }
+            }
+            else{
+                if ((accessor->time.tv_sec != accessor->page->tv_sec) && (accessor->time.tv_nsec != accessor->page->tv_nsec))
+                {
+                    log_err_lld("Invalid time marker on page #", accessor->page_number);
+                    log_err_llx("Expected=", accessor->time.tv_sec);
+                    log_err_llx("Read=", accessor->page->tv_sec);
+
+                    //cbt data skipped
+                    accessor->time.tv_sec = 0ull;
+                    accessor->time.tv_nsec = 0ul;
+
+                    break;
+                }
+            }
+        }
+    }
+
+    if (res != SUCCESS){
+        log_err("Check failed");
+        return res;
+    }
+
+    if (accessor->time.tv_sec != 0ull){
+        //show time
+        struct tm modify_time;
+#if LINUX_VERSION_CODE < KERNEL_VERSION(4,20,0)
+        time_to_tm(accessor->time.tv_sec, 0, &modify_time);
+#else
+        time64_to_tm(accessor->time.tv_sec, 0, &modify_time);
+#endif
+        log_tr_format("Persistent CBT data from %04ld.%02d.%02d %02ld:%02d:%02d %d",
+            modify_time.tm_year + 1900,
+            modify_time.tm_mon + 1,
+            modify_time.tm_mday,
+            modify_time.tm_hour,
+            modify_time.tm_min,
+            modify_time.tm_sec,
+            accessor->time.tv_nsec);
+    }
+
+    return res;
+}
+
+
+int cbt_storage_prepare4read(cbt_storage_accessor_t* accessor)
+{
+    int res = SUCCESS;
+
+    //set position to first page
+    accessor->page_number = 0;
+    accessor->page_offset = 0;
+
+    res = _cbt_storage_read_page(accessor);
+    if (res != SUCCESS){
+        log_err("Failed to get first page ");
+        return res;
+    }
+    //check time from fisrt page
+    accessor->time.tv_sec = accessor->page->tv_sec;
+    accessor->time.tv_nsec = accessor->page->tv_nsec;
+
+    if (accessor->time.tv_sec == 0ull)
+        return ENODATA;
+
+    //set CBT data empty
+    {
+        struct timespec64 tm = {0}; //
+        res = _cbt_storage_write_page(accessor, &tm);
+        if (res != SUCCESS){
+            log_err("Failed to write first page ");
+            return res;
+        }
+    }
+
+    return res;
+}
+
+int cbt_storage_prepare4write(cbt_storage_accessor_t* accessor)
+{
+    int res = SUCCESS;
+    //set position to first page
+    accessor->page_number = 0;
+    accessor->page_offset = 0;
+
+    res = _cbt_storage_read_page(accessor);
+    if (res != SUCCESS){
+        log_err("Failed to get first page ");
+        return res;
+    }
+    //get time
+    ktime_get_ts64(&accessor->time);
+
+    return res;
+}
+
+int cbt_storage_read(cbt_storage_accessor_t* accessor, void* dst, size_t sz)
+{
+    int res = SUCCESS;
+    size_t ofs = 0;
+    size_t can_be_read;
+    if (accessor->page_number == accessor->page_count){
+        log_err_lld("EOF reached, page number ", accessor->page_number);
+        return -ENODATA;
+    }
+
+    can_be_read = min(CBT_PAGE_DATA_SIZE - accessor->page_offset, sz - ofs);
+    memcpy(dst, accessor->page->data + accessor->page_offset, can_be_read);
+    accessor->page_offset += can_be_read;
+    ofs += can_be_read;
+
+    do{
+        if (accessor->page_offset == CBT_PAGE_DATA_SIZE) {
+            accessor->page_number++;
+            accessor->page_offset = 0;
+        }
+
+        if (accessor->page_number == accessor->page_count){
+            if (ofs < sz){
+                log_err_lld("EOF reached, page number= ", accessor->page_number);
+                res = -ENODATA;
+            }
+            else{
+                log_tr("Reached EOF");
+                res = SUCCESS;
+            }
+            break;
+        }
+
+        //read next page
+        res = _cbt_storage_read_page(accessor);
+        if (res != SUCCESS){
+            log_err_lld("Failed to get page #", accessor->page_number);
+            return res;
+        }
+
+        if (ofs == sz)
+            break;//reading is complete 
+
+        can_be_read = min(CBT_PAGE_DATA_SIZE - accessor->page_offset, sz - ofs);
+        memcpy(dst, accessor->page->data + accessor->page_offset, can_be_read);
+        accessor->page_offset += can_be_read;
+        ofs += can_be_read;
+
+    } while (true);
+    return res;
+}
+
+int cbt_storage_write(cbt_storage_accessor_t* accessor, void* src, size_t sz)
+{
+    int res = SUCCESS;
+    size_t ofs = 0;
+    size_t can_be_write;
+
+    if (accessor->page_number == accessor->page_count){
+        log_err_lld("Reached EOF, page number= ", accessor->page_number);
+        return -ENODATA;
+    }
+
+    can_be_write = min(CBT_PAGE_DATA_SIZE - accessor->page_offset, sz - ofs);
+    log_tr_sz("DEBUG! can_be_write=", can_be_write);
+    if (can_be_write == 0){
+        log_tr_format("can_be_write is zero. sz=%lu, ofs=%lu page_offset=%lu", (unsigned long)(sz), (unsigned long)(ofs), (unsigned long)(accessor->page_offset));
+        return -EFAULT;
+    }
+    
+    memcpy(accessor->page->data + accessor->page_offset, src + ofs, can_be_write);
+    accessor->page_offset += can_be_write;
+    ofs += can_be_write;
+
+    do{
+        if (accessor->page_offset == CBT_PAGE_DATA_SIZE){
+            //write current page
+            res = _cbt_storage_write_page(accessor, NULL);
+            if (res != SUCCESS){
+                log_err_lld("Failed to get page #", accessor->page_number);
+                return res;
+            }
+
+            accessor->page_number++;
+            accessor->page_offset = 0;
+        }
+
+        if (accessor->page_number == accessor->page_count){
+            if (ofs < sz){
+                log_err_lld("Reached EOF, page number= ", accessor->page_number);
+                res = -ENODATA;
+            }
+            else{
+                log_tr("Reached EOF");
+                res = SUCCESS;
+            }
+            break;
+        }
+
+        if (ofs == sz)
+            break;//writing is complete 
+
+        can_be_write = min(CBT_PAGE_DATA_SIZE - accessor->page_offset, sz - ofs);
+        log_tr_sz("DEBUG! can_be_write=", can_be_write);
+        if (can_be_write == 0){
+            log_tr_format("can_be_write is zero. sz=%lu, ofs=%lu page_offset=%lu", (unsigned long)sz, (unsigned long)ofs, (unsigned long)accessor->page_offset);
+            return -EFAULT;
+        }
+        memcpy(accessor->page->data + accessor->page_offset, src + ofs, can_be_write);
+        accessor->page_offset += can_be_write;
+        ofs += can_be_write;
+
+    } while (true);
+
+    return res;
+}
+
+int cbt_storage_write_finish(cbt_storage_accessor_t* accessor)
+{
+    int res = SUCCESS;
+
+    if (accessor->page_number == accessor->page_count)
+        return SUCCESS;
+
+    //write last page
+    log_tr_lld("DEBUG! write last page #", accessor->page_number);
+
+    res = _cbt_storage_write_page(accessor, NULL);
+    if (res != SUCCESS){
+        log_err_lld("Failed to get page #", accessor->page_number);
+        return res;
+    }
+
+    accessor->page_number++;
+    accessor->page_offset = 0;
+
+    {//store empty unused pages
+        struct timespec64 tm = {0}; 
+        memset(accessor->page->data, 0, CBT_PAGE_DATA_SIZE);
+
+        while (accessor->page_number < accessor->page_count){
+
+            accessor->page->number = accessor->page_number;
+
+            //log_tr_lld("DEBUG! write empty page #", accessor->page_number);
+            res = _cbt_storage_write_page(accessor, &tm);
+            if (res != SUCCESS){
+                log_err_lld("Failed to get page #", accessor->page_number);
+                break;
+            }
+            accessor->page_number++;
+        }
+    }
+    return res;
+}
+
+
+#endif//PERSISTENT_CBT

@redrum781 PR for this patch?

fixed in 4.0.1.2365