pnfs: prepare layout under a single lock
when starting io, both pnfs_read() and pnfs_write() need a guarantee that their range is covered by layout segments. because we have to drop the lock for LAYOUTGET and GETDEVICEINFO, earlier layout segments may be recalled during this process. to avoid this, new function pnfs_layout_state_prepare() gets called repeatedly until it can verify under a single lock that 1) the entire desired range is covered with layouts and 2) each of these layouts has an associated device. whenever pnfs_layout_state_prepare() has to drop its lock for LAYOUTGET or GETDEVICEINFO, it returns PNFS_PENDING on PNFS_SUCCESS, the caller knows that all segments in the range are valid and can dispatch io to those segments without worrying about recalls, because it still holds the pnfs_layout_state lock Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
parent
c66771cda6
commit
91609640df
4 changed files with 256 additions and 276 deletions
|
|
@ -257,10 +257,17 @@ void pnfs_layout_list_free(
|
||||||
|
|
||||||
enum pnfs_status pnfs_layout_state_open(
|
enum pnfs_status pnfs_layout_state_open(
|
||||||
IN struct __nfs41_open_state *state,
|
IN struct __nfs41_open_state *state,
|
||||||
|
OUT pnfs_layout_state **layout_out);
|
||||||
|
|
||||||
|
/* expects caller to hold an exclusive lock on pnfs_layout_state */
|
||||||
|
enum pnfs_status pnfs_layout_state_prepare(
|
||||||
|
IN pnfs_layout_state *state,
|
||||||
|
IN struct __nfs41_session *session,
|
||||||
|
IN nfs41_path_fh *meta_file,
|
||||||
|
IN struct __stateid_arg *stateid,
|
||||||
IN enum pnfs_iomode iomode,
|
IN enum pnfs_iomode iomode,
|
||||||
IN uint64_t offset,
|
IN uint64_t offset,
|
||||||
IN uint64_t length,
|
IN uint64_t length);
|
||||||
OUT pnfs_layout_state **layout_out);
|
|
||||||
|
|
||||||
void pnfs_layout_state_close(
|
void pnfs_layout_state_close(
|
||||||
IN struct __nfs41_session *session,
|
IN struct __nfs41_session *session,
|
||||||
|
|
@ -271,6 +278,7 @@ enum pnfs_status pnfs_file_layout_recall(
|
||||||
IN struct __nfs41_client *client,
|
IN struct __nfs41_client *client,
|
||||||
IN const struct cb_layoutrecall_args *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(
|
enum pnfs_status pnfs_layout_io_start(
|
||||||
IN pnfs_layout_state *state);
|
IN pnfs_layout_state *state);
|
||||||
|
|
||||||
|
|
@ -361,7 +369,7 @@ __inline uint32_t data_server_index(
|
||||||
enum pnfs_status pnfs_read(
|
enum pnfs_status pnfs_read(
|
||||||
IN struct __nfs41_root *root,
|
IN struct __nfs41_root *root,
|
||||||
IN struct __nfs41_open_state *state,
|
IN struct __nfs41_open_state *state,
|
||||||
IN const struct __stateid_arg *stateid,
|
IN struct __stateid_arg *stateid,
|
||||||
IN pnfs_layout_state *layout,
|
IN pnfs_layout_state *layout,
|
||||||
IN uint64_t offset,
|
IN uint64_t offset,
|
||||||
IN uint64_t length,
|
IN uint64_t length,
|
||||||
|
|
@ -371,7 +379,7 @@ enum pnfs_status pnfs_read(
|
||||||
enum pnfs_status pnfs_write(
|
enum pnfs_status pnfs_write(
|
||||||
IN struct __nfs41_root *root,
|
IN struct __nfs41_root *root,
|
||||||
IN struct __nfs41_open_state *state,
|
IN struct __nfs41_open_state *state,
|
||||||
IN const struct __stateid_arg *stateid,
|
IN struct __stateid_arg *stateid,
|
||||||
IN pnfs_layout_state *layout,
|
IN pnfs_layout_state *layout,
|
||||||
IN uint64_t offset,
|
IN uint64_t offset,
|
||||||
IN uint64_t length,
|
IN uint64_t length,
|
||||||
|
|
|
||||||
|
|
@ -428,8 +428,8 @@ out:
|
||||||
|
|
||||||
enum pnfs_status pnfs_read(
|
enum pnfs_status pnfs_read(
|
||||||
IN nfs41_root *root,
|
IN nfs41_root *root,
|
||||||
IN struct __nfs41_open_state *state,
|
IN nfs41_open_state *state,
|
||||||
IN const stateid_arg *stateid,
|
IN stateid_arg *stateid,
|
||||||
IN pnfs_layout_state *layout,
|
IN pnfs_layout_state *layout,
|
||||||
IN uint64_t offset,
|
IN uint64_t offset,
|
||||||
IN uint64_t length,
|
IN uint64_t length,
|
||||||
|
|
@ -443,14 +443,29 @@ enum pnfs_status pnfs_read(
|
||||||
|
|
||||||
*len_out = 0;
|
*len_out = 0;
|
||||||
|
|
||||||
|
AcquireSRWLockExclusive(&layout->lock);
|
||||||
|
|
||||||
|
/* get layouts/devices for the entire range; PNFS_PENDING means we
|
||||||
|
* dropped the lock to send an rpc, so repeat until it succeeds */
|
||||||
|
do {
|
||||||
|
status = pnfs_layout_state_prepare(layout, state->session,
|
||||||
|
&state->file, stateid, PNFS_IOMODE_READ, offset, length);
|
||||||
|
} while (status == PNFS_PENDING);
|
||||||
|
|
||||||
|
if (status == PNFS_SUCCESS) {
|
||||||
|
/* interpret the layout and set up threads for io */
|
||||||
status = pattern_init(&pattern, root, &state->file, stateid, layout,
|
status = pattern_init(&pattern, root, &state->file, stateid, layout,
|
||||||
buffer_out, offset, length, state->session->lease_time);
|
buffer_out, offset, length, state->session->lease_time);
|
||||||
if (status) {
|
if (status)
|
||||||
eprintf("pattern_init() failed with %s\n",
|
eprintf("pattern_init() failed with %s\n",
|
||||||
pnfs_error_string(status));
|
pnfs_error_string(status));
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReleaseSRWLockExclusive(&layout->lock);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
goto out;
|
||||||
|
|
||||||
status = pattern_fork(&pattern, file_layout_read_thread);
|
status = pattern_fork(&pattern, file_layout_read_thread);
|
||||||
if (status != PNFS_SUCCESS && status != PNFS_READ_EOF)
|
if (status != PNFS_SUCCESS && status != PNFS_READ_EOF)
|
||||||
goto out_free_pattern;
|
goto out_free_pattern;
|
||||||
|
|
@ -507,7 +522,7 @@ static enum pnfs_status layout_commit(
|
||||||
enum pnfs_status pnfs_write(
|
enum pnfs_status pnfs_write(
|
||||||
IN nfs41_root *root,
|
IN nfs41_root *root,
|
||||||
IN nfs41_open_state *state,
|
IN nfs41_open_state *state,
|
||||||
IN const stateid_arg *stateid,
|
IN stateid_arg *stateid,
|
||||||
IN pnfs_layout_state *layout,
|
IN pnfs_layout_state *layout,
|
||||||
IN uint64_t offset,
|
IN uint64_t offset,
|
||||||
IN uint64_t length,
|
IN uint64_t length,
|
||||||
|
|
@ -524,14 +539,29 @@ enum pnfs_status pnfs_write(
|
||||||
|
|
||||||
*len_out = 0;
|
*len_out = 0;
|
||||||
|
|
||||||
|
AcquireSRWLockExclusive(&layout->lock);
|
||||||
|
|
||||||
|
/* get layouts/devices for the entire range; PNFS_PENDING means we
|
||||||
|
* dropped the lock to send an rpc, so repeat until it succeeds */
|
||||||
|
do {
|
||||||
|
status = pnfs_layout_state_prepare(layout, state->session,
|
||||||
|
&state->file, stateid, PNFS_IOMODE_RW, offset, length);
|
||||||
|
} while (status == PNFS_PENDING);
|
||||||
|
|
||||||
|
if (status == PNFS_SUCCESS) {
|
||||||
|
/* interpret the layout and set up threads for io */
|
||||||
status = pattern_init(&pattern, root, &state->file, stateid, layout,
|
status = pattern_init(&pattern, root, &state->file, stateid, layout,
|
||||||
buffer, offset, length, state->session->lease_time);
|
buffer, offset, length, state->session->lease_time);
|
||||||
if (status) {
|
if (status)
|
||||||
eprintf("pattern_init() failed with %s\n",
|
eprintf("pattern_init() failed with %s\n",
|
||||||
pnfs_error_string(status));
|
pnfs_error_string(status));
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReleaseSRWLockExclusive(&layout->lock);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
goto out;
|
||||||
|
|
||||||
status = pattern_fork(&pattern, file_layout_write_thread);
|
status = pattern_fork(&pattern, file_layout_write_thread);
|
||||||
/* on layout recall, we still attempt to commit what we wrote */
|
/* on layout recall, we still attempt to commit what we wrote */
|
||||||
if (status != PNFS_SUCCESS && status != PNFSERR_LAYOUT_RECALLED)
|
if (status != PNFS_SUCCESS && status != PNFSERR_LAYOUT_RECALLED)
|
||||||
|
|
|
||||||
|
|
@ -338,29 +338,39 @@ static enum pnfs_status file_layout_fetch(
|
||||||
return pnfsstat;
|
return pnfsstat;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum pnfs_status layout_grant_status(
|
/* returns PNFS_SUCCESS if the client holds valid layouts that cover
|
||||||
IN const pnfs_layout_state *layout,
|
* the entire range requested. otherwise, returns PNFS_PENDING and
|
||||||
IN enum pnfs_iomode iomode)
|
* sets 'offset_missing' to the lowest offset that is not covered */
|
||||||
|
static enum pnfs_status layout_coverage_status(
|
||||||
|
IN pnfs_layout_state *state,
|
||||||
|
IN enum pnfs_iomode iomode,
|
||||||
|
IN uint64_t offset,
|
||||||
|
IN uint64_t length,
|
||||||
|
OUT uint64_t *offset_missing)
|
||||||
{
|
{
|
||||||
enum pnfs_status status = PNFS_PENDING;
|
pnfs_file_layout *layout;
|
||||||
|
uint64_t position = offset;
|
||||||
|
|
||||||
if (layout->status & PNFS_LAYOUT_RECALLED) {
|
/* XXX: foreach layout, sorted from lowest offset */
|
||||||
/* don't use a recalled layout */
|
layout = state->layout;
|
||||||
status = PNFSERR_LAYOUT_RECALLED;
|
if (layout) {
|
||||||
} else if (layout->status & PNFS_LAYOUT_GRANTED) {
|
/* if the current position intersects with a compatible
|
||||||
/* the layout is granted; use it if it's compatible */
|
* layout, move the position to the end of that layout */
|
||||||
status = PNFS_SUCCESS;
|
if (layout->layout.iomode >= iomode &&
|
||||||
} else if ((layout->status & PNFS_LAYOUT_UNAVAILABLE) ||
|
layout->layout.offset <= position &&
|
||||||
(iomode == PNFS_IOMODE_RW && layout->status & PNFS_LAYOUT_NOT_RW)) {
|
position < layout->layout.offset + layout->layout.length)
|
||||||
/* an error from LAYOUTGET indicated that the server
|
position = layout->layout.offset + layout->layout.length;
|
||||||
* won't ever grant this layout, so stop trying */
|
|
||||||
status = PNFSERR_NOT_SUPPORTED;
|
|
||||||
}
|
}
|
||||||
return status;
|
|
||||||
|
if (position >= offset + length)
|
||||||
|
return PNFS_SUCCESS;
|
||||||
|
|
||||||
|
*offset_missing = position;
|
||||||
|
return PNFS_PENDING;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum pnfs_status file_layout_cache(
|
static enum pnfs_status layout_fetch(
|
||||||
IN OUT pnfs_layout_state *state,
|
IN pnfs_layout_state *state,
|
||||||
IN nfs41_session *session,
|
IN nfs41_session *session,
|
||||||
IN nfs41_path_fh *meta_file,
|
IN nfs41_path_fh *meta_file,
|
||||||
IN stateid_arg *stateid,
|
IN stateid_arg *stateid,
|
||||||
|
|
@ -368,26 +378,20 @@ static enum pnfs_status file_layout_cache(
|
||||||
IN uint64_t offset,
|
IN uint64_t offset,
|
||||||
IN uint64_t length)
|
IN uint64_t length)
|
||||||
{
|
{
|
||||||
enum pnfs_status status;
|
enum pnfs_status status = PNFS_PENDING;
|
||||||
|
|
||||||
/* use a shared lock to see if it's already been granted */
|
/* check for previous errors from LAYOUTGET */
|
||||||
AcquireSRWLockShared(&state->lock);
|
if ((state->status & PNFS_LAYOUT_UNAVAILABLE) ||
|
||||||
status = layout_grant_status(state, iomode);
|
((state->status & PNFS_LAYOUT_NOT_RW) && iomode == PNFS_IOMODE_RW)) {
|
||||||
ReleaseSRWLockShared(&state->lock);
|
status = PNFSERR_NO_LAYOUT;
|
||||||
|
|
||||||
if (status != PNFS_PENDING)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
/* use an exclusive lock while attempting to get a new layout */
|
|
||||||
AcquireSRWLockExclusive(&state->lock);
|
|
||||||
|
|
||||||
/* wait for any pending LAYOUTGETs/LAYOUTRETURNs */
|
/* wait for any pending LAYOUTGETs/LAYOUTRETURNs */
|
||||||
while (state->pending)
|
while (state->pending)
|
||||||
SleepConditionVariableSRW(&state->cond, &state->lock, INFINITE, 0);
|
SleepConditionVariableSRW(&state->cond, &state->lock, INFINITE, 0);
|
||||||
state->pending = TRUE;
|
state->pending = TRUE;
|
||||||
|
|
||||||
status = layout_grant_status(state, iomode);
|
|
||||||
if (status == PNFS_PENDING) {
|
|
||||||
/* if there's an existing layout stateid, use it */
|
/* if there's an existing layout stateid, use it */
|
||||||
if (state->stateid.seqid) {
|
if (state->stateid.seqid) {
|
||||||
memcpy(&stateid->stateid, &state->stateid, sizeof(stateid4));
|
memcpy(&stateid->stateid, &state->stateid, sizeof(stateid4));
|
||||||
|
|
@ -397,121 +401,167 @@ static enum pnfs_status file_layout_cache(
|
||||||
if ((state->status & PNFS_LAYOUT_NOT_RW) == 0) {
|
if ((state->status & PNFS_LAYOUT_NOT_RW) == 0) {
|
||||||
/* try to get a RW layout first */
|
/* try to get a RW layout first */
|
||||||
status = file_layout_fetch(state, session, meta_file,
|
status = file_layout_fetch(state, session, meta_file,
|
||||||
stateid, PNFS_IOMODE_RW, offset, 0, NFS4_UINT32_MAX);
|
stateid, PNFS_IOMODE_RW, offset, length, NFS4_UINT64_MAX);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status && iomode == PNFS_IOMODE_READ) {
|
if (status && iomode == PNFS_IOMODE_READ) {
|
||||||
/* fall back on READ if necessary */
|
/* fall back on READ if necessary */
|
||||||
status = file_layout_fetch(state, session, meta_file,
|
status = file_layout_fetch(state, session, meta_file,
|
||||||
stateid, iomode, offset, 0, NFS4_UINT32_MAX);
|
stateid, iomode, offset, length, NFS4_UINT64_MAX);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state->pending = FALSE;
|
state->pending = FALSE;
|
||||||
WakeConditionVariable(&state->cond);
|
WakeConditionVariable(&state->cond);
|
||||||
ReleaseSRWLockExclusive(&state->lock);
|
|
||||||
out:
|
out:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum pnfs_status layout_compatible(
|
static enum pnfs_status device_status(
|
||||||
IN OUT pnfs_layout_state *state,
|
IN pnfs_layout_state *state,
|
||||||
IN enum pnfs_iomode iomode,
|
|
||||||
IN uint64_t offset,
|
IN uint64_t offset,
|
||||||
IN uint64_t length)
|
IN uint64_t length,
|
||||||
|
OUT unsigned char *deviceid)
|
||||||
{
|
{
|
||||||
pnfs_layout *layout;
|
/* XXX: foreach layout */
|
||||||
enum pnfs_status status = PNFS_SUCCESS;
|
if (state->layout == NULL)
|
||||||
|
return PNFSERR_NO_LAYOUT;
|
||||||
AcquireSRWLockShared(&state->lock);
|
if (state->layout->device)
|
||||||
|
return PNFS_SUCCESS;
|
||||||
if (state->layout == NULL) {
|
|
||||||
status = PNFSERR_NOT_SUPPORTED;
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
layout = &state->layout->layout;
|
|
||||||
if (iomode == PNFS_IOMODE_RW && layout->iomode == PNFS_IOMODE_READ) {
|
|
||||||
status = PNFSERR_NOT_SUPPORTED;
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
if (offset < layout->offset ||
|
|
||||||
offset + length > layout->offset + layout->length) {
|
|
||||||
status = PNFSERR_NOT_SUPPORTED;
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
out_unlock:
|
|
||||||
ReleaseSRWLockShared(&state->lock);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum pnfs_status file_device_status(
|
|
||||||
IN const pnfs_layout_state *state)
|
|
||||||
{
|
|
||||||
enum pnfs_status status = PNFS_PENDING;
|
|
||||||
|
|
||||||
if (state->layout == NULL) {
|
|
||||||
status = PNFSERR_NO_LAYOUT;
|
|
||||||
} else if (state->status & PNFS_LAYOUT_RECALLED) {
|
|
||||||
/* don't fetch deviceinfo for a recalled layout */
|
|
||||||
status = PNFSERR_LAYOUT_RECALLED;
|
|
||||||
} else if (state->status & PNFS_LAYOUT_HAS_DEVICE) {
|
|
||||||
/* deviceinfo already cached */
|
|
||||||
status = PNFS_SUCCESS;
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum pnfs_status file_layout_device(
|
|
||||||
IN OUT pnfs_layout_state *state,
|
|
||||||
IN nfs41_session *session)
|
|
||||||
{
|
|
||||||
enum pnfs_status status = PNFS_PENDING;
|
|
||||||
|
|
||||||
/* use a shared lock to see if we already have a device */
|
|
||||||
AcquireSRWLockShared(&state->lock);
|
|
||||||
status = file_device_status(state);
|
|
||||||
ReleaseSRWLockShared(&state->lock);
|
|
||||||
|
|
||||||
if (status != PNFS_PENDING)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* use an exclusive lock to look up device info */
|
|
||||||
AcquireSRWLockExclusive(&state->lock);
|
|
||||||
|
|
||||||
/* wait for any pending LAYOUTGETs/LAYOUTRETURNs */
|
|
||||||
while (state->pending)
|
|
||||||
SleepConditionVariableSRW(&state->cond, &state->lock, INFINITE, 0);
|
|
||||||
state->pending = TRUE;
|
|
||||||
|
|
||||||
status = file_device_status(state);
|
|
||||||
if (status == PNFS_PENDING) {
|
|
||||||
unsigned char deviceid[PNFS_DEVICEID_SIZE];
|
|
||||||
pnfs_file_device *device;
|
|
||||||
|
|
||||||
|
/* copy missing deviceid */
|
||||||
memcpy(deviceid, state->layout->deviceid, PNFS_DEVICEID_SIZE);
|
memcpy(deviceid, state->layout->deviceid, PNFS_DEVICEID_SIZE);
|
||||||
|
return PNFS_PENDING;
|
||||||
|
}
|
||||||
|
|
||||||
/* drop the lock during the rpc call */
|
static enum pnfs_status 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;
|
||||||
|
|
||||||
|
return PNFS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum pnfs_status device_fetch(
|
||||||
|
IN pnfs_layout_state *state,
|
||||||
|
IN nfs41_session *session,
|
||||||
|
IN unsigned char *deviceid)
|
||||||
|
{
|
||||||
|
pnfs_file_device *device;
|
||||||
|
enum pnfs_status status;
|
||||||
|
|
||||||
|
/* drop the layoutstate lock for the rpc call */
|
||||||
ReleaseSRWLockExclusive(&state->lock);
|
ReleaseSRWLockExclusive(&state->lock);
|
||||||
status = pnfs_file_device_get(session,
|
status = pnfs_file_device_get(session,
|
||||||
session->client->devices, deviceid, &device);
|
session->client->devices, deviceid, &device);
|
||||||
AcquireSRWLockExclusive(&state->lock);
|
AcquireSRWLockExclusive(&state->lock);
|
||||||
|
if (status)
|
||||||
|
goto out;
|
||||||
|
|
||||||
if (status == PNFS_SUCCESS) {
|
status = device_assign(state, deviceid, device);
|
||||||
state->layout->device = device;
|
|
||||||
state->status |= PNFS_LAYOUT_HAS_DEVICE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
state->pending = FALSE;
|
|
||||||
WakeConditionVariable(&state->cond);
|
|
||||||
ReleaseSRWLockExclusive(&state->lock);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum pnfs_status file_layout_get(
|
|
||||||
IN OUT pnfs_layout_state *state,
|
/* nfs41_open_state */
|
||||||
|
static enum pnfs_status client_supports_pnfs(
|
||||||
|
IN nfs41_client *client)
|
||||||
|
{
|
||||||
|
enum pnfs_status status;
|
||||||
|
AcquireSRWLockShared(&client->exid_lock);
|
||||||
|
status = client->roles & EXCHGID4_FLAG_USE_PNFS_MDS
|
||||||
|
? PNFS_SUCCESS : PNFSERR_NOT_SUPPORTED;
|
||||||
|
ReleaseSRWLockShared(&client->exid_lock);
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum pnfs_status fs_supports_layout(
|
||||||
|
IN const nfs41_superblock *superblock,
|
||||||
|
IN enum pnfs_layout_type type)
|
||||||
|
{
|
||||||
|
const uint32_t flag = 1 << (type - 1);
|
||||||
|
return (superblock->layout_types & flag) == 0
|
||||||
|
? PNFSERR_NOT_SUPPORTED : PNFS_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static enum pnfs_status open_state_layout_cached(
|
||||||
|
IN nfs41_open_state *state,
|
||||||
|
OUT pnfs_layout_state **layout_out)
|
||||||
|
{
|
||||||
|
enum pnfs_status status = PNFSERR_NO_LAYOUT;
|
||||||
|
|
||||||
|
if (state->layout) {
|
||||||
|
status = PNFS_SUCCESS;
|
||||||
|
*layout_out = state->layout;
|
||||||
|
|
||||||
|
dprintf(FLLVL, "pnfs_open_state_layout() found "
|
||||||
|
"cached layout %p\n", *layout_out);
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum pnfs_status pnfs_layout_state_open(
|
||||||
|
IN nfs41_open_state *state,
|
||||||
|
OUT pnfs_layout_state **layout_out)
|
||||||
|
{
|
||||||
|
struct pnfs_layout_list *layouts = state->session->client->layouts;
|
||||||
|
nfs41_session *session = state->session;
|
||||||
|
pnfs_layout_state *layout;
|
||||||
|
enum pnfs_status status;
|
||||||
|
|
||||||
|
dprintf(FLLVL, "--> pnfs_layout_state_open()\n");
|
||||||
|
|
||||||
|
status = client_supports_pnfs(session->client);
|
||||||
|
if (status)
|
||||||
|
goto out;
|
||||||
|
status = fs_supports_layout(state->file.fh.superblock, PNFS_LAYOUTTYPE_FILE);
|
||||||
|
if (status)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* under shared lock, check open state for cached layouts */
|
||||||
|
AcquireSRWLockShared(&state->lock);
|
||||||
|
status = open_state_layout_cached(state, &layout);
|
||||||
|
ReleaseSRWLockShared(&state->lock);
|
||||||
|
|
||||||
|
if (status) {
|
||||||
|
/* under exclusive lock, find or create a layout for this file */
|
||||||
|
AcquireSRWLockExclusive(&state->lock);
|
||||||
|
|
||||||
|
status = open_state_layout_cached(state, &layout);
|
||||||
|
if (status) {
|
||||||
|
status = layout_state_find_or_create(layouts, &state->file.fh, &layout);
|
||||||
|
if (status == PNFS_SUCCESS) {
|
||||||
|
LONG open_count = InterlockedIncrement(&layout->open_count);
|
||||||
|
state->layout = layout;
|
||||||
|
|
||||||
|
dprintf(FLLVL, "pnfs_layout_state_open() caching layout %p "
|
||||||
|
"(%u opens)\n", state->layout, open_count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReleaseSRWLockExclusive(&state->lock);
|
||||||
|
|
||||||
|
if (status)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
*layout_out = layout;
|
||||||
|
out:
|
||||||
|
dprintf(FLLVL, "<-- pnfs_layout_state_open() returning %s\n",
|
||||||
|
pnfs_error_string(status));
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* expects caller to hold an exclusive lock on pnfs_layout_state */
|
||||||
|
enum pnfs_status pnfs_layout_state_prepare(
|
||||||
|
IN pnfs_layout_state *state,
|
||||||
IN nfs41_session *session,
|
IN nfs41_session *session,
|
||||||
IN nfs41_path_fh *meta_file,
|
IN nfs41_path_fh *meta_file,
|
||||||
IN stateid_arg *stateid,
|
IN stateid_arg *stateid,
|
||||||
|
|
@ -519,30 +569,38 @@ static enum pnfs_status file_layout_get(
|
||||||
IN uint64_t offset,
|
IN uint64_t offset,
|
||||||
IN uint64_t length)
|
IN uint64_t length)
|
||||||
{
|
{
|
||||||
|
unsigned char deviceid[PNFS_DEVICEID_SIZE];
|
||||||
|
uint64_t missing;
|
||||||
enum pnfs_status status;
|
enum pnfs_status status;
|
||||||
|
|
||||||
/* request a range that covers this io */
|
/* check for layout recall */
|
||||||
status = file_layout_cache(state, session,
|
if (state->status & PNFS_LAYOUT_RECALLED) {
|
||||||
meta_file, stateid, iomode, offset, length);
|
status = PNFSERR_LAYOUT_RECALLED;
|
||||||
if (status) {
|
|
||||||
dprintf(FLLVL, "file_layout_cache() failed with %s\n",
|
|
||||||
pnfs_error_string(status));
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* fail if we don't get everything we asked for */
|
/* if part of the given range is not covered by a layout,
|
||||||
status = layout_compatible(state, iomode, offset, length);
|
* attempt to fetch it with LAYOUTGET */
|
||||||
if (status) {
|
status = layout_coverage_status(state, iomode, offset, length, &missing);
|
||||||
dprintf(FLLVL, "file_layout_compatible() failed with %s\n",
|
if (status == PNFS_PENDING) {
|
||||||
pnfs_error_string(status));
|
status = layout_fetch(state, session, meta_file, stateid,
|
||||||
|
iomode, missing, offset + length - missing);
|
||||||
|
|
||||||
|
/* return pending because layout_fetch() dropped the lock */
|
||||||
|
if (status == PNFS_SUCCESS)
|
||||||
|
status = PNFS_PENDING;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* make sure we have a device for the layout */
|
/* if any layouts in the range are missing device info,
|
||||||
status = file_layout_device(state, session);
|
* fetch them with GETDEVICEINFO */
|
||||||
if (status) {
|
status = device_status(state, offset, length, deviceid);
|
||||||
dprintf(FLLVL, "file_layout_device() failed with %s\n",
|
if (status == PNFS_PENDING) {
|
||||||
pnfs_error_string(status));
|
status = device_fetch(state, session, deviceid);
|
||||||
|
|
||||||
|
/* return pending because device_fetch() dropped the lock */
|
||||||
|
if (status == PNFS_SUCCESS)
|
||||||
|
status = PNFS_PENDING;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
out:
|
out:
|
||||||
|
|
@ -633,114 +691,6 @@ out:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* nfs41_open_state */
|
|
||||||
static enum pnfs_status client_supports_pnfs(
|
|
||||||
IN nfs41_client *client)
|
|
||||||
{
|
|
||||||
enum pnfs_status status;
|
|
||||||
AcquireSRWLockShared(&client->exid_lock);
|
|
||||||
status = client->roles & EXCHGID4_FLAG_USE_PNFS_MDS
|
|
||||||
? PNFS_SUCCESS : PNFSERR_NOT_SUPPORTED;
|
|
||||||
ReleaseSRWLockShared(&client->exid_lock);
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum pnfs_status fs_supports_layout(
|
|
||||||
IN const nfs41_superblock *superblock,
|
|
||||||
IN enum pnfs_layout_type type)
|
|
||||||
{
|
|
||||||
const uint32_t flag = 1 << (type - 1);
|
|
||||||
return (superblock->layout_types & flag) == 0
|
|
||||||
? PNFSERR_NOT_SUPPORTED : PNFS_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum pnfs_status open_state_layout_cached(
|
|
||||||
IN nfs41_open_state *state,
|
|
||||||
IN enum pnfs_iomode iomode,
|
|
||||||
IN uint64_t offset,
|
|
||||||
IN uint64_t length,
|
|
||||||
OUT pnfs_layout_state **layout_out)
|
|
||||||
{
|
|
||||||
enum pnfs_status status = PNFSERR_NO_LAYOUT;
|
|
||||||
|
|
||||||
if (state->layout) {
|
|
||||||
status = PNFS_SUCCESS;
|
|
||||||
*layout_out = state->layout;
|
|
||||||
|
|
||||||
dprintf(FLLVL, "pnfs_open_state_layout() found "
|
|
||||||
"cached layout %p\n", *layout_out);
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum pnfs_status pnfs_layout_state_open(
|
|
||||||
IN nfs41_open_state *state,
|
|
||||||
IN enum pnfs_iomode iomode,
|
|
||||||
IN uint64_t offset,
|
|
||||||
IN uint64_t length,
|
|
||||||
OUT pnfs_layout_state **layout_out)
|
|
||||||
{
|
|
||||||
struct pnfs_layout_list *layouts = state->session->client->layouts;
|
|
||||||
nfs41_session *session = state->session;
|
|
||||||
stateid_arg stateid;
|
|
||||||
pnfs_layout_state *layout;
|
|
||||||
enum pnfs_status status;
|
|
||||||
|
|
||||||
dprintf(FLLVL, "--> pnfs_layout_state_open()\n");
|
|
||||||
|
|
||||||
status = client_supports_pnfs(session->client);
|
|
||||||
if (status)
|
|
||||||
goto out;
|
|
||||||
status = fs_supports_layout(state->file.fh.superblock, PNFS_LAYOUTTYPE_FILE);
|
|
||||||
if (status)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* under shared lock, check open state for cached layouts */
|
|
||||||
AcquireSRWLockShared(&state->lock);
|
|
||||||
status = open_state_layout_cached(state, iomode, offset, length, &layout);
|
|
||||||
ReleaseSRWLockShared(&state->lock);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
/* under exclusive lock, find or create a layout for this file */
|
|
||||||
AcquireSRWLockExclusive(&state->lock);
|
|
||||||
|
|
||||||
status = open_state_layout_cached(state, iomode, offset, length, &layout);
|
|
||||||
if (status) {
|
|
||||||
status = layout_state_find_or_create(layouts, &state->file.fh, &layout);
|
|
||||||
if (status == PNFS_SUCCESS) {
|
|
||||||
LONG open_count = InterlockedIncrement(&layout->open_count);
|
|
||||||
state->layout = layout;
|
|
||||||
|
|
||||||
dprintf(FLLVL, "pnfs_layout_state_open() caching layout %p "
|
|
||||||
"(%u opens)\n", state->layout, open_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReleaseSRWLockExclusive(&state->lock);
|
|
||||||
|
|
||||||
if (status)
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
nfs41_open_stateid_arg(state, &stateid);
|
|
||||||
|
|
||||||
/* make sure the layout can satisfy this request */
|
|
||||||
status = file_layout_get(layout, session, &state->file,
|
|
||||||
&stateid, iomode, offset, length);
|
|
||||||
if (status) {
|
|
||||||
dprintf(FLLVL, "file_layout_get() failed with %s\n",
|
|
||||||
pnfs_error_string(status));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
*layout_out = layout;
|
|
||||||
out:
|
|
||||||
dprintf(FLLVL, "<-- pnfs_layout_state_open() returning %s\n",
|
|
||||||
pnfs_error_string(status));
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
void pnfs_layout_state_close(
|
void pnfs_layout_state_close(
|
||||||
IN nfs41_session *session,
|
IN nfs41_session *session,
|
||||||
IN nfs41_open_state *state,
|
IN nfs41_open_state *state,
|
||||||
|
|
@ -967,18 +917,13 @@ out:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* expects caller to hold an exclusive lock on pnfs_layout_state */
|
||||||
enum pnfs_status pnfs_layout_io_start(
|
enum pnfs_status pnfs_layout_io_start(
|
||||||
IN pnfs_layout_state *state)
|
IN pnfs_layout_state *state)
|
||||||
{
|
{
|
||||||
enum pnfs_status status = PNFS_SUCCESS;
|
enum pnfs_status status = PNFS_SUCCESS;
|
||||||
|
|
||||||
AcquireSRWLockExclusive(&state->lock);
|
if ((layout_unit_size(state->layout) == 0 ) || /* prevent div/0 */
|
||||||
|
|
||||||
if ((state->status & PNFS_LAYOUT_RECALLED) != 0) {
|
|
||||||
/* don't start any more io if the layout has been recalled */
|
|
||||||
status = PNFSERR_LAYOUT_RECALLED;
|
|
||||||
dprintf(FLLVL, "pnfs_layout_io_start() failed, layout was recalled\n");
|
|
||||||
} else if ((layout_unit_size(state->layout) == 0 ) || /* prevent div/0 */
|
|
||||||
(state->layout->device->stripes.count == 0) ||
|
(state->layout->device->stripes.count == 0) ||
|
||||||
(state->layout->device->servers.count == 0)) {
|
(state->layout->device->servers.count == 0)) {
|
||||||
status = PNFSERR_NO_LAYOUT;
|
status = PNFSERR_NO_LAYOUT;
|
||||||
|
|
@ -990,7 +935,6 @@ enum pnfs_status pnfs_layout_io_start(
|
||||||
state->io_count);
|
state->io_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
ReleaseSRWLockExclusive(&state->lock);
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,8 +114,7 @@ static int read_from_pnfs(
|
||||||
enum pnfs_status pnfsstat;
|
enum pnfs_status pnfsstat;
|
||||||
int status = NO_ERROR;
|
int status = NO_ERROR;
|
||||||
|
|
||||||
if (pnfs_layout_state_open(upcall->state_ref, PNFS_IOMODE_READ,
|
if (pnfs_layout_state_open(upcall->state_ref, &layout)) {
|
||||||
args->offset, args->len, &layout)) {
|
|
||||||
status = ERROR_NOT_SUPPORTED;
|
status = ERROR_NOT_SUPPORTED;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
@ -250,15 +249,14 @@ out_verify_failed:
|
||||||
|
|
||||||
static int write_to_pnfs(
|
static int write_to_pnfs(
|
||||||
IN nfs41_upcall *upcall,
|
IN nfs41_upcall *upcall,
|
||||||
IN const stateid_arg *stateid)
|
IN stateid_arg *stateid)
|
||||||
{
|
{
|
||||||
readwrite_upcall_args *args = &upcall->args.rw;
|
readwrite_upcall_args *args = &upcall->args.rw;
|
||||||
pnfs_layout_state *layout;
|
pnfs_layout_state *layout;
|
||||||
int status = NO_ERROR;
|
int status = NO_ERROR;
|
||||||
nfs41_file_info info = { 0 };
|
nfs41_file_info info = { 0 };
|
||||||
|
|
||||||
if (pnfs_layout_state_open(upcall->state_ref, PNFS_IOMODE_RW, args->offset,
|
if (pnfs_layout_state_open(upcall->state_ref, &layout)) {
|
||||||
args->len, &layout)) {
|
|
||||||
status = ERROR_NOT_SUPPORTED;
|
status = ERROR_NOT_SUPPORTED;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue