diff --git a/include/linux/crush/crush.h b/include/linux/crush/crush.h
index 09561a04c12708109078f0d832b65f34c5ce9c0e..83543c504b5a215ed36e9439147e0b7fb08b0437 100644
--- a/include/linux/crush/crush.h
+++ b/include/linux/crush/crush.h
@@ -21,7 +21,6 @@
 
 
 #define CRUSH_MAX_DEPTH 10  /* max crush hierarchy depth */
-#define CRUSH_MAX_SET   10  /* max size of a mapping result */
 
 
 /*
diff --git a/include/linux/crush/mapper.h b/include/linux/crush/mapper.h
index 69310b03187518ddeca8fc1cd09b78471b60f61e..eab367446eea7fa683cb4fd15e74ad3822bb35c8 100644
--- a/include/linux/crush/mapper.h
+++ b/include/linux/crush/mapper.h
@@ -14,6 +14,7 @@ extern int crush_find_rule(const struct crush_map *map, int ruleset, int type, i
 extern int crush_do_rule(const struct crush_map *map,
 			 int ruleno,
 			 int x, int *result, int result_max,
-			 const __u32 *weights, int weight_max);
+			 const __u32 *weights, int weight_max,
+			 int *scratch);
 
 #endif
diff --git a/net/ceph/crush/mapper.c b/net/ceph/crush/mapper.c
index 82cab7d3e89d61ec94a570936be56dd31b38efb0..dcf48bc504ea46137d4e89b9a31cfd0bc82c331b 100644
--- a/net/ceph/crush/mapper.c
+++ b/net/ceph/crush/mapper.c
@@ -478,15 +478,17 @@ static int crush_choose(const struct crush_map *map,
  * @result_max: maximum result size
  * @weight: weight vector (for map leaves)
  * @weight_max: size of weight vector
+ * @scratch: scratch vector for private use; must be >= 3 * result_max
  */
 int crush_do_rule(const struct crush_map *map,
 		  int ruleno, int x, int *result, int result_max,
-		  const __u32 *weight, int weight_max)
+		  const __u32 *weight, int weight_max,
+		  int *scratch)
 {
 	int result_len;
-	int a[CRUSH_MAX_SET];
-	int b[CRUSH_MAX_SET];
-	int c[CRUSH_MAX_SET];
+	int *a = scratch;
+	int *b = scratch + result_max;
+	int *c = scratch + result_max*2;
 	int recurse_to_leaf;
 	int *w;
 	int wsize = 0;
diff --git a/net/ceph/osdmap.c b/net/ceph/osdmap.c
index 6477a68ddecb7a01701f3e956b81e21bb45dc21f..8b1a6b48bb5d962d9877c1d66498b21077efcd56 100644
--- a/net/ceph/osdmap.c
+++ b/net/ceph/osdmap.c
@@ -1110,6 +1110,16 @@ int ceph_calc_ceph_pg(struct ceph_pg *pg, const char *oid,
 }
 EXPORT_SYMBOL(ceph_calc_ceph_pg);
 
+static int crush_do_rule_ary(const struct crush_map *map, int ruleno, int x,
+			     int *result, int result_max,
+			     const __u32 *weight, int weight_max)
+{
+	int scratch[result_max * 3];
+
+	return crush_do_rule(map, ruleno, x, result, result_max,
+			     weight, weight_max, scratch);
+}
+
 /*
  * Calculate raw osd vector for the given pgid.  Return pointer to osd
  * array, or NULL on failure.
@@ -1163,9 +1173,9 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
 				      pool->pgp_num_mask) +
 			(unsigned)pgid.pool;
 	}
-	r = crush_do_rule(osdmap->crush, ruleno, pps, osds,
-			  min_t(int, pool->size, *num),
-			  osdmap->osd_weight, osdmap->max_osd);
+	r = crush_do_rule_ary(osdmap->crush, ruleno, pps,
+			      osds, min_t(int, pool->size, *num),
+			      osdmap->osd_weight, osdmap->max_osd);
 	if (r < 0) {
 		pr_err("error %d from crush rule: pool %lld ruleset %d type %d"
 		       " size %d\n", r, pgid.pool, pool->crush_ruleset,