pnfs: strategy for merging layout segments
when processing new layout segments from a LAYOUTGET response, layout_update_range() first attempts to merge each new segment into existing segments before calling layout_ordered_insert(). two segments are eligible for merging if their ranges overlap, and all other relevant fields (iomode, stripe unit, deviceid, filehandles, etc) match when a new segment is merged with an existing segment, the existing segment's extended range may cause it to overlap with another existing segment; additional merging may then be necessary. but merging an existing segment with another existing segment results in the the first segment being removed/freed, so this type of merging can -only- be performed when no io threads are referencing the layout. pnfs_layout_io_finished() calls layout_state_merge() to finish any merging that was delayed during io Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
parent
5cc317e8a5
commit
d0ff37a195
1 changed files with 87 additions and 4 deletions
|
|
@ -228,6 +228,81 @@ static bool_t layout_sanity_check(
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static int layout_filehandles_cmp(
|
||||
IN const pnfs_file_layout_handles *lhs,
|
||||
IN const pnfs_file_layout_handles *rhs)
|
||||
{
|
||||
const uint32_t diff = rhs->count - lhs->count;
|
||||
return diff ? diff : memcmp(rhs->arr, lhs->arr,
|
||||
rhs->count * sizeof(nfs41_path_fh));
|
||||
}
|
||||
|
||||
static bool_t layout_merge_segments(
|
||||
IN pnfs_file_layout *to,
|
||||
IN pnfs_file_layout *from)
|
||||
{
|
||||
const uint64_t to_max = range_max(&to->layout);
|
||||
const uint64_t from_max = range_max(&from->layout);
|
||||
|
||||
/* cannot merge a segment with itself */
|
||||
if (to == from)
|
||||
return FALSE;
|
||||
|
||||
/* the ranges must meet or overlap */
|
||||
if (to_max < from->layout.offset || from_max < to->layout.offset)
|
||||
return FALSE;
|
||||
|
||||
/* the following fields must match: */
|
||||
if (to->layout.iomode != from->layout.iomode ||
|
||||
to->layout.type != from->layout.type ||
|
||||
layout_filehandles_cmp(&to->filehandles, &from->filehandles) != 0 ||
|
||||
memcmp(to->deviceid, from->deviceid, PNFS_DEVICEID_SIZE) != 0 ||
|
||||
to->pattern_offset != from->pattern_offset ||
|
||||
to->first_index != from->first_index ||
|
||||
to->util != from->util)
|
||||
return FALSE;
|
||||
|
||||
dprintf(FLLVL, "merging layout range {%llu, %llu} with {%llu, %llu}\n",
|
||||
to->layout.offset, to->layout.length,
|
||||
from->layout.offset, from->layout.length);
|
||||
|
||||
/* calculate the union of the two ranges */
|
||||
to->layout.offset = min(to->layout.offset, from->layout.offset);
|
||||
to->layout.length = max(to_max, from_max) - to->layout.offset;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static enum pnfs_status layout_state_merge(
|
||||
IN pnfs_layout_state *state,
|
||||
IN pnfs_file_layout *from)
|
||||
{
|
||||
struct list_entry *entry, *tmp;
|
||||
pnfs_file_layout *to;
|
||||
enum pnfs_status status = PNFSERR_NO_LAYOUT;
|
||||
|
||||
/* attempt to merge the new segment with each existing segment */
|
||||
list_for_each_tmp(entry, tmp, &state->layouts) {
|
||||
to = file_layout_entry(entry);
|
||||
if (!layout_merge_segments(to, from))
|
||||
continue;
|
||||
|
||||
/* on success, remove/free the new segment */
|
||||
list_remove(&from->layout.entry);
|
||||
file_layout_free(from);
|
||||
status = PNFS_SUCCESS;
|
||||
|
||||
/* because the existing segment 'to' has grown, we may
|
||||
* be able to merge it with later segments */
|
||||
from = to;
|
||||
|
||||
/* but if there could be io threads referencing this segment,
|
||||
* we can't free it until io is finished */
|
||||
if (state->io_count)
|
||||
break;
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
static void layout_ordered_insert(
|
||||
IN pnfs_layout_state *state,
|
||||
IN pnfs_layout *layout)
|
||||
|
|
@ -272,12 +347,16 @@ static enum pnfs_status layout_update_range(
|
|||
continue;
|
||||
}
|
||||
|
||||
dprintf(FLLVL, "Saving layout:\n");
|
||||
/* attempt to merge the range with existing segments */
|
||||
status = layout_state_merge(state, layout);
|
||||
if (status) {
|
||||
dprintf(FLLVL, "saving new layout:\n");
|
||||
dprint_layout(FLLVL, layout);
|
||||
|
||||
layout_ordered_insert(state, &layout->layout);
|
||||
status = PNFS_SUCCESS;
|
||||
}
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -976,6 +1055,10 @@ void pnfs_layout_io_finished(
|
|||
if (state->status & PNFS_LAYOUT_RECALLED)
|
||||
layout_recall_return(state);
|
||||
|
||||
/* finish any segment merging that was delayed during io */
|
||||
if (!list_empty(&state->layouts))
|
||||
layout_state_merge(state, file_layout_entry(state->layouts.next));
|
||||
|
||||
out_unlock:
|
||||
ReleaseSRWLockExclusive(&state->lock);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue