From c72007f07643ca52b466b71eaad8335471d0d643 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Mon, 11 Oct 2010 16:08:54 -0400 Subject: [PATCH] name cache: LINK inserts target to name cache the link part of basic test7 was failing because LINK's target was still cached as a negative entry, leading to the error "can't stat newfile.0 after link". the solution is to replace the negative entry with the real fh and attributes of the target file so instead of doing RESTOREFH+GETATTR on the source file and calling nfs41_attr_cache_update(), nfs41_link() uses LOOKUP+GETATTR+GETFH to get attributes for the target file and passes them to nfs41_name_cache_insert() along with dst_dir's changeinfo. because the source and target file will have the same fileid attribute, nfs41_name_cache_insert() will update the attributes of both at the same time. added the target file as an optional return parameter Signed-off-by: Casey Bodley --- daemon/nfs41_ops.c | 83 ++++++++++++++++++++++++++++++---------------- daemon/nfs41_ops.h | 3 +- daemon/setattr.c | 3 +- 3 files changed, 59 insertions(+), 30 deletions(-) diff --git a/daemon/nfs41_ops.c b/daemon/nfs41_ops.c index 4815859..9a6a83a 100644 --- a/daemon/nfs41_ops.c +++ b/daemon/nfs41_ops.c @@ -1241,12 +1241,13 @@ int nfs41_link( IN nfs41_session *session, IN nfs41_path_fh *src, IN nfs41_path_fh *dst_dir, - IN const nfs41_component *target) + IN const nfs41_component *target, + OUT OPTIONAL nfs41_path_fh *link_out) { int status; nfs41_compound compound; - nfs_argop4 argops[8]; - nfs_resop4 resops[8]; + nfs_argop4 argops[9]; + nfs_resop4 resops[9]; nfs41_sequence_args sequence_args; nfs41_sequence_res sequence_res; nfs41_putfh_args putfh_args[2]; @@ -1254,16 +1255,22 @@ int nfs41_link( nfs41_savefh_res savefh_res; nfs41_link_args link_args; nfs41_link_res link_res; - nfs41_restorefh_res restorefh_res; - nfs41_getattr_args getattr_args, pgetattr_args; - nfs41_getattr_res getattr_res, pgetattr_res; - nfs41_file_info info, dir_info; - bitmap4 dir_attr_request; + nfs41_lookup_args lookup_args; + nfs41_lookup_res lookup_res; + nfs41_getfh_res getfh_res; + nfs41_getattr_args getattr_args[2]; + nfs41_getattr_res getattr_res[2]; + nfs41_file_info info[2]; + nfs41_path_fh file; + + if (link_out == NULL) + link_out = &file; ZeroMemory(&info, sizeof(info)); - info.attrmask.count = 2; - info.attrmask.arr[1] = FATTR4_WORD1_NUMLINKS; - init_getattr_request(&dir_attr_request); + init_getattr_request(&info[0].attrmask); + info[0].attrmask.arr[0] |= FATTR4_WORD0_FILEID; + init_getattr_request(&info[1].attrmask); + info[1].attrmask.arr[0] |= FATTR4_WORD0_FILEID; compound_init(&compound, argops, resops); @@ -1272,12 +1279,14 @@ int nfs41_link( if (status) goto out; + /* PUTFH(src) */ compound_add_op(&compound, OP_PUTFH, &putfh_args[0], &putfh_res[0]); putfh_args[0].file = src; putfh_args[0].in_recovery = 0; compound_add_op(&compound, OP_SAVEFH, NULL, &savefh_res); + /* PUTFH(dst_dir) */ compound_add_op(&compound, OP_PUTFH, &putfh_args[1], &putfh_res[1]); putfh_args[1].file = dst_dir; putfh_args[1].in_recovery = 0; @@ -1285,17 +1294,25 @@ int nfs41_link( compound_add_op(&compound, OP_LINK, &link_args, &link_res); link_args.newname = target; - compound_add_op(&compound, OP_GETATTR, &pgetattr_args, &pgetattr_res); - pgetattr_args.attr_request = &dir_attr_request; - pgetattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; - pgetattr_res.info = &dir_info; + /* GETATTR(dst_dir) */ + compound_add_op(&compound, OP_GETATTR, &getattr_args[0], &getattr_res[0]); + getattr_args[0].attr_request = &info[0].attrmask; + getattr_res[0].obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res[0].info = &info[0]; - compound_add_op(&compound, OP_RESTOREFH, NULL, &restorefh_res); + /* LOOKUP(target) */ + compound_add_op(&compound, OP_LOOKUP, &lookup_args, &lookup_res); + lookup_args.name = target; - compound_add_op(&compound, OP_GETATTR, &getattr_args, &getattr_res); - getattr_args.attr_request = &info.attrmask; - getattr_res.obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; - getattr_res.info = &info; + /* GETATTR(target) */ + compound_add_op(&compound, OP_GETATTR, &getattr_args[1], &getattr_res[1]); + getattr_args[1].attr_request = &info[1].attrmask; + getattr_res[1].obj_attributes.attr_vals_len = NFS4_OPAQUE_LIMIT; + getattr_res[1].info = &info[1]; + + /* GETFH(target) */ + compound_add_op(&compound, OP_GETFH, NULL, &getfh_res); + getfh_res.fh = &link_out->fh; status = compound_encode_send_decode(session, &compound, 0, 0); if (status) @@ -1304,17 +1321,27 @@ int nfs41_link( if (compound_error(status = compound.res.status)) goto out; - /* update the attributes of the destination directory */ - memcpy(&dir_info.attrmask, &pgetattr_res.obj_attributes.attrmask, - sizeof(bitmap4)); - nfs41_attr_cache_update(session_name_cache(session), - dst_dir->fh.fileid, &dir_info); + /* fill in the file handle's fileid and superblock */ + link_out->fh.fileid = info[1].fileid; + status = nfs41_superblock_for_fh(session, + &info[1].fsid, &dst_dir->fh, link_out); + if (status) + goto out; - /* update the attributes of the source file */ - memcpy(&info.attrmask, &getattr_res.obj_attributes.attrmask, + /* update the attributes of the destination directory */ + memcpy(&info[0].attrmask, &getattr_res[0].obj_attributes.attrmask, sizeof(bitmap4)); nfs41_attr_cache_update(session_name_cache(session), - src->fh.fileid, &info); + info[0].fileid, &info[0]); + + /* add the new file handle and attributes to the name cache */ + memcpy(&info[1].attrmask, &getattr_res[1].obj_attributes.attrmask, + sizeof(bitmap4)); + AcquireSRWLockShared(&dst_dir->path->lock); + nfs41_name_cache_insert(session_name_cache(session), + dst_dir->path->path, target, &link_out->fh, + &info[1], &link_res.cinfo); + ReleaseSRWLockShared(&dst_dir->path->lock); out: return status; } diff --git a/daemon/nfs41_ops.h b/daemon/nfs41_ops.h index 280d764..ca50b57 100644 --- a/daemon/nfs41_ops.h +++ b/daemon/nfs41_ops.h @@ -1017,7 +1017,8 @@ int nfs41_link( IN nfs41_session *session, IN nfs41_path_fh *src, IN nfs41_path_fh *dst_dir, - IN const nfs41_component *target); + IN const nfs41_component *target, + OUT OPTIONAL nfs41_path_fh *link_out); int nfs41_readlink( IN nfs41_session *session, diff --git a/daemon/setattr.c b/daemon/setattr.c index ad10a45..b065448 100644 --- a/daemon/setattr.c +++ b/daemon/setattr.c @@ -367,7 +367,8 @@ int handle_nfs41_link(setattr_upcall_args *args) } } - status = nfs41_link(state->session, &state->file, &dst_dir, &dst_name); + status = nfs41_link(state->session, &state->file, + &dst_dir, &dst_name, NULL); if (status) { dprintf(1, "nfs41_link() failed with error %s.\n", nfs_error_string(status));