Commit 3c3ed482dc077a67903a58c9e1aedba1bb18c18a

Authored by Rusty Russell
1 parent 6d7a5d1ea3

lguest: Simplify device initialization.

We used to notify the Host every time we updated a device's status.  However,
it only really needs to know when we're resetting the device, or failed to
initialize it, or when we've finished our feature negotiation.

In particular, we used to wait for VIRTIO_CONFIG_S_DRIVER_OK in the
status byte before starting the device service threads.  But this
corresponds to the successful finish of device initialization, which
might (like virtio_blk's partition scanning) use the device.  So we
had a hack, if they used the device before we expected we started the
threads anyway.

Now we hook into the finalize_features hook in the Guest: at that
point we tell the Launcher that it can rely on the features we have
acked.  On the Launcher side, we look at the status at that point, and
start servicing the device.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>

Showing 2 changed files with 28 additions and 34 deletions Side-by-side Diff

Documentation/virtual/lguest/lguest.c
... ... @@ -1095,9 +1095,10 @@
1095 1095 warnx("Device %s configuration FAILED", dev->name);
1096 1096 if (dev->running)
1097 1097 reset_device(dev);
1098   - } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) {
1099   - if (!dev->running)
1100   - start_device(dev);
  1098 + } else {
  1099 + if (dev->running)
  1100 + err(1, "Device %s features finalized twice", dev->name);
  1101 + start_device(dev);
1101 1102 }
1102 1103 }
1103 1104  
1104 1105  
... ... @@ -1122,25 +1123,11 @@
1122 1123 return;
1123 1124 }
1124 1125  
1125   - /*
1126   - * Devices *can* be used before status is set to DRIVER_OK.
1127   - * The original plan was that they would never do this: they
1128   - * would always finish setting up their status bits before
1129   - * actually touching the virtqueues. In practice, we allowed
1130   - * them to, and they do (eg. the disk probes for partition
1131   - * tables as part of initialization).
1132   - *
1133   - * If we see this, we start the device: once it's running, we
1134   - * expect the device to catch all the notifications.
1135   - */
  1126 + /* Devices should not be used before features are finalized. */
1136 1127 for (vq = i->vq; vq; vq = vq->next) {
1137 1128 if (addr != vq->config.pfn*getpagesize())
1138 1129 continue;
1139   - if (i->running)
1140   - errx(1, "Notification on running %s", i->name);
1141   - /* This just calls create_thread() for each virtqueue */
1142   - start_device(i);
1143   - return;
  1130 + errx(1, "Notification on %s before setup!", i->name);
1144 1131 }
1145 1132 }
1146 1133  
drivers/lguest/lguest_device.c
... ... @@ -109,6 +109,17 @@
109 109 }
110 110  
111 111 /*
  112 + * To notify on reset or feature finalization, we (ab)use the NOTIFY
  113 + * hypercall, with the descriptor address of the device.
  114 + */
  115 +static void status_notify(struct virtio_device *vdev)
  116 +{
  117 + unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
  118 +
  119 + hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0);
  120 +}
  121 +
  122 +/*
112 123 * The virtio core takes the features the Host offers, and copies the ones
113 124 * supported by the driver into the vdev->features array. Once that's all
114 125 * sorted out, this routine is called so we can tell the Host which features we
... ... @@ -135,6 +146,9 @@
135 146 if (test_bit(i, vdev->features))
136 147 out_features[i / 8] |= (1 << (i % 8));
137 148 }
  149 +
  150 + /* Tell Host we've finished with this device's feature negotiation */
  151 + status_notify(vdev);
138 152 }
139 153  
140 154 /* Once they've found a field, getting a copy of it is easy. */
141 155  
142 156  
... ... @@ -168,28 +182,21 @@
168 182 return to_lgdev(vdev)->desc->status;
169 183 }
170 184  
171   -/*
172   - * To notify on status updates, we (ab)use the NOTIFY hypercall, with the
173   - * descriptor address of the device. A zero status means "reset".
174   - */
175   -static void set_status(struct virtio_device *vdev, u8 status)
176   -{
177   - unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
178   -
179   - /* We set the status. */
180   - to_lgdev(vdev)->desc->status = status;
181   - hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0);
182   -}
183   -
184 185 static void lg_set_status(struct virtio_device *vdev, u8 status)
185 186 {
186 187 BUG_ON(!status);
187   - set_status(vdev, status);
  188 + to_lgdev(vdev)->desc->status = status;
  189 +
  190 + /* Tell Host immediately if we failed. */
  191 + if (status & VIRTIO_CONFIG_S_FAILED)
  192 + status_notify(vdev);
188 193 }
189 194  
190 195 static void lg_reset(struct virtio_device *vdev)
191 196 {
192   - set_status(vdev, 0);
  197 + /* 0 status means "reset" */
  198 + to_lgdev(vdev)->desc->status = 0;
  199 + status_notify(vdev);
193 200 }
194 201  
195 202 /*