diff --git a/daemon/pnfs.h b/daemon/pnfs.h index 7326989..329f9e7 100644 --- a/daemon/pnfs.h +++ b/daemon/pnfs.h @@ -84,11 +84,6 @@ enum pnfs_iomode { }; enum pnfs_layout_status { - /* LAYOUTGET was successful, and the layout has not been returned or - * otherwise revoked by the server */ - PNFS_LAYOUT_GRANTED = 0x01, - /* GETDEVICEINFO was successful, and we have a valid 'device' pointer */ - PNFS_LAYOUT_HAS_DEVICE = 0x02, /* CB_LAYOUTRECALL indicated that the server has recalled this layout, * and it should be returned on completion of any pending io */ PNFS_LAYOUT_RECALLED = 0x04, @@ -162,7 +157,7 @@ typedef struct __pnfs_layout_state { nfs41_fh meta_fh; stateid4 stateid; struct list_entry entry; /* position in nfs41_client.layouts */ - struct __pnfs_file_layout *layout; + struct list_entry layouts; /* list of pnfs_file_layouts */ enum pnfs_layout_status status; bool_t return_on_close; LONG open_count; /* for return on last close */ @@ -245,7 +240,7 @@ enum pnfs_status pnfs_file_layout_recall( IN const struct cb_layoutrecall_args *recall); /* expects caller to hold an exclusive lock on pnfs_layout_state */ -enum pnfs_status pnfs_layout_io_start( +void pnfs_layout_io_start( IN pnfs_layout_state *state); void pnfs_layout_io_finished( diff --git a/daemon/pnfs_io.c b/daemon/pnfs_io.c index ece24cd..ac2f68c 100644 --- a/daemon/pnfs_io.c +++ b/daemon/pnfs_io.c @@ -29,6 +29,7 @@ #define IOLVL 2 /* dprintf level for pnfs io logging */ +#define file_layout_entry(pos) list_container(pos, pnfs_file_layout, layout.entry) typedef struct __pnfs_io_pattern { struct __pnfs_io_thread *threads; @@ -63,6 +64,13 @@ typedef struct __pnfs_io_unit { typedef uint32_t (WINAPI *pnfs_io_thread_fn)(void*); +static enum pnfs_status stripe_next_unit( + IN const pnfs_file_layout *layout, + IN uint32_t stripeid, + IN uint64_t *position, + IN uint64_t offset_end, + OUT pnfs_io_unit *io); + /* 13.4.2. Interpreting the File Layout Using Sparse Packing * http://tools.ietf.org/html/rfc5661#section-13.4.2 */ @@ -113,22 +121,107 @@ static enum pnfs_status get_dense_fh( return status; } +static __inline bool_t layout_compatible( + IN const pnfs_layout *layout, + IN enum pnfs_iomode iomode, + IN uint64_t position) +{ + return layout->iomode >= iomode + && layout->offset <= position + && position < layout->offset + layout->length; +} + +/* count stripes for all layout segments that intersect the range + * and have not been covered by previous segments */ +static uint32_t thread_count( + IN pnfs_layout_state *state, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length) +{ + uint64_t position = offset; + struct list_entry *entry; + uint32_t count = 0; + + list_for_each(entry, &state->layouts) { + pnfs_file_layout *layout = file_layout_entry(entry); + + if (!layout_compatible(&layout->layout, iomode, position)) + continue; + + position = layout->layout.offset + layout->layout.length; + count += layout->device->stripes.count; + } + return count; +} + static enum pnfs_status thread_init( IN pnfs_io_pattern *pattern, IN pnfs_io_thread *thread, IN pnfs_file_layout *layout, - IN uint32_t stripeid) + IN uint32_t stripeid, + IN uint64_t offset) { thread->pattern = pattern; thread->layout = layout; thread->stable = FILE_SYNC4; - thread->offset = pattern->offset_start; + thread->offset = offset; thread->id = stripeid; return is_dense(layout) ? get_dense_fh(layout, stripeid, &thread->file) : get_sparse_fh(layout, pattern->meta_file, stripeid, &thread->file); } +static enum pnfs_status pattern_threads_init( + IN pnfs_io_pattern *pattern, + IN enum pnfs_iomode iomode, + IN uint64_t offset, + IN uint64_t length) +{ + pnfs_io_unit io; + uint64_t position = offset; + struct list_entry *entry; + uint32_t s, t = 0; + enum pnfs_status status = PNFS_SUCCESS; + + list_for_each(entry, &pattern->state->layouts) { + pnfs_file_layout *layout = file_layout_entry(entry); + + if (!layout_compatible(&layout->layout, iomode, position)) + continue; + + for (s = 0; s < layout->device->stripes.count; s++) { + uint64_t off = position; + + /* does the range contain this stripe? */ + status = stripe_next_unit(layout, s, &off, offset + length, &io); + if (status != PNFS_PENDING) + continue; + + if (t >= pattern->count) { /* miscounted threads needed? */ + status = PNFSERR_NO_LAYOUT; + goto out; + } + + status = thread_init(pattern, &pattern->threads[t++], layout, s, off); + if (status) + goto out; + } + position = layout->layout.offset + layout->layout.length; + } + + if (position < offset + length) { + /* unable to satisfy the entire range */ + status = PNFSERR_NO_LAYOUT; + goto out; + } + + /* update the pattern with the actual number of threads used */ + pattern->count = t; +out: + return status; +} + static enum pnfs_status pattern_init( IN pnfs_io_pattern *pattern, IN nfs41_root *root, @@ -136,20 +229,22 @@ static enum pnfs_status pattern_init( IN const stateid_arg *stateid, IN pnfs_layout_state *state, IN unsigned char *buffer, + IN enum pnfs_iomode iomode, IN uint64_t offset, IN uint64_t length, IN uint32_t default_lease) { - uint32_t i; enum pnfs_status status; - pattern->count = state->layout->device->stripes.count; + /* calculate an upper bound on the number of threads to allocate */ + pattern->count = thread_count(state, iomode, offset, length); pattern->threads = calloc(pattern->count, sizeof(pnfs_io_thread)); if (pattern->threads == NULL) { status = PNFSERR_RESOURCES; goto out; } + /* information shared between threads */ pattern->root = root; pattern->meta_file = meta_file; pattern->stateid = stateid; @@ -159,16 +254,13 @@ static enum pnfs_status pattern_init( pattern->offset_end = offset + length; pattern->default_lease = default_lease; - for (i = 0; i < pattern->count; i++) { - status = thread_init(pattern, &pattern->threads[i], state->layout, i); - if (status) - goto out_err_free; - } - - /* take a reference on the layout so we don't return it during io */ - status = pnfs_layout_io_start(state); + /* initialize a thread for every stripe necessary to cover the range */ + status = pattern_threads_init(pattern, iomode, offset, length); if (status) goto out_err_free; + + /* take a reference on the layout so we don't return it during io */ + pnfs_layout_io_start(state); out: return status; @@ -278,65 +370,77 @@ static enum pnfs_status thread_data_server( return PNFS_SUCCESS; } +static enum pnfs_status pattern_join( + IN HANDLE *threads, + IN DWORD count) +{ + DWORD status; + /* WaitForMultipleObjects() supports a maximum of 64 objects */ + while (count) { + const DWORD n = min(count, MAXIMUM_WAIT_OBJECTS); + status = WaitForMultipleObjects(n, threads, TRUE, INFINITE); + if (status != WAIT_OBJECT_0) + return PNFSERR_RESOURCES; + + count -= n; + threads += n; + } + return PNFS_SUCCESS; +} + static enum pnfs_status pattern_fork( IN pnfs_io_pattern *pattern, IN pnfs_io_thread_fn thread_fn) { - pnfs_io_unit io; -#ifdef PNFS_THREADING HANDLE *threads; - uint32_t num_threads; -#endif uint32_t i; - DWORD status; - enum pnfs_status pnfsstat = PNFS_SUCCESS; + enum pnfs_status status = PNFS_SUCCESS; if (pattern->count == 0) goto out; -#ifdef PNFS_THREADING - /* create a thread for each unit that has actual io */ - threads = calloc(pattern->count, sizeof(HANDLE)); - if (threads == NULL) { - pnfsstat = PNFSERR_RESOURCES; + if (pattern->count == 1) { + /* no need to fork if there's only 1 thread */ + status = (enum pnfs_status)thread_fn(pattern->threads); + goto out; + } + + /* create a thread for each unit that has actual io */ + threads = calloc(pattern->count, sizeof(HANDLE)); + if (threads == NULL) { + status = PNFSERR_RESOURCES; goto out; } - num_threads = 0; for (i = 0; i < pattern->count; i++) { - if (thread_next_unit(&pattern->threads[i], &io) == PNFS_PENDING) { - threads[num_threads++] = (HANDLE)_beginthreadex(NULL, 0, - thread_fn, &pattern->threads[i], 0, NULL); + threads[i] = (HANDLE)_beginthreadex(NULL, 0, + thread_fn, &pattern->threads[i], 0, NULL); + if (threads[i] == NULL) { + eprintf("_beginthreadex() failed with %d\n", GetLastError()); + pattern->count = i; /* join any threads already started */ + break; } } - if (num_threads) { /* wait on all threads to finish */ - status = WaitForMultipleObjects(num_threads, threads, TRUE, INFINITE); - if (status == WAIT_OBJECT_0) - status = NO_ERROR; + /* wait on all threads to finish */ + status = pattern_join(threads, pattern->count); + if (status) { + eprintf("pattern_join() failed with %s\n", pnfs_error_string(status)); + goto out; + } - for (i = 0; i < num_threads; i++) { - /* keep track of the most severe error returned by a thread */ - if (GetExitCodeThread(threads[i], &status)) - pnfsstat = max(pnfsstat, (enum pnfs_status)status); + for (i = 0; i < pattern->count; i++) { + /* keep track of the most severe error returned by a thread */ + DWORD exitcode; + if (GetExitCodeThread(threads[i], &exitcode)) + status = max(status, (enum pnfs_status)exitcode); - CloseHandle(threads[i]); - } + CloseHandle(threads[i]); } free(threads); -#else - /* process each server that has actual io */ - for (i = 0; i < pattern->count; i++) { - if (thread_next_unit(&pattern->threads[i], &io) == PNFS_PENDING) { - /* keep track of the most severe error returned by a thread */ - status = thread_fn(&pattern->threads[i]); - pnfsstat = max(pnfsstat, (enum pnfs_status)status); - } - } -#endif out: - return pnfsstat; + return status; } static uint64_t pattern_bytes_transferred( @@ -376,8 +480,6 @@ static enum pnfs_status map_ds_error( AcquireSRWLockExclusive(&state->lock); /* flag the layout for return once io is finished */ state->status |= PNFS_LAYOUT_RECALLED | PNFS_LAYOUT_CHANGED; - /* reset GRANTED so we know not to try LAYOUTRETURN */ - state->status &= ~PNFS_LAYOUT_GRANTED; ReleaseSRWLockExclusive(&state->lock); /* return CHANGED to prevent any further use of the layout */ @@ -423,7 +525,7 @@ static uint32_t WINAPI file_layout_read_thread(void *args) stateid.stateid.seqid = 0; total_read = 0; - while ((status = thread_next_unit(thread, &io)) == PNFS_PENDING) { + while (thread_next_unit(thread, &io) == PNFS_PENDING) { maxreadsize = max_read_size(client->session, &thread->file->fh); if (io.length > maxreadsize) io.length = maxreadsize; @@ -498,7 +600,7 @@ retry_write: commit_max = 0; total_written = 0; - while ((status = thread_next_unit(thread, &io)) == PNFS_PENDING) { + while (thread_next_unit(thread, &io) == PNFS_PENDING) { if (io.length > maxwritesize) io.length = maxwritesize; @@ -589,8 +691,9 @@ enum pnfs_status pnfs_read( if (status == PNFS_SUCCESS) { /* interpret the layout and set up threads for io */ - status = pattern_init(&pattern, root, &state->file, stateid, layout, - buffer_out, offset, length, state->session->lease_time); + status = pattern_init(&pattern, root, &state->file, stateid, + layout, buffer_out, PNFS_IOMODE_READ, offset, length, + state->session->lease_time); if (status) eprintf("pattern_init() failed with %s\n", pnfs_error_string(status)); @@ -685,8 +788,9 @@ enum pnfs_status pnfs_write( if (status == PNFS_SUCCESS) { /* interpret the layout and set up threads for io */ - status = pattern_init(&pattern, root, &state->file, stateid, layout, - buffer, offset, length, state->session->lease_time); + status = pattern_init(&pattern, root, &state->file, stateid, + layout, buffer, PNFS_IOMODE_RW, offset, length, + state->session->lease_time); if (status) eprintf("pattern_init() failed with %s\n", pnfs_error_string(status)); diff --git a/daemon/pnfs_layout.c b/daemon/pnfs_layout.c index f677efb..7684676 100644 --- a/daemon/pnfs_layout.c +++ b/daemon/pnfs_layout.c @@ -37,6 +37,8 @@ struct pnfs_layout_list { }; #define state_entry(pos) list_container(pos, pnfs_layout_state, entry) +#define layout_entry(pos) list_container(pos, pnfs_layout, entry) +#define file_layout_entry(pos) list_container(pos, pnfs_file_layout, layout.entry) static enum pnfs_status layout_state_create( IN const nfs41_fh *meta_fh, @@ -52,6 +54,7 @@ static enum pnfs_status layout_state_create( } fh_copy(&layout->meta_fh, meta_fh); + list_init(&layout->layouts); InitializeSRWLock(&layout->lock); InitializeConditionVariable(&layout->cond); @@ -68,10 +71,19 @@ static void file_layout_free( free(layout); } +static void layout_state_free_layouts( + IN pnfs_layout_state *state) +{ + struct list_entry *entry, *tmp; + list_for_each_tmp(entry, tmp, &state->layouts) + file_layout_free(file_layout_entry(entry)); + list_init(&state->layouts); +} + static void layout_state_free( IN pnfs_layout_state *state) { - if (state->layout) file_layout_free(state->layout); + layout_state_free_layouts(state); free(state); } @@ -194,36 +206,77 @@ static enum pnfs_status layout_state_find_and_delete( /* pnfs_file_layout */ +static uint64_t range_max( + IN const pnfs_layout *layout) +{ + uint64_t result = layout->offset + layout->length; + return result < layout->offset ? NFS4_UINT64_MAX : result; +} + +static bool_t layout_sanity_check( + IN pnfs_file_layout *layout) +{ + /* prevent div/0 */ + if (layout->layout.length == 0 || + layout->layout.iomode < PNFS_IOMODE_READ || + layout->layout.iomode > PNFS_IOMODE_RW || + layout_unit_size(layout) == 0) + return FALSE; + + /* put a cap on layout.length to prevent overflow */ + layout->layout.length = range_max(&layout->layout) - layout->layout.offset; + return TRUE; +} + +static void layout_ordered_insert( + IN pnfs_layout_state *state, + IN pnfs_layout *layout) +{ + struct list_entry *entry; + list_for_each(entry, &state->layouts) { + pnfs_layout *existing = layout_entry(entry); + + /* maintain an order of increasing offset */ + if (existing->offset < layout->offset) + continue; + + /* when offsets are equal, prefer a longer segment first */ + if (existing->offset == layout->offset && + existing->length > layout->length) + continue; + + list_add(&layout->entry, existing->entry.prev, &existing->entry); + return; + } + + list_add_tail(&state->layouts, &layout->entry); +} + static enum pnfs_status layout_update_range( IN OUT pnfs_layout_state *state, IN const struct list_entry *layouts) { struct list_entry *entry, *tmp; - pnfs_layout *layout; + pnfs_file_layout *layout; enum pnfs_status status = PNFSERR_NO_LAYOUT; list_for_each_tmp(entry, tmp, layouts) { - layout = list_container(entry, pnfs_layout, entry); + layout = file_layout_entry(entry); /* don't know what to do with non-file layouts */ - if (layout->type != PNFS_LAYOUTTYPE_FILE) + if (layout->layout.type != PNFS_LAYOUTTYPE_FILE) continue; - if (state->layout == NULL) { - /* store the first file layout returned */ - dprintf(FLLVL, "Saving layout:\n"); - dprint_layout(FLLVL, (pnfs_file_layout*)layout); - - state->layout = (pnfs_file_layout*)layout; - status = PNFS_SUCCESS; - } else { - /* free anything else */ - /* TODO: attempt to merge with existing segments */ - dprintf(FLLVL, "Discarding extra layout:\n"); - dprint_layout(FLLVL, (pnfs_file_layout*)layout); - - file_layout_free((pnfs_file_layout*)layout); + if (!layout_sanity_check(layout)) { + file_layout_free(layout); + continue; } + + dprintf(FLLVL, "Saving layout:\n"); + dprint_layout(FLLVL, layout); + + layout_ordered_insert(state, &layout->layout); + status = PNFS_SUCCESS; } return status; } @@ -263,18 +316,13 @@ static enum pnfs_status layout_update( status = layout_update_stateid(state, &layoutget_res->stateid); if (status) { eprintf("LAYOUTGET returned a new stateid when we already had one\n"); - goto out_free; + goto out; } /* if a previous LAYOUTGET set return_on_close, don't overwrite it */ if (!state->return_on_close) state->return_on_close = layoutget_res->return_on_close; out: return status; - -out_free: - file_layout_free(state->layout); - state->layout = NULL; - goto out; } static enum pnfs_status file_layout_fetch( @@ -312,11 +360,6 @@ static enum pnfs_status file_layout_fetch( case NFS4_OK: /* use the LAYOUTGET results to update our view of the layout */ pnfsstat = layout_update(state, &layoutget_res); - if (pnfsstat) - break; - - /* mark granted and clear other flags */ - state->status = PNFS_LAYOUT_GRANTED; break; case NFS4ERR_BADIOMODE: @@ -348,18 +391,17 @@ static enum pnfs_status layout_coverage_status( IN uint64_t length, OUT uint64_t *offset_missing) { - pnfs_file_layout *layout; uint64_t position = offset; + struct list_entry *entry; - /* XXX: foreach layout, sorted from lowest offset */ - layout = state->layout; - if (layout) { + list_for_each(entry, &state->layouts) { /* if the current position intersects with a compatible * layout, move the position to the end of that layout */ - if (layout->layout.iomode >= iomode && - layout->layout.offset <= position && - position < layout->layout.offset + layout->layout.length) - position = layout->layout.offset + layout->layout.length; + pnfs_layout *layout = layout_entry(entry); + if (layout->iomode >= iomode && + layout->offset <= position && + position < layout->offset + layout->length) + position = layout->offset + layout->length; } if (position >= offset + length) @@ -378,6 +420,7 @@ static enum pnfs_status layout_fetch( IN uint64_t offset, IN uint64_t length) { + stateid_arg layout_stateid = { 0 }; enum pnfs_status status = PNFS_PENDING; /* check for previous errors from LAYOUTGET */ @@ -394,8 +437,9 @@ static enum pnfs_status layout_fetch( /* if there's an existing layout stateid, use it */ if (state->stateid.seqid) { - memcpy(&stateid->stateid, &state->stateid, sizeof(stateid4)); - stateid->type = STATEID_LAYOUT; + memcpy(&layout_stateid.stateid, &state->stateid, sizeof(stateid4)); + layout_stateid.type = STATEID_LAYOUT; + stateid = &layout_stateid; } if ((state->status & PNFS_LAYOUT_NOT_RW) == 0) { @@ -422,30 +466,41 @@ static enum pnfs_status device_status( IN uint64_t length, OUT unsigned char *deviceid) { - /* XXX: foreach layout */ - if (state->layout == NULL) - return PNFSERR_NO_LAYOUT; - if (state->layout->device) - return PNFS_SUCCESS; + struct list_entry *entry; + enum pnfs_status status = PNFS_SUCCESS; - /* copy missing deviceid */ - memcpy(deviceid, state->layout->deviceid, PNFS_DEVICEID_SIZE); - return PNFS_PENDING; + list_for_each(entry, &state->layouts) { + pnfs_file_layout *layout = file_layout_entry(entry); + + if (layout->device == NULL) { + /* copy missing deviceid */ + memcpy(deviceid, layout->deviceid, PNFS_DEVICEID_SIZE); + status = PNFS_PENDING; + break; + } + } + return status; } -static enum pnfs_status device_assign( +static void device_assign( IN pnfs_layout_state *state, IN const unsigned char *deviceid, IN pnfs_file_device *device) { - /* XXX: foreach layout */ - if (state->layout == NULL) - return PNFSERR_NO_LAYOUT; - /* update layouts with a matching deviceid */ - if (memcmp(state->layout->deviceid, deviceid, PNFS_DEVICEID_SIZE) == 0) - state->layout->device = device; + struct list_entry *entry; + list_for_each(entry, &state->layouts) { + pnfs_file_layout *layout = file_layout_entry(entry); - return PNFS_SUCCESS; + /* assign the device to any matching layouts */ + if (layout->device == NULL && + memcmp(layout->deviceid, deviceid, PNFS_DEVICEID_SIZE) == 0) { + layout->device = device; + + /* XXX: only assign the device to a single segment, because + * pnfs_file_device_get() only gives us a single reference */ + break; + } + } } static enum pnfs_status device_fetch( @@ -461,11 +516,9 @@ static enum pnfs_status device_fetch( status = pnfs_file_device_get(session, session->client->devices, deviceid, &device); AcquireSRWLockExclusive(&state->lock); - if (status) - goto out; - status = device_assign(state, deviceid, device); -out: + if (status == PNFS_SUCCESS) + device_assign(state, deviceid, device); return status; } @@ -610,8 +663,8 @@ out: static enum pnfs_status layout_return_status( IN const pnfs_layout_state *state) { - return (state->status & PNFS_LAYOUT_GRANTED) == 0 - ? PNFS_SUCCESS : PNFS_PENDING; + /* return the layout if we have a stateid */ + return state->stateid.seqid ? PNFS_SUCCESS : PNFS_PENDING; } static enum pnfs_status file_layout_return( @@ -660,24 +713,12 @@ static enum pnfs_status file_layout_return( status = PNFS_SUCCESS; /* update the layout range held by the client */ - file_layout_free(state->layout); - state->layout = NULL; + layout_state_free_layouts(state); - if (layoutreturn_res.stateid_present) { - /* update the layout seqid */ - /* XXX: this shouldn't happen when we send a LAYOUTRETURN - * with IOMODE_ANY for the entire range */ - memcpy(&state->stateid, &layoutreturn_res.stateid, - sizeof(stateid4)); - } else { - /* 12.5.3. Layout Stateid: Once a client has no more - * layouts on a file, the layout stateid is no longer - * valid and MUST NOT be used. */ - ZeroMemory(&state->stateid, sizeof(stateid4)); - } - - /* reset the granted flag */ - state->status &= ~PNFS_LAYOUT_GRANTED; + /* 12.5.3. Layout Stateid: Once a client has no more + * layouts on a file, the layout stateid is no longer + * valid and MUST NOT be used. */ + ZeroMemory(&state->stateid, sizeof(stateid4)); } } @@ -736,17 +777,7 @@ static void layout_recall_return( { dprintf(FLLVL, "layout_recall_return() 'forgetting' layout\n"); - if (state->layout) { - /* release our reference on the device */ - if (state->layout->device) { - pnfs_file_device_put(state->layout->device); - state->layout->device = NULL; - } - - /* update the layout range held by the client */ - file_layout_free(state->layout); - state->layout = NULL; - } + layout_state_free_layouts(state); /* since we're forgetful, we don't actually return the layout; * just zero the stateid since it won't be valid anymore */ @@ -764,7 +795,7 @@ static enum pnfs_status file_layout_recall( /* under an exclusive lock, flag the layout as recalled */ AcquireSRWLockExclusive(&state->lock); - if ((state->status & PNFS_LAYOUT_GRANTED) == 0) { + if (state->stateid.seqid == 0) { /* return NOMATCHINGLAYOUT if it wasn't actually granted */ status = PNFSERR_NO_LAYOUT; } else if (recall->recall.type == PNFS_RETURN_FILE @@ -918,24 +949,14 @@ out: /* expects caller to hold an exclusive lock on pnfs_layout_state */ -enum pnfs_status pnfs_layout_io_start( +void pnfs_layout_io_start( IN pnfs_layout_state *state) { - enum pnfs_status status = PNFS_SUCCESS; - - if ((layout_unit_size(state->layout) == 0 ) || /* prevent div/0 */ - (state->layout->device->stripes.count == 0) || - (state->layout->device->servers.count == 0)) { - status = PNFSERR_NO_LAYOUT; - } else { - /* take a reference on the layout, so that it won't be recalled - * until all io is finished */ - state->io_count++; - dprintf(FLLVL, "pnfs_layout_io_start(): count -> %u\n", - state->io_count); - } - - return status; + /* take a reference on the layout, so that it won't be recalled + * until all io is finished */ + state->io_count++; + dprintf(FLLVL, "pnfs_layout_io_start(): count -> %u\n", + state->io_count); } void pnfs_layout_io_finished( diff --git a/daemon/recovery.c b/daemon/recovery.c index 82af5a0..02cd209 100644 --- a/daemon/recovery.c +++ b/daemon/recovery.c @@ -606,7 +606,7 @@ static uint32_t stateid_array( if (open->layout) { /* layout stateid? */ AcquireSRWLockShared(&open->layout->lock); - if (open->layout->status & PNFS_LAYOUT_GRANTED) { + if (open->layout->stateid.seqid) { memcpy(&stateids[i].stateid, &open->layout->stateid, sizeof(stateid4)); stateids[i].type = STATEID_LAYOUT; stateids[i].open = open;