Home

Resume

Blog

Teikitu


/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/*  »Project«   Teikitu Gaming System (TgS) (∂)
    »File«      TgS Kernel - File Job.c
    »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
    »Version«   4.51 / »GUID« A9981407-3EC9-42AF-8B6F-8BE6DD919615                                                                                                        */
/*   -------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
/*  Copyright: © 2002-2017, Andrew Aye.  All Rights Reserved.
    This software is free for non-commercial use.  Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
      following conditions are met:
        Redistribution of source code must retain this copyright notice, this list of conditions and the following disclaimers.
        Redistribution in binary form must reproduce this copyright notice, this list of conditions and the following disclaimers in the documentation and other materials
          provided with the distribution.
    The name of the author may not be used to endorse or promote products derived from this software without specific prior written permission.
    The intellectual property rights of the algorithms used reside with Andrew Aye.
    You may not use this software, in whole or in part, in support of any commercial product without the express written consent of the author.
    There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".                                                   */
/* =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= */
/* == Kernel ============================================================================================================================================================ */

/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions                                                                                                                                                  */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

static TgBOOL                               tgKN_FS_Mount__Is_Valid( C_TgKN_FS_MOUNT_ID );
TgFORCEINLINE TgBOOL                        tgKN_FS_Open_Command_Test( CPCU_STg2_KN_File_Open_Command );
static TgBOOL                               tgKN_FS_Command_Test( C_TgKN_FILE_ID, C_ETgFILE_COMMAND );

TgFORCEINLINE P_STg2_KN_File_Job            tgKN_FS_Mount_Get_Job_Command( TgVOID );

static TgKN_FILE_ID                         tgKN_FS_JB_Open_Internal( CPCU_STg2_KN_File_Open_Command, C_TgBOOL );
static TgKN_FILE_JOB_ID                     tgKN_FS_JB_Read_Internal( CPCU_STg2_KN_File_Read_Command, C_TgBOOL );
static TgKN_FILE_JOB_ID                     tgKN_FS_JB_Cache_Internal( CPCU_STg2_KN_File_Cache_Command, C_TgBOOL );
static TgKN_FILE_JOB_ID                     tgKN_FS_JB_Write_Internal( CPCU_STg2_KN_File_Write_Command, C_TgBOOL );
static TgKN_FILE_JOB_ID                     tgKN_FS_JB_Flush_Internal( C_TgKN_FILE_ID, C_TgBOOL );
static TgKN_FILE_JOB_ID                     tgKN_FS_JB_Close_Internal( C_TgKN_FILE_ID, C_TgBOOL );

static TgVOID                               tgKN_FS_BL_Read_Callback( PCU_STg2_KN_File_Read_Command );
static TgVOID                               tgKN_FS_BL_Write_Callback( PCU_STg2_KN_File_Write_Command );

static TgVOID                               tgKN_FS_Job_Queue( PCU_STg2_KN_File_Job, C_TgBOOL );

static TgVOID                               tgKN_FS_Job_Complete_Final( PC_STg2_KN_File_System, P_STg2_KN_File_Job );
static TgVOID                               tgKN_FS_Job_Execute( PC_STg2_KN_File_System );




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Public Functions                                                                                                                                                      */
/*                                                                                                                                                                        */
/* There is a single global pool of file jobs, that each function will pop from to create a command.  Once we have validated the file, file mount, and file system the    */
/* command will be added to the file system queue.  We want to allow for multiple read | write commands to be in flight, but also maintain order of commands. This allows */
/* the user to submit (for example) a series of writes, and a flush, but be guaranteed the flush would occur after the completion of all the write commands.  (Ditto for  */
/* a cache command followed by reads.)  This is done by opportunistic concurrency.  On every command insertion, and command completion we will attempt to lock the file   */
/* system queue for processing.  On a fail, the lock increments an attempt counter (atomically with the attempt to acquire the lock). Then on a signal (lock release), if */
/* there have been any lock attempts, the lock is not released - and the attempt count is returned to the caller.  This allows us to avoid a race condition that happens  */
/* when we are processing the file system queue, and a command is added to one of the auxiliary processing queues (add queue).                                            */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- tgKN_FS_BL_Open ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_ID tgKN_FS_BL_Open( CPCU_STg2_KN_File_Open_Command psCmd )
{
    TgKN_FILE_ID                        tiFile;

    tiFile = tgKN_FS_JB_Open_Internal( psCmd, TgTRUE );
    return (tiFile);
}


/* ---- tgKN_FS_BL_Read ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgKN_FS_BL_Read( PCU_STg2_KN_File_Read_Command psCmd )
{
    TgKN_FILE_JOB_ID                    tiFile_Job;
    TgKN_FILE_READ_CALLBACK             pfnRead_Callback;
    TgUINTPTR                           uiParam;

    pfnRead_Callback = psCmd->m_pfnFinish;
    uiParam = psCmd->m_uiParam;
    psCmd->m_pfnFinish = tgKN_FS_BL_Read_Callback;
    psCmd->m_uiParam = (TgUINTPTR)psCmd;

    tiFile_Job = tgKN_FS_JB_Read_Internal( psCmd, TgTRUE );

    psCmd->m_pfnFinish = pfnRead_Callback;
    psCmd->m_uiParam = uiParam;

    if (nullptr != pfnRead_Callback)
    {
        pfnRead_Callback( psCmd );
    };

    return (TgTRUE == tgKN_FILE_JOB_ID_Is_Valid( tiFile_Job ) ? KTgS_OK : KTgE_FAIL);
}


/* ---- tgKN_FS_BL_Cache ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgKN_FS_BL_Cache( CPCU_STg2_KN_File_Cache_Command psCmd )
{
    TgKN_FILE_JOB_ID                    tiFile_Job;

    tiFile_Job = tgKN_FS_JB_Cache_Internal( psCmd, TgTRUE );
    return (TgTRUE == tgKN_FILE_JOB_ID_Is_Valid( tiFile_Job ) ? KTgS_OK : KTgE_FAIL);
}


/* ---- tgKN_FS_BL_Write ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgKN_FS_BL_Write( PCU_STg2_KN_File_Write_Command psCmd )
{
    TgKN_FILE_JOB_ID                    tiFile_Job;
    TgKN_FILE_WRITE_CALLBACK            pfnWrite_Callback;
    TgUINTPTR                           uiParam;

    pfnWrite_Callback = psCmd->m_pfnFinish;
    uiParam = psCmd->m_uiParam;
    psCmd->m_pfnFinish = tgKN_FS_BL_Write_Callback;
    psCmd->m_uiParam = (TgUINTPTR)psCmd;

    tiFile_Job = tgKN_FS_JB_Write_Internal( psCmd, TgTRUE );

    psCmd->m_pfnFinish = pfnWrite_Callback;
    psCmd->m_uiParam = uiParam;

    if (nullptr != pfnWrite_Callback)
    {
        pfnWrite_Callback( psCmd );
    };

    return (TgTRUE == tgKN_FILE_JOB_ID_Is_Valid( tiFile_Job ) ? KTgS_OK : KTgE_FAIL);
}


/* ---- tgKN_FS_BL_Flush ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgKN_FS_BL_Flush( C_TgKN_FILE_ID tiFile )
{
    TgKN_FILE_JOB_ID                    tiFile_Job;

    tiFile_Job = tgKN_FS_JB_Flush_Internal( tiFile, TgTRUE );
    return (TgTRUE == tgKN_FILE_JOB_ID_Is_Valid( tiFile_Job ) ? KTgS_OK : KTgE_FAIL);
}


/* ---- tgKN_FS_BL_Close ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgRESULT tgKN_FS_BL_Close( C_TgKN_FILE_ID tiFile )
{
    TgKN_FILE_JOB_ID                    tiFile_Job;

    tiFile_Job = tgKN_FS_JB_Close_Internal( tiFile, TgTRUE );
    return (TgTRUE == tgKN_FILE_JOB_ID_Is_Valid( tiFile_Job ) ? KTgS_OK : KTgE_FAIL);
}


/* ---- tgKN_FS_JB_Read ------------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_JOB_ID tgKN_FS_JB_Read( CPCU_STg2_KN_File_Read_Command psCmd )
{
    return (tgKN_FS_JB_Read_Internal( psCmd, TgFALSE ));
}


/* ---- tgKN_FS_JB_Cache ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_JOB_ID tgKN_FS_JB_Cache( CPCU_STg2_KN_File_Cache_Command psCmd )
{
    return (tgKN_FS_JB_Cache_Internal( psCmd, TgFALSE ));
}


/* ---- tgKN_FS_JB_Write ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_JOB_ID tgKN_FS_JB_Write( CPCU_STg2_KN_File_Write_Command psCmd )
{
    return (tgKN_FS_JB_Write_Internal( psCmd, TgFALSE ));
}


/* ---- tgKN_FS_JB_Flush ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_JOB_ID tgKN_FS_JB_Flush( C_TgKN_FILE_ID tiFile )
{
    return (tgKN_FS_JB_Flush_Internal( tiFile, TgFALSE ));
}


/* ---- tgKN_FS_JB_Close ------------------------------------------------------------------------------------------------------------------------------------------------ */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_JOB_ID tgKN_FS_JB_Close( C_TgKN_FILE_ID tiFile )
{
    return (tgKN_FS_JB_Close_Internal( tiFile, TgFALSE ));
}


/* ---- tgKN_FS_JB_Cancel ----------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgKN_FS_JB_Cancel( C_TgKN_FILE_JOB_ID tiFile_Job )
{
    P_STg2_KN_File_Info                 psFile_Info;
    P_STg2_KN_File_System               psFS;
    P_STg2_KN_File_Job                  psJob;

    if (TgTRUE != tgEQ_KN_FILE_JOB_ID( g_asKN_File_Job[tiFile_Job.m.iI].m_tiFile_Job, tiFile_Job ))
    {
        return;
    };

    if (TgTRUE != tgKN_FS_Command_Test( g_asKN_File_Job[tiFile_Job.m.iI].m_tiFile, ETgFILE_COMMAND__UNKNOWN ))
    {
        return;
    };

    psFile_Info = g_asKN_File_Info + g_asKN_File_Job[tiFile_Job.m.iI].m_tiFile.m.iI;
    psFS = g_asKN_FS + psFile_Info->m_tiFS.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FILE_SYSTEM_ID( psFile_Info->m_tiFS, psFS->m_tiFS ) );

    psJob = tgKN_FS_Mount_Get_Job_Command();

    psJob->m_sCmd.m_sCancel.m_tiFile_Job = tiFile_Job;
    psJob->m_enCmd = ETgFILE_COMMAND__CANCEL;

    tgCM_UTM_AM_ST_Push( &psFS->m_sComplete_Job.m_sStack, (P_STg2_UTM_Node)psJob );
}


/* ---- tgKN_FS_JB_Status ----------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
ETgKN_IO_STATUS tgKN_FS_JB_Status( C_TgKN_FILE_JOB_ID tiFile_Job )
{
    if (TgTRUE != tgEQ_KN_FILE_JOB_ID( g_asKN_File_Job[tiFile_Job.m.iI].m_tiFile_Job, tiFile_Job ))
    {
        return (ETgKN_IO_STATUS__INVALID);
    };

    if (TgTRUE != tgKN_FS_Command_Test( g_asKN_File_Job[tiFile_Job.m.iI].m_tiFile, ETgFILE_COMMAND__UNKNOWN ))
    {
        return (ETgKN_IO_STATUS__INVALID);
    };

    return (tgAM32_READ( &g_asKN_File_Job[tiFile_Job.m.iI].m_xiStatus ));
}




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  Private Functions                                                                                                                                                     */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- tgKN_File__Info_Init -------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_ID tgKN_File__Info_Init( CPCU_STg2_KN_File_Open_Command psCmd )
{
    union
    {
        P_STg2_UTM_Node                     psNode;
        P_STg2_KN_File_Info                 ps;
    }                                   sFile_Info;

    sFile_Info.psNode = tgCM_UTM_AM_ST_Pop( &g_sKN_File_Info__Free_Stack.m_sStack );
    if (nullptr == sFile_Info.psNode)
    {
        TgWARNING_MSGF( 0, TgT( "%-16.16s(%-32.32s): Too many files open.\n" ), TgT("Kernel"), TgT("File Open") );
        return (KTgKN_FILE_ID__INVALID);
    };

    sFile_Info.ps->m_tiFS = g_asKN_FS_Mount[psCmd->m_tiFS_Mount.m.iI].m_tiFS;
    sFile_Info.ps->m_tiFS_Mount = psCmd->m_tiFS_Mount;
    TgERROR(TgTRUE == tgEQ_KN_FS_MOUNT_ID( g_asKN_FS_Mount[psCmd->m_tiFS_Mount.m.iI].m_tiFS_Mount, psCmd->m_tiFS_Mount ));
    sFile_Info.ps->m_uiPath = psCmd->m_uiPath;
    sFile_Info.ps->m_uiFile = psCmd->m_uiFile;
    sFile_Info.ps->m_uiSize = KTgMAX_SIZE;
    sFile_Info.ps->m_uiPos = 0;
    sFile_Info.ps->m_uiCache_Pos = 0;
    sFile_Info.ps->m_uiCache_Size = 0;
    sFile_Info.ps->m_puiCache = nullptr;
    sFile_Info.ps->m_enMode = psCmd->m_enMode;
    sFile_Info.ps->m_niCmd = 0;
    sFile_Info.ps->m_niExecute = 0;

    tgInit_KN_FILE_ID( &sFile_Info.ps->m_tiFile, (TgSINT32)(sFile_Info.ps - g_asKN_File_Info) );

    return (sFile_Info.ps->m_tiFile);
}


/* ---- tgKN_File__Info_Free -------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgKN_File__Info_Free( C_TgKN_FILE_ID tiFile )
{
    TgERROR((TgTRUE == tgEQ_KN_FILE_ID( tiFile, g_asKN_File_Info[tiFile.m.iI].m_tiFile )) || (TgTRUE != tgKN_FILE_ID_Is_Valid( g_asKN_File_Info[tiFile.m.iI].m_tiFile )));

    if (nullptr != g_asKN_File_Info[tiFile.m.iI].m_puiCache)
    {
        TgFREE_POOL( g_asKN_File_Info[tiFile.m.iI].m_puiCache );
        g_asKN_File_Info[tiFile.m.iI].m_puiCache = nullptr;
    };

    g_asKN_File_Info[tiFile.m.iI].m_tiFS = KTgKN_FILE_SYSTEM_ID__INVALID;
    g_asKN_File_Info[tiFile.m.iI].m_tiFS_Mount = KTgKN_FS_MOUNT_ID__INVALID;
    g_asKN_File_Info[tiFile.m.iI].m_tiFile = KTgKN_FILE_ID__INVALID;
    tgCM_UTM_AM_ST_Push( &g_sKN_File_Info__Free_Stack.m_sStack, (P_STg2_UTM_Node)(g_asKN_File_Info + tiFile.m.iI) );
}


/* ---- tgKN_FS_Job_Complete -------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgVOID tgKN_FS_Job_Complete( PCU_STg2_KN_File_Job psJob )
{
    P_STg2_KN_File_Info                 psFile_Info;
    P_STg2_KN_File_System               psFS;

    TgPARAM_CHECK( nullptr != psJob );
    TgPARAM_CHECK_INDEX( psJob->m_tiFile.m.iI, g_asKN_File_Info );

    psFile_Info = g_asKN_File_Info + psJob->m_tiFile.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FILE_ID( psJob->m_tiFile, psFile_Info->m_tiFile ) );
    psFS = g_asKN_FS + psFile_Info->m_tiFS.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FILE_SYSTEM_ID( psFile_Info->m_tiFS, psFS->m_tiFS ) );

    /* Execute the user completion call back function */
    if (ETgFILE_COMMAND__WRITE_ASYNC == psJob->m_enCmd  && psJob->m_sCmd.m_sWrite.m_pfnFinish)
    {
        psJob->m_sCmd.m_sWrite.m_pfnFinish( &psJob->m_sCmd.m_sWrite );
    }
    else if (ETgFILE_COMMAND__READ_ASYNC == psJob->m_enCmd && psJob->m_sCmd.m_sRead.m_pfnFinish)
    {
        psJob->m_sCmd.m_sRead.m_pfnFinish( &psJob->m_sCmd.m_sRead );
    };

    if (TgSUCCEEDED(tgCM_UTM_SNC_Lock_Test( &psFS->m_sProcess_Lock.m_sLock )))
    {
        tgKN_FS_Job_Complete_Final( psFS, psJob );
        tgKN_FS_Job_Execute( psFS ); /* Execute the next set of jobs */
    }
    else
    {
        tgCM_UTM_AM_ST_Push( &psFS->m_sComplete_Job.m_sStack, (P_STg2_UTM_Node)psJob );
    };
}




/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */
/*  File Local Functions                                                                                                                                                  */
/* -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. */

/* ---- tgKN_FS_Mount__Is_Valid ----------------------------------------------------------------------------------------------------------------------------------------- */
/* Validates the FS Mount ID, and make sure that the mount access mode support the requested file access                                                                  */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgBOOL tgKN_FS_Mount__Is_Valid( C_TgKN_FS_MOUNT_ID tiFS_Mount )
{
    /* Make sure that the chosen mount id is valid */
    TgERROR_MSGF( tiFS_Mount.m.iI >= 0 && tiFS_Mount.m.iI < KTgKN_MAX_FILE_SYSTEM_MOUNT,
                  TgT( "%-16.16s(%-32.32s): Invalid Mount Point ID.\n" ), TgT("Kernel"), TgT("tgKN_FS_Mount__Is_Valid") );

    /* Make sure that the supporting file system id is valid */
    TgERROR_INDEX( tiFS_Mount.m.iI, g_asKN_FS_Mount );
    TgERROR_MSGF( g_asKN_FS_Mount[tiFS_Mount.m.iI].m_tiFS.m.iI >= 0 && g_asKN_FS_Mount[tiFS_Mount.m.iI].m_tiFS.m.iI < KTgKN_MAX_FILE_SYSTEM,
                  TgT( "%-16.16s(%-32.32s): Invalid File System ID.\n" ), TgT("Kernel"), TgT("tgKN_FS_Mount__Is_Valid") );

    /* Make sure that the supporting file system is valid */
    TgERROR_INDEX( g_asKN_FS_Mount[tiFS_Mount.m.iI].m_tiFS.m.iI, g_asKN_FS );
    TgERROR_MSGF( TgTRUE == tgEQ_KN_FILE_SYSTEM_ID( g_asKN_FS_Mount[tiFS_Mount.m.iI].m_tiFS, g_asKN_FS[g_asKN_FS_Mount[tiFS_Mount.m.iI].m_tiFS.m.iI].m_tiFS ),
                  TgT( "%-16.16s(%-32.32s): Invalid File System in Command.\n" ), TgT("Kernel"), TgT("tgKN_FS_Mount__Is_Valid") );

    /* Make sure that the chosen mount point is valid */
    if (TgTRUE != tgEQ_KN_FS_MOUNT_ID( g_asKN_FS_Mount[tiFS_Mount.m.iI].m_tiFS_Mount, tiFS_Mount ))
    {
        TgERROR_MSGF( 0, TgT( "%-16.16s(%-32.32s): Invalid File System Mount in Command.\n" ), TgT("Kernel"), TgT("tgKN_FS_Mount__Is_Valid") );
        return (TgFALSE);
    };

    return (TgTRUE);
}


/* ---- tgKN_FS_Open_Command_Test --------------------------------------------------------------------------------------------------------------------------------------- */
/* Validates the FS Mount ID, and make sure that the mount access mode support the requested file access                                                                  */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgFORCEINLINE TgBOOL tgKN_FS_Open_Command_Test( CPCU_STg2_KN_File_Open_Command psCmd )
{
    /* Make sure that the chosen mount point is valid */
    if (TgTRUE != tgKN_FS_Mount__Is_Valid( g_asKN_FS_Mount[psCmd->m_tiFS_Mount.m.iI].m_tiFS_Mount ))
    {
        return (TgFALSE);
    };

    /* Validate the request against the permission flags on the file system */
    if ((psCmd->m_enMode & ETgFILE_IO_ACCESS__ACCESS_MASK) != (psCmd->m_enMode & g_asKN_FS_Mount[psCmd->m_tiFS_Mount.m.iI].m_enMode))
    {
        TgERROR_MSGF( 0, TgT( "%-16.16s(%-32.32s): Invalid File Access Mode request for Mount Point.\n" ), TgT("Kernel"), TgT("tgKN_FS_Open_Command_Test") );
        return (TgFALSE);
    };

    if (ETgFILE_IO_ACCESS__CREATE == (psCmd->m_enMode & ETgFILE_IO_ACCESS__CREATE))
    {
        if (nullptr == psCmd->m_pszFile_Name)
        {
            TgERROR_MSGF( 0, TgT( "%-16.16s(%-32.32s): No file name provided for open command with create.\n" ), TgT( "Kernel" ), TgT( "tgKN_FS_Open_Command_Test" ) );
            return (TgFALSE);
        };
    }
    else
    {
        if (nullptr != psCmd->m_pszFile_Name)
        {
            TgERROR_MSGF( 0, TgT( "%-16.16s(%-32.32s): File name provided for open command without create.\n" ), TgT( "Kernel" ), TgT( "tgKN_FS_Open_Command_Test" ) );
            return (TgFALSE);
        };

        if (KTgEMPTY_HASH == psCmd->m_uiFile)
        {
            TgERROR_MSGF( 0, TgT( "%-16.16s(%-32.32s): No hash provided for open command.\n" ), TgT( "Kernel" ), TgT( "tgKN_FS_Open_Command_Test" ) );
            return (TgFALSE);
        };
    };

    return (TgTRUE);
}


/* ---- tgKN_FS_Command_Test -------------------------------------------------------------------------------------------------------------------------------------------- */
/* Note: this is not thread safe, in that the file could be closed during execution of this function (or other commands) - caveat emptor                                  */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgBOOL tgKN_FS_Command_Test( C_TgKN_FILE_ID tiFile, C_ETgFILE_COMMAND enFile_Operation )
{
    /* Make sure that the chosen mount id is KTgKN_MAX_FILE_OPEN */
    TgERROR_MSGF( (tiFile.m.iI >= 0) && (tiFile.m.iI < KTgKN_MAX_FILE_OPEN),
                  TgT( "%-16.16s(%-32.32s): Invalid File ID.\n" ), TgT("Kernel"), TgT("tgKN_FS_Command_Test") );

    /* Make sure that the chosen mount point is valid */
    TgERROR_INDEX( tiFile.m.iI, g_asKN_File_Info );
    if (TgTRUE != tgEQ_KN_FILE_ID( g_asKN_File_Info[tiFile.m.iI].m_tiFile, tiFile ))
    {
        TgERROR_MSGF( 0, TgT( "%-16.16s(%-32.32s): Invalid File in Command.\n" ), TgT("Kernel"), TgT("tgKN_FS_Command_Test") );
        return (TgFALSE);
    };

    /* Make sure that the chosen mount point is valid */
    if (TgTRUE != tgKN_FS_Mount__Is_Valid( g_asKN_File_Info[tiFile.m.iI].m_tiFS_Mount ))
    {
        return (TgFALSE);
    };

    /* See if the file has a job request to be closed */
    if ((ETgFILE_COMMAND__CLOSE != enFile_Operation) && (ETgFILE_IO_ACCESS__CLOSING == (ETgFILE_IO_ACCESS__CLOSING & g_asKN_File_Info[tiFile.m.iI].m_enMode)))
    {
        return (TgFALSE);
    };

    switch (enFile_Operation)
    {
        case ETgFILE_COMMAND__READ_ASYNC:
            if (ETgFILE_IO_ACCESS__READ != (ETgFILE_IO_ACCESS__READ & g_asKN_File_Info[tiFile.m.iI].m_enMode))
            {
                TgERROR_MSGF( 0, TgT( "%-16.16s(%-32.32s): Invalid Request to Non-Read File.\n" ), TgT("Kernel"), TgT("tgKN_FS_Command_Test") );
                return (TgFALSE);
            };
            break;

        case ETgFILE_COMMAND__FLUSH:
        case ETgFILE_COMMAND__WRITE_ASYNC:
            if (ETgFILE_IO_ACCESS__WRITE != (ETgFILE_IO_ACCESS__WRITE & g_asKN_File_Info[tiFile.m.iI].m_enMode))
            {
                TgERROR_MSGF( 0, TgT( "%-16.16s(%-32.32s): Invalid Request to Non-Write File.\n" ), TgT("Kernel"), TgT("tgKN_FS_Command_Test") );
                return (TgFALSE);
            };
            break;

        case ETgFILE_COMMAND__UNKNOWN:
        case ETgFILE_COMMAND__OPEN:
        case ETgFILE_COMMAND__CACHE:
        case ETgFILE_COMMAND__CLOSE:
            break;

        case ETgFILE_COMMAND__CANCEL:
        default:
            TgS_NO_DEFAULT(break);
    };

    return (TgTRUE);
}


/* ---- tgKN_FS_Mount_Get_Job_Command ----------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgFORCEINLINE P_STg2_KN_File_Job tgKN_FS_Mount_Get_Job_Command( TgVOID )
{
    union
    {
        P_STg2_UTM_Node                     psNode;
        P_STg2_KN_File_Job                  ps;
    }                                   sJob;

    sJob.psNode = tgCM_UTM_AM_ST_Pop( &g_sKN_File_Job__Free_Stack.m_sStack );
    if (nullptr == sJob.psNode)
    {
        TgWARNING_MSGF( 0, TgT( "%-16.16s(%-32.32s): Too many file requests.\n" ), TgT("Kernel"), TgT("tgKN_FS_Mount_Get_Job_Command") );
        sJob.psNode = tgCM_UTM_AM_ST_Pop_Wait_Yield( &g_sKN_File_Job__Free_Stack.m_sStack );
    };

    tgInit_KN_FILE_JOB_ID( &sJob.ps->m_tiFile_Job, (TgSINT32)(sJob.ps - g_asKN_File_Job) );
    sJob.ps->m_sFS_Node.m_pNext_Node = nullptr;
    sJob.ps->m_enCmd = ETgFILE_COMMAND__UNKNOWN;
    sJob.ps->m_tiFile = KTgKN_FILE_ID__INVALID;
    sJob.ps->m_psmBL = nullptr;
    sJob.ps->m_xiStatus = ETgKN_IO_STATUS__INVALID;

    return (sJob.ps);
}


/* ---- tgKN_FS_JB_Open_Internal ---------------------------------------------------------------------------------------------------------------------------------------- */
/* NOTE: There is no Job version of this command - because I do not like the idea of allowing the user to queue a bunch of commands on a file that fails to open.  This   */
/* function exists for consistency - but is only ever called in as a blocking call (note the error check on it).                                                          */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_ID tgKN_FS_JB_Open_Internal( CPCU_STg2_KN_File_Open_Command psCmd, C_TgBOOL bBlocking )
{
    P_STg2_KN_File_Job                  psJob;
    TgKN_FILE_ID                        tiFile;

    TgPARAM_CHECK( nullptr != psCmd );
    TgPARAM_CHECK( TgTRUE == bBlocking );

    /* Validate the file parameters from the command */
    if (TgTRUE != tgKN_FS_Open_Command_Test( psCmd ))
    {
        return (KTgKN_FILE_ID__INVALID);
    };

    /* Attempt to acquire a kernel file data structure for the request */
    tiFile = tgKN_File__Info_Init( psCmd );

    if (TgTRUE != tgKN_FILE_ID_Is_Valid( tiFile ))
    {
        return (KTgKN_FILE_ID__INVALID);
    };

    psJob = tgKN_FS_Mount_Get_Job_Command();

    psJob->m_sCmd.m_sOpen = *psCmd;
    psJob->m_enCmd = ETgFILE_COMMAND__OPEN;
    psJob->m_tiFile = tiFile;

    tgKN_FS_Job_Queue( psJob, bBlocking );

    if (TgTRUE != tgEQ_KN_FILE_ID( g_asKN_File_Info[tiFile.m.iI].m_tiFile, tiFile ))
    {
        tgKN_File__Info_Free( tiFile );
        tiFile = KTgKN_FILE_ID__INVALID;
    };

    return (tiFile);
}


/* ---- tgKN_FS_JB_Read_Internal ---------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_JOB_ID tgKN_FS_JB_Read_Internal( CPCU_STg2_KN_File_Read_Command psCmd, C_TgBOOL bBlocking )
{
    P_STg2_KN_File_Job                  psJob;
    TgKN_FILE_JOB_ID                    tiFile_Job;

    TgPARAM_CHECK( nullptr != psCmd );

    if (TgTRUE != tgKN_FS_Command_Test( psCmd->m_tiFile, ETgFILE_COMMAND__READ_ASYNC ))
    {
        return (KTgKN_FILE_JOB_ID__INVALID);
    };

    psJob = tgKN_FS_Mount_Get_Job_Command();

    psJob->m_sCmd.m_sRead = *psCmd;
    psJob->m_tiFile = psCmd->m_tiFile;
    psJob->m_enCmd = ETgFILE_COMMAND__READ_ASYNC;

    tiFile_Job = psJob->m_tiFile_Job;
    tgKN_FS_Job_Queue( psJob, bBlocking );

    return (tiFile_Job);
}


/* ---- tgKN_FS_JB_Cache_Internal --------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_JOB_ID tgKN_FS_JB_Cache_Internal( CPCU_STg2_KN_File_Cache_Command psCmd, C_TgBOOL bBlocking )
{
    P_STg2_KN_File_Job                  psJob;
    TgKN_FILE_JOB_ID                    tiFile_Job;

    TgPARAM_CHECK( nullptr != psCmd );

    if (TgTRUE != tgKN_FS_Command_Test( psCmd->m_tiFile, ETgFILE_COMMAND__CACHE ))
    {
        return (KTgKN_FILE_JOB_ID__INVALID);
    };

    psJob = tgKN_FS_Mount_Get_Job_Command();

    psJob->m_sCmd.m_sCache = *psCmd;
    psJob->m_tiFile = psCmd->m_tiFile;
    psJob->m_enCmd = ETgFILE_COMMAND__CACHE;

    tiFile_Job = psJob->m_tiFile_Job;
    tgKN_FS_Job_Queue( psJob, bBlocking );

    return (tiFile_Job);
}


/* ---- tgKN_FS_JB_Write_Internal --------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_JOB_ID tgKN_FS_JB_Write_Internal( CPCU_STg2_KN_File_Write_Command psCmd, C_TgBOOL bBlocking )
{
    P_STg2_KN_File_Job                  psJob;
    TgKN_FILE_JOB_ID                    tiFile_Job;

    TgPARAM_CHECK( nullptr != psCmd );

    if (TgTRUE != tgKN_FS_Command_Test( psCmd->m_tiFile, ETgFILE_COMMAND__WRITE_ASYNC ))
    {
        return (KTgKN_FILE_JOB_ID__INVALID);
    };

    psJob = tgKN_FS_Mount_Get_Job_Command();

    psJob->m_sCmd.m_sWrite = *psCmd;
    psJob->m_tiFile = psCmd->m_tiFile;
    psJob->m_enCmd = ETgFILE_COMMAND__WRITE_ASYNC;

    tiFile_Job = psJob->m_tiFile_Job;
    tgKN_FS_Job_Queue( psJob, bBlocking );

    return (tiFile_Job);
}


/* ---- tgKN_FS_JB_Flush_Internal --------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_JOB_ID tgKN_FS_JB_Flush_Internal( C_TgKN_FILE_ID tiFile, C_TgBOOL bBlocking )
{
    P_STg2_KN_File_Job                  psJob;
    TgKN_FILE_JOB_ID                    tiFile_Job;

    TgPARAM_CHECK( TgTRUE == tgKN_FILE_ID_Is_Valid( tiFile ) );

    if (TgTRUE != tgKN_FS_Command_Test( tiFile, ETgFILE_COMMAND__FLUSH ))
    {
        return (KTgKN_FILE_JOB_ID__INVALID);
    };

    psJob = tgKN_FS_Mount_Get_Job_Command();

    psJob->m_enCmd = ETgFILE_COMMAND__FLUSH;
    psJob->m_tiFile = tiFile;

    tiFile_Job = psJob->m_tiFile_Job;
    tgKN_FS_Job_Queue( psJob, bBlocking );

    return (tiFile_Job);
}


/* ---- tgKN_FS_JB_Close_Internal --------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
TgKN_FILE_JOB_ID tgKN_FS_JB_Close_Internal( C_TgKN_FILE_ID tiFile, C_TgBOOL bBlocking )
{
    P_STg2_KN_File_Job                  psJob;
    TgKN_FILE_JOB_ID                    tiFile_Job;

    TgPARAM_CHECK( TgTRUE == tgKN_FILE_ID_Is_Valid( tiFile ) );

    if (TgTRUE != tgKN_FS_Command_Test( tiFile, ETgFILE_COMMAND__CLOSE ))
    {
        return (KTgKN_FILE_JOB_ID__INVALID);
    };

    psJob = tgKN_FS_Mount_Get_Job_Command();

    psJob->m_enCmd = ETgFILE_COMMAND__CLOSE;
    psJob->m_tiFile = tiFile;

    tiFile_Job = psJob->m_tiFile_Job;
    tgKN_FS_Job_Queue( psJob, bBlocking );

    return (tiFile_Job);
}


/* ---- tgKN_FS_BL_Read_Callback ---------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgKN_FS_BL_Read_Callback( PCU_STg2_KN_File_Read_Command psCmd )
{
    P_STg2_KN_File_Read_Command         psBL_Cmd;

    psBL_Cmd = (P_STg2_KN_File_Read_Command)psCmd->m_uiParam;
    psBL_Cmd->m_nuiBuffer = psCmd->m_nuiBuffer;
    psBL_Cmd->m_nuiResult = psCmd->m_nuiResult;
    psBL_Cmd->m_pBuffer = psCmd->m_pBuffer;
}


/* ---- tgKN_FS_BL_Write_Callback --------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgKN_FS_BL_Write_Callback( PCU_STg2_KN_File_Write_Command psCmd )
{
    P_STg2_KN_File_Write_Command        psBL_Cmd;

    psBL_Cmd = (P_STg2_KN_File_Write_Command)psCmd->m_uiParam;
    psBL_Cmd->m_nuiResult = psCmd->m_nuiResult;
}


/* ---- tgKN_FS_Job_Queue ----------------------------------------------------------------------------------------------------------------------------------------------- */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgKN_FS_Job_Queue( PCU_STg2_KN_File_Job psJob, C_TgBOOL bBlocking )
{
    P_STg2_KN_File_Info                 psFile_Info;
    P_STg2_KN_File_System               psFS;
    STg1_MP_SM                          smWait;

    TgPARAM_CHECK( nullptr != psJob );
    TgPARAM_CHECK_INDEX( psJob->m_tiFile.m.iI, g_asKN_File_Info );

    psFile_Info = g_asKN_File_Info + psJob->m_tiFile.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FILE_ID( psJob->m_tiFile, psFile_Info->m_tiFile ) );
    psFS = g_asKN_FS + psFile_Info->m_tiFS.m.iI;
    TgERROR( TgTRUE == tgEQ_KN_FILE_SYSTEM_ID( psFile_Info->m_tiFS, psFS->m_tiFS ) );

    if (TgFALSE != bBlocking)
    {
        tgCM_MP_SM_Init( &smWait, 1 );
        psJob->m_psmBL = &smWait;
    };

    tgCM_UTM_SN_Lock_Spin( &psFS->m_sAdd_Lock.m_sLock );
    tgAM32_XCHG( &psJob->m_xiStatus, ETgKN_IO_STATUS__QUEUED );
    tgCM_UTS_QU_Enqueue( &psFS->m_sAdd_Queue, &psJob->m_sFS_Node );
    ++psFile_Info->m_niCmd;
    tgAM_WRITE_FENCE();
    tgCM_UTM_SN_Signal( &psFS->m_sAdd_Lock.m_sLock );

    if (TgSUCCEEDED(tgCM_UTM_SNC_Lock_Test( &psFS->m_sProcess_Lock.m_sLock )))
    {
        tgKN_FS_Job_Execute( psFS );
    };

    if (TgFALSE != bBlocking)
    {
        tgCM_MP_SM_Wait_Block( &smWait );
        tgCM_MP_SM_Free( &smWait );
    };
}


/* ---- tgKN_FS_Job_Complete_Final -------------------------------------------------------------------------------------------------------------------------------------- */
/* ASSUME: File System Process Lock has been Acquired                                                                                                                     */
/* FUNC: Used to cancel jobs that are queued, decrement the execution count on the file, and file system, and restore the overlapped state for the file                   */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgKN_FS_Job_Complete_Final( PC_STg2_KN_File_System psFS, P_STg2_KN_File_Job psJob )
{
    P_STg2_KN_File_Info                 psFile_Info;

    if (ETgFILE_COMMAND__CANCEL == psJob->m_enCmd)
    {
        do
        {
            TgKN_FILE_JOB_ID                    tiFile_Job;

            tiFile_Job = psJob->m_sCmd.m_sCancel.m_tiFile_Job;

            /* Cancel job request refers to an invalid job - may have completed */
            if (TgTRUE != tgEQ_KN_FILE_JOB_ID( g_asKN_File_Job[tiFile_Job.m.iI].m_tiFile_Job, tiFile_Job ))
            {
                break;
            };

            /* Only Cancel jobs that are in the queued state */
            if (ETgKN_IO_STATUS__QUEUED != tgAM32_XCMP( &g_asKN_File_Job[tiFile_Job.m.iI].m_xiStatus, ETgKN_IO_STATUS__CANCEL, ETgKN_IO_STATUS__QUEUED ))
            {
                break;
            };

            if (g_asKN_File_Job[tiFile_Job.m.iI].m_sCmd.m_sCancel.m_pfnFinish)
            {
                g_asKN_File_Job[tiFile_Job.m.iI].m_sCmd.m_sCancel.m_pfnFinish( &g_asKN_File_Job[tiFile_Job.m.iI].m_sCmd.m_sCancel );
            };

        } while (0);

        tgCM_UTM_AM_ST_Push( &g_sKN_File_Job__Free_Stack.m_sStack, (P_STg2_UTM_Node)psJob );
        return;
    };

    psFile_Info = g_asKN_File_Info + psJob->m_tiFile.m.iI;
    TgERROR( psFS == g_asKN_FS + psFile_Info->m_tiFS.m.iI );

    /* Decrement the execution counters */
    switch (psJob->m_enCmd)
    {
        case ETgFILE_COMMAND__CACHE:
            --psFile_Info->m_niExecute;
            --psFS->m_niExecute;
        case ETgFILE_COMMAND__OPEN:
        case ETgFILE_COMMAND__FLUSH:
            psFile_Info->m_enMode |= ETgFILE_IO_ACCESS__OVERLAPPED;
            break;

        case ETgFILE_COMMAND__WRITE_ASYNC:
        case ETgFILE_COMMAND__READ_ASYNC:
            --psFile_Info->m_niExecute;
            --psFS->m_niExecute;
            break;

        case ETgFILE_COMMAND__CLOSE:
            break;

        case ETgFILE_COMMAND__CANCEL:
        case ETgFILE_COMMAND__UNKNOWN:
        default:
            TgS_NO_DEFAULT( break );
    };

    TgERROR( psFile_Info->m_niExecute >= 0 );
    TgERROR( psFS->m_niExecute >= 0 );

    if (ETgFILE_COMMAND__CLOSE == psJob->m_enCmd)
    {
        tgKN_File__Info_Free( psJob->m_tiFile );
        psJob->m_tiFile = KTgKN_FILE_ID__INVALID;
    };

    if (nullptr != psJob->m_psmBL)
    {
        tgCM_MP_SM_Signal( psJob->m_psmBL, 1 );
        psJob->m_psmBL = nullptr;
    };

    tgCM_UTM_AM_ST_Push( &g_sKN_File_Job__Free_Stack.m_sStack, (P_STg2_UTM_Node)psJob);
}


/* ---- tgKN_FS_Job_Execute --------------------------------------------------------------------------------------------------------------------------------------------- */
/* ASSUME: File System Process Lock has been Acquired                                                                                                                     */
/* ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- */
static TgVOID tgKN_FS_Job_Execute( PC_STg2_KN_File_System psFS )
{
    do
    {
        union
        {
            P_STg2_UTM_Node                     psNode;
            P_STg2_UTS_QU_Node                  psQU_Node;
            P_STg2_KN_File_Job                  ps;
        }                                   sJob;
        STg2_UTS_QU                         sQueue;

        while (1)
        {
            sJob.psNode = tgCM_UTM_AM_ST_Pop( &psFS->m_sComplete_Job.m_sStack );
            if (nullptr == sJob.psNode)
            {
                break;
            };
            tgKN_FS_Job_Complete_Final( psFS, sJob.ps );
        };

        /* Add the Add Queue to the process Queue */
        tgCM_UTM_SN_Lock_Spin( &psFS->m_sAdd_Lock.m_sLock );
        tgCM_UTS_QU_Merge( &psFS->m_sProcess_Queue, &psFS->m_sAdd_Queue );
        tgCM_UTM_SN_Signal( &psFS->m_sAdd_Lock.m_sLock );

        /* Process all available jobs */
        tgCM_UTS_QU_Init( &sQueue );
        do
        {
            P_STg2_KN_File_Info                 psFile_Info;

            sJob.psQU_Node = tgCM_UTS_QU_Dequeue( &psFS->m_sProcess_Queue );
            if (nullptr == sJob.psNode)
            {
                break;
            };

            psFile_Info = g_asKN_File_Info + sJob.ps->m_tiFile.m.iI;

            if (TgTRUE != tgEQ_KN_FS_MOUNT_ID( g_asKN_FS_Mount[psFile_Info->m_tiFS_Mount.m.iI].m_tiFS_Mount, psFile_Info->m_tiFS_Mount ))
            {
                tgAM32_XCHG( &sJob.ps->m_xiStatus, ETgKN_IO_STATUS__INVALID );
                tgKN_FS_Job_Complete_Final( psFS, sJob.ps );
                continue;
            };

            switch (sJob.ps->m_enCmd)
            {
                case ETgFILE_COMMAND__CLOSE:
                case ETgFILE_COMMAND__OPEN:
                case ETgFILE_COMMAND__FLUSH:
                    psFile_Info->m_enMode &= ~ETgFILE_IO_ACCESS__OVERLAPPED;
                    if (0 == psFile_Info->m_niExecute)
                    {
                        ETgKN_IO_STATUS                     enKN_IO_Status;

                        TgERROR( psFile_Info->m_niCmd >= 1 );
                        --psFile_Info->m_niCmd;
                        enKN_IO_Status = tgAM32_XCMP( &sJob.ps->m_xiStatus, ETgKN_IO_STATUS__EXECUTE, ETgKN_IO_STATUS__QUEUED );
                        if (ETgKN_IO_STATUS__QUEUED == enKN_IO_Status)
                        {
                            psFS->m_pfnExecute_Job( sJob.ps );
                        }
                        else
                        {
                            TgERROR( ETgKN_IO_STATUS__CANCEL == enKN_IO_Status );
                            tgKN_FS_Job_Complete_Final( psFS, sJob.ps );
                        };
                    }
                    else
                    {
                        tgCM_UTS_QU_Enqueue( &sQueue, sJob.psQU_Node );
                    };
                    break;

                case ETgFILE_COMMAND__WRITE_ASYNC:
                case ETgFILE_COMMAND__CACHE:
                case ETgFILE_COMMAND__READ_ASYNC:
                    if (psFS->m_niExecute >= psFS->m_niMax_Execute)
                    {
                        tgCM_UTS_QU_Enqueue( &sQueue, sJob.psQU_Node );
                        sJob.psNode = nullptr; /* Not entirely correct, we could continue processing to fill IO queues on other file systems but ... */
                        break;
                    };

                    if (ETgFILE_IO_ACCESS__OVERLAPPED == (psFile_Info->m_enMode & ETgFILE_IO_ACCESS__OVERLAPPED))
                    {
                        ETgKN_IO_STATUS                     enKN_IO_Status;

                        --psFile_Info->m_niCmd;
                        enKN_IO_Status = tgAM32_XCMP( &sJob.ps->m_xiStatus, ETgKN_IO_STATUS__EXECUTE, ETgKN_IO_STATUS__QUEUED );
                        if (ETgKN_IO_STATUS__QUEUED == enKN_IO_Status)
                        {
                            if (ETgFILE_COMMAND__CACHE == sJob.ps->m_enCmd)
                            {
                                /* #IMPLEMENT */
                                psFile_Info->m_enMode &= ~ETgFILE_IO_ACCESS__OVERLAPPED;
                            };
                            ++psFile_Info->m_niExecute;
                            ++psFS->m_niExecute;
                            psFS->m_pfnExecute_Job( sJob.ps );
                        }
                        else
                        {
                            TgERROR( ETgKN_IO_STATUS__CANCEL == enKN_IO_Status );
                            tgKN_FS_Job_Complete_Final( psFS, sJob.ps );
                        };
                    }
                    else
                    {
                        tgCM_UTS_QU_Enqueue( &sQueue, sJob.psQU_Node );
                    };
                    break;

                case ETgFILE_COMMAND__CANCEL:
                case ETgFILE_COMMAND__UNKNOWN:
                default:
                    TgS_NO_DEFAULT( break );
            };
        }
        while (nullptr != sJob.psNode);

        tgCM_UTS_QU_Merge( &sQueue, &psFS->m_sProcess_Queue );
        tgCM_UTS_QU_Init( &psFS->m_sProcess_Queue );
        tgCM_UTS_QU_Merge( &psFS->m_sProcess_Queue, &sQueue );
    }
    while (0 != tgCM_UTM_SNC_Signal( &psFS->m_sProcess_Lock.m_sLock ));
}