Index: sys/nfsclient/nfs_subs.c =================================================================== --- sys/nfsclient/nfs_subs.c (revision 211279) +++ sys/nfsclient/nfs_subs.c (working copy) @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -117,6 +118,7 @@ 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 @@ */ 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; Index: sys/nfsclient/nfs_nfsiod.c =================================================================== --- sys/nfsclient/nfs_nfsiod.c (revision 211279) +++ sys/nfsclient/nfs_nfsiod.c (working copy) @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,16 @@ 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 @@ 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 @@ 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; Index: sys/nfsclient/nfs.h =================================================================== --- sys/nfsclient/nfs.h (revision 211279) +++ sys/nfsclient/nfs.h (working copy) @@ -125,6 +125,7 @@ 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 @@ 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 *);