Jetson-io.py in r32.7.2

While trying to chase down an issue where GPIOs were not behaving as I expected since updating from 32.6.1 to 32.7.2 (not clear where that problem stands, still researching), I tried running /opt/nvidia/jetson-io/jetson-io.py as I had before (under 32.6.1 and previous), but it immediately exited - in fact, when running while connected via ssh, I couldn’t even tell that curses had initialized.

I then ran it on the serial console (where things ran a little slower), and I could see that curses initialized, but the only thing I could see (even after reviewing a screen capture) was the words “FATAL ERROR”. Hm. I then ran an edited copy of jetson-io.py to see if I could tell what was happening, and I saw this:

    raise RuntimeError("Multiple %s partitions mounted!" % partlabel)
RuntimeError: Multiple APP partitions mounted!

… this gave me more of a clue - I was running off a USB drive, so there were two APP partitions; the one on the running system (USB) and the one on the internal emmc. When I booted off the internal emmc WITHOUT the USB connected, the script ran normally. If I had the USB drive mounted for any reason (even when not booting from it), I got the above error.

So, two questions:

  • how can I make jetson-io.py give decent error messages without editing the script? It’s ridiculous that a system tool breaks like this.
  • Is there any way I can run this tool while both disks are active? Any way to specify WHICH APP partition is the right one? (Why did it work under 32.6.1??)

Sorry for the late response, our team will do the investigation and provide suggestions soon. Thanks

Looks like I get the same error with /opt/nvidia/jetson-io/config-by-hardware.py

Can confirm similar issues on r32.7.1. I have a NX production module 16 GB and am booting a NVME SSD from M.2 port. The SSD was flashed with the SDK manager only. Removing the SSD and booting from just the eMMC resolves it but is impractical.

This is very annoying because jetson-io.py is very convenient for switching cameras for 3rd party CSI cameras.

I have a rough workaround implemented that lets me use jetson-io.py with two APP partitions. In /opt/nvidia/jetson-io/Jetson/board.py, edit line 134 from:

if partlabel == label:

to

if partlabel == label and mount == '/':

If the mounting location for the primary APP partition is default (“/”) then this should ignore the other APP partition. Although, the custom dtb outputted from jetson-io will only be read if the system reads from the right device. I tested this on both NVME and eMMC and jetson-io.py loads properly for both, but only changes done on the NVME are implemented.

The more appropriate thing for me to do is to wipe the rootfs and APP partition from the eMMC, but I’m not sure how… any advice?

Could you apply below patch to try.

diff --git a/jetson-io/Jetson/board.py b/jetson-io/Jetson/board.py
index 8d0eb86..aa540e2 100644
--- a/jetson-io/Jetson/board.py
+++ b/jetson-io/Jetson/board.py
@@ -117,6 +117,22 @@ def _board_get_dtb(compat, model, path):
     return dtbs[0]


+def _board_root_partition_is_block_device():
+    dev = syscall.call_out('mountpoint -q -d /')
+    if not dev or len(dev) != 1:
+        raise RuntimeError("Root partition not found!")
+    return os.path.exists("/dev/block/%s" % dev[0])
+
+
+def _board_root_partition_get_partlabel():
+    entries = syscall.call_out('lsblk -n -r -o mountpoint,partlabel')
+    for entry in entries:
+        mountpoint,label = entry.split(' ')
+        if mountpoint == '/':
+            return label
+    return None
+
+
 def _board_partition_exists(partlabel):
     numparts = 0
     partlabels = syscall.call_out('lsblk -n -r -o partlabel')
@@ -126,16 +142,12 @@ def _board_partition_exists(partlabel):
     return numparts


-def _board_partition_is_mounted(partlabel):
-    mountpoint = None
-    entries = syscall.call_out('lsblk -n -r -o mountpoint,partlabel')
-    for entry in entries:
-        mount,label = entry.split(' ')
-        if partlabel == label:
-            if mountpoint:
-                raise RuntimeError("Multiple %s partitions mounted!" % partlabel)
-            mountpoint = mount
-    return mountpoint
+def _board_partition_is_root_mountpoint(partlabel):
+    if not _board_root_partition_is_block_device():
+        return False
+    if _board_root_partition_get_partlabel() == 'APP':
+        return True
+    return False


 def _board_partition_mount(partlabel):
@@ -195,27 +207,22 @@ class Board(object):
     def __init__(self):
         self.appdir = None
         self.bootdir = '/boot'
+        self.extlinux = '/boot/extlinux/extlinux.conf'
+        dtbdir = os.path.join(self.bootdir, 'dtb')
         fio.is_rw(self.bootdir)

-        # The partition that needs to be updated by Jetson-IO is the APP
-        # partition. In certain cases, such as mounting the rootfs via
-        # NFS, the APP partition is not mounted by default and so needs
-        # to be mounted. Therefore, we first check to see if the APP
-        # partition is mounted and if so where it is mounted. If it is
-        # not mounted then it is necessary to find and mount the 'APP'
-        # partition and copy the generated files back to this partition.
-        mountpoint = _board_partition_is_mounted('APP')
-        if mountpoint:
-            if mountpoint != '/':
-                self.bootdir = mountpoint
-            dtbdir = os.path.join(self.bootdir, 'dtb')
-        else:
+        # When mounting the rootfs via NFS, the root partition is not a
+        # block device. Furthermore, when booting with NFS the partition
+        # that the bootloader reads to parse the extlinux.conf and load
+        # the kernel DTB may not be mounted. Therefore, if the rootfs is
+        # not mounted on a partition called 'APP', then it is necessary
+        # to find and mount the 'APP' partition and copy the generated
+        # files back to this partition.
+        if not _board_partition_is_root_mountpoint('APP'):
             self.appdir = _board_partition_mount('APP')
             dtbdir = os.path.join(self.appdir, 'boot/dtb')
             fio.is_rw(self.appdir)

-        self.extlinux = os.path.join(self.bootdir, 'extlinux/extlinux.conf')
-
         # Import platform specific data
         self.compat = dt.read_prop('compatible')
         self.model = dt.read_prop('model')

This does appear to fix the problem. Thanks!

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.