PCI: Rework config space locking, add INTx masking services
Subsystems (6)
v2 cover PCI: Rework config space locking, add INTx masking services
[ Rebase of v1 over yesterday's linux-next ]
This series tries to heal the currently broken locking scheme around PCI config space accesses.
We have an interface lock out access via sysfs, but that service wrongly assumes it is only called by one instance at a time for some device. So two loops doing
echo 1 > /sys/bus/pci/devices/<some-device>/reset
in parallel will trigger a kernel BUG at the moment.
Besides synchronizing with user space, we also need to manage config space access of generic PCI drivers. They need to mask legacy interrupt lines while the specific driver runs in user space or a guest OS.
The approach taken here is provide mutex-like locking for general access - which still requires a special mechanism due to requirements of the IBM Power RAID SCSI driver. Furthermore, INTx masking is now available via the PCI core and synchronized via the internal pci_lock.
Jan Kiszka (3):
pci: Rework config space blocking services
pci: Introduce INTx check & mask API
uio: Convert uio_generic_pci to new intx masking API
drivers/pci/access.c | 76 +++++++++++++++++---------- drivers/pci/iov.c | 12 ++-- drivers/pci/pci.c | 114 ++++++++++++++++++++++++++++++++++++++++- drivers/pci/pci.h | 2 + drivers/scsi/ipr.c | 67 +++++++++++++++++++++--- drivers/scsi/ipr.h | 1 + drivers/uio/uio_pci_generic.c | 76 ++------------------------- include/linux/pci.h | 17 ++++-- 8 files changed, 248 insertions(+), 117 deletions(-)
Signature · 1 line
1.7.3.4
PATCH v2 1/3 pci: Rework config space blocking services
pci_block_user_cfg_access was designed for the use case that a single context, the IPR driver, temporarily delays user space accesses to the config space via sysfs. This assumption became invalid by the time pci_dev_reset was added as locking instance. Today, if you run two loops in parallel that reset the same device via sysfs, you end up with a kernel BUG as pci_block_user_cfg_access detect the broken assumption.
This reworks the pci_block_user_cfg_access to a sleeping service pci_cfg_access_lock and an atomic-compatible variant called pci_cfg_access_trylock. The former not only blocks user space access as before but also waits if access was already locked. The latter service just returns false in this case, allowing the caller to resolve the conflict instead of raising a BUG.
Adaptions of the ipr driver were originally written by Brian King.
--- drivers/pci/access.c | 74 ++++++++++++++++++++++++++-------------- drivers/pci/iov.c | 12 +++--- drivers/pci/pci.c | 4 +- drivers/scsi/ipr.c | 67 +++++++++++++++++++++++++++++++++---- drivers/scsi/ipr.h | 1 + drivers/uio/uio_pci_generic.c | 9 +++-- include/linux/pci.h | 14 +++++--- 7 files changed, 131 insertions(+), 50 deletions(-)
drivers/pci/access.c +48 -26
@@ -127,20 +127,20 @@ EXPORT_SYMBOL(pci_write_vpd);* We have a bit per device to indicate it's blocked and a global wait queue * for callers to sleep on until devices are unblocked. */ -static DECLARE_WAIT_QUEUE_HEAD (pci_ucfg_wait); +static DECLARE_WAIT_QUEUE_HEAD (pci_cfg_wait); -static noinline void pci_wait_ucfg(struct pci_dev *dev) +static noinline void pci_wait_cfg(struct pci_dev *dev) {DECLARE_WAITQUEUE (wait, current); -__add_wait_queue (&pci_ucfg_wait, &wait); +__add_wait_queue (&pci_cfg_wait, &wait);do {set_current_state (TASK_UNINTERRUPTIBLE );raw_spin_unlock_irq (&pci_lock);schedule ();raw_spin_lock_irq (&pci_lock); - }while (dev->block_ucfg_access); -__remove_wait_queue (&pci_ucfg_wait, &wait); + }while (dev->block_cfg_access); +__remove_wait_queue (&pci_cfg_wait, &wait); }/* Returns 0 on success, negative values indicate error. */
@@ -153,7 +153,8 @@ int pci_user_read_config_##size \ if (PCI_##size##_BAD) \return -EINVAL ; \raw_spin_lock_irq (&pci_lock); \ -if (unlikely (dev->block_ucfg_access))pci_wait_ucfg (dev); \ +if (unlikely (dev->block_cfg_access)) \ +pci_wait_cfg (dev); \ ret = dev->bus->ops->read (dev->bus, dev->devfn, \ pos,sizeof (type), &data); \raw_spin_unlock_irq (&pci_lock); \
@@ -172,7 +173,8 @@ int pci_user_write_config_##size \ if (PCI_##size##_BAD) \return -EINVAL ; \raw_spin_lock_irq (&pci_lock); \ -if (unlikely (dev->block_ucfg_access))pci_wait_ucfg (dev); \ +if (unlikely (dev->block_cfg_access)) \ +pci_wait_cfg (dev); \ ret = dev->bus->ops->write (dev->bus, dev->devfn, \ pos,sizeof (type), val); \raw_spin_unlock_irq (&pci_lock); \
@@ -401,36 +403,56 @@ int pci_vpd_truncate(struct pci_dev *dev, size_t size)EXPORT_SYMBOL (pci_vpd_truncate);/** -* pci_block_user_cfg_access - Block userspace PCI config reads/writes +* pci_cfg_access_lock - Lock PCI config reads/writes * @dev: pci device struct * -* When user access is blocked, any reads or writes to config space will -* sleep until access is unblocked again. We don't allow nesting of -* block/unblock calls. +* When access is locked, any userspace reads or writes to config +* space and concurrent lock requests will sleep until access is +* allowed via pci_cfg_access_unlocked again. */ -void pci_block_user_cfg_access (struct pci_dev *dev) +void pci_cfg_access_lock (struct pci_dev *dev) +{ +might_sleep (); + +raw_spin_lock_irq (&pci_lock); +if (dev->block_cfg_access) +pci_wait_cfg (dev); + dev->block_cfg_access =1 ; +raw_spin_unlock_irq (&pci_lock); +} +EXPORT_SYMBOL_GPL (pci_cfg_access_lock); + +/** +* pci_cfg_access_trylock - try to lock PCI config reads/writes +* @dev: pci device struct +* +* Same as pci_cfg_access_lock, but will return 0 if access is +* already locked, 1 otherwise. This function can be used from +* atomic contexts. +*/ +bool pci_cfg_access_trylock (struct pci_dev *dev) {unsigned long flags; -int was_blocked; +bool locked = true;raw_spin_lock_irqsave (&pci_lock, flags); - was_blocked = dev->block_ucfg_access; - dev->block_ucfg_access =1 ; +if (dev->block_cfg_access) + locked = false; +else + dev->block_cfg_access =1 ;raw_spin_unlock_irqrestore (&pci_lock, flags); -/* If we BUG() inside the pci_lock, we're guaranteed to hose -* the machine */ -BUG_ON (was_blocked); +return locked; } -EXPORT_SYMBOL_GPL (pci_block_user_cfg_access); +EXPORT_SYMBOL_GPL (pci_cfg_access_trylock);/** -* pci_unblock_user_cfg_access - Unblock userspace PCI config reads/writes +* pci_cfg_access_unlock - Unlock PCI config reads/writes * @dev: pci device struct * -* This function allows userspace PCI config accesses to resume. +* This function allows PCI config accesses to resume. */ -void pci_unblock_user_cfg_access (struct pci_dev *dev) +void pci_cfg_access_unlock (struct pci_dev *dev) {unsigned long flags;
@@ -438,10 +460,10 @@ void pci_unblock_user_cfg_access(struct pci_dev *dev)/* This indicates a problem in the caller, but we don't need * to kill them, unlike a double-block above. */ -WARN_ON (!dev->block_ucfg_access); +WARN_ON (!dev->block_cfg_access); - dev->block_ucfg_access =0 ; -wake_up_all (&pci_ucfg_wait); + dev->block_cfg_access =0 ; +wake_up_all (&pci_cfg_wait);raw_spin_unlock_irqrestore (&pci_lock, flags); } -EXPORT_SYMBOL_GPL (pci_unblock_user_cfg_access); +EXPORT_SYMBOL_GPL (pci_cfg_access_unlock);
drivers/pci/iov.c +6 -6
@@ -341,10 +341,10 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) } iov->ctrl |=PCI_SRIOV_CTRL_VFE |PCI_SRIOV_CTRL_MSE ; -pci_block_user_cfg_access (dev); +pci_cfg_access_lock (dev);pci_write_config_word (dev, iov->pos +PCI_SRIOV_CTRL , iov->ctrl);msleep (100 ); -pci_unblock_user_cfg_access (dev); +pci_cfg_access_unlock (dev); iov->initial = initial;if (nr_virtfn < initial)
@@ -372,10 +372,10 @@ failed:virtfn_remove (dev, j,0 ); iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE |PCI_SRIOV_CTRL_MSE ); -pci_block_user_cfg_access (dev); +pci_cfg_access_lock (dev);pci_write_config_word (dev, iov->pos +PCI_SRIOV_CTRL , iov->ctrl);ssleep (1 ); -pci_unblock_user_cfg_access (dev); +pci_cfg_access_unlock (dev);if (iov->link != dev->devfn)sysfs_remove_link (&dev->dev.kobj,"dep_link" );
@@ -398,10 +398,10 @@ static void sriov_disable(struct pci_dev *dev)virtfn_remove (dev, i,0 ); iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE |PCI_SRIOV_CTRL_MSE ); -pci_block_user_cfg_access (dev); +pci_cfg_access_lock (dev);pci_write_config_word (dev, iov->pos +PCI_SRIOV_CTRL , iov->ctrl);ssleep (1 ); -pci_unblock_user_cfg_access (dev); +pci_cfg_access_unlock (dev);if (iov->link != dev->devfn)sysfs_remove_link (&dev->dev.kobj,"dep_link" );
drivers/pci/pci.c +2 -2
@@ -2958,7 +2958,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe)might_sleep ();if (!probe) { -pci_block_user_cfg_access (dev); +pci_cfg_access_lock (dev);/* block PM suspend, driver probe, etc. */ device_lock (&dev->dev); }
@@ -2983,7 +2983,7 @@ static int pci_dev_reset(struct pci_dev *dev, int probe) done:if (!probe) {device_unlock (&dev->dev); -pci_unblock_user_cfg_access (dev); +pci_cfg_access_unlock (dev); }return rc;
drivers/scsi/ipr.c +60 -7
110 lines not on this page · raw message
drivers/scsi/ipr.h +1 -0
@@ -1387,6 +1387,7 @@ struct ipr_ioa_cfg { u8 msi_received:1; u8 sis64:1; u8 dump_timeout:1; + u8 cfg_locked:1;u8 revid;
drivers/uio/uio_pci_generic.c +5 -4
@@ -55,7 +55,8 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info)BUILD_BUG_ON (PCI_COMMAND %4 );BUILD_BUG_ON (PCI_COMMAND +2 !=PCI_STATUS ); -pci_block_user_cfg_access (pdev); +if (!pci_cfg_access_trylock (pdev)) + goto error;/* Read both command and status registers in a single 32-bit operation. * Note: we could cache the value for command and move the status read
@@ -79,7 +80,7 @@ static irqreturn_t irqhandler(int irq, struct uio_info *info) ret =IRQ_HANDLED ; done: -pci_unblock_user_cfg_access (pdev); +pci_cfg_access_lock (pdev);return ret; }
@@ -91,7 +92,7 @@ static int __devinit verify_pci_2_3(struct pci_dev *pdev)u16 orig, new;int err =0 ; -pci_block_user_cfg_access (pdev); +pci_cfg_access_lock (pdev);pci_read_config_word (pdev,PCI_COMMAND , &orig);pci_write_config_word (pdev,PCI_COMMAND , orig ^PCI_COMMAND_INTX_DISABLE );
@@ -114,7 +115,7 @@ static int __devinit verify_pci_2_3(struct pci_dev *pdev)/* Now restore the original value. */ pci_write_config_word (pdev,PCI_COMMAND , orig); err: -pci_unblock_user_cfg_access (pdev); +pci_cfg_access_unlock (pdev);return err; }
include/linux/pci.h +9 -5
@@ -308,7 +308,7 @@ struct pci_dev { unsigned int is_added:1; unsigned int is_busmaster:1; /* device is busmaster */ unsigned int no_msi:1; /* device may not use msi */ - unsigned int block_ucfg_access:1; /* userspace config space access is blocked */ + unsigned int block_cfg_access:1; /* config space access is blocked */ unsigned int broken_parity_status:1; /* Device generates false positive parity */ unsigned int irq_reroute_variant:2; /* device needs IRQ rerouting variant */ unsigned int msi_enabled:1;
@@ -1084,8 +1084,9 @@ int ht_create_irq(struct pci_dev *dev, int idx);void ht_destroy_irq (unsigned int irq);#endif /* CONFIG_HT_IRQ */ -extern void pci_block_user_cfg_access (struct pci_dev *dev); -extern void pci_unblock_user_cfg_access (struct pci_dev *dev); +extern void pci_cfg_access_lock (struct pci_dev *dev); +extern bool pci_cfg_access_trylock (struct pci_dev *dev); +extern void pci_cfg_access_unlock (struct pci_dev *dev);/* * PCI domain support. Sometimes called PCI segment (eg by ACPI),
@@ -1282,10 +1283,13 @@ static inline void pci_release_regions(struct pci_dev *dev)#define pci_dma_burst_advice (pdev, strat, strategy_parameter) do { } while (0) -static inline void pci_block_user_cfg_access (struct pci_dev *dev) +static inline void pci_block_cfg_access (struct pci_dev *dev) { } -static inline void pci_unblock_user_cfg_access (struct pci_dev *dev) +static inline int pci_block_cfg_access_in_atomic (struct pci_dev *dev) +{return 0 ; } + +static inline void pci_unblock_cfg_access (struct pci_dev *dev) { }static inline struct pci_bus *pci_find_next_bus (const struct pci_bus *from)
Signature · 1 line
1.7.3.4
Jesse Barnes
AppliedRe: [PATCH v2 1/3] pci: Rework config space blocking services
Quoted 7 lines · On Fri, 4 Nov 2011 09:45:59 +0100 Jan Kiszka <[email protected]> wrote:
pci_block_user_cfg_accesswas designed for the use case that a single context, the IPR driver, temporarily delays user space accesses to the config space via sysfs. This assumption became invalid by the timepci_dev_resetwas added as locking instance. Today, if you run two loops in parallel that reset the same device via sysfs, you end up with a kernel BUG aspci_block_user_cfg_accessdetect the broken assumption.
Quoted 8 lines
This reworks the
pci_block_user_cfg_accessto a sleeping servicepci_cfg_access_lockand an atomic-compatible variant calledpci_cfg_access_trylock. The former not only blocks user space access as before but also waits if access was already locked. The latter service just returns false in this case, allowing the caller to resolve the conflict instead of raising a BUG.Adaptions of the ipr driver were originally written by Brian King.
Applied this series to linux-next, thanks.
Signature · 1 line
Jesse Barnes, Intel Open Source Technology Center
PATCH v2 2/3 pci: Introduce INTx check & mask API
In reply to Jan KiszkaThese new PCI services allow to probe for 2.3-compliant INTx masking support and then use the feature from PCI interrupt handlers. The services are properly synchronized with concurrent config space access via sysfs or on device reset.
This enables generic PCI device drivers like uio_pci_generic or KVM's device assignment to implement the necessary kernel-side IRQ handling without any knowledge about device-specific interrupt status and control registers.
--- drivers/pci/access.c | 2 +- drivers/pci/pci.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 2 + include/linux/pci.h | 3 + 4 files changed, 116 insertions(+), 1 deletions(-)
drivers/pci/access.c +1 -1
@@ -13,7 +13,7 @@* configuration space. */ -static DEFINE_RAW_SPINLOCK (pci_lock); +DEFINE_RAW_SPINLOCK (pci_lock);/* * Wrappers for all PCI configuration access functions. They just check
drivers/pci/pci.c +110 -0
116 lines not on this page · raw message
drivers/pci/pci.h +2 -0
@@ -136,6 +136,8 @@ static inline void pci_remove_legacy_files(struct pci_bus *bus) { return; }/* Lock for read/write access to pci device and bus lists */ extern struct rw_semaphore pci_bus_sem; +extern raw_spinlock_t pci_lock; +extern unsigned int pci_pm_d3_delay;#ifdef CONFIG_PCI_MSI
include/linux/pci.h +3 -0
@@ -803,6 +803,9 @@ int __must_check pci_set_mwi(struct pci_dev *dev);int pci_try_set_mwi (struct pci_dev *dev);void pci_clear_mwi (struct pci_dev *dev);void pci_intx (struct pci_dev *dev,int enable); +bool pci_intx_mask_supported (struct pci_dev *dev); +bool pci_check_and_mask_intx (struct pci_dev *dev); +bool pci_check_and_unmask_intx (struct pci_dev *dev);void pci_msi_off (struct pci_dev *dev);int pci_set_dma_max_seg_size (struct pci_dev *dev,unsigned int size);int pci_set_dma_seg_boundary (struct pci_dev *dev,unsigned long mask);
Signature · 1 line
1.7.3.4
PATCH v2 3/3 uio: Convert uio_generic_pci to new intx masking API
In reply to Jan KiszkaThe new PCI API provides both generic probing for 2.3 masking support and check&mask in the interrupt handler.
--- drivers/uio/uio_pci_generic.c | 77 +++------------------------------------- 1 files changed, 6 insertions(+), 71 deletions(-)
drivers/uio/uio_pci_generic.c +7 -72
@@ -45,78 +45,12 @@ to_uio_pci_generic_dev(struct uio_info *info)static irqreturn_t irqhandler (int irq,struct uio_info *info) {struct uio_pci_generic_dev *gdev =to_uio_pci_generic_dev (info); -struct pci_dev *pdev = gdev->pdev; -irqreturn_t ret =IRQ_NONE ; -u32 cmd_status_dword; -u16 origcmd, newcmd, status; - -/* We do a single dword read to retrieve both command and status. -* Document assumptions that make this possible. */ -BUILD_BUG_ON (PCI_COMMAND %4 ); -BUILD_BUG_ON (PCI_COMMAND +2 !=PCI_STATUS ); - -if (!pci_cfg_access_trylock (pdev)) - goto error; - -/* Read both command and status registers in a single 32-bit operation. -* Note: we could cache the value for command and move the status read -* out of the lock if there was a way to get notified of user changes -* to command register through sysfs. Should be good for shared irqs. */ -pci_read_config_dword (pdev,PCI_COMMAND , &cmd_status_dword); - origcmd = cmd_status_dword; - status = cmd_status_dword >>16 ; - -/* Check interrupt status register to see whether our device -* triggered the interrupt. */ -if (!(status &PCI_STATUS_INTERRUPT )) - goto done; - -/* We triggered the interrupt, disable it. */ - newcmd = origcmd |PCI_COMMAND_INTX_DISABLE ; -if (newcmd != origcmd) -pci_write_config_word (pdev,PCI_COMMAND , newcmd); -/* UIO core will signal the user process. */ - ret =IRQ_HANDLED ; -done: - -pci_cfg_access_lock (pdev); -return ret; -} +if (!pci_check_and_mask_intx (gdev->pdev)) +return IRQ_NONE ; -/* Verify that the device supports Interrupt Disable bit in command register, -* per PCI 2.3, by flipping this bit and reading it back: this bit was readonly -* in PCI 2.2. */ -static int __devinit verify_pci_2_3 (struct pci_dev *pdev) -{ -u16 orig, new; -int err =0 ; - -pci_cfg_access_lock (pdev); -pci_read_config_word (pdev,PCI_COMMAND , &orig); -pci_write_config_word (pdev,PCI_COMMAND , - orig ^PCI_COMMAND_INTX_DISABLE ); -pci_read_config_word (pdev,PCI_COMMAND , &new); -/* There's no way to protect against -* hardware bugs or detect them reliably, but as long as we know -* what the value should be, let's go ahead and check it. */ -if ((new ^ orig) & ~PCI_COMMAND_INTX_DISABLE ) { - err = -EBUSY ; -dev_err (&pdev->dev,"Command changed from 0x%x to 0x%x: " -"driver or HW bug?\n" , orig, new); - goto err; - } -if (!((new ^ orig) &PCI_COMMAND_INTX_DISABLE )) { -dev_warn (&pdev->dev,"Device does not support " -"disabling interrupts: unable to bind.\n" ); - err = -ENODEV ; - goto err; - } -/* Now restore the original value. */ -pci_write_config_word (pdev,PCI_COMMAND , orig); -err: -pci_cfg_access_unlock (pdev); -return err; +/* UIO core will signal the user process. */ +return IRQ_HANDLED ; } static int __devinit probe(struct pci_dev *pdev,
@@ -139,9 +73,10 @@ static int __devinit probe(struct pci_dev *pdev,return -ENODEV ; } - err =verify_pci_2_3 (pdev); -if (err) +if (!pci_intx_mask_supported (pdev)) { + err = -ENODEV ; goto err_verify; + } gdev =kzalloc (sizeof (struct uio_pci_generic_dev ),GFP_KERNEL );if (!gdev) {
Signature · 1 line
1.7.3.4
Quoted 27 lines · Jan Kiszka
[ Rebase of v1 over yesterday's linux-next ]
This series tries to heal the currently broken locking scheme around PCI config space accesses.
We have an interface lock out access via sysfs, but that service wrongly assumes it is only called by one instance at a time for some device. So two loops doing
echo 1 > /sys/bus/pci/devices/<some-device>/reset
in parallel will trigger a kernel BUG at the moment.
Besides synchronizing with user space, we also need to manage config space access of generic PCI drivers. They need to mask legacy interrupt lines while the specific driver runs in user space or a guest OS.
The approach taken here is provide mutex-like locking for general access - which still requires a special mechanism due to requirements of the IBM Power RAID SCSI driver. Furthermore, INTx masking is now available via the PCI core and synchronized via the internal
pci_lock.Jan Kiszka (3):
pci: Rework config space blocking services
pci: Introduce INTx check & mask API
uio: Convertuio_generic_pcito new intx masking API
Quoted 10 lines
drivers/pci/access.c | 76 +++++++++++++++++---------- drivers/pci/iov.c | 12 ++-- drivers/pci/pci.c | 114 ++++++++++++++++++++++++++++++++++++++++- drivers/pci/pci.h | 2 + drivers/scsi/ipr.c | 67 +++++++++++++++++++++--- drivers/scsi/ipr.h | 1 + drivers/uio/uio_pci_generic.c | 76 ++------------------------- include/linux/pci.h | 17 ++++-- 8 files changed, 248 insertions(+), 117 deletions(-)
I just received yet another request regarding the KVM feature that depends on this. What's the status of these patches? Were they merged into some staging tree already (didn't find any traces so far)?
Thanks,
Jan
Signature · 2 lines
Siemens AG, Corporate Technology, CT T DE IT 1 Corporate Competence Center Embedded Linux
Quoted 42 lines · On Thu, 01 Dec 2011 13:04:15 +0100 Jan Kiszka <[email protected]> wrote:
Quoted 38 lines · Jan Kiszka
[ Rebase of v1 over yesterday's linux-next ]
This series tries to heal the currently broken locking scheme around PCI config space accesses.
We have an interface lock out access via sysfs, but that service wrongly assumes it is only called by one instance at a time for some device. So two loops doing
echo 1 > /sys/bus/pci/devices/<some-device>/reset
in parallel will trigger a kernel BUG at the moment.
Besides synchronizing with user space, we also need to manage config space access of generic PCI drivers. They need to mask legacy interrupt lines while the specific driver runs in user space or a guest OS.
The approach taken here is provide mutex-like locking for general access - which still requires a special mechanism due to requirements of the IBM Power RAID SCSI driver. Furthermore, INTx masking is now available via the PCI core and synchronized via the internal
pci_lock.Jan Kiszka (3):
pci: Rework config space blocking services
pci: Introduce INTx check & mask API
uio: Convertuio_generic_pcito new intx masking APIdrivers/pci/access.c | 76 +++++++++++++++++---------- drivers/pci/iov.c | 12 ++-- drivers/pci/pci.c | 114 ++++++++++++++++++++++++++++++++++++++++- drivers/pci/pci.h | 2 + drivers/scsi/ipr.c | 67 +++++++++++++++++++++--- drivers/scsi/ipr.h | 1 + drivers/uio/uio_pci_generic.c | 76 ++------------------------- include/linux/pci.h | 17 ++++-- 8 files changed, 248Quoted 2 lines
insertions(+), 117 deletions(-)
Quoted 3 lines
I just received yet another request regarding the KVM feature that depends on this. What's the status of these patches? Were they merged into some staging tree already (didn't find any traces so far)?
Yeah I think it's ok now; I'll give it one more look and pull it into -next.
Thanks,
Jesse