From 83d17fcb69a270ce1ca4543c8febd7d0e0aa6c56 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Fri, 8 Jul 2011 10:05:23 -0400 Subject: [PATCH] deleg: use SETATTR for OPEN4_CREATE prevent an OPEN with OPEN4_CREATE from breaking a write delegation by sending a SETATTR instead moved static function remove_unsupported_attrs() from setattr.c to nfs41_superblock_supported_attrs() in nfs41_superblock.c, now used by both setattr.c and delegation.c Signed-off-by: Casey Bodley --- daemon/delegation.c | 47 +++++++++++++++++++++++++++++++++++---- daemon/delegation.h | 1 + daemon/nfs41.h | 4 ++++ daemon/nfs41_superblock.c | 16 +++++++++++++ daemon/open.c | 5 +++-- daemon/setattr.c | 26 ++-------------------- 6 files changed, 69 insertions(+), 30 deletions(-) diff --git a/daemon/delegation.c b/daemon/delegation.c index 1386170..022698d 100644 --- a/daemon/delegation.c +++ b/daemon/delegation.c @@ -215,10 +215,6 @@ static bool_t delegation_compatible( 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, @@ -229,6 +225,8 @@ static bool_t delegation_compatible( /* 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 (create == OPEN4_CREATE) + return FALSE; if (access & OPEN4_SHARE_ACCESS_WRITE || deny & OPEN4_SHARE_DENY_READ) return FALSE; return TRUE; @@ -258,16 +256,45 @@ static int delegation_find( return status; } +static int delegation_truncate( + IN nfs41_delegation_state *deleg, + IN nfs41_client *client, + IN stateid_arg *stateid, + IN uint32_t mode, + IN nfs41_file_info *info) +{ + nfs41_superblock *superblock = deleg->file.fh.superblock; + + /* use SETATTR to truncate the file */ + info->attrmask.arr[0] = FATTR4_WORD0_SIZE; + info->attrmask.arr[1] = FATTR4_WORD1_MODE | + FATTR4_WORD1_TIME_CREATE | FATTR4_WORD1_TIME_MODIFY_SET; + info->attrmask.count = 2; + + info->size = 0; + info->mode = mode; + get_nfs_time(&info->time_create); + get_nfs_time(&info->time_modify); + info->time_delta = &superblock->time_delta; + + /* mask out unsupported attributes */ + nfs41_superblock_supported_attrs(superblock, &info->attrmask); + + return nfs41_setattr(client->session, &deleg->file, stateid, info); +} + int nfs41_delegate_open( IN nfs41_client *client, IN nfs41_path_fh *file, IN uint32_t create, + IN uint32_t mode, IN uint32_t access, IN uint32_t deny, OUT nfs41_delegation_state **deleg_out, OUT nfs41_file_info *info) { nfs41_delegation_state *deleg; + stateid_arg stateid; int status; /* search for a delegation with this filehandle */ @@ -290,6 +317,11 @@ int nfs41_delegate_open( #else status = NFS4ERR_BADHANDLE; #endif + } else if (create == OPEN4_CREATE) { + /* copy the stateid for SETATTR */ + stateid.open = NULL; + stateid.type = STATEID_DELEG_FILE; + memcpy(&stateid.stateid, &deleg->state.stateid, sizeof(stateid4)); } ReleaseSRWLockExclusive(&deleg->lock); @@ -298,6 +330,13 @@ int nfs41_delegate_open( if (status) goto out_deleg; + if (create == OPEN4_CREATE) { + /* write delegations allow us to simulate OPEN4_CREATE with SETATTR */ + status = delegation_truncate(deleg, client, &stateid, mode, info); + if (status) + goto out_deleg; + } + /* TODO: check access against deleg->state.permissions or send ACCESS */ *deleg_out = deleg; diff --git a/daemon/delegation.h b/daemon/delegation.h index bb7dab9..0f4ca9f 100644 --- a/daemon/delegation.h +++ b/daemon/delegation.h @@ -53,6 +53,7 @@ int nfs41_delegate_open( IN nfs41_client *client, IN nfs41_path_fh *file, IN uint32_t create, + IN uint32_t mode, IN uint32_t access, IN uint32_t deny, OUT nfs41_delegation_state **deleg_out, diff --git a/daemon/nfs41.h b/daemon/nfs41.h index 545828c..ef24343 100644 --- a/daemon/nfs41.h +++ b/daemon/nfs41.h @@ -412,6 +412,10 @@ int nfs41_superblock_for_fh( IN const nfs41_fh *parent OPTIONAL, OUT nfs41_path_fh *file); +void nfs41_superblock_supported_attrs( + IN nfs41_superblock *superblock, + IN OUT bitmap4 *attrs); + void nfs41_superblock_space_changed( IN nfs41_superblock *superblock); diff --git a/daemon/nfs41_superblock.c b/daemon/nfs41_superblock.c index d09c361..d37d37c 100644 --- a/daemon/nfs41_superblock.c +++ b/daemon/nfs41_superblock.c @@ -247,6 +247,22 @@ out: return status; } +void nfs41_superblock_supported_attrs( + IN nfs41_superblock *superblock, + IN OUT bitmap4 *attrs) +{ + uint32_t i, count = 0; + + AcquireSRWLockShared(&superblock->lock); + for (i = 0; i < 3; i++) { + attrs->arr[i] &= superblock->supported_attrs.arr[i]; + if (attrs->arr[i]) + count = i+1; + } + attrs->count = min(attrs->count, count); + ReleaseSRWLockShared(&superblock->lock); +} + void nfs41_superblock_space_changed( IN nfs41_superblock *superblock) { diff --git a/daemon/open.c b/daemon/open.c index ed7e29a..21a88c9 100644 --- a/daemon/open.c +++ b/daemon/open.c @@ -233,8 +233,9 @@ static int open_or_delegate( 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); + status = nfs41_delegate_open(state->session->client, &state->file, + create, mode, state->share_access, state->share_deny, + &state->delegation.state, info); /* get an open stateid if we have no delegation stateid */ if (status) diff --git a/daemon/setattr.c b/daemon/setattr.c index 0fdafd3..537bbaf 100644 --- a/daemon/setattr.c +++ b/daemon/setattr.c @@ -65,26 +65,6 @@ out_free: goto out; } -static void remove_unsupported_attrs( - IN const bitmap4 *supported_attrs, - IN OUT bitmap4 *attrs) -{ - uint32_t i, count = 0; - dprintf(3, "remove_unsupported_attrs\n"); - for (i = 0; i < 3; i++) { - dprintf(3, "\tmask[%d] = %12u", i, attrs->arr[i]); - dprintf(3, " & %12u", supported_attrs->arr[i]); - - attrs->arr[i] &= supported_attrs->arr[i]; - if (attrs->arr[i]) - count = i+1; - - dprintf(3, " = %12d\n", attrs->arr[i]); - } - attrs->count = min(attrs->count, count); - dprintf(3, "\tcount = %d\n", attrs->count); -} - static int handle_nfs41_setattr(setattr_upcall_args *args) { PFILE_BASIC_INFO basic_info = (PFILE_BASIC_INFO)args->buf; @@ -136,10 +116,8 @@ static int handle_nfs41_setattr(setattr_upcall_args *args) info.attrmask.count = 2; } - /* only ask for attributes that are supported by the filesystem */ - AcquireSRWLockShared(&superblock->lock); - remove_unsupported_attrs(&superblock->supported_attrs, &info.attrmask); - ReleaseSRWLockShared(&superblock->lock); + /* mask out unsupported attributes */ + nfs41_superblock_supported_attrs(superblock, &info.attrmask); if (!info.attrmask.count) goto out;