diff options
author | Zefan Li <lizefan@huawei.com> | 2015-10-13 20:43:23 +0800 |
---|---|---|
committer | Zefan Li <lizefan@huawei.com> | 2015-10-13 20:43:23 +0800 |
commit | 30370a66fcc80d3686e85b658147e80a70b216dc (patch) | |
tree | 326d0181560f51048cdc65292deaa992d8d2dd4c | |
parent | 1afe6fdedef22bbaaff59f875ce7fd9205a0d2c3 (diff) | |
download | linux-3.4.y-queue-30370a66fcc80d3686e85b658147e80a70b216dc.tar.gz |
Add a few fixes
4 files changed, 346 insertions, 0 deletions
diff --git a/patches/ib-qib-change-lkey-table-allocation-to-support-more-mrs.patch b/patches/ib-qib-change-lkey-table-allocation-to-support-more-mrs.patch new file mode 100644 index 0000000..6799a4d --- /dev/null +++ b/patches/ib-qib-change-lkey-table-allocation-to-support-more-mrs.patch @@ -0,0 +1,119 @@ +From 9f386b43b12b8051a610e790c74865e83a8804cd Mon Sep 17 00:00:00 2001 +From: Mike Marciniszyn <mike.marciniszyn@intel.com> +Date: Fri, 9 Oct 2015 01:12:28 +0100 +Subject: [PATCH] IB/qib: Change lkey table allocation to support more MRs + +commit d6f1c17e162b2a11e708f28fa93f2f79c164b442 upstream. + +The lkey table is allocated with with a get_user_pages() with an +order based on a number of index bits from a module parameter. + +The underlying kernel code cannot allocate that many contiguous pages. + +There is no reason the underlying memory needs to be physically +contiguous. + +This patch: +- switches the allocation/deallocation to vmalloc/vfree +- caps the number of bits to 23 to insure at least 1 generation bit + o this matches the module parameter description + +Reviewed-by: Vinit Agnihotri <vinit.abhay.agnihotri@intel.com> +Signed-off-by: Mike Marciniszyn <mike.marciniszyn@intel.com> +Signed-off-by: Doug Ledford <dledford@redhat.com> +[bwh: Backported to 3.2: + - Adjust context + - Add definition of qib_dev_warn(), added upstream by commit ddb887658970 + ("IB/qib: Convert opcode counters to per-context")] +Signed-off-by: Ben Hutchings <ben@decadent.org.uk> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + drivers/infiniband/hw/qib/qib.h | 4 ++++ + drivers/infiniband/hw/qib/qib_keys.c | 4 ++++ + drivers/infiniband/hw/qib/qib_verbs.c | 14 ++++++++++---- + drivers/infiniband/hw/qib/qib_verbs.h | 2 ++ + 4 files changed, 20 insertions(+), 4 deletions(-) + +--- a/drivers/infiniband/hw/qib/qib.h ++++ b/drivers/infiniband/hw/qib/qib.h +@@ -1429,6 +1429,10 @@ extern struct mutex qib_mutex; + qib_get_unit_name((dd)->unit), ##__VA_ARGS__); \ + } while (0) + ++#define qib_dev_warn(dd, fmt, ...) \ ++ dev_warn(&(dd)->pcidev->dev, "%s: " fmt, \ ++ qib_get_unit_name((dd)->unit), ##__VA_ARGS__) ++ + #define qib_dev_porterr(dd, port, fmt, ...) \ + do { \ + dev_err(&(dd)->pcidev->dev, "%s: IB%u:%u " fmt, \ +--- a/drivers/infiniband/hw/qib/qib_keys.c ++++ b/drivers/infiniband/hw/qib/qib_keys.c +@@ -69,6 +69,10 @@ int qib_alloc_lkey(struct qib_lkey_table + * unrestricted LKEY. + */ + rkt->gen++; ++ /* ++ * bits are capped in qib_verbs.c to insure enough bits ++ * for generation number ++ */ + mr->lkey = (r << (32 - ib_qib_lkey_table_size)) | + ((((1 << (24 - ib_qib_lkey_table_size)) - 1) & rkt->gen) + << 8); +--- a/drivers/infiniband/hw/qib/qib_verbs.c ++++ b/drivers/infiniband/hw/qib/qib_verbs.c +@@ -40,6 +40,7 @@ + #include <linux/rculist.h> + #include <linux/mm.h> + #include <linux/random.h> ++#include <linux/vmalloc.h> + + #include "qib.h" + #include "qib_common.h" +@@ -2058,10 +2059,16 @@ int qib_register_ib_device(struct qib_de + * the LKEY). The remaining bits act as a generation number or tag. + */ + spin_lock_init(&dev->lk_table.lock); ++ /* insure generation is at least 4 bits see keys.c */ ++ if (ib_qib_lkey_table_size > MAX_LKEY_TABLE_BITS) { ++ qib_dev_warn(dd, "lkey bits %u too large, reduced to %u\n", ++ ib_qib_lkey_table_size, MAX_LKEY_TABLE_BITS); ++ ib_qib_lkey_table_size = MAX_LKEY_TABLE_BITS; ++ } + dev->lk_table.max = 1 << ib_qib_lkey_table_size; + lk_tab_size = dev->lk_table.max * sizeof(*dev->lk_table.table); + dev->lk_table.table = (struct qib_mregion **) +- __get_free_pages(GFP_KERNEL, get_order(lk_tab_size)); ++ vmalloc(lk_tab_size); + if (dev->lk_table.table == NULL) { + ret = -ENOMEM; + goto err_lk; +@@ -2231,7 +2238,7 @@ err_tx: + sizeof(struct qib_pio_header), + dev->pio_hdrs, dev->pio_hdrs_phys); + err_hdrs: +- free_pages((unsigned long) dev->lk_table.table, get_order(lk_tab_size)); ++ vfree(dev->lk_table.table); + err_lk: + kfree(dev->qp_table); + err_qpt: +@@ -2285,7 +2292,6 @@ void qib_unregister_ib_device(struct qib + sizeof(struct qib_pio_header), + dev->pio_hdrs, dev->pio_hdrs_phys); + lk_tab_size = dev->lk_table.max * sizeof(*dev->lk_table.table); +- free_pages((unsigned long) dev->lk_table.table, +- get_order(lk_tab_size)); ++ vfree(dev->lk_table.table); + kfree(dev->qp_table); + } +--- a/drivers/infiniband/hw/qib/qib_verbs.h ++++ b/drivers/infiniband/hw/qib/qib_verbs.h +@@ -622,6 +622,8 @@ struct qib_qpn_table { + struct qpn_map map[QPNMAP_ENTRIES]; + }; + ++#define MAX_LKEY_TABLE_BITS 23 ++ + struct qib_lkey_table { + spinlock_t lock; /* protect changes in this struct */ + u32 next; /* next unused index (speeds search) */ diff --git a/patches/jbd2-avoid-infinite-loop-when-destroying-aborted-journal.patch b/patches/jbd2-avoid-infinite-loop-when-destroying-aborted-journal.patch new file mode 100644 index 0000000..eaaa1b5 --- /dev/null +++ b/patches/jbd2-avoid-infinite-loop-when-destroying-aborted-journal.patch @@ -0,0 +1,171 @@ +From 841df7df196237ea63233f0f9eaa41db53afd70f Mon Sep 17 00:00:00 2001 +From: Jan Kara <jack@suse.com> +Date: Tue, 28 Jul 2015 14:57:14 -0400 +Subject: jbd2: avoid infinite loop when destroying aborted journal + +commit 841df7df196237ea63233f0f9eaa41db53afd70f upstream. + +Commit 6f6a6fda2945 "jbd2: fix ocfs2 corrupt when updating journal +superblock fails" changed jbd2_cleanup_journal_tail() to return EIO +when the journal is aborted. That makes logic in +jbd2_log_do_checkpoint() bail out which is fine, except that +jbd2_journal_destroy() expects jbd2_log_do_checkpoint() to always make +a progress in cleaning the journal. Without it jbd2_journal_destroy() +just loops in an infinite loop. + +Fix jbd2_journal_destroy() to cleanup journal checkpoint lists of +jbd2_log_do_checkpoint() fails with error. + +Reported-by: Eryu Guan <guaneryu@gmail.com> +Tested-by: Eryu Guan <guaneryu@gmail.com> +Fixes: 6f6a6fda294506dfe0e3e0a253bb2d2923f28f0a +Signed-off-by: Jan Kara <jack@suse.com> +Signed-off-by: Theodore Ts'o <tytso@mit.edu> +[lizf: Backported to 3.4: adjust context] +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + fs/jbd2/checkpoint.c | 39 +++++++++++++++++++++++++++++++++------ + fs/jbd2/commit.c | 2 +- + fs/jbd2/journal.c | 11 ++++++++++- + include/linux/jbd2.h | 3 ++- + 4 files changed, 46 insertions(+), 9 deletions(-) + +--- a/fs/jbd2/checkpoint.c ++++ b/fs/jbd2/checkpoint.c +@@ -467,14 +467,14 @@ int jbd2_cleanup_journal_tail(journal_t + * journal_clean_one_cp_list + * + * Find all the written-back checkpoint buffers in the given list and +- * release them. ++ * release them. If 'destroy' is set, clean all buffers unconditionally. + * + * Called with the journal locked. + * Called with j_list_lock held. + * Returns number of buffers reaped (for debug) + */ + +-static int journal_clean_one_cp_list(struct journal_head *jh, int *released) ++static int journal_clean_one_cp_list(struct journal_head *jh, int *released, bool destroy) + { + struct journal_head *last_jh; + struct journal_head *next_jh = jh; +@@ -488,7 +488,10 @@ static int journal_clean_one_cp_list(str + do { + jh = next_jh; + next_jh = jh->b_cpnext; +- ret = __try_to_free_cp_buf(jh); ++ if (!destroy) ++ ret = __try_to_free_cp_buf(jh); ++ else ++ ret = __jbd2_journal_remove_checkpoint(jh) + 1; + if (ret) { + freed++; + if (ret == 2) { +@@ -514,12 +517,14 @@ static int journal_clean_one_cp_list(str + * + * Find all the written-back checkpoint buffers in the journal and release them. + * ++ * If 'destroy' is set, release all buffers unconditionally. ++ * + * Called with the journal locked. + * Called with j_list_lock held. + * Returns number of buffers reaped (for debug) + */ + +-int __jbd2_journal_clean_checkpoint_list(journal_t *journal) ++int __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy) + { + transaction_t *transaction, *last_transaction, *next_transaction; + int ret = 0; +@@ -535,7 +540,7 @@ int __jbd2_journal_clean_checkpoint_list + transaction = next_transaction; + next_transaction = transaction->t_cpnext; + ret += journal_clean_one_cp_list(transaction-> +- t_checkpoint_list, &released); ++ t_checkpoint_list, &released, destroy); + /* + * This function only frees up some memory if possible so we + * dont have an obligation to finish processing. Bail out if +@@ -551,7 +556,7 @@ int __jbd2_journal_clean_checkpoint_list + * we can possibly see not yet submitted buffers on io_list + */ + ret += journal_clean_one_cp_list(transaction-> +- t_checkpoint_io_list, &released); ++ t_checkpoint_io_list, &released, destroy); + if (need_resched()) + goto out; + } while (transaction != last_transaction); +@@ -560,6 +565,28 @@ out: + } + + /* ++ * Remove buffers from all checkpoint lists as journal is aborted and we just ++ * need to free memory ++ */ ++void jbd2_journal_destroy_checkpoint(journal_t *journal) ++{ ++ /* ++ * We loop because __jbd2_journal_clean_checkpoint_list() may abort ++ * early due to a need of rescheduling. ++ */ ++ while (1) { ++ spin_lock(&journal->j_list_lock); ++ if (!journal->j_checkpoint_transactions) { ++ spin_unlock(&journal->j_list_lock); ++ break; ++ } ++ __jbd2_journal_clean_checkpoint_list(journal, true); ++ spin_unlock(&journal->j_list_lock); ++ cond_resched(); ++ } ++} ++ ++/* + * journal_remove_checkpoint: called after a buffer has been committed + * to disk (either by being write-back flushed to disk, or being + * committed to the log). +--- a/fs/jbd2/commit.c ++++ b/fs/jbd2/commit.c +@@ -438,7 +438,7 @@ void jbd2_journal_commit_transaction(jou + * frees some memory + */ + spin_lock(&journal->j_list_lock); +- __jbd2_journal_clean_checkpoint_list(journal); ++ __jbd2_journal_clean_checkpoint_list(journal, false); + spin_unlock(&journal->j_list_lock); + + jbd_debug(3, "JBD2: commit phase 1\n"); +--- a/fs/jbd2/journal.c ++++ b/fs/jbd2/journal.c +@@ -1591,8 +1591,17 @@ int jbd2_journal_destroy(journal_t *jour + while (journal->j_checkpoint_transactions != NULL) { + spin_unlock(&journal->j_list_lock); + mutex_lock(&journal->j_checkpoint_mutex); +- jbd2_log_do_checkpoint(journal); ++ err = jbd2_log_do_checkpoint(journal); + mutex_unlock(&journal->j_checkpoint_mutex); ++ /* ++ * If checkpointing failed, just free the buffers to avoid ++ * looping forever ++ */ ++ if (err) { ++ jbd2_journal_destroy_checkpoint(journal); ++ spin_lock(&journal->j_list_lock); ++ break; ++ } + spin_lock(&journal->j_list_lock); + } + +--- a/include/linux/jbd2.h ++++ b/include/linux/jbd2.h +@@ -981,8 +981,9 @@ void jbd2_update_log_tail(journal_t *jou + extern void jbd2_journal_commit_transaction(journal_t *); + + /* Checkpoint list management */ +-int __jbd2_journal_clean_checkpoint_list(journal_t *journal); ++int __jbd2_journal_clean_checkpoint_list(journal_t *journal, bool destroy); + int __jbd2_journal_remove_checkpoint(struct journal_head *); ++void jbd2_journal_destroy_checkpoint(journal_t *journal); + void __jbd2_journal_insert_checkpoint(struct journal_head *, transaction_t *); + + diff --git a/patches/series b/patches/series index 6804feb..a963646 100644 --- a/patches/series +++ b/patches/series @@ -58,3 +58,6 @@ revert-drm-radeon-use-drm_calloc_ab-for-cs-relocs.patch drm-radeon-partially-revert-fix-vm_context-_page_table_end_addr-handling.patch crypto-s390-ghash-fix-incorrect-backport-of-a1cae34e23b1.patch arm-fix-incorrect-backport-of-0b59d8806a31.patch +usb-dwc3-reset-the-transfer-resource-index-on-set_interface.patch +jbd2-avoid-infinite-loop-when-destroying-aborted-journal.patch +ib-qib-change-lkey-table-allocation-to-support-more-mrs.patch diff --git a/patches/usb-dwc3-reset-the-transfer-resource-index-on-set_interface.patch b/patches/usb-dwc3-reset-the-transfer-resource-index-on-set_interface.patch new file mode 100644 index 0000000..69b9f49 --- /dev/null +++ b/patches/usb-dwc3-reset-the-transfer-resource-index-on-set_interface.patch @@ -0,0 +1,53 @@ +From aebda618718157a69c0dc0adb978d69bc2b8723c Mon Sep 17 00:00:00 2001 +From: John Youn <John.Youn@synopsys.com> +Date: Mon, 17 Sep 2001 00:00:00 -0700 +Subject: usb: dwc3: Reset the transfer resource index on SET_INTERFACE + +commit aebda618718157a69c0dc0adb978d69bc2b8723c upstream. + +This fixes an issue introduced in commit b23c843992b6 (usb: dwc3: +gadget: fix DEPSTARTCFG for non-EP0 EPs) that made sure we would +only use DEPSTARTCFG once per SetConfig. + +The trick is that we should use one DEPSTARTCFG per SetConfig *OR* +SetInterface. SetInterface was completely missed from the original +patch. + +This problem became aparent after commit 76e838c9f776 (usb: dwc3: +gadget: return error if command sent to DEPCMD register fails) +added checking of the return status of device endpoint commands. + +'Set Endpoint Transfer Resource' command was caught failing +occasionally. This is because the Transfer Resource +Index was not getting reset during a SET_INTERFACE request. + +Finally, to fix the issue, was we have to do is make sure that +our start_config_issued flag gets reset whenever we receive a +SetInterface request. + +To verify the problem (and its fix), all we have to do is run +test 9 from testusb with 'testusb -t 9 -s 2048 -a -c 5000'. + +Tested-by: Huang Rui <ray.huang@amd.com> +Tested-by: Subbaraya Sundeep Bhatta <subbaraya.sundeep.bhatta@xilinx.com> +Fixes: b23c843992b6 (usb: dwc3: gadget: fix DEPSTARTCFG for non-EP0 EPs) +Signed-off-by: John Youn <johnyoun@synopsys.com> +Signed-off-by: Felipe Balbi <balbi@ti.com> +Signed-off-by: Zefan Li <lizefan@huawei.com> +--- + drivers/usb/dwc3/ep0.c | 4 ++++ + 1 file changed, 4 insertions(+) + +--- a/drivers/usb/dwc3/ep0.c ++++ b/drivers/usb/dwc3/ep0.c +@@ -644,6 +644,10 @@ static void dwc3_ep0_xfer_complete(struc + dev_vdbg(dwc->dev, "Status Phase\n"); + dwc3_ep0_complete_req(dwc, event); + break; ++ case USB_REQ_SET_INTERFACE: ++ dwc3_trace(trace_dwc3_ep0, "USB_REQ_SET_INTERFACE"); ++ dwc->start_config_issued = false; ++ /* Fall through */ + default: + WARN(true, "UNKNOWN ep0state %d\n", dwc->ep0state); + } |