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:
Casey Bodley 2012-02-01 15:13:20 -05:00 committed by unknown
parent 5cc317e8a5
commit d0ff37a195

View file

@ -228,6 +228,81 @@ static bool_t layout_sanity_check(
return TRUE; 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( static void layout_ordered_insert(
IN pnfs_layout_state *state, IN pnfs_layout_state *state,
IN pnfs_layout *layout) IN pnfs_layout *layout)
@ -272,11 +347,15 @@ static enum pnfs_status layout_update_range(
continue; continue;
} }
dprintf(FLLVL, "Saving layout:\n"); /* attempt to merge the range with existing segments */
dprint_layout(FLLVL, layout); status = layout_state_merge(state, layout);
if (status) {
dprintf(FLLVL, "saving new layout:\n");
dprint_layout(FLLVL, layout);
layout_ordered_insert(state, &layout->layout); layout_ordered_insert(state, &layout->layout);
status = PNFS_SUCCESS; status = PNFS_SUCCESS;
}
} }
return status; return status;
} }
@ -976,6 +1055,10 @@ void pnfs_layout_io_finished(
if (state->status & PNFS_LAYOUT_RECALLED) if (state->status & PNFS_LAYOUT_RECALLED)
layout_recall_return(state); 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: out_unlock:
ReleaseSRWLockExclusive(&state->lock); ReleaseSRWLockExclusive(&state->lock);
} }