summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/nfsclient/nfs.h2
-rw-r--r--sys/nfsclient/nfs_nfsiod.c41
-rw-r--r--sys/nfsclient/nfs_subs.c7
3 files changed, 48 insertions, 2 deletions
diff --git a/sys/nfsclient/nfs.h b/sys/nfsclient/nfs.h
index 6f6e0d33..da61175 100644
--- a/sys/nfsclient/nfs.h
+++ b/sys/nfsclient/nfs.h
@@ -125,6 +125,7 @@ extern struct uma_zone *nfsmount_zone;
extern struct nfsstats nfsstats;
extern struct mtx nfs_iod_mtx;
+extern struct task nfs_nfsiodnew_task;
extern int nfs_numasync;
extern unsigned int nfs_iodmax;
@@ -253,6 +254,7 @@ int nfs_commit(struct vnode *vp, u_quad_t offset, int cnt,
struct ucred *cred, struct thread *td);
int nfs_readdirrpc(struct vnode *, struct uio *, struct ucred *);
int nfs_nfsiodnew(int);
+void nfs_nfsiodnew_tq(__unused void *, int);
int nfs_asyncio(struct nfsmount *, struct buf *, struct ucred *, struct thread *);
int nfs_doio(struct vnode *, struct buf *, struct ucred *, struct thread *);
void nfs_doio_directwrite (struct buf *);
diff --git a/sys/nfsclient/nfs_nfsiod.c b/sys/nfsclient/nfs_nfsiod.c
index d192848..5e2fbcc 100644
--- a/sys/nfsclient/nfs_nfsiod.c
+++ b/sys/nfsclient/nfs_nfsiod.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <sys/fcntl.h>
#include <sys/lockf.h>
#include <sys/mutex.h>
+#include <sys/taskqueue.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
@@ -75,6 +76,16 @@ static MALLOC_DEFINE(M_NFSSVC, "nfsclient_srvsock", "Nfs server structure");
static void nfssvc_iod(void *);
+struct nfsiod_str {
+ STAILQ_ENTRY(nfsiod_str) ni_links;
+ int *ni_inst;
+ int ni_iod;
+ int ni_error;
+ int ni_done;
+};
+static STAILQ_HEAD(, nfsiod_str) nfsiodhead =
+ STAILQ_HEAD_INITIALIZER(nfsiodhead);
+
static int nfs_asyncdaemon[NFS_MAXASYNCDAEMON];
SYSCTL_DECL(_vfs_nfs);
@@ -159,11 +170,30 @@ SYSCTL_PROC(_vfs_nfs, OID_AUTO, iodmax, CTLTYPE_UINT | CTLFLAG_RW, 0,
sizeof (nfs_iodmax), sysctl_iodmax, "IU",
"Max number of nfsiod kthreads");
+void
+nfs_nfsiodnew_tq(__unused void *arg, int pending)
+{
+ struct nfsiod_str *nip;
+
+ mtx_lock(&nfs_iod_mtx);
+ while ((nip = STAILQ_FIRST(&nfsiodhead)) != NULL) {
+ STAILQ_REMOVE_HEAD(&nfsiodhead, ni_links);
+ mtx_unlock(&nfs_iod_mtx);
+ nip->ni_error = kproc_create(nfssvc_iod, nip->ni_inst, NULL,
+ RFHIGHPID, 0, "nfsiod %d", nip->ni_iod);
+ nip->ni_done = 1;
+ mtx_lock(&nfs_iod_mtx);
+ wakeup(nip);
+ }
+ mtx_unlock(&nfs_iod_mtx);
+}
+
int
nfs_nfsiodnew(int set_iodwant)
{
int error, i;
int newiod;
+ struct nfsiod_str *nip;
if (nfs_numasync >= nfs_iodmax)
return (-1);
@@ -179,9 +209,16 @@ nfs_nfsiodnew(int set_iodwant)
if (set_iodwant > 0)
nfs_iodwant[i] = NFSIOD_CREATED_FOR_NFS_ASYNCIO;
mtx_unlock(&nfs_iod_mtx);
- error = kproc_create(nfssvc_iod, nfs_asyncdaemon + i, NULL, RFHIGHPID,
- 0, "nfsiod %d", newiod);
+ nip = malloc(sizeof(*nip), M_TEMP, M_WAITOK | M_ZERO);
+ nip->ni_inst = nfs_asyncdaemon + i;
+ nip->ni_iod = newiod;
mtx_lock(&nfs_iod_mtx);
+ STAILQ_INSERT_TAIL(&nfsiodhead, nip, ni_links);
+ taskqueue_enqueue(taskqueue_thread, &nfs_nfsiodnew_task);
+ while (!nip->ni_done)
+ mtx_sleep(nip, &nfs_iod_mtx, 0, "niwt", 0);
+ error = nip->ni_error;
+ free(nip, M_TEMP);
if (error) {
if (set_iodwant > 0)
nfs_iodwant[i] = NFSIOD_NOT_AVAILABLE;
diff --git a/sys/nfsclient/nfs_subs.c b/sys/nfsclient/nfs_subs.c
index 0ab5fa2..7c9941f 100644
--- a/sys/nfsclient/nfs_subs.c
+++ b/sys/nfsclient/nfs_subs.c
@@ -59,6 +59,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sysent.h>
#include <sys/syscall.h>
#include <sys/sysproto.h>
+#include <sys/taskqueue.h>
#include <vm/vm.h>
#include <vm/vm_object.h>
@@ -117,6 +118,7 @@ int nfs_pbuf_freecnt = -1; /* start out unlimited */
struct nfs_bufq nfs_bufq;
static struct mtx nfs_xid_mtx;
+struct task nfs_nfsiodnew_task;
/*
* and the reverse mapping from generic to Version 2 procedure numbers
@@ -354,6 +356,7 @@ nfs_init(struct vfsconf *vfsp)
*/
mtx_init(&nfs_iod_mtx, "NFS iod lock", NULL, MTX_DEF);
mtx_init(&nfs_xid_mtx, "NFS xid lock", NULL, MTX_DEF);
+ TASK_INIT(&nfs_nfsiodnew_task, 0, nfs_nfsiodnew_tq, NULL);
nfs_pbuf_freecnt = nswbuf / 2 + 1;
@@ -368,9 +371,13 @@ nfs_uninit(struct vfsconf *vfsp)
/*
* Tell all nfsiod processes to exit. Clear nfs_iodmax, and wakeup
* any sleeping nfsiods so they check nfs_iodmax and exit.
+ * Drain nfsiodnew task before we wait for them to finish.
*/
mtx_lock(&nfs_iod_mtx);
nfs_iodmax = 0;
+ mtx_unlock(&nfs_iod_mtx);
+ taskqueue_drain(taskqueue_thread, &nfs_nfsiodnew_task);
+ mtx_lock(&nfs_iod_mtx);
for (i = 0; i < nfs_numasync; i++)
if (nfs_iodwant[i] == NFSIOD_AVAILABLE)
wakeup(&nfs_iodwant[i]);
OpenPOWER on IntegriCloud