Convert algorithm into commented-out not-working-yet code :)

master
Vitaliy Filippov 2013-05-26 15:49:34 +04:00
parent 73351b46dc
commit d9a12d2ace
1 changed files with 145 additions and 36 deletions

181
sftl.c
View File

@ -141,7 +141,7 @@ static void sftl_make_request(struct request_queue *q, struct bio *bio)
}
else
{
// cluster on the disk
// cluster needs to be read from disk
struct block_device *bdev = sftl->blkdev;
struct request_queue *q = bdev_get_queue(bdev);
struct bio *bb = bio_alloc(GFP_KERNEL, 1);
@ -205,54 +205,163 @@ static void sftl_make_request(struct request_queue *q, struct bio *bio)
sftl->freesegs--;
// FIXME Correctly adjust free segment address
sftl->free_start_seg++;
// Algorithm:
// 0) If no free clusters are left on the device except reserved ones => goto FAIL
// 1) If more than N-1 free segments are left in current sequence => goto END
// 2) Try to find a free sequence of N segments
// If there is one => remember it as "next free sequence", goto END
// 3) Try to find a freeable sequence of N segments
// If there is one => free it using current N-1 free segments,
// and remember it as the current.
// 4) Move data from a segment adjacent to current free sequence
// to random free places on the device. This operation ensures that
// reserved segments are never fragmented. It may fail if nearly ALL
// clusters are occupied on the device. This should be ignored,
// because we have N-1 segments reserved and we know that we'll
// definitely have at least N free clusters on the device after writing
// one segment of the reserved ones.
// END) Continue writing as usual - into a next free segment in sequence.
// FAIL) This shouldn't happen. Abort writing.
/*
u32 defrag[seg_clust];
u32 prev = sftl->free_start_seg;
int n = 0, m, n_defrag = 0;
while (n < seg_clust)
Algorithm:
1) If less than reserved clusters are free on the device
=> This shouldn't happen. Abort writing.
2) If a "next free sequence" is already remembered, and there are
no free segments left in current free sequence
=> Switch free sequence to "next", write as usual
3) If more than N-1 free segments are left in current sequence,
or if a "next free sequence" is already remembered
=> Write as usual
4) Try to find a free sequence of N segments. If there is one
=> Remember it as a "next free sequence", write as usual
5) Try to find a freeable sequence of N segments. If there is one
=> Free it using current N-1 free segments, make it current
and write as usual
6) If there is no complete freeable sequence found
=> Move data from a segment adjacent to current free sequence
to random free clusters on the device.
This operation ensures that reserved segments are never fragmented.
It may fail if nearly ALL clusters are occupied on the device.
This is OK because we know that we'll definitely have at least N
free clusters on the device after writing any of the reserved segments.
*/
/*
BUG_ON(dev->freeclust < dev->reserved_segs*seg_clust);
if (sftl->next_free_end)
{
i = prev;
do
if (sftl->free_end_seg <= sftl->free_start_seg)
{
i = (i+1) % sftl->segs;
} while (i != prev && !(m = free_clusters_count(i)));
BUG_ON(i == prev); // infinite loop prevented
n += m;
defrag[n_defrag++] = prev = i;
sftl->free_start_seg = sftl->next_free_start;
sftl->free_end_seg = sftl->next_free_end;
sftl->next_free_start = 0;
sftl->next_free_end = 0;
}
}
if (n_defrag > 1)
else if (sftl->free_end_seg - sftl->free_start_seg <= seg_clust-1)
{
// Next free segment is fragmented
for (i = 0; i < n_defrag; i++)
// Search for a sequence of at least @seg_clust free segments
u32 i, j, cur_first = 0, cur_free = 0;
for (i = 0; i < sftl->segs; i++)
{
for (j = 0; j < seg_clust; j++)
{
if (virt = sftl->clust_map[defrag[i]*seg_clust+j])
if (sftl->clust_map[i*seg_clust+j])
{
@read(sftl, virt, buf);
@write(sftl, virt, buf);
break;
}
}
if (j == seg_clust)
{
if (cur_free)
{
cur_free++;
}
else
{
cur_first = i;
cur_free = 1;
}
}
else if (cur_free >= seg_clust)
{
break;
}
else
{
cur_free = 0;
}
}
if (cur_free)
{
// If found, remember as next and continue writing into current sequence
sftl->next_free_start = cur_first;
sftl->next_free_end = cur_first+cur_free;
}
else
{
// Search for a freeable sequence
u32 random_free[seg_clust], random_found = 0;
u32 min_freeable_start = 0, min_freeable_cost = seg_clust*seg_clust, cur_freeable_cost = 0;
for (i = 0; i < sftl->segs; i++)
{
for (j = 0; j < seg_clust; j++)
{
if (i >= seg_clust && sftl->clust_map[i*seg_clust+j - seg_clust*seg_clust])
{
cur_freeable--;
}
if (sftl->clust_map[i*seg_clust+j])
{
cur_freeable++;
}
else if (random_found < seg_clust)
{
random_free[random_found++] = i*seg_clust+j;
}
}
if (i >= seg_clust-1 && cur_freeable_cost < min_freeable_cost)
{
min_freeable_cost = cur_freeable_cost;
min_freeable_start = i-seg_clust+1;
}
}
if (min_freeable_cost < seg_clust*(seg_clust-1))
{
// Best freeable sequence found -> free it and continue writing
sftl->next_free_start = min_freeable_start;
sftl->next_free_end = min_freeable_start+seg_clust;
for (k = min_freeable_start*seg_clust, i = 0; i < seg_clust; i++)
{
for (j = 0; j < seg_clust; j++, k++)
{
if (sftl->clust_map[k])
{
READ(sftl, sftl->clust_map[k]-1, buf);
WRITE(sftl, sftl->clust_map[k]-1, buf);
}
}
}
}
else
{
// Move data into random free clusters
if (sftl->free_end_seg < sftl->segs)
{
next_seg = sftl->free_end_seg;
}
else
{
next_seg = sftl->free_start_seg-1;
}
for (j = 0, i = 0; i < seg_clust && j < random_found; i++)
{
if (sftl->clust_map[next_seg*seg_clust + i])
{
u32 mv = sftl->clust_map[next_seg*seg_clust + i]-1;
READ(sftl, mv, buf);
WRITE_SINGLE(sftl, mv, random_free[j++], buf);
}
}
if (i >= seg_clust)
{
// Adjacent segment freed!
sftl->freesegs++;
if (sftl->free_end_seg < sftl->segs)
{
sftl->free_end_seg++;
}
else
{
sftl->free_start_seg--;
}
}
}
}
}
sftl->free_start_seg = defrag[0];
*/
}
else