Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

lguest: make Launcher see device status updates

This brings us closer to Real Life, where we'd examine the device
features once it's set the DRIVER_OK status bit.

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

+51 -25
+35 -15
Documentation/lguest/lguest.c
··· 131 131 /* Any queues attached to this device */ 132 132 struct virtqueue *vq; 133 133 134 + /* Handle status being finalized (ie. feature bits stable). */ 135 + void (*ready)(struct device *me); 136 + 134 137 /* Device-specific data. */ 135 138 void *priv; 136 139 }; ··· 928 925 write(waker_fd, &vq->dev->fd, sizeof(vq->dev->fd)); 929 926 } 930 927 931 - /* When the Guest asks us to reset a device, it's is fairly easy. */ 932 - static void reset_device(struct device *dev) 928 + /* When the Guest tells us they updated the status field, we handle it. */ 929 + static void update_device_status(struct device *dev) 933 930 { 934 931 struct virtqueue *vq; 935 932 936 - verbose("Resetting device %s\n", dev->name); 937 - /* Clear the status. */ 938 - dev->desc->status = 0; 933 + /* This is a reset. */ 934 + if (dev->desc->status == 0) { 935 + verbose("Resetting device %s\n", dev->name); 939 936 940 - /* Clear any features they've acked. */ 941 - memset(get_feature_bits(dev) + dev->desc->feature_len, 0, 942 - dev->desc->feature_len); 937 + /* Clear any features they've acked. */ 938 + memset(get_feature_bits(dev) + dev->desc->feature_len, 0, 939 + dev->desc->feature_len); 943 940 944 - /* Zero out the virtqueues. */ 945 - for (vq = dev->vq; vq; vq = vq->next) { 946 - memset(vq->vring.desc, 0, 947 - vring_size(vq->config.num, getpagesize())); 948 - vq->last_avail_idx = 0; 941 + /* Zero out the virtqueues. */ 942 + for (vq = dev->vq; vq; vq = vq->next) { 943 + memset(vq->vring.desc, 0, 944 + vring_size(vq->config.num, getpagesize())); 945 + vq->last_avail_idx = 0; 946 + } 947 + } else if (dev->desc->status & VIRTIO_CONFIG_S_FAILED) { 948 + warnx("Device %s configuration FAILED", dev->name); 949 + } else if (dev->desc->status & VIRTIO_CONFIG_S_DRIVER_OK) { 950 + unsigned int i; 951 + 952 + verbose("Device %s OK: offered", dev->name); 953 + for (i = 0; i < dev->desc->feature_len; i++) 954 + verbose(" %08x", get_feature_bits(dev)[i]); 955 + verbose(", accepted"); 956 + for (i = 0; i < dev->desc->feature_len; i++) 957 + verbose(" %08x", get_feature_bits(dev) 958 + [dev->desc->feature_len+i]); 959 + 960 + if (dev->ready) 961 + dev->ready(dev); 949 962 } 950 963 } 951 964 ··· 973 954 974 955 /* Check each device and virtqueue. */ 975 956 for (i = devices.dev; i; i = i->next) { 976 - /* Notifications to device descriptors reset the device. */ 957 + /* Notifications to device descriptors update device status. */ 977 958 if (from_guest_phys(addr) == i->desc) { 978 - reset_device(i); 959 + update_device_status(i); 979 960 return; 980 961 } 981 962 ··· 1189 1170 dev->handle_input = handle_input; 1190 1171 dev->name = name; 1191 1172 dev->vq = NULL; 1173 + dev->ready = NULL; 1192 1174 1193 1175 /* Append to device list. Prepending to a single-linked list is 1194 1176 * easier, but the user expects the devices to be arranged on the bus
+16 -10
drivers/lguest/lguest_device.c
··· 144 144 return to_lgdev(vdev)->desc->status; 145 145 } 146 146 147 - static void lg_set_status(struct virtio_device *vdev, u8 status) 148 - { 149 - BUG_ON(!status); 150 - to_lgdev(vdev)->desc->status = status; 151 - } 152 - 153 - /* To reset the device, we (ab)use the NOTIFY hypercall, with the descriptor 154 - * address of the device. The Host will zero the status and all the 155 - * features. */ 156 - static void lg_reset(struct virtio_device *vdev) 147 + /* To notify on status updates, we (ab)use the NOTIFY hypercall, with the 148 + * descriptor address of the device. A zero status means "reset". */ 149 + static void set_status(struct virtio_device *vdev, u8 status) 157 150 { 158 151 unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices; 159 152 153 + /* We set the status. */ 154 + to_lgdev(vdev)->desc->status = status; 160 155 hcall(LHCALL_NOTIFY, (max_pfn<<PAGE_SHIFT) + offset, 0, 0); 156 + } 157 + 158 + static void lg_set_status(struct virtio_device *vdev, u8 status) 159 + { 160 + BUG_ON(!status); 161 + set_status(vdev, status); 162 + } 163 + 164 + static void lg_reset(struct virtio_device *vdev) 165 + { 166 + set_status(vdev, 0); 161 167 } 162 168 163 169 /*