The following pull request was submitted through Github.
It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/6744

This e-mail was sent by the LXC bot, direct replies will not reach the author
unless they happen to be subscribed to this list.

=== Description (from pull-request) ===
- Adds support for Disk and NIC device `boot.priority` setting.
- Unifies root disk and other disk qemu config creation.
- Makes root disk default `boot.priority` 1 and other devices default `boot.priority` 0.
- Uses boot index for SCSI ID.
From 9fbd01aee9042c2114e5ed81604ab6d81e21b7d5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Mon, 20 Jan 2020 16:34:31 +0200
Subject: [PATCH 1/9] doc/api-extensions: Fix syntax
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 doc/api-extensions.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index 5b3c2e5331..a2bc88793a 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -895,7 +895,7 @@ This adds a new `architecture` attribute to cluster members 
which indicates a cl
 member's architecture.
 
 ## resources\_disk\_id
-Add a new device_id field in the disk entries on the resources API.
+Add a new device\_id field in the disk entries on the resources API.
 
 ## storage\_lvm\_stripes
 This adds the ability to use LVM stripes on normal volumes and thin pool 
volumes.

From 44f6dfe0a43ef89d4b6f457bc4006dceded89796 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Mon, 20 Jan 2020 16:35:28 +0200
Subject: [PATCH 2/9] api: vm_boot_priority
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 doc/api-extensions.md | 3 +++
 shared/version/api.go | 1 +
 2 files changed, 4 insertions(+)

diff --git a/doc/api-extensions.md b/doc/api-extensions.md
index a2bc88793a..a5dad365ea 100644
--- a/doc/api-extensions.md
+++ b/doc/api-extensions.md
@@ -899,3 +899,6 @@ Add a new device\_id field in the disk entries on the 
resources API.
 
 ## storage\_lvm\_stripes
 This adds the ability to use LVM stripes on normal volumes and thin pool 
volumes.
+
+## vm\_boot\_priority
+Adds a `boot.priority` property on nic and disk devices to control the boot 
order.
diff --git a/shared/version/api.go b/shared/version/api.go
index 95985665cb..b06864911b 100644
--- a/shared/version/api.go
+++ b/shared/version/api.go
@@ -183,6 +183,7 @@ var APIExtensions = []string{
        "clustering_architecture",
        "resources_disk_id",
        "storage_lvm_stripes",
+       "vm_boot_priority",
 }
 
 // APIExtensionsCount returns the number of available API extensions.

From 2e8f4bb22d7023ef79f9a3319c1781584c208230 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com>
Date: Mon, 20 Jan 2020 16:33:57 +0200
Subject: [PATCH 3/9] lxd/vm: Add boot.priority
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Stéphane Graber <stgra...@ubuntu.com>
---
 doc/instances.md           | 6 ++++++
 lxd/device/disk.go         | 1 +
 lxd/device/nic.go          | 1 +
 lxd/device/nic_bridged.go  | 1 +
 lxd/device/nic_macvlan.go  | 2 +-
 lxd/device/nic_physical.go | 1 +
 lxd/device/nic_sriov.go    | 1 +
 scripts/bash/lxd-client    | 3 ++-
 8 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/doc/instances.md b/doc/instances.md
index e845ae0b92..08149c0f24 100644
--- a/doc/instances.md
+++ b/doc/instances.md
@@ -272,6 +272,7 @@ hwaddr                  | string    | randomly assigned | 
no        | The MAC ad
 vlan                    | integer   | -                 | no        | The VLAN 
ID to attach to
 maas.subnet.ipv4        | string    | -                 | no        | MAAS 
IPv4 subnet to register the instance in
 maas.subnet.ipv6        | string    | -                 | no        | MAAS 
IPv6 subnet to register the instance in
+boot.priority           | integer   | -                 | no        | Boot 
priority for VMs (higher boots first)
 
 #### nictype: bridged
 Uses an existing bridge on the host and creates a virtual device pair to 
connect the host bridge to the instance.
@@ -297,6 +298,7 @@ security.ipv4\_filtering | boolean   | false             | 
no        | Prevent t
 security.ipv6\_filtering | boolean   | false             | no        | Prevent 
the instance from spoofing another's IPv6 address (enables mac\_filtering)
 maas.subnet.ipv4         | string    | -                 | no        | MAAS 
IPv4 subnet to register the instance in
 maas.subnet.ipv6         | string    | -                 | no        | MAAS 
IPv6 subnet to register the instance in
+boot.priority            | integer   | -                 | no        | Boot 
priority for VMs (higher boots first)
 
 #### nictype: macvlan
 Sets up a new network device based on an existing one but using a different 
MAC address.
@@ -312,6 +314,7 @@ hwaddr                  | string    | randomly assigned | 
no        | The MAC ad
 vlan                    | integer   | -                 | no        | The VLAN 
ID to attach to
 maas.subnet.ipv4        | string    | -                 | no        | MAAS 
IPv4 subnet to register the instance in
 maas.subnet.ipv6        | string    | -                 | no        | MAAS 
IPv6 subnet to register the instance in
+boot.priority           | integer   | -                 | no        | Boot 
priority for VMs (higher boots first)
 
 #### nictype: ipvlan
 Sets up a new network device based on an existing one using the same MAC 
address but a different IP.
@@ -365,6 +368,7 @@ limits.egress           | string    | -                 | 
no        | I/O limit
 limits.max              | string    | -                 | no        | Same as 
modifying both limits.ingress and limits.egress
 ipv4.routes             | string    | -                 | no        | Comma 
delimited list of IPv4 static routes to add on host to nic
 ipv6.routes             | string    | -                 | no        | Comma 
delimited list of IPv6 static routes to add on host to nic
+boot.priority           | integer   | -                 | no        | Boot 
priority for VMs (higher boots first)
 
 #### nictype: sriov
 Passes a virtual function of an SR-IOV enabled physical network device into 
the instance.
@@ -381,6 +385,7 @@ security.mac\_filtering | boolean   | false             | 
no        | Prevent th
 vlan                    | integer   | -                 | no        | The VLAN 
ID to attach to
 maas.subnet.ipv4        | string    | -                 | no        | MAAS 
IPv4 subnet to register the instance in
 maas.subnet.ipv6        | string    | -                 | no        | MAAS 
IPv6 subnet to register the instance in
+boot.priority           | integer   | -                 | no        | Boot 
priority for VMs (higher boots first)
 
 #### nictype: routed
 This NIC type is similar in operation to IPVLAN, in that it allows an instance 
to join an external network without needing to configure a bridge and shares 
the host's MAC address.
@@ -572,6 +577,7 @@ shift               | boolean   | false     | no        | 
Setup a shifting overl
 raw.mount.options   | string    | -         | no        | Filesystem specific 
mount options
 ceph.user\_name     | string    | admin     | no        | If source is ceph or 
cephfs then ceph user\_name must be specified by user for proper mount
 ceph.cluster\_name  | string    | admin     | no        | If source is ceph or 
cephfs then ceph cluster\_name must be specified by user for proper mount
+boot.priority       | integer   | -         | no        | Boot priority for 
VMs (higher boots first)
 
 ### Type: unix-char
 Unix character device entries simply make the requested character device
diff --git a/lxd/device/disk.go b/lxd/device/disk.go
index 508b31bc0a..c0fff8f6c5 100644
--- a/lxd/device/disk.go
+++ b/lxd/device/disk.go
@@ -82,6 +82,7 @@ func (d *disk) validateConfig() error {
                "raw.mount.options": shared.IsAny,
                "ceph.cluster_name": shared.IsAny,
                "ceph.user_name":    shared.IsAny,
+               "boot.priority":     shared.IsUint32,
        }
 
        // VMs don't use the "path" property, but containers need it, so if we 
are validating a profile that can
diff --git a/lxd/device/nic.go b/lxd/device/nic.go
index 7f7f942ebc..562ee7a08a 100644
--- a/lxd/device/nic.go
+++ b/lxd/device/nic.go
@@ -47,6 +47,7 @@ func nicValidationRules(requiredFields []string, 
optionalFields []string) map[st
                "ipv6.address":            NetworkValidAddressV6,
                "ipv4.routes":             NetworkValidNetworkV4List,
                "ipv6.routes":             NetworkValidNetworkV6List,
+               "boot.priority":           shared.IsUint32,
        }
 
        validators := map[string]func(value string) error{}
diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index 0428adbbd4..3ec776aeb2 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -71,6 +71,7 @@ func (d *nicBridged) validateConfig() error {
                "security.ipv6_filtering",
                "maas.subnet.ipv4",
                "maas.subnet.ipv6",
+               "boot.priority",
        }
        err := d.config.Validate(nicValidationRules(requiredFields, 
optionalFields))
        if err != nil {
diff --git a/lxd/device/nic_macvlan.go b/lxd/device/nic_macvlan.go
index fb7b87d21d..d59ad57bb0 100644
--- a/lxd/device/nic_macvlan.go
+++ b/lxd/device/nic_macvlan.go
@@ -19,7 +19,7 @@ func (d *nicMACVLAN) validateConfig() error {
        }
 
        requiredFields := []string{"parent"}
-       optionalFields := []string{"name", "mtu", "hwaddr", "vlan", 
"maas.subnet.ipv4", "maas.subnet.ipv6"}
+       optionalFields := []string{"name", "mtu", "hwaddr", "vlan", 
"maas.subnet.ipv4", "maas.subnet.ipv6", "boot.priority"}
        err := d.config.Validate(nicValidationRules(requiredFields, 
optionalFields))
        if err != nil {
                return err
diff --git a/lxd/device/nic_physical.go b/lxd/device/nic_physical.go
index 8376da3a07..ebb465b70a 100644
--- a/lxd/device/nic_physical.go
+++ b/lxd/device/nic_physical.go
@@ -26,6 +26,7 @@ func (d *nicPhysical) validateConfig() error {
                "vlan",
                "maas.subnet.ipv4",
                "maas.subnet.ipv6",
+               "boot.priority",
        }
        err := d.config.Validate(nicValidationRules(requiredFields, 
optionalFields))
        if err != nil {
diff --git a/lxd/device/nic_sriov.go b/lxd/device/nic_sriov.go
index 1079b9773f..508036d799 100644
--- a/lxd/device/nic_sriov.go
+++ b/lxd/device/nic_sriov.go
@@ -37,6 +37,7 @@ func (d *nicSRIOV) validateConfig() error {
                "security.mac_filtering",
                "maas.subnet.ipv4",
                "maas.subnet.ipv6",
+               "boot.priority",
        }
        err := d.config.Validate(nicValidationRules(requiredFields, 
optionalFields))
        if err != nil {
diff --git a/scripts/bash/lxd-client b/scripts/bash/lxd-client
index b437c10524..65de585d16 100644
--- a/scripts/bash/lxd-client
+++ b/scripts/bash/lxd-client
@@ -114,7 +114,8 @@ _have lxc && {
       security.ipv4_filtering security.ipv6_filtering vlan limits.read \
       limits.write path source optional readonly size recursive pool \
       propagation shift major minor uid gid mode required vendorid productid \
-      pci id listen connect bind nat proxy_protocol security.uid security.gid"
+      pci id listen connect bind nat proxy_protocol security.uid security.gid \
+      boot.priority"
 
     networks_keys="bridge.driver bridge.external_interfaces bridge.mode \
       bridge.mtu bridge.hwaddr dns.domain dns.mode fan.overlay_subnet fan.type 
\

From 273de74a5048c7f8f9bdb2a0cbe5e6d55de090b9 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Mon, 20 Jan 2020 19:52:57 +0000
Subject: [PATCH 4/9] lxd/container/logs: Makes log file retrieval project
 aware

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/container_logs.go | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/lxd/container_logs.go b/lxd/container_logs.go
index d093eefb35..dc1355a05c 100644
--- a/lxd/container_logs.go
+++ b/lxd/container_logs.go
@@ -9,6 +9,7 @@ import (
 
        "github.com/gorilla/mux"
 
+       "github.com/lxc/lxd/lxd/project"
        "github.com/lxc/lxd/lxd/response"
        "github.com/lxc/lxd/shared"
        "github.com/lxc/lxd/shared/version"
@@ -103,11 +104,11 @@ func containerLogGet(d *Daemon, r *http.Request) 
response.Response {
                return response.SmartError(err)
        }
 
-       project := projectParam(r)
+       projectName := projectParam(r)
        name := mux.Vars(r)["name"]
 
        // Handle requests targeted to a container on a different node
-       resp, err := ForwardedResponseIfContainerIsRemote(d, r, project, name, 
instanceType)
+       resp, err := ForwardedResponseIfContainerIsRemote(d, r, projectName, 
name, instanceType)
        if err != nil {
                return response.SmartError(err)
        }
@@ -126,7 +127,7 @@ func containerLogGet(d *Daemon, r *http.Request) 
response.Response {
        }
 
        ent := response.FileResponseEntry{
-               Path:     shared.LogPath(name, file),
+               Path:     shared.LogPath(project.Prefix(projectName, name), 
file),
                Filename: file,
        }
 

From 2115bb6456a9bc1b5b1db4c7b5e251461bd2744f Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Mon, 20 Jan 2020 19:53:21 +0000
Subject: [PATCH 5/9] lxd/container/lxc: Adds devName skipping for startCommon

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/container_lxc.go | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/lxd/container_lxc.go b/lxd/container_lxc.go
index df12b17c21..4e8f3eb3ba 100644
--- a/lxd/container_lxc.go
+++ b/lxd/container_lxc.go
@@ -2172,6 +2172,10 @@ func (c *containerLXC) startCommon() (string, []func() 
error, error) {
                        }
 
                        for _, nicItem := range runConf.NetworkInterface {
+                               if nicItem.Key == "devName" {
+                                       // Skip internal device name key, not 
used by liblxc.
+                                       continue
+                               }
                                err = lxcSetConfigItem(c.c, 
fmt.Sprintf("%s.%d.%s", networkKeyPrefix, nicID, nicItem.Key), nicItem.Value)
                                if err != nil {
                                        return "", postStartHooks, 
errors.Wrapf(err, "Failed to setup device network interface '%s'", dev.Name)

From 088246c4a70dc0e956d5c3ca50a0774be487c4ca Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Mon, 20 Jan 2020 19:53:40 +0000
Subject: [PATCH 6/9] lxd/device/config/device/runconfig: Adds DevName to
 MountEntryItem

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/device/config/device_runconfig.go | 1 +
 1 file changed, 1 insertion(+)

diff --git a/lxd/device/config/device_runconfig.go 
b/lxd/device/config/device_runconfig.go
index 744e9027fa..35b24e3cbf 100644
--- a/lxd/device/config/device_runconfig.go
+++ b/lxd/device/config/device_runconfig.go
@@ -17,6 +17,7 @@ type RunConfigItem struct {
 
 // MountEntryItem represents a single mount entry item.
 type MountEntryItem struct {
+       DevName    string   // The internal name for the device.
        DevPath    string   // Describes the block special device or remote 
filesystem to be mounted.
        TargetPath string   // Describes the mount point (target) for the 
filesystem.
        FSType     string   // Describes the type of the filesystem.

From 03874f8833c757f584526abf93c24b2a28015110 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Mon, 20 Jan 2020 19:54:49 +0000
Subject: [PATCH 7/9] lxd/device/disk: Adds DevName to MountEntryItem

Also sets TargetPath for root disk device for VMs. This will be used as root 
device indicator.

Also switches to using just MountEntryItem for VM disk configs.

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/device/disk.go | 19 +++++++++++++------
 1 file changed, 13 insertions(+), 6 deletions(-)

diff --git a/lxd/device/disk.go b/lxd/device/disk.go
index c0fff8f6c5..7fd8b50763 100644
--- a/lxd/device/disk.go
+++ b/lxd/device/disk.go
@@ -344,6 +344,7 @@ func (d *disk) startContainer() (*deviceConfig.RunConfig, 
error) {
                if sourceDevPath != "" {
                        // Instruct LXD to perform the mount.
                        runConf.Mounts = append(runConf.Mounts, 
deviceConfig.MountEntryItem{
+                               DevName:    d.name,
                                DevPath:    sourceDevPath,
                                TargetPath: relativeDestPath,
                                FSType:     "none",
@@ -364,8 +365,13 @@ func (d *disk) startVM() (*deviceConfig.RunConfig, error) {
        runConf := deviceConfig.RunConfig{}
 
        if shared.IsRootDiskDevice(d.config) {
-               // The root disk device is special as it is given the first 
device ID and boot order in VM config.
-               runConf.RootFS.Path = d.config["path"]
+               runConf.Mounts = []deviceConfig.MountEntryItem{
+                       {
+                               TargetPath: d.config["path"], // Indicator used 
that this is the root device.
+                               DevName:    d.name,
+                       },
+               }
+
                return &runConf, nil
        } else if d.config["source"] == diskSourceCloudInit {
                // This is a special virtual disk source that can be attached 
to a VM to provide cloud-init config.
@@ -376,8 +382,8 @@ func (d *disk) startVM() (*deviceConfig.RunConfig, error) {
 
                runConf.Mounts = []deviceConfig.MountEntryItem{
                        {
-                               DevPath:    isoPath,
-                               TargetPath: d.name,
+                               DevPath: isoPath,
+                               DevName: d.name,
                        },
                }
                return &runConf, nil
@@ -386,10 +392,11 @@ func (d *disk) startVM() (*deviceConfig.RunConfig, error) 
{
                if !shared.PathExists(d.config["source"]) {
                        return nil, fmt.Errorf("Cannot find disk source")
                }
+
                runConf.Mounts = []deviceConfig.MountEntryItem{
                        {
-                               DevPath:    d.config["source"],
-                               TargetPath: d.name,
+                               DevPath: d.config["source"],
+                               DevName: d.name,
                        },
                }
                return &runConf, nil

From 1670a1abd30908ee82c48d0a6cc006f6e122ec56 Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Mon, 20 Jan 2020 19:56:05 +0000
Subject: [PATCH 8/9] lxd/device: Adds devName property to network interface
 run config

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/device/infiniband_physical.go | 1 +
 lxd/device/infiniband_sriov.go    | 1 +
 lxd/device/nic_bridged.go         | 1 +
 lxd/device/nic_macvlan.go         | 1 +
 lxd/device/nic_p2p.go             | 1 +
 lxd/device/nic_physical.go        | 1 +
 lxd/device/nic_sriov.go           | 1 +
 7 files changed, 7 insertions(+)

diff --git a/lxd/device/infiniband_physical.go 
b/lxd/device/infiniband_physical.go
index 564625461a..f1ba582621 100644
--- a/lxd/device/infiniband_physical.go
+++ b/lxd/device/infiniband_physical.go
@@ -116,6 +116,7 @@ func (d *infinibandPhysical) Start() 
(*deviceConfig.RunConfig, error) {
        }
 
        runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+               {Key: "devName", Value: d.name},
                {Key: "name", Value: d.config["name"]},
                {Key: "type", Value: "phys"},
                {Key: "flags", Value: "up"},
diff --git a/lxd/device/infiniband_sriov.go b/lxd/device/infiniband_sriov.go
index f471d9419b..ea37fda93c 100644
--- a/lxd/device/infiniband_sriov.go
+++ b/lxd/device/infiniband_sriov.go
@@ -138,6 +138,7 @@ func (d *infinibandSRIOV) Start() (*deviceConfig.RunConfig, 
error) {
        }
 
        runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+               {Key: "devName", Value: d.name},
                {Key: "name", Value: d.config["name"]},
                {Key: "type", Value: "phys"},
                {Key: "flags", Value: "up"},
diff --git a/lxd/device/nic_bridged.go b/lxd/device/nic_bridged.go
index 3ec776aeb2..6359052328 100644
--- a/lxd/device/nic_bridged.go
+++ b/lxd/device/nic_bridged.go
@@ -176,6 +176,7 @@ func (d *nicBridged) Start() (*deviceConfig.RunConfig, 
error) {
 
        runConf := deviceConfig.RunConfig{}
        runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+               {Key: "devName", Value: d.name},
                {Key: "name", Value: d.config["name"]},
                {Key: "type", Value: "phys"},
                {Key: "flags", Value: "up"},
diff --git a/lxd/device/nic_macvlan.go b/lxd/device/nic_macvlan.go
index d59ad57bb0..5471bc869b 100644
--- a/lxd/device/nic_macvlan.go
+++ b/lxd/device/nic_macvlan.go
@@ -106,6 +106,7 @@ func (d *nicMACVLAN) Start() (*deviceConfig.RunConfig, 
error) {
 
        runConf := deviceConfig.RunConfig{}
        runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+               {Key: "devName", Value: d.name},
                {Key: "name", Value: d.config["name"]},
                {Key: "type", Value: "phys"},
                {Key: "flags", Value: "up"},
diff --git a/lxd/device/nic_p2p.go b/lxd/device/nic_p2p.go
index 2349039c50..6b2770218e 100644
--- a/lxd/device/nic_p2p.go
+++ b/lxd/device/nic_p2p.go
@@ -85,6 +85,7 @@ func (d *nicP2P) Start() (*deviceConfig.RunConfig, error) {
 
        runConf := deviceConfig.RunConfig{}
        runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+               {Key: "devName", Value: d.name},
                {Key: "name", Value: d.config["name"]},
                {Key: "type", Value: "phys"},
                {Key: "flags", Value: "up"},
diff --git a/lxd/device/nic_physical.go b/lxd/device/nic_physical.go
index ebb465b70a..09f4002568 100644
--- a/lxd/device/nic_physical.go
+++ b/lxd/device/nic_physical.go
@@ -111,6 +111,7 @@ func (d *nicPhysical) Start() (*deviceConfig.RunConfig, 
error) {
 
        runConf := deviceConfig.RunConfig{}
        runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+               {Key: "devName", Value: d.name},
                {Key: "name", Value: d.config["name"]},
                {Key: "type", Value: "phys"},
                {Key: "flags", Value: "up"},
diff --git a/lxd/device/nic_sriov.go b/lxd/device/nic_sriov.go
index 508036d799..7c426e01e5 100644
--- a/lxd/device/nic_sriov.go
+++ b/lxd/device/nic_sriov.go
@@ -113,6 +113,7 @@ func (d *nicSRIOV) Start() (*deviceConfig.RunConfig, error) 
{
 
        runConf := deviceConfig.RunConfig{}
        runConf.NetworkInterface = []deviceConfig.RunConfigItem{
+               {Key: "devName", Value: d.name},
                {Key: "name", Value: d.config["name"]},
                {Key: "type", Value: "phys"},
                {Key: "flags", Value: "up"},

From 1ff1c82b40ebdeaba531514259b6fa682bfe311d Mon Sep 17 00:00:00 2001
From: Thomas Parrott <thomas.parr...@canonical.com>
Date: Mon, 20 Jan 2020 19:58:11 +0000
Subject: [PATCH 9/9] lxd/instance/drivers/driver/qemu: Adds support for Disk
 and NIC device boot.priority setting

Signed-off-by: Thomas Parrott <thomas.parr...@canonical.com>
---
 lxd/instance/drivers/driver_qemu.go | 125 +++++++++++++++++-----------
 1 file changed, 76 insertions(+), 49 deletions(-)

diff --git a/lxd/instance/drivers/driver_qemu.go 
b/lxd/instance/drivers/driver_qemu.go
index 90cd4f9245..c20d3f784b 100644
--- a/lxd/instance/drivers/driver_qemu.go
+++ b/lxd/instance/drivers/driver_qemu.go
@@ -10,6 +10,7 @@ import (
        "os"
        "os/exec"
        "path/filepath"
+       "sort"
        "strconv"
        "strings"
        "sync"
@@ -1136,6 +1137,45 @@ echo "To start it now, unmount this filesystem and run: 
systemctl start lxd-agen
        return nil
 }
 
+// deviceBootPriorities returns a map keyed on device name containing the boot 
index to use.
+// Qemu tries to boot devices in order of boot index (lowest first).
+func (vm *qemu) deviceBootPriorities() (map[string]int, error) {
+       type devicePrios struct {
+               Name     string
+               BootPrio uint32
+       }
+
+       devices := []devicePrios{}
+
+       for devName, devConf := range vm.expandedDevices {
+               if devConf["type"] != "disk" && devConf["type"] != "nic" {
+                       continue
+               }
+
+               bootPrio := uint32(0) // Default to lowest priority.
+               if devConf["boot.priority"] != "" {
+                       prio, err := strconv.ParseInt(devConf["boot.priority"], 
10, 32)
+                       if err != nil {
+                               return nil, errors.Wrapf(err, "Invalid 
boot.priority for device %q", devName)
+                       }
+                       bootPrio = uint32(prio)
+               } else if devConf["path"] == "/" {
+                       bootPrio = 1 // Set boot priority of root disk higher 
than any device without a boot prio.
+               }
+
+               devices = append(devices, devicePrios{Name: devName, BootPrio: 
bootPrio})
+       }
+
+       sort.SliceStable(devices, func(i, j int) bool { return 
devices[i].BootPrio > devices[j].BootPrio })
+
+       sortedDevs := make(map[string]int, len(devices))
+       for bootIndex, dev := range devices {
+               sortedDevs[dev.Name] = bootIndex
+       }
+
+       return sortedDevs, nil
+}
+
 // generateQemuConfigFile writes the qemu config file and returns its location.
 // It writes the config file inside the VM's log path.
 func (vm *qemu) generateQemuConfigFile(qemuType string, qemuConf string, 
devConfs []*deviceConfig.RunConfig) (string, error) {
@@ -1260,22 +1300,20 @@ backend = "pty"
        }
 
        nicIndex := 0
-       driveIndex := 0
-       for _, runConf := range devConfs {
-               // Add root drive device.
-               if runConf.RootFS.Path != "" {
-                       err = vm.addRootDriveConfig(sb)
-                       if err != nil {
-                               return "", err
-                       }
-               }
+       bootIndexes, err := vm.deviceBootPriorities()
+       if err != nil {
+               return "", errors.Wrap(err, "Error calculating boot indexes")
+       }
 
+       for _, runConf := range devConfs {
                // Add drive devices.
                if len(runConf.Mounts) > 0 {
                        for _, drive := range runConf.Mounts {
-                               // Increment first so index starts at 1, as 
root drive uses index 0.
-                               driveIndex++
-                               err = vm.addDriveConfig(sb, driveIndex, drive)
+                               if drive.TargetPath == "/" {
+                                       err = vm.addRootDriveConfig(sb, 
bootIndexes, drive)
+                               } else {
+                                       err = vm.addDriveConfig(sb, 
bootIndexes, drive)
+                               }
                                if err != nil {
                                        return "", err
                                }
@@ -1284,7 +1322,7 @@ backend = "pty"
 
                // Add network device.
                if len(runConf.NetworkInterface) > 0 {
-                       err = vm.addNetDevConfig(sb, nicIndex, 
runConf.NetworkInterface)
+                       err = vm.addNetDevConfig(sb, nicIndex, bootIndexes, 
runConf.NetworkInterface)
                        if err != nil {
                                return "", err
                        }
@@ -1451,7 +1489,11 @@ mount_tag = "config"
 }
 
 // addRootDriveConfig adds the qemu config required for adding the root drive.
-func (vm *qemu) addRootDriveConfig(sb *strings.Builder) error {
+func (vm *qemu) addRootDriveConfig(sb *strings.Builder, bootIndexes 
map[string]int, rootDriveConf deviceConfig.MountEntryItem) error {
+       if rootDriveConf.TargetPath != "/" {
+               return fmt.Errorf("Non-root drive config supplied")
+       }
+
        pool, err := vm.getStoragePool()
        if err != nil {
                return err
@@ -1462,67 +1504,52 @@ func (vm *qemu) addRootDriveConfig(sb *strings.Builder) 
error {
                return err
        }
 
-       // Devices use "lxd_" prefix indicating that this is a user named 
device.
-       t := template.Must(template.New("").Parse(`
-# Root drive ("root" device)
-[drive "lxd_root"]
-file = "{{.file}}"
-format = "raw"
-if = "none"
-cache = "none"
-aio = "native"
-
-[device "dev-lxd_root"]
-driver = "scsi-hd"
-bus = "qemu_scsi.0"
-channel = "0"
-scsi-id = "0"
-lun = "1"
-drive = "lxd_root"
-bootindex = "1"
-`))
-       m := map[string]interface{}{
-               "file": rootDrivePath,
+       // Generate a new device config with the root device path expanded.
+       driveConf := deviceConfig.MountEntryItem{
+               DevName: rootDriveConf.DevName,
+               DevPath: rootDrivePath,
        }
-       return t.Execute(sb, m)
+
+       return vm.addDriveConfig(sb, bootIndexes, driveConf)
 }
 
 // addDriveConfig adds the qemu config required for adding a supplementary 
drive.
-func (vm *qemu) addDriveConfig(sb *strings.Builder, driveIndex int, driveConf 
deviceConfig.MountEntryItem) error {
-       driveName := fmt.Sprintf(driveConf.TargetPath)
+func (vm *qemu) addDriveConfig(sb *strings.Builder, bootIndexes 
map[string]int, driveConf deviceConfig.MountEntryItem) error {
+       devName := fmt.Sprintf(driveConf.DevName)
 
        // Devices use "lxd_" prefix indicating that this is a user named 
device.
        t := template.Must(template.New("").Parse(`
-# {{.driveName}} drive
-[drive "lxd_{{.driveName}}"]
+# {{.devName}} drive
+[drive "lxd_{{.devName}}"]
 file = "{{.devPath}}"
 format = "raw"
 if = "none"
 cache = "none"
 aio = "native"
 
-[device "dev-lxd_{{.driveName}}"]
+[device "dev-lxd_{{.devName}}"]
 driver = "scsi-hd"
 bus = "qemu_scsi.0"
 channel = "0"
-scsi-id = "{{.driveIndex}}"
+scsi-id = "{{.bootIndex}}"
 lun = "1"
-drive = "lxd_{{.driveName}}"
+drive = "lxd_{{.devName}}"
+bootindex = "{{.bootIndex}}"
 `))
 
        m := map[string]interface{}{
-               "driveName":  driveName,
-               "devPath":    driveConf.DevPath,
-               "driveIndex": driveIndex,
+               "devName":   devName,
+               "devPath":   driveConf.DevPath,
+               "bootIndex": bootIndexes[devName],
        }
        return t.Execute(sb, m)
 }
 
 // addNetDevConfig adds the qemu config required for adding a network device.
-func (vm *qemu) addNetDevConfig(sb *strings.Builder, nicIndex int, nicConfig 
[]deviceConfig.RunConfigItem) error {
+func (vm *qemu) addNetDevConfig(sb *strings.Builder, nicIndex int, bootIndexes 
map[string]int, nicConfig []deviceConfig.RunConfigItem) error {
        var devName, devTap, devHwaddr string
        for _, nicItem := range nicConfig {
-               if nicItem.Key == "name" {
+               if nicItem.Key == "devName" {
                        devName = nicItem.Value
                } else if nicItem.Key == "link" {
                        devTap = nicItem.Value
@@ -1563,7 +1590,7 @@ bootindex = "{{.bootIndex}}"
                "portIndex":    14 + nicIndex,
                "pcieAddr":     4 + nicIndex,
                "devHwaddr":    devHwaddr,
-               "bootIndex":    2 + nicIndex,
+               "bootIndex":    bootIndexes[devName],
        }
        return t.Execute(sb, m)
 }
_______________________________________________
lxc-devel mailing list
lxc-devel@lists.linuxcontainers.org
http://lists.linuxcontainers.org/listinfo/lxc-devel

Reply via email to