Deleted Added
full compact
nfs_vnops.c (224733) nfs_vnops.c (230394)
1/*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 19 unchanged lines hidden (view full) ---

28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
33 */
34
35#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without

--- 19 unchanged lines hidden (view full) ---

28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * @(#)nfs_vnops.c 8.16 (Berkeley) 5/27/95
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_vnops.c 224733 2011-08-09 15:29:58Z jhb $");
36__FBSDID("$FreeBSD: head/sys/nfsclient/nfs_vnops.c 230394 2012-01-20 20:02:01Z jhb $");
37
38/*
39 * vnode op calls for Sun NFS version 2 and 3
40 */
41
42#include "opt_inet.h"
43#include "opt_kdtrace.h"
44

--- 863 unchanged lines hidden (view full) ---

908static int
909nfs_lookup(struct vop_lookup_args *ap)
910{
911 struct componentname *cnp = ap->a_cnp;
912 struct vnode *dvp = ap->a_dvp;
913 struct vnode **vpp = ap->a_vpp;
914 struct mount *mp = dvp->v_mount;
915 struct vattr vattr;
37
38/*
39 * vnode op calls for Sun NFS version 2 and 3
40 */
41
42#include "opt_inet.h"
43#include "opt_kdtrace.h"
44

--- 863 unchanged lines hidden (view full) ---

908static int
909nfs_lookup(struct vop_lookup_args *ap)
910{
911 struct componentname *cnp = ap->a_cnp;
912 struct vnode *dvp = ap->a_dvp;
913 struct vnode **vpp = ap->a_vpp;
914 struct mount *mp = dvp->v_mount;
915 struct vattr vattr;
916 struct timespec dmtime;
916 struct timespec nctime;
917 int flags = cnp->cn_flags;
918 struct vnode *newvp;
919 struct nfsmount *nmp;
920 caddr_t bpos, dpos;
921 struct mbuf *mreq, *mrep, *md, *mb;
922 long len;
923 nfsfh_t *fhp;
924 struct nfsnode *np, *newnp;
917 int flags = cnp->cn_flags;
918 struct vnode *newvp;
919 struct nfsmount *nmp;
920 caddr_t bpos, dpos;
921 struct mbuf *mreq, *mrep, *md, *mb;
922 long len;
923 nfsfh_t *fhp;
924 struct nfsnode *np, *newnp;
925 int error = 0, attrflag, fhsize, ltype;
925 int error = 0, attrflag, dattrflag, fhsize, ltype, ncticks;
926 int v3 = NFS_ISV3(dvp);
927 struct thread *td = cnp->cn_thread;
928
929 *vpp = NULLVP;
930 if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) &&
931 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
932 return (EROFS);
933 if (dvp->v_type != VDIR)
934 return (ENOTDIR);
935 nmp = VFSTONFS(mp);
936 np = VTONFS(dvp);
937 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) {
938 *vpp = NULLVP;
939 return (error);
940 }
926 int v3 = NFS_ISV3(dvp);
927 struct thread *td = cnp->cn_thread;
928
929 *vpp = NULLVP;
930 if ((flags & ISLASTCN) && (mp->mnt_flag & MNT_RDONLY) &&
931 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
932 return (EROFS);
933 if (dvp->v_type != VDIR)
934 return (ENOTDIR);
935 nmp = VFSTONFS(mp);
936 np = VTONFS(dvp);
937 if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, td)) != 0) {
938 *vpp = NULLVP;
939 return (error);
940 }
941 error = cache_lookup(dvp, vpp, cnp);
941 error = cache_lookup_times(dvp, vpp, cnp, &nctime, &ncticks);
942 if (error > 0 && error != ENOENT)
943 return (error);
944 if (error == -1) {
945 /*
942 if (error > 0 && error != ENOENT)
943 return (error);
944 if (error == -1) {
945 /*
946 * Lookups of "." are special and always return the
947 * current directory. cache_lookup() already handles
948 * associated locking bookkeeping, etc.
949 */
950 if (cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
951 /* XXX: Is this really correct? */
952 if (cnp->cn_nameiop != LOOKUP &&
953 (flags & ISLASTCN))
954 cnp->cn_flags |= SAVENAME;
955 return (0);
956 }
957
958 /*
946 * We only accept a positive hit in the cache if the
947 * change time of the file matches our cached copy.
948 * Otherwise, we discard the cache entry and fallback
949 * to doing a lookup RPC.
950 *
951 * To better handle stale file handles and attributes,
952 * clear the attribute cache of this node if it is a
953 * leaf component, part of an open() call, and not

--- 9 unchanged lines hidden (view full) ---

963 (flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN) &&
964 !(newnp->n_flag & NMODIFIED)) {
965 mtx_lock(&newnp->n_mtx);
966 newnp->n_attrstamp = 0;
967 KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp);
968 mtx_unlock(&newnp->n_mtx);
969 }
970 if (VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
959 * We only accept a positive hit in the cache if the
960 * change time of the file matches our cached copy.
961 * Otherwise, we discard the cache entry and fallback
962 * to doing a lookup RPC.
963 *
964 * To better handle stale file handles and attributes,
965 * clear the attribute cache of this node if it is a
966 * leaf component, part of an open() call, and not

--- 9 unchanged lines hidden (view full) ---

976 (flags & (ISLASTCN | ISOPEN)) == (ISLASTCN | ISOPEN) &&
977 !(newnp->n_flag & NMODIFIED)) {
978 mtx_lock(&newnp->n_mtx);
979 newnp->n_attrstamp = 0;
980 KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp);
981 mtx_unlock(&newnp->n_mtx);
982 }
983 if (VOP_GETATTR(newvp, &vattr, cnp->cn_cred) == 0 &&
971 timespeccmp(&vattr.va_ctime, &newnp->n_ctime, ==)) {
984 timespeccmp(&vattr.va_ctime, &nctime, ==)) {
972 nfsstats.lookupcache_hits++;
973 if (cnp->cn_nameiop != LOOKUP &&
974 (flags & ISLASTCN))
975 cnp->cn_flags |= SAVENAME;
976 return (0);
977 }
978 cache_purge(newvp);
979 if (dvp != newvp)
980 vput(newvp);
981 else
982 vrele(newvp);
983 *vpp = NULLVP;
984 } else if (error == ENOENT) {
985 if (dvp->v_iflag & VI_DOOMED)
986 return (ENOENT);
987 /*
988 * We only accept a negative hit in the cache if the
989 * modification time of the parent directory matches
985 nfsstats.lookupcache_hits++;
986 if (cnp->cn_nameiop != LOOKUP &&
987 (flags & ISLASTCN))
988 cnp->cn_flags |= SAVENAME;
989 return (0);
990 }
991 cache_purge(newvp);
992 if (dvp != newvp)
993 vput(newvp);
994 else
995 vrele(newvp);
996 *vpp = NULLVP;
997 } else if (error == ENOENT) {
998 if (dvp->v_iflag & VI_DOOMED)
999 return (ENOENT);
1000 /*
1001 * We only accept a negative hit in the cache if the
1002 * modification time of the parent directory matches
990 * our cached copy. Otherwise, we discard all of the
991 * negative cache entries for this directory. We also
992 * only trust -ve cache entries for less than
993 * nm_negative_namecache_timeout seconds.
1003 * the cached copy in the name cache entry.
1004 * Otherwise, we discard all of the negative cache
1005 * entries for this directory. We also only trust
1006 * negative cache entries for up to nm_negnametimeo
1007 * seconds.
994 */
1008 */
995 if ((u_int)(ticks - np->n_dmtime_ticks) <
996 (nmp->nm_negnametimeo * hz) &&
1009 if ((u_int)(ticks - ncticks) < (nmp->nm_negnametimeo * hz) &&
997 VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 &&
1010 VOP_GETATTR(dvp, &vattr, cnp->cn_cred) == 0 &&
998 timespeccmp(&vattr.va_mtime, &np->n_dmtime, ==)) {
1011 timespeccmp(&vattr.va_mtime, &nctime, ==)) {
999 nfsstats.lookupcache_hits++;
1000 return (ENOENT);
1001 }
1002 cache_purge_negative(dvp);
1012 nfsstats.lookupcache_hits++;
1013 return (ENOENT);
1014 }
1015 cache_purge_negative(dvp);
1003 mtx_lock(&np->n_mtx);
1004 timespecclear(&np->n_dmtime);
1005 mtx_unlock(&np->n_mtx);
1006 }
1007
1016 }
1017
1008 /*
1009 * Cache the modification time of the parent directory in case
1010 * the lookup fails and results in adding the first negative
1011 * name cache entry for the directory. Since this is reading
1012 * a single time_t, don't bother with locking. The
1013 * modification time may be a bit stale, but it must be read
1014 * before performing the lookup RPC to prevent a race where
1015 * another lookup updates the timestamp on the directory after
1016 * the lookup RPC has been performed on the server but before
1017 * n_dmtime is set at the end of this function.
1018 */
1019 dmtime = np->n_vattr.va_mtime;
1018 attrflag = dattrflag = 0;
1020 error = 0;
1021 newvp = NULLVP;
1022 nfsstats.lookupcache_misses++;
1023 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1024 len = cnp->cn_namelen;
1025 mreq = nfsm_reqhead(dvp, NFSPROC_LOOKUP,
1026 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
1027 mb = mreq;
1028 bpos = mtod(mb, caddr_t);
1029 nfsm_fhtom(dvp, v3);
1030 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1031 nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_thread, cnp->cn_cred);
1032 if (error) {
1033 if (v3) {
1019 error = 0;
1020 newvp = NULLVP;
1021 nfsstats.lookupcache_misses++;
1022 nfsstats.rpccnt[NFSPROC_LOOKUP]++;
1023 len = cnp->cn_namelen;
1024 mreq = nfsm_reqhead(dvp, NFSPROC_LOOKUP,
1025 NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
1026 mb = mreq;
1027 bpos = mtod(mb, caddr_t);
1028 nfsm_fhtom(dvp, v3);
1029 nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
1030 nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_thread, cnp->cn_cred);
1031 if (error) {
1032 if (v3) {
1034 nfsm_postop_attr(dvp, attrflag);
1033 nfsm_postop_attr_va(dvp, dattrflag, &vattr);
1035 m_freem(mrep);
1036 }
1037 goto nfsmout;
1038 }
1039 nfsm_getfh(fhp, fhsize, v3);
1040
1041 /*
1042 * Handle RENAME case...

--- 79 unchanged lines hidden (view full) ---

1122 !(np->n_flag & NMODIFIED)) {
1123 mtx_lock(&np->n_mtx);
1124 np->n_attrstamp = 0;
1125 KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp);
1126 mtx_unlock(&np->n_mtx);
1127 }
1128 }
1129 if (v3) {
1034 m_freem(mrep);
1035 }
1036 goto nfsmout;
1037 }
1038 nfsm_getfh(fhp, fhsize, v3);
1039
1040 /*
1041 * Handle RENAME case...

--- 79 unchanged lines hidden (view full) ---

1121 !(np->n_flag & NMODIFIED)) {
1122 mtx_lock(&np->n_mtx);
1123 np->n_attrstamp = 0;
1124 KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp);
1125 mtx_unlock(&np->n_mtx);
1126 }
1127 }
1128 if (v3) {
1130 nfsm_postop_attr(newvp, attrflag);
1131 nfsm_postop_attr(dvp, attrflag);
1132 } else
1133 nfsm_loadattr(newvp, NULL);
1129 nfsm_postop_attr_va(newvp, attrflag, &vattr);
1130 nfsm_postop_attr(dvp, dattrflag);
1131 } else {
1132 nfsm_loadattr(newvp, &vattr);
1133 attrflag = 1;
1134 }
1134 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
1135 cnp->cn_flags |= SAVENAME;
1136 if ((cnp->cn_flags & MAKEENTRY) &&
1135 if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
1136 cnp->cn_flags |= SAVENAME;
1137 if ((cnp->cn_flags & MAKEENTRY) &&
1137 (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN))) {
1138 np->n_ctime = np->n_vattr.va_ctime;
1139 cache_enter(dvp, newvp, cnp);
1138 (cnp->cn_nameiop != DELETE || !(flags & ISLASTCN)) && attrflag) {
1139 cache_enter_time(dvp, newvp, cnp, &vattr.va_ctime);
1140 }
1141 *vpp = newvp;
1142 m_freem(mrep);
1143nfsmout:
1144 if (error) {
1145 if (newvp != NULLVP) {
1146 vput(newvp);
1147 *vpp = NULLVP;

--- 11 unchanged lines hidden (view full) ---

1159 * MNT_RDONLY.
1160 */
1161 if (mp->mnt_flag & MNT_RDONLY)
1162 return (EROFS);
1163 cnp->cn_flags |= SAVENAME;
1164 return (EJUSTRETURN);
1165 }
1166
1140 }
1141 *vpp = newvp;
1142 m_freem(mrep);
1143nfsmout:
1144 if (error) {
1145 if (newvp != NULLVP) {
1146 vput(newvp);
1147 *vpp = NULLVP;

--- 11 unchanged lines hidden (view full) ---

1159 * MNT_RDONLY.
1160 */
1161 if (mp->mnt_flag & MNT_RDONLY)
1162 return (EROFS);
1163 cnp->cn_flags |= SAVENAME;
1164 return (EJUSTRETURN);
1165 }
1166
1167 if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE) {
1167 if ((cnp->cn_flags & MAKEENTRY) && cnp->cn_nameiop != CREATE &&
1168 dattrflag) {
1168 /*
1169 /*
1169 * Maintain n_dmtime as the modification time
1170 * of the parent directory when the oldest -ve
1171 * name cache entry for this directory was
1172 * added. If a -ve cache entry has already
1173 * been added with a newer modification time
1174 * by a concurrent lookup, then don't bother
1175 * adding a cache entry. The modification
1176 * time of the directory might have changed
1177 * due to the file this lookup failed to find
1178 * being created. In that case a subsequent
1179 * lookup would incorrectly use the entry
1180 * added here instead of doing an extra
1181 * lookup.
1170 * Cache the modification time of the parent
1171 * directory from the post-op attributes in
1172 * the name cache entry. The negative cache
1173 * entry will be ignored once the directory
1174 * has changed. Don't bother adding the entry
1175 * if the directory has already changed.
1182 */
1183 mtx_lock(&np->n_mtx);
1176 */
1177 mtx_lock(&np->n_mtx);
1184 if (timespeccmp(&np->n_dmtime, &dmtime, <=)) {
1185 if (!timespecisset(&np->n_dmtime)) {
1186 np->n_dmtime = dmtime;
1187 np->n_dmtime_ticks = ticks;
1188 }
1178 if (timespeccmp(&np->n_vattr.va_mtime,
1179 &vattr.va_mtime, ==)) {
1189 mtx_unlock(&np->n_mtx);
1180 mtx_unlock(&np->n_mtx);
1190 cache_enter(dvp, NULL, cnp);
1181 cache_enter_time(dvp, NULL, cnp,
1182 &vattr.va_mtime);
1191 } else
1192 mtx_unlock(&np->n_mtx);
1193 }
1194 return (ENOENT);
1195 }
1196done:
1197 return (error);
1198}

--- 1269 unchanged lines hidden (view full) ---

2468 nfsuint64 *cookiep;
2469 caddr_t bpos, dpos, dpossav1, dpossav2;
2470 struct mbuf *mreq, *mrep, *md, *mb, *mdsav1, *mdsav2;
2471 struct nameidata nami, *ndp = &nami;
2472 struct componentname *cnp = &ndp->ni_cnd;
2473 nfsuint64 cookie;
2474 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2475 struct nfsnode *dnp = VTONFS(vp), *np;
1183 } else
1184 mtx_unlock(&np->n_mtx);
1185 }
1186 return (ENOENT);
1187 }
1188done:
1189 return (error);
1190}

--- 1269 unchanged lines hidden (view full) ---

2460 nfsuint64 *cookiep;
2461 caddr_t bpos, dpos, dpossav1, dpossav2;
2462 struct mbuf *mreq, *mrep, *md, *mb, *mdsav1, *mdsav2;
2463 struct nameidata nami, *ndp = &nami;
2464 struct componentname *cnp = &ndp->ni_cnd;
2465 nfsuint64 cookie;
2466 struct nfsmount *nmp = VFSTONFS(vp->v_mount);
2467 struct nfsnode *dnp = VTONFS(vp), *np;
2468 struct vattr vattr;
2476 nfsfh_t *fhp;
2477 u_quad_t fileno;
2478 int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
2479 int attrflag, fhsize;
2480
2481#ifndef nolint
2482 dp = NULL;
2483#endif

--- 164 unchanged lines hidden (view full) ---

2648 newvp = NFSTOV(np);
2649 }
2650 }
2651 if (doit && bigenough) {
2652 dpossav2 = dpos;
2653 dpos = dpossav1;
2654 mdsav2 = md;
2655 md = mdsav1;
2469 nfsfh_t *fhp;
2470 u_quad_t fileno;
2471 int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
2472 int attrflag, fhsize;
2473
2474#ifndef nolint
2475 dp = NULL;
2476#endif

--- 164 unchanged lines hidden (view full) ---

2641 newvp = NFSTOV(np);
2642 }
2643 }
2644 if (doit && bigenough) {
2645 dpossav2 = dpos;
2646 dpos = dpossav1;
2647 mdsav2 = md;
2648 md = mdsav1;
2656 nfsm_loadattr(newvp, NULL);
2649 nfsm_loadattr(newvp, &vattr);
2657 dpos = dpossav2;
2658 md = mdsav2;
2650 dpos = dpossav2;
2651 md = mdsav2;
2659 dp->d_type =
2660 IFTODT(VTTOIF(np->n_vattr.va_type));
2652 dp->d_type = IFTODT(VTTOIF(vattr.va_type));
2661 ndp->ni_vp = newvp;
2653 ndp->ni_vp = newvp;
2662 /*
2663 * Update n_ctime so subsequent lookup
2664 * doesn't purge entry.
2665 */
2666 np->n_ctime = np->n_vattr.va_ctime;
2667 cache_enter(ndp->ni_dvp, ndp->ni_vp, cnp);
2654 cache_enter_time(ndp->ni_dvp, ndp->ni_vp, cnp,
2655 &vattr.va_ctime);
2668 }
2669 } else {
2670 /* Just skip over the file handle */
2671 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
2672 i = fxdr_unsigned(int, *tl);
2673 if (i) {
2674 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
2675 fhsize = fxdr_unsigned(int, *tl);

--- 862 unchanged lines hidden ---
2656 }
2657 } else {
2658 /* Just skip over the file handle */
2659 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
2660 i = fxdr_unsigned(int, *tl);
2661 if (i) {
2662 tl = nfsm_dissect(u_int32_t *, NFSX_UNSIGNED);
2663 fhsize = fxdr_unsigned(int, *tl);

--- 862 unchanged lines hidden ---