vfio: Add capability chain helpers

Allow sub-modules to easily reallocate a buffer for managing
capability chains for info ioctls.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
Alex Williamson 2016-02-22 16:02:33 -07:00
parent c84982adb2
commit d7a8d5ed87
2 changed files with 65 additions and 0 deletions

View File

@ -1728,6 +1728,60 @@ long vfio_external_check_extension(struct vfio_group *group, unsigned long arg)
}
EXPORT_SYMBOL_GPL(vfio_external_check_extension);
/**
* Sub-module support
*/
/*
* Helper for managing a buffer of info chain capabilities, allocate or
* reallocate a buffer with additional @size, filling in @id and @version
* of the capability. A pointer to the new capability is returned.
*
* NB. The chain is based at the head of the buffer, so new entries are
* added to the tail, vfio_info_cap_shift() should be called to fixup the
* next offsets prior to copying to the user buffer.
*/
struct vfio_info_cap_header *vfio_info_cap_add(struct vfio_info_cap *caps,
size_t size, u16 id, u16 version)
{
void *buf;
struct vfio_info_cap_header *header, *tmp;
buf = krealloc(caps->buf, caps->size + size, GFP_KERNEL);
if (!buf) {
kfree(caps->buf);
caps->size = 0;
return ERR_PTR(-ENOMEM);
}
caps->buf = buf;
header = buf + caps->size;
/* Eventually copied to user buffer, zero */
memset(header, 0, size);
header->id = id;
header->version = version;
/* Add to the end of the capability chain */
for (tmp = caps->buf; tmp->next; tmp = (void *)tmp + tmp->next)
; /* nothing */
tmp->next = caps->size;
caps->size += size;
return header;
}
EXPORT_SYMBOL_GPL(vfio_info_cap_add);
void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset)
{
struct vfio_info_cap_header *tmp;
for (tmp = caps->buf; tmp->next; tmp = (void *)tmp + tmp->next - offset)
tmp->next += offset;
}
EXPORT_SYMBOL_GPL(vfio_info_cap_shift);
/**
* Module/class support
*/

View File

@ -92,6 +92,17 @@ extern int vfio_external_user_iommu_id(struct vfio_group *group);
extern long vfio_external_check_extension(struct vfio_group *group,
unsigned long arg);
/*
* Sub-module helpers
*/
struct vfio_info_cap {
struct vfio_info_cap_header *buf;
size_t size;
};
extern struct vfio_info_cap_header *vfio_info_cap_add(
struct vfio_info_cap *caps, size_t size, u16 id, u16 version);
extern void vfio_info_cap_shift(struct vfio_info_cap *caps, size_t offset);
struct pci_dev;
#ifdef CONFIG_EEH
extern void vfio_spapr_pci_eeh_open(struct pci_dev *pdev);