advin

NVMe cache support

Recommended Posts

5 hours ago, The Chief said:

I'm more than happy to say — no, it's not! It's just simple pci bus number check in proprietary Syno code.

Thank you! Very good news.

 

I also tried this method with nvme (Kingston A1000 240GB) on motherboard's internal nvme connector. So I changed those values to "0000:04:00.0".  And it works!

 

The only one thing I still do not understand is - what about second nvme drive for RW cache setup? Does it have the same pci ids as the first one on add-on card? If so what about my second nvme slot on motherboard, no chance?..

Share this post


Link to post
Share on other sites
6 часов назад, vasiliy_gr сказал:

The only one thing I still do not understand is - what about second nvme drive for RW cache setup? Does it have the same pci ids as the first one on add-on card? If so what about my second nvme slot on motherboard, no chance?..

You have to wait until someone will make full patch, removing pci bus check completely from syno library.

 

PS: I personally can't recommend RW cache setup — it can lead to data corruption. And even more, it both ssd's went dead, you loose access to RW-cached volume until you replace ssd's with new ones.

Edited by The Chief

Share this post


Link to post
Share on other sites
10 часов назад, vasiliy_gr сказал:

Does it have the same pci ids as the first one on add-on card?

Try this:

 

918+ NVME unipatch.png

 

Any nvme ssd in any pcie slot shoud do from now. Xpeno has to be DS918+, obviously.

 

root@Xpenology:~# synonvme --is-nvme-ssd /dev/nvme0n1
It is a NVMe SSD
root@Xpenology:~# synonvme --m2-card-model-get /dev/nvme0n1
Not M.2 adapter card
root@Xpenology:~# synonvme --model-get /dev/nvme0n1
Model name: INTEL MEMPEK1W016GAH
root@Xpenology:~# nvme list
Node             SN                   Model                                    Namespace Usage                      Format           FW Rev
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1     PHBT730601CQ016D     INTEL MEMPEK1W016GAH                     1          14.40  GB /  14.40  GB    512   B +  0 B   K3110310
/dev/nvme0n1p1   PHBT730601CQ016D     INTEL MEMPEK1W016GAH                     1          14.40  GB /  14.40  GB    512   B +  0 B   K3110310
root@Xpenology:~# udevadm info /dev/nvme0n1
P: /devices/pci0000:00/0000:00:01.0/0000:01:00.0/nvme/nvme0/nvme0n1
N: nvme0n1
E: DEVNAME=/dev/nvme0n1
E: DEVPATH=/devices/pci0000:00/0000:00:01.0/0000:01:00.0/nvme/nvme0/nvme0n1
E: DEVTYPE=disk
E: ID_PART_TABLE_TYPE=dos
E: MAJOR=259
E: MINOR=0
E: PHYSDEVBUS=pci
E: PHYSDEVDRIVER=nvme
E: PHYSDEVPATH=/devices/pci0000:00/0000:00:01.0/0000:01:00.0
E: SUBSYSTEM=block
E: SYNO_ATTR_SERIAL=PHBT730601CQ016D
E: SYNO_DEV_DISKPORTTYPE=CACHE
E: SYNO_INFO_PLATFORM_NAME=apollolake
E: SYNO_KERNEL_VERSION=4.4
E: USEC_INITIALIZED=94668

root@Xpenology:~# synonvme --get-location /dev/nvme0n1
Device: /dev/nvme0n1, PCI Slot: 0, Card Slot: 1
root@Xpenology:~# synonvme --port-type-get /dev/nvme0n1
SSD Cache.
root@Xpenology:~# synodiskport -cache
 nvme0n1
root@Xpenology:~# ls -l /dev/mapper/cache*
brw------- 1 root root 252, 2 Nov 27 10:12 /dev/mapper/cachedev_0
root@Xpenology:~# dmsetup status
vg1-syno_vg_reserved_area: 0 24576 linear
cachedev_0: 0 11701714944 flashcache-syno stats:
        reads(9899), writes(3082)
        read hits(4377), read hit percent(44)
        replacement(0), write replacement(0)
        invalidates(0)
        pending enqueues(792), pending inval(0)
        no room(0)
        disk reads(5522), disk writes(3082) ssd reads(3585) ssd writes(4833)
        uncached reads(689), uncached writes(3082), uncached IO requeue(0)
        disk read errors(0), disk write errors(0) ssd read errors(0) ssd write errors(0)
        uncached sequential reads(689), uncached sequential writes(0)
        pid_adds(0), pid_dels(0), pid_drops(0) pid_expiry(0)
        write miss ssd(0)
        ---------------------------
        Read hit statistics:
        pending preread(792)
        match none read disk(0) busy in io(792) busy wait queue(0)
        match partial: total(0)
        Write hit statistics:
        busy inval(0)
        do pending write back(0)
        map skip_unaligned_io(0)
        dirty_writeback(0)
        cleanings_over_threshold(0)
        cleanings_total(0)
        preread_job_mem_count(0)
        num_uncached_write(0) num_write_cache(0) num_flush_bio(318)
        inval dirty writeback(0)
        write miss invalidate(0)
        map_inval(0) uncacheable_inval(0) do_pending_no_error_inval(0)
        pending enqueue inval (0) pending enqueue inval handled(0)
        disk flush start(0) disk flush done(0)
        dirty writeback start (0) dirty writeback done (0)

vg1-volume_1: 0 11701714944 linear

 

Edited by The Chief
  • Like 1
  • Thanks 3

Share this post


Link to post
Share on other sites

The way Syno checks NVME cache (two most interesting functions, reversed to C) :

 

Скрытый текст



//-------------------------------------------------------------------------
// Data declarations

char *off_DS719_PCIBUS = "0000:00:13.2"; // weak
char *off_DS1019_PCIBUS = "0000:00:13.2"; // weak
char *off_DS419_PCIBUS = "0000:00:13.1"; // weak
char *off_RS1619_PCIBUS = "0000:00:03.2"; // weak
char *off_DS918_PCIBUS = "0000:00:13.1"; // weak
char *off_207C00 = "08.0"; // weak
char *off_207C40 = "08.0"; // weak
char *off_207C80 = "08.0"; // weak
char *off_207CC0 = "04.0"; // weak
char *off_207D00 = "04.0"; // weak
char *off_207D40 = "04.0"; // weak
char *off_207D80 = "04.0"; // weak
char *off_207DC0 = "04.0"; // weak
char *off_207E00 = "04.0"; // weak

//----- (0000000000003E10) ----------------------------------------------------
__int64 __fastcall SYNONVMeModelSpecGet(_QWORD *a1, char *a2)
{
  _QWORD *v2; // rbp
  unsigned int v3; // eax
  __int64 result; // rax
  __int64 v5; // [rsp+0h] [rbp-418h]

  v2 = a1;
  memset(&v5, 0, 0x400uLL);
  if ( a1 && a2 )
  {
    if ( (unsigned int)SYNONVMeModelNameGet((char *)&v5) )
    {
      syslog(3, "%s:%d Failed to get model name", "nvme_model_spec_get.c", 261LL);
      result = 0xFFFFFFFFLL;
    }
    else
    {
      *a1 = 0LL;
      a1[1] = 0LL;
      v3 = SYNOM2CardModelGet(a2);
      if ( v3 == 1 ) // Syno M.2 card adapter present
      {
        if ( !memcmp(&v5, "FS6400", 6uLL) )
        {
          *(_DWORD *)v2 = 2;
          v2[1] = &off_207D40;
          result = 0LL;
        }
        else
        {
          *(_DWORD *)v2 = 2;
          if ( !memcmp(&v5, "RS1619xs+", 9uLL) )
            v2[1] = &off_207D00;
          else
            v2[1] = &off_207CC0;
          result = 0LL;
        }
      }
      else if ( v3 < 1 ) // different M.2 adapter type?
      {
        if ( (unsigned int)SLIBCSupportM2AllDev(a2, 1024LL) ) // 'support_m2_all_devices' in config is TRUE
        {
          *(_DWORD *)a1 = 2;
          if ( !memcmp(&v5, "FS6400", 6uLL) )
            v2[1] = &off_207E00;
          else
            v2[1] = &off_207DC0;
          result = 0LL;
        }
        else
        {
          *(_DWORD *)a1 = 2;
          a1[1] = &off_207D80;
          result = 0LL;
        }
      }
      else if ( v3 == 2 ) // and one more M.2 adapter type?
      {
        if ( !memcmp(&v5, "FS6400", 6uLL) )
        {
          *(_DWORD *)v2 = 2;
          v2[1] = &off_207C80;
          result = 0LL;
        }
        else
        {
          *(_DWORD *)v2 = 2;
          if ( !memcmp(&v5, "RS1619xs+", 9uLL) )
            v2[1] = &off_207C40;
          else
            v2[1] = &off_207C00;
          result = 0LL;
        }
      }
      else if ( v3 == 3 ) // M.2 adapter search error, try to find nvme on well-known pci hubs
      {
        if ( !memcmp(&v5, "DS918+", 6uLL) )
        {
          *(_DWORD *)v2 = 2;
          v2[1] = &off_DS918_PCIBUS;
          result = 0LL;
        }
        else if ( !memcmp(&v5, "RS1619xs+", 9uLL) )
        {
          *(_DWORD *)v2 = 2;
          v2[1] = &off_RS1619_PCIBUS;
          result = 0LL;
        }
        else if ( !memcmp(&v5, "DS419+", 6uLL) )
        {
          *(_DWORD *)v2 = 2;
          v2[1] = &off_DS419_PCIBUS;
          result = 0LL;
        }
        else if ( !memcmp(&v5, "DS1019+", 7uLL) )
        {
          *(_DWORD *)v2 = 2;
          v2[1] = &off_DS1019_PCIBUS;
          result = 0LL;
        }
        else
        {
          if ( !memcmp(&v5, "DS719+", 6uLL) )
          {
            *(_DWORD *)v2 = 2;
            v2[1] = &off_DS719_PCIBUS;
          }
          else
          {
            *(_DWORD *)v2 = 1;
            v2[1] = &off_207AA0; // void*
          }
          result = 0LL;
        }
      }
      else
      {
        syslog(3, "%s:%d Do not support this device", "nvme_model_spec_get.c", 280LL);
        result = 0xFFFFFFFFLL;
      }
    }
  }
  else
  {
    syslog(3, "%s:%d Bad paramter", "nvme_model_spec_get.c", 256LL);
    result = 0xFFFFFFFFLL;
  }
  return result;
}

//----- (00000000000041F0) ----------------------------------------------------
const char **__fastcall SYNONVMeSlotInfoGet(char *s)
{
  FILE *v1; // r12
  char *v2; // rbp
  char *v3; // rdi
  const char **v4; // rbx
  __int64 v6; // r13
  __int64 v7; // [rsp+0h] [rbp-2048h]
  char *haystack; // [rsp+8h] [rbp-2040h]
  __int64 v9; // [rsp+10h] [rbp-2038h]
  const char **v10; // [rsp+18h] [rbp-2030h]
  char sa; // [rsp+20h] [rbp-2028h]
  char v12; // [rsp+1020h] [rbp-1028h]

  v7 = 0LL;
  haystack = 0LL;
  v9 = 0LL;
  v10 = 0LL;
  memset(&sa, 0, 0x1000uLL);
  memset(&v12, 0, 0x1000uLL);
  if ( (int)SYNONVMeDevNameGet(s, &v12) < 0 )
  {
    syslog(3, "%s:%d Can't get the device name", "nvme_slot_info_get.c", 81LL);
LABEL_18:
    if ( haystack )
      free(haystack);
    return 0LL;
  }
  if ( (int)SYNONVMeModelSpecGet(&v9, &v12) < 0 )
  {
    syslog(3, "%s:%d Failed to get model specification", "nvme_slot_info_get.c", 86LL);
    goto LABEL_18;
  }
  snprintf(&sa, 0x1000uLL, "%s/%s/uevent", "/sys/block", &v12);
  v1 = fopen64(&sa, "r");
  if ( !v1 )
  {
    syslog(3, "%s:%d Can't open file %s", "nvme_slot_info_get.c", 93LL, &sa);
    goto LABEL_18;
  }
  while ( getline(&haystack, (size_t *)&v7, v1) != -1 )
  {
    v2 = haystack;
    if ( strstr(haystack, "PHYSDEVPATH") )
    {
      if ( (int)v9 <= 0 )
      {
LABEL_10:
        v4 = 0LL;
        v3 = v2;
      }
      else
      {
        v4 = v10;
        v6 = (__int64)&v10[3LL * (unsigned int)(v9 - 1) + 3];
        while ( !strstr(v2, *v4) )
        {
          v4 += 3;
          if ( v4 == (const char **)v6 )
            goto LABEL_10;
        }
        v3 = v2;
      }
      goto LABEL_11;
    }
  }
  syslog(3, "%s:%d Fail to read PHYSDEVPATH from %s", "nvme_slot_info_get.c", 106LL, &sa);
  v3 = haystack;
  v4 = 0LL;
  if ( !haystack )
    goto LABEL_8;
LABEL_11:
  free(v3);
LABEL_8:
  fclose(v1);
  return v4;
}


 

 

Edited by The Chief

Share this post


Link to post
Share on other sites
В 07.03.2019 в 01:34, flyride сказал:

Ooo, I wonder if Syno coded their utilities specifically to a particular PCIe address for DS918?

Yes, they were.

Share this post


Link to post
Share on other sites

This is nice work, and thank you for your contribution.

 

For those who aren't familiar with patching binary files, here's a script to enable nvme support per this research.

It must be run as sudo and you should reboot afterward.

 

Note that an update to DSM might overwrite this file such that it has to be patched again (and/or can't be patched due to string changes, although this is unlikely).  Your volume might appear as corrupt or not mountable until the patch is reapplied.  To be very safe, you may want to remove the cache drive from the volume prior to each update.

#!/bin/ash
# patchnvme for DSM 6.2.x
#
TARGFILE="/usr/lib/libsynonvme.so.1"
PCISTR="\x00\x30\x30\x30\x30\x3A\x30\x30\x3A\x31\x33\x2E\x31\x00"
PHYSDEVSTR="\x00\x50\x48\x59\x53\x44\x45\x56\x50\x41\x54\x48\x00\x00\x00\x00\x00\x00"
PCINEW="\x00\x6E\x76\x6D\x65\x00\x00\x00\x00\x00\x00\x00\x00\x00"
PHYSDEVNEW="\x00\x50\x48\x59\x53\x44\x45\x56\x44\x52\x49\x56\x45\x52\x00\x00\x00\x00"
#
[ -f $TARGFILE.bak ] || cp $TARGFILE $TARGFILE.bak
if [ $? == 1 ]; then
  echo "patchnvme: can't create backup (sudo?)"
  exit
fi
COUNT=`grep -obUaP "$PCISTR" $TARGFILE | wc -l`
if [ $COUNT == 0 ]; then
  echo "patchnvme: can't find PCI reference (already patched?)"
  exit
fi
if [ $COUNT -gt 1 ]; then
  echo "patchnvme: multiple PCI reference! abort"
  exit
fi
COUNT=`grep -obUaP "$PHYSDEVSTR" $TARGFILE | wc -l`
if [ $COUNT == 0 ]; then
  echo "patchnvme: can't find PHYSDEV reference (already patched?)"
  exit
fi
if [ $COUNT -gt 1 ]; then
  echo "patchnvme: multiple PHYSDEV reference! abort"
  exit
fi
sed "s/$PCISTR/$PCINEW/g" $TARGFILE >$TARGFILE.tmp
if [ $? == 1 ]; then
  echo "patchnvme: patch could not be applied (sudo?)"
  exit
fi
sed "s/$PHYSDEVSTR/$PHYSDEVNEW/g" $TARGFILE.tmp >$TARGFILE
if [ $? == 1 ]; then
  echo "patchnvme: patch could not be applied (sudo?)"
  exit
fi
echo "patchnvme: success"
rm $TARGFILE.tmp 2>/dev/null

 

Edited by flyride
fixed formatting
  • Like 3
  • Thanks 1

Share this post


Link to post
Share on other sites

This is nice work, and thank you for your contribution. flyride & The Chief😊

Share this post


Link to post
Share on other sites
1 hour ago, flyride said:

Note that an update to DSM might overwrite this file such that it has to be patched again (and/or can't be patched due to string changes, although this is unlikely).  Your volume might appear as corrupt or not mountable until the patch is reapplied.  To be very safe, you may want to remove the cache drive from the volume prior to each patch.

 

that needs to be red an bold !!!

Share this post


Link to post
Share on other sites
9 часов назад, flyride сказал:

prior to each patch

«…prior to each DSM update», I guess. :)

 

PS: this final patch version needs more testing in real setups, and more feedback as well to claim it stable. Comrades, test & provide feedback, if you please.

Edited by The Chief

Share this post


Link to post
Share on other sites
9 часов назад, flyride сказал:

It must be run as sudo and you should reboot afterward.

Is there a way to do a shellscript automagically post-update or at boot/premount time? Hmmm…

Edited by The Chief

Share this post


Link to post
Share on other sites
14 часа назад, flyride сказал:

Note that an update to DSM might overwrite this file such that it has to be patched again

 

Put attached script in /usr/local/etc/rc.d/ — it will try to keep .so patched (script is executed at system startup/shutdown), even after DSM update. Based on the nice shell code of yours, thanx a lot!

libNVMEpatch.sh

Share this post


Link to post
Share on other sites

 @The Chief

 

thanks for your good work,

 

ive tried your script to get my test cache ssd to work...

 

im running DSM 6.2.2-24922 U4

on Baremetal ASRock B250M

with Intel i5-6400T

 

ive copied your script to the NAS, started the shell script as ROOT and after this ive copied the file to /usr/local/etc/rc.d/ and rebooted the NAS with init 6....

 

but after the reboot my NVME isnt alive on the volume manager.

 

Its an Intenso 128GB NVME

 

root@NAS:/# nvme list
Node             SN                   Model                                    Namespace Usage                      Format           FW Rev
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1     3QLUS7RSFP174FJTPDR5 INTENSO                                  1         128.04  GB / 128.04  GB    512   B +  0 B   R1115A0
/dev/nvme0n1p1   3QLUS7RSFP174FJTPDR5 INTENSO                                  1         128.04  GB / 128.04  GB    512   B +  0 B   R1115A0
/dev/nvme0n1p2   3QLUS7RSFP174FJTPDR5 INTENSO                                  1         128.04  GB / 128.04  GB    512   B +  0 B   R1115A0
root@NAS:/

root@NAS:/# synonvme --is-nvme-ssd /dev/nvme0n1
It is a NVMe SSD
root@NAS:/#

root@NAS:/# synonvme --model-get /dev/nvme0
Model name: INTENSO
root@NAS:/# udevadm info /dev/nvme0n1
P: /devices/pci0000:00/0000:00:1d.0/0000:01:00.0/nvme/nvme0/nvme0n1
N: nvme0n1
E: DEVNAME=/dev/nvme0n1
E: DEVPATH=/devices/pci0000:00/0000:00:1d.0/0000:01:00.0/nvme/nvme0/nvme0n1
E: DEVTYPE=disk
E: ID_PART_TABLE_TYPE=gpt
E: MAJOR=259
E: MINOR=0
E: PHYSDEVBUS=pci
E: PHYSDEVDRIVER=nvme
E: PHYSDEVPATH=/devices/pci0000:00/0000:00:1d.0/0000:01:00.0
E: SUBSYSTEM=block
E: SYNO_ATTR_SERIAL=3QLUS7RSFP174FJTPDR5
E: SYNO_DEV_DISKPORTTYPE=UNKNOWN
E: SYNO_INFO_PLATFORM_NAME=apollolake
E: SYNO_KERNEL_VERSION=4.4
E: USEC_INITIALIZED=648737

root@NAS:/#

 

when i look for the age of the file libsynonvme.so i can see that it was modded. (by the date)

root@NAS:/usr/lib# ls -l
total 145160
lrwxrwxrwx  1 root root       16 Nov 29 17:35 libsynonvme.so -> libsynonvme.so.1
-rw-r--r--  1 root root    33578 May  9  2019 libsynonvme.so.1

 

d u got a hint for me?

 

 

Edited by DerMoeJoe

Share this post


Link to post
Share on other sites

Shellscript has to be executable:

chmod 0755  /usr/local/etc/rc.d/libNVMEpatch.sh

 

What «Storage Manager → SSD Cache → Create»  says? It should allow you to select SSD after «Choose Mode → Next».

Edited by The Chief

Share this post


Link to post
Share on other sites

Thank you !

 

root@DiskStation:~# nvme list
Node             SN                   Model                                    Namespace Usage                      Format           FW Rev
---------------- -------------------- ---------------------------------------- --------- -------------------------- ---------------- --------
/dev/nvme0n1     2J1820020553         ADATA SX6000LNP                          1         128.04  GB / 128.04  GB    512   B +  0 B   V9001c01
/dev/nvme0n1p1   2J1820020553         ADATA SX6000LNP                          1         128.04  GB / 128.04  GB    512   B +  0 B   V9001c01
/dev/nvme1n1     2J1820018995         ADATA SX6000LNP                          1         128.04  GB / 128.04  GB    512   B +  0 B   V9001c01
/dev/nvme1n1p1   2J1820018995         ADATA SX6000LNP                          1         128.04  GB / 128.04  GB    512   B +  0 B   V9001c01

Share this post


Link to post
Share on other sites

Does this still work? having issues getting it working.

 

EDIT: nvm sorted it.

Edited by fma965

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.