af_key: fix buffer overread in parse_exthdrs()
[pandora-kernel.git] / fs / exofs / ore.c
index fcfa86a..df4a10f 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <linux/slab.h>
+#include <linux/module.h>
 #include <asm/div64.h>
 #include <linux/lcm.h>
 
@@ -102,7 +103,7 @@ int ore_verify_layout(unsigned total_comps, struct ore_layout *layout)
 
        layout->max_io_length =
                (BIO_MAX_PAGES_KMALLOC * PAGE_SIZE - layout->stripe_unit) *
-                                                       layout->group_width;
+                                       (layout->group_width - layout->parity);
        if (layout->parity) {
                unsigned stripe_length =
                                (layout->group_width - layout->parity) *
@@ -265,7 +266,7 @@ int  ore_get_rw_state(struct ore_layout *layout, struct ore_components *oc,
 
                        /* first/last seg is split */
                        num_raid_units += layout->group_width;
-                       sgs_per_dev = div_u64(num_raid_units, data_devs);
+                       sgs_per_dev = div_u64(num_raid_units, data_devs) + 2;
                } else {
                        /* For Writes add parity pages array. */
                        max_par_pages = num_raid_units * pages_in_unit *
@@ -285,7 +286,8 @@ int  ore_get_rw_state(struct ore_layout *layout, struct ore_components *oc,
        if (length) {
                ore_calc_stripe_info(layout, offset, length, &ios->si);
                ios->length = ios->si.length;
-               ios->nr_pages = (ios->length + PAGE_SIZE - 1) / PAGE_SIZE;
+               ios->nr_pages = ((ios->offset & (PAGE_SIZE - 1)) +
+                                ios->length + PAGE_SIZE - 1) / PAGE_SIZE;
                if (layout->parity)
                        _ore_post_alloc_raid_stuff(ios);
        }
@@ -400,7 +402,7 @@ static void _clear_bio(struct bio *bio)
        struct bio_vec *bv;
        unsigned i;
 
-       __bio_for_each_segment(bv, bio, i, 0) {
+       bio_for_each_segment_all(bv, bio, i) {
                unsigned this_count = bv->bv_len;
 
                if (likely(PAGE_SIZE == this_count))
@@ -444,10 +446,10 @@ int ore_check_io(struct ore_io_state *ios, ore_on_dev_error on_dev_error)
                        u64 residual = ios->reading ?
                                        or->in.residual : or->out.residual;
                        u64 offset = (ios->offset + ios->length) - residual;
-                       struct ore_dev *od = ios->oc->ods[
-                                       per_dev->dev - ios->oc->first_dev];
+                       unsigned dev = per_dev->dev - ios->oc->first_dev;
+                       struct ore_dev *od = ios->oc->ods[dev];
 
-                       on_dev_error(ios, od, per_dev->dev, osi.osd_err_pri,
+                       on_dev_error(ios, od, dev, osi.osd_err_pri,
                                     offset, residual);
                }
                if (osi.osd_err_pri >= acumulated_osd_err) {
@@ -535,6 +537,7 @@ void ore_calc_stripe_info(struct ore_layout *layout, u64 file_offset,
        u64     H = LmodS - G * T;
 
        u32     N = div_u64(H, U);
+       u32     Nlast;
 
        /* "H - (N * U)" is just "H % U" so it's bound to u32 */
        u32     C = (u32)(H - (N * U)) / stripe_unit + G * group_width;
@@ -567,6 +570,10 @@ void ore_calc_stripe_info(struct ore_layout *layout, u64 file_offset,
        si->length = T - H;
        if (si->length > length)
                si->length = length;
+
+       Nlast = div_u64(H + si->length + U - 1, U);
+       si->maxdevUnits = Nlast - N;
+
        si->M = M;
 }
 EXPORT_SYMBOL(ore_calc_stripe_info);
@@ -582,13 +589,16 @@ int _ore_add_stripe_unit(struct ore_io_state *ios,  unsigned *cur_pg,
        int ret;
 
        if (per_dev->bio == NULL) {
-               unsigned pages_in_stripe = ios->layout->group_width *
-                                       (ios->layout->stripe_unit / PAGE_SIZE);
-               unsigned nr_pages = ios->nr_pages * ios->layout->group_width /
-                                       (ios->layout->group_width -
-                                        ios->layout->parity);
-               unsigned bio_size = (nr_pages + pages_in_stripe) /
-                                       ios->layout->group_width;
+               unsigned bio_size;
+
+               if (!ios->reading) {
+                       bio_size = ios->si.maxdevUnits;
+               } else {
+                       bio_size = (ios->si.maxdevUnits + 1) *
+                            (ios->layout->group_width - ios->layout->parity) /
+                            ios->layout->group_width;
+               }
+               bio_size *= (ios->layout->stripe_unit / PAGE_SIZE);
 
                per_dev->bio = bio_kmalloc(GFP_KERNEL, bio_size);
                if (unlikely(!per_dev->bio)) {
@@ -608,8 +618,12 @@ int _ore_add_stripe_unit(struct ore_io_state *ios,  unsigned *cur_pg,
                added_len = bio_add_pc_page(q, per_dev->bio, pages[pg],
                                            pglen, pgbase);
                if (unlikely(pglen != added_len)) {
-                       ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=%u\n",
-                                  per_dev->bio->bi_vcnt);
+                       /* If bi_vcnt == bi_max then this is a SW BUG */
+                       ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=0x%x "
+                                  "bi_max=0x%x BIO_MAX=0x%x cur_len=0x%x\n",
+                                  per_dev->bio->bi_vcnt,
+                                  per_dev->bio->bi_max_vecs,
+                                  BIO_MAX_PAGES_KMALLOC, cur_len);
                        ret = -ENOMEM;
                        goto out;
                }
@@ -734,13 +748,7 @@ static int _prepare_for_striping(struct ore_io_state *ios)
 out:
        ios->numdevs = devs_in_group;
        ios->pages_consumed = cur_pg;
-       if (unlikely(ret)) {
-               if (length == ios->length)
-                       return ret;
-               else
-                       ios->length -= length;
-       }
-       return 0;
+       return ret;
 }
 
 int ore_create(struct ore_io_state *ios)
@@ -842,11 +850,11 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp)
                                bio->bi_rw |= REQ_WRITE;
                        }
 
-                       osd_req_write(or, _ios_obj(ios, dev), per_dev->offset,
-                                     bio, per_dev->length);
+                       osd_req_write(or, _ios_obj(ios, cur_comp),
+                                     per_dev->offset, bio, per_dev->length);
                        ORE_DBGMSG("write(0x%llx) offset=0x%llx "
                                      "length=0x%llx dev=%d\n",
-                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(_ios_obj(ios, cur_comp)->id),
                                     _LLU(per_dev->offset),
                                     _LLU(per_dev->length), dev);
                } else if (ios->kern_buff) {
@@ -858,20 +866,20 @@ static int _write_mirror(struct ore_io_state *ios, int cur_comp)
                               (ios->si.unit_off + ios->length >
                                ios->layout->stripe_unit));
 
-                       ret = osd_req_write_kern(or, _ios_obj(ios, per_dev->dev),
+                       ret = osd_req_write_kern(or, _ios_obj(ios, cur_comp),
                                                 per_dev->offset,
                                                 ios->kern_buff, ios->length);
                        if (unlikely(ret))
                                goto out;
                        ORE_DBGMSG2("write_kern(0x%llx) offset=0x%llx "
                                      "length=0x%llx dev=%d\n",
-                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(_ios_obj(ios, cur_comp)->id),
                                     _LLU(per_dev->offset),
                                     _LLU(ios->length), per_dev->dev);
                } else {
-                       osd_req_set_attributes(or, _ios_obj(ios, dev));
+                       osd_req_set_attributes(or, _ios_obj(ios, cur_comp));
                        ORE_DBGMSG2("obj(0x%llx) set_attributes=%d dev=%d\n",
-                                    _LLU(_ios_obj(ios, dev)->id),
+                                    _LLU(_ios_obj(ios, cur_comp)->id),
                                     ios->out_attr_len, dev);
                }
 
@@ -1104,7 +1112,7 @@ int ore_truncate(struct ore_layout *layout, struct ore_components *oc,
                size_attr->attr = g_attr_logical_length;
                size_attr->attr.val_ptr = &size_attr->newsize;
 
-               ORE_DBGMSG("trunc(0x%llx) obj_offset=0x%llx dev=%d\n",
+               ORE_DBGMSG2("trunc(0x%llx) obj_offset=0x%llx dev=%d\n",
                             _LLU(oc->comps->obj.id), _LLU(obj_size), i);
                ret = _truncate_mirrors(ios, i * ios->layout->mirrors_p1,
                                        &size_attr->attr);