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;
nfs41_root *root;
nfs41_client *client;
nfs41_path_fh file;
// resolve hostname,port
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
status = nfs41_lookup(root, client->session,
&path, NULL, NULL, NULL, NULL);
&path, NULL, &file, NULL, NULL);
if (status) {
eprintf("nfs41_lookup('%s') failed with %d\n", path.path, status);
status = ERROR_BAD_NETPATH;
goto out_err;
}
nfs41_superblock_fs_attributes(file.fh.superblock, &args->FsAttrs);
upcall->root_ref = root;
nfs41_root_ref(upcall->root_ref);
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));
if (status) goto out;
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:
return status;
}

View file

@ -443,6 +443,11 @@ static __inline void nfs41_superblock_supported_attrs_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(
IN nfs41_superblock *superblock);

View file

@ -25,6 +25,7 @@
#include "daemon_debug.h"
#include "nfs41.h"
#include "nfs41_ops.h"
#include "from_kernel.h"
#include "util.h"
@ -160,6 +161,35 @@ out:
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 */
#define superblock_entry(pos) list_container(pos, nfs41_superblock, entry)

View file

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

View file

@ -112,39 +112,6 @@ out:
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)
{
volume_upcall_args *args = &upcall->args.volume;
@ -176,7 +143,8 @@ static int handle_volume(nfs41_upcall *upcall)
break;
case FileFsAttributeInformation:
handle_volume_attributes(args, upcall->state_ref);
nfs41_superblock_fs_attributes(upcall->state_ref->file.fh.superblock,
&args->info.attribute);
break;
default:

View file

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