summaryrefslogtreecommitdiffstats
path: root/sys/fs/nfsclient
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fs/nfsclient')
-rw-r--r--sys/fs/nfsclient/nfs_clbio.c22
-rw-r--r--sys/fs/nfsclient/nfs_clcomsubs.c2
-rw-r--r--sys/fs/nfsclient/nfs_clkdtrace.c600
-rw-r--r--sys/fs/nfsclient/nfs_clkrpc.c12
-rw-r--r--sys/fs/nfsclient/nfs_clnode.c5
-rw-r--r--sys/fs/nfsclient/nfs_clport.c97
-rw-r--r--sys/fs/nfsclient/nfs_clrpcops.c33
-rw-r--r--sys/fs/nfsclient/nfs_clstate.c126
-rw-r--r--sys/fs/nfsclient/nfs_clsubs.c5
-rw-r--r--sys/fs/nfsclient/nfs_clvfsops.c12
-rw-r--r--sys/fs/nfsclient/nfs_clvnops.c103
-rw-r--r--sys/fs/nfsclient/nfs_kdtrace.h120
12 files changed, 1014 insertions, 123 deletions
diff --git a/sys/fs/nfsclient/nfs_clbio.c b/sys/fs/nfsclient/nfs_clbio.c
index fee8b05..b33c8a5 100644
--- a/sys/fs/nfsclient/nfs_clbio.c
+++ b/sys/fs/nfsclient/nfs_clbio.c
@@ -35,6 +35,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_kdtrace.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bio.h>
@@ -55,6 +57,7 @@ __FBSDID("$FreeBSD$");
#include <fs/nfsclient/nfsmount.h>
#include <fs/nfsclient/nfs.h>
#include <fs/nfsclient/nfsnode.h>
+#include <fs/nfsclient/nfs_kdtrace.h>
extern int newnfs_directio_allow_mmap;
extern struct nfsstats newnfsstats;
@@ -302,7 +305,7 @@ ncl_putpages(struct vop_putpages_args *ap)
}
for (i = 0; i < npages; i++)
- rtvals[i] = VM_PAGER_AGAIN;
+ rtvals[i] = VM_PAGER_ERROR;
/*
* When putting pages, do not extend file past EOF.
@@ -345,16 +348,9 @@ ncl_putpages(struct vop_putpages_args *ap)
pmap_qremove(kva, npages);
relpbuf(bp, &ncl_pbuf_freecnt);
- if (!error) {
- int nwritten = round_page(count - uio.uio_resid) / PAGE_SIZE;
- for (i = 0; i < nwritten; i++) {
- rtvals[i] = VM_PAGER_OK;
- vm_page_undirty(pages[i]);
- }
- if (must_commit) {
- ncl_clearcommit(vp->v_mount);
- }
- }
+ vnode_pager_undirty_pages(pages, rtvals, count - uio.uio_resid);
+ if (must_commit)
+ ncl_clearcommit(vp->v_mount);
return rtvals[0];
}
@@ -406,6 +402,7 @@ nfs_bioread_check_cons(struct vnode *vp, struct thread *td, struct ucred *cred)
goto out;
}
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
error = VOP_GETATTR(vp, &vattr, cred);
if (error)
goto out;
@@ -922,6 +919,7 @@ ncl_write(struct vop_write_args *ap)
#endif
flush_and_restart:
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
error = ncl_vinvalbuf(vp, V_SAVE, td, 1);
if (error)
return (error);
@@ -935,6 +933,7 @@ flush_and_restart:
*/
if (ioflag & IO_APPEND) {
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
error = VOP_GETATTR(vp, &vattr, cred);
if (error)
return (error);
@@ -1755,6 +1754,7 @@ ncl_doio(struct vnode *vp, struct buf *bp, struct ucred *cr, struct thread *td,
mtx_lock(&np->n_mtx);
np->n_flag |= NWRITEERR;
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
mtx_unlock(&np->n_mtx);
}
bp->b_dirtyoff = bp->b_dirtyend = 0;
diff --git a/sys/fs/nfsclient/nfs_clcomsubs.c b/sys/fs/nfsclient/nfs_clcomsubs.c
index 6866a73..c7fd69b 100644
--- a/sys/fs/nfsclient/nfs_clcomsubs.c
+++ b/sys/fs/nfsclient/nfs_clcomsubs.c
@@ -482,7 +482,7 @@ nfscl_lockexcl(struct nfsv4lock *lckp, void *mutex)
int igotlock;
do {
- igotlock = nfsv4_lock(lckp, 1, NULL, mutex);
+ igotlock = nfsv4_lock(lckp, 1, NULL, mutex, NULL);
} while (!igotlock);
}
diff --git a/sys/fs/nfsclient/nfs_clkdtrace.c b/sys/fs/nfsclient/nfs_clkdtrace.c
new file mode 100644
index 0000000..c7db3a4
--- /dev/null
+++ b/sys/fs/nfsclient/nfs_clkdtrace.c
@@ -0,0 +1,600 @@
+/*-
+ * Copyright (c) 2009 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed at the University of Cambridge Computer
+ * Laboratory with support from a grant from Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/conf.h>
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <sys/module.h>
+
+#include <sys/dtrace.h>
+#include <sys/dtrace_bsd.h>
+
+#include <fs/nfs/nfsproto.h>
+
+#include <fs/nfsclient/nfs_kdtrace.h>
+
+/*
+ * dtnfscl is a DTrace provider that tracks the intent to perform RPCs
+ * in the NFS client, as well as acess to and maintenance of the access and
+ * attribute caches. This is not quite the same as RPCs, because NFS may
+ * issue multiple RPC transactions in the event that authentication fails,
+ * there's a jukebox error, or none at all if the access or attribute cache
+ * hits. However, it cleanly represents the logical layer between RPC
+ * transmission and vnode/vfs operations, providing access to state linking
+ * the two.
+ */
+
+static int dtnfsclient_unload(void);
+static void dtnfsclient_getargdesc(void *, dtrace_id_t, void *,
+ dtrace_argdesc_t *);
+static void dtnfsclient_provide(void *, dtrace_probedesc_t *);
+static void dtnfsclient_destroy(void *, dtrace_id_t, void *);
+static void dtnfsclient_enable(void *, dtrace_id_t, void *);
+static void dtnfsclient_disable(void *, dtrace_id_t, void *);
+static void dtnfsclient_load(void *);
+
+static dtrace_pattr_t dtnfsclient_attr = {
+{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_PRIVATE, DTRACE_STABILITY_PRIVATE, DTRACE_CLASS_UNKNOWN },
+{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
+{ DTRACE_STABILITY_STABLE, DTRACE_STABILITY_STABLE, DTRACE_CLASS_COMMON },
+};
+
+/*
+ * Description of NFSv4, NFSv3 and (optional) NFSv2 probes for a procedure.
+ */
+struct dtnfsclient_rpc {
+ char *nr_v4_name;
+ char *nr_v3_name; /* Or NULL if none. */
+ char *nr_v2_name; /* Or NULL if none. */
+
+ /*
+ * IDs for the start and done cases, for NFSv2, NFSv3 and NFSv4.
+ */
+ uint32_t nr_v2_id_start, nr_v2_id_done;
+ uint32_t nr_v3_id_start, nr_v3_id_done;
+ uint32_t nr_v4_id_start, nr_v4_id_done;
+};
+
+/*
+ * This table is indexed by NFSv3 procedure number, but also used for NFSv2
+ * procedure names and NFSv4 operations.
+ */
+static struct dtnfsclient_rpc dtnfsclient_rpcs[NFS_NPROCS + 1] = {
+ { "null", "null", "null" },
+ { "getattr", "getattr", "getattr" },
+ { "setattr", "setattr", "setattr" },
+ { "lookup", "lookup", "lookup" },
+ { "access", "access", "noop" },
+ { "readlink", "readlink", "readlink" },
+ { "read", "read", "read" },
+ { "write", "write", "write" },
+ { "create", "create", "create" },
+ { "mkdir", "mkdir", "mkdir" },
+ { "symlink", "symlink", "symlink" },
+ { "mknod", "mknod" },
+ { "remove", "remove", "remove" },
+ { "rmdir", "rmdir", "rmdir" },
+ { "rename", "rename", "rename" },
+ { "link", "link", "link" },
+ { "readdir", "readdir", "readdir" },
+ { "readdirplus", "readdirplus" },
+ { "fsstat", "fsstat", "statfs" },
+ { "fsinfo", "fsinfo" },
+ { "pathconf", "pathconf" },
+ { "commit", "commit" },
+ { "lookupp" },
+ { "setclientid" },
+ { "setclientidcfrm" },
+ { "lock" },
+ { "locku" },
+ { "open" },
+ { "close" },
+ { "openconfirm" },
+ { "lockt" },
+ { "opendowngrade" },
+ { "renew" },
+ { "putrootfh" },
+ { "releaselckown" },
+ { "delegreturn" },
+ { "retdelegremove" },
+ { "retdelegrename1" },
+ { "retdelegrename2" },
+ { "getacl" },
+ { "setacl" },
+ { "noop", "noop", "noop" }
+};
+
+/*
+ * Module name strings.
+ */
+static char *dtnfsclient_accesscache_str = "accesscache";
+static char *dtnfsclient_attrcache_str = "attrcache";
+static char *dtnfsclient_nfs2_str = "nfs2";
+static char *dtnfsclient_nfs3_str = "nfs3";
+static char *dtnfsclient_nfs4_str = "nfs4";
+
+/*
+ * Function name strings.
+ */
+static char *dtnfsclient_flush_str = "flush";
+static char *dtnfsclient_load_str = "load";
+static char *dtnfsclient_get_str = "get";
+
+/*
+ * Name strings.
+ */
+static char *dtnfsclient_done_str = "done";
+static char *dtnfsclient_hit_str = "hit";
+static char *dtnfsclient_miss_str = "miss";
+static char *dtnfsclient_start_str = "start";
+
+static dtrace_pops_t dtnfsclient_pops = {
+ dtnfsclient_provide,
+ NULL,
+ dtnfsclient_enable,
+ dtnfsclient_disable,
+ NULL,
+ NULL,
+ dtnfsclient_getargdesc,
+ NULL,
+ NULL,
+ dtnfsclient_destroy
+};
+
+static dtrace_provider_id_t dtnfsclient_id;
+
+/*
+ * Most probes are generated from the above RPC table, but for access and
+ * attribute caches, we have specific IDs we recognize and handle specially
+ * in various spots.
+ */
+extern uint32_t nfscl_accesscache_flush_done_id;
+extern uint32_t nfscl_accesscache_get_hit_id;
+extern uint32_t nfscl_accesscache_get_miss_id;
+extern uint32_t nfscl_accesscache_load_done_id;
+
+extern uint32_t nfscl_attrcache_flush_done_id;
+extern uint32_t nfscl_attrcache_get_hit_id;
+extern uint32_t nfscl_attrcache_get_miss_id;
+extern uint32_t nfscl_attrcache_load_done_id;
+
+/*
+ * When tracing on a procedure is enabled, the DTrace ID for an RPC event is
+ * stored in one of these two NFS client-allocated arrays; 0 indicates that
+ * the event is not being traced so probes should not be called.
+ *
+ * For simplicity, we allocate both v2, v3 and v4 arrays as NFS_NPROCS + 1, and
+ * the v2, v3 arrays are simply sparse.
+ */
+extern uint32_t nfscl_nfs2_start_probes[NFS_NPROCS + 1];
+extern uint32_t nfscl_nfs2_done_probes[NFS_NPROCS + 1];
+
+extern uint32_t nfscl_nfs3_start_probes[NFS_NPROCS + 1];
+extern uint32_t nfscl_nfs3_done_probes[NFS_NPROCS + 1];
+
+extern uint32_t nfscl_nfs4_start_probes[NFS_NPROCS + 1];
+extern uint32_t nfscl_nfs4_done_probes[NFS_NPROCS + 1];
+
+/*
+ * Look up a DTrace probe ID to see if it's associated with a "done" event --
+ * if so, we will return a fourth argument type of "int".
+ */
+static int
+dtnfs234_isdoneprobe(dtrace_id_t id)
+{
+ int i;
+
+ for (i = 0; i < NFS_NPROCS + 1; i++) {
+ if (dtnfsclient_rpcs[i].nr_v4_id_done == id ||
+ dtnfsclient_rpcs[i].nr_v3_id_done == id ||
+ dtnfsclient_rpcs[i].nr_v2_id_done == id)
+ return (1);
+ }
+ return (0);
+}
+
+static void
+dtnfsclient_getargdesc(void *arg, dtrace_id_t id, void *parg,
+ dtrace_argdesc_t *desc)
+{
+ const char *p = NULL;
+
+ if (id == nfscl_accesscache_flush_done_id ||
+ id == nfscl_attrcache_flush_done_id ||
+ id == nfscl_attrcache_get_miss_id) {
+ switch (desc->dtargd_ndx) {
+ case 0:
+ p = "struct vnode *";
+ break;
+ default:
+ desc->dtargd_ndx = DTRACE_ARGNONE;
+ break;
+ }
+ } else if (id == nfscl_accesscache_get_hit_id ||
+ id == nfscl_accesscache_get_miss_id) {
+ switch (desc->dtargd_ndx) {
+ case 0:
+ p = "struct vnode *";
+ break;
+ case 1:
+ p = "uid_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ default:
+ desc->dtargd_ndx = DTRACE_ARGNONE;
+ break;
+ }
+ } else if (id == nfscl_accesscache_load_done_id) {
+ switch (desc->dtargd_ndx) {
+ case 0:
+ p = "struct vnode *";
+ break;
+ case 1:
+ p = "uid_t";
+ break;
+ case 2:
+ p = "uint32_t";
+ break;
+ case 3:
+ p = "int";
+ break;
+ default:
+ desc->dtargd_ndx = DTRACE_ARGNONE;
+ break;
+ }
+ } else if (id == nfscl_attrcache_get_hit_id) {
+ switch (desc->dtargd_ndx) {
+ case 0:
+ p = "struct vnode *";
+ break;
+ case 1:
+ p = "struct vattr *";
+ break;
+ default:
+ desc->dtargd_ndx = DTRACE_ARGNONE;
+ break;
+ }
+ } else if (id == nfscl_attrcache_load_done_id) {
+ switch (desc->dtargd_ndx) {
+ case 0:
+ p = "struct vnode *";
+ break;
+ case 1:
+ p = "struct vattr *";
+ break;
+ case 2:
+ p = "int";
+ break;
+ default:
+ desc->dtargd_ndx = DTRACE_ARGNONE;
+ break;
+ }
+ } else {
+ switch (desc->dtargd_ndx) {
+ case 0:
+ p = "struct vnode *";
+ break;
+ case 1:
+ p = "struct mbuf *";
+ break;
+ case 2:
+ p = "struct ucred *";
+ break;
+ case 3:
+ p = "int";
+ break;
+ case 4:
+ if (dtnfs234_isdoneprobe(id)) {
+ p = "int";
+ break;
+ }
+ /* FALLSTHROUGH */
+ default:
+ desc->dtargd_ndx = DTRACE_ARGNONE;
+ break;
+ }
+ }
+ if (p != NULL)
+ strlcpy(desc->dtargd_native, p, sizeof(desc->dtargd_native));
+}
+
+static void
+dtnfsclient_provide(void *arg, dtrace_probedesc_t *desc)
+{
+ int i;
+
+ if (desc != NULL)
+ return;
+
+ /*
+ * Register access cache probes.
+ */
+ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
+ dtnfsclient_flush_str, dtnfsclient_done_str) == 0) {
+ nfscl_accesscache_flush_done_id = dtrace_probe_create(
+ dtnfsclient_id, dtnfsclient_accesscache_str,
+ dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL);
+ }
+ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
+ dtnfsclient_get_str, dtnfsclient_hit_str) == 0) {
+ nfscl_accesscache_get_hit_id = dtrace_probe_create(
+ dtnfsclient_id, dtnfsclient_accesscache_str,
+ dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL);
+ }
+ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
+ dtnfsclient_get_str, dtnfsclient_miss_str) == 0) {
+ nfscl_accesscache_get_miss_id = dtrace_probe_create(
+ dtnfsclient_id, dtnfsclient_accesscache_str,
+ dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL);
+ }
+ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_accesscache_str,
+ dtnfsclient_load_str, dtnfsclient_done_str) == 0) {
+ nfscl_accesscache_load_done_id = dtrace_probe_create(
+ dtnfsclient_id, dtnfsclient_accesscache_str,
+ dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL);
+ }
+
+ /*
+ * Register attribute cache probes.
+ */
+ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
+ dtnfsclient_flush_str, dtnfsclient_done_str) == 0) {
+ nfscl_attrcache_flush_done_id = dtrace_probe_create(
+ dtnfsclient_id, dtnfsclient_attrcache_str,
+ dtnfsclient_flush_str, dtnfsclient_done_str, 0, NULL);
+ }
+ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
+ dtnfsclient_get_str, dtnfsclient_hit_str) == 0) {
+ nfscl_attrcache_get_hit_id = dtrace_probe_create(
+ dtnfsclient_id, dtnfsclient_attrcache_str,
+ dtnfsclient_get_str, dtnfsclient_hit_str, 0, NULL);
+ }
+ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
+ dtnfsclient_get_str, dtnfsclient_miss_str) == 0) {
+ nfscl_attrcache_get_miss_id = dtrace_probe_create(
+ dtnfsclient_id, dtnfsclient_attrcache_str,
+ dtnfsclient_get_str, dtnfsclient_miss_str, 0, NULL);
+ }
+ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_attrcache_str,
+ dtnfsclient_load_str, dtnfsclient_done_str) == 0) {
+ nfscl_attrcache_load_done_id = dtrace_probe_create(
+ dtnfsclient_id, dtnfsclient_attrcache_str,
+ dtnfsclient_load_str, dtnfsclient_done_str, 0, NULL);
+ }
+
+ /*
+ * Register NFSv2 RPC procedures; note sparseness check for each slot
+ * in the NFSv3, NFSv4 procnum-indexed array.
+ */
+ for (i = 0; i < NFS_NPROCS + 1; i++) {
+ if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
+ dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
+ dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_start_str) ==
+ 0) {
+ dtnfsclient_rpcs[i].nr_v2_id_start =
+ dtrace_probe_create(dtnfsclient_id,
+ dtnfsclient_nfs2_str,
+ dtnfsclient_rpcs[i].nr_v2_name,
+ dtnfsclient_start_str, 0,
+ &nfscl_nfs2_start_probes[i]);
+ }
+ if (dtnfsclient_rpcs[i].nr_v2_name != NULL &&
+ dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs2_str,
+ dtnfsclient_rpcs[i].nr_v2_name, dtnfsclient_done_str) ==
+ 0) {
+ dtnfsclient_rpcs[i].nr_v2_id_done =
+ dtrace_probe_create(dtnfsclient_id,
+ dtnfsclient_nfs2_str,
+ dtnfsclient_rpcs[i].nr_v2_name,
+ dtnfsclient_done_str, 0,
+ &nfscl_nfs2_done_probes[i]);
+ }
+ }
+
+ /*
+ * Register NFSv3 RPC procedures; note sparseness check for each slot
+ * in the NFSv4 procnum-indexed array.
+ */
+ for (i = 0; i < NFS_NPROCS + 1; i++) {
+ if (dtnfsclient_rpcs[i].nr_v3_name != NULL &&
+ dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
+ dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_start_str) ==
+ 0) {
+ dtnfsclient_rpcs[i].nr_v3_id_start =
+ dtrace_probe_create(dtnfsclient_id,
+ dtnfsclient_nfs3_str,
+ dtnfsclient_rpcs[i].nr_v3_name,
+ dtnfsclient_start_str, 0,
+ &nfscl_nfs3_start_probes[i]);
+ }
+ if (dtnfsclient_rpcs[i].nr_v3_name != NULL &&
+ dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs3_str,
+ dtnfsclient_rpcs[i].nr_v3_name, dtnfsclient_done_str) ==
+ 0) {
+ dtnfsclient_rpcs[i].nr_v3_id_done =
+ dtrace_probe_create(dtnfsclient_id,
+ dtnfsclient_nfs3_str,
+ dtnfsclient_rpcs[i].nr_v3_name,
+ dtnfsclient_done_str, 0,
+ &nfscl_nfs3_done_probes[i]);
+ }
+ }
+
+ /*
+ * Register NFSv4 RPC procedures.
+ */
+ for (i = 0; i < NFS_NPROCS + 1; i++) {
+ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs4_str,
+ dtnfsclient_rpcs[i].nr_v4_name, dtnfsclient_start_str) ==
+ 0) {
+ dtnfsclient_rpcs[i].nr_v4_id_start =
+ dtrace_probe_create(dtnfsclient_id,
+ dtnfsclient_nfs4_str,
+ dtnfsclient_rpcs[i].nr_v4_name,
+ dtnfsclient_start_str, 0,
+ &nfscl_nfs4_start_probes[i]);
+ }
+ if (dtrace_probe_lookup(dtnfsclient_id, dtnfsclient_nfs4_str,
+ dtnfsclient_rpcs[i].nr_v4_name, dtnfsclient_done_str) ==
+ 0) {
+ dtnfsclient_rpcs[i].nr_v4_id_done =
+ dtrace_probe_create(dtnfsclient_id,
+ dtnfsclient_nfs4_str,
+ dtnfsclient_rpcs[i].nr_v4_name,
+ dtnfsclient_done_str, 0,
+ &nfscl_nfs4_done_probes[i]);
+ }
+ }
+}
+
+static void
+dtnfsclient_destroy(void *arg, dtrace_id_t id, void *parg)
+{
+}
+
+static void
+dtnfsclient_enable(void *arg, dtrace_id_t id, void *parg)
+{
+ uint32_t *p = parg;
+ void *f = dtrace_probe;
+
+ if (id == nfscl_accesscache_flush_done_id)
+ dtrace_nfscl_accesscache_flush_done_probe = f;
+ else if (id == nfscl_accesscache_get_hit_id)
+ dtrace_nfscl_accesscache_get_hit_probe = f;
+ else if (id == nfscl_accesscache_get_miss_id)
+ dtrace_nfscl_accesscache_get_miss_probe = f;
+ else if (id == nfscl_accesscache_load_done_id)
+ dtrace_nfscl_accesscache_load_done_probe = f;
+ else if (id == nfscl_attrcache_flush_done_id)
+ dtrace_nfscl_attrcache_flush_done_probe = f;
+ else if (id == nfscl_attrcache_get_hit_id)
+ dtrace_nfscl_attrcache_get_hit_probe = f;
+ else if (id == nfscl_attrcache_get_miss_id)
+ dtrace_nfscl_attrcache_get_miss_probe = f;
+ else if (id == nfscl_attrcache_load_done_id)
+ dtrace_nfscl_attrcache_load_done_probe = f;
+ else
+ *p = id;
+}
+
+static void
+dtnfsclient_disable(void *arg, dtrace_id_t id, void *parg)
+{
+ uint32_t *p = parg;
+
+ if (id == nfscl_accesscache_flush_done_id)
+ dtrace_nfscl_accesscache_flush_done_probe = NULL;
+ else if (id == nfscl_accesscache_get_hit_id)
+ dtrace_nfscl_accesscache_get_hit_probe = NULL;
+ else if (id == nfscl_accesscache_get_miss_id)
+ dtrace_nfscl_accesscache_get_miss_probe = NULL;
+ else if (id == nfscl_accesscache_load_done_id)
+ dtrace_nfscl_accesscache_load_done_probe = NULL;
+ else if (id == nfscl_attrcache_flush_done_id)
+ dtrace_nfscl_attrcache_flush_done_probe = NULL;
+ else if (id == nfscl_attrcache_get_hit_id)
+ dtrace_nfscl_attrcache_get_hit_probe = NULL;
+ else if (id == nfscl_attrcache_get_miss_id)
+ dtrace_nfscl_attrcache_get_miss_probe = NULL;
+ else if (id == nfscl_attrcache_load_done_id)
+ dtrace_nfscl_attrcache_load_done_probe = NULL;
+ else
+ *p = 0;
+}
+
+static void
+dtnfsclient_load(void *dummy)
+{
+
+ if (dtrace_register("nfscl", &dtnfsclient_attr,
+ DTRACE_PRIV_USER, NULL, &dtnfsclient_pops, NULL,
+ &dtnfsclient_id) != 0)
+ return;
+
+ dtrace_nfscl_nfs234_start_probe =
+ (dtrace_nfsclient_nfs23_start_probe_func_t)dtrace_probe;
+ dtrace_nfscl_nfs234_done_probe =
+ (dtrace_nfsclient_nfs23_done_probe_func_t)dtrace_probe;
+}
+
+
+static int
+dtnfsclient_unload()
+{
+
+ dtrace_nfscl_nfs234_start_probe = NULL;
+ dtrace_nfscl_nfs234_done_probe = NULL;
+
+ return (dtrace_unregister(dtnfsclient_id));
+}
+
+static int
+dtnfsclient_modevent(module_t mod __unused, int type, void *data __unused)
+{
+ int error = 0;
+
+ switch (type) {
+ case MOD_LOAD:
+ break;
+
+ case MOD_UNLOAD:
+ break;
+
+ case MOD_SHUTDOWN:
+ break;
+
+ default:
+ error = EOPNOTSUPP;
+ break;
+ }
+
+ return (error);
+}
+
+SYSINIT(dtnfsclient_load, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
+ dtnfsclient_load, NULL);
+SYSUNINIT(dtnfsclient_unload, SI_SUB_DTRACE_PROVIDER, SI_ORDER_ANY,
+ dtnfsclient_unload, NULL);
+
+DEV_MODULE(dtnfscl, dtnfsclient_modevent, NULL);
+MODULE_VERSION(dtnfscl, 1);
+MODULE_DEPEND(dtnfscl, dtrace, 1, 1, 1);
+MODULE_DEPEND(dtnfscl, opensolaris, 1, 1, 1);
+MODULE_DEPEND(dtnfscl, nfscl, 1, 1, 1);
+MODULE_DEPEND(dtnfscl, nfscommon, 1, 1, 1);
diff --git a/sys/fs/nfsclient/nfs_clkrpc.c b/sys/fs/nfsclient/nfs_clkrpc.c
index c4f7e94..0cd41b3 100644
--- a/sys/fs/nfsclient/nfs_clkrpc.c
+++ b/sys/fs/nfsclient/nfs_clkrpc.c
@@ -215,12 +215,9 @@ nfscbd_addsock(struct file *fp)
int
nfscbd_nfsd(struct thread *td, struct nfsd_nfscbd_args *args)
{
-#ifdef KGSSAPI
char principal[128];
int error;
-#endif
-#ifdef KGSSAPI
if (args != NULL) {
error = copyinstr(args->principal, principal,
sizeof(principal), NULL);
@@ -229,7 +226,6 @@ nfscbd_nfsd(struct thread *td, struct nfsd_nfscbd_args *args)
} else {
principal[0] = '\0';
}
-#endif
/*
* Only the first nfsd actually does any work. The RPC code
@@ -244,20 +240,16 @@ nfscbd_nfsd(struct thread *td, struct nfsd_nfscbd_args *args)
NFSD_UNLOCK();
-#ifdef KGSSAPI
if (principal[0] != '\0')
- rpc_gss_set_svc_name(principal, "kerberosv5",
+ rpc_gss_set_svc_name_call(principal, "kerberosv5",
GSS_C_INDEFINITE, NFS_CALLBCKPROG, NFSV4_CBVERS);
-#endif
nfscbd_pool->sp_minthreads = 4;
nfscbd_pool->sp_maxthreads = 4;
svc_run(nfscbd_pool);
-#ifdef KGSSAPI
- rpc_gss_clear_svc_name(NFS_CALLBCKPROG, NFSV4_CBVERS);
-#endif
+ rpc_gss_clear_svc_name_call(NFS_CALLBCKPROG, NFSV4_CBVERS);
NFSD_LOCK();
nfs_numnfscbd--;
diff --git a/sys/fs/nfsclient/nfs_clnode.c b/sys/fs/nfsclient/nfs_clnode.c
index d4d652e..d15de6e 100644
--- a/sys/fs/nfsclient/nfs_clnode.c
+++ b/sys/fs/nfsclient/nfs_clnode.c
@@ -35,6 +35,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_kdtrace.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/fcntl.h>
@@ -53,6 +55,7 @@ __FBSDID("$FreeBSD$");
#include <fs/nfsclient/nfsnode.h>
#include <fs/nfsclient/nfsmount.h>
#include <fs/nfsclient/nfs.h>
+#include <fs/nfsclient/nfs_kdtrace.h>
#include <nfs/nfs_lock.h>
@@ -300,7 +303,9 @@ ncl_invalcaches(struct vnode *vp)
mtx_lock(&np->n_mtx);
for (i = 0; i < NFS_ACCESSCACHESIZE; i++)
np->n_accesscache[i].stamp = 0;
+ KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp);
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
mtx_unlock(&np->n_mtx);
}
diff --git a/sys/fs/nfsclient/nfs_clport.c b/sys/fs/nfsclient/nfs_clport.c
index 0c3a4c9..0538382 100644
--- a/sys/fs/nfsclient/nfs_clport.c
+++ b/sys/fs/nfsclient/nfs_clport.c
@@ -34,6 +34,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_kdtrace.h"
+
/*
* generally, I don't like #includes inside .h files, but it seems to
* be the easiest way to handle the port.
@@ -43,6 +45,26 @@ __FBSDID("$FreeBSD$");
#include <netinet/if_ether.h>
#include <net/if_types.h>
+#include <fs/nfsclient/nfs_kdtrace.h>
+
+#ifdef KDTRACE_HOOKS
+dtrace_nfsclient_attrcache_flush_probe_func_t
+ dtrace_nfscl_attrcache_flush_done_probe;
+uint32_t nfscl_attrcache_flush_done_id;
+
+dtrace_nfsclient_attrcache_get_hit_probe_func_t
+ dtrace_nfscl_attrcache_get_hit_probe;
+uint32_t nfscl_attrcache_get_hit_id;
+
+dtrace_nfsclient_attrcache_get_miss_probe_func_t
+ dtrace_nfscl_attrcache_get_miss_probe;
+uint32_t nfscl_attrcache_get_miss_id;
+
+dtrace_nfsclient_attrcache_load_probe_func_t
+ dtrace_nfscl_attrcache_load_done_probe;
+uint32_t nfscl_attrcache_load_done_id;
+#endif /* !KDTRACE_HOOKS */
+
extern u_int32_t newnfs_true, newnfs_false, newnfs_xdrneg1;
extern struct vop_vector newnfs_vnodeops;
extern struct vop_vector newnfs_fifoops;
@@ -407,6 +429,7 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
*/
vap->va_size = np->n_size;
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
} else if (np->n_flag & NMODIFIED) {
/*
* We've modified the file: Use the larger
@@ -439,9 +462,11 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
* We detect this by for the mtime moving back. We invalidate the
* attrcache when this happens.
*/
- if (timespeccmp(&mtime_save, &vap->va_mtime, >))
+ if (timespeccmp(&mtime_save, &vap->va_mtime, >)) {
/* Size changed or mtime went backwards */
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
+ }
if (vaper != NULL) {
NFSBCOPY((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
if (np->n_flag & NCHG) {
@@ -451,6 +476,10 @@ nfscl_loadattrcache(struct vnode **vpp, struct nfsvattr *nap, void *nvaper,
vaper->va_mtime = np->n_mtim;
}
}
+#ifdef KDTRACE_HOOKS
+ if (np->n_attrstamp != 0)
+ KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, vap, 0);
+#endif
NFSUNLOCKNODE(np);
return (0);
}
@@ -500,7 +529,7 @@ nfscl_fillclid(u_int64_t clval, char *uuid, u_int8_t *cp, u_int16_t idlen)
* Fill in a lock owner name. For now, pid + the process's creation time.
*/
void
-nfscl_filllockowner(struct thread *td, u_int8_t *cp)
+nfscl_filllockowner(void *id, u_int8_t *cp, int flags)
{
union {
u_int32_t lval;
@@ -508,37 +537,35 @@ nfscl_filllockowner(struct thread *td, u_int8_t *cp)
} tl;
struct proc *p;
-if (td == NULL) {
- printf("NULL td\n");
- bzero(cp, 12);
- return;
-}
- p = td->td_proc;
-if (p == NULL) {
- printf("NULL pid\n");
- bzero(cp, 12);
- return;
-}
- tl.lval = p->p_pid;
- *cp++ = tl.cval[0];
- *cp++ = tl.cval[1];
- *cp++ = tl.cval[2];
- *cp++ = tl.cval[3];
-if (p->p_stats == NULL) {
- printf("pstats null\n");
- bzero(cp, 8);
- return;
-}
- tl.lval = p->p_stats->p_start.tv_sec;
- *cp++ = tl.cval[0];
- *cp++ = tl.cval[1];
- *cp++ = tl.cval[2];
- *cp++ = tl.cval[3];
- tl.lval = p->p_stats->p_start.tv_usec;
- *cp++ = tl.cval[0];
- *cp++ = tl.cval[1];
- *cp++ = tl.cval[2];
- *cp = tl.cval[3];
+ if (id == NULL) {
+ printf("NULL id\n");
+ bzero(cp, NFSV4CL_LOCKNAMELEN);
+ return;
+ }
+ if ((flags & F_POSIX) != 0) {
+ p = (struct proc *)id;
+ tl.lval = p->p_pid;
+ *cp++ = tl.cval[0];
+ *cp++ = tl.cval[1];
+ *cp++ = tl.cval[2];
+ *cp++ = tl.cval[3];
+ tl.lval = p->p_stats->p_start.tv_sec;
+ *cp++ = tl.cval[0];
+ *cp++ = tl.cval[1];
+ *cp++ = tl.cval[2];
+ *cp++ = tl.cval[3];
+ tl.lval = p->p_stats->p_start.tv_usec;
+ *cp++ = tl.cval[0];
+ *cp++ = tl.cval[1];
+ *cp++ = tl.cval[2];
+ *cp = tl.cval[3];
+ } else if ((flags & F_FLOCK) != 0) {
+ bcopy(&id, cp, sizeof(id));
+ bzero(&cp[sizeof(id)], NFSV4CL_LOCKNAMELEN - sizeof(id));
+ } else {
+ printf("nfscl_filllockowner: not F_POSIX or F_FLOCK\n");
+ bzero(cp, NFSV4CL_LOCKNAMELEN);
+ }
}
/*
@@ -943,6 +970,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
sad.sin_family = AF_INET;
sad.sin_len = sizeof (struct sockaddr_in);
sad.sin_addr.s_addr = sin->sin_addr.s_addr;
+ CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
rt = rtalloc1((struct sockaddr *)&sad, 0, 0UL);
if (rt != NULL) {
if (rt->rt_ifp != NULL &&
@@ -956,6 +984,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
}
RTFREE_LOCKED(rt);
}
+ CURVNET_RESTORE();
#ifdef INET6
} else if (nmp->nm_nam->sa_family == AF_INET6) {
struct sockaddr_in6 sad6, *sin6;
@@ -966,6 +995,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
sad6.sin6_family = AF_INET6;
sad6.sin6_len = sizeof (struct sockaddr_in6);
sad6.sin6_addr = sin6->sin6_addr;
+ CURVNET_SET(CRED_TO_VNET(nmp->nm_sockreq.nr_cred));
rt = rtalloc1((struct sockaddr *)&sad6, 0, 0UL);
if (rt != NULL) {
if (rt->rt_ifp != NULL &&
@@ -980,6 +1010,7 @@ nfscl_getmyip(struct nfsmount *nmp, int *isinet6p)
}
RTFREE_LOCKED(rt);
}
+ CURVNET_RESTORE();
#endif
}
return (retp);
diff --git a/sys/fs/nfsclient/nfs_clrpcops.c b/sys/fs/nfsclient/nfs_clrpcops.c
index 7af0852..5d83d0b 100644
--- a/sys/fs/nfsclient/nfs_clrpcops.c
+++ b/sys/fs/nfsclient/nfs_clrpcops.c
@@ -68,7 +68,7 @@ static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
-static int nfsrpc_writerpc(vnode_t , struct uio *, int *, u_char *,
+static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
void *);
static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
@@ -1369,7 +1369,7 @@ nfsmout:
* will then deadlock.
*/
APPLESTATIC int
-nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, u_char *verfp,
+nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
void *stuff, int called_from_strategy)
{
@@ -1382,6 +1382,7 @@ nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, u_char *verfp,
nfsv4stateid_t stateid;
void *lckp;
+ *must_commit = 0;
if (nmp->nm_clp != NULL)
clidrev = nmp->nm_clp->nfsc_clientidrev;
newcred = cred;
@@ -1412,7 +1413,7 @@ nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, u_char *verfp,
if (nostateid)
error = 0;
else
- error = nfsrpc_writerpc(vp, uiop, iomode, verfp,
+ error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
newcred, &stateid, p, nap, attrflagp, stuff);
if (error == NFSERR_STALESTATEID)
nfscl_initiate_recovery(nmp->nm_clp);
@@ -1447,7 +1448,7 @@ nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, u_char *verfp,
*/
static int
nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
- u_char *verfp, struct ucred *cred, nfsv4stateid_t *stateidp,
+ int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
{
u_int32_t *tl;
@@ -1585,14 +1586,16 @@ nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
else if (committed == NFSWRITE_DATASYNC &&
commit == NFSWRITE_UNSTABLE)
committed = commit;
- if (verfp != NULL)
- NFSBCOPY((caddr_t)tl, verfp, NFSX_VERF);
NFSLOCKMNT(nmp);
if (!NFSHASWRITEVERF(nmp)) {
NFSBCOPY((caddr_t)tl,
(caddr_t)&nmp->nm_verf[0],
NFSX_VERF);
NFSSETWRITEVERF(nmp);
+ } else if (NFSBCMP(tl, nmp->nm_verf,
+ NFSX_VERF)) {
+ *must_commit = 1;
+ NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
}
NFSUNLOCKMNT(nmp);
}
@@ -3456,7 +3459,7 @@ nfsmout:
*/
APPLESTATIC int
nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
- int reclaim, struct ucred *cred, NFSPROC_T *p)
+ int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
{
struct nfscllockowner *lp;
struct nfsclclient *clp;
@@ -3508,11 +3511,11 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
error = nfscl_getcl(vp, cred, p, &clp);
if (error)
return (error);
- error = nfscl_lockt(vp, clp, off, len, fl, p);
+ error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
if (!error) {
clidrev = clp->nfsc_clientidrev;
error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
- p);
+ p, id, flags);
} else if (error == -1) {
error = 0;
}
@@ -3527,7 +3530,7 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
return (error);
do {
error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
- clp, &lp, &dorpc);
+ clp, id, flags, &lp, &dorpc);
/*
* If it returns a NULL lp, we're done.
*/
@@ -3535,7 +3538,7 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
if (callcnt == 0)
nfscl_clientrelease(clp);
else
- nfscl_releasealllocks(clp, vp, p);
+ nfscl_releasealllocks(clp, vp, p, id, flags);
return (error);
}
if (nmp->nm_clp != NULL)
@@ -3569,10 +3572,10 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
}
callcnt++;
} while (error == 0 && nd->nd_repstat == 0);
- nfscl_releasealllocks(clp, vp, p);
+ nfscl_releasealllocks(clp, vp, p, id, flags);
} else if (op == F_SETLK) {
error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
- NULL, 0, NULL, NULL, &lp, &newone, &donelocally);
+ NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
if (error || donelocally) {
return (error);
}
@@ -3622,7 +3625,7 @@ nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
APPLESTATIC int
nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
- struct ucred *cred, NFSPROC_T *p)
+ struct ucred *cred, NFSPROC_T *p, void *id, int flags)
{
u_int32_t *tl;
int error, type, size;
@@ -3640,7 +3643,7 @@ nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
tl += 2;
*tl++ = clp->nfsc_clientid.lval[0];
*tl = clp->nfsc_clientid.lval[1];
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
(void) nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN);
error = nfscl_request(nd, vp, p, cred, NULL);
if (error)
diff --git a/sys/fs/nfsclient/nfs_clstate.c b/sys/fs/nfsclient/nfs_clstate.c
index 8e9aa6a..aa81437 100644
--- a/sys/fs/nfsclient/nfs_clstate.c
+++ b/sys/fs/nfsclient/nfs_clstate.c
@@ -226,7 +226,7 @@ nfscl_open(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t amode, int usedeleg,
* If none found, add the new one or return error, depending upon
* "create".
*/
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(p->td_proc, own, F_POSIX);
NFSLOCKCLSTATE();
dp = NULL;
/* First check the delegation list */
@@ -521,7 +521,7 @@ nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode,
* If p != NULL, we want to search the parentage tree
* for a matching OpenOwner and use that.
*/
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(p->td_proc, own, F_POSIX);
error = nfscl_getopen(&clp->nfsc_owner, nfhp, fhlen, NULL, p,
mode, NULL, &op);
if (error == 0) {
@@ -596,7 +596,7 @@ nfscl_getopen(struct nfsclownerhead *ohp, u_int8_t *nfhp, int fhlen,
op = NULL;
while (op == NULL && (nproc != NULL || rown != NULL)) {
if (nproc != NULL) {
- nfscl_filllockowner(nproc, own);
+ nfscl_filllockowner(nproc->td_proc, own, F_POSIX);
ownp = own;
} else {
ownp = rown;
@@ -687,11 +687,14 @@ nfscl_getcl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
struct nfsclclient *clp;
struct nfsclclient *newclp = NULL;
struct nfscllockowner *lp, *nlp;
- struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
+ struct mount *mp;
+ struct nfsmount *nmp;
char uuid[HOSTUUIDLEN];
int igotlock = 0, error, trystalecnt, clidinusedelay, i;
u_int16_t idlen = 0;
+ mp = vnode_mount(vp);
+ nmp = VFSTONFS(mp);
if (cred != NULL) {
getcredhostuuid(cred, uuid, sizeof uuid);
idlen = strlen(uuid);
@@ -704,6 +707,17 @@ nfscl_getcl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
M_WAITOK);
}
NFSLOCKCLSTATE();
+ /*
+ * If a forced dismount is already in progress, don't
+ * allocate a new clientid and get out now. For the case where
+ * clp != NULL, this is a harmless optimization.
+ */
+ if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ NFSUNLOCKCLSTATE();
+ if (newclp != NULL)
+ free(newclp, M_NFSCLCLIENT);
+ return (EBADF);
+ }
clp = nmp->nm_clp;
if (clp == NULL) {
if (newclp == NULL) {
@@ -736,9 +750,21 @@ nfscl_getcl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
NFSLOCKCLSTATE();
while ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0 && !igotlock)
igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
- NFSCLSTATEMUTEXPTR);
+ NFSCLSTATEMUTEXPTR, mp);
if (!igotlock)
- nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR);
+ nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR, mp);
+ if (igotlock == 0 && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ /*
+ * Both nfsv4_lock() and nfsv4_getref() know to check
+ * for MNTK_UNMOUNTF and return without sleeping to
+ * wait for the exclusive lock to be released, since it
+ * might be held by nfscl_umount() and we need to get out
+ * now for that case and not wait until nfscl_umount()
+ * releases it.
+ */
+ NFSUNLOCKCLSTATE();
+ return (EBADF);
+ }
NFSUNLOCKCLSTATE();
/*
@@ -855,7 +881,7 @@ nfscl_clientrelease(struct nfsclclient *clp)
APPLESTATIC int
nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
short type, struct ucred *cred, NFSPROC_T *p, struct nfsclclient *rclp,
- int recovery, u_int8_t *rownp, u_int8_t *ropenownp,
+ int recovery, void *id, int flags, u_int8_t *rownp, u_int8_t *ropenownp,
struct nfscllockowner **lpp, int *newonep, int *donelocallyp)
{
struct nfscllockowner *lp;
@@ -916,7 +942,7 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
if (recovery) {
ownp = rownp;
} else {
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
ownp = own;
}
if (!recovery) {
@@ -1053,7 +1079,8 @@ nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
APPLESTATIC int
nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
__unused struct ucred *cred, NFSPROC_T *p, int callcnt,
- struct nfsclclient *clp, struct nfscllockowner **lpp, int *dorpcp)
+ struct nfsclclient *clp, void *id, int flags,
+ struct nfscllockowner **lpp, int *dorpcp)
{
struct nfscllockowner *lp;
struct nfsclowner *owp;
@@ -1090,7 +1117,7 @@ nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
*other_lop = *nlop;
}
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
dp = NULL;
NFSLOCKCLSTATE();
if (callcnt == 0)
@@ -1162,7 +1189,8 @@ nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
* Release all lockowners marked in progess for this process and file.
*/
APPLESTATIC void
-nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p)
+nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p,
+ void *id, int flags)
{
struct nfsclowner *owp;
struct nfsclopen *op;
@@ -1171,7 +1199,7 @@ nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p)
u_int8_t own[NFSV4CL_LOCKNAMELEN];
np = VTONFS(vp);
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
NFSLOCKCLSTATE();
LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
@@ -1200,7 +1228,7 @@ nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p)
*/
APPLESTATIC int
nfscl_checkwritelocked(vnode_t vp, struct flock *fl,
- struct ucred *cred, NFSPROC_T *p)
+ struct ucred *cred, NFSPROC_T *p, void *id, int flags)
{
struct nfsclowner *owp;
struct nfscllockowner *lp;
@@ -1240,7 +1268,7 @@ nfscl_checkwritelocked(vnode_t vp, struct flock *fl,
error = nfscl_getcl(vp, cred, p, &clp);
if (error)
return (1);
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
NFSLOCKCLSTATE();
/*
@@ -1615,7 +1643,7 @@ nfscl_cleanup(NFSPROC_T *p)
if (!nfscl_inited)
return;
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(p->td_proc, own, F_POSIX);
NFSLOCKCLSTATE();
/*
@@ -1713,6 +1741,7 @@ nfscl_cleanupkext(struct nfsclclient *clp)
}
#endif /* APPLEKEXT || __FreeBSD__ */
+static int fake_global; /* Used to force visibility of MNTK_UNMOUNTF */
/*
* Called from nfs umount to free up the clientid.
*/
@@ -1723,6 +1752,33 @@ nfscl_umount(struct nfsmount *nmp, NFSPROC_T *p)
struct ucred *cred;
int igotlock;
+ /*
+ * For the case that matters, this is the thread that set
+ * MNTK_UNMOUNTF, so it will see it set. The code that follows is
+ * done to ensure that any thread executing nfscl_getcl() after
+ * this time, will see MNTK_UNMOUNTF set. nfscl_getcl() uses the
+ * mutex for NFSLOCKCLSTATE(), so it is "m" for the following
+ * explanation, courtesy of Alan Cox.
+ * What follows is a snippet from Alan Cox's email at:
+ * http://docs.FreeBSD.org/cgi/
+ * mid.cgi?BANLkTikR3d65zPHo9==08ZfJ2vmqZucEvw
+ *
+ * 1. Set MNTK_UNMOUNTF
+ * 2. Acquire a standard FreeBSD mutex "m".
+ * 3. Update some data structures.
+ * 4. Release mutex "m".
+ *
+ * Then, other threads that acquire "m" after step 4 has occurred will
+ * see MNTK_UNMOUNTF as set. But, other threads that beat thread X to
+ * step 2 may or may not see MNTK_UNMOUNTF as set.
+ */
+ NFSLOCKCLSTATE();
+ if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ fake_global++;
+ NFSUNLOCKCLSTATE();
+ NFSLOCKCLSTATE();
+ }
+
clp = nmp->nm_clp;
if (clp != NULL) {
if ((clp->nfsc_flags & NFSCLFLAGS_INITED) == 0)
@@ -1734,12 +1790,16 @@ nfscl_umount(struct nfsmount *nmp, NFSPROC_T *p)
*/
clp->nfsc_flags |= NFSCLFLAGS_UMOUNT;
while (clp->nfsc_flags & NFSCLFLAGS_HASTHREAD)
- (void) tsleep((caddr_t)clp, PWAIT, "nfsclumnt", hz);
+ (void)mtx_sleep(clp, NFSCLSTATEMUTEXPTR, PWAIT,
+ "nfsclumnt", hz);
- NFSLOCKCLSTATE();
+ /*
+ * Now, get the exclusive lock on the client state, so
+ * that no uses of the state are still in progress.
+ */
do {
igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
- NFSCLSTATEMUTEXPTR);
+ NFSCLSTATEMUTEXPTR, NULL);
} while (!igotlock);
NFSUNLOCKCLSTATE();
@@ -1756,8 +1816,8 @@ nfscl_umount(struct nfsmount *nmp, NFSPROC_T *p)
nmp->nm_clp = NULL;
NFSFREECRED(cred);
FREE((caddr_t)clp, M_NFSCLCLIENT);
- }
-
+ } else
+ NFSUNLOCKCLSTATE();
}
/*
@@ -1790,7 +1850,7 @@ nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p)
clp->nfsc_flags |= NFSCLFLAGS_RECVRINPROG;
do {
igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
- NFSCLSTATEMUTEXPTR);
+ NFSCLSTATEMUTEXPTR, NULL);
} while (!igotlock);
NFSUNLOCKCLSTATE();
@@ -2105,7 +2165,7 @@ nfscl_hasexpired(struct nfsclclient *clp, u_int32_t clidrev, NFSPROC_T *p)
clp->nfsc_flags |= NFSCLFLAGS_EXPIREIT;
do {
igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
- NFSCLSTATEMUTEXPTR);
+ NFSCLSTATEMUTEXPTR, NULL);
} while (!igotlock && (clp->nfsc_flags & NFSCLFLAGS_EXPIREIT));
if ((clp->nfsc_flags & NFSCLFLAGS_EXPIREIT) == 0) {
if (igotlock)
@@ -2464,7 +2524,7 @@ tryagain:
}
while (!igotlock) {
igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
- &islept, NFSCLSTATEMUTEXPTR);
+ &islept, NFSCLSTATEMUTEXPTR, NULL);
if (islept)
goto tryagain;
}
@@ -2556,14 +2616,18 @@ tryagain:
}
#endif /* APPLEKEXT || __FreeBSD__ */
+ NFSLOCKCLSTATE();
if ((clp->nfsc_flags & NFSCLFLAGS_RECOVER) == 0)
- (void) tsleep((caddr_t)clp, PWAIT, "nfscl", hz);
+ (void)mtx_sleep(clp, NFSCLSTATEMUTEXPTR, PWAIT, "nfscl",
+ hz);
if (clp->nfsc_flags & NFSCLFLAGS_UMOUNT) {
- NFSFREECRED(cred);
clp->nfsc_flags &= ~NFSCLFLAGS_HASTHREAD;
+ NFSUNLOCKCLSTATE();
+ NFSFREECRED(cred);
wakeup((caddr_t)clp);
return;
}
+ NFSUNLOCKCLSTATE();
}
}
@@ -3260,7 +3324,7 @@ nfscl_checkconflict(struct nfscllockownerhead *lhp, struct nfscllock *nlop,
*/
APPLESTATIC int
nfscl_lockt(vnode_t vp, struct nfsclclient *clp, u_int64_t off,
- u_int64_t len, struct flock *fl, NFSPROC_T *p)
+ u_int64_t len, struct flock *fl, NFSPROC_T *p, void *id, int flags)
{
struct nfscllock *lop, nlck;
struct nfscldeleg *dp;
@@ -3278,7 +3342,7 @@ nfscl_lockt(vnode_t vp, struct nfsclclient *clp, u_int64_t off,
return (NFSERR_INVAL);
}
np = VTONFS(vp);
- nfscl_filllockowner(p, own);
+ nfscl_filllockowner(id, own, flags);
NFSLOCKCLSTATE();
dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
error = nfscl_localconflict(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
@@ -3553,7 +3617,7 @@ nfscl_relock(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp,
off = lop->nfslo_first;
len = lop->nfslo_end - lop->nfslo_first;
error = nfscl_getbytelock(vp, off, len, lop->nfslo_type, cred, p,
- clp, 1, lp->nfsl_owner, lp->nfsl_openowner, &nlp, &newone,
+ clp, 1, NULL, 0, lp->nfsl_owner, lp->nfsl_openowner, &nlp, &newone,
&donelocally);
if (error || donelocally)
return (error);
@@ -3864,7 +3928,7 @@ nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp)
islept = 0;
while (!igotlock) {
igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
- &islept, NFSCLSTATEMUTEXPTR);
+ &islept, NFSCLSTATEMUTEXPTR, NULL);
if (islept)
break;
}
@@ -3963,7 +4027,7 @@ nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp,
islept = 0;
while (!igotlock) {
igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
- &islept, NFSCLSTATEMUTEXPTR);
+ &islept, NFSCLSTATEMUTEXPTR, NULL);
if (islept)
break;
}
@@ -4043,7 +4107,7 @@ nfscl_getref(struct nfsmount *nmp)
NFSUNLOCKCLSTATE();
return (0);
}
- nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR);
+ nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR, NULL);
NFSUNLOCKCLSTATE();
return (1);
}
diff --git a/sys/fs/nfsclient/nfs_clsubs.c b/sys/fs/nfsclient/nfs_clsubs.c
index 0c05631..214dfb7 100644
--- a/sys/fs/nfsclient/nfs_clsubs.c
+++ b/sys/fs/nfsclient/nfs_clsubs.c
@@ -35,6 +35,8 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_kdtrace.h"
+
/*
* These functions support the macros and help fiddle mbuf chains for
* the nfs op functions. They do things like create the rpc header and
@@ -68,6 +70,7 @@ __FBSDID("$FreeBSD$");
#include <fs/nfsclient/nfsnode.h>
#include <fs/nfsclient/nfsmount.h>
#include <fs/nfsclient/nfs.h>
+#include <fs/nfsclient/nfs_kdtrace.h>
#include <netinet/in.h>
@@ -238,6 +241,7 @@ ncl_getattrcache(struct vnode *vp, struct vattr *vaper)
#ifdef NFS_ACDEBUG
mtx_unlock(&Giant); /* ncl_printf() */
#endif
+ KDTRACE_NFS_ATTRCACHE_GET_MISS(vp);
return( ENOENT);
}
newnfsstats.attrcache_hits++;
@@ -267,6 +271,7 @@ ncl_getattrcache(struct vnode *vp, struct vattr *vaper)
#ifdef NFS_ACDEBUG
mtx_unlock(&Giant); /* ncl_printf() */
#endif
+ KDTRACE_NFS_ATTRCACHE_GET_HIT(vp, vap);
return (0);
}
diff --git a/sys/fs/nfsclient/nfs_clvfsops.c b/sys/fs/nfsclient/nfs_clvfsops.c
index 84725dd..d962a54 100644
--- a/sys/fs/nfsclient/nfs_clvfsops.c
+++ b/sys/fs/nfsclient/nfs_clvfsops.c
@@ -1458,10 +1458,20 @@ nfs_sync(struct mount *mp, int waitfor)
td = curthread;
+ MNT_ILOCK(mp);
+ /*
+ * If a forced dismount is in progress, return from here so that
+ * the umount(2) syscall doesn't get stuck in VFS_SYNC() before
+ * calling VFS_UNMOUNT().
+ */
+ if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
+ MNT_IUNLOCK(mp);
+ return (EBADF);
+ }
+
/*
* Force stale buffer cache information to be flushed.
*/
- MNT_ILOCK(mp);
loop:
MNT_VNODE_FOREACH(vp, mp, mvp) {
VI_LOCK(vp);
diff --git a/sys/fs/nfsclient/nfs_clvnops.c b/sys/fs/nfsclient/nfs_clvnops.c
index 1b08582..0a1d6a2 100644
--- a/sys/fs/nfsclient/nfs_clvnops.c
+++ b/sys/fs/nfsclient/nfs_clvnops.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
* vnode op calls for Sun NFS version 2, 3 and 4
*/
+#include "opt_kdtrace.h"
#include "opt_inet.h"
#include <sys/param.h>
@@ -70,6 +71,7 @@ __FBSDID("$FreeBSD$");
#include <fs/nfsclient/nfsnode.h>
#include <fs/nfsclient/nfsmount.h>
#include <fs/nfsclient/nfs.h>
+#include <fs/nfsclient/nfs_kdtrace.h>
#include <net/if.h>
#include <netinet/in.h>
@@ -77,6 +79,24 @@ __FBSDID("$FreeBSD$");
#include <nfs/nfs_lock.h>
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+
+dtrace_nfsclient_accesscache_flush_probe_func_t
+ dtrace_nfscl_accesscache_flush_done_probe;
+uint32_t nfscl_accesscache_flush_done_id;
+
+dtrace_nfsclient_accesscache_get_probe_func_t
+ dtrace_nfscl_accesscache_get_hit_probe,
+ dtrace_nfscl_accesscache_get_miss_probe;
+uint32_t nfscl_accesscache_get_hit_id;
+uint32_t nfscl_accesscache_get_miss_id;
+
+dtrace_nfsclient_accesscache_load_probe_func_t
+ dtrace_nfscl_accesscache_load_done_probe;
+uint32_t nfscl_accesscache_load_done_id;
+#endif /* !KDTRACE_HOOKS */
+
/* Defs */
#define TRUE 1
#define FALSE 0
@@ -298,9 +318,15 @@ nfs34_access_otw(struct vnode *vp, int wmode, struct thread *td,
mtx_unlock(&np->n_mtx);
if (retmode != NULL)
*retmode = rmode;
+ KDTRACE_NFS_ACCESSCACHE_LOAD_DONE(vp, cred->cr_uid, rmode, 0);
} else if (NFS_ISV4(vp)) {
error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
}
+#ifdef KDTRACE_HOOKS
+ if (error != 0)
+ KDTRACE_NFS_ACCESSCACHE_LOAD_DONE(vp, cred->cr_uid, 0,
+ error);
+#endif
return (error);
}
@@ -397,6 +423,14 @@ nfs_access(struct vop_access_args *ap)
}
}
mtx_unlock(&np->n_mtx);
+#ifdef KDTRACE_HOOKS
+ if (gotahit != 0)
+ KDTRACE_NFS_ACCESSCACHE_GET_HIT(vp,
+ ap->a_cred->cr_uid, mode);
+ else
+ KDTRACE_NFS_ACCESSCACHE_GET_MISS(vp,
+ ap->a_cred->cr_uid, mode);
+#endif
if (gotahit == 0) {
/*
* Either a no, or a don't know. Go to the wire.
@@ -507,6 +541,7 @@ nfs_open(struct vop_open_args *ap)
}
mtx_lock(&np->n_mtx);
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
if (vp->v_type == VDIR)
np->n_direofoffset = 0;
mtx_unlock(&np->n_mtx);
@@ -692,8 +727,10 @@ nfs_close(struct vop_close_args *ap)
* is the cause of some caching/coherency issue that might
* crop up.)
*/
- if (VFSTONFS(vp->v_mount)->nm_negnametimeo == 0)
+ if (VFSTONFS(vp->v_mount)->nm_negnametimeo == 0) {
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
+ }
if (np->n_flag & NWRITEERR) {
np->n_flag &= ~NWRITEERR;
error = np->n_error;
@@ -949,6 +986,7 @@ nfs_setattrrpc(struct vnode *vp, struct vattr *vap, struct ucred *cred,
np->n_accesscache[i].stamp = 0;
np->n_flag |= NDELEGMOD;
mtx_unlock(&np->n_mtx);
+ KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp);
}
error = nfsrpc_setattr(vp, vap, NULL, cred, td, &nfsva, &attrflag,
NULL);
@@ -1030,6 +1068,7 @@ nfs_lookup(struct vop_lookup_args *ap)
!(newnp->n_flag & NMODIFIED)) {
mtx_lock(&newnp->n_mtx);
newnp->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp);
mtx_unlock(&newnp->n_mtx);
}
if (nfscl_nodeleg(newvp, 0) == 0 ||
@@ -1233,6 +1272,7 @@ nfs_lookup(struct vop_lookup_args *ap)
*/
mtx_lock(&np->n_mtx);
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(newvp);
mtx_unlock(&np->n_mtx);
}
}
@@ -1332,19 +1372,9 @@ ncl_writerpc(struct vnode *vp, struct uio *uiop, struct ucred *cred,
{
struct nfsvattr nfsva;
int error = 0, attrflag, ret;
- u_char verf[NFSX_VERF];
- struct nfsmount *nmp = VFSTONFS(vp->v_mount);
- *must_commit = 0;
- error = nfsrpc_write(vp, uiop, iomode, verf, cred,
+ error = nfsrpc_write(vp, uiop, iomode, must_commit, cred,
uiop->uio_td, &nfsva, &attrflag, NULL, called_from_strategy);
- NFSLOCKMNT(nmp);
- if (!error && NFSHASWRITEVERF(nmp) &&
- NFSBCMP(verf, nmp->nm_verf, NFSX_VERF)) {
- *must_commit = 1;
- NFSBCOPY(verf, nmp->nm_verf, NFSX_VERF);
- }
- NFSUNLOCKMNT(nmp);
if (attrflag) {
if (VTONFS(vp)->n_flag & ND_NFSV4)
ret = nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 1,
@@ -1422,8 +1452,10 @@ nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
dnp = VTONFS(dvp);
mtx_lock(&dnp->n_mtx);
dnp->n_flag |= NMODIFIED;
- if (!dattrflag)
+ if (!dattrflag) {
dnp->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp);
+ }
mtx_unlock(&dnp->n_mtx);
return (error);
}
@@ -1576,8 +1608,10 @@ again:
}
mtx_lock(&dnp->n_mtx);
dnp->n_flag |= NMODIFIED;
- if (!dattrflag)
+ if (!dattrflag) {
dnp->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp);
+ }
mtx_unlock(&dnp->n_mtx);
return (error);
}
@@ -1640,6 +1674,7 @@ nfs_remove(struct vop_remove_args *ap)
mtx_lock(&np->n_mtx);
np->n_attrstamp = 0;
mtx_unlock(&np->n_mtx);
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
return (error);
}
@@ -1688,8 +1723,10 @@ nfs_removerpc(struct vnode *dvp, struct vnode *vp, char *name,
(void) nfscl_loadattrcache(&dvp, &dnfsva, NULL, NULL, 0, 1);
mtx_lock(&dnp->n_mtx);
dnp->n_flag |= NMODIFIED;
- if (!dattrflag)
+ if (!dattrflag) {
dnp->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp);
+ }
mtx_unlock(&dnp->n_mtx);
if (error && NFS_ISV4(dvp))
error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
@@ -1867,6 +1904,7 @@ nfs_renamerpc(struct vnode *fdvp, struct vnode *fvp, char *fnameptr,
} else {
fdnp->n_attrstamp = 0;
mtx_unlock(&fdnp->n_mtx);
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(fdvp);
}
mtx_lock(&tdnp->n_mtx);
tdnp->n_flag |= NMODIFIED;
@@ -1876,6 +1914,7 @@ nfs_renamerpc(struct vnode *fdvp, struct vnode *fvp, char *fnameptr,
} else {
tdnp->n_attrstamp = 0;
mtx_unlock(&tdnp->n_mtx);
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(tdvp);
}
if (error && NFS_ISV4(fdvp))
error = nfscl_maperr(td, error, (uid_t)0, (gid_t)0);
@@ -1918,6 +1957,7 @@ nfs_link(struct vop_link_args *ap)
} else {
tdnp->n_attrstamp = 0;
mtx_unlock(&tdnp->n_mtx);
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(tdvp);
}
if (attrflag)
(void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL, 0, 1);
@@ -1926,6 +1966,7 @@ nfs_link(struct vop_link_args *ap)
mtx_lock(&np->n_mtx);
np->n_attrstamp = 0;
mtx_unlock(&np->n_mtx);
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
}
/*
* If negative lookup caching is enabled, I might as well
@@ -2012,6 +2053,7 @@ nfs_symlink(struct vop_symlink_args *ap)
} else {
dnp->n_attrstamp = 0;
mtx_unlock(&dnp->n_mtx);
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp);
}
return (error);
}
@@ -2047,6 +2089,7 @@ nfs_mkdir(struct vop_mkdir_args *ap)
} else {
dnp->n_attrstamp = 0;
mtx_unlock(&dnp->n_mtx);
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp);
}
if (nfhp) {
ret = nfscl_nget(dvp->v_mount, dvp, nfhp, cnp, cnp->cn_thread,
@@ -2115,6 +2158,7 @@ nfs_rmdir(struct vop_rmdir_args *ap)
} else {
dnp->n_attrstamp = 0;
mtx_unlock(&dnp->n_mtx);
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(dvp);
}
cache_purge(dvp);
@@ -2480,10 +2524,12 @@ ncl_commit(struct vnode *vp, u_quad_t offset, int cnt, struct ucred *cred,
error = nfsrpc_commit(vp, offset, cnt, cred, td, verf, &nfsva,
&attrflag, NULL);
if (!error) {
+ mtx_lock(&nmp->nm_mtx);
if (NFSBCMP((caddr_t)nmp->nm_verf, verf, NFSX_VERF)) {
NFSBCOPY(verf, (caddr_t)nmp->nm_verf, NFSX_VERF);
error = NFSERR_STALEWRITEVERF;
}
+ mtx_unlock(&nmp->nm_mtx);
if (!error && attrflag)
(void) nfscl_loadattrcache(&vp, &nfsva, NULL, NULL,
0, 1);
@@ -2892,8 +2938,11 @@ nfs_advlock(struct vop_advlock_args *ap)
int ret, error = EOPNOTSUPP;
u_quad_t size;
- if (NFS_ISV4(vp) && (ap->a_flags & F_POSIX)) {
- cred = p->p_ucred;
+ if (NFS_ISV4(vp) && (ap->a_flags & (F_POSIX | F_FLOCK)) != 0) {
+ if ((ap->a_flags & F_POSIX) != 0)
+ cred = p->p_ucred;
+ else
+ cred = td->td_ucred;
vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
if (vp->v_iflag & VI_DOOMED) {
VOP_UNLOCK(vp, 0);
@@ -2906,7 +2955,8 @@ nfs_advlock(struct vop_advlock_args *ap)
* RFC3530 Sec. 9.3.2.
*/
if (ap->a_op == F_UNLCK &&
- nfscl_checkwritelocked(vp, ap->a_fl, cred, td))
+ nfscl_checkwritelocked(vp, ap->a_fl, cred, td, ap->a_id,
+ ap->a_flags))
(void) ncl_flush(vp, MNT_WAIT, cred, td, 1, 0);
/*
@@ -2915,7 +2965,7 @@ nfs_advlock(struct vop_advlock_args *ap)
*/
do {
ret = nfsrpc_advlock(vp, np->n_size, ap->a_op,
- ap->a_fl, 0, cred, td);
+ ap->a_fl, 0, cred, td, ap->a_id, ap->a_flags);
if (ret == NFSERR_DENIED && (ap->a_flags & F_WAIT) &&
ap->a_op == F_SETLK) {
VOP_UNLOCK(vp, 0);
@@ -2950,12 +3000,14 @@ nfs_advlock(struct vop_advlock_args *ap)
if (ap->a_op == F_SETLK) {
if ((np->n_flag & NMODIFIED) == 0) {
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
ret = VOP_GETATTR(vp, &va, cred);
}
if ((np->n_flag & NMODIFIED) || ret ||
np->n_change != va.va_filerev) {
(void) ncl_vinvalbuf(vp, V_SAVE, td, 1);
np->n_attrstamp = 0;
+ KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp);
ret = VOP_GETATTR(vp, &va, cred);
if (!ret) {
np->n_mtime = va.va_mtime;
@@ -3301,7 +3353,13 @@ nfs_pathconf(struct vop_pathconf_args *ap)
struct thread *td = curthread;
int attrflag, error;
- if (NFS_ISV34(vp)) {
+ if (NFS_ISV4(vp) || (NFS_ISV3(vp) && (ap->a_name == _PC_LINK_MAX ||
+ ap->a_name == _PC_NAME_MAX || ap->a_name == _PC_CHOWN_RESTRICTED ||
+ ap->a_name == _PC_NO_TRUNC))) {
+ /*
+ * Since only the above 4 a_names are returned by the NFSv3
+ * Pathconf RPC, there is no point in doing it for others.
+ */
error = nfsrpc_pathconf(vp, &pc, td->td_ucred, td, &nfsva,
&attrflag, NULL);
if (attrflag != 0)
@@ -3310,7 +3368,10 @@ nfs_pathconf(struct vop_pathconf_args *ap)
if (error != 0)
return (error);
} else {
- /* For NFSv2, just fake them. */
+ /*
+ * For NFSv2 (or NFSv3 when not one of the above 4 a_names),
+ * just fake them.
+ */
pc.pc_linkmax = LINK_MAX;
pc.pc_namemax = NFS_MAXNAMLEN;
pc.pc_notrunc = 1;
diff --git a/sys/fs/nfsclient/nfs_kdtrace.h b/sys/fs/nfsclient/nfs_kdtrace.h
new file mode 100644
index 0000000..f8f143f
--- /dev/null
+++ b/sys/fs/nfsclient/nfs_kdtrace.h
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (c) 2009 Robert N. M. Watson
+ * All rights reserved.
+ *
+ * This software was developed at the University of Cambridge Computer
+ * Laboratory with support from a grant from Google, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _NFSCL_NFS_KDTRACE_H_
+#define _NFSCL_NFS_KDTRACE_H_
+
+#ifdef KDTRACE_HOOKS
+#include <sys/dtrace_bsd.h>
+
+/*
+ * Definitions for NFS access cache probes.
+ */
+extern uint32_t nfscl_accesscache_flush_done_id;
+extern uint32_t nfscl_accesscache_get_hit_id;
+extern uint32_t nfscl_accesscache_get_miss_id;
+extern uint32_t nfscl_accesscache_load_done_id;
+
+#define KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp) do { \
+ if (dtrace_nfscl_accesscache_flush_done_probe != NULL) \
+ (dtrace_nfscl_accesscache_flush_done_probe)( \
+ nfscl_accesscache_flush_done_id, (vp)); \
+} while (0)
+
+#define KDTRACE_NFS_ACCESSCACHE_GET_HIT(vp, uid, mode) do { \
+ if (dtrace_nfscl_accesscache_get_hit_probe != NULL) \
+ (dtrace_nfscl_accesscache_get_hit_probe)( \
+ nfscl_accesscache_get_hit_id, (vp), (uid), \
+ (mode)); \
+} while (0)
+
+#define KDTRACE_NFS_ACCESSCACHE_GET_MISS(vp, uid, mode) do { \
+ if (dtrace_nfscl_accesscache_get_miss_probe != NULL) \
+ (dtrace_nfscl_accesscache_get_miss_probe)( \
+ nfscl_accesscache_get_miss_id, (vp), (uid), \
+ (mode)); \
+} while (0)
+
+#define KDTRACE_NFS_ACCESSCACHE_LOAD_DONE(vp, uid, rmode, error) do { \
+ if (dtrace_nfscl_accesscache_load_done_probe != NULL) \
+ (dtrace_nfscl_accesscache_load_done_probe)( \
+ nfscl_accesscache_load_done_id, (vp), (uid), \
+ (rmode), (error)); \
+} while (0)
+
+/*
+ * Definitions for NFS attribute cache probes.
+ */
+extern uint32_t nfscl_attrcache_flush_done_id;
+extern uint32_t nfscl_attrcache_get_hit_id;
+extern uint32_t nfscl_attrcache_get_miss_id;
+extern uint32_t nfscl_attrcache_load_done_id;
+
+#define KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp) do { \
+ if (dtrace_nfscl_attrcache_flush_done_probe != NULL) \
+ (dtrace_nfscl_attrcache_flush_done_probe)( \
+ nfscl_attrcache_flush_done_id, (vp)); \
+} while (0)
+
+#define KDTRACE_NFS_ATTRCACHE_GET_HIT(vp, vap) do { \
+ if (dtrace_nfscl_attrcache_get_hit_probe != NULL) \
+ (dtrace_nfscl_attrcache_get_hit_probe)( \
+ nfscl_attrcache_get_hit_id, (vp), (vap)); \
+} while (0)
+
+#define KDTRACE_NFS_ATTRCACHE_GET_MISS(vp) do { \
+ if (dtrace_nfscl_attrcache_get_miss_probe != NULL) \
+ (dtrace_nfscl_attrcache_get_miss_probe)( \
+ nfscl_attrcache_get_miss_id, (vp)); \
+} while (0)
+
+#define KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, vap, error) do { \
+ if (dtrace_nfscl_attrcache_load_done_probe != NULL) \
+ (dtrace_nfscl_attrcache_load_done_probe)( \
+ nfscl_attrcache_load_done_id, (vp), (vap), \
+ (error)); \
+} while (0)
+
+#else /* !KDTRACE_HOOKS */
+
+#define KDTRACE_NFS_ACCESSCACHE_FLUSH_DONE(vp)
+#define KDTRACE_NFS_ACCESSCACHE_GET_HIT(vp, uid, mode)
+#define KDTRACE_NFS_ACCESSCACHE_GET_MISS(vp, uid, mode)
+#define KDTRACE_NFS_ACCESSCACHE_LOAD_DONE(vp, uid, rmode, error)
+
+#define KDTRACE_NFS_ATTRCACHE_FLUSH_DONE(vp)
+#define KDTRACE_NFS_ATTRCACHE_GET_HIT(vp, vap)
+#define KDTRACE_NFS_ATTRCACHE_GET_MISS(vp)
+#define KDTRACE_NFS_ATTRCACHE_LOAD_DONE(vp, vap, error)
+
+#endif /* KDTRACE_HOOKS */
+
+#endif /* !_NFSCL_NFS_KDTRACE_H_ */
OpenPOWER on IntegriCloud