Mercurial > illumos > illumos-gate
changeset 3734:cc8896fe34a1
6502013 kernel heap corruptions have been seen during io stress test on domain0
6527579 port_dissociate() does not indicate whether fd was associated
author | praks |
---|---|
date | Wed, 28 Feb 2007 17:06:58 -0800 |
parents | f1b41f5144cc |
children | 74d8d0dc0268 |
files | usr/src/uts/common/fs/portfs/port_fd.c usr/src/uts/common/os/port_subr.c usr/src/uts/common/sys/port_impl.h |
diffstat | 3 files changed, 73 insertions(+), 42 deletions(-) [+] |
line wrap: on
line diff
--- a/usr/src/uts/common/fs/portfs/port_fd.c Wed Feb 28 16:55:11 2007 -0800 +++ b/usr/src/uts/common/fs/portfs/port_fd.c Wed Feb 28 17:06:58 2007 -0800 @@ -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_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 @@ * 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 @@ */ 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 @@ 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_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 @@ 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 @@ 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 @@ delfd_port(fd, pfd); releasef(fd); - /* remove polldat & port event structure */ - port_remove_fd_object(pfd, pp, pcp); - mutex_exit(&pcp->pc_lock); - return (0); -} + /* + * 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 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); + /* remove polldat & port event structure */ + 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); - 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 @@ 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); } }
--- a/usr/src/uts/common/os/port_subr.c Wed Feb 28 16:55:11 2007 -0800 +++ b/usr/src/uts/common/os/port_subr.c Wed Feb 28 17:06:58 2007 -0800 @@ -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 @@ /* * 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 @@ } /* cleanup merged port queue */ port_remove_event_doneq(pkevp, portq); + removed = 1; } port_unblock(portq); mutex_exit(&portq->portq_mutex); @@ -641,6 +644,7 @@ /* remove polldat struct */ port_pcache_remove_fd(pcp, pfd); + return (removed); } /* @@ -663,7 +667,7 @@ 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); }
--- a/usr/src/uts/common/sys/port_impl.h Wed Feb 28 16:55:11 2007 -0800 +++ b/usr/src/uts/common/sys/port_impl.h Wed Feb 28 17:06:58 2007 -0800 @@ -229,7 +229,7 @@ /* 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 *);