Gitweb:     
http://git.kernel.org/git/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commit;h=9f35575dfc172f0a93fb464761883c8f49599b7a
Commit:     9f35575dfc172f0a93fb464761883c8f49599b7a
Parent:     392ee1e6dd901db6c4504617476f6442ed91f72d
Author:     Eric W. Biederman <[EMAIL PROTECTED]>
AuthorDate: Thu Mar 8 13:06:13 2007 -0700
Committer:  Linus Torvalds <[EMAIL PROTECTED]>
CommitDate: Mon Mar 12 16:31:50 2007 -0700

    [PATCH] pci: Repair pci_save/restore_state so we can restore one save many 
times.
    
    Because we do not reserve space for the pci-x and pci-e state in struct
    pci dev we need to dynamically allocate it.  However because we need
    to support restore being called multiple times after a single save
    it is never safe to free the buffers we have allocated to hold the
    state.
    
    So this patch modifies the save routines to first check to see
    if we have already allocated a state buffer before allocating
    a new one.  Then the restore routines are modified to not free
    the state after restoring it.  Simple and it fixes some subtle
    error path handling bugs, that are hard to test for.
    
    Signed-off-by: Eric W. Biederman <[EMAIL PROTECTED]>
    Signed-off-by: Greg Kroah-Hartman <[EMAIL PROTECTED]>
    Acked-by: Auke Kok <[EMAIL PROTECTED]>
    Signed-off-by: Linus Torvalds <[EMAIL PROTECTED]>
---
 drivers/pci/pci.c   |   12 ++++++------
 include/linux/pci.h |    5 -----
 2 files changed, 6 insertions(+), 11 deletions(-)

diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 6048c0c..d3eab05 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -551,7 +551,9 @@ static int pci_save_pcie_state(struct pci_dev *dev)
        if (pos <= 0)
                return 0;
 
-       save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, GFP_KERNEL);
+       save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+       if (!save_state)
+               save_state = kzalloc(sizeof(*save_state) + sizeof(u16) * 4, 
GFP_KERNEL);
        if (!save_state) {
                dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
                return -ENOMEM;
@@ -582,8 +584,6 @@ static void pci_restore_pcie_state(struct pci_dev *dev)
        pci_write_config_word(dev, pos + PCI_EXP_LNKCTL, cap[i++]);
        pci_write_config_word(dev, pos + PCI_EXP_SLTCTL, cap[i++]);
        pci_write_config_word(dev, pos + PCI_EXP_RTCTL, cap[i++]);
-       pci_remove_saved_cap(save_state);
-       kfree(save_state);
 }
 
 
@@ -597,7 +597,9 @@ static int pci_save_pcix_state(struct pci_dev *dev)
        if (pos <= 0)
                return 0;
 
-       save_state = kzalloc(sizeof(*save_state) + sizeof(u16), GFP_KERNEL);
+       save_state = pci_find_saved_cap(dev, PCI_CAP_ID_EXP);
+       if (!save_state)
+               save_state = kzalloc(sizeof(*save_state) + sizeof(u16), 
GFP_KERNEL);
        if (!save_state) {
                dev_err(&dev->dev, "Out of memory in pci_save_pcie_state\n");
                return -ENOMEM;
@@ -622,8 +624,6 @@ static void pci_restore_pcix_state(struct pci_dev *dev)
        cap = (u16 *)&save_state->data[0];
 
        pci_write_config_word(dev, pos + PCI_X_CMD, cap[i++]);
-       pci_remove_saved_cap(save_state);
-       kfree(save_state);
 }
 
 
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 78417e4..481ea06 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -209,11 +209,6 @@ static inline void pci_add_saved_cap(struct pci_dev 
*pci_dev,
        hlist_add_head(&new_cap->next, &pci_dev->saved_cap_space);
 }
 
-static inline void pci_remove_saved_cap(struct pci_cap_saved_state *cap)
-{
-       hlist_del(&cap->next);
-}
-
 /*
  *  For PCI devices, the region numbers are assigned this way:
  *
-
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to