func: int vring_pop(VirtIODevice *vdev, Vring *vring,
  
                VirtQueueElement **p_elem)
  
  {
  
      struct vring_desc desc;
  
      unsigned int i, head, found = 0, num = vring->vr.num;
  
      uint16_t avail_idx, last_avail_idx;
  
      VirtQueueElement *elem = NULL;
  
      int ret;
  
  
  
      /* If there was a fatal error then refuse operation */
  
      if (vring->broken) {
  
          ret = -EFAULT;
  
          goto out;
  
      }
  
  
  
      /* Check it isn't doing very strange things with descriptor numbers. */
  
      last_avail_idx = vring->last_avail_idx;
  
      avail_idx = vring->vr.avail->idx;
  
      barrier(); /* load indices now and not again later */
  
  
  
      if (unlikely((uint16_t)(avail_idx - last_avail_idx) > num)) {
  
          error_report("Guest moved used index from %u to %u",
  
                       last_avail_idx, avail_idx);
  
          ret = -EFAULT;
  
          goto out;
  
      }
  
  
  
      /* If there's nothing new since last we looked. */
  
      if (avail_idx == last_avail_idx) {
  
          ret = -EAGAIN;
  
          goto out;
  
      }
  
  
  
      /* Only get avail ring entries after they have been exposed by guest. */
  
      smp_rmb();
  
  
  
      /* Grab the next descriptor number they're advertising, and increment
  
       * the index we've seen. */
  
      head = vring->vr.avail->ring[last_avail_idx % num];
  
  
  
      elem = g_slice_new(VirtQueueElement);
  
      elem->index = head;
  
      elem->in_num = elem->out_num = 0;
  
      
  
      /* If their number is silly, that's an error. */
  
      if (unlikely(head >= num)) {
  
          error_report("Guest says index %u > %u is available", head, num);
  
          ret = -EFAULT;
  
          goto out;
  
      }
  
  
  
      if (vdev->guest_features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
  
          vring_avail_event(&vring->vr) = vring->vr.avail->idx;
  
      }
  
  
  
      i = head;
  
      do {
  
          if (unlikely(i >= num)) {
  
              error_report("Desc index is %u > %u, head = %u", i, num, head);
  
              ret = -EFAULT;
  
              goto out;
  
          }
  
          if (unlikely(++found > num)) {
  
              error_report("Loop detected: last one at %u vq size %u head %u",
  
                           i, num, head);
  
              ret = -EFAULT;
  
              goto out;
  
          }
  
          desc = vring->vr.desc[i];
  
  
  
          /* Ensure descriptor is loaded before accessing fields */
  
          barrier();
  
  
  
          if (desc.flags & VRING_DESC_F_INDIRECT) {
  
              ret = get_indirect(vring, elem, &desc);
  
              if (ret < 0) {
  
                  goto out;
  
              }
  
              continue;
  
          }
  
  
  
          ret = get_desc(vring, elem, &desc);
  
          if (ret < 0) {
  
              goto out;
  
          }
  
  
  
          i = desc.next;
  
      } while (desc.flags & VRING_DESC_F_NEXT);
  
  
  
      /* On success, increment avail index. */
  
      vring->last_avail_idx++;
  
      *p_elem = elem;
  
      return head;
  
  
  
  out:
  
      assert(ret < 0);
  
      if (ret == -EFAULT) {
  
          vring->broken = true;
  
      }
  
      if (elem) {
  
          vring_unmap_element(elem);
  
          g_slice_free(VirtQueueElement, elem);
  
      }
  
      *p_elem = NULL;
  
      return ret;
  
  }
  