volume: cache volume attributes on mount

struct NFS41_V_NET_ROOT_EXTENSION now stores only the FILE_FS_ATTRIBUTE_INFORMATION (without the extra buffer space for a name).  on QueryVolumeInfo() for FileFsAttributeInformation on the root directory, the FILE_FS_ATTRIBUTE_INFORMATION is copied into the output buffer, and the name is added there.  QueryVolumeInfo() only makes upcalls when FileFsAttributeInformation queries are not for the root directory

new function is_root_directory() uses the logic from Set/GetReparsePoint() to determine whether it's operating on the root directory

moved logic from volume.c:handle_volume_attributes() to superblock.c:nfs41_superblock_fs_attributes().  the mount downcall copies the FILE_FS_ATTRIBUTE_INFORMATION buffer down to the driver.  the driver reads this buffer directly into VNetRootContext->FsAttrs

Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
Casey Bodley 2012-04-10 12:05:43 -04:00 committed by unknown
parent 4c8c263b49
commit 2baeeb855b
6 changed files with 94 additions and 78 deletions

View file

@ -61,6 +61,7 @@ static int handle_mount(nfs41_upcall *upcall)
multi_addr4 addrs; multi_addr4 addrs;
nfs41_root *root; nfs41_root *root;
nfs41_client *client; nfs41_client *client;
nfs41_path_fh file;
// resolve hostname,port // resolve hostname,port
status = nfs41_server_resolve(args->hostname, 2049, &addrs); status = nfs41_server_resolve(args->hostname, 2049, &addrs);
@ -95,13 +96,15 @@ static int handle_mount(nfs41_upcall *upcall)
// look up the mount path, and fail if it doesn't exist // look up the mount path, and fail if it doesn't exist
status = nfs41_lookup(root, client->session, status = nfs41_lookup(root, client->session,
&path, NULL, NULL, NULL, NULL); &path, NULL, &file, NULL, NULL);
if (status) { if (status) {
eprintf("nfs41_lookup('%s') failed with %d\n", path.path, status); eprintf("nfs41_lookup('%s') failed with %d\n", path.path, status);
status = ERROR_BAD_NETPATH; status = ERROR_BAD_NETPATH;
goto out_err; goto out_err;
} }
nfs41_superblock_fs_attributes(file.fh.superblock, &args->FsAttrs);
upcall->root_ref = root; upcall->root_ref = root;
nfs41_root_ref(upcall->root_ref); nfs41_root_ref(upcall->root_ref);
args->lease_time = client->session->lease_time; args->lease_time = client->session->lease_time;
@ -124,6 +127,8 @@ static int marshall_mount(unsigned char *buffer, uint32_t *length, nfs41_upcall
status = safe_write(&buffer, length, &NFS41D_VERSION, sizeof(DWORD)); status = safe_write(&buffer, length, &NFS41D_VERSION, sizeof(DWORD));
if (status) goto out; if (status) goto out;
status = safe_write(&buffer, length, &args->lease_time, sizeof(DWORD)); status = safe_write(&buffer, length, &args->lease_time, sizeof(DWORD));
if (status) goto out;
status = safe_write(&buffer, length, &args->FsAttrs, sizeof(args->FsAttrs));
out: out:
return status; return status;
} }

View file

@ -443,6 +443,11 @@ static __inline void nfs41_superblock_supported_attrs_exclcreat(
bitmap_intersect(attrs, &superblock->suppattr_exclcreat); bitmap_intersect(attrs, &superblock->suppattr_exclcreat);
} }
struct _FILE_FS_ATTRIBUTE_INFORMATION;
void nfs41_superblock_fs_attributes(
IN const nfs41_superblock *superblock,
OUT struct _FILE_FS_ATTRIBUTE_INFORMATION *FsAttrs);
void nfs41_superblock_space_changed( void nfs41_superblock_space_changed(
IN nfs41_superblock *superblock); IN nfs41_superblock *superblock);

View file

@ -25,6 +25,7 @@
#include "daemon_debug.h" #include "daemon_debug.h"
#include "nfs41.h" #include "nfs41.h"
#include "nfs41_ops.h" #include "nfs41_ops.h"
#include "from_kernel.h"
#include "util.h" #include "util.h"
@ -160,6 +161,35 @@ out:
return status; return status;
} }
void nfs41_superblock_fs_attributes(
IN const nfs41_superblock *superblock,
OUT PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs)
{
FsAttrs->FileSystemAttributes = FILE_SUPPORTS_REMOTE_STORAGE;
if (superblock->link_support)
FsAttrs->FileSystemAttributes |= FILE_SUPPORTS_HARD_LINKS;
if (superblock->symlink_support)
FsAttrs->FileSystemAttributes |= FILE_SUPPORTS_REPARSE_POINTS;
if (superblock->ea_support)
FsAttrs->FileSystemAttributes |= FILE_SUPPORTS_EXTENDED_ATTRIBUTES;
if (superblock->case_preserving)
FsAttrs->FileSystemAttributes |= FILE_CASE_PRESERVED_NAMES;
if (!superblock->case_insensitive)
FsAttrs->FileSystemAttributes |= FILE_CASE_SENSITIVE_SEARCH;
if (superblock->aclsupport)
FsAttrs->FileSystemAttributes |= FILE_PERSISTENT_ACLS;
FsAttrs->MaximumComponentNameLength = NFS41_MAX_COMPONENT_LEN;
/* let the driver fill in FileSystemName */
FsAttrs->FileSystemNameLength = 0;
dprintf(SBLVL, "FileFsAttributeInformation: case_preserving %u, "
"case_insensitive %u, max component %u\n",
superblock->case_preserving, superblock->case_insensitive,
FsAttrs->MaximumComponentNameLength);
}
/* nfs41_superblock_list */ /* nfs41_superblock_list */
#define superblock_entry(pos) list_container(pos, nfs41_superblock, entry) #define superblock_entry(pos) list_container(pos, nfs41_superblock, entry)

View file

@ -35,6 +35,7 @@ typedef struct __mount_upcall_args {
DWORD rsize; DWORD rsize;
DWORD wsize; DWORD wsize;
DWORD lease_time; DWORD lease_time;
FILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
} mount_upcall_args; } mount_upcall_args;
typedef struct __open_upcall_args { typedef struct __open_upcall_args {

View file

@ -112,39 +112,6 @@ out:
return status; return status;
} }
static void handle_volume_attributes(
IN volume_upcall_args *args,
IN nfs41_open_state *state)
{
PFILE_FS_ATTRIBUTE_INFORMATION attr = &args->info.attribute;
const nfs41_superblock *superblock = state->file.fh.superblock;
attr->FileSystemAttributes = FILE_SUPPORTS_REMOTE_STORAGE;
if (superblock->link_support)
attr->FileSystemAttributes |= FILE_SUPPORTS_HARD_LINKS;
if (superblock->symlink_support)
attr->FileSystemAttributes |= FILE_SUPPORTS_REPARSE_POINTS;
if (superblock->ea_support)
attr->FileSystemAttributes |= FILE_SUPPORTS_EXTENDED_ATTRIBUTES;
if (superblock->case_preserving)
attr->FileSystemAttributes |= FILE_CASE_PRESERVED_NAMES;
if (!superblock->case_insensitive)
attr->FileSystemAttributes |= FILE_CASE_SENSITIVE_SEARCH;
if (superblock->aclsupport)
attr->FileSystemAttributes |= FILE_PERSISTENT_ACLS;
attr->MaximumComponentNameLength = NFS41_MAX_COMPONENT_LEN;
/* let the driver fill in FileSystemName/Len */
args->len = sizeof(args->info.attribute);
dprintf(2, "FileFsAttributeInformation: case_preserving %u, "
"case_insensitive %u, max component %u\n",
superblock->case_preserving, superblock->case_insensitive,
attr->MaximumComponentNameLength);
}
static int handle_volume(nfs41_upcall *upcall) static int handle_volume(nfs41_upcall *upcall)
{ {
volume_upcall_args *args = &upcall->args.volume; volume_upcall_args *args = &upcall->args.volume;
@ -176,7 +143,8 @@ static int handle_volume(nfs41_upcall *upcall)
break; break;
case FileFsAttributeInformation: case FileFsAttributeInformation:
handle_volume_attributes(args, upcall->state_ref); nfs41_superblock_fs_attributes(upcall->state_ref->file.fh.superblock,
&args->info.attribute);
break; break;
default: default:

View file

@ -159,6 +159,7 @@ typedef struct _updowncall_entry {
struct { struct {
PUNICODE_STRING srv_name; PUNICODE_STRING srv_name;
PUNICODE_STRING root; PUNICODE_STRING root;
PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
DWORD sec_flavor; DWORD sec_flavor;
DWORD rsize; DWORD rsize;
DWORD wsize; DWORD wsize;
@ -375,8 +376,7 @@ typedef struct _NFS41_V_NET_ROOT_EXTENSION {
NODE_TYPE_CODE NodeTypeCode; NODE_TYPE_CODE NodeTypeCode;
NODE_BYTE_SIZE NodeByteSize; NODE_BYTE_SIZE NodeByteSize;
HANDLE session; HANDLE session;
BYTE FsAttrs[FS_ATTR_LEN]; FILE_FS_ATTRIBUTE_INFORMATION FsAttrs;
LONG FsAttrsLen;
DWORD sec_flavor; DWORD sec_flavor;
DWORD timeout; DWORD timeout;
BOOLEAN read_only; BOOLEAN read_only;
@ -1587,6 +1587,8 @@ void unmarshal_nfs41_mount(
RtlCopyMemory(&cur->version, *buf, sizeof(DWORD)); RtlCopyMemory(&cur->version, *buf, sizeof(DWORD));
*buf += sizeof(DWORD); *buf += sizeof(DWORD);
RtlCopyMemory(&cur->u.Mount.lease_time, *buf, sizeof(DWORD)); RtlCopyMemory(&cur->u.Mount.lease_time, *buf, sizeof(DWORD));
*buf += sizeof(DWORD);
RtlCopyMemory(cur->u.Mount.FsAttrs, *buf, sizeof(FILE_FS_ATTRIBUTE_INFORMATION));
#ifdef DEBUG_MARSHAL_DETAIL #ifdef DEBUG_MARSHAL_DETAIL
DbgP("unmarshal_nfs41_mount: session pointer 0x%x version %d lease_time " DbgP("unmarshal_nfs41_mount: session pointer 0x%x version %d lease_time "
"%d\n", cur->session, cur->version, cur->u.Mount.lease_time); "%d\n", cur->session, cur->version, cur->u.Mount.lease_time);
@ -2543,7 +2545,8 @@ NTSTATUS nfs41_mount(
PNFS41_MOUNT_CONFIG config, PNFS41_MOUNT_CONFIG config,
DWORD sec_flavor, DWORD sec_flavor,
PHANDLE session, PHANDLE session,
DWORD *version) DWORD *version,
PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs)
{ {
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES; NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
nfs41_updowncall_entry *entry; nfs41_updowncall_entry *entry;
@ -2562,6 +2565,7 @@ NTSTATUS nfs41_mount(
entry->u.Mount.rsize = config->ReadSize; entry->u.Mount.rsize = config->ReadSize;
entry->u.Mount.wsize = config->WriteSize; entry->u.Mount.wsize = config->WriteSize;
entry->u.Mount.sec_flavor = sec_flavor; entry->u.Mount.sec_flavor = sec_flavor;
entry->u.Mount.FsAttrs = FsAttrs;
status = nfs41_UpcallWaitForReply(entry, config->timeout); status = nfs41_UpcallWaitForReply(entry, config->timeout);
SeDeleteClientSecurity(&entry->sec_ctx); SeDeleteClientSecurity(&entry->sec_ctx);
@ -2985,7 +2989,8 @@ NTSTATUS nfs41_CreateVNetRoot(
if (!found_existing_mount || !found_matching_flavor) { if (!found_existing_mount || !found_matching_flavor) {
/* send the mount upcall */ /* send the mount upcall */
status = nfs41_mount(&Config, pVNetRootContext->sec_flavor, status = nfs41_mount(&Config, pVNetRootContext->sec_flavor,
&pVNetRootContext->session, &nfs41d_version); &pVNetRootContext->session, &nfs41d_version,
&pVNetRootContext->FsAttrs);
if (status != STATUS_SUCCESS) { if (status != STATUS_SUCCESS) {
if (!found_existing_mount && if (!found_existing_mount &&
IsListEmpty(&pNetRootContext->mounts->head)) { IsListEmpty(&pNetRootContext->mounts->head)) {
@ -3281,11 +3286,9 @@ BOOLEAN isFilenameTooLong(
PUNICODE_STRING name, PUNICODE_STRING name,
PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext) PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext)
{ {
PFILE_FS_ATTRIBUTE_INFORMATION attrs = PFILE_FS_ATTRIBUTE_INFORMATION attrs = &pVNetRootContext->FsAttrs;
(PFILE_FS_ATTRIBUTE_INFORMATION)pVNetRootContext->FsAttrs;
LONG len = attrs->MaximumComponentNameLength, count = 1, i; LONG len = attrs->MaximumComponentNameLength, count = 1, i;
PWCH p = name->Buffer; PWCH p = name->Buffer;
if (!pVNetRootContext->FsAttrsLen) len = 64;
for (i = 0; i < name->Length / 2; i++) { for (i = 0; i < name->Length / 2; i++) {
if (p[0] == L'\\') count = 1; if (p[0] == L'\\') count = 1;
else { else {
@ -3393,7 +3396,7 @@ NTSTATUS check_nfs41_create_args(
__notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
__notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs = __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs =
(PFILE_FS_ATTRIBUTE_INFORMATION)pVNetRootContext->FsAttrs; &pVNetRootContext->FsAttrs;
__notnull PNFS41_NETROOT_EXTENSION pNetRootContext = __notnull PNFS41_NETROOT_EXTENSION pNetRootContext =
NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot); NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
__notnull PMRX_FCB Fcb = RxContext->pFcb; __notnull PMRX_FCB Fcb = RxContext->pFcb;
@ -4183,6 +4186,17 @@ void nfs41_create_volume_info(PFILE_FS_VOLUME_INFORMATION pVolInfo, DWORD *len)
*len = sizeof(FILE_FS_VOLUME_INFORMATION) + VolName.Length; *len = sizeof(FILE_FS_VOLUME_INFORMATION) + VolName.Length;
} }
static BOOLEAN is_root_directory(
PRX_CONTEXT RxContext)
{
__notnull PV_NET_ROOT VNetRoot = (PV_NET_ROOT)
RxContext->pRelevantSrvOpen->pVNetRoot;
/* compare the FileObject name with the VNetRoot prefix to determine
* whether it's the root directory (allowing for added \) */
return RxContext->CurrentIrpSp->FileObject->FileName.Length <=
VNetRoot->PrefixEntry.Prefix.Length + sizeof(WCHAR);
}
NTSTATUS nfs41_QueryVolumeInformation( NTSTATUS nfs41_QueryVolumeInformation(
IN OUT PRX_CONTEXT RxContext) IN OUT PRX_CONTEXT RxContext)
{ {
@ -4245,20 +4259,28 @@ NTSTATUS nfs41_QueryVolumeInformation(
goto out; goto out;
case FileFsAttributeInformation: case FileFsAttributeInformation:
/* used cached fs attributes if available */ if (RxContext->Info.LengthRemaining < FS_ATTR_LEN) {
if (pVNetRootContext->FsAttrsLen) { RxContext->InformationToReturn = FS_ATTR_LEN;
const LONG len = pVNetRootContext->FsAttrsLen; status = STATUS_BUFFER_TOO_SMALL;
if (RxContext->Info.LengthRemaining < len) { goto out;
RtlCopyMemory(RxContext->Info.Buffer, }
pVNetRootContext->FsAttrs,
RxContext->Info.LengthRemaining); /* on attribute queries for the root directory,
status = STATUS_BUFFER_OVERFLOW; * use cached volume attributes from mount */
goto out; if (is_root_directory(RxContext)) {
} PFILE_FS_ATTRIBUTE_INFORMATION attrs =
RtlCopyMemory(RxContext->Info.Buffer, (PFILE_FS_ATTRIBUTE_INFORMATION)RxContext->Info.Buffer;
pVNetRootContext->FsAttrs, len); DECLARE_CONST_UNICODE_STRING(FsName, FS_NAME);
RxContext->Info.LengthRemaining -= len;
status = STATUS_SUCCESS; RtlCopyMemory(attrs, &pVNetRootContext->FsAttrs,
sizeof(pVNetRootContext->FsAttrs));
/* fill in the FileSystemName */
RtlCopyMemory(attrs->FileSystemName, FsName.Buffer,
FsName.MaximumLength); /* 'MaximumLength' to include null */
attrs->FileSystemNameLength = FsName.Length;
RxContext->Info.LengthRemaining -= FS_ATTR_LEN;
goto out; goto out;
} }
/* else fall through and send the upcall */ /* else fall through and send the upcall */
@ -4292,22 +4314,12 @@ NTSTATUS nfs41_QueryVolumeInformation(
PFILE_FS_ATTRIBUTE_INFORMATION attrs = PFILE_FS_ATTRIBUTE_INFORMATION attrs =
(PFILE_FS_ATTRIBUTE_INFORMATION)RxContext->Info.Buffer; (PFILE_FS_ATTRIBUTE_INFORMATION)RxContext->Info.Buffer;
DECLARE_CONST_UNICODE_STRING(FsName, FS_NAME); DECLARE_CONST_UNICODE_STRING(FsName, FS_NAME);
entry->u.Volume.buf_len += FsName.Length;
if (entry->u.Volume.buf_len > (ULONG)RxContext->Info.LengthRemaining) {
RxContext->InformationToReturn = entry->u.Volume.buf_len;
status = STATUS_BUFFER_TOO_SMALL;
goto out;
}
RtlCopyMemory(attrs->FileSystemName, FsName.Buffer, RtlCopyMemory(attrs->FileSystemName, FsName.Buffer,
FsName.MaximumLength); /* 'MaximumLength' to include null */ FsName.MaximumLength); /* 'MaximumLength' to include null */
attrs->FileSystemNameLength = FsName.Length; attrs->FileSystemNameLength = FsName.Length;
/* save fs attributes with the vnetroot */ entry->u.Volume.buf_len = FS_ATTR_LEN;
if (entry->u.Volume.buf_len <= FS_ATTR_LEN) {
RtlCopyMemory(&pVNetRootContext->FsAttrs,
RxContext->Info.Buffer, entry->u.Volume.buf_len);
pVNetRootContext->FsAttrsLen = entry->u.Volume.buf_len;
}
} }
#ifdef ENABLE_TIMINGS #ifdef ENABLE_TIMINGS
InterlockedIncrement(&volume.sops); InterlockedIncrement(&volume.sops);
@ -4436,7 +4448,7 @@ NTSTATUS check_nfs41_setea_args(
__notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot); NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
__notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs = __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs =
(PFILE_FS_ATTRIBUTE_INFORMATION)pVNetRootContext->FsAttrs; &pVNetRootContext->FsAttrs;
__notnull PFILE_FULL_EA_INFORMATION ea = __notnull PFILE_FULL_EA_INFORMATION ea =
(PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer; (PFILE_FULL_EA_INFORMATION)RxContext->Info.Buffer;
@ -4567,7 +4579,7 @@ NTSTATUS check_nfs41_queryea_args(
__notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext = __notnull PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot); NFS41GetVNetRootExtension(RxContext->pRelevantSrvOpen->pVNetRoot);
__notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs = __notnull PFILE_FS_ATTRIBUTE_INFORMATION FsAttrs =
(PFILE_FS_ATTRIBUTE_INFORMATION)pVNetRootContext->FsAttrs; &pVNetRootContext->FsAttrs;
PFILE_GET_EA_INFORMATION ea = (PFILE_GET_EA_INFORMATION) PFILE_GET_EA_INFORMATION ea = (PFILE_GET_EA_INFORMATION)
RxContext->CurrentIrpSp->Parameters.QueryEa.EaList; RxContext->CurrentIrpSp->Parameters.QueryEa.EaList;
@ -6075,7 +6087,6 @@ NTSTATUS check_nfs41_setreparse_args(
__notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen; __notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
__notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext = __notnull PNFS41_V_NET_ROOT_EXTENSION VNetRootContext =
NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
__notnull PV_NET_ROOT VNetRoot = (PV_NET_ROOT)SrvOpen->pVNetRoot;
const ULONG HeaderLen = REPARSE_DATA_BUFFER_HEADER_SIZE; const ULONG HeaderLen = REPARSE_DATA_BUFFER_HEADER_SIZE;
/* access checks */ /* access checks */
@ -6090,8 +6101,7 @@ NTSTATUS check_nfs41_setreparse_args(
/* must have a filename longer than vnetroot name, /* must have a filename longer than vnetroot name,
* or it's trying to operate on the volume itself */ * or it's trying to operate on the volume itself */
if (RxContext->CurrentIrpSp->FileObject->FileName.Length <= if (is_root_directory(RxContext)) {
VNetRoot->PrefixEntry.Prefix.Length + sizeof(WCHAR)) {
status = STATUS_INVALID_PARAMETER; status = STATUS_INVALID_PARAMETER;
goto out; goto out;
} }
@ -6183,15 +6193,12 @@ NTSTATUS check_nfs41_getreparse_args(
{ {
NTSTATUS status = STATUS_SUCCESS; NTSTATUS status = STATUS_SUCCESS;
XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl; XXCTL_LOWIO_COMPONENT *FsCtl = &RxContext->LowIoContext.ParamsFor.FsCtl;
__notnull PV_NET_ROOT VNetRoot =
(PV_NET_ROOT)RxContext->pRelevantSrvOpen->pVNetRoot;
const USHORT HeaderLen = FIELD_OFFSET(REPARSE_DATA_BUFFER, const USHORT HeaderLen = FIELD_OFFSET(REPARSE_DATA_BUFFER,
SymbolicLinkReparseBuffer.PathBuffer); SymbolicLinkReparseBuffer.PathBuffer);
/* must have a filename longer than vnetroot name, /* must have a filename longer than vnetroot name,
* or it's trying to operate on the volume itself */ * or it's trying to operate on the volume itself */
if (RxContext->CurrentIrpSp->FileObject->FileName.Length <= if (is_root_directory(RxContext)) {
VNetRoot->PrefixEntry.Prefix.Length + sizeof(WCHAR)) {
status = STATUS_INVALID_PARAMETER; status = STATUS_INVALID_PARAMETER;
goto out; goto out;
} }