pnfs: handle partial layout recalls

layout status flags for PNFS_LAYOUT_RECALLED and PNFS_LAYOUT_CHANGED are removed, and replaced by a list of recalled ranges.  recalls during io are added to the list and processed on pnfs_layout_io_finished().  recalls outside of io are processed immediately

new function layout_recall_range() loops through all existing layout segments, and removes ranges that intersect with the range recalled.  deals with 4 cases per segment:
-only the beginning of the segment is recalled
-only the end of the segment is recalled
-the entire segment is recalled
-only a middle part of the segment is recalled

new function pnfs_layout_recall_status() is called before each unit of io, allowing io threads to bail out early if a recall is detected.  takes a layout segment as an argument, and only returns an error if that segment intersects a recalled range

new function pnfs_layout_recall_fenced() is called when map_ds_error() in pnfs_io.c detects fencing.  also takes a layout segment as an argument, and appends a recall matching the range of the segment

pnfs_layout_state_prepare() now checks the given range against the list of recalled ranges

Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
Casey Bodley 2012-01-30 13:49:40 -05:00 committed by unknown
parent d0ff37a195
commit db7caebe28
3 changed files with 277 additions and 71 deletions

View file

@ -332,19 +332,14 @@ static enum pnfs_status thread_next_unit(
{
pnfs_io_pattern *pattern = thread->pattern;
pnfs_layout_state *state = pattern->state;
enum pnfs_status status = PNFS_SUCCESS;
enum pnfs_status status;
AcquireSRWLockShared(&state->lock);
/* stop io if the layout is recalled */
if (state->status & PNFS_LAYOUT_CHANGED) {
status = PNFSERR_LAYOUT_CHANGED;
status = pnfs_layout_recall_status(state, &thread->layout->layout);
if (status)
goto out_unlock;
}
if (state->status & PNFS_LAYOUT_RECALLED) {
status = PNFSERR_LAYOUT_RECALLED;
goto out_unlock;
}
status = stripe_next_unit(thread->layout, thread->id,
&thread->offset, pattern->offset_end, io);
@ -462,7 +457,8 @@ static uint64_t pattern_bytes_transferred(
static enum pnfs_status map_ds_error(
IN enum nfsstat4 nfsstat,
IN pnfs_layout_state *state)
IN pnfs_layout_state *state,
IN const pnfs_file_layout *layout)
{
switch (nfsstat) {
case NO_ERROR:
@ -477,10 +473,7 @@ static enum pnfs_status map_ds_error(
case NFS4ERR_PNFS_NO_LAYOUT:
dprintf(IOLVL, "data server fencing detected!\n");
AcquireSRWLockExclusive(&state->lock);
/* flag the layout for return once io is finished */
state->status |= PNFS_LAYOUT_RECALLED | PNFS_LAYOUT_CHANGED;
ReleaseSRWLockExclusive(&state->lock);
pnfs_layout_recall_fenced(state, &layout->layout);
/* return CHANGED to prevent any further use of the layout */
return PNFSERR_LAYOUT_CHANGED;
@ -535,7 +528,7 @@ static uint32_t WINAPI file_layout_read_thread(void *args)
if (nfsstat) {
eprintf("nfs41_read() failed with %s\n",
nfs_error_string(nfsstat));
status = map_ds_error(nfsstat, pattern->state);
status = map_ds_error(nfsstat, pattern->state, thread->layout);
break;
}
@ -610,7 +603,7 @@ retry_write:
if (nfsstat) {
eprintf("nfs41_write() failed with %s\n",
nfs_error_string(nfsstat));
status = map_ds_error(nfsstat, pattern->state);
status = map_ds_error(nfsstat, pattern->state, thread->layout);
break;
}
if (!verify_write(&verf, &thread->stable))
@ -645,7 +638,7 @@ retry_write:
commit_min, (uint32_t)(commit_max - commit_min), 0, &verf, NULL);
if (nfsstat)
status = map_ds_error(nfsstat, pattern->state);
status = map_ds_error(nfsstat, pattern->state, thread->layout);
else if (!verify_commit(&verf)) {
/* resend the writes unless the layout was recalled */
if (status != PNFSERR_LAYOUT_RECALLED)