diff options
Diffstat (limited to 'fs/exofs/ore_raid.c')
| -rw-r--r-- | fs/exofs/ore_raid.c | 91 | 
1 files changed, 48 insertions, 43 deletions
diff --git a/fs/exofs/ore_raid.c b/fs/exofs/ore_raid.c index d222c77cfa1b..5f376d14fdcc 100644 --- a/fs/exofs/ore_raid.c +++ b/fs/exofs/ore_raid.c @@ -144,26 +144,26 @@ static void _sp2d_reset(struct __stripe_pages_2d *sp2d,  {  	unsigned data_devs = sp2d->data_devs;  	unsigned group_width = data_devs + sp2d->parity; -	unsigned p; +	int p, c;  	if (!sp2d->needed)  		return; -	for (p = 0; p < sp2d->pages_in_unit; p++) { -		struct __1_page_stripe *_1ps = &sp2d->_1p_stripes[p]; - -		if (_1ps->write_count < group_width) { -			unsigned c; +	for (c = data_devs - 1; c >= 0; --c) +		for (p = sp2d->pages_in_unit - 1; p >= 0; --p) { +			struct __1_page_stripe *_1ps = &sp2d->_1p_stripes[p]; -			for (c = 0; c < data_devs; c++) -				if (_1ps->page_is_read[c]) { -					struct page *page = _1ps->pages[c]; +			if (_1ps->page_is_read[c]) { +				struct page *page = _1ps->pages[c]; -					r4w->put_page(priv, page); -					_1ps->page_is_read[c] = false; -				} +				r4w->put_page(priv, page); +				_1ps->page_is_read[c] = false; +			}  		} +	for (p = 0; p < sp2d->pages_in_unit; p++) { +		struct __1_page_stripe *_1ps = &sp2d->_1p_stripes[p]; +  		memset(_1ps->pages, 0, group_width * sizeof(*_1ps->pages));  		_1ps->write_count = 0;  		_1ps->tx = NULL; @@ -461,16 +461,12 @@ static void _mark_read4write_pages_uptodate(struct ore_io_state *ios, int ret)   * ios->sp2d[p][*], xor is calculated the same way. These pages are   * allocated/freed and don't go through cache   */ -static int _read_4_write(struct ore_io_state *ios) +static int _read_4_write_first_stripe(struct ore_io_state *ios)  { -	struct ore_io_state *ios_read;  	struct ore_striping_info read_si;  	struct __stripe_pages_2d *sp2d = ios->sp2d;  	u64 offset = ios->si.first_stripe_start; -	u64 last_stripe_end; -	unsigned bytes_in_stripe = ios->si.bytes_in_stripe; -	unsigned i, c, p, min_p = sp2d->pages_in_unit, max_p = -1; -	int ret; +	unsigned c, p, min_p = sp2d->pages_in_unit, max_p = -1;  	if (offset == ios->offset) /* Go to start collect $200 */  		goto read_last_stripe; @@ -478,6 +474,9 @@ static int _read_4_write(struct ore_io_state *ios)  	min_p = _sp2d_min_pg(sp2d);  	max_p = _sp2d_max_pg(sp2d); +	ORE_DBGMSG("stripe_start=0x%llx ios->offset=0x%llx min_p=%d max_p=%d\n", +		   offset, ios->offset, min_p, max_p); +  	for (c = 0; ; c++) {  		ore_calc_stripe_info(ios->layout, offset, 0, &read_si);  		read_si.obj_offset += min_p * PAGE_SIZE; @@ -512,6 +511,18 @@ static int _read_4_write(struct ore_io_state *ios)  	}  read_last_stripe: +	return 0; +} + +static int _read_4_write_last_stripe(struct ore_io_state *ios) +{ +	struct ore_striping_info read_si; +	struct __stripe_pages_2d *sp2d = ios->sp2d; +	u64 offset; +	u64 last_stripe_end; +	unsigned bytes_in_stripe = ios->si.bytes_in_stripe; +	unsigned c, p, min_p = sp2d->pages_in_unit, max_p = -1; +  	offset = ios->offset + ios->length;  	if (offset % PAGE_SIZE)  		_add_to_r4w_last_page(ios, &offset); @@ -527,15 +538,15 @@ read_last_stripe:  	c = _dev_order(ios->layout->group_width * ios->layout->mirrors_p1,  		       ios->layout->mirrors_p1, read_si.par_dev, read_si.dev); -	BUG_ON(ios->si.first_stripe_start + bytes_in_stripe != last_stripe_end); -	/* unaligned IO must be within a single stripe */ -  	if (min_p == sp2d->pages_in_unit) {  		/* Didn't do it yet */  		min_p = _sp2d_min_pg(sp2d);  		max_p = _sp2d_max_pg(sp2d);  	} +	ORE_DBGMSG("offset=0x%llx stripe_end=0x%llx min_p=%d max_p=%d\n", +		   offset, last_stripe_end, min_p, max_p); +  	while (offset < last_stripe_end) {  		struct __1_page_stripe *_1ps = &sp2d->_1p_stripes[p]; @@ -568,6 +579,15 @@ read_last_stripe:  	}  read_it: +	return 0; +} + +static int _read_4_write_execute(struct ore_io_state *ios) +{ +	struct ore_io_state *ios_read; +	unsigned i; +	int ret; +  	ios_read = ios->ios_read_4_write;  	if (!ios_read)  		return 0; @@ -591,6 +611,8 @@ read_it:  	}  	_mark_read4write_pages_uptodate(ios_read, ret); +	ore_put_io_state(ios_read); +	ios->ios_read_4_write = NULL; /* Might need a reuse at last stripe */  	return 0;  } @@ -626,8 +648,11 @@ int _ore_add_parity_unit(struct ore_io_state *ios,  			/* If first stripe, Read in all read4write pages  			 * (if needed) before we calculate the first parity.  			 */ -			_read_4_write(ios); +			_read_4_write_first_stripe(ios);  		} +		if (!cur_len) /* If last stripe r4w pages of last stripe */ +			_read_4_write_last_stripe(ios); +		_read_4_write_execute(ios);  		for (i = 0; i < num_pages; i++) {  			pages[i] = _raid_page_alloc(); @@ -654,34 +679,14 @@ int _ore_add_parity_unit(struct ore_io_state *ios,  int _ore_post_alloc_raid_stuff(struct ore_io_state *ios)  { -	struct ore_layout *layout = ios->layout; -  	if (ios->parity_pages) { +		struct ore_layout *layout = ios->layout;  		unsigned pages_in_unit = layout->stripe_unit / PAGE_SIZE; -		unsigned stripe_size = ios->si.bytes_in_stripe; -		u64 last_stripe, first_stripe;  		if (_sp2d_alloc(pages_in_unit, layout->group_width,  				layout->parity, &ios->sp2d)) {  			return -ENOMEM;  		} - -		/* Round io down to last full strip */ -		first_stripe = div_u64(ios->offset, stripe_size); -		last_stripe = div_u64(ios->offset + ios->length, stripe_size); - -		/* If an IO spans more then a single stripe it must end at -		 * a stripe boundary. The reminder at the end is pushed into the -		 * next IO. -		 */ -		if (last_stripe != first_stripe) { -			ios->length = last_stripe * stripe_size - ios->offset; - -			BUG_ON(!ios->length); -			ios->nr_pages = (ios->length + PAGE_SIZE - 1) / -					PAGE_SIZE; -			ios->si.length = ios->length; /*make it consistent */ -		}  	}  	return 0;  }  | 
