]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.7-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 14 Jan 2013 18:51:51 +0000 (10:51 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 14 Jan 2013 18:51:51 +0000 (10:51 -0800)
added patches:
dm-disable-write-same.patch
dm-ioctl-prevent-unsafe-change-to-dm_ioctl-data_size.patch
dm-persistent-data-rename-node-to-btree_node.patch
dm-thin-replace-dm_cell_release_singleton-with-cell_defer_except.patch
rdma-nes-fix-for-crash-when-registering-zero-length-mr-for-cq.patch
rdma-nes-fix-for-terminate-timer-crash.patch

queue-3.7/dm-disable-write-same.patch [new file with mode: 0644]
queue-3.7/dm-ioctl-prevent-unsafe-change-to-dm_ioctl-data_size.patch [new file with mode: 0644]
queue-3.7/dm-persistent-data-rename-node-to-btree_node.patch [new file with mode: 0644]
queue-3.7/dm-thin-replace-dm_cell_release_singleton-with-cell_defer_except.patch [new file with mode: 0644]
queue-3.7/rdma-nes-fix-for-crash-when-registering-zero-length-mr-for-cq.patch [new file with mode: 0644]
queue-3.7/rdma-nes-fix-for-terminate-timer-crash.patch [new file with mode: 0644]
queue-3.7/series

diff --git a/queue-3.7/dm-disable-write-same.patch b/queue-3.7/dm-disable-write-same.patch
new file mode 100644 (file)
index 0000000..5804411
--- /dev/null
@@ -0,0 +1,37 @@
+From c1a94672a830e01d58c7c7e8de530c3f136d6ff2 Mon Sep 17 00:00:00 2001
+From: Mike Snitzer <snitzer@redhat.com>
+Date: Fri, 21 Dec 2012 20:23:30 +0000
+Subject: dm: disable WRITE SAME
+
+From: Mike Snitzer <snitzer@redhat.com>
+
+commit c1a94672a830e01d58c7c7e8de530c3f136d6ff2 upstream.
+
+WRITE SAME bios are not yet handled correctly by device-mapper so
+disable their use on device-mapper devices by setting
+max_write_same_sectors to zero.
+
+As an example, a ciphertext device is incompatible because the data
+gets changed according to the location at which it written and so the
+dm crypt target cannot support it.
+
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Cc: Milan Broz <mbroz@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm-table.c |    2 ++
+ 1 file changed, 2 insertions(+)
+
+--- a/drivers/md/dm-table.c
++++ b/drivers/md/dm-table.c
+@@ -1445,6 +1445,8 @@ void dm_table_set_restrictions(struct dm
+       else
+               queue_flag_clear_unlocked(QUEUE_FLAG_NONROT, q);
++      q->limits.max_write_same_sectors = 0;
++
+       dm_table_set_integrity(t);
+       /*
diff --git a/queue-3.7/dm-ioctl-prevent-unsafe-change-to-dm_ioctl-data_size.patch b/queue-3.7/dm-ioctl-prevent-unsafe-change-to-dm_ioctl-data_size.patch
new file mode 100644 (file)
index 0000000..cb7a986
--- /dev/null
@@ -0,0 +1,62 @@
+From e910d7ebecd1aac43125944a8641b6cb1a0dfabe Mon Sep 17 00:00:00 2001
+From: Alasdair G Kergon <agk@redhat.com>
+Date: Fri, 21 Dec 2012 20:23:30 +0000
+Subject: dm ioctl: prevent unsafe change to dm_ioctl data_size
+
+From: Alasdair G Kergon <agk@redhat.com>
+
+commit e910d7ebecd1aac43125944a8641b6cb1a0dfabe upstream.
+
+Abort dm ioctl processing if userspace changes the data_size parameter
+after we validated it but before we finished copying the data buffer
+from userspace.
+
+The dm ioctl parameters are processed in the following sequence:
+ 1. ctl_ioctl() calls copy_params();
+ 2. copy_params() makes a first copy of the fixed-sized portion of the
+    userspace parameters into the local variable "tmp";
+ 3. copy_params() then validates tmp.data_size and allocates a new
+    structure big enough to hold the complete data and copies the whole
+    userspace buffer there;
+ 4. ctl_ioctl() reads userspace data the second time and copies the whole
+    buffer into the pointer "param";
+ 5. ctl_ioctl() reads param->data_size without any validation and stores it
+    in the variable "input_param_size";
+ 6. "input_param_size" is further used as the authoritative size of the
+    kernel buffer.
+
+The problem is that userspace code could change the contents of user
+memory between steps 2 and 4.  In particular, the data_size parameter
+can be changed to an invalid value after the kernel has validated it.
+This lets userspace force the kernel to access invalid kernel memory.
+
+The fix is to ensure that the size has not changed at step 4.
+
+This patch shouldn't have a security impact because CAP_SYS_ADMIN is
+required to run this code, but it should be fixed anyway.
+
+Reported-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm-ioctl.c |    8 ++++++++
+ 1 file changed, 8 insertions(+)
+
+--- a/drivers/md/dm-ioctl.c
++++ b/drivers/md/dm-ioctl.c
+@@ -1566,6 +1566,14 @@ static int copy_params(struct dm_ioctl _
+       if (copy_from_user(dmi, user, tmp.data_size))
+               goto bad;
++      /*
++       * Abort if something changed the ioctl data while it was being copied.
++       */
++      if (dmi->data_size != tmp.data_size) {
++              DMERR("rejecting ioctl: data size modified while processing parameters");
++              goto bad;
++      }
++
+       /* Wipe the user buffer so we do not return it to userspace */
+       if (secure_data && clear_user(user, tmp.data_size))
+               goto bad;
diff --git a/queue-3.7/dm-persistent-data-rename-node-to-btree_node.patch b/queue-3.7/dm-persistent-data-rename-node-to-btree_node.patch
new file mode 100644 (file)
index 0000000..427d577
--- /dev/null
@@ -0,0 +1,403 @@
+From 550929faf89e2e2cdb3e9945ea87d383989274cf Mon Sep 17 00:00:00 2001
+From: Mikulas Patocka <mpatocka@redhat.com>
+Date: Fri, 21 Dec 2012 20:23:30 +0000
+Subject: dm persistent data: rename node to btree_node
+
+From: Mikulas Patocka <mpatocka@redhat.com>
+
+commit 550929faf89e2e2cdb3e9945ea87d383989274cf upstream.
+
+This patch fixes a compilation failure on sparc32 by renaming struct node.
+
+struct node is already defined in include/linux/node.h. On sparc32, it
+happens to be included through other dependencies and persistent-data
+doesn't compile because of conflicting declarations.
+
+Signed-off-by: Mikulas Patocka <mpatocka@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/persistent-data/dm-btree-internal.h |   16 ++++----
+ drivers/md/persistent-data/dm-btree-remove.c   |   50 ++++++++++++-------------
+ drivers/md/persistent-data/dm-btree-spine.c    |    6 +--
+ drivers/md/persistent-data/dm-btree.c          |   22 +++++------
+ 4 files changed, 47 insertions(+), 47 deletions(-)
+
+--- a/drivers/md/persistent-data/dm-btree-internal.h
++++ b/drivers/md/persistent-data/dm-btree-internal.h
+@@ -36,13 +36,13 @@ struct node_header {
+       __le32 padding;
+ } __packed;
+-struct node {
++struct btree_node {
+       struct node_header header;
+       __le64 keys[0];
+ } __packed;
+-void inc_children(struct dm_transaction_manager *tm, struct node *n,
++void inc_children(struct dm_transaction_manager *tm, struct btree_node *n,
+                 struct dm_btree_value_type *vt);
+ int new_block(struct dm_btree_info *info, struct dm_block **result);
+@@ -64,7 +64,7 @@ struct ro_spine {
+ void init_ro_spine(struct ro_spine *s, struct dm_btree_info *info);
+ int exit_ro_spine(struct ro_spine *s);
+ int ro_step(struct ro_spine *s, dm_block_t new_child);
+-struct node *ro_node(struct ro_spine *s);
++struct btree_node *ro_node(struct ro_spine *s);
+ struct shadow_spine {
+       struct dm_btree_info *info;
+@@ -98,17 +98,17 @@ int shadow_root(struct shadow_spine *s);
+ /*
+  * Some inlines.
+  */
+-static inline __le64 *key_ptr(struct node *n, uint32_t index)
++static inline __le64 *key_ptr(struct btree_node *n, uint32_t index)
+ {
+       return n->keys + index;
+ }
+-static inline void *value_base(struct node *n)
++static inline void *value_base(struct btree_node *n)
+ {
+       return &n->keys[le32_to_cpu(n->header.max_entries)];
+ }
+-static inline void *value_ptr(struct node *n, uint32_t index)
++static inline void *value_ptr(struct btree_node *n, uint32_t index)
+ {
+       uint32_t value_size = le32_to_cpu(n->header.value_size);
+       return value_base(n) + (value_size * index);
+@@ -117,7 +117,7 @@ static inline void *value_ptr(struct nod
+ /*
+  * Assumes the values are suitably-aligned and converts to core format.
+  */
+-static inline uint64_t value64(struct node *n, uint32_t index)
++static inline uint64_t value64(struct btree_node *n, uint32_t index)
+ {
+       __le64 *values_le = value_base(n);
+@@ -127,7 +127,7 @@ static inline uint64_t value64(struct no
+ /*
+  * Searching for a key within a single node.
+  */
+-int lower_bound(struct node *n, uint64_t key);
++int lower_bound(struct btree_node *n, uint64_t key);
+ extern struct dm_block_validator btree_node_validator;
+--- a/drivers/md/persistent-data/dm-btree-remove.c
++++ b/drivers/md/persistent-data/dm-btree-remove.c
+@@ -53,7 +53,7 @@
+ /*
+  * Some little utilities for moving node data around.
+  */
+-static void node_shift(struct node *n, int shift)
++static void node_shift(struct btree_node *n, int shift)
+ {
+       uint32_t nr_entries = le32_to_cpu(n->header.nr_entries);
+       uint32_t value_size = le32_to_cpu(n->header.value_size);
+@@ -79,7 +79,7 @@ static void node_shift(struct node *n, i
+       }
+ }
+-static void node_copy(struct node *left, struct node *right, int shift)
++static void node_copy(struct btree_node *left, struct btree_node *right, int shift)
+ {
+       uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
+       uint32_t value_size = le32_to_cpu(left->header.value_size);
+@@ -108,7 +108,7 @@ static void node_copy(struct node *left,
+ /*
+  * Delete a specific entry from a leaf node.
+  */
+-static void delete_at(struct node *n, unsigned index)
++static void delete_at(struct btree_node *n, unsigned index)
+ {
+       unsigned nr_entries = le32_to_cpu(n->header.nr_entries);
+       unsigned nr_to_copy = nr_entries - (index + 1);
+@@ -128,7 +128,7 @@ static void delete_at(struct node *n, un
+       n->header.nr_entries = cpu_to_le32(nr_entries - 1);
+ }
+-static unsigned merge_threshold(struct node *n)
++static unsigned merge_threshold(struct btree_node *n)
+ {
+       return le32_to_cpu(n->header.max_entries) / 3;
+ }
+@@ -136,7 +136,7 @@ static unsigned merge_threshold(struct n
+ struct child {
+       unsigned index;
+       struct dm_block *block;
+-      struct node *n;
++      struct btree_node *n;
+ };
+ static struct dm_btree_value_type le64_type = {
+@@ -147,7 +147,7 @@ static struct dm_btree_value_type le64_t
+       .equal = NULL
+ };
+-static int init_child(struct dm_btree_info *info, struct node *parent,
++static int init_child(struct dm_btree_info *info, struct btree_node *parent,
+                     unsigned index, struct child *result)
+ {
+       int r, inc;
+@@ -177,7 +177,7 @@ static int exit_child(struct dm_btree_in
+       return dm_tm_unlock(info->tm, c->block);
+ }
+-static void shift(struct node *left, struct node *right, int count)
++static void shift(struct btree_node *left, struct btree_node *right, int count)
+ {
+       uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
+       uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
+@@ -203,11 +203,11 @@ static void shift(struct node *left, str
+       right->header.nr_entries = cpu_to_le32(nr_right + count);
+ }
+-static void __rebalance2(struct dm_btree_info *info, struct node *parent,
++static void __rebalance2(struct dm_btree_info *info, struct btree_node *parent,
+                        struct child *l, struct child *r)
+ {
+-      struct node *left = l->n;
+-      struct node *right = r->n;
++      struct btree_node *left = l->n;
++      struct btree_node *right = r->n;
+       uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
+       uint32_t nr_right = le32_to_cpu(right->header.nr_entries);
+       unsigned threshold = 2 * merge_threshold(left) + 1;
+@@ -239,7 +239,7 @@ static int rebalance2(struct shadow_spin
+                     unsigned left_index)
+ {
+       int r;
+-      struct node *parent;
++      struct btree_node *parent;
+       struct child left, right;
+       parent = dm_block_data(shadow_current(s));
+@@ -270,9 +270,9 @@ static int rebalance2(struct shadow_spin
+  * in right, then rebalance2.  This wastes some cpu, but I want something
+  * simple atm.
+  */
+-static void delete_center_node(struct dm_btree_info *info, struct node *parent,
++static void delete_center_node(struct dm_btree_info *info, struct btree_node *parent,
+                              struct child *l, struct child *c, struct child *r,
+-                             struct node *left, struct node *center, struct node *right,
++                             struct btree_node *left, struct btree_node *center, struct btree_node *right,
+                              uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
+ {
+       uint32_t max_entries = le32_to_cpu(left->header.max_entries);
+@@ -301,9 +301,9 @@ static void delete_center_node(struct dm
+ /*
+  * Redistributes entries among 3 sibling nodes.
+  */
+-static void redistribute3(struct dm_btree_info *info, struct node *parent,
++static void redistribute3(struct dm_btree_info *info, struct btree_node *parent,
+                         struct child *l, struct child *c, struct child *r,
+-                        struct node *left, struct node *center, struct node *right,
++                        struct btree_node *left, struct btree_node *center, struct btree_node *right,
+                         uint32_t nr_left, uint32_t nr_center, uint32_t nr_right)
+ {
+       int s;
+@@ -343,12 +343,12 @@ static void redistribute3(struct dm_btre
+       *key_ptr(parent, r->index) = right->keys[0];
+ }
+-static void __rebalance3(struct dm_btree_info *info, struct node *parent,
++static void __rebalance3(struct dm_btree_info *info, struct btree_node *parent,
+                        struct child *l, struct child *c, struct child *r)
+ {
+-      struct node *left = l->n;
+-      struct node *center = c->n;
+-      struct node *right = r->n;
++      struct btree_node *left = l->n;
++      struct btree_node *center = c->n;
++      struct btree_node *right = r->n;
+       uint32_t nr_left = le32_to_cpu(left->header.nr_entries);
+       uint32_t nr_center = le32_to_cpu(center->header.nr_entries);
+@@ -371,7 +371,7 @@ static int rebalance3(struct shadow_spin
+                     unsigned left_index)
+ {
+       int r;
+-      struct node *parent = dm_block_data(shadow_current(s));
++      struct btree_node *parent = dm_block_data(shadow_current(s));
+       struct child left, center, right;
+       /*
+@@ -421,7 +421,7 @@ static int get_nr_entries(struct dm_tran
+ {
+       int r;
+       struct dm_block *block;
+-      struct node *n;
++      struct btree_node *n;
+       r = dm_tm_read_lock(tm, b, &btree_node_validator, &block);
+       if (r)
+@@ -438,7 +438,7 @@ static int rebalance_children(struct sha
+ {
+       int i, r, has_left_sibling, has_right_sibling;
+       uint32_t child_entries;
+-      struct node *n;
++      struct btree_node *n;
+       n = dm_block_data(shadow_current(s));
+@@ -483,7 +483,7 @@ static int rebalance_children(struct sha
+       return r;
+ }
+-static int do_leaf(struct node *n, uint64_t key, unsigned *index)
++static int do_leaf(struct btree_node *n, uint64_t key, unsigned *index)
+ {
+       int i = lower_bound(n, key);
+@@ -506,7 +506,7 @@ static int remove_raw(struct shadow_spin
+                     uint64_t key, unsigned *index)
+ {
+       int i = *index, r;
+-      struct node *n;
++      struct btree_node *n;
+       for (;;) {
+               r = shadow_step(s, root, vt);
+@@ -556,7 +556,7 @@ int dm_btree_remove(struct dm_btree_info
+       unsigned level, last_level = info->levels - 1;
+       int index = 0, r = 0;
+       struct shadow_spine spine;
+-      struct node *n;
++      struct btree_node *n;
+       init_shadow_spine(&spine, info);
+       for (level = 0; level < info->levels; level++) {
+--- a/drivers/md/persistent-data/dm-btree-spine.c
++++ b/drivers/md/persistent-data/dm-btree-spine.c
+@@ -23,7 +23,7 @@ static void node_prepare_for_write(struc
+                                  struct dm_block *b,
+                                  size_t block_size)
+ {
+-      struct node *n = dm_block_data(b);
++      struct btree_node *n = dm_block_data(b);
+       struct node_header *h = &n->header;
+       h->blocknr = cpu_to_le64(dm_block_location(b));
+@@ -38,7 +38,7 @@ static int node_check(struct dm_block_va
+                     struct dm_block *b,
+                     size_t block_size)
+ {
+-      struct node *n = dm_block_data(b);
++      struct btree_node *n = dm_block_data(b);
+       struct node_header *h = &n->header;
+       size_t value_size;
+       __le32 csum_disk;
+@@ -164,7 +164,7 @@ int ro_step(struct ro_spine *s, dm_block
+       return r;
+ }
+-struct node *ro_node(struct ro_spine *s)
++struct btree_node *ro_node(struct ro_spine *s)
+ {
+       struct dm_block *block;
+--- a/drivers/md/persistent-data/dm-btree.c
++++ b/drivers/md/persistent-data/dm-btree.c
+@@ -38,7 +38,7 @@ static void array_insert(void *base, siz
+ /*----------------------------------------------------------------*/
+ /* makes the assumption that no two keys are the same. */
+-static int bsearch(struct node *n, uint64_t key, int want_hi)
++static int bsearch(struct btree_node *n, uint64_t key, int want_hi)
+ {
+       int lo = -1, hi = le32_to_cpu(n->header.nr_entries);
+@@ -58,12 +58,12 @@ static int bsearch(struct node *n, uint6
+       return want_hi ? hi : lo;
+ }
+-int lower_bound(struct node *n, uint64_t key)
++int lower_bound(struct btree_node *n, uint64_t key)
+ {
+       return bsearch(n, key, 0);
+ }
+-void inc_children(struct dm_transaction_manager *tm, struct node *n,
++void inc_children(struct dm_transaction_manager *tm, struct btree_node *n,
+                 struct dm_btree_value_type *vt)
+ {
+       unsigned i;
+@@ -77,7 +77,7 @@ void inc_children(struct dm_transaction_
+                       vt->inc(vt->context, value_ptr(n, i));
+ }
+-static int insert_at(size_t value_size, struct node *node, unsigned index,
++static int insert_at(size_t value_size, struct btree_node *node, unsigned index,
+                     uint64_t key, void *value)
+                     __dm_written_to_disk(value)
+ {
+@@ -122,7 +122,7 @@ int dm_btree_empty(struct dm_btree_info
+ {
+       int r;
+       struct dm_block *b;
+-      struct node *n;
++      struct btree_node *n;
+       size_t block_size;
+       uint32_t max_entries;
+@@ -154,7 +154,7 @@ EXPORT_SYMBOL_GPL(dm_btree_empty);
+ #define MAX_SPINE_DEPTH 64
+ struct frame {
+       struct dm_block *b;
+-      struct node *n;
++      struct btree_node *n;
+       unsigned level;
+       unsigned nr_children;
+       unsigned current_child;
+@@ -295,7 +295,7 @@ EXPORT_SYMBOL_GPL(dm_btree_del);
+ /*----------------------------------------------------------------*/
+ static int btree_lookup_raw(struct ro_spine *s, dm_block_t block, uint64_t key,
+-                          int (*search_fn)(struct node *, uint64_t),
++                          int (*search_fn)(struct btree_node *, uint64_t),
+                           uint64_t *result_key, void *v, size_t value_size)
+ {
+       int i, r;
+@@ -406,7 +406,7 @@ static int btree_split_sibling(struct sh
+       size_t size;
+       unsigned nr_left, nr_right;
+       struct dm_block *left, *right, *parent;
+-      struct node *ln, *rn, *pn;
++      struct btree_node *ln, *rn, *pn;
+       __le64 location;
+       left = shadow_current(s);
+@@ -491,7 +491,7 @@ static int btree_split_beneath(struct sh
+       size_t size;
+       unsigned nr_left, nr_right;
+       struct dm_block *left, *right, *new_parent;
+-      struct node *pn, *ln, *rn;
++      struct btree_node *pn, *ln, *rn;
+       __le64 val;
+       new_parent = shadow_current(s);
+@@ -576,7 +576,7 @@ static int btree_insert_raw(struct shado
+                           uint64_t key, unsigned *index)
+ {
+       int r, i = *index, top = 1;
+-      struct node *node;
++      struct btree_node *node;
+       for (;;) {
+               r = shadow_step(s, root, vt);
+@@ -643,7 +643,7 @@ static int insert(struct dm_btree_info *
+       unsigned level, index = -1, last_level = info->levels - 1;
+       dm_block_t block = root;
+       struct shadow_spine spine;
+-      struct node *n;
++      struct btree_node *n;
+       struct dm_btree_value_type le64_type;
+       le64_type.context = NULL;
diff --git a/queue-3.7/dm-thin-replace-dm_cell_release_singleton-with-cell_defer_except.patch b/queue-3.7/dm-thin-replace-dm_cell_release_singleton-with-cell_defer_except.patch
new file mode 100644 (file)
index 0000000..edb3278
--- /dev/null
@@ -0,0 +1,183 @@
+From b7ca9c9273e5eebd63880dd8a6e4e5c18fc7901d Mon Sep 17 00:00:00 2001
+From: Joe Thornber <ejt@redhat.com>
+Date: Fri, 21 Dec 2012 20:23:31 +0000
+Subject: dm thin: replace dm_cell_release_singleton with cell_defer_except
+
+From: Joe Thornber <ejt@redhat.com>
+
+commit b7ca9c9273e5eebd63880dd8a6e4e5c18fc7901d upstream.
+
+Change existing users of the function dm_cell_release_singleton to share
+cell_defer_except instead, and then remove the now-unused function.
+
+Everywhere that calls dm_cell_release_singleton, the bio in question
+is the holder of the cell.
+
+If there are no non-holder entries in the cell then cell_defer_except
+behaves exactly like dm_cell_release_singleton.  Conversely, if there
+*are* non-holder entries then dm_cell_release_singleton must not be used
+because those entries would need to be deferred.
+
+Consequently, it is safe to replace use of dm_cell_release_singleton
+with cell_defer_except.
+
+This patch is a pre-requisite for "dm thin: fix race between
+simultaneous io and discards to same block".
+
+Signed-off-by: Joe Thornber <ejt@redhat.com>
+Signed-off-by: Mike Snitzer <snitzer@redhat.com>
+Signed-off-by: Alasdair G Kergon <agk@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/md/dm-bio-prison.c |   25 -------------------------
+ drivers/md/dm-bio-prison.h |    1 -
+ drivers/md/dm-thin.c       |   25 ++++++++++++-------------
+ 3 files changed, 12 insertions(+), 39 deletions(-)
+
+--- a/drivers/md/dm-bio-prison.c
++++ b/drivers/md/dm-bio-prison.c
+@@ -208,31 +208,6 @@ void dm_cell_release(struct dm_bio_priso
+ EXPORT_SYMBOL_GPL(dm_cell_release);
+ /*
+- * There are a couple of places where we put a bio into a cell briefly
+- * before taking it out again.  In these situations we know that no other
+- * bio may be in the cell.  This function releases the cell, and also does
+- * a sanity check.
+- */
+-static void __cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio)
+-{
+-      BUG_ON(cell->holder != bio);
+-      BUG_ON(!bio_list_empty(&cell->bios));
+-
+-      __cell_release(cell, NULL);
+-}
+-
+-void dm_cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio)
+-{
+-      unsigned long flags;
+-      struct dm_bio_prison *prison = cell->prison;
+-
+-      spin_lock_irqsave(&prison->lock, flags);
+-      __cell_release_singleton(cell, bio);
+-      spin_unlock_irqrestore(&prison->lock, flags);
+-}
+-EXPORT_SYMBOL_GPL(dm_cell_release_singleton);
+-
+-/*
+  * Sometimes we don't want the holder, just the additional bios.
+  */
+ static void __cell_release_no_holder(struct dm_bio_prison_cell *cell, struct bio_list *inmates)
+--- a/drivers/md/dm-bio-prison.h
++++ b/drivers/md/dm-bio-prison.h
+@@ -44,7 +44,6 @@ int dm_bio_detain(struct dm_bio_prison *
+                 struct bio *inmate, struct dm_bio_prison_cell **ref);
+ void dm_cell_release(struct dm_bio_prison_cell *cell, struct bio_list *bios);
+-void dm_cell_release_singleton(struct dm_bio_prison_cell *cell, struct bio *bio); // FIXME: bio arg not needed
+ void dm_cell_release_no_holder(struct dm_bio_prison_cell *cell, struct bio_list *inmates);
+ void dm_cell_error(struct dm_bio_prison_cell *cell);
+--- a/drivers/md/dm-thin.c
++++ b/drivers/md/dm-thin.c
+@@ -513,8 +513,7 @@ static void cell_defer(struct thin_c *tc
+ }
+ /*
+- * Same as cell_defer above, except it omits one particular detainee,
+- * a write bio that covers the block and has already been processed.
++ * Same as cell_defer except it omits the original holder of the cell.
+  */
+ static void cell_defer_except(struct thin_c *tc, struct dm_bio_prison_cell *cell)
+ {
+@@ -936,7 +935,7 @@ static void process_discard(struct thin_
+                */
+               build_data_key(tc->td, lookup_result.block, &key2);
+               if (dm_bio_detain(tc->pool->prison, &key2, bio, &cell2)) {
+-                      dm_cell_release_singleton(cell, bio);
++                      cell_defer_except(tc, cell);
+                       break;
+               }
+@@ -967,8 +966,8 @@ static void process_discard(struct thin_
+                        * a block boundary.  So we submit the discard of a
+                        * partial block appropriately.
+                        */
+-                      dm_cell_release_singleton(cell, bio);
+-                      dm_cell_release_singleton(cell2, bio);
++                      cell_defer_except(tc, cell);
++                      cell_defer_except(tc, cell2);
+                       if ((!lookup_result.shared) && pool->pf.discard_passdown)
+                               remap_and_issue(tc, bio, lookup_result.block);
+                       else
+@@ -980,13 +979,13 @@ static void process_discard(struct thin_
+               /*
+                * It isn't provisioned, just forget it.
+                */
+-              dm_cell_release_singleton(cell, bio);
++              cell_defer_except(tc, cell);
+               bio_endio(bio, 0);
+               break;
+       default:
+               DMERR("discard: find block unexpectedly returned %d", r);
+-              dm_cell_release_singleton(cell, bio);
++              cell_defer_except(tc, cell);
+               bio_io_error(bio);
+               break;
+       }
+@@ -1041,7 +1040,7 @@ static void process_shared_bio(struct th
+               h->shared_read_entry = dm_deferred_entry_inc(pool->shared_read_ds);
+-              dm_cell_release_singleton(cell, bio);
++              cell_defer_except(tc, cell);
+               remap_and_issue(tc, bio, lookup_result->block);
+       }
+ }
+@@ -1056,7 +1055,7 @@ static void provision_block(struct thin_
+        * Remap empty bios (flushes) immediately, without provisioning.
+        */
+       if (!bio->bi_size) {
+-              dm_cell_release_singleton(cell, bio);
++              cell_defer_except(tc, cell);
+               remap_and_issue(tc, bio, 0);
+               return;
+       }
+@@ -1066,7 +1065,7 @@ static void provision_block(struct thin_
+        */
+       if (bio_data_dir(bio) == READ) {
+               zero_fill_bio(bio);
+-              dm_cell_release_singleton(cell, bio);
++              cell_defer_except(tc, cell);
+               bio_endio(bio, 0);
+               return;
+       }
+@@ -1120,7 +1119,7 @@ static void process_bio(struct thin_c *t
+                * TODO: this will probably have to change when discard goes
+                * back in.
+                */
+-              dm_cell_release_singleton(cell, bio);
++              cell_defer_except(tc, cell);
+               if (lookup_result.shared)
+                       process_shared_bio(tc, bio, block, &lookup_result);
+@@ -1130,7 +1129,7 @@ static void process_bio(struct thin_c *t
+       case -ENODATA:
+               if (bio_data_dir(bio) == READ && tc->origin_dev) {
+-                      dm_cell_release_singleton(cell, bio);
++                      cell_defer_except(tc, cell);
+                       remap_to_origin_and_issue(tc, bio);
+               } else
+                       provision_block(tc, bio, block, cell);
+@@ -1138,7 +1137,7 @@ static void process_bio(struct thin_c *t
+       default:
+               DMERR("dm_thin_find_block() failed, error = %d", r);
+-              dm_cell_release_singleton(cell, bio);
++              cell_defer_except(tc, cell);
+               bio_io_error(bio);
+               break;
+       }
diff --git a/queue-3.7/rdma-nes-fix-for-crash-when-registering-zero-length-mr-for-cq.patch b/queue-3.7/rdma-nes-fix-for-crash-when-registering-zero-length-mr-for-cq.patch
new file mode 100644 (file)
index 0000000..a050d6d
--- /dev/null
@@ -0,0 +1,32 @@
+From 7d9c199a55200c9b9fcad08e150470d02fb385be Mon Sep 17 00:00:00 2001
+From: Tatyana Nikolova <Tatyana.E.Nikolova@intel.com>
+Date: Thu, 6 Dec 2012 20:05:02 +0000
+Subject: RDMA/nes: Fix for crash when registering zero length MR for CQ
+
+From: Tatyana Nikolova <Tatyana.E.Nikolova@intel.com>
+
+commit 7d9c199a55200c9b9fcad08e150470d02fb385be upstream.
+
+Signed-off-by: Tatyana Nikolova <Tatyana.E.Nikolova@intel.com>
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+Signed-off-by: CAI Qian <caiqian@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/hw/nes/nes_verbs.c |    5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/drivers/infiniband/hw/nes/nes_verbs.c
++++ b/drivers/infiniband/hw/nes/nes_verbs.c
+@@ -2559,6 +2559,11 @@ static struct ib_mr *nes_reg_user_mr(str
+                       return ibmr;
+               case IWNES_MEMREG_TYPE_QP:
+               case IWNES_MEMREG_TYPE_CQ:
++                      if (!region->length) {
++                              nes_debug(NES_DBG_MR, "Unable to register zero length region for CQ\n");
++                              ib_umem_release(region);
++                              return ERR_PTR(-EINVAL);
++                      }
+                       nespbl = kzalloc(sizeof(*nespbl), GFP_KERNEL);
+                       if (!nespbl) {
+                               nes_debug(NES_DBG_MR, "Unable to allocate PBL\n");
diff --git a/queue-3.7/rdma-nes-fix-for-terminate-timer-crash.patch b/queue-3.7/rdma-nes-fix-for-terminate-timer-crash.patch
new file mode 100644 (file)
index 0000000..2c698ac
--- /dev/null
@@ -0,0 +1,84 @@
+From 7bfcfa51c35cdd2d37e0d70fc11790642dd11fb3 Mon Sep 17 00:00:00 2001
+From: Tatyana Nikolova <Tatyana.E.Nikolova@intel.com>
+Date: Thu, 6 Dec 2012 19:58:27 +0000
+Subject: RDMA/nes: Fix for terminate timer crash
+
+From: Tatyana Nikolova <Tatyana.E.Nikolova@intel.com>
+
+commit 7bfcfa51c35cdd2d37e0d70fc11790642dd11fb3 upstream.
+
+The terminate timer needs to be initialized just once.
+
+Signed-off-by: Tatyana Nikolova <Tatyana.E.Nikolova@intel.com>
+Signed-off-by: Roland Dreier <roland@purestorage.com>
+Signed-off-by: CAI Qian <caiqian@redhat.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ drivers/infiniband/hw/nes/nes.h       |    1 +
+ drivers/infiniband/hw/nes/nes_hw.c    |    9 ++-------
+ drivers/infiniband/hw/nes/nes_verbs.c |    4 +++-
+ 3 files changed, 6 insertions(+), 8 deletions(-)
+
+--- a/drivers/infiniband/hw/nes/nes.h
++++ b/drivers/infiniband/hw/nes/nes.h
+@@ -532,6 +532,7 @@ void nes_iwarp_ce_handler(struct nes_dev
+ int nes_destroy_cqp(struct nes_device *);
+ int nes_nic_cm_xmit(struct sk_buff *, struct net_device *);
+ void nes_recheck_link_status(struct work_struct *work);
++void nes_terminate_timeout(unsigned long context);
+ /* nes_nic.c */
+ struct net_device *nes_netdev_init(struct nes_device *, void __iomem *);
+--- a/drivers/infiniband/hw/nes/nes_hw.c
++++ b/drivers/infiniband/hw/nes/nes_hw.c
+@@ -75,7 +75,6 @@ static void nes_process_iwarp_aeqe(struc
+ static void process_critical_error(struct nes_device *nesdev);
+ static void nes_process_mac_intr(struct nes_device *nesdev, u32 mac_number);
+ static unsigned int nes_reset_adapter_ne020(struct nes_device *nesdev, u8 *OneG_Mode);
+-static void nes_terminate_timeout(unsigned long context);
+ static void nes_terminate_start_timer(struct nes_qp *nesqp);
+ #ifdef CONFIG_INFINIBAND_NES_DEBUG
+@@ -3520,7 +3519,7 @@ static void nes_terminate_received(struc
+ }
+ /* Timeout routine in case terminate fails to complete */
+-static void nes_terminate_timeout(unsigned long context)
++void nes_terminate_timeout(unsigned long context)
+ {
+       struct nes_qp *nesqp = (struct nes_qp *)(unsigned long)context;
+@@ -3530,11 +3529,7 @@ static void nes_terminate_timeout(unsign
+ /* Set a timer in case hw cannot complete the terminate sequence */
+ static void nes_terminate_start_timer(struct nes_qp *nesqp)
+ {
+-      init_timer(&nesqp->terminate_timer);
+-      nesqp->terminate_timer.function = nes_terminate_timeout;
+-      nesqp->terminate_timer.expires = jiffies + HZ;
+-      nesqp->terminate_timer.data = (unsigned long)nesqp;
+-      add_timer(&nesqp->terminate_timer);
++      mod_timer(&nesqp->terminate_timer, (jiffies + HZ));
+ }
+ /**
+--- a/drivers/infiniband/hw/nes/nes_verbs.c
++++ b/drivers/infiniband/hw/nes/nes_verbs.c
+@@ -1404,6 +1404,9 @@ static struct ib_qp *nes_create_qp(struc
+       }
+       nesqp->sig_all = (init_attr->sq_sig_type == IB_SIGNAL_ALL_WR);
++      init_timer(&nesqp->terminate_timer);
++      nesqp->terminate_timer.function = nes_terminate_timeout;
++      nesqp->terminate_timer.data = (unsigned long)nesqp;
+       /* update the QP table */
+       nesdev->nesadapter->qp_table[nesqp->hwqp.qp_id-NES_FIRST_QPN] = nesqp;
+@@ -1413,7 +1416,6 @@ static struct ib_qp *nes_create_qp(struc
+       return &nesqp->ibqp;
+ }
+-
+ /**
+  * nes_clean_cq
+  */
index 1ad6a1c811bb1766faf52786c076a7c620db3a74..b62f37c2128f692a49befec7a21c4b9f548ea6ee 100644 (file)
@@ -86,3 +86,9 @@ drm-prime-drop-reference-on-imported-dma-buf-come-from-gem.patch
 drm-only-evict-the-blocks-required-to-create-the-requested-hole.patch
 drm-i915-only-increment-the-user-pin-count-after-successfully-pinning-the-bo.patch
 drm-i915-revert-shrinker-changes-from-track-unbound-pages.patch
+rdma-nes-fix-for-crash-when-registering-zero-length-mr-for-cq.patch
+rdma-nes-fix-for-terminate-timer-crash.patch
+dm-disable-write-same.patch
+dm-persistent-data-rename-node-to-btree_node.patch
+dm-ioctl-prevent-unsafe-change-to-dm_ioctl-data_size.patch
+dm-thin-replace-dm_cell_release_singleton-with-cell_defer_except.patch