first stab at time-based data coherency

This commit is contained in:
Olga Kornievskaia 2012-02-08 18:24:19 -05:00
parent 13c3723191
commit 43424fc653

View file

@ -66,7 +66,7 @@ PRDBSS_DEVICE_OBJECT nfs41_dev;
#define NFS41_MM_POOLTAG ('nfs4') #define NFS41_MM_POOLTAG ('nfs4')
KEVENT upcallEvent; KEVENT upcallEvent;
FAST_MUTEX upcallLock, downcallLock; FAST_MUTEX upcallLock, downcallLock, srvopenLock;
FAST_MUTEX xidLock; FAST_MUTEX xidLock;
FAST_MUTEX openOwnerLock; FAST_MUTEX openOwnerLock;
@ -317,7 +317,6 @@ typedef struct _NFS41_MOUNT_CONFIG {
BOOLEAN ReadOnly; BOOLEAN ReadOnly;
BOOLEAN write_thru; BOOLEAN write_thru;
BOOLEAN nocache; BOOLEAN nocache;
BOOLEAN nocoherence;
WCHAR srv_buffer[SERVER_NAME_BUFFER_SIZE]; WCHAR srv_buffer[SERVER_NAME_BUFFER_SIZE];
UNICODE_STRING SrvName; UNICODE_STRING SrvName;
WCHAR mntpt_buffer[MAX_PATH]; WCHAR mntpt_buffer[MAX_PATH];
@ -358,7 +357,6 @@ typedef struct _NFS41_V_NET_ROOT_EXTENSION {
BOOLEAN read_only; BOOLEAN read_only;
BOOLEAN write_thru; BOOLEAN write_thru;
BOOLEAN nocache; BOOLEAN nocache;
BOOLEAN nocoherence;
#define STORE_MOUNT_SEC_CONTEXT #define STORE_MOUNT_SEC_CONTEXT
#ifdef STORE_MOUNT_SEC_CONTEXT #ifdef STORE_MOUNT_SEC_CONTEXT
SECURITY_CLIENT_CONTEXT mount_sec_ctx; SECURITY_CLIENT_CONTEXT mount_sec_ctx;
@ -390,6 +388,7 @@ typedef struct _NFS41_FOBX {
PVOID acl; PVOID acl;
DWORD acl_len; DWORD acl_len;
LARGE_INTEGER time; LARGE_INTEGER time;
DWORD deleg_type;
} NFS41_FOBX, *PNFS41_FOBX; } NFS41_FOBX, *PNFS41_FOBX;
#define NFS41GetFobxExtension(pFobx) \ #define NFS41GetFobxExtension(pFobx) \
(((pFobx) == NULL) ? NULL : (PNFS41_FOBX)((pFobx)->Context)) (((pFobx) == NULL) ? NULL : (PNFS41_FOBX)((pFobx)->Context))
@ -409,12 +408,26 @@ typedef struct _NFS41_DEVICE_EXTENSION {
DWORD nfs41d_version; DWORD nfs41d_version;
BYTE VolAttrs[VOL_ATTR_LEN]; BYTE VolAttrs[VOL_ATTR_LEN];
DWORD VolAttrsLen; DWORD VolAttrsLen;
HANDLE openlistHandle;
} NFS41_DEVICE_EXTENSION, *PNFS41_DEVICE_EXTENSION; } NFS41_DEVICE_EXTENSION, *PNFS41_DEVICE_EXTENSION;
#define NFS41GetDeviceExtension(RxContext,pExt) \ #define NFS41GetDeviceExtension(RxContext,pExt) \
PNFS41_DEVICE_EXTENSION pExt = (PNFS41_DEVICE_EXTENSION) \ PNFS41_DEVICE_EXTENSION pExt = (PNFS41_DEVICE_EXTENSION) \
((PBYTE)(RxContext->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT)) ((PBYTE)(RxContext->RxDeviceObject) + sizeof(RDBSS_DEVICE_OBJECT))
typedef struct _nfs41_srvopen_list_entry {
LIST_ENTRY next;
PMRX_SRV_OPEN srv_open;
PNFS41_FOBX nfs41_fobx;
ULONGLONG ChangeTime;
BOOLEAN skip;
} nfs41_srvopen_list_entry;
typedef struct _nfs41_srvopen_list {
LIST_ENTRY head;
} nfs41_srvopen_list;
nfs41_srvopen_list *openlist = NULL;
typedef enum _NULMRX_STORAGE_TYPE_CODES { typedef enum _NULMRX_STORAGE_TYPE_CODES {
NTC_NFS41_DEVICE_EXTENSION = (NODE_TYPE_CODE)0xFC00, NTC_NFS41_DEVICE_EXTENSION = (NODE_TYPE_CODE)0xFC00,
} NFS41_STORAGE_TYPE_CODES; } NFS41_STORAGE_TYPE_CODES;
@ -1670,6 +1683,7 @@ void unmarshal_nfs41_getattr(
unmarshal_nfs41_attrget(cur, cur->u.QueryFile.buf, unmarshal_nfs41_attrget(cur, cur->u.QueryFile.buf,
&cur->u.QueryFile.buf_len, buf); &cur->u.QueryFile.buf_len, buf);
RtlCopyMemory(&cur->u.QueryFile.ChangeTime, *buf, sizeof(LONGLONG)); RtlCopyMemory(&cur->u.QueryFile.ChangeTime, *buf, sizeof(LONGLONG));
if (cur->u.QueryFile.InfoClass == FileBasicInformation)
DbgP("[getattr] ChangeTime %llu\n", cur->u.QueryFile.ChangeTime); DbgP("[getattr] ChangeTime %llu\n", cur->u.QueryFile.ChangeTime);
} }
@ -2530,7 +2544,6 @@ void nfs41_MountConfig_InitDefaults(
Config->ReadOnly = FALSE; Config->ReadOnly = FALSE;
Config->write_thru = FALSE; Config->write_thru = FALSE;
Config->nocache = FALSE; Config->nocache = FALSE;
Config->nocoherence = FALSE;
Config->SrvName.Length = 0; Config->SrvName.Length = 0;
Config->SrvName.MaximumLength = SERVER_NAME_BUFFER_SIZE; Config->SrvName.MaximumLength = SERVER_NAME_BUFFER_SIZE;
Config->SrvName.Buffer = Config->srv_buffer; Config->SrvName.Buffer = Config->srv_buffer;
@ -2624,10 +2637,6 @@ NTSTATUS nfs41_MountConfig_ParseOptions(
status = nfs41_MountConfig_ParseBoolean(Option, &usValue, status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
&Config->nocache); &Config->nocache);
} }
else if (wcsncmp(L"nocoherence", Name, NameLen) == 0) {
status = nfs41_MountConfig_ParseBoolean(Option, &usValue,
&Config->nocoherence);
}
else if (wcsncmp(L"rsize", Name, NameLen) == 0) { else if (wcsncmp(L"rsize", Name, NameLen) == 0) {
status = nfs41_MountConfig_ParseDword(Option, &usValue, status = nfs41_MountConfig_ParseDword(Option, &usValue,
&Config->ReadSize, MOUNT_CONFIG_RW_SIZE_MIN, &Config->ReadSize, MOUNT_CONFIG_RW_SIZE_MIN,
@ -2830,7 +2839,6 @@ NTSTATUS nfs41_CreateVNetRoot(
pVNetRootContext->read_only = Config.ReadOnly; pVNetRootContext->read_only = Config.ReadOnly;
pVNetRootContext->write_thru = Config.write_thru; pVNetRootContext->write_thru = Config.write_thru;
pVNetRootContext->nocache = Config.nocache; pVNetRootContext->nocache = Config.nocache;
pVNetRootContext->nocoherence = Config.nocoherence;
} else { } else {
/* use the SRV_CALL name (without leading \) as the hostname */ /* use the SRV_CALL name (without leading \) as the hostname */
Config.SrvName.Buffer = pSrvCall->pSrvCallName->Buffer + 1; Config.SrvName.Buffer = pSrvCall->pSrvCallName->Buffer + 1;
@ -3182,19 +3190,6 @@ BOOLEAN isDataAccess(
return FALSE; return FALSE;
} }
BOOLEAN has_file_changed(
IN ULONGLONG new_changeattr,
IN PFILE_BASIC_INFORMATION new_binfo,
IN PNFS41_FCB nfs41_fcb)
{
if (new_changeattr != nfs41_fcb->changeattr && nfs41_fcb->changeattr)
return TRUE;
if (new_binfo->ChangeTime.QuadPart !=
nfs41_fcb->BasicInfo.ChangeTime.QuadPart)
return TRUE;
return FALSE;
}
NTSTATUS map_open_errors( NTSTATUS map_open_errors(
DWORD status, DWORD status,
USHORT len) USHORT len)
@ -3425,10 +3420,9 @@ NTSTATUS nfs41_Create(
#endif #endif
// we get attributes only for data access and file (not directories) // we get attributes only for data access and file (not directories)
if (Fcb->OpenCount > 0) if (Fcb->OpenCount == 0 ||
file_changed = has_file_changed(entry->u.Open.changeattr, (Fcb->OpenCount > 0 &&
&entry->u.Open.binfo, nfs41_fcb); nfs41_fcb->changeattr != entry->u.Open.changeattr)) {
if (Fcb->OpenCount == 0 || file_changed) {
print_basic_info(1, &entry->u.Open.binfo); print_basic_info(1, &entry->u.Open.binfo);
print_std_info(1, &entry->u.Open.sinfo); print_std_info(1, &entry->u.Open.sinfo);
RtlCopyMemory(&nfs41_fcb->BasicInfo, &entry->u.Open.binfo, RtlCopyMemory(&nfs41_fcb->BasicInfo, &entry->u.Open.binfo,
@ -3466,44 +3460,52 @@ NTSTATUS nfs41_Create(
} }
} }
if (file_changed && !nfs41_fcb->StandardInfo.Directory) { if (Fcb->OpenCount > 0 &&
nfs41_fcb->changeattr != entry->u.Open.changeattr &&
!nfs41_fcb->StandardInfo.Directory) {
ULONG flag = DISABLE_CACHING; ULONG flag = DISABLE_CACHING;
DbgP("file object %wZ changed\n", SrvOpen->pAlreadyPrefixedName); DbgP("nfs41_Create: reopening (changed) file %wZ\n", SrvOpen->pAlreadyPrefixedName);
RxIndicateChangeOfBufferingStateForSrvOpen( RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
SrvOpen->pVNetRoot->pNetRoot->pSrvCall,
SrvOpen, SrvOpen->Key, ULongToPtr(flag));
} else if (!file_changed && !nfs41_fcb->StandardInfo.Directory) { } else if (!file_changed && !nfs41_fcb->StandardInfo.Directory) {
// windows does agressive write flushing (every 2s) nfs41_fobx->deleg_type = entry->u.Open.deleg_type;
// thus we'll always turn on write buffering DbgP("nfs41_Create: received delegation %d\n", entry->u.Open.deleg_type);
if ((!pVNetRootContext->nocoherence && if (!(params.CreateOptions & FILE_WRITE_THROUGH) &&
(entry->u.Open.deleg_type == 2 &&
!(params.CreateOptions & FILE_WRITE_THROUGH))) ||
(pVNetRootContext->nocoherence &&
((params.DesiredAccess & FILE_WRITE_DATA ||
params.DesiredAccess & FILE_APPEND_DATA) &&
!pVNetRootContext->write_thru && !pVNetRootContext->write_thru &&
!(params.CreateOptions & FILE_WRITE_THROUGH)))) { (entry->u.Open.deleg_type == 2 ||
(params.DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)))) {
DbgP("nfs41_Create: enabling write buffering\n"); DbgP("nfs41_Create: enabling write buffering\n");
SrvOpen->BufferingFlags |= SrvOpen->BufferingFlags |=
(FCB_STATE_WRITECACHING_ENABLED | (FCB_STATE_WRITECACHING_ENABLED |
FCB_STATE_WRITEBUFFERING_ENABLED); FCB_STATE_WRITEBUFFERING_ENABLED);
} }
if (entry->u.Open.deleg_type >= 1 ||
// if we received read delegation, turn on read buffering params.DesiredAccess & FILE_READ_DATA) {
if ((!pVNetRootContext->nocoherence &&
(entry->u.Open.deleg_type >= 1)) ||
(pVNetRootContext->nocoherence &&
(params.DesiredAccess & FILE_READ_DATA))) {
DbgP("nfs41_Create: enabling read buffering\n"); DbgP("nfs41_Create: enabling read buffering\n");
SrvOpen->BufferingFlags |= SrvOpen->BufferingFlags |=
(FCB_STATE_READBUFFERING_ENABLED | (FCB_STATE_READBUFFERING_ENABLED |
FCB_STATE_READCACHING_ENABLED); FCB_STATE_READCACHING_ENABLED);
} }
if (pVNetRootContext->nocache || if (pVNetRootContext->nocache ||
(params.CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)) { (params.CreateOptions & FILE_NO_INTERMEDIATE_BUFFERING)) {
DbgP("nfs41_Create: disabling buffering\n"); DbgP("nfs41_Create: disabling buffering\n");
SrvOpen->BufferingFlags = FCB_STATE_DISABLE_LOCAL_BUFFERING; SrvOpen->BufferingFlags = FCB_STATE_DISABLE_LOCAL_BUFFERING;
} else if (!entry->u.Open.deleg_type &&
(params.DesiredAccess &
(FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA))) {
nfs41_srvopen_list_entry *oentry;
DbgP("nfs41_Create: received no delegations: srv_open=%p "
"ctime=%llu\n", SrvOpen, entry->u.Open.changeattr);
oentry = RxAllocatePoolWithTag(NonPagedPool,
sizeof(nfs41_srvopen_list_entry), NFS41_MM_POOLTAG);
if (oentry == NULL) {
status = STATUS_INSUFFICIENT_RESOURCES;
goto out;
}
oentry->srv_open = SrvOpen;
oentry->nfs41_fobx = nfs41_fobx;
oentry->ChangeTime = entry->u.Open.changeattr;
oentry->skip = FALSE;
nfs41_AddEntry(srvopenLock, openlist, oentry);
} }
} }
@ -3609,6 +3611,34 @@ ULONG nfs41_ExtendForNonCache(
return status; return status;
} }
VOID nfs41_remove_srvopen_entry(
PMRX_SRV_OPEN SrvOpen)
{
PLIST_ENTRY pEntry;
nfs41_srvopen_list_entry *cur;
ExAcquireFastMutex(&srvopenLock);
pEntry = openlist->head.Flink;
DbgP("nfs41_remove_srvopen_entry: Looking for srv_open=%p\n", SrvOpen);
while (!IsListEmpty(&openlist->head)) {
cur = (nfs41_srvopen_list_entry *)CONTAINING_RECORD(pEntry,
nfs41_srvopen_list_entry, next);
if (cur->srv_open == SrvOpen) {
DbgP("nfs41_remove_srvopen_entry: Found match\n");
RemoveEntryList(pEntry);
RxFreePool(cur);
break;
}
/* place an upcall for this srv_open */
if (pEntry->Flink == &openlist->head) {
DbgP("nfs41_remove_srvopen_entry: reached end of the list\n");
break;
}
pEntry = pEntry->Flink;
}
ExReleaseFastMutex(&srvopenLock);
}
NTSTATUS map_close_errors( NTSTATUS map_close_errors(
DWORD status) DWORD status)
{ {
@ -3644,6 +3674,12 @@ NTSTATUS nfs41_CloseSrvOpen(
DbgEn(); DbgEn();
print_debug_header(RxContext); print_debug_header(RxContext);
if (!nfs41_fobx->deleg_type && !nfs41_fcb->StandardInfo.Directory &&
(SrvOpen->DesiredAccess &
(FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA))) {
nfs41_remove_srvopen_entry(SrvOpen);
}
status = nfs41_UpcallCreate(NFS41_CLOSE, &nfs41_fobx->sec_ctx, status = nfs41_UpcallCreate(NFS41_CLOSE, &nfs41_fobx->sec_ctx,
pVNetRootContext->session, nfs41_fobx->nfs41_open_state, pVNetRootContext->session, nfs41_fobx->nfs41_open_state,
pNetRootContext->nfs41d_version, &entry); pNetRootContext->nfs41d_version, &entry);
@ -4027,6 +4063,35 @@ out:
return status; return status;
} }
VOID nfs41_update_srvopen_list(
PMRX_SRV_OPEN SrvOpen,
ULONGLONG ChangeTime)
{
PLIST_ENTRY pEntry;
nfs41_srvopen_list_entry *cur;
ExAcquireFastMutex(&srvopenLock);
pEntry = openlist->head.Flink;
DbgP("nfs41_update_srvopen_list: Looking for srv_open=%p\n", SrvOpen);
while (!IsListEmpty(&openlist->head)) {
cur = (nfs41_srvopen_list_entry *)CONTAINING_RECORD(pEntry,
nfs41_srvopen_list_entry, next);
if (cur->srv_open == SrvOpen &&
cur->ChangeTime != ChangeTime) {
DbgP("nfs41_update_srvopen_list: Found match: updating %llu to "
"%llu\n", cur->ChangeTime, ChangeTime);
cur->ChangeTime = ChangeTime;
break;
}
/* place an upcall for this srv_open */
if (pEntry->Flink == &openlist->head) {
DbgP("nfs41_update_srvopen_list: reached end of the list\n");
break;
}
pEntry = pEntry->Flink;
}
ExReleaseFastMutex(&srvopenLock);
}
void print_nfs3_attrs( void print_nfs3_attrs(
nfs3_attrs *attrs) nfs3_attrs *attrs)
{ {
@ -4152,6 +4217,13 @@ NTSTATUS nfs41_SetEaInformation(
} }
#endif #endif
status = map_setea_error(entry->status); status = map_setea_error(entry->status);
if (!status) {
if (!nfs41_fobx->deleg_type && entry->u.SetEa.ChangeTime &&
(SrvOpen->DesiredAccess &
(FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)))
nfs41_update_srvopen_list(SrvOpen, entry->u.SetEa.ChangeTime);
nfs41_fcb->changeattr = entry->u.SetEa.ChangeTime;
}
RxFreePool(entry); RxFreePool(entry);
out: out:
#ifdef ENABLE_TIMINGS #ifdef ENABLE_TIMINGS
@ -4441,6 +4513,7 @@ NTSTATUS nfs41_SetSecurityInformation(
NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot); NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
__notnull PSECURITY_DESCRIPTOR sec_desc = __notnull PSECURITY_DESCRIPTOR sec_desc =
RxContext->CurrentIrpSp->Parameters.SetSecurity.SecurityDescriptor; RxContext->CurrentIrpSp->Parameters.SetSecurity.SecurityDescriptor;
__notnull PNFS41_FCB nfs41_fcb = NFS41GetFcbExtension(RxContext->pFcb);
SECURITY_INFORMATION info_class = SECURITY_INFORMATION info_class =
RxContext->CurrentIrpSp->Parameters.SetSecurity.SecurityInformation; RxContext->CurrentIrpSp->Parameters.SetSecurity.SecurityInformation;
#ifdef ENABLE_TIMINGS #ifdef ENABLE_TIMINGS
@ -4497,6 +4570,13 @@ NTSTATUS nfs41_SetSecurityInformation(
goto out; goto out;
} }
status = map_query_acl_error(entry->status); status = map_query_acl_error(entry->status);
if (!status) {
if (!nfs41_fobx->deleg_type && entry->u.Acl.ChangeTime &&
(SrvOpen->DesiredAccess &
(FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)))
nfs41_update_srvopen_list(SrvOpen, entry->u.Acl.ChangeTime);
nfs41_fcb->changeattr = entry->u.Acl.ChangeTime;
}
RxFreePool(entry); RxFreePool(entry);
out: out:
#ifdef ENABLE_TIMINGS #ifdef ENABLE_TIMINGS
@ -4838,6 +4918,13 @@ NTSTATUS nfs41_SetFileInformation(
} }
status = map_setfile_error(entry->status); status = map_setfile_error(entry->status);
if (!status) {
if (!nfs41_fobx->deleg_type && entry->u.SetFile.ChangeTime &&
(SrvOpen->DesiredAccess &
(FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA)))
nfs41_update_srvopen_list(SrvOpen, entry->u.SetFile.ChangeTime);
nfs41_fcb->changeattr = entry->u.SetFile.ChangeTime;
}
RxFreePool(entry); RxFreePool(entry);
out: out:
#ifdef ENABLE_TIMINGS #ifdef ENABLE_TIMINGS
@ -4936,9 +5023,15 @@ void print_readwrite_args(
} }
void enable_caching( void enable_caching(
PMRX_SRV_OPEN SrvOpen) PMRX_SRV_OPEN SrvOpen,
PNFS41_FOBX nfs41_fobx,
ULONGLONG ChangeTime)
{ {
ULONG flag = 0; ULONG flag = 0;
PLIST_ENTRY pEntry;
nfs41_srvopen_list_entry *cur;
BOOLEAN found = FALSE;
if (SrvOpen->DesiredAccess & FILE_READ_DATA) if (SrvOpen->DesiredAccess & FILE_READ_DATA)
flag = ENABLE_READ_CACHING; flag = ENABLE_READ_CACHING;
if (SrvOpen->DesiredAccess & FILE_WRITE_DATA) if (SrvOpen->DesiredAccess & FILE_WRITE_DATA)
@ -4953,6 +5046,39 @@ void enable_caching(
return; return;
RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1); RxChangeBufferingState((PSRV_OPEN)SrvOpen, ULongToPtr(flag), 1);
ExAcquireFastMutex(&srvopenLock);
pEntry = openlist->head.Flink;
DbgP("enable_caching: Looking for srv_open=%p\n", SrvOpen);
while (!IsListEmpty(&openlist->head)) {
cur = (nfs41_srvopen_list_entry *)CONTAINING_RECORD(pEntry,
nfs41_srvopen_list_entry, next);
if (cur->srv_open == SrvOpen) {
DbgP("enable_caching: Found match\n");
cur->skip = FALSE;
found = TRUE;
break;
}
if (pEntry->Flink == &openlist->head) {
DbgP("enable_caching: reached end of the list\n");
break;
}
pEntry = pEntry->Flink;
}
if (!found && nfs41_fobx->deleg_type) {
nfs41_srvopen_list_entry *oentry;
DbgP("enable_caching: delegation recalled: srv_open=%p\n", SrvOpen);
oentry = RxAllocatePoolWithTag(NonPagedPool,
sizeof(nfs41_srvopen_list_entry), NFS41_MM_POOLTAG);
if (oentry == NULL) return;
oentry->srv_open = SrvOpen;
oentry->nfs41_fobx = nfs41_fobx;
oentry->ChangeTime = ChangeTime;
oentry->skip = FALSE;
InsertTailList(&openlist->head, &oentry->next);
nfs41_fobx->deleg_type = 0;
}
ExReleaseFastMutex(&srvopenLock);
} }
NTSTATUS map_readwrite_errors( NTSTATUS map_readwrite_errors(
@ -5029,15 +5155,15 @@ NTSTATUS nfs41_Read(
RxContext->IoStatusBlock.Information = entry->u.ReadWrite.len; RxContext->IoStatusBlock.Information = entry->u.ReadWrite.len;
nfs41_fcb->Flags = 0; nfs41_fcb->Flags = 0;
if (pVNetRootContext->nocoherence && if ((!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
(!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
LOWIO_READWRITEFLAG_PAGING_IO) && LOWIO_READWRITEFLAG_PAGING_IO) &&
(SrvOpen->DesiredAccess & FILE_READ_DATA) && (SrvOpen->DesiredAccess & FILE_READ_DATA) &&
!pVNetRootContext->nocache && !pVNetRootContext->nocache &&
!(SrvOpen->BufferingFlags & !(SrvOpen->BufferingFlags &
(FCB_STATE_READBUFFERING_ENABLED | (FCB_STATE_READBUFFERING_ENABLED |
FCB_STATE_READCACHING_ENABLED)))) FCB_STATE_READCACHING_ENABLED)))) {
enable_caching(SrvOpen); enable_caching(SrvOpen, nfs41_fobx, nfs41_fcb->changeattr);
}
} else { } else {
status = map_readwrite_errors(entry->status); status = map_readwrite_errors(entry->status);
RxContext->CurrentIrp->IoStatus.Status = status; RxContext->CurrentIrp->IoStatus.Status = status;
@ -5123,19 +5249,21 @@ NTSTATUS nfs41_Write(
status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS; status = RxContext->CurrentIrp->IoStatus.Status = STATUS_SUCCESS;
RxContext->IoStatusBlock.Information = entry->u.ReadWrite.len; RxContext->IoStatusBlock.Information = entry->u.ReadWrite.len;
nfs41_fcb->Flags = 0; nfs41_fcb->Flags = 0;
nfs41_fcb->changeattr = entry->u.ReadWrite.ChangeTime;
//re-enable write buffering //re-enable write buffering
if (pVNetRootContext->nocoherence && if ((!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
(!BooleanFlagOn(LowIoContext->ParamsFor.ReadWrite.Flags,
LOWIO_READWRITEFLAG_PAGING_IO) && LOWIO_READWRITEFLAG_PAGING_IO) &&
(SrvOpen->DesiredAccess & FILE_WRITE_DATA) && (SrvOpen->DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA)) &&
(SrvOpen->DesiredAccess & FILE_READ_DATA) &&
!pVNetRootContext->write_thru && !pVNetRootContext->write_thru &&
!pVNetRootContext->nocache && !pVNetRootContext->nocache &&
!(SrvOpen->BufferingFlags & !(SrvOpen->BufferingFlags &
(FCB_STATE_WRITEBUFFERING_ENABLED | (FCB_STATE_WRITEBUFFERING_ENABLED |
FCB_STATE_WRITECACHING_ENABLED)))) FCB_STATE_WRITECACHING_ENABLED)))) {
enable_caching(SrvOpen); enable_caching(SrvOpen, nfs41_fobx, nfs41_fcb->changeattr);
} else if (!nfs41_fobx->deleg_type)
nfs41_update_srvopen_list(SrvOpen, entry->u.ReadWrite.ChangeTime);
} else { } else {
status = map_readwrite_errors(entry->status); status = map_readwrite_errors(entry->status);
RxContext->CurrentIrp->IoStatus.Status = status; RxContext->CurrentIrp->IoStatus.Status = status;
@ -5765,6 +5893,83 @@ NTSTATUS nfs41_init_ops()
return(STATUS_SUCCESS); return(STATUS_SUCCESS);
} }
#define RELATIVE(wait) (-(wait))
#define NANOSECONDS(nanos) (((signed __int64)(nanos)) / 100L)
#define MICROSECONDS(micros) (((signed __int64)(micros)) * NANOSECONDS(1000L))
#define MILLISECONDS(milli) (((signed __int64)(milli)) * MICROSECONDS(1000L))
#define SECONDS(seconds) (((signed __int64)(seconds)) * MILLISECONDS(1000L))
KSTART_ROUTINE srvopen_main;
VOID srvopen_main(PVOID ctx)
{
NTSTATUS status;
LARGE_INTEGER timeout;
DbgEn();
timeout.QuadPart = RELATIVE(SECONDS(30));
while(1) {
PLIST_ENTRY pEntry;
nfs41_srvopen_list_entry *cur;
status = KeDelayExecutionThread(KernelMode, TRUE, &timeout);
ExAcquireFastMutex(&srvopenLock);
pEntry = openlist->head.Flink;
while (!IsListEmpty(&openlist->head)) {
PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext;
PNFS41_NETROOT_EXTENSION pNetRootContext;
nfs41_updowncall_entry *entry;
FILE_BASIC_INFORMATION binfo;
PNFS41_FCB nfs41_fcb;
cur = (nfs41_srvopen_list_entry *)CONTAINING_RECORD(pEntry,
nfs41_srvopen_list_entry, next);
DbgP("srvopen_main: Checking attributes for srv_open=%p "
"change_time=%llu skipping=%d\n", cur->srv_open,
cur->ChangeTime, cur->skip);
if (cur->skip) goto out;
pVNetRootContext =
NFS41GetVNetRootExtension(cur->srv_open->pVNetRoot);
pNetRootContext =
NFS41GetNetRootExtension(cur->srv_open->pVNetRoot->pNetRoot);
/* place an upcall for this srv_open */
status = nfs41_UpcallCreate(NFS41_FILE_QUERY,
&cur->nfs41_fobx->sec_ctx, pVNetRootContext->session,
cur->nfs41_fobx->nfs41_open_state,
pNetRootContext->nfs41d_version, &entry);
if (status)
goto out;
entry->u.QueryFile.InfoClass = FileBasicInformation;
entry->u.QueryFile.buf = &binfo;
entry->u.QueryFile.buf_len = sizeof(binfo);
if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) {
status = STATUS_INTERNAL_ERROR;
goto out;
}
if (cur->ChangeTime != entry->u.QueryFile.ChangeTime) {
ULONG flag = DISABLE_CACHING;
DbgP("srvopen_main: old ctime=%llu new_ctime=%llu\n",
cur->ChangeTime, entry->u.QueryFile.ChangeTime);
DbgP("************ Invalidate the cache ************\n");
RxChangeBufferingState((PSRV_OPEN)cur->srv_open,
ULongToPtr(flag), 1);
cur->ChangeTime = entry->u.QueryFile.ChangeTime;
cur->skip = TRUE;
}
nfs41_fcb = (PNFS41_FCB)cur->srv_open->pFcb->Context;
nfs41_fcb->changeattr = entry->u.QueryFile.ChangeTime;
RxFreePool(entry);
out:
if (pEntry->Flink == &openlist->head) {
DbgP("srvopen_main: reached end of the list\n");
break;
}
pEntry = pEntry->Flink;
}
ExReleaseFastMutex(&srvopenLock);
}
DbgEx();
}
NTSTATUS DriverEntry( NTSTATUS DriverEntry(
IN PDRIVER_OBJECT drv, IN PDRIVER_OBJECT drv,
IN PUNICODE_STRING path) IN PUNICODE_STRING path)
@ -5774,6 +5979,8 @@ NTSTATUS DriverEntry(
UNICODE_STRING dev_name, user_dev_name; UNICODE_STRING dev_name, user_dev_name;
PNFS41_DEVICE_EXTENSION dev_exts; PNFS41_DEVICE_EXTENSION dev_exts;
TIME_FIELDS jan_1_1970 = {1970, 1, 1, 0, 0, 0, 0, 0}; TIME_FIELDS jan_1_1970 = {1970, 1, 1, 0, 0, 0, 0, 0};
ACCESS_MASK mask = 0;
OBJECT_ATTRIBUTES oattrs;
DbgEn(); DbgEn();
@ -5823,6 +6030,7 @@ NTSTATUS DriverEntry(
ExInitializeFastMutex(&downcallLock); ExInitializeFastMutex(&downcallLock);
ExInitializeFastMutex(&xidLock); ExInitializeFastMutex(&xidLock);
ExInitializeFastMutex(&openOwnerLock); ExInitializeFastMutex(&openOwnerLock);
ExInitializeFastMutex(&srvopenLock);
upcall = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_updowncall_list), upcall = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_updowncall_list),
NFS41_MM_POOLTAG); NFS41_MM_POOLTAG);
if (upcall == NULL) if (upcall == NULL)
@ -5835,6 +6043,23 @@ NTSTATUS DriverEntry(
goto out_unregister; goto out_unregister;
} }
InitializeListHead(&downcall->head); InitializeListHead(&downcall->head);
openlist = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_srvopen_list),
NFS41_MM_POOLTAG);
if (openlist == NULL) {
RxFreePool(upcall);
RxFreePool(downcall);
goto out_unregister;
}
InitializeListHead(&openlist->head);
InitializeObjectAttributes(&oattrs, NULL, OBJ_KERNEL_HANDLE, NULL, NULL);
status = PsCreateSystemThread(&dev_exts->openlistHandle, mask,
&oattrs, NULL, NULL, &srvopen_main, NULL);
if (status != STATUS_SUCCESS) {
RxFreePool(upcall);
RxFreePool(downcall);
RxFreePool(openlist);
goto out;
}
drv->DriverUnload = nfs41_driver_unload; drv->DriverUnload = nfs41_driver_unload;