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:
parent
c84982adb2
commit
d7a8d5ed87
@ -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
|
||||
*/
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user