From f988c89bf4f8481fc05e8a688b849a47771bb352 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Fri, 4 Nov 2011 10:17:17 -0400 Subject: [PATCH] namecache: fix for numlinks on remove nfs41_name_cache_remove() needs to update the 'numlinks' attribute for other links, even if the file being removed is not found in the cache. to search for its attr cache entry, nfs41_name_cache_remove() now requires a fileid argument. nfs41_remove() only gets a pointer to the parent's filehandle, so it also needs the target fileid argument Signed-off-by: Casey Bodley --- daemon/name_cache.c | 16 +++++++++++++--- daemon/name_cache.h | 1 + daemon/nfs41_ops.c | 5 +++-- daemon/nfs41_ops.h | 3 ++- daemon/open.c | 6 ++++-- daemon/setattr.c | 7 ++++--- daemon/symlink.c | 3 ++- 7 files changed, 29 insertions(+), 12 deletions(-) diff --git a/daemon/name_cache.c b/daemon/name_cache.c index d437bea..4e1763c 100644 --- a/daemon/name_cache.c +++ b/daemon/name_cache.c @@ -1041,9 +1041,11 @@ int nfs41_name_cache_remove( IN struct nfs41_name_cache *cache, IN const char *path, IN const nfs41_component *name, + IN uint64_t fileid, IN const change_info4 *cinfo) { struct name_cache_entry *parent, *target; + struct attr_cache_entry *attributes = NULL; int status; dprintf(NCLVL1, "--> nfs41_name_cache_remove('%s')\n", path); @@ -1058,15 +1060,15 @@ int nfs41_name_cache_remove( status = name_cache_lookup(cache, 0, path, name->name + name->len, NULL, &parent, &target, NULL); if (status == ERROR_PATH_NOT_FOUND) - goto out_unlock; + goto out_attributes; if (cinfo && name_cache_entry_changed(cache, parent, cinfo)) { name_cache_entry_invalidate(cache, parent); - goto out_unlock; + goto out_attributes; } if (status == ERROR_FILE_NOT_FOUND) - goto out_unlock; + goto out_attributes; if (target->attributes) target->attributes->numlinks--; @@ -1080,6 +1082,14 @@ out_unlock: dprintf(NCLVL1, "<-- nfs41_name_cache_remove() returning %d\n", status); return status; + +out_attributes: + /* in the presence of other links, we need to update numlinks + * regardless of a failure to find the target entry */ + attributes = attr_cache_search(&cache->attributes, fileid); + if (attributes) + attributes->numlinks--; + goto out_unlock; } int nfs41_name_cache_rename( diff --git a/daemon/name_cache.h b/daemon/name_cache.h index 61344d2..358eb2b 100644 --- a/daemon/name_cache.h +++ b/daemon/name_cache.h @@ -91,6 +91,7 @@ int nfs41_name_cache_remove( IN struct nfs41_name_cache *cache, IN const char *path, IN const nfs41_component *name, + IN uint64_t fileid, IN const change_info4 *cinfo); int nfs41_name_cache_rename( diff --git a/daemon/nfs41_ops.c b/daemon/nfs41_ops.c index 455d4ef..65337c0 100644 --- a/daemon/nfs41_ops.c +++ b/daemon/nfs41_ops.c @@ -1140,7 +1140,8 @@ out: int nfs41_remove( IN nfs41_session *session, IN nfs41_path_fh *parent, - IN const nfs41_component *target) + IN const nfs41_component *target, + IN uint64_t fileid) { int status; nfs41_compound compound; @@ -1194,7 +1195,7 @@ int nfs41_remove( /* remove the target file from the cache */ AcquireSRWLockShared(&parent->path->lock); nfs41_name_cache_remove(session_name_cache(session), - parent->path->path, target, &remove_res.cinfo); + parent->path->path, target, fileid, &remove_res.cinfo); ReleaseSRWLockShared(&parent->path->lock); nfs41_superblock_space_changed(parent->fh.superblock); diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h index 4479900..89e56b3 100644 --- a/daemon/nfs41_ops.h +++ b/daemon/nfs41_ops.h @@ -1147,7 +1147,8 @@ int nfs41_cached_getattr( int nfs41_remove( IN nfs41_session *session, IN nfs41_path_fh *parent, - IN const nfs41_component *target); + IN const nfs41_component *target, + IN uint64_t fileid); int nfs41_rename( IN nfs41_session *session, diff --git a/daemon/open.c b/daemon/open.c index 8f30df8..8eb24cd 100644 --- a/daemon/open.c +++ b/daemon/open.c @@ -676,7 +676,8 @@ static void cancel_open(IN nfs41_upcall *upcall) /* break any delegations and truncate before REMOVE */ nfs41_delegation_return(state->session, &state->file, OPEN_DELEGATE_WRITE, TRUE); - status = nfs41_remove(state->session, &state->parent, name); + status = nfs41_remove(state->session, &state->parent, + name, state->file.fh.fileid); if (status) dprintf(1, "cancel_open: nfs41_remove() failed with %s\n", nfs_error_string(status)); @@ -735,7 +736,8 @@ static int handle_close(nfs41_upcall *upcall) OPEN_DELEGATE_WRITE, TRUE); dprintf(1, "calling nfs41_remove for %s\n", name->name); - rm_status = nfs41_remove(state->session, &state->parent, name); + rm_status = nfs41_remove(state->session, &state->parent, + name, state->file.fh.fileid); if (rm_status) { dprintf(1, "nfs41_remove() failed with error %s.\n", nfs_error_string(rm_status)); diff --git a/daemon/setattr.c b/daemon/setattr.c index 9252e7d..26d62ce 100644 --- a/daemon/setattr.c +++ b/daemon/setattr.c @@ -141,7 +141,7 @@ static int handle_nfs41_remove(setattr_upcall_args *args) OPEN_DELEGATE_WRITE, TRUE); status = nfs41_remove(state->session, &state->parent, - &state->file.name); + &state->file.name, state->file.fh.fileid); if (status) dprintf(1, "nfs41_remove() failed with error %s.\n", nfs_error_string(status)); @@ -401,7 +401,7 @@ static int handle_nfs41_link(setattr_upcall_args *args) /* redo the lookup until it doesn't return REPARSE */ status = nfs41_lookup(args->root, dst_session, - &dst_path, &dst_dir, NULL, NULL, &dst_session); + &dst_path, &dst_dir, &dst, NULL, &dst_session); } /* get the components after lookup in case a referral changed its path */ @@ -434,7 +434,8 @@ static int handle_nfs41_link(setattr_upcall_args *args) /* LINK will return NFS4ERR_EXIST if the target file exists, * so we have to remove it ourselves */ - status = nfs41_remove(state->session, &dst_dir, &dst_name); + status = nfs41_remove(state->session, + &dst_dir, &dst_name, dst.fh.fileid); if (status) { dprintf(1, "nfs41_remove() failed with error %s.\n", nfs_error_string(status)); diff --git a/daemon/symlink.c b/daemon/symlink.c index f1a8651..47b0b37 100644 --- a/daemon/symlink.c +++ b/daemon/symlink.c @@ -240,7 +240,8 @@ static int handle_symlink(nfs41_upcall *upcall) eprintf("handle_symlink: attempting to create a symlink when " "the file=%s was already created on open; sending REMOVE " "first\n", state->file.path->path); - nfs41_remove(state->session, &state->parent, &state->file.name); + nfs41_remove(state->session, &state->parent, + &state->file.name, state->file.fh.fileid); } /* create the symlink */