* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <linux/slab.h>
#include <scsi/scsi_device.h>
#include <asm/div64.h>
return acumulated_lin_err;
}
-/* REMOVEME: After review
- Some quoteing from the standard
-
- L = logical offset into the file
- W = number of data components in a stripe
- S = W * stripe_unit (S is Stripe length)
- N = L / S (N is the stripe Number)
- C = (L-(N*S)) / stripe_unit (C is the component)
- O = (N*stripe_unit)+(L%stripe_unit) (O is the object's offset)
-*/
+/*
+ * L - logical offset into the file
+ *
+ * U - The number of bytes in a stripe within a group
+ *
+ * U = stripe_unit * group_width
+ *
+ * T - The number of bytes striped within a group of component objects
+ * (before advancing to the next group)
+ *
+ * T = stripe_unit * group_width * group_depth
+ *
+ * S - The number of bytes striped across all component objects
+ * before the pattern repeats
+ *
+ * S = stripe_unit * group_width * group_depth * group_count
+ *
+ * M - The "major" (i.e., across all components) stripe number
+ *
+ * M = L / S
+ *
+ * G - Counts the groups from the beginning of the major stripe
+ *
+ * G = (L - (M * S)) / T [or (L % S) / T]
+ *
+ * H - The byte offset within the group
+ *
+ * H = (L - (M * S)) % T [or (L % S) % T]
+ *
+ * N - The "minor" (i.e., across the group) stripe number
+ *
+ * N = H / U
+ *
+ * C - The component index coresponding to L
+ *
+ * C = (H - (N * U)) / stripe_unit + G * group_width
+ * [or (L % U) / stripe_unit + G * group_width]
+ *
+ * O - The component offset coresponding to L
+ *
+ * O = L % stripe_unit + N * stripe_unit + M * group_depth * stripe_unit
+ */
+struct _striping_info {
+ u64 obj_offset;
+ u64 group_length;
+ u64 total_group_length;
+ u64 Major;
+ unsigned dev;
+ unsigned unit_off;
+};
-static void _offset_dev_unit_off(struct exofs_io_state *ios, u64 file_offset,
- u64 *obj_offset, unsigned *dev, unsigned *unit_off)
+static void _calc_stripe_info(struct exofs_io_state *ios, u64 file_offset,
+ struct _striping_info *si)
{
- unsigned stripe_unit = ios->layout->stripe_unit;
- unsigned stripe_length = stripe_unit * ios->layout->group_width;
- u64 stripe_no = file_offset;
- unsigned stripe_mod = do_div(stripe_no, stripe_length);
+ u32 stripe_unit = ios->layout->stripe_unit;
+ u32 group_width = ios->layout->group_width;
+ u64 group_depth = ios->layout->group_depth;
+
+ u32 U = stripe_unit * group_width;
+ u64 T = U * group_depth;
+ u64 S = T * ios->layout->group_count;
+ u64 M = div64_u64(file_offset, S);
+
+ /*
+ G = (L - (M * S)) / T
+ H = (L - (M * S)) % T
+ */
+ u64 LmodS = file_offset - M * S;
+ u32 G = div64_u64(LmodS, T);
+ u64 H = LmodS - G * T;
+
+ u32 N = div_u64(H, U);
+
+ /* "H - (N * U)" is just "H % U" so it's bound to u32 */
+ si->dev = (u32)(H - (N * U)) / stripe_unit + G * group_width;
+ si->dev *= ios->layout->mirrors_p1;
- *unit_off = stripe_mod % stripe_unit;
- *obj_offset = stripe_no * stripe_unit + *unit_off;
- *dev = stripe_mod / stripe_unit * ios->layout->mirrors_p1;
+ div_u64_rem(file_offset, stripe_unit, &si->unit_off);
+
+ si->obj_offset = si->unit_off + (N * stripe_unit) +
+ (M * group_depth * stripe_unit);
+
+ si->group_length = T - H;
+ si->total_group_length = T;
+ si->Major = M;
}
-static int _add_stripe_unit(struct exofs_io_state *ios, unsigned *cur_bvec,
- struct exofs_per_dev_state *per_dev, int cur_len)
+static int _add_stripe_unit(struct exofs_io_state *ios, unsigned *cur_pg,
+ unsigned pgbase, struct exofs_per_dev_state *per_dev,
+ int cur_len)
{
- unsigned bv = *cur_bvec;
+ unsigned pg = *cur_pg;
struct request_queue *q =
osd_request_queue(exofs_ios_od(ios, per_dev->dev));
if (per_dev->bio == NULL) {
unsigned pages_in_stripe = ios->layout->group_width *
(ios->layout->stripe_unit / PAGE_SIZE);
- unsigned bio_size = (ios->bio->bi_vcnt + pages_in_stripe) /
+ unsigned bio_size = (ios->nr_pages + pages_in_stripe) /
ios->layout->group_width;
per_dev->bio = bio_kmalloc(GFP_KERNEL, bio_size);
}
while (cur_len > 0) {
- int added_len;
- struct bio_vec *bvec = &ios->bio->bi_io_vec[bv];
+ unsigned pglen = min_t(unsigned, PAGE_SIZE - pgbase, cur_len);
+ unsigned added_len;
- BUG_ON(ios->bio->bi_vcnt <= bv);
- cur_len -= bvec->bv_len;
+ BUG_ON(ios->nr_pages <= pg);
+ cur_len -= pglen;
- added_len = bio_add_pc_page(q, per_dev->bio, bvec->bv_page,
- bvec->bv_len, bvec->bv_offset);
- if (unlikely(bvec->bv_len != added_len))
+ added_len = bio_add_pc_page(q, per_dev->bio, ios->pages[pg],
+ pglen, pgbase);
+ if (unlikely(pglen != added_len))
return -ENOMEM;
- ++bv;
+ pgbase = 0;
+ ++pg;
}
BUG_ON(cur_len);
- *cur_bvec = bv;
+ *cur_pg = pg;
return 0;
}
+static int _prepare_one_group(struct exofs_io_state *ios, u64 length,
+ struct _striping_info *si, unsigned first_comp)
+{
+ unsigned stripe_unit = ios->layout->stripe_unit;
+ unsigned mirrors_p1 = ios->layout->mirrors_p1;
+ unsigned devs_in_group = ios->layout->group_width * mirrors_p1;
+ unsigned dev = si->dev;
+ unsigned first_dev = dev - (dev % devs_in_group);
+ unsigned comp = first_comp + (dev - first_dev);
+ unsigned max_comp = ios->numdevs ? ios->numdevs - mirrors_p1 : 0;
+ unsigned cur_pg = ios->pages_consumed;
+ int ret = 0;
+
+ while (length) {
+ struct exofs_per_dev_state *per_dev = &ios->per_dev[comp];
+ unsigned cur_len, page_off = 0;
+
+ if (!per_dev->length) {
+ per_dev->dev = dev;
+ if (dev < si->dev) {
+ per_dev->offset = si->obj_offset + stripe_unit -
+ si->unit_off;
+ cur_len = stripe_unit;
+ } else if (dev == si->dev) {
+ per_dev->offset = si->obj_offset;
+ cur_len = stripe_unit - si->unit_off;
+ page_off = si->unit_off & ~PAGE_MASK;
+ BUG_ON(page_off && (page_off != ios->pgbase));
+ } else { /* dev > si->dev */
+ per_dev->offset = si->obj_offset - si->unit_off;
+ cur_len = stripe_unit;
+ }
+
+ if (max_comp < comp)
+ max_comp = comp;
+
+ dev += mirrors_p1;
+ dev = (dev % devs_in_group) + first_dev;
+ } else {
+ cur_len = stripe_unit;
+ }
+ if (cur_len >= length)
+ cur_len = length;
+
+ ret = _add_stripe_unit(ios, &cur_pg, page_off , per_dev,
+ cur_len);
+ if (unlikely(ret))
+ goto out;
+
+ comp += mirrors_p1;
+ comp = (comp % devs_in_group) + first_comp;
+
+ length -= cur_len;
+ }
+out:
+ ios->numdevs = max_comp + mirrors_p1;
+ ios->pages_consumed = cur_pg;
+ return ret;
+}
+
static int _prepare_for_striping(struct exofs_io_state *ios)
{
u64 length = ios->length;
- u64 offset = ios->offset;
- unsigned stripe_unit = ios->layout->stripe_unit;
- unsigned comp = 0;
- unsigned stripes = 0;
- unsigned cur_bvec = 0;
- int ret;
+ struct _striping_info si;
+ unsigned devs_in_group = ios->layout->group_width *
+ ios->layout->mirrors_p1;
+ unsigned first_comp = 0;
+ int ret = 0;
+
+ _calc_stripe_info(ios, ios->offset, &si);
- if (!ios->bio) {
+ if (!ios->pages) {
if (ios->kern_buff) {
struct exofs_per_dev_state *per_dev = &ios->per_dev[0];
- unsigned unit_off;
- _offset_dev_unit_off(ios, offset, &per_dev->offset,
- &per_dev->dev, &unit_off);
+ per_dev->offset = si.obj_offset;
+ per_dev->dev = si.dev;
+
/* no cross device without page array */
BUG_ON((ios->layout->group_width > 1) &&
- (unit_off + length > stripe_unit));
+ (si.unit_off + ios->length >
+ ios->layout->stripe_unit));
}
ios->numdevs = ios->layout->mirrors_p1;
return 0;
}
while (length) {
- struct exofs_per_dev_state *per_dev = &ios->per_dev[comp];
- unsigned cur_len;
-
- if (!per_dev->length) {
- unsigned unit_off;
-
- _offset_dev_unit_off(ios, offset, &per_dev->offset,
- &per_dev->dev, &unit_off);
- stripes++;
- cur_len = min_t(u64, stripe_unit - unit_off, length);
- offset += cur_len;
- } else {
- cur_len = min_t(u64, stripe_unit, length);
- }
+ if (length < si.group_length)
+ si.group_length = length;
- ret = _add_stripe_unit(ios, &cur_bvec, per_dev, cur_len);
+ ret = _prepare_one_group(ios, si.group_length, &si, first_comp);
if (unlikely(ret))
goto out;
- comp += ios->layout->mirrors_p1;
- comp %= ios->layout->s_numdevs;
+ length -= si.group_length;
- length -= cur_len;
+ si.group_length = si.total_group_length;
+ si.unit_off = 0;
+ ++si.Major;
+ si.obj_offset = si.Major * ios->layout->stripe_unit *
+ ios->layout->group_depth;
+
+ si.dev = (si.dev - (si.dev % devs_in_group)) + devs_in_group;
+ si.dev %= ios->layout->s_numdevs;
+
+ first_comp += devs_in_group;
+ first_comp %= ios->layout->s_numdevs;
}
+
out:
- ios->numdevs = stripes * ios->layout->mirrors_p1;
return ret;
}
unsigned last_comp = cur_comp + ios->layout->mirrors_p1;
int ret = 0;
+ if (ios->pages && !master_dev->length)
+ return 0; /* Just an empty slot */
+
for (; cur_comp < last_comp; ++cur_comp, ++dev) {
struct exofs_per_dev_state *per_dev = &ios->per_dev[cur_comp];
struct osd_request *or;
per_dev->or = or;
per_dev->offset = master_dev->offset;
- if (ios->bio) {
+ if (ios->pages) {
struct bio *bio;
if (per_dev != master_dev) {
struct exofs_per_dev_state *per_dev = &ios->per_dev[cur_comp];
unsigned first_dev = (unsigned)ios->obj.id;
+ if (ios->pages && !per_dev->length)
+ return 0; /* Just an empty slot */
+
first_dev = per_dev->dev + first_dev % ios->layout->mirrors_p1;
or = osd_start_request(exofs_ios_od(ios, first_dev), GFP_KERNEL);
if (unlikely(!or)) {
}
per_dev->or = or;
- if (ios->bio) {
+ if (ios->pages) {
osd_req_read(or, &ios->obj, per_dev->offset,
per_dev->bio, per_dev->length);
EXOFS_DBGMSG("read(0x%llx) offset=0x%llx length=0x%llx"
struct osd_attr attr;
__be64 newsize;
} *size_attrs;
- u64 this_obj_size;
- unsigned dev;
- unsigned unit_off;
+ struct _striping_info si;
int i, ret;
ret = exofs_get_io_state(&sbi->layout, &ios);
ios->cred = oi->i_cred;
ios->numdevs = ios->layout->s_numdevs;
- _offset_dev_unit_off(ios, size, &this_obj_size, &dev, &unit_off);
+ _calc_stripe_info(ios, size, &si);
for (i = 0; i < ios->layout->group_width; ++i) {
struct exofs_trunc_attr *size_attr = &size_attrs[i];
u64 obj_size;
- if (i < dev)
- obj_size = this_obj_size +
- ios->layout->stripe_unit - unit_off;
- else if (i == dev)
- obj_size = this_obj_size;
- else /* i > dev */
- obj_size = this_obj_size - unit_off;
+ if (i < si.dev)
+ obj_size = si.obj_offset +
+ ios->layout->stripe_unit - si.unit_off;
+ else if (i == si.dev)
+ obj_size = si.obj_offset;
+ else /* i > si.dev */
+ obj_size = si.obj_offset - si.unit_off;
size_attr->newsize = cpu_to_be64(obj_size);
size_attr->attr = g_attr_logical_length;