svn commit: r364542 - in head/sys: kern sys
Mateusz Guzik
mjg at FreeBSD.org
Sun Aug 23 21:06:42 UTC 2020
Author: mjg
Date: Sun Aug 23 21:06:41 2020
New Revision: 364542
URL: https://svnweb.freebsd.org/changeset/base/364542
Log:
vfs: validate ndp state after the lookup
The intent is to remove known-to-be-nops NDFREE calls after many lookups.
Modified:
head/sys/kern/vfs_lookup.c
head/sys/sys/namei.h
Modified: head/sys/kern/vfs_lookup.c
==============================================================================
--- head/sys/kern/vfs_lookup.c Sun Aug 23 21:05:54 2020 (r364541)
+++ head/sys/kern/vfs_lookup.c Sun Aug 23 21:06:41 2020 (r364542)
@@ -482,6 +482,15 @@ namei(struct nameidata *ndp)
cnp = &ndp->ni_cnd;
td = cnp->cn_thread;
+#ifdef INVARIANTS
+ /*
+ * For NDVALIDATE.
+ *
+ * While NDINIT may seem like a more natural place to do it, there are
+ * callers which directly modify flags past invoking init.
+ */
+ cnp->cn_origflags = cnp->cn_flags;
+#endif
ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred;
KASSERT(cnp->cn_cred && td->td_proc, ("namei: bad cred/proc"));
KASSERT((cnp->cn_flags & NAMEI_INTERNAL_FLAGS) == 0,
@@ -542,6 +551,8 @@ namei(struct nameidata *ndp)
__assert_unreachable();
break;
case CACHE_FPL_STATUS_HANDLED:
+ if (error == 0)
+ NDVALIDATE(ndp);
return (error);
case CACHE_FPL_STATUS_PARTIAL:
TAILQ_INIT(&ndp->ni_cap_tracker);
@@ -584,6 +595,8 @@ namei(struct nameidata *ndp)
SDT_PROBE3(vfs, namei, lookup, return, error,
(error == 0 ? ndp->ni_vp : NULL), false);
pwd_drop(pwd);
+ if (error == 0)
+ NDVALIDATE(ndp);
return (error);
}
if (ndp->ni_loopcnt++ >= MAXSYMLINKS) {
@@ -1432,6 +1445,68 @@ void
ndp->ni_startdir = NULL;
}
}
+
+#ifdef INVARIANTS
+/*
+ * Validate the final state of ndp after the lookup.
+ *
+ * Historically filesystems were allowed to modify cn_flags. Most notably they
+ * can add SAVENAME to the request, resulting in HASBUF and pushing subsequent
+ * clean up to the consumer. In practice this seems to only concern != LOOKUP
+ * operations.
+ *
+ * As a step towards stricter API contract this routine validates the state to
+ * clean up. Note validation is a work in progress with the intent of becoming
+ * stricter over time.
+ */
+#define NDMODIFYINGFLAGS (LOCKLEAF | LOCKPARENT | WANTPARENT | SAVENAME | SAVESTART | HASBUF)
+void
+NDVALIDATE(struct nameidata *ndp)
+{
+ struct componentname *cnp;
+ u_int64_t used, orig;
+
+ cnp = &ndp->ni_cnd;
+ orig = cnp->cn_origflags;
+ used = cnp->cn_flags;
+ switch (cnp->cn_nameiop) {
+ case LOOKUP:
+ /*
+ * For plain lookup we require strict conformance -- nothing
+ * to clean up if it was not requested by the caller.
+ */
+ orig &= NDMODIFYINGFLAGS;
+ used &= NDMODIFYINGFLAGS;
+ if ((orig & (SAVENAME | SAVESTART)) != 0)
+ orig |= HASBUF;
+ if (orig != used) {
+ goto out_mismatch;
+ }
+ break;
+ case CREATE:
+ case DELETE:
+ case RENAME:
+ /*
+ * Some filesystems set SAVENAME to provoke HASBUF, accomodate
+ * for it until it gets fixed.
+ */
+ orig &= NDMODIFYINGFLAGS;
+ orig |= (SAVENAME | HASBUF);
+ used &= NDMODIFYINGFLAGS;
+ used |= (SAVENAME | HASBUF);
+ if (orig != used) {
+ goto out_mismatch;
+ }
+ break;
+ }
+ return;
+out_mismatch:
+ panic("%s: mismatched flags for op %d: added %" PRIx64 ", "
+ "removed %" PRIx64" (%" PRIx64" != %" PRIx64"; stored %" PRIx64" != %" PRIx64")",
+ __func__, cnp->cn_nameiop, used & ~orig, orig &~ used,
+ orig, used, cnp->cn_origflags, cnp->cn_flags);
+}
+#endif
/*
* Determine if there is a suitable alternate filename under the specified
Modified: head/sys/sys/namei.h
==============================================================================
--- head/sys/sys/namei.h Sun Aug 23 21:05:54 2020 (r364541)
+++ head/sys/sys/namei.h Sun Aug 23 21:06:41 2020 (r364542)
@@ -46,6 +46,7 @@ struct componentname {
/*
* Arguments to lookup.
*/
+ u_int64_t cn_origflags; /* flags to namei */
u_int64_t cn_flags; /* flags to namei */
struct thread *cn_thread;/* thread requesting lookup */
struct ucred *cn_cred; /* credentials */
@@ -250,6 +251,12 @@ void NDFREE(struct nameidata *, const u_int);
else \
NDFREE(_ndp, flags); \
} while (0)
+
+#ifdef INVARIANTS
+void NDVALIDATE(struct nameidata *);
+#else
+#define NDVALIDATE(ndp) do { } while (0)
+#endif
int namei(struct nameidata *ndp);
int lookup(struct nameidata *ndp);
More information about the svn-src-all
mailing list