/* Editor Settings: expandtabs and use 4 spaces for indentation
* ex: set softtabstop=4 tabstop=8 expandtab shiftwidth=4: *
* -*- mode: c, c-basic-offset: 4 -*- */
/*
* Copyright Likewise Software
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or (at
* your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details. You should have received a copy of the GNU General
* Public License along with this program. If not, see
* .
*
* LIKEWISE SOFTWARE MAKES THIS SOFTWARE AVAILABLE UNDER OTHER LICENSING
* TERMS AS WELL. IF YOU HAVE ENTERED INTO A SEPARATE LICENSE AGREEMENT
* WITH LIKEWISE SOFTWARE, THEN YOU MAY ELECT TO USE THE SOFTWARE UNDER THE
* TERMS OF THAT SOFTWARE LICENSE AGREEMENT INSTEAD OF THE TERMS OF THE GNU
* GENERAL PUBLIC LICENSE, NOTWITHSTANDING THE ABOVE NOTICE. IF YOU
* HAVE QUESTIONS, OR WISH TO REQUEST A COPY OF THE ALTERNATE LICENSING
* TERMS OFFERED BY LIKEWISE SOFTWARE, PLEASE CONTACT LIKEWISE SOFTWARE AT
* license@likewisesoftware.com
*/
/*
* Copyright (C) Likewise Software. All rights reserved.
*
* Module Name:
*
* async_handler.c
*
* Abstract:
*
* Likewise Posix File System Driver (PVFS)
*
* Async IRP dispatch routines
*
* Authors: Gerald Carter
*/
#include "pvfs.h"
/* Forward declarations */
/* Code */
/***********************************************************************
**********************************************************************/
VOID
PvfsQueueCancelIrp(
PIRP pIrp,
PVOID pCancelContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_IRP_CONTEXT pIrpContext = (PPVFS_IRP_CONTEXT)pCancelContext;
USHORT SetFlag = 0;
SetFlag = PvfsIrpContextConditionalSetFlag(
pIrpContext,
PVFS_IRP_CTX_FLAG_ACTIVE,
PVFS_IRP_CTX_FLAG_REQUEST_CANCEL,
PVFS_IRP_CTX_FLAG_CANCELLED);
if (IsSetFlag(SetFlag, PVFS_IRP_CTX_FLAG_CANCELLED))
{
switch(pIrpContext->QueueType)
{
case PVFS_QUEUE_TYPE_IO:
/* Nothing to do. Let the general Io Work queue processing
handle it */
ntError = STATUS_SUCCESS;
break;
case PVFS_QUEUE_TYPE_OPLOCK:
ntError = PvfsScheduleCancelOplock(pIrpContext);
break;
case PVFS_QUEUE_TYPE_PENDING_OPLOCK_BREAK:
ntError = PvfsScheduleCancelPendingOp(pIrpContext);
break;
case PVFS_QUEUE_TYPE_PENDING_LOCK:
ntError = PvfsScheduleCancelLock(pIrpContext);
break;
case PVFS_QUEUE_TYPE_NOTIFY:
ntError = PvfsScheduleCancelNotify(pIrpContext);
break;
default:
/* Should never be reachable */
ntError = STATUS_INTERNAL_ERROR;
break;
}
}
return;
}
/***********************************************************************
**********************************************************************/
NTSTATUS
PvfsQueueCancelIrpIfRequested(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_SUCCESS;
USHORT SetFlag = 0;
/* First check to see if we've been requested to cancel the IRP */
SetFlag = PvfsIrpContextConditionalSetFlag(
pIrpContext,
PVFS_IRP_CTX_FLAG_REQUEST_CANCEL,
PVFS_IRP_CTX_FLAG_CANCELLED,
0);
if (IsSetFlag(SetFlag, PVFS_IRP_CTX_FLAG_CANCELLED))
{
PvfsIrpContextClearFlag(pIrpContext, PVFS_IRP_CTX_FLAG_ACTIVE);
PvfsQueueCancelIrp(pIrpContext->pIrp, pIrpContext);
ntError = STATUS_CANCELLED;
}
return ntError;
}
/***********************************************************************
**********************************************************************/
static NTSTATUS
PvfsScheduleIoWorkItem(
IN PPVFS_WORK_CONTEXT pWorkContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_IRP_CONTEXT pIrpCtx = NULL;
if (pWorkContext->bIsIrpContext)
{
pIrpCtx = (PPVFS_IRP_CONTEXT)pWorkContext->pContext;
pIrpCtx->QueueType = PVFS_QUEUE_TYPE_IO;
PvfsIrpMarkPending(pIrpCtx, PvfsQueueCancelIrp, pIrpCtx);
}
ntError = PvfsAddWorkItem(gpPvfsIoWorkQueue, (PVOID)pWorkContext);
if (ntError != STATUS_SUCCESS && pWorkContext->bIsIrpContext)
{
pIrpCtx->pIrp->IoStatusBlock.Status = ntError;
PvfsAsyncIrpComplete(pIrpCtx);
}
BAIL_ON_NT_STATUS(ntError);
ntError = STATUS_PENDING;
cleanup:
return ntError;
error:
goto cleanup;
}
/*****************************************************************************
****************************************************************************/
NTSTATUS
PvfsCreateWorkContext(
OUT PPVFS_WORK_CONTEXT *ppWorkContext,
IN BOOLEAN bIsIrpContext,
IN PVOID pContext,
IN PPVFS_WORK_CONTEXT_CALLBACK pfnCompletion,
IN PPVFS_WORK_CONTEXT_FREE_CTX pfnFreeContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsAllocateMemory(
(PVOID*)&pWorkCtx,
sizeof(PVFS_WORK_CONTEXT));
BAIL_ON_NT_STATUS(ntError);
pWorkCtx->bIsIrpContext = bIsIrpContext;
if (bIsIrpContext)
{
pWorkCtx->pContext = (PVOID)PvfsReferenceIrpContext(
(PPVFS_IRP_CONTEXT)pContext);
}
else
{
pWorkCtx->pContext = pContext;
}
pWorkCtx->pfnCompletion = pfnCompletion;
pWorkCtx->pfnFreeContext = pfnFreeContext;
*ppWorkContext = pWorkCtx;
#ifdef _PVFS_DEVELOPER_DEBUG
InterlockedIncrement(&gPvfsWorkContextCount);
#endif
ntError = STATUS_SUCCESS;
cleanup:
return ntError;
error:
goto cleanup;
}
/*****************************************************************************
****************************************************************************/
VOID
PvfsFreeWorkContext(
IN OUT PPVFS_WORK_CONTEXT *ppWorkContext
)
{
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
if (ppWorkContext && *ppWorkContext)
{
pWorkCtx = *ppWorkContext;
if (pWorkCtx->pContext)
{
if (pWorkCtx->bIsIrpContext)
{
PvfsReleaseIrpContext((PPVFS_IRP_CONTEXT*)&pWorkCtx->pContext);
}
else
{
if (pWorkCtx->pfnFreeContext)
{
pWorkCtx->pfnFreeContext(&pWorkCtx->pContext);
}
else
{
PVFS_FREE(&pWorkCtx->pContext);
}
}
}
PVFS_FREE(ppWorkContext);
#ifdef _PVFS_DEVELOPER_DEBUG
InterlockedDecrement(&gPvfsWorkContextCount);
#endif
}
return;
}
/************************************************************
***********************************************************/
NTSTATUS
PvfsAsyncCreate(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsCreateWorkContext(
&pWorkCtx,
TRUE,
(PVOID)pIrpContext,
(PPVFS_WORK_CONTEXT_CALLBACK)PvfsCreate,
NULL);
BAIL_ON_NT_STATUS(ntError);
ntError = PvfsScheduleIoWorkItem(pWorkCtx);
if (ntError == STATUS_PENDING)
{
pWorkCtx = NULL;
}
cleanup:
PvfsFreeWorkContext(&pWorkCtx);
return ntError;
error:
goto cleanup;
}
/************************************************************
***********************************************************/
NTSTATUS
PvfsAsyncRead(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsCreateWorkContext(
&pWorkCtx,
TRUE,
(PVOID)pIrpContext,
(PPVFS_WORK_CONTEXT_CALLBACK)PvfsRead,
NULL);
BAIL_ON_NT_STATUS(ntError);
ntError = PvfsScheduleIoWorkItem(pWorkCtx);
if (ntError == STATUS_PENDING)
{
pWorkCtx = NULL;
}
cleanup:
PvfsFreeWorkContext(&pWorkCtx);
return ntError;
error:
goto cleanup;
}
/************************************************************
***********************************************************/
NTSTATUS
PvfsAsyncWrite(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsCreateWorkContext(
&pWorkCtx,
TRUE,
(PVOID)pIrpContext,
(PPVFS_WORK_CONTEXT_CALLBACK)PvfsWrite,
NULL);
BAIL_ON_NT_STATUS(ntError);
ntError = PvfsScheduleIoWorkItem(pWorkCtx);
if (ntError == STATUS_PENDING)
{
pWorkCtx = NULL;
}
cleanup:
PvfsFreeWorkContext(&pWorkCtx);
return ntError;
error:
goto cleanup;
}
/************************************************************
***********************************************************/
NTSTATUS
PvfsAsyncFlushBuffers(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsCreateWorkContext(
&pWorkCtx,
TRUE,
(PVOID)pIrpContext,
(PPVFS_WORK_CONTEXT_CALLBACK)PvfsFlushBuffers,
NULL);
BAIL_ON_NT_STATUS(ntError);
ntError = PvfsScheduleIoWorkItem(pWorkCtx);
if (ntError == STATUS_PENDING)
{
pWorkCtx = NULL;
}
cleanup:
PvfsFreeWorkContext(&pWorkCtx);
return ntError;
error:
goto cleanup;
}
/************************************************************
***********************************************************/
NTSTATUS
PvfsAsyncQueryInformationFile(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsCreateWorkContext(
&pWorkCtx,
TRUE,
(PVOID)pIrpContext,
(PPVFS_WORK_CONTEXT_CALLBACK)PvfsQueryInformationFile,
NULL);
BAIL_ON_NT_STATUS(ntError);
ntError = PvfsScheduleIoWorkItem(pWorkCtx);
if (ntError == STATUS_PENDING)
{
pWorkCtx = NULL;
}
cleanup:
PvfsFreeWorkContext(&pWorkCtx);
return ntError;
error:
goto cleanup;
}
/************************************************************
***********************************************************/
NTSTATUS
PvfsAsyncSetInformationFile(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsCreateWorkContext(
&pWorkCtx,
TRUE,
(PVOID)pIrpContext,
(PPVFS_WORK_CONTEXT_CALLBACK)PvfsSetInformationFile,
NULL);
BAIL_ON_NT_STATUS(ntError);
ntError = PvfsScheduleIoWorkItem(pWorkCtx);
if (ntError == STATUS_PENDING)
{
pWorkCtx = NULL;
}
cleanup:
PvfsFreeWorkContext(&pWorkCtx);
return ntError;
error:
goto cleanup;
}
/************************************************************
***********************************************************/
NTSTATUS
PvfsAsyncQueryDirInformation(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsCreateWorkContext(
&pWorkCtx,
TRUE,
(PVOID)pIrpContext,
(PPVFS_WORK_CONTEXT_CALLBACK)PvfsQueryDirInformation,
NULL);
BAIL_ON_NT_STATUS(ntError);
ntError = PvfsScheduleIoWorkItem(pWorkCtx);
if (ntError == STATUS_PENDING)
{
pWorkCtx = NULL;
}
cleanup:
PvfsFreeWorkContext(&pWorkCtx);
return ntError;
error:
goto cleanup;
}
/************************************************************
***********************************************************/
NTSTATUS
PvfsAsyncQueryVolumeInformation(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsCreateWorkContext(
&pWorkCtx,
TRUE,
(PVOID)pIrpContext,
(PPVFS_WORK_CONTEXT_CALLBACK)PvfsQueryVolumeInformation,
NULL);
BAIL_ON_NT_STATUS(ntError);
ntError = PvfsScheduleIoWorkItem(pWorkCtx);
if (ntError == STATUS_PENDING)
{
pWorkCtx = NULL;
}
cleanup:
PvfsFreeWorkContext(&pWorkCtx);
return ntError;
error:
goto cleanup;
}
/************************************************************
***********************************************************/
NTSTATUS
PvfsAsyncQuerySecurityFile(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsCreateWorkContext(
&pWorkCtx,
TRUE,
(PVOID)pIrpContext,
(PPVFS_WORK_CONTEXT_CALLBACK)PvfsQuerySecurityFile,
NULL);
BAIL_ON_NT_STATUS(ntError);
ntError = PvfsScheduleIoWorkItem(pWorkCtx);
if (ntError == STATUS_PENDING)
{
pWorkCtx = NULL;
}
cleanup:
PvfsFreeWorkContext(&pWorkCtx);
return ntError;
error:
goto cleanup;
}
/************************************************************
***********************************************************/
NTSTATUS
PvfsAsyncSetSecurityFile(
PPVFS_IRP_CONTEXT pIrpContext
)
{
NTSTATUS ntError = STATUS_UNSUCCESSFUL;
PPVFS_WORK_CONTEXT pWorkCtx = NULL;
ntError = PvfsCreateWorkContext(
&pWorkCtx,
TRUE,
(PVOID)pIrpContext,
(PPVFS_WORK_CONTEXT_CALLBACK)PvfsSetSecurityFile,
NULL);
BAIL_ON_NT_STATUS(ntError);
ntError = PvfsScheduleIoWorkItem(pWorkCtx);
if (ntError == STATUS_PENDING)
{
pWorkCtx = NULL;
}
cleanup:
PvfsFreeWorkContext(&pWorkCtx);
return ntError;
error:
goto cleanup;
}
/*
local variables:
mode: c
c-basic-offset: 4
indent-tabs-mode: nil
tab-width: 4
end:
*/