deleg: use delegations to satisfy opens locally
added delegation.c and .h nfs41_client stores a list of nfs41_delegation_state new function nfs41_delegate_open() to look for a compatible delegation before calling nfs41_open() if nfs41_open() is granted a delegation, call nfs41_delegation_granted() to register it with the client client calls nfs41_client_delegation_free() on unmount to free list of delegations Signed-off-by: Casey Bodley <cbodley@citi.umich.edu>
This commit is contained in:
parent
0c874a66ba
commit
0bee545e91
7 changed files with 345 additions and 16 deletions
|
|
@ -195,6 +195,7 @@
|
|||
<ClCompile Include="..\daemon\callback_xdr.c" />
|
||||
<ClCompile Include="..\daemon\callback_server.c" />
|
||||
<ClCompile Include="..\daemon\daemon_debug.c" />
|
||||
<ClCompile Include="..\daemon\delegation.c" />
|
||||
<ClCompile Include="..\daemon\getattr.c" />
|
||||
<ClCompile Include="..\daemon\idmap.c" />
|
||||
<ClCompile Include="..\daemon\lock.c" />
|
||||
|
|
@ -227,6 +228,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\daemon\daemon_debug.h" />
|
||||
<ClInclude Include="..\daemon\delegation.h" />
|
||||
<ClInclude Include="..\daemon\from_kernel.h" />
|
||||
<ClInclude Include="..\daemon\idmap.h" />
|
||||
<ClInclude Include="..\daemon\list.h" />
|
||||
|
|
|
|||
|
|
@ -113,6 +113,9 @@
|
|||
<ClCompile Include="..\daemon\acl.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\daemon\delegation.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\daemon\daemon_debug.h">
|
||||
|
|
@ -166,6 +169,9 @@
|
|||
<ClInclude Include="..\daemon\tree.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\daemon\delegation.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\daemon\sources">
|
||||
|
|
|
|||
216
daemon/delegation.c
Normal file
216
daemon/delegation.c
Normal file
|
|
@ -0,0 +1,216 @@
|
|||
/* Copyright (c) 2010
|
||||
* The Regents of the University of Michigan
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Permission is granted to use, copy and redistribute this software
|
||||
* for noncommercial education and research purposes, so long as no
|
||||
* fee is charged, and so long as the name of the University of Michigan
|
||||
* is not used in any advertising or publicity pertaining to the use
|
||||
* or distribution of this software without specific, written prior
|
||||
* authorization. Permission to modify or otherwise create derivative
|
||||
* works of this software is not granted.
|
||||
*
|
||||
* This software is provided as is, without representation or warranty
|
||||
* of any kind either express or implied, including without limitation
|
||||
* the implied warranties of merchantability, fitness for a particular
|
||||
* purpose, or noninfringement. The Regents of the University of
|
||||
* Michigan shall not be liable for any damages, including special,
|
||||
* indirect, incidental, or consequential damages, with respect to any
|
||||
* claim arising out of or in connection with the use of the software,
|
||||
* even if it has been or is hereafter advised of the possibility of
|
||||
* such damages.
|
||||
*/
|
||||
|
||||
#include "delegation.h"
|
||||
#include "nfs41_ops.h"
|
||||
#include "util.h"
|
||||
#include "daemon_debug.h"
|
||||
|
||||
|
||||
#define DGLVL 2 /* dprintf level for delegation logging */
|
||||
|
||||
|
||||
/* allocation and reference counting */
|
||||
static int delegation_create(
|
||||
IN const nfs41_path_fh *file,
|
||||
IN const open_delegation4 *delegation,
|
||||
OUT nfs41_delegation_state **deleg_out)
|
||||
{
|
||||
nfs41_delegation_state *state;
|
||||
int status = NO_ERROR;
|
||||
|
||||
state = calloc(1, sizeof(nfs41_delegation_state));
|
||||
if (state == NULL) {
|
||||
status = GetLastError();
|
||||
goto out;
|
||||
}
|
||||
|
||||
memcpy(&state->state, delegation, sizeof(open_delegation4));
|
||||
fh_copy(&state->fh, &file->fh);
|
||||
list_init(&state->client_entry);
|
||||
state->ref_count = 1;
|
||||
*deleg_out = state;
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
void nfs41_delegation_ref(
|
||||
IN nfs41_delegation_state *state)
|
||||
{
|
||||
const LONG count = InterlockedIncrement(&state->ref_count);
|
||||
dprintf(DGLVL, "nfs41_delegation_ref() count %d\n", count);
|
||||
}
|
||||
|
||||
void nfs41_delegation_deref(
|
||||
IN nfs41_delegation_state *state)
|
||||
{
|
||||
const LONG count = InterlockedDecrement(&state->ref_count);
|
||||
dprintf(DGLVL, "nfs41_delegation_deref() count %d\n", count);
|
||||
if (count == 0)
|
||||
free(state);
|
||||
}
|
||||
|
||||
|
||||
/* open delegation */
|
||||
int nfs41_delegation_granted(
|
||||
IN nfs41_session *session,
|
||||
IN nfs41_path_fh *file,
|
||||
IN open_delegation4 *delegation,
|
||||
OUT nfs41_delegation_state **deleg_out)
|
||||
{
|
||||
nfs41_client *client = session->client;
|
||||
nfs41_delegation_state *state;
|
||||
int status = NO_ERROR;
|
||||
|
||||
if (delegation->recalled ||
|
||||
delegation->type == OPEN_DELEGATE_NONE ||
|
||||
delegation->type == OPEN_DELEGATE_NONE_EXT)
|
||||
goto out;
|
||||
|
||||
/* allocate the delegation state */
|
||||
status = delegation_create(file, delegation, &state);
|
||||
if (status)
|
||||
goto out_return;
|
||||
|
||||
/* register the delegation with the client */
|
||||
EnterCriticalSection(&client->state.lock);
|
||||
/* XXX: check for duplicates by fh and stateid? */
|
||||
list_add_tail(&client->state.delegations, &state->client_entry);
|
||||
LeaveCriticalSection(&client->state.lock);
|
||||
|
||||
nfs41_delegation_ref(state); /* return a reference */
|
||||
*deleg_out = state;
|
||||
out:
|
||||
return status;
|
||||
|
||||
out_return: /* return the delegation on failure */
|
||||
nfs41_delegreturn(session, file, &delegation->stateid);
|
||||
goto out;
|
||||
}
|
||||
|
||||
#define deleg_entry(pos) list_container(pos, nfs41_delegation_state, client_entry)
|
||||
|
||||
static int deleg_fh_cmp(const struct list_entry *entry, const void *value)
|
||||
{
|
||||
const nfs41_fh *lhs = &deleg_entry(entry)->fh;
|
||||
const nfs41_fh *rhs = (const nfs41_fh*)value;
|
||||
if (lhs->superblock != rhs->superblock) return -1;
|
||||
if (lhs->fileid != rhs->fileid) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool_t delegation_compatible(
|
||||
IN enum open_delegation_type4 type,
|
||||
IN uint32_t create,
|
||||
IN uint32_t access,
|
||||
IN uint32_t deny)
|
||||
{
|
||||
/* TODO: allow write delegation to handle OPEN4_CREATE */
|
||||
if (create == OPEN4_CREATE)
|
||||
return FALSE;
|
||||
|
||||
switch (type) {
|
||||
case OPEN_DELEGATE_WRITE:
|
||||
/* An OPEN_DELEGATE_WRITE delegation allows the client to handle,
|
||||
* on its own, all opens. */
|
||||
return TRUE;
|
||||
|
||||
case OPEN_DELEGATE_READ:
|
||||
/* An OPEN_DELEGATE_READ delegation allows a client to handle,
|
||||
* on its own, requests to open a file for reading that do not
|
||||
* deny OPEN4_SHARE_ACCESS_READ access to others. */
|
||||
if (access & OPEN4_SHARE_ACCESS_WRITE || deny & OPEN4_SHARE_DENY_READ)
|
||||
return FALSE;
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static int delegation_find(
|
||||
IN nfs41_client *client,
|
||||
IN const void *value,
|
||||
IN list_compare_fn cmp,
|
||||
OUT nfs41_delegation_state **deleg_out)
|
||||
{
|
||||
struct list_entry *entry;
|
||||
int status = NFS4ERR_BADHANDLE;
|
||||
|
||||
EnterCriticalSection(&client->state.lock);
|
||||
entry = list_search(&client->state.delegations, value, cmp);
|
||||
if (entry) {
|
||||
*deleg_out = deleg_entry(entry);
|
||||
nfs41_delegation_ref(*deleg_out);
|
||||
status = NFS4_OK;
|
||||
}
|
||||
LeaveCriticalSection(&client->state.lock);
|
||||
return status;
|
||||
}
|
||||
|
||||
int nfs41_delegate_open(
|
||||
IN nfs41_client *client,
|
||||
IN nfs41_path_fh *file,
|
||||
IN uint32_t create,
|
||||
IN uint32_t access,
|
||||
IN uint32_t deny,
|
||||
OUT nfs41_delegation_state **deleg_out,
|
||||
OUT nfs41_file_info *info)
|
||||
{
|
||||
nfs41_delegation_state *deleg;
|
||||
int status;
|
||||
|
||||
/* search for a delegation with this filehandle */
|
||||
status = delegation_find(client, &file->fh, deleg_fh_cmp, &deleg);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
if (!delegation_compatible(deleg->state.type, create, access, deny)) {
|
||||
status = NFS4ERR_BADHANDLE;
|
||||
goto out_deleg;
|
||||
}
|
||||
|
||||
/* TODO: check access against deleg->state.permissions or send ACCESS */
|
||||
|
||||
*deleg_out = deleg;
|
||||
status = NFS4_OK;
|
||||
out:
|
||||
return status;
|
||||
|
||||
out_deleg:
|
||||
nfs41_delegation_deref(deleg);
|
||||
goto out;
|
||||
}
|
||||
|
||||
void nfs41_client_delegation_free(
|
||||
IN nfs41_client *client)
|
||||
{
|
||||
struct list_entry *entry, *tmp;
|
||||
|
||||
EnterCriticalSection(&client->state.lock);
|
||||
list_for_each_tmp (entry, tmp, &client->state.delegations) {
|
||||
list_remove(entry);
|
||||
nfs41_delegation_deref(deleg_entry(entry));
|
||||
}
|
||||
LeaveCriticalSection(&client->state.lock);
|
||||
}
|
||||
57
daemon/delegation.h
Normal file
57
daemon/delegation.h
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/* Copyright (c) 2010
|
||||
* The Regents of the University of Michigan
|
||||
* All Rights Reserved
|
||||
*
|
||||
* Permission is granted to use, copy and redistribute this software
|
||||
* for noncommercial education and research purposes, so long as no
|
||||
* fee is charged, and so long as the name of the University of Michigan
|
||||
* is not used in any advertising or publicity pertaining to the use
|
||||
* or distribution of this software without specific, written prior
|
||||
* authorization. Permission to modify or otherwise create derivative
|
||||
* works of this software is not granted.
|
||||
*
|
||||
* This software is provided as is, without representation or warranty
|
||||
* of any kind either express or implied, including without limitation
|
||||
* the implied warranties of merchantability, fitness for a particular
|
||||
* purpose, or noninfringement. The Regents of the University of
|
||||
* Michigan shall not be liable for any damages, including special,
|
||||
* indirect, incidental, or consequential damages, with respect to any
|
||||
* claim arising out of or in connection with the use of the software,
|
||||
* even if it has been or is hereafter advised of the possibility of
|
||||
* such damages.
|
||||
*/
|
||||
|
||||
#ifndef DELEGATION_H
|
||||
#define DELEGATION_H
|
||||
|
||||
#include "nfs41.h"
|
||||
|
||||
|
||||
/* reference counting and cleanup */
|
||||
void nfs41_delegation_ref(
|
||||
IN nfs41_delegation_state *state);
|
||||
|
||||
void nfs41_delegation_deref(
|
||||
IN nfs41_delegation_state *state);
|
||||
|
||||
void nfs41_client_delegation_free(
|
||||
IN nfs41_client *client);
|
||||
|
||||
|
||||
/* open delegation */
|
||||
int nfs41_delegation_granted(
|
||||
IN nfs41_session *session,
|
||||
IN nfs41_path_fh *file,
|
||||
IN open_delegation4 *delegation,
|
||||
OUT nfs41_delegation_state **deleg_out);
|
||||
|
||||
int nfs41_delegate_open(
|
||||
IN nfs41_client *client,
|
||||
IN nfs41_path_fh *file,
|
||||
IN uint32_t create,
|
||||
IN uint32_t access,
|
||||
IN uint32_t deny,
|
||||
OUT nfs41_delegation_state **deleg_out,
|
||||
OUT nfs41_file_info *info);
|
||||
|
||||
#endif /* DELEGATION_H */
|
||||
|
|
@ -80,6 +80,13 @@ typedef struct __nfs41_server {
|
|||
LONG ref_count;
|
||||
} nfs41_server;
|
||||
|
||||
typedef struct __nfs41_delegation_state {
|
||||
open_delegation4 state;
|
||||
nfs41_fh fh;
|
||||
struct list_entry client_entry; /* entry in nfs41_client.delegations */
|
||||
LONG ref_count;
|
||||
} nfs41_delegation_state;
|
||||
|
||||
typedef struct __nfs41_lock_state {
|
||||
struct list_entry open_entry; /* entry in nfs41_open_state.locks */
|
||||
uint64_t offset;
|
||||
|
|
@ -110,6 +117,10 @@ typedef struct __nfs41_open_state {
|
|||
uint32_t share_access;
|
||||
uint32_t share_deny;
|
||||
|
||||
struct {
|
||||
nfs41_delegation_state *state;
|
||||
} delegation;
|
||||
|
||||
struct { /* list of open lock state for recovery */
|
||||
stateid4 stateid;
|
||||
struct list_entry list;
|
||||
|
|
@ -137,6 +148,7 @@ typedef struct __nfs41_rpc_clnt {
|
|||
|
||||
struct client_state {
|
||||
struct list_entry opens; /* list of associated nfs41_open_state */
|
||||
struct list_entry delegations; /* list of associated delegations */
|
||||
CRITICAL_SECTION lock;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <winsock2.h> /* for hostent struct */
|
||||
|
||||
#include "tree.h"
|
||||
#include "delegation.h"
|
||||
#include "daemon_debug.h"
|
||||
#include "nfs41_ops.h"
|
||||
|
||||
|
|
@ -248,6 +249,7 @@ int nfs41_client_create(
|
|||
goto out_err_client;
|
||||
|
||||
list_init(&client->state.opens);
|
||||
list_init(&client->state.delegations);
|
||||
InitializeCriticalSection(&client->state.lock);
|
||||
|
||||
//initialize a lock used to protect access to client id and client id seq#
|
||||
|
|
@ -326,6 +328,7 @@ void nfs41_client_free(
|
|||
IN nfs41_client *client)
|
||||
{
|
||||
dprintf(2, "nfs41_client_free(%llu)\n", client->clnt_id);
|
||||
nfs41_client_delegation_free(client);
|
||||
if (client->session) nfs41_session_free(client->session);
|
||||
nfs41_destroy_clientid(client->rpc, client->clnt_id);
|
||||
if (client->server) nfs41_server_deref(client->server);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <strsafe.h>
|
||||
|
||||
#include "nfs41_ops.h"
|
||||
#include "delegation.h"
|
||||
#include "from_kernel.h"
|
||||
#include "daemon_debug.h"
|
||||
#include "upcall.h"
|
||||
|
|
@ -63,6 +64,7 @@ static int create_open_state(
|
|||
(const char*)state->owner.owner);
|
||||
state->ref_count = 1;
|
||||
list_init(&state->locks.list);
|
||||
list_init(&state->client_entry);
|
||||
|
||||
*state_out = state;
|
||||
status = NO_ERROR;
|
||||
|
|
@ -82,6 +84,8 @@ static void open_state_free(
|
|||
/* free associated lock state */
|
||||
list_for_each_tmp(entry, tmp, &state->locks.list)
|
||||
free(list_container(entry, nfs41_lock_state, open_entry));
|
||||
if (state->delegation.state)
|
||||
nfs41_delegation_deref(state->delegation.state);
|
||||
free(state);
|
||||
}
|
||||
|
||||
|
|
@ -119,7 +123,7 @@ void nfs41_open_stateid_arg(
|
|||
}
|
||||
|
||||
/* client list of associated open state */
|
||||
void client_state_add(
|
||||
static void client_state_add(
|
||||
IN nfs41_open_state *state)
|
||||
{
|
||||
nfs41_client *client = state->session->client;
|
||||
|
|
@ -129,7 +133,7 @@ void client_state_add(
|
|||
LeaveCriticalSection(&client->state.lock);
|
||||
}
|
||||
|
||||
void client_state_remove(
|
||||
static void client_state_remove(
|
||||
IN nfs41_open_state *state)
|
||||
{
|
||||
nfs41_client *client = state->session->client;
|
||||
|
|
@ -148,7 +152,9 @@ int nfs41_open(
|
|||
OUT OPTIONAL nfs41_file_info *info)
|
||||
{
|
||||
open_claim4 claim;
|
||||
stateid4 open_stateid;
|
||||
open_delegation4 delegation = { 0 };
|
||||
nfs41_delegation_state *deleg_state = NULL;
|
||||
int status;
|
||||
|
||||
claim.claim = CLAIM_NULL;
|
||||
|
|
@ -156,18 +162,45 @@ int nfs41_open(
|
|||
|
||||
status = nfs41_rpc_open(state->session, &state->parent, &state->file,
|
||||
&state->owner, &claim, state->share_access, state->share_deny,
|
||||
create, createhow, mode, TRUE, &state->stateid, &delegation, info);
|
||||
create, createhow, mode, TRUE, &open_stateid, &delegation, info);
|
||||
if (status)
|
||||
goto out;
|
||||
|
||||
if (delegation.type == OPEN_DELEGATE_READ ||
|
||||
delegation.type == OPEN_DELEGATE_WRITE)
|
||||
nfs41_delegreturn(state->session, &state->file, &delegation.stateid);
|
||||
/* allocate delegation state and register it with the client */
|
||||
nfs41_delegation_granted(state->session,
|
||||
&state->file, &delegation, &deleg_state);
|
||||
|
||||
AcquireSRWLockExclusive(&state->lock);
|
||||
/* update the stateid */
|
||||
memcpy(&state->stateid, &open_stateid, sizeof(open_stateid));
|
||||
state->do_close = 1;
|
||||
state->delegation.state = deleg_state;
|
||||
ReleaseSRWLockExclusive(&state->lock);
|
||||
out:
|
||||
return status;
|
||||
}
|
||||
|
||||
static int open_or_delegate(
|
||||
IN OUT nfs41_open_state *state,
|
||||
IN uint32_t create,
|
||||
IN uint32_t createhow,
|
||||
IN uint32_t mode,
|
||||
IN bool_t try_recovery,
|
||||
OUT nfs41_file_info *info)
|
||||
{
|
||||
int status;
|
||||
|
||||
/* check for existing delegation */
|
||||
status = nfs41_delegate_open(state->session->client, &state->file, create,
|
||||
state->share_access, state->share_deny, &state->delegation.state, info);
|
||||
|
||||
/* get an open stateid if we have no delegation stateid */
|
||||
if (status)
|
||||
status = nfs41_open(state, create, createhow, mode, try_recovery, info);
|
||||
|
||||
/* register the client's open state on success */
|
||||
client_state_add(state);
|
||||
state->do_close = 1;
|
||||
out:
|
||||
if (status == NFS4_OK)
|
||||
client_state_add(state);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
|
@ -509,8 +542,8 @@ static int handle_open(nfs41_upcall *upcall)
|
|||
args->std_info.Directory = 1;
|
||||
args->created = status == NFS4_OK ? TRUE : FALSE;
|
||||
} else {
|
||||
status = nfs41_open(state, create, createhowmode,
|
||||
args->mode, TRUE, &info);
|
||||
status = open_or_delegate(state, create,
|
||||
createhowmode, args->mode, TRUE, &info);
|
||||
if (status == NFS4_OK) {
|
||||
nfs_to_basic_info(&info, &args->basic_info);
|
||||
nfs_to_standard_info(&info, &args->std_info);
|
||||
|
|
@ -589,8 +622,6 @@ static void cancel_open(IN nfs41_upcall *upcall)
|
|||
dprintf(1, "cancel_open: nfs41_close() failed with %s\n",
|
||||
nfs_error_string(status));
|
||||
|
||||
/* remove from the client's list of state for recovery */
|
||||
client_state_remove(state);
|
||||
} else if (args->created) {
|
||||
const nfs41_component *name = &state->file.name;
|
||||
status = nfs41_remove(state->session, &state->parent, name);
|
||||
|
|
@ -599,6 +630,8 @@ static void cancel_open(IN nfs41_upcall *upcall)
|
|||
nfs_error_string(status));
|
||||
}
|
||||
|
||||
/* remove from the client's list of state for recovery */
|
||||
client_state_remove(state);
|
||||
nfs41_open_state_deref(state);
|
||||
out:
|
||||
status = nfs_to_windows_error(status, ERROR_INTERNAL_ERROR);
|
||||
|
|
@ -664,11 +697,11 @@ static int handle_close(nfs41_upcall *upcall)
|
|||
nfs_error_string(status));
|
||||
status = nfs_to_windows_error(status, ERROR_INTERNAL_ERROR);
|
||||
}
|
||||
|
||||
/* remove from the client's list of state for recovery */
|
||||
client_state_remove(state);
|
||||
}
|
||||
|
||||
/* remove from the client's list of state for recovery */
|
||||
client_state_remove(state);
|
||||
|
||||
if (status || !rm_status)
|
||||
return status;
|
||||
else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue