--- /usr/src/sys/netncp/ncp_conn.c 2009-01-10 13:39:48.000000000 +0100 +++ sys/netncp/ncp_conn.c 2009-01-28 19:20:02.000000000 +0100 @@ -38,11 +38,13 @@ #include #include #include +#include #include +#include #include #include -#include #include +#include #include #include @@ -51,6 +53,17 @@ #include #include +#define NCP_REFLCNT(ncp) ((ncp)->nc_lockcnt++) +#define NCP_RELLCNT(ncp) do { \ + (ncp)->nc_lockcnt--; \ + if ((ncp)->nc_lockcnt == 0 && \ + ((ncp)->flags & NCPFL_DRAINING) != 0) { \ + MPASS((ncp)->nc_id == 0); \ + (ncp)->flags &= ~NCPFL_DRAINING; \ + wakeup(&(ncp)->nc_lockcnt); \ + } \ +} while(0) + SLIST_HEAD(ncp_handle_head,ncp_handle); int ncp_burst_enabled = 1; @@ -58,15 +71,16 @@ struct ncp_conn_head conn_list={NULL}; static int ncp_conn_cnt = 0; static int ncp_next_ref = 1; -static struct lock listlock; +static struct sx listlock; struct ncp_handle_head lhlist={NULL}; static int ncp_next_handle = 1; -static struct lock lhlock; +static struct sx lhlock; static int ncp_sysctl_connstat(SYSCTL_HANDLER_ARGS); static int ncp_conn_lock_any(struct ncp_conn *conn, struct thread *td, struct ucred *cred); +static void ncp_conn_lock_assert(struct ncp_conn *conn, int what); SYSCTL_DECL(_net_ncp); SYSCTL_INT (_net_ncp, OID_AUTO, burst_enabled, CTLFLAG_RD, &ncp_burst_enabled, 0, ""); @@ -79,8 +93,8 @@ int ncp_conn_init(void) { - lockinit(&listlock, PSOCK, "ncpll", 0, 0); - lockinit(&lhlock, PSOCK, "ncplh", 0, 0); + sx_init_flags(&listlock, "ncpll", SX_RECURSE); + sx_init(&lhlock, "ncplh"); return 0; } @@ -91,21 +105,51 @@ NCPERROR("There are %d connections active\n", ncp_conn_cnt); return EBUSY; } - lockdestroy(&listlock); - lockdestroy(&lhlock); + sx_destroy(&listlock); + sx_destroy(&lhlock); return 0; } +void +ncp_conn_slocklist() +{ + + sx_slock(&listlock); +} + +void +ncp_conn_xlocklist() +{ + + sx_xlock(&listlock); +} + int -ncp_conn_locklist(int flags, struct thread *td) +ncp_conn_try_slocklist() { - return lockmgr(&listlock, flags | LK_CANRECURSE, 0); + + return (sx_try_slock(&listlock)); +} + +int +ncp_conn_try_xlocklist() +{ + + return (sx_try_xlock(&listlock)); } void -ncp_conn_unlocklist(struct thread *td) +ncp_conn_sunlocklist() { - lockmgr(&listlock, LK_RELEASE, 0); + + sx_sunlock(&listlock); +} + +void +ncp_conn_xunlocklist() +{ + + sx_xunlock(&listlock); } int @@ -128,17 +172,31 @@ { int error; - if (conn->nc_id == 0) return EACCES; - error = lockmgr(&conn->nc_lock, LK_EXCLUSIVE | LK_CANRECURSE, 0); - if (error == ERESTART) + NCP_ILOCK(conn); + if (conn->nc_id == 0) + return EACCES; + NCP_REFLCNT(conn); + error = lockmgr(&conn->nc_lock, LK_EXCLUSIVE | LK_CANRECURSE | + LK_INTERLOCK, NCP_MTX(conn)); + if (error == ERESTART) { + NCP_ILOCK(conn); + NCP_RELLCNT(conn); + NCP_IUNLOCK(conn); return EINTR; + } error = ncp_chkintr(conn, td); if (error) { + NCP_ILOCK(conn); + NCP_RELLCNT(conn); + NCP_IUNLOCK(conn); lockmgr(&conn->nc_lock, LK_RELEASE, 0); return error; } if (conn->nc_id == 0) { + NCP_ILOCK(conn); + NCP_RELLCNT(conn); + NCP_IUNLOCK(conn); lockmgr(&conn->nc_lock, LK_RELEASE, 0); return EACCES; } @@ -147,6 +205,13 @@ return 0; } +static void +ncp_conn_lock_assert(struct ncp_conn *conn, int what) +{ + + lockmgr_assert(&conn->nc_lock, what); +} + int ncp_conn_lock(struct ncp_conn *conn, struct thread *td, struct ucred *cred, int mode) { @@ -167,11 +232,11 @@ error = ncp_conn_access(conn, cred, mode); if (error) { - ncp_conn_unlocklist(td); + ncp_conn_sunlocklist(); return error; } conn->nc_lwant++; - ncp_conn_unlocklist(td); + ncp_conn_sunlocklist(); error = ncp_conn_lock_any(conn, td, cred); conn->nc_lwant--; if (conn->nc_lwant == 0) { @@ -183,19 +248,11 @@ void ncp_conn_unlock(struct ncp_conn *conn, struct thread *td) { - /* - * note, that LK_RELASE will do wakeup() instead of wakeup_one(). - * this will do a little overhead - */ - lockmgr(&conn->nc_lock, LK_RELEASE, 0); -} -int -ncp_conn_assert_locked(struct ncp_conn *conn, const char *checker, struct thread *td) -{ - if (lockstatus(&conn->nc_lock) == LK_EXCLUSIVE) return 0; - printf("%s: connection isn't locked!\n", checker); - return EIO; + NCP_ILOCK(conn); + NCP_RELLCNT(conn); + NCP_IUNLOCK(conn); + lockmgr(&conn->nc_lock, LK_RELEASE, 0); } void @@ -242,7 +299,9 @@ M_NCPDATA, M_WAITOK | M_ZERO); error = 0; lockinit(&ncp->nc_lock, PZERO, "ncplck", 0, 0); + mtx_init(&ncp->nc_ilock, "ncpilck", NULL, 0); ncp_conn_cnt++; + ncp->nc_lockcnt = 0; ncp->nc_id = ncp_next_ref++; ncp->nc_owner = owner; ncp->seq = 0; @@ -257,9 +316,9 @@ ncp->li.timeout = NCP_RETRY_TIMEOUT; ncp_conn_lock_any(ncp, td, ncp->nc_owner); *conn = ncp; - ncp_conn_locklist(LK_EXCLUSIVE, td); + ncp_conn_xlocklist(); SLIST_INSERT_HEAD(&conn_list,ncp,nc_next); - ncp_conn_unlocklist(td); + ncp_conn_xunlocklist(); return (error); } @@ -270,20 +329,12 @@ ncp_conn_free(struct ncp_conn *ncp) { struct thread *td; - int error; - if (ncp == NULL) { - NCPFATAL("ncp == NULL\n"); - return 0; - } - if (ncp->nc_id == 0) { - NCPERROR("nc_id == 0\n"); - return EACCES; - } + MPASS(ncp != NULL); + MPASS(ncp->nc_id != 0); + ncp_conn_lock_assert(ncp, KA_XLOCKED); + td = ncp->td; - error = ncp_conn_assert_locked(ncp, __func__, td); - if (error) - return error; if (ncp->ref_cnt != 0 || (ncp->flags & NCPFL_PERMANENT)) return EBUSY; if (ncp_conn_access(ncp, ncp->ucred, NCPM_WRITE)) @@ -292,26 +343,28 @@ if (ncp->flags & NCPFL_ATTACHED) ncp_ncp_disconnect(ncp); ncp_sock_disconnect(ncp); + ncp_conn_unlock(ncp, td); /* * Mark conn as dead and wait for other process */ + NCP_ILOCK(ncp); ncp->nc_id = 0; - ncp_conn_unlock(ncp, td); - /* - * if signal is raised - how I do react ? - */ - lockmgr(&ncp->nc_lock, LK_DRAIN, 0); - lockmgr(&ncp->nc_lock, LK_RELEASE, 0); + if (ncp->nc_lockcnt != 0) { + ncp->flags |= NCPFL_DRAINING; + msleep(&ncp->nc_lockcnt, NCP_MTX(ncp), PSOCK, + "ncp connection drain", 0); + } + NCP_IUNLOCK(ncp); lockdestroy(&ncp->nc_lock); while (ncp->nc_lwant) { printf("lwant = %d\n", ncp->nc_lwant); tsleep(&ncp->nc_lwant, PZERO,"ncpdr",2*hz); } - ncp_conn_locklist(LK_EXCLUSIVE, td); + ncp_conn_xlocklist(); SLIST_REMOVE(&conn_list, ncp, ncp_conn, nc_next); ncp_conn_cnt--; - ncp_conn_unlocklist(td); + ncp_conn_xunlocklist(); if (ncp->li.user) free(ncp->li.user, M_NCPDATA); if (ncp->li.password) @@ -390,11 +443,11 @@ struct ncp_conn *ncp; int error = 0; - ncp_conn_locklist(LK_SHARED, td); + ncp_conn_slocklist(); SLIST_FOREACH(ncp, &conn_list, nc_next) if (ncp->nc_id == ref) break; if (ncp == NULL) { - ncp_conn_unlocklist(td); + ncp_conn_sunlocklist(); return(EBADF); } error = ncp_conn_lock2(ncp, td, cred, mode); @@ -412,7 +465,7 @@ struct ncp_conn *ncp, *ncp2 = NULL; int error = 0; - ncp_conn_locklist(LK_SHARED, td); + ncp_conn_slocklist(); SLIST_FOREACH(ncp, &conn_list, nc_next) { if ((ncp->flags & NCPFL_LOGGED) != 0 || strcmp(ncp->li.server,li->server) != 0 || @@ -428,7 +481,7 @@ } if (ncp == NULL) ncp = ncp2; if (ncp == NULL) { - ncp_conn_unlocklist(td); + ncp_conn_sunlocklist(); return(EBADF); } error = ncp_conn_lock2(ncp, td, cred, mode); @@ -456,7 +509,7 @@ partial = (li == NULL || li->server[0] == 0 || li->user == NULL); haveserv = (li && li->server[0]); - ncp_conn_locklist(LK_SHARED, td); + ncp_conn_slocklist(); SLIST_FOREACH(ncp, &conn_list, nc_next) { if (partial) { if (cred->cr_uid == ncp->nc_owner->cr_uid) { @@ -486,7 +539,7 @@ } if (ncp == NULL) ncp = ncp2; if (ncp == NULL) { - ncp_conn_unlocklist(td); + ncp_conn_sunlocklist(); return(EBADF); } error = ncp_conn_lock2(ncp, td, cred,mode); @@ -507,12 +560,12 @@ if (conn->ucred->cr_uid != conn->nc_owner->cr_uid) return EACCES; - ncp_conn_locklist(LK_SHARED, conn->td); + ncp_conn_slocklist(); SLIST_FOREACH(ncp, &conn_list, nc_next) { if (conn->ucred->cr_uid == ncp->nc_owner->cr_uid) ncp->flags &= ~NCPFL_PRIMARY; } - ncp_conn_unlocklist(conn->td); + ncp_conn_sunlocklist(); if (on) conn->flags |= NCPFL_PRIMARY; return 0; @@ -526,14 +579,14 @@ { struct ncp_handle *refp; - lockmgr(&lhlock, LK_EXCLUSIVE, 0); + sx_xlock(&lhlock); SLIST_FOREACH(refp, &lhlist, nh_next) if (refp->nh_conn == conn && td == refp->nh_td) break; if (refp) { conn->ref_cnt++; refp->nh_ref++; *handle = refp; - lockmgr(&lhlock, LK_RELEASE, 0); + sx_xunlock(&lhlock); return 0; } refp = malloc(sizeof(struct ncp_handle),M_NCPDATA, @@ -545,7 +598,7 @@ refp->nh_id = ncp_next_handle++; *handle = refp; conn->ref_cnt++; - lockmgr(&lhlock, LK_RELEASE, 0); + sx_xunlock(&lhlock); return 0; } /* @@ -556,7 +609,7 @@ { struct ncp_handle *refp = handle; - lockmgr(&lhlock, LK_EXCLUSIVE, 0); + sx_xlock(&lhlock); refp->nh_ref--; refp->nh_conn->ref_cnt--; if (force) { @@ -567,7 +620,7 @@ SLIST_REMOVE(&lhlist, refp, ncp_handle, nh_next); free(refp, M_NCPDATA); } - lockmgr(&lhlock, LK_RELEASE, 0); + sx_xunlock(&lhlock); return 0; } /* @@ -577,10 +630,10 @@ ncp_conn_findhandle(int connHandle, struct thread *td, struct ncp_handle **handle) { struct ncp_handle *refp; - lockmgr(&lhlock, LK_SHARED, 0); + sx_slock(&lhlock); SLIST_FOREACH(refp, &lhlist, nh_next) if (refp->nh_td == td && refp->nh_id == connHandle) break; - lockmgr(&lhlock, LK_RELEASE, 0); + sx_sunlock(&lhlock); if (refp == NULL) { return EBADF; } @@ -596,7 +649,7 @@ struct ncp_handle *hp, *nhp; int haveone = 0; - lockmgr(&lhlock, LK_EXCLUSIVE, 0); + sx_xlock(&lhlock); for (hp = SLIST_FIRST(&lhlist); hp; hp = nhp) { nhp = SLIST_NEXT(hp, nh_next); if (hp->nh_td != td) continue; @@ -605,7 +658,7 @@ SLIST_REMOVE(&lhlist, hp, ncp_handle, nh_next); free(hp, M_NCPDATA); } - lockmgr(&lhlock, LK_RELEASE, 0); + sx_xunlock(&lhlock); return haveone; } /* @@ -616,11 +669,11 @@ ncp_conn_list_rm_ref(pid_t pid) { struct ncp_conn *ncp; - ncp_conn_locklist(LK_SHARED, NULL); + ncp_conn_slocklist(); SLIST_FOREACH(ncp, &conn_list, nc_next) { ncp_conn_rm_ref(ncp,pid,1); } - ncp_conn_unlocklist(NULL); + ncp_conn_sunlocklist(); return; } */ @@ -653,7 +706,7 @@ error = sysctl_wire_old_buffer(req, 0); if (error != 0) return (error); - ncp_conn_locklist(LK_SHARED, req->td); + ncp_conn_slocklist(); error = SYSCTL_OUT(req, &ncp_conn_cnt, sizeof(ncp_conn_cnt)); SLIST_FOREACH(ncp, &conn_list, nc_next) { if (error) break; @@ -663,6 +716,6 @@ ncp->nc_lwant--; error = SYSCTL_OUT(req, &ncs, sizeof(ncs)); } - ncp_conn_unlocklist(req->td); + ncp_conn_sunlocklist(); return(error); } --- /usr/src/sys/netncp/ncp_conn.h 2008-03-12 14:55:40.000000000 +0100 +++ sys/netncp/ncp_conn.h 2009-01-28 19:20:02.000000000 +0100 @@ -63,6 +63,7 @@ #define NCPFL_WASLOGGED 0x0200 /* there was at least one successfull login */ #define NCPFL_SIGNACTIVE 0x1000 /* packet signing active */ #define NCPFL_SIGNWANTED 0x2000 /* signing should start */ +#define NCPFL_DRAINING 0x4000 /* structure under draining */ /* access mode for connection */ #define NCPM_READ 0400 /* able to fetch conn params */ @@ -72,6 +73,9 @@ #define NCP_DEFAULT_OWNER ((uid_t)-1) #define NCP_DEFAULT_GROUP ((uid_t)-1) +#define NCP_ILOCK(ncp) mtx_lock(&(ncp)->nc_ilock) +#define NCP_IUNLOCK(ncp) mtx_unlock(&(ncp)->nc_ilock) +#define NCP_MTX(ncp) (&(ncp)->nc_ilock) /* args used to create connection */ #define ncp_conn_loginfo ncp_conn_args @@ -173,6 +177,8 @@ int ref_cnt; /* how many handles leased */ SLIST_HEAD(ncp_ref_hd,ncp_ref) ref_list;/* list of handles */ struct lock nc_lock; /* excl locks */ + struct mtx nc_ilock; /* connection interlock */ + int nc_lockcnt; /* lock refcount */ int nc_lwant; /* number of wanted locks */ struct thread *td; /* pid currently operates */ struct ucred *ucred; /* usr currently operates */ @@ -201,7 +207,6 @@ int ncp_conn_access(struct ncp_conn *conn,struct ucred *cred,mode_t mode); int ncp_conn_lock(struct ncp_conn *conn,struct thread *td, struct ucred *cred,int mode); void ncp_conn_unlock(struct ncp_conn *conn,struct thread *td); -int ncp_conn_assert_locked(struct ncp_conn *conn,const char *checker,struct thread *td); void ncp_conn_invalidate(struct ncp_conn *ncp); int ncp_conn_invalid(struct ncp_conn *ncp); /*int ncp_conn_ref(struct ncp_conn *conn, pid_t pid); @@ -212,8 +217,12 @@ int ncp_conn_getbyli(struct ncp_conn_loginfo *li,struct thread *td, struct ucred *cred, int mode, struct ncp_conn **connpp); int ncp_conn_setprimary(struct ncp_conn *conn, int on); -int ncp_conn_locklist(int flags, struct thread *td); -void ncp_conn_unlocklist(struct thread *td); +void ncp_conn_slocklist(void); +void ncp_conn_xlocklist(void); +int ncp_conn_try_slocklist(void); +int ncp_conn_try_xlocklist(void); +void ncp_conn_sunlocklist(void); +void ncp_conn_xunlocklist(void); int ncp_conn_gethandle(struct ncp_conn *conn, struct thread *td, struct ncp_handle **handle); int ncp_conn_puthandle(struct ncp_handle *handle, struct thread *td, int force); int ncp_conn_findhandle(int connHandle, struct thread *td, struct ncp_handle **handle); --- /usr/src/sys/netncp/ncp_subr.c 2009-01-10 13:39:48.000000000 +0100 +++ sys/netncp/ncp_subr.c 2009-01-28 19:24:08.000000000 +0100 @@ -90,7 +90,7 @@ if (ncp_conn_putprochandles(td) == 0) continue; - ncp_conn_locklist(LK_EXCLUSIVE, td); + ncp_conn_xlocklist(); for (ncp = SLIST_FIRST(&conn_list); ncp; ncp = nncp) { nncp = SLIST_NEXT(ncp, nc_next); if (ncp_conn_lock(ncp, td, td->td_ucred, @@ -99,7 +99,7 @@ if (ncp_conn_free(ncp) != 0) ncp_conn_unlock(ncp, td); } - ncp_conn_unlocklist(td); + ncp_conn_xunlocklist(); } mtx_unlock(&Giant); } @@ -134,10 +134,10 @@ { struct ncp_conn *conn; - if(ncp_conn_locklist(LK_SHARED | LK_NOWAIT, NULL) == 0) { + if (ncp_conn_try_slocklist()) { SLIST_FOREACH(conn, &conn_list, nc_next) ncp_check_conn(conn); - ncp_conn_unlocklist(NULL); + ncp_conn_sunlocklist(); } ncp_timer_handle = timeout(ncp_timer, NULL, NCP_TIMER_TICK); }