X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0a7de7458d150b5d4dffc935ba399be265ef0a1a..eb6b6ca394357805f2bdba989abae309f718b4d8:/bsd/nfs/nfs_vnops.c diff --git a/bsd/nfs/nfs_vnops.c b/bsd/nfs/nfs_vnops.c index 0991a5373..4f9208b25 100644 --- a/bsd/nfs/nfs_vnops.c +++ b/bsd/nfs/nfs_vnops.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2017 Apple Inc. All rights reserved. + * Copyright (c) 2000-2019 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -65,6 +65,8 @@ * FreeBSD-Id: nfs_vnops.c,v 1.72 1997/11/07 09:20:48 phk Exp $ */ +#include +#if CONFIG_NFS_CLIENT /* * vnode op calls for Sun NFS version 2 and 3 @@ -87,6 +89,7 @@ #include #include #include +#include #include @@ -157,53 +160,56 @@ int nfs3_vnop_mkdir(struct vnop_mkdir_args *); int nfs3_vnop_rmdir(struct vnop_rmdir_args *); int nfs3_vnop_symlink(struct vnop_symlink_args *); + vnop_t **nfsv2_vnodeop_p; -static struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { - { &vnop_default_desc, (vnop_t *)vn_default_error }, - { &vnop_lookup_desc, (vnop_t *)nfs_vnop_lookup }, /* lookup */ - { &vnop_create_desc, (vnop_t *)nfs3_vnop_create }, /* create */ - { &vnop_mknod_desc, (vnop_t *)nfs3_vnop_mknod }, /* mknod */ - { &vnop_open_desc, (vnop_t *)nfs_vnop_open }, /* open */ - { &vnop_close_desc, (vnop_t *)nfs_vnop_close }, /* close */ - { &vnop_access_desc, (vnop_t *)nfs_vnop_access }, /* access */ - { &vnop_getattr_desc, (vnop_t *)nfs3_vnop_getattr }, /* getattr */ - { &vnop_setattr_desc, (vnop_t *)nfs_vnop_setattr }, /* setattr */ - { &vnop_read_desc, (vnop_t *)nfs_vnop_read }, /* read */ - { &vnop_write_desc, (vnop_t *)nfs_vnop_write }, /* write */ - { &vnop_ioctl_desc, (vnop_t *)nfs_vnop_ioctl }, /* ioctl */ - { &vnop_select_desc, (vnop_t *)nfs_vnop_select }, /* select */ - { &vnop_revoke_desc, (vnop_t *)nfs_vnop_revoke }, /* revoke */ - { &vnop_mmap_desc, (vnop_t *)nfs_vnop_mmap }, /* mmap */ - { &vnop_mnomap_desc, (vnop_t *)nfs_vnop_mnomap }, /* mnomap */ - { &vnop_fsync_desc, (vnop_t *)nfs_vnop_fsync }, /* fsync */ - { &vnop_remove_desc, (vnop_t *)nfs_vnop_remove }, /* remove */ - { &vnop_link_desc, (vnop_t *)nfs3_vnop_link }, /* link */ - { &vnop_rename_desc, (vnop_t *)nfs_vnop_rename }, /* rename */ - { &vnop_mkdir_desc, (vnop_t *)nfs3_vnop_mkdir }, /* mkdir */ - { &vnop_rmdir_desc, (vnop_t *)nfs3_vnop_rmdir }, /* rmdir */ - { &vnop_symlink_desc, (vnop_t *)nfs3_vnop_symlink }, /* symlink */ - { &vnop_readdir_desc, (vnop_t *)nfs_vnop_readdir }, /* readdir */ - { &vnop_readlink_desc, (vnop_t *)nfs_vnop_readlink }, /* readlink */ - { &vnop_inactive_desc, (vnop_t *)nfs_vnop_inactive }, /* inactive */ - { &vnop_reclaim_desc, (vnop_t *)nfs_vnop_reclaim }, /* reclaim */ - { &vnop_strategy_desc, (vnop_t *)err_strategy }, /* strategy */ - { &vnop_pathconf_desc, (vnop_t *)nfs_vnop_pathconf }, /* pathconf */ - { &vnop_advlock_desc, (vnop_t *)nfs_vnop_advlock }, /* advlock */ - { &vnop_bwrite_desc, (vnop_t *)err_bwrite }, /* bwrite */ - { &vnop_pagein_desc, (vnop_t *)nfs_vnop_pagein }, /* Pagein */ - { &vnop_pageout_desc, (vnop_t *)nfs_vnop_pageout }, /* Pageout */ - { &vnop_copyfile_desc, (vnop_t *)err_copyfile }, /* Copyfile */ - { &vnop_blktooff_desc, (vnop_t *)nfs_vnop_blktooff }, /* blktooff */ - { &vnop_offtoblk_desc, (vnop_t *)nfs_vnop_offtoblk }, /* offtoblk */ - { &vnop_blockmap_desc, (vnop_t *)nfs_vnop_blockmap }, /* blockmap */ - { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */ - { NULL, NULL } +static const struct vnodeopv_entry_desc nfsv2_vnodeop_entries[] = { + { .opve_op = &vnop_default_desc, .opve_impl = (vnop_t *)vn_default_error }, + { .opve_op = &vnop_lookup_desc, .opve_impl = (vnop_t *)nfs_vnop_lookup }, /* lookup */ + { .opve_op = &vnop_create_desc, .opve_impl = (vnop_t *)nfs3_vnop_create }, /* create */ + { .opve_op = &vnop_mknod_desc, .opve_impl = (vnop_t *)nfs3_vnop_mknod }, /* mknod */ + { .opve_op = &vnop_open_desc, .opve_impl = (vnop_t *)nfs_vnop_open }, /* open */ + { .opve_op = &vnop_close_desc, .opve_impl = (vnop_t *)nfs_vnop_close }, /* close */ + { .opve_op = &vnop_access_desc, .opve_impl = (vnop_t *)nfs_vnop_access }, /* access */ + { .opve_op = &vnop_getattr_desc, .opve_impl = (vnop_t *)nfs3_vnop_getattr }, /* getattr */ + { .opve_op = &vnop_setattr_desc, .opve_impl = (vnop_t *)nfs_vnop_setattr }, /* setattr */ + { .opve_op = &vnop_read_desc, .opve_impl = (vnop_t *)nfs_vnop_read }, /* read */ + { .opve_op = &vnop_write_desc, .opve_impl = (vnop_t *)nfs_vnop_write }, /* write */ + { .opve_op = &vnop_ioctl_desc, .opve_impl = (vnop_t *)nfs_vnop_ioctl }, /* ioctl */ + { .opve_op = &vnop_select_desc, .opve_impl = (vnop_t *)nfs_vnop_select }, /* select */ + { .opve_op = &vnop_revoke_desc, .opve_impl = (vnop_t *)nfs_vnop_revoke }, /* revoke */ + { .opve_op = &vnop_mmap_desc, .opve_impl = (vnop_t *)nfs_vnop_mmap }, /* mmap */ + { .opve_op = &vnop_mnomap_desc, .opve_impl = (vnop_t *)nfs_vnop_mnomap }, /* mnomap */ + { .opve_op = &vnop_fsync_desc, .opve_impl = (vnop_t *)nfs_vnop_fsync }, /* fsync */ + { .opve_op = &vnop_remove_desc, .opve_impl = (vnop_t *)nfs_vnop_remove }, /* remove */ + { .opve_op = &vnop_link_desc, .opve_impl = (vnop_t *)nfs3_vnop_link }, /* link */ + { .opve_op = &vnop_rename_desc, .opve_impl = (vnop_t *)nfs_vnop_rename }, /* rename */ + { .opve_op = &vnop_mkdir_desc, .opve_impl = (vnop_t *)nfs3_vnop_mkdir }, /* mkdir */ + { .opve_op = &vnop_rmdir_desc, .opve_impl = (vnop_t *)nfs3_vnop_rmdir }, /* rmdir */ + { .opve_op = &vnop_symlink_desc, .opve_impl = (vnop_t *)nfs3_vnop_symlink }, /* symlink */ + { .opve_op = &vnop_readdir_desc, .opve_impl = (vnop_t *)nfs_vnop_readdir }, /* readdir */ + { .opve_op = &vnop_readlink_desc, .opve_impl = (vnop_t *)nfs_vnop_readlink }, /* readlink */ + { .opve_op = &vnop_inactive_desc, .opve_impl = (vnop_t *)nfs_vnop_inactive }, /* inactive */ + { .opve_op = &vnop_reclaim_desc, .opve_impl = (vnop_t *)nfs_vnop_reclaim }, /* reclaim */ + { .opve_op = &vnop_strategy_desc, .opve_impl = (vnop_t *)err_strategy }, /* strategy */ + { .opve_op = &vnop_pathconf_desc, .opve_impl = (vnop_t *)nfs_vnop_pathconf }, /* pathconf */ + { .opve_op = &vnop_advlock_desc, .opve_impl = (vnop_t *)nfs_vnop_advlock }, /* advlock */ + { .opve_op = &vnop_bwrite_desc, .opve_impl = (vnop_t *)err_bwrite }, /* bwrite */ + { .opve_op = &vnop_pagein_desc, .opve_impl = (vnop_t *)nfs_vnop_pagein }, /* Pagein */ + { .opve_op = &vnop_pageout_desc, .opve_impl = (vnop_t *)nfs_vnop_pageout }, /* Pageout */ + { .opve_op = &vnop_copyfile_desc, .opve_impl = (vnop_t *)err_copyfile }, /* Copyfile */ + { .opve_op = &vnop_blktooff_desc, .opve_impl = (vnop_t *)nfs_vnop_blktooff }, /* blktooff */ + { .opve_op = &vnop_offtoblk_desc, .opve_impl = (vnop_t *)nfs_vnop_offtoblk }, /* offtoblk */ + { .opve_op = &vnop_blockmap_desc, .opve_impl = (vnop_t *)nfs_vnop_blockmap }, /* blockmap */ + { .opve_op = &vnop_monitor_desc, .opve_impl = (vnop_t *)nfs_vnop_monitor }, /* monitor */ + { .opve_op = NULL, .opve_impl = NULL } }; -struct vnodeopv_desc nfsv2_vnodeop_opv_desc = +const struct vnodeopv_desc nfsv2_vnodeop_opv_desc = { &nfsv2_vnodeop_p, nfsv2_vnodeop_entries }; + +#if CONFIG_NFS4 vnop_t **nfsv4_vnodeop_p; -static struct vnodeopv_entry_desc nfsv4_vnodeop_entries[] = { +static const struct vnodeopv_entry_desc nfsv4_vnodeop_entries[] = { { &vnop_default_desc, (vnop_t *)vn_default_error }, { &vnop_lookup_desc, (vnop_t *)nfs_vnop_lookup }, /* lookup */ { &vnop_create_desc, (vnop_t *)nfs4_vnop_create }, /* create */ @@ -253,14 +259,15 @@ static struct vnodeopv_entry_desc nfsv4_vnodeop_entries[] = { { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */ { NULL, NULL } }; -struct vnodeopv_desc nfsv4_vnodeop_opv_desc = +const struct vnodeopv_desc nfsv4_vnodeop_opv_desc = { &nfsv4_vnodeop_p, nfsv4_vnodeop_entries }; +#endif /* * Special device vnode ops */ vnop_t **spec_nfsv2nodeop_p; -static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { +static const struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { { &vnop_default_desc, (vnop_t *)vn_default_error }, { &vnop_lookup_desc, (vnop_t *)spec_lookup }, /* lookup */ { &vnop_create_desc, (vnop_t *)spec_create }, /* create */ @@ -298,10 +305,11 @@ static struct vnodeopv_entry_desc spec_nfsv2nodeop_entries[] = { { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */ { NULL, NULL } }; -struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = +const struct vnodeopv_desc spec_nfsv2nodeop_opv_desc = { &spec_nfsv2nodeop_p, spec_nfsv2nodeop_entries }; +#if CONFIG_NFS4 vnop_t **spec_nfsv4nodeop_p; -static struct vnodeopv_entry_desc spec_nfsv4nodeop_entries[] = { +static const struct vnodeopv_entry_desc spec_nfsv4nodeop_entries[] = { { &vnop_default_desc, (vnop_t *)vn_default_error }, { &vnop_lookup_desc, (vnop_t *)spec_lookup }, /* lookup */ { &vnop_create_desc, (vnop_t *)spec_create }, /* create */ @@ -348,12 +356,13 @@ static struct vnodeopv_entry_desc spec_nfsv4nodeop_entries[] = { { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */ { NULL, NULL } }; -struct vnodeopv_desc spec_nfsv4nodeop_opv_desc = +const struct vnodeopv_desc spec_nfsv4nodeop_opv_desc = { &spec_nfsv4nodeop_p, spec_nfsv4nodeop_entries }; +#endif /* CONFIG_NFS4 */ #if FIFO vnop_t **fifo_nfsv2nodeop_p; -static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { +static const struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { { &vnop_default_desc, (vnop_t *)vn_default_error }, { &vnop_lookup_desc, (vnop_t *)fifo_lookup }, /* lookup */ { &vnop_create_desc, (vnop_t *)fifo_create }, /* create */ @@ -391,11 +400,14 @@ static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = { { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */ { NULL, NULL } }; -struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = +const struct vnodeopv_desc fifo_nfsv2nodeop_opv_desc = { &fifo_nfsv2nodeop_p, fifo_nfsv2nodeop_entries }; +#endif +#if CONFIG_NFS4 +#if FIFO vnop_t **fifo_nfsv4nodeop_p; -static struct vnodeopv_entry_desc fifo_nfsv4nodeop_entries[] = { +static const struct vnodeopv_entry_desc fifo_nfsv4nodeop_entries[] = { { &vnop_default_desc, (vnop_t *)vn_default_error }, { &vnop_lookup_desc, (vnop_t *)fifo_lookup }, /* lookup */ { &vnop_create_desc, (vnop_t *)fifo_create }, /* create */ @@ -442,14 +454,45 @@ static struct vnodeopv_entry_desc fifo_nfsv4nodeop_entries[] = { { &vnop_monitor_desc, (vnop_t *)nfs_vnop_monitor }, /* monitor */ { NULL, NULL } }; -struct vnodeopv_desc fifo_nfsv4nodeop_opv_desc = +const struct vnodeopv_desc fifo_nfsv4nodeop_opv_desc = { &fifo_nfsv4nodeop_p, fifo_nfsv4nodeop_entries }; #endif /* FIFO */ +#endif /* CONFIG_NFS4 */ int nfs_sillyrename(nfsnode_t, nfsnode_t, struct componentname *, vfs_context_t); int nfs_getattr_internal(nfsnode_t, struct nfs_vattr *, vfs_context_t, int); int nfs_refresh_fh(nfsnode_t, vfs_context_t); + +/* + * Update nfsnode attributes to avoid extra getattr calls for each direntry. + * This function should be called only if RDIRPLUS flag is enabled. + */ +void +nfs_rdirplus_update_node_attrs(nfsnode_t dnp, struct direntry *dp, fhandle_t *fhp, struct nfs_vattr *nvattrp, uint64_t *savedxidp) +{ + nfsnode_t np; + struct componentname cn; + int isdot = (dp->d_namlen == 1) && (dp->d_name[0] == '.'); + int isdotdot = (dp->d_namlen == 2) && (dp->d_name[0] == '.') && (dp->d_name[1] == '.'); + + if (isdot || isdotdot) { + return; + } + + np = NULL; + bzero(&cn, sizeof(cn)); + cn.cn_nameptr = dp->d_name; + cn.cn_namelen = dp->d_namlen; + cn.cn_nameiop = LOOKUP; + + nfs_nget(NFSTOMP(dnp), dnp, &cn, fhp->fh_data, fhp->fh_len, nvattrp, savedxidp, RPCAUTH_UNKNOWN, NG_NOCREATE, &np); + if (np) { + nfs_node_unlock(np); + vnode_put(NFSTOV(np)); + } +} + /* * Find the slot in the access cache for this UID. * If adding and no existing slot is found, reuse slots in FIFO order. @@ -514,11 +557,15 @@ nfs3_access_rpc(nfsnode_t np, u_int32_t *access, int rpcflags, vfs_context_t ctx } nfsmout_if(error); +#if CONFIG_NFS_GSS if (auth_is_kerberized(np->n_auth) || auth_is_kerberized(nmp->nm_auth)) { uid = nfs_cred_getasid2uid(vfs_context_ucred(ctx)); } else { uid = kauth_cred_getuid(vfs_context_ucred(ctx)); } +#else + uid = kauth_cred_getuid(vfs_context_ucred(ctx)); +#endif /* CONFIG_NFS_GSS */ slot = nfs_node_access_slot(np, uid, 1); np->n_accessuid[slot] = uid; microuptime(&now); @@ -551,6 +598,7 @@ nfsmout: return error; } + /* * NFS access vnode op. * For NFS version 2, just return ok. File accesses may fail later. @@ -582,7 +630,8 @@ nfs_vnop_access( } nfsvers = nmp->nm_vers; - if (nfsvers == NFS_VER2) { + + if (nfsvers == NFS_VER2 || NMFLAG(nmp, NOOPAQUE_AUTH)) { if ((ap->a_action & KAUTH_VNODE_WRITE_RIGHTS) && vfs_isrdonly(vnode_mount(vp))) { return EROFS; @@ -670,11 +719,15 @@ nfs_vnop_access( * Does our cached result allow us to give a definite yes to * this request? */ +#if CONFIG_NFS_GSS if (auth_is_kerberized(np->n_auth) || auth_is_kerberized(nmp->nm_auth)) { uid = nfs_cred_getasid2uid(vfs_context_ucred(ctx)); } else { uid = kauth_cred_getuid(vfs_context_ucred(ctx)); } +#else + uid = kauth_cred_getuid(vfs_context_ucred(ctx)); +#endif /* CONFIG_NFS_GSS */ slot = nfs_node_access_slot(np, uid, 0); dorpc = 1; if (access == 0) { @@ -851,6 +904,7 @@ restart: NP(np, "nfs_vnop_open: LOST %d", kauth_cred_getuid(nofp->nof_owner->noo_cred)); error = EIO; } +#if CONFIG_NFS4 if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) { nfs_mount_state_in_use_end(nmp, 0); error = nfs4_reopen(nofp, vfs_context_thread(ctx)); @@ -859,6 +913,7 @@ restart: goto restart; } } +#endif if (!error) { error = nfs_open_file_set_busy(nofp, vfs_context_thread(ctx)); } @@ -886,9 +941,11 @@ restart: nofp->nof_flags &= ~NFS_OPEN_FILE_CREATE; nofp->nof_creator = NULL; } else { +#if CONFIG_NFS4 if (!opened) { error = nfs4_open(np, nofp, accessMode, denyMode, ctx); } +#endif if ((error == EACCES) && (nofp->nof_flags & NFS_OPEN_FILE_CREATE) && (nofp->nof_creator == current_thread())) { /* @@ -1154,6 +1211,7 @@ restart: } error = nfs_open_file_find(np, noop, &nofp, 0, 0, 0); +#if CONFIG_NFS4 if (!error && (nofp->nof_flags & NFS_OPEN_FILE_REOPEN)) { nfs_mount_state_in_use_end(nmp, 0); error = nfs4_reopen(nofp, NULL); @@ -1162,6 +1220,7 @@ restart: goto restart; } } +#endif if (error) { NP(np, "nfs_vnop_close: no open file for owner, error %d, %d", error, kauth_cred_getuid(noop->noo_cred)); error = EBADF; @@ -1210,9 +1269,11 @@ nfs_close( struct nfs_open_file *nofp, uint32_t accessMode, uint32_t denyMode, - vfs_context_t ctx) + __unused vfs_context_t ctx) { +#if CONFIG_NFS4 struct nfs_lock_owner *nlop; +#endif int error = 0, changed = 0, delegated = 0, closed = 0, downgrade = 0; uint32_t newAccessMode, newDenyMode; @@ -1254,10 +1315,11 @@ nfs_close( changed = 0; } - if (NFSTONMP(np)->nm_vers < NFS_VER4) { /* NFS v2/v3 closes simply need to remove the open. */ + if (NFSTONMP(np)->nm_vers < NFS_VER4) { + /* NFS v2/v3 closes simply need to remove the open. */ goto v3close; } - +#if CONFIG_NFS4 if ((newAccessMode == 0) || (nofp->nof_opencnt == 1)) { /* * No more access after this close, so clean up and close it. @@ -1305,13 +1367,13 @@ nfs_close( } } } - +#endif +v3close: if (error) { NP(np, "nfs_close: error %d, %d", error, kauth_cred_getuid(nofp->nof_owner->noo_cred)); return error; } -v3close: if (!downgrade) { nfs_open_file_remove_open(nofp, accessMode, denyMode); } @@ -1402,7 +1464,7 @@ nfs3_getattr_rpc( error = status; } nfsmout_if(error); - error = nfs_parsefattr(&nmrep, nfsvers, nvap); + error = nfs_parsefattr(nmp, &nmrep, nfsvers, nvap); nfsmout: nfsm_chain_cleanup(&nmreq); nfsm_chain_cleanup(&nmrep); @@ -1426,7 +1488,7 @@ nfs_refresh_fh(nfsnode_t np, vfs_context_t ctx) int namelen, fhsize, refreshed; int error, wanted = 0; uint8_t *fhp; - struct timespec ts = {2, 0}; + struct timespec ts = {.tv_sec = 2, .tv_nsec = 0}; NFS_VNOP_DBG("vnode is %d\n", vnode_vtype(vp)); @@ -1574,7 +1636,7 @@ nfs_getattr_internal(nfsnode_t np, struct nfs_vattr *nvap, vfs_context_t ctx, in struct nfsmount *nmp; int error = 0, nfsvers, inprogset = 0, wanted = 0, avoidfloods; struct nfs_vattr nvattr; - struct timespec ts = { 2, 0 }; + struct timespec ts = { .tv_sec = 2, .tv_nsec = 0 }; u_int64_t xid; FSDBG_TOP(513, np->n_size, np, np->n_vattr.nva_size, np->n_flag); @@ -1796,6 +1858,7 @@ nfsmout: return error; } + /* * NFS getattr call from vfs. */ @@ -1821,6 +1884,7 @@ nfsmout: VNODE_ATTR_va_fileid | \ VNODE_ATTR_va_type) + int nfs3_vnop_getattr( struct vnop_getattr_args /* { @@ -1831,18 +1895,25 @@ nfs3_vnop_getattr( * } */*ap) { int error; + nfsnode_t np; + uint64_t supported_attrs; struct nfs_vattr nva; struct vnode_attr *vap = ap->a_vap; struct nfsmount *nmp; dev_t rdev; + nmp = VTONMP(ap->a_vp); + /* * Lets don't go over the wire if we don't support any of the attributes. * Just fall through at the VFS layer and let it cons up what it needs. */ /* Return the io size no matter what, since we don't go over the wire for this */ VATTR_RETURN(vap, va_iosize, nfs_iosize); - if ((vap->va_active & NFS3_SUPPORTED_VATTRS) == 0) { + + supported_attrs = NFS3_SUPPORTED_VATTRS; + + if ((vap->va_active & supported_attrs) == 0) { return 0; } @@ -1851,13 +1922,24 @@ nfs3_vnop_getattr( (uint64_t)VM_KERNEL_ADDRPERM(ap->a_vp), ap->a_vp->v_name ? ap->a_vp->v_name : "empty"); } + + /* + * We should not go over the wire if only fileid was requested and has ever been populated. + */ + if ((vap->va_active & supported_attrs) == VNODE_ATTR_va_fileid) { + np = VTONFS(ap->a_vp); + if (np->n_attrstamp) { + VATTR_RETURN(vap, va_fileid, np->n_vattr.nva_fileid); + return 0; + } + } + error = nfs_getattr(VTONFS(ap->a_vp), &nva, ap->a_context, NGA_CACHED); if (error) { return error; } /* copy nva to *a_vap */ - nmp = VTONMP(ap->a_vp); VATTR_RETURN(vap, va_type, nva.nva_type); VATTR_RETURN(vap, va_mode, nva.nva_mode); rdev = makedev(nva.nva_rawdev.specdata1, nva.nva_rawdev.specdata2); @@ -1878,6 +1960,7 @@ nfs3_vnop_getattr( vap->va_change_time.tv_nsec = nva.nva_timensec[NFSTIME_CHANGE]; VATTR_SET_SUPPORTED(vap, va_change_time); + // VATTR_RETURN(vap, va_encoding, 0xffff /* kTextEncodingUnknown */); return error; } @@ -1907,9 +1990,10 @@ nfs_vnop_setattr( int dul_in_progress = 0; vnode_t dvp = NULL; const char *vname = NULL; +#if CONFIG_NFS4 struct nfs_open_owner *noop = NULL; struct nfs_open_file *nofp = NULL; - +#endif nmp = VTONMP(vp); if (nfs_mount_gone(nmp)) { return ENXIO; @@ -1966,6 +2050,7 @@ nfs_vnop_setattr( FSDBG_BOT(512, np->n_size, vap->va_data_size, np->n_vattr.nva_size, -1); return error; } +#if CONFIG_NFS4 if (nfsvers >= NFS_VER4) { /* setting file size requires having the file open for write access */ if (np->n_flag & NREVOKE) { @@ -2018,6 +2103,7 @@ restart: } } } +#endif nfs_data_lock(np, NFS_DATA_LOCK_EXCLUSIVE); if (np->n_size > vap->va_data_size) { /* shrinking? */ daddr64_t obn, bn; @@ -2201,6 +2287,7 @@ restart: nfs_node_unlock(np); } nfs_data_unlock(np); +#if CONFIG_NFS4 if (nfsvers >= NFS_VER4) { if (nofp) { /* don't close our setattr open if we'll be restarting... */ @@ -2220,6 +2307,7 @@ restart: } nfs_open_owner_rele(noop); } +#endif } return error; } @@ -2250,7 +2338,9 @@ nfs3_setattr_rpc( VATTR_SET_SUPPORTED(vap, va_access_time); VATTR_SET_SUPPORTED(vap, va_modify_time); - if (VATTR_IS_ACTIVE(vap, va_flags)) { + + if (VATTR_IS_ACTIVE(vap, va_flags) + ) { if (vap->va_flags) { /* we don't support setting flags */ if (vap->va_active & ~VNODE_ATTR_va_flags) { return EINVAL; /* return EINVAL if other attributes also set */ @@ -2348,7 +2438,7 @@ nfs3_setattr_rpc( error = lockerror; } if (nfsvers == NFS_VER3) { - struct timespec premtime = { 0, 0 }; + struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 }; nfsm_chain_get_wcc_data(error, &nmrep, np, &premtime, &wccpostattr, &xid); nfsmout_if(error); /* if file hadn't changed, update cached mtime */ @@ -2503,11 +2593,13 @@ nfs_vnop_lookup( fh.fh_len = 0; goto found; } +#if CONFIG_NFS4 if ((nfsvers >= NFS_VER4) && (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER)) { /* we should never be looking things up in a trigger directory, return nothing */ error = ENOENT; goto error_return; } +#endif /* do we know this name is too long? */ nmp = VTONMP(dvp); @@ -2788,8 +2880,9 @@ nfs_read_rpc(nfsnode_t np, uio_t uio, vfs_context_t ctx) user_ssize_t tsiz; off_t txoffset; struct nfsreq rq, *req = &rq; +#if CONFIG_NFS4 uint32_t stategenid = 0, restart = 0; - +#endif FSDBG_TOP(536, np, uio_offset(uio), uio_resid(uio), 0); nmp = NFSTONMP(np); if (nfs_mount_gone(nmp)) { @@ -2812,14 +2905,17 @@ nfs_read_rpc(nfsnode_t np, uio_t uio, vfs_context_t ctx) error = EIO; break; } +#if CONFIG_NFS4 if (nmp->nm_vers >= NFS_VER4) { stategenid = nmp->nm_stategenid; } +#endif error = nmp->nm_funcs->nf_read_rpc_async(np, txoffset, len, vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, &req); if (!error) { error = nmp->nm_funcs->nf_read_rpc_async_finish(np, req, uio, &retlen, &eof); } +#if CONFIG_NFS4 if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error) && (++restart <= nfs_mount_state_max_restarts(nmp))) { /* guard against no progress */ lck_mtx_lock(&nmp->nm_lock); @@ -2839,6 +2935,7 @@ nfs_read_rpc(nfsnode_t np, uio_t uio, vfs_context_t ctx) } } } +#endif if (error) { break; } @@ -3557,6 +3654,8 @@ skipread: } nfs_buf_write_delayed(bp); } + + if (np->n_needcommitcnt >= NFS_A_LOT_OF_NEEDCOMMITS) { nfs_flushcommits(np, 1); } @@ -3565,6 +3664,9 @@ skipread: out: nfs_node_lock_force(np); np->n_wrbusy--; + if ((ioflag & IO_SYNC) && !np->n_wrbusy && !np->n_numoutput) { + np->n_flag &= ~NMODIFIED; + } nfs_node_unlock(np); nfs_data_unlock(np); FSDBG_BOT(515, np, uio_offset(uio), uio_resid(uio), error); @@ -3601,7 +3703,10 @@ nfs_write_rpc2( uint64_t wverf = 0, wverf2; size_t nmwsize, totalsize, tsiz, len, rlen; struct nfsreq rq, *req = &rq; - uint32_t stategenid = 0, vrestart = 0, restart = 0; +#if CONFIG_NFS4 + uint32_t stategenid = 0, restart = 0; +#endif + uint32_t vrestart = 0; uio_t uio_save = NULL; #if DIAGNOSTIC @@ -3639,9 +3744,11 @@ nfs_write_rpc2( error = EIO; break; } +#if CONFIG_NFS4 if (nmp->nm_vers >= NFS_VER4) { stategenid = nmp->nm_stategenid; } +#endif error = nmp->nm_funcs->nf_write_rpc_async(np, uio, len, thd, cred, *iomodep, NULL, &req); if (!error) { error = nmp->nm_funcs->nf_write_rpc_async_finish(np, req, &commit, &rlen, &wverf2); @@ -3650,6 +3757,7 @@ nfs_write_rpc2( if (nfs_mount_gone(nmp)) { error = ENXIO; } +#if CONFIG_NFS4 if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error) && (++restart <= nfs_mount_state_max_restarts(nmp))) { /* guard against no progress */ lck_mtx_lock(&nmp->nm_lock); @@ -3669,6 +3777,7 @@ nfs_write_rpc2( } } } +#endif if (error) { break; } @@ -3811,7 +3920,7 @@ nfs3_write_rpc_async_finish( error = lockerror; } if (nfsvers == NFS_VER3) { - struct timespec premtime = { 0, 0 }; + struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 }; nfsm_chain_get_wcc_data(error, &nmrep, np, &premtime, &wccpostattr, &xid); if (nfstimespeccmp(&np->n_mtime, &premtime, ==)) { updatemtime = 1; @@ -3891,7 +4000,7 @@ nfs3_vnop_mknod( struct nfs_vattr nvattr; fhandle_t fh; int error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0; - struct timespec premtime = { 0, 0 }; + struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 }; u_int32_t rdev; u_int64_t xid = 0, dxid; int nfsvers, gotuid, gotgid; @@ -3942,7 +4051,7 @@ nfs3_vnop_mknod( nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp); if (nfsvers == NFS_VER3) { nfsm_chain_add_32(error, &nmreq, vtonfs_type(vap->va_type, nfsvers)); - nfsm_chain_add_v3sattr(error, &nmreq, vap); + nfsm_chain_add_v3sattr(nmp, error, &nmreq, vap); if (vap->va_type == VCHR || vap->va_type == VBLK) { nfsm_chain_add_32(error, &nmreq, major(vap->va_rdev)); nfsm_chain_add_32(error, &nmreq, minor(vap->va_rdev)); @@ -3972,7 +4081,7 @@ nfs3_vnop_mknod( dnp->n_flag &= ~NNEGNCENTRIES; cache_purge_negatives(dvp); } - error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr); + error = nfsm_chain_get_fh_attr(nmp, &nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr); } if (nfsvers == NFS_VER3) { nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &dxid); @@ -4054,19 +4163,22 @@ nfs3_vnop_create( nfsnode_t dnp = VTONFS(dvp); vnode_t newvp = NULL; int error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0, fmode = 0; - struct timespec premtime = { 0, 0 }; + struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 }; int nfsvers, gotuid, gotgid; u_int64_t xid, dxid; uint32_t val; struct nfsm_chain nmreq, nmrep; struct nfsreq rq, *req = &rq; struct nfs_dulookup dul; + int dul_in_progress = 0; + int namedattrs; nmp = VTONMP(dvp); if (nfs_mount_gone(nmp)) { return ENXIO; } nfsvers = nmp->nm_vers; + namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR); if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN)) { return ENAMETOOLONG; @@ -4083,7 +4195,8 @@ nfs3_vnop_create( gotuid = VATTR_IS_ACTIVE(vap, va_uid); gotgid = VATTR_IS_ACTIVE(vap, va_gid); - if (vap->va_vaflags & VA_EXCLUSIVE) { + if ((vap->va_vaflags & VA_EXCLUSIVE) + ) { fmode |= O_EXCL; if (!VATTR_IS_ACTIVE(vap, va_access_time) || !VATTR_IS_ACTIVE(vap, va_modify_time)) { vap->va_vaflags |= VA_UTIMES_NULL; @@ -4092,7 +4205,9 @@ nfs3_vnop_create( again: error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx)); - nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx); + if (!namedattrs) { + nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx); + } nfsm_chain_null(&nmreq); nfsm_chain_null(&nmrep); @@ -4117,7 +4232,7 @@ again: nfsm_chain_add_32(error, &nmreq, create_verf); } else { nfsm_chain_add_32(error, &nmreq, NFS_CREATE_UNCHECKED); - nfsm_chain_add_v3sattr(error, &nmreq, vap); + nfsm_chain_add_v3sattr(nmp, error, &nmreq, vap); } } else { nfsm_chain_add_v2sattr(error, &nmreq, vap, 0); @@ -4128,7 +4243,10 @@ again: error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_CREATE, vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req); if (!error) { - nfs_dulookup_start(&dul, dnp, ctx); + if (!namedattrs) { + nfs_dulookup_start(&dul, dnp, ctx); + dul_in_progress = 1; + } error = nfs_request_async_finish(req, &nmrep, &xid, &status); } @@ -4141,7 +4259,7 @@ again: dnp->n_flag &= ~NNEGNCENTRIES; cache_purge_negatives(dvp); } - error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr); + error = nfsm_chain_get_fh_attr(nmp, &nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr); } if (nfsvers == NFS_VER3) { nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &dxid); @@ -4174,7 +4292,9 @@ nfsmout: newvp = NFSTOV(np); } - nfs_dulookup_finish(&dul, dnp, ctx); + if (dul_in_progress) { + nfs_dulookup_finish(&dul, dnp, ctx); + } if (!busyerror) { nfs_node_clear_busy(dnp); } @@ -4320,11 +4440,11 @@ again: } goto again_relock; } - +#if CONFIG_NFS4 if ((nmp->nm_vers >= NFS_VER4) && (np->n_openflags & N_DELEG_MASK)) { nfs4_delegation_return(np, 0, vfs_context_thread(ctx), vfs_context_ucred(ctx)); } - +#endif /* * Purge the name cache so that the chance of a lookup for * the name succeeding while the remove is in progress is @@ -4440,7 +4560,7 @@ nfs3_remove_rpc( kauth_cred_t cred) { int error = 0, lockerror = ENOENT, status, wccpostattr = 0; - struct timespec premtime = { 0, 0 }; + struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 }; struct nfsmount *nmp; int nfsvers; u_int64_t xid; @@ -4581,10 +4701,12 @@ nfs_vnop_rename( /* sillyrename succeeded.*/ tvp = NULL; } - } else if (tvp && (nmp->nm_vers >= NFS_VER4) && (tnp->n_openflags & N_DELEG_MASK)) { + } +#if CONFIG_NFS4 + else if (tvp && (nmp->nm_vers >= NFS_VER4) && (tnp->n_openflags & N_DELEG_MASK)) { nfs4_delegation_return(tnp, 0, vfs_context_thread(ctx), vfs_context_ucred(ctx)); } - +#endif error = nmp->nm_funcs->nf_rename_rpc(fdnp, fcnp->cn_nameptr, fcnp->cn_namelen, tdnp, tcnp->cn_nameptr, tcnp->cn_namelen, ctx); @@ -4685,7 +4807,7 @@ nfs3_rename_rpc( vfs_context_t ctx) { int error = 0, lockerror = ENOENT, status, fwccpostattr = 0, twccpostattr = 0; - struct timespec fpremtime = { 0, 0 }, tpremtime = { 0, 0 }; + struct timespec fpremtime = { .tv_sec = 0, .tv_nsec = 0 }, tpremtime = { .tv_sec = 0, .tv_nsec = 0 }; struct nfsmount *nmp; int nfsvers; u_int64_t xid, txid; @@ -4770,7 +4892,7 @@ nfs3_vnop_link( vnode_t tdvp = ap->a_tdvp; struct componentname *cnp = ap->a_cnp; int error = 0, lockerror = ENOENT, status, wccpostattr = 0, attrflag = 0; - struct timespec premtime = { 0, 0 }; + struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 }; struct nfsmount *nmp; nfsnode_t np = VTONFS(vp); nfsnode_t tdnp = VTONFS(tdvp); @@ -4880,7 +5002,7 @@ nfs3_vnop_symlink( struct nfs_vattr nvattr; fhandle_t fh; int slen, error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0; - struct timespec premtime = { 0, 0 }; + struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 }; vnode_t newvp = NULL; int nfsvers, gotuid, gotgid; u_int64_t xid = 0, dxid; @@ -4890,12 +5012,15 @@ nfs3_vnop_symlink( struct nfsm_chain nmreq, nmrep; struct nfsreq rq, *req = &rq; struct nfs_dulookup dul; + int namedattrs; + int dul_in_progress = 0; nmp = VTONMP(dvp); if (nfs_mount_gone(nmp)) { return ENXIO; } nfsvers = nmp->nm_vers; + namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR); slen = strlen(ap->a_target); if ((nfsvers == NFS_VER2) && @@ -4915,7 +5040,9 @@ nfs3_vnop_symlink( gotgid = VATTR_IS_ACTIVE(vap, va_gid); error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx)); - nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx); + if (!namedattrs) { + nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx); + } nfsm_chain_null(&nmreq); nfsm_chain_null(&nmrep); @@ -4926,7 +5053,7 @@ nfs3_vnop_symlink( nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize); nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp); if (nfsvers == NFS_VER3) { - nfsm_chain_add_v3sattr(error, &nmreq, vap); + nfsm_chain_add_v3sattr(nmp, error, &nmreq, vap); } nfsm_chain_add_name(error, &nmreq, ap->a_target, slen, nmp); if (nfsvers == NFS_VER2) { @@ -4938,7 +5065,10 @@ nfs3_vnop_symlink( error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_SYMLINK, vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req); if (!error) { - nfs_dulookup_start(&dul, dnp, ctx); + if (!namedattrs) { + nfs_dulookup_start(&dul, dnp, ctx); + dul_in_progress = 1; + } error = nfs_request_async_finish(req, &nmrep, &xid, &status); } @@ -4952,7 +5082,7 @@ nfs3_vnop_symlink( cache_purge_negatives(dvp); } if (nfsvers == NFS_VER3) { - error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr); + error = nfsm_chain_get_fh_attr(nmp, &nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr); } else { fh.fh_len = 0; } @@ -4985,7 +5115,9 @@ nfsmout: newvp = NFSTOV(np); } - nfs_dulookup_finish(&dul, dnp, ctx); + if (dul_in_progress) { + nfs_dulookup_finish(&dul, dnp, ctx); + } /* * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry @@ -5052,19 +5184,23 @@ nfs3_vnop_mkdir( nfsnode_t dnp = VTONFS(dvp); vnode_t newvp = NULL; int error = 0, lockerror = ENOENT, busyerror = ENOENT, status, wccpostattr = 0; - struct timespec premtime = { 0, 0 }; + struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 }; int nfsvers, gotuid, gotgid; u_int64_t xid = 0, dxid; fhandle_t fh; struct nfsm_chain nmreq, nmrep; struct nfsreq rq, *req = &rq; struct nfs_dulookup dul; + int namedattrs; + int dul_in_progress = 0; nmp = VTONMP(dvp); if (nfs_mount_gone(nmp)) { return ENXIO; } nfsvers = nmp->nm_vers; + namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR); + if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN)) { return ENAMETOOLONG; } @@ -5081,7 +5217,9 @@ nfs3_vnop_mkdir( gotgid = VATTR_IS_ACTIVE(vap, va_gid); error = busyerror = nfs_node_set_busy(dnp, vfs_context_thread(ctx)); - nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx); + if (!namedattrs) { + nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx); + } nfsm_chain_null(&nmreq); nfsm_chain_null(&nmrep); @@ -5092,7 +5230,7 @@ nfs3_vnop_mkdir( nfsm_chain_add_fh(error, &nmreq, nfsvers, dnp->n_fhp, dnp->n_fhsize); nfsm_chain_add_name(error, &nmreq, cnp->cn_nameptr, cnp->cn_namelen, nmp); if (nfsvers == NFS_VER3) { - nfsm_chain_add_v3sattr(error, &nmreq, vap); + nfsm_chain_add_v3sattr(nmp, error, &nmreq, vap); } else { nfsm_chain_add_v2sattr(error, &nmreq, vap, -1); } @@ -5102,7 +5240,10 @@ nfs3_vnop_mkdir( error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_MKDIR, vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req); if (!error) { - nfs_dulookup_start(&dul, dnp, ctx); + if (!namedattrs) { + nfs_dulookup_start(&dul, dnp, ctx); + dul_in_progress = 1; + } error = nfs_request_async_finish(req, &nmrep, &xid, &status); } @@ -5115,7 +5256,7 @@ nfs3_vnop_mkdir( dnp->n_flag &= ~NNEGNCENTRIES; cache_purge_negatives(dvp); } - error = nfsm_chain_get_fh_attr(&nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr); + error = nfsm_chain_get_fh_attr(nmp, &nmrep, dnp, ctx, nfsvers, &xid, &fh, &nvattr); } if (nfsvers == NFS_VER3) { nfsm_chain_get_wcc_data(error, &nmrep, dnp, &premtime, &wccpostattr, &dxid); @@ -5145,7 +5286,9 @@ nfsmout: newvp = NFSTOV(np); } - nfs_dulookup_finish(&dul, dnp, ctx); + if (dul_in_progress) { + nfs_dulookup_finish(&dul, dnp, ctx); + } /* * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry @@ -5206,7 +5349,7 @@ nfs3_vnop_rmdir( vnode_t dvp = ap->a_dvp; struct componentname *cnp = ap->a_cnp; int error = 0, lockerror = ENOENT, status, wccpostattr = 0; - struct timespec premtime = { 0, 0 }; + struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 }; struct nfsmount *nmp; nfsnode_t np = VTONFS(vp); nfsnode_t dnp = VTONFS(dvp); @@ -5215,12 +5358,16 @@ nfs3_vnop_rmdir( struct nfsm_chain nmreq, nmrep; struct nfsreq rq, *req = &rq; struct nfs_dulookup dul; + int namedattrs; + int dul_in_progress = 0; nmp = VTONMP(vp); if (nfs_mount_gone(nmp)) { return ENXIO; } nfsvers = nmp->nm_vers; + namedattrs = (nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_NAMED_ATTR); + if ((nfsvers == NFS_VER2) && (cnp->cn_namelen > NFS_MAXNAMLEN)) { return ENAMETOOLONG; } @@ -5229,7 +5376,9 @@ nfs3_vnop_rmdir( return error; } - nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx); + if (!namedattrs) { + nfs_dulookup_init(&dul, dnp, cnp->cn_nameptr, cnp->cn_namelen, ctx); + } nfsm_chain_null(&nmreq); nfsm_chain_null(&nmrep); @@ -5244,7 +5393,10 @@ nfs3_vnop_rmdir( error = nfs_request_async(dnp, NULL, &nmreq, NFSPROC_RMDIR, vfs_context_thread(ctx), vfs_context_ucred(ctx), NULL, 0, NULL, &req); if (!error) { - nfs_dulookup_start(&dul, dnp, ctx); + if (!namedattrs) { + nfs_dulookup_start(&dul, dnp, ctx); + dul_in_progress = 1; + } error = nfs_request_async_finish(req, &nmrep, &xid, &status); } @@ -5272,7 +5424,9 @@ nfsmout: /* nfs_getattr() will check changed and purge caches */ nfs_getattr(dnp, NULL, ctx, wccpostattr ? NGA_CACHED : NGA_UNCACHED); } - nfs_dulookup_finish(&dul, dnp, ctx); + if (dul_in_progress) { + nfs_dulookup_finish(&dul, dnp, ctx); + } nfs_node_clear_busy2(dnp, np); /* @@ -5337,7 +5491,7 @@ nfs_vnop_readdir( nfsnode_t dnp = VTONFS(dvp); struct nfsmount *nmp; uio_t uio = ap->a_uio; - int error, nfsvers, extended, numdirent, bigcookies, ptc, done; + int error, nfsvers, extended, numdirent, bigcookies, ptc, done, attrcachetimeout; uint16_t i, iptc, rlen, nlen; uint64_t cookie, nextcookie, lbn = 0; struct nfsbuf *bp = NULL; @@ -5345,6 +5499,7 @@ nfs_vnop_readdir( struct direntry *dp, *dpptc; struct dirent dent; char *cp = NULL; + struct timeval now; thread_t thd; nmp = VTONMP(dvp); @@ -5366,12 +5521,12 @@ nfs_vnop_readdir( if (uio_resid(uio) == 0) { return 0; } - +#if CONFIG_NFS4 if ((nfsvers >= NFS_VER4) && (dnp->n_vattr.nva_flags & NFS_FFLAG_TRIGGER)) { /* trigger directories should never be read, return nothing */ return 0; } - +#endif thd = vfs_context_thread(ctx); numdirent = done = 0; nextcookie = uio_offset(uio); @@ -5394,6 +5549,23 @@ nfs_vnop_readdir( } } + if (dnp->n_rdirplusstamp_eof && dnp->n_rdirplusstamp_sof) { + attrcachetimeout = nfs_attrcachetimeout(dnp); + microuptime(&now); + if (attrcachetimeout && (now.tv_sec - dnp->n_rdirplusstamp_sof > attrcachetimeout - 1)) { + dnp->n_rdirplusstamp_eof = dnp->n_rdirplusstamp_sof = 0; + nfs_invaldir(dnp); + nfs_node_unlock(dnp); + error = nfs_vinvalbuf(dvp, 0, ctx, 1); + if (!error) { + error = nfs_node_lock(dnp); + } + if (error) { + goto out; + } + } + } + /* * check for need to invalidate when (re)starting at beginning */ @@ -5857,7 +6029,7 @@ nfs_dir_buf_search( if ((cnp->cn_namelen == dp->d_namlen) && !strcmp(cnp->cn_nameptr, dp->d_name)) { fhlen = dp->d_name[dp->d_namlen + 1]; nvattrp = NFS_DIR_BUF_NVATTR(bp, i); - if ((ndbhp->ndbh_ncgen != bp->nb_np->n_ncgen) || (fhp->fh_len == 0) || + if ((ndbhp->ndbh_ncgen != bp->nb_np->n_ncgen) || (fhlen == 0) || (nvattrp->nva_type == VNON) || (nvattrp->nva_fileid == 0)) { /* entry is not valid */ error = ENOENT; @@ -5917,6 +6089,8 @@ nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cn struct nfsbuflists blist; daddr64_t lbn, nextlbn; int dotunder = (cnp->cn_namelen > 2) && (cnp->cn_nameptr[0] == '.') && (cnp->cn_nameptr[1] == '_'); + int isdot = (cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.'); + int isdotdot = (cnp->cn_namelen == 2) && (cnp->cn_nameptr[0] == '.') && (cnp->cn_nameptr[1] == '.'); nmp = NFSTONMP(dnp); if (nfs_mount_gone(nmp)) { @@ -5926,6 +6100,10 @@ nfs_dir_buf_cache_lookup(nfsnode_t dnp, nfsnode_t *npp, struct componentname *cn *npp = NULL; } + if (isdot || isdotdot) { + return 0; + } + /* first check most recent buffer (and next one too) */ lbn = dnp->n_lastdbl; for (i = 0; i < 2; i++) { @@ -6162,6 +6340,10 @@ noplus: if (rdirplus) { microuptime(&now); + if (lastcookie == 0) { + dnp->n_rdirplusstamp_sof = now.tv_sec; + dnp->n_rdirplusstamp_eof = 0; + } } /* loop through the entries packing them into the buffer */ @@ -6250,7 +6432,7 @@ nextbuffer: nfsmout_if(error); if (attrflag) { /* grab attributes */ - error = nfs_parsefattr(&nmrep, NFS_VER3, nvattrp); + error = nfs_parsefattr(nmp, &nmrep, NFS_VER3, nvattrp); nfsmout_if(error); dp->d_type = IFTODT(VTTOIF(nvattrp->nva_type)); /* fileid is already in d_fileno, so stash xid in attrs */ @@ -6287,6 +6469,7 @@ nextbuffer: } *(time_t*)(&dp->d_name[dp->d_namlen + 1 + fhlen]) = now.tv_sec; dp->d_reclen = reclen; + nfs_rdirplus_update_node_attrs(dnp, dp, &fh, nvattrp, &savedxid); } padstart = dp->d_name + dp->d_namlen + 1 + xlen; ndbhp->ndbh_count++; @@ -6310,6 +6493,9 @@ nextbuffer: ndbhp->ndbh_flags |= (NDB_FULL | NDB_EOF); nfs_node_lock_force(dnp); dnp->n_eofcookie = lastcookie; + if (rdirplus) { + dnp->n_rdirplusstamp_eof = now.tv_sec; + } nfs_node_unlock(dnp); } else { more_entries = 1; @@ -6521,13 +6707,13 @@ nfs3_lookup_rpc_async_finish( /* get the attributes */ if (nfsvers == NFS_VER3) { - nfsm_chain_postop_attr_get(error, &nmrep, attrflag, nvap); + nfsm_chain_postop_attr_get(nmp, error, &nmrep, attrflag, nvap); nfsm_chain_postop_attr_update(error, &nmrep, dnp, &xid); if (!error && !attrflag) { error = nfs3_getattr_rpc(NULL, NFSTOMP(dnp), fhp->fh_data, fhp->fh_len, 0, ctx, nvap, xidp); } } else { - error = nfs_parsefattr(&nmrep, nfsvers, nvap); + error = nfs_parsefattr(nmp, &nmrep, nfsvers, nvap); } nfsmout: if (!lockerror) { @@ -6771,7 +6957,7 @@ nfs3_commit_rpc( { struct nfsmount *nmp; int error = 0, lockerror, status, wccpostattr = 0, nfsvers; - struct timespec premtime = { 0, 0 }; + struct timespec premtime = { .tv_sec = 0, .tv_nsec = 0 }; u_int64_t xid, newwverf; uint32_t count32; struct nfsm_chain nmreq, nmrep; @@ -7039,7 +7225,9 @@ nfs_vnop_pathconf( } else { nfsap = &nmp->nm_fsattr; } - } else if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_HOMOGENEOUS)) { + } +#if CONFIG_NFS4 + else if (!(nmp->nm_fsattr.nfsa_flags & NFS_FSFLAG_HOMOGENEOUS)) { /* no pathconf info cached */ lck_mtx_unlock(&nmp->nm_lock); NFS_CLEAR_ATTRIBUTES(nfsa.nfsa_bitmap); @@ -7053,16 +7241,19 @@ nfs_vnop_pathconf( } lck_mtx_lock(&nmp->nm_lock); nfsap = &nfsa; - } else { + } +#endif + else { nfsap = &nmp->nm_fsattr; } - switch (ap->a_name) { case _PC_LINK_MAX: if (NFS_BITMAP_ISSET(nfsap->nfsa_bitmap, NFS_FATTR_MAXLINK)) { *ap->a_retval = nfsap->nfsa_maxlink; +#if CONFIG_NFS4 } else if ((nmp->nm_vers == NFS_VER4) && NFS_BITMAP_ISSET(np->n_vattr.nva_bitmap, NFS_FATTR_MAXLINK)) { *ap->a_retval = np->n_vattr.nva_maxlink; +#endif } else { error = EINVAL; } @@ -7390,14 +7581,15 @@ nfs_vnop_ioctl( vfs_context_t ctx = ap->a_context; vnode_t vp = ap->a_vp; struct nfsmount *mp = VTONMP(vp); + int error = ENOTTY; +#if CONFIG_NFS_GSS struct user_nfs_gss_principal gprinc = {}; uint32_t len; - int error = ENOTTY; +#endif if (mp == NULL) { return ENXIO; } - switch (ap->a_command) { case F_FULLFSYNC: if (vnode_vfsisrdonly(vp)) { @@ -7405,6 +7597,7 @@ nfs_vnop_ioctl( } error = nfs_flush(VTONFS(vp), MNT_WAIT, vfs_context_thread(ctx), 0); break; +#if CONFIG_NFS_GSS case NFS_IOC_DESTROY_CRED: if (!auth_is_kerberized(mp->nm_auth)) { return ENOTSUP; @@ -7499,6 +7692,7 @@ nfs_vnop_ioctl( if (gprinc.principal) { FREE(gprinc.principal, M_TEMP); } +#endif /* CONFIG_NFS_GSS */ } return error; @@ -7561,7 +7755,10 @@ nfs_vnop_pagein( #define MAXPAGINGREQS 16 /* max outstanding RPCs for pagein/pageout */ struct nfsreq *req[MAXPAGINGREQS]; int nextsend, nextwait; - uint32_t stategenid = 0, restart = 0; +#if CONFIG_NFS4 + uint32_t stategenid = 0; +#endif + uint32_t restart = 0; kern_return_t kret; FSDBG(322, np, f_offset, size, flags); @@ -7611,9 +7808,11 @@ nfs_vnop_pagein( ioaddr += pl_offset; tryagain: +#if CONFIG_NFS4 if (nmp->nm_vers >= NFS_VER4) { stategenid = nmp->nm_stategenid; } +#endif txsize = rxsize = size; txoffset = f_offset; rxaddr = ioaddr; @@ -7649,6 +7848,7 @@ tryagain: error = nmp->nm_funcs->nf_read_rpc_async_finish(np, req[nextwait], uio, &retsize, NULL); req[nextwait] = NULL; nextwait = (nextwait + 1) % MAXPAGINGREQS; +#if CONFIG_NFS4 if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error)) { lck_mtx_lock(&nmp->nm_lock); if ((error != NFSERR_GRACE) && (stategenid == nmp->nm_stategenid)) { @@ -7659,6 +7859,7 @@ tryagain: restart++; goto cancel; } +#endif if (error) { FSDBG(322, uio_offset(uio), uio_resid(uio), error, -1); break; @@ -7681,7 +7882,9 @@ tryagain: restart = 0; if (error) { +#if CONFIG_NFS4 cancel: +#endif /* cancel any outstanding requests */ while (req[nextwait]) { nfs_request_async_cancel(req[nextwait]); @@ -7885,7 +8088,10 @@ nfs_vnop_pageout( struct nfsreq *req[MAXPAGINGREQS]; int nextsend, nextwait, wverfset, commit; uint64_t wverf, wverf2; - uint32_t stategenid = 0, vrestart = 0, restart = 0, vrestarts = 0, restarts = 0; +#if CONFIG_NFS4 + uint32_t stategenid = 0; +#endif + uint32_t vrestart = 0, restart = 0, vrestarts = 0, restarts = 0; kern_return_t kret; FSDBG(323, f_offset, size, pl, pl_offset); @@ -8081,9 +8287,11 @@ nfs_vnop_pageout( &uio_buf, sizeof(uio_buf)); tryagain: +#if CONFIG_NFS4 if (nmp->nm_vers >= NFS_VER4) { stategenid = nmp->nm_stategenid; } +#endif wverf = wverf2 = wverfset = 0; txsize = rxsize = xsize; txoffset = rxoffset = f_offset; @@ -8132,6 +8340,7 @@ tryagain: nfs_node_lock_force(np); np->n_numoutput--; nfs_node_unlock(np); +#if CONFIG_NFS4 if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error)) { lck_mtx_lock(&nmp->nm_lock); if ((error != NFSERR_GRACE) && (stategenid == nmp->nm_stategenid)) { @@ -8142,6 +8351,7 @@ tryagain: restart = 1; goto cancel; } +#endif if (error) { FSDBG(323, rxoffset, rxsize, error, -1); break; @@ -8169,6 +8379,7 @@ tryagain: uio_addiov(auio, CAST_USER_ADDR_T(rxaddr), remsize); iomode = NFS_WRITE_UNSTABLE; error = nfs_write_rpc2(np, auio, thd, cred, &iomode, &wverf2); +#if CONFIG_NFS4 if ((nmp->nm_vers >= NFS_VER4) && nfs_mount_state_error_should_restart(error)) { NP(np, "nfs_vnop_pageout: restart: error %d", error); lck_mtx_lock(&nmp->nm_lock); @@ -8180,6 +8391,7 @@ tryagain: restart = 1; goto cancel; } +#endif if (error) { FSDBG(323, rxoffset, rxsize, error, -1); break; @@ -8394,7 +8606,7 @@ nfs_vnop_monitor( /* This vnode is no longer being monitored, make sure we're not tracking it. */ /* Wait for any in-progress getattr to complete first. */ while (np->n_mflag & NMMONSCANINPROG) { - struct timespec ts = { 1, 0 }; + struct timespec ts = { .tv_sec = 1, .tv_nsec = 0 }; np->n_mflag |= NMMONSCANWANT; msleep(&np->n_mflag, &nmp->nm_lock, PZERO - 1, "nfswaitmonscan", &ts); } @@ -8443,3 +8655,5 @@ nfs_vnode_notify(nfsnode_t np, uint32_t events) } vnode_notify(NFSTOV(np), events, vap); } + +#endif /* CONFIG_NFS_CLIENT */