diff options
author | praks <none@none> | 2007-02-28 17:06:58 -0800 |
---|---|---|
committer | praks <none@none> | 2007-02-28 17:06:58 -0800 |
commit | 9f23d599d2e10f1fbd15dae924ba047538390387 (patch) | |
tree | b74f668c4543688317bd1dc953f9153636fce0d2 /usr | |
parent | fe70c9cf90dfc23d18485fb7b4b20a1175d53a8b (diff) | |
download | illumos-gate-9f23d599d2e10f1fbd15dae924ba047538390387.tar.gz |
6502013 kernel heap corruptions have been seen during io stress test on domain0
6527579 port_dissociate() does not indicate whether fd was associated
Diffstat (limited to 'usr')
-rw-r--r-- | usr/src/uts/common/fs/portfs/port_fd.c | 99 | ||||
-rw-r--r-- | usr/src/uts/common/os/port_subr.c | 12 | ||||
-rw-r--r-- | usr/src/uts/common/sys/port_impl.h | 2 |
3 files changed, 72 insertions, 41 deletions
diff --git a/usr/src/uts/common/fs/portfs/port_fd.c b/usr/src/uts/common/fs/portfs/port_fd.c index 710b2d27d6..61c0c9df41 100644 --- a/usr/src/uts/common/fs/portfs/port_fd.c +++ b/usr/src/uts/common/fs/portfs/port_fd.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -42,7 +42,6 @@ /* local functions */ static int port_fd_callback(void *, int *, pid_t, int, void *); static int port_bind_pollhead(pollhead_t **, polldat_t *, short *); -static void port_remove_fd_local(portfd_t *, port_fdcache_t *); static void port_close_sourcefd(void *, int, pid_t, int); static void port_cache_insert_fd(port_fdcache_t *, polldat_t *); @@ -188,6 +187,7 @@ port_associate_fd(port_t *pp, int source, uintptr_t object, int events, port_kevent_t *pkevp; short revents; int error = 0; + int active; pcp = pp->port_queue.portq_pcp; if (object > (uintptr_t)INT_MAX) @@ -323,12 +323,7 @@ port_associate_fd(port_t *pp, int source, uintptr_t object, int events, * call VOP_POLL() again (see port_bind_pollhead()). */ if (error) { - /* dissociate the fd from the port */ - delfd_port(fd, pfd); - port_remove_fd_local(pfd, pcp); - releasef(fd); - mutex_exit(&pcp->pc_lock); - return (error); + goto errout; } if (php != NULL) { @@ -340,11 +335,7 @@ port_associate_fd(port_t *pp, int source, uintptr_t object, int events, */ error = port_bind_pollhead(&php, pdp, &revents); if (error) { - delfd_port(fd, pfd); - port_remove_fd_local(pfd, pcp); - releasef(fd); - mutex_exit(&pcp->pc_lock); - return (error); + goto errout; } } @@ -371,6 +362,32 @@ port_associate_fd(port_t *pp, int source, uintptr_t object, int events, releasef(fd); mutex_exit(&pcp->pc_lock); return (error); + +errout: + delfd_port(fd, pfd); + /* + * If the portkev is not valid, then an event was + * delivered. + * + * If an event was delivered and got picked up, then + * we return error = 0 treating this as a successful + * port associate call. The thread which received + * the event gets control of the object. + */ + active = 0; + mutex_enter(&pkevp->portkev_lock); + if (pkevp->portkev_flags & PORT_KEV_VALID) { + pkevp->portkev_flags &= ~PORT_KEV_VALID; + active = 1; + } + mutex_enter(&pkevp->portkev_lock); + + if (!port_remove_fd_object(pfd, pp, pcp) && !active) { + error = 0; + } + releasef(fd); + mutex_exit(&pcp->pc_lock); + return (error); } /* @@ -390,6 +407,8 @@ port_dissociate_fd(port_t *pp, uintptr_t object) port_fdcache_t *pcp; portfd_t *pfd; file_t *fp; + int active; + port_kevent_t *pkevp; if (object > (uintptr_t)INT_MAX) return (EBADFD); @@ -401,7 +420,7 @@ port_dissociate_fd(port_t *pp, uintptr_t object) if (pcp->pc_hash == NULL) { /* no file descriptor cache available */ mutex_exit(&pcp->pc_lock); - return (0); + return (ENOENT); } if ((fp = getf(fd)) == NULL) { mutex_exit(&pcp->pc_lock); @@ -411,7 +430,7 @@ port_dissociate_fd(port_t *pp, uintptr_t object) if (pfd == NULL) { releasef(fd); mutex_exit(&pcp->pc_lock); - return (0); + return (ENOENT); } /* only association owner is allowed to remove the association */ if (curproc->p_pid != PFTOD(pfd)->pd_portev->portkev_pid) { @@ -424,29 +443,37 @@ port_dissociate_fd(port_t *pp, uintptr_t object) delfd_port(fd, pfd); releasef(fd); + /* + * Deactivate the association. No events get posted after + * this. + */ + pkevp = PFTOD(pfd)->pd_portev; + mutex_enter(&pkevp->portkev_lock); + if (pkevp->portkev_flags & PORT_KEV_VALID) { + pkevp->portkev_flags &= ~PORT_KEV_VALID; + active = 1; + } else { + active = 0; + } + mutex_exit(&pkevp->portkev_lock); + /* remove polldat & port event structure */ - port_remove_fd_object(pfd, pp, pcp); + if (port_remove_fd_object(pfd, pp, pcp)) { + /* + * An event was found and removed from the + * port done queue. This means the event has not yet + * been retrived. In this case we treat this as an active + * association. + */ + ASSERT(active == 0); + active = 1; + } mutex_exit(&pcp->pc_lock); - return (0); -} -/* - * Remove the fd from the event port cache. - */ -static void -port_remove_fd_local(portfd_t *pfd, port_fdcache_t *pcp) -{ - polldat_t *pdp = PFTOD(pfd); - - ASSERT(MUTEX_HELD(&pcp->pc_lock)); - pdp->pd_fp = NULL; - if (pdp->pd_php != NULL) { - pollhead_delete(pdp->pd_php, pdp); - pdp->pd_php = NULL; - } - port_free_event_local(pdp->pd_portev, 0); - /* remove polldat struct */ - port_pcache_remove_fd(pcp, pfd); + /* + * Return ENOENT if there was no active association. + */ + return ((active ? 0 : ENOENT)); } /* @@ -564,7 +591,7 @@ port_remove_portfd(polldat_t *pdp, port_fdcache_t *pcp) if (fp != NULL) { delfd_port(pdp->pd_fd, PDTOF(pdp)); releasef(pdp->pd_fd); - port_remove_fd_object(PDTOF(pdp), pp, pcp); + (void) port_remove_fd_object(PDTOF(pdp), pp, pcp); } } diff --git a/usr/src/uts/common/os/port_subr.c b/usr/src/uts/common/os/port_subr.c index 03231cd0d8..11a701a78a 100644 --- a/usr/src/uts/common/os/port_subr.c +++ b/usr/src/uts/common/os/port_subr.c @@ -20,7 +20,7 @@ */ /* - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -600,15 +600,17 @@ port_push_eventq(port_queue_t *portq) /* * The port_remove_fd_object() function frees all resources associated with - * delivered portfd_t structure. + * delivered portfd_t structure. Returns 1 if the port_kevent was found + * and removed from the port queue. */ -void +int port_remove_fd_object(portfd_t *pfd, port_t *pp, port_fdcache_t *pcp) { port_queue_t *portq; polldat_t *pdp = PFTOD(pfd); port_kevent_t *pkevp; int error; + int removed = 0; ASSERT(MUTEX_HELD(&pcp->pc_lock)); if (pdp->pd_php != NULL) { @@ -629,6 +631,7 @@ port_remove_fd_object(portfd_t *pfd, port_t *pp, port_fdcache_t *pcp) } /* cleanup merged port queue */ port_remove_event_doneq(pkevp, portq); + removed = 1; } port_unblock(portq); mutex_exit(&portq->portq_mutex); @@ -641,6 +644,7 @@ port_remove_fd_object(portfd_t *pfd, port_t *pp, port_fdcache_t *pcp) /* remove polldat struct */ port_pcache_remove_fd(pcp, pfd); + return (removed); } /* @@ -663,7 +667,7 @@ port_close_pfd(portfd_t *pfd) pp = PFTOD(pfd)->pd_portev->portkev_port; pcp = pp->port_queue.portq_pcp; mutex_enter(&pcp->pc_lock); - port_remove_fd_object(pfd, pp, pcp); + (void) port_remove_fd_object(pfd, pp, pcp); mutex_exit(&pcp->pc_lock); } diff --git a/usr/src/uts/common/sys/port_impl.h b/usr/src/uts/common/sys/port_impl.h index 58a1653b5f..3b12a20873 100644 --- a/usr/src/uts/common/sys/port_impl.h +++ b/usr/src/uts/common/sys/port_impl.h @@ -229,7 +229,7 @@ void port_unblock(port_queue_t *); /* PORT_SOURCE_FD cache management */ void port_pcache_remove_fd(port_fdcache_t *, portfd_t *); -void port_remove_fd_object(portfd_t *, struct port *, port_fdcache_t *); +int port_remove_fd_object(portfd_t *, struct port *, port_fdcache_t *); /* file close management */ extern void addfd_port(int, portfd_t *); |