1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 
  22 /*
  23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 
  27 /*
  28  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
  29  */
  30 
  31 #include <sys/types.h>
  32 #include <sys/vnode.h>
  33 #include <sys/vfs_opreg.h>
  34 #include <sys/kmem.h>
  35 #include <fs/fs_subr.h>
  36 #include <sys/proc.h>
  37 #include <sys/kstat.h>
  38 #include <sys/port_impl.h>
  39 
  40 /* local functions */
  41 static int port_open(struct vnode **, int, cred_t *, caller_context_t *);
  42 static int port_close(struct vnode *, int, int, offset_t, cred_t *,
  43         caller_context_t *);
  44 static int port_getattr(struct vnode *, struct vattr *, int, cred_t *,
  45         caller_context_t *);
  46 static int port_access(struct vnode *, int, int, cred_t *, caller_context_t *);
  47 static int port_realvp(vnode_t *, vnode_t **, caller_context_t *);
  48 static int port_poll(vnode_t *, short, int, short *, struct pollhead **,
  49         caller_context_t *);
  50 static void port_inactive(struct vnode *, cred_t *, caller_context_t *);
  51 
  52 const fs_operation_def_t port_vnodeops_template[] = {
  53         { VOPNAME_OPEN,         { .vop_open = port_open } },
  54         { VOPNAME_CLOSE,        { .vop_close = port_close } },
  55         { VOPNAME_GETATTR,      { .vop_getattr = port_getattr } },
  56         { VOPNAME_ACCESS,       { .vop_access = port_access } },
  57         { VOPNAME_INACTIVE,     { .vop_inactive = port_inactive } },
  58         { VOPNAME_FRLOCK,       { .error = fs_error } },
  59         { VOPNAME_REALVP,       { .vop_realvp = port_realvp } },
  60         { VOPNAME_POLL,         { .vop_poll = port_poll } },
  61         { VOPNAME_PATHCONF,     { .error = fs_error } },
  62         { VOPNAME_DISPOSE,      { .error = fs_error } },
  63         { VOPNAME_GETSECATTR,   { .error = fs_error } },
  64         { VOPNAME_SHRLOCK,      { .error = fs_error } },
  65         { NULL,                 { NULL } }
  66 };
  67 
  68 /* ARGSUSED */
  69 static int
  70 port_open(struct vnode **vpp, int flag, cred_t *cr, caller_context_t *ct)
  71 {
  72         return (0);
  73 }
  74 
  75 /*
  76  * port_discard_events() scans the port event queue for events owned
  77  * by current proc. Non-shareable events will be discarded, all other
  78  * events remain in the event queue.
  79  */
  80 void
  81 port_discard_events(port_queue_t *portq)
  82 {
  83         port_kevent_t   *kevp;
  84         pid_t           pid = curproc->p_pid;
  85 
  86         /*
  87          * The call to port_block() is required to avoid interaction
  88          * with other threads in port_get(n).
  89          */
  90         mutex_enter(&portq->portq_mutex);
  91         port_block(portq);
  92         port_push_eventq(portq);        /* empty temporary queue */
  93         kevp = list_head(&portq->portq_list);
  94         while (kevp) {
  95                 if (kevp->portkev_pid == pid) {
  96                         /* own event, check if it is shareable */
  97                         if (kevp->portkev_flags & PORT_KEV_NOSHARE)
  98                                 kevp->portkev_flags |= PORT_KEV_FREE;
  99                 }
 100                 kevp = list_next(&portq->portq_list, kevp);
 101         }
 102         port_unblock(portq);
 103         mutex_exit(&portq->portq_mutex);
 104 }
 105 
 106 /*
 107  * Called from port_close().
 108  * Free all kernel events structures which are still in the event queue.
 109  */
 110 static void
 111 port_close_events(port_queue_t *portq)
 112 {
 113         port_kevent_t   *pkevp;
 114         int             events;         /* ignore events */
 115 
 116         mutex_enter(&portq->portq_mutex);
 117         while (pkevp = list_head(&portq->portq_list)) {
 118                 portq->portq_nent--;
 119                 list_remove(&portq->portq_list, pkevp);
 120                 if (pkevp->portkev_callback) {
 121                         (void) (*pkevp->portkev_callback)(pkevp->portkev_arg,
 122                             &events, pkevp->portkev_pid, PORT_CALLBACK_CLOSE,
 123                             pkevp);
 124                 }
 125                 mutex_exit(&portq->portq_mutex);
 126                 port_free_event_local(pkevp, 0);
 127                 mutex_enter(&portq->portq_mutex);
 128         }
 129 
 130         /*
 131          * Wait for any thread in pollwakeup(), accessing this port to
 132          * finish.
 133          */
 134         while (portq->portq_flags & PORTQ_POLLWK_PEND) {
 135                 cv_wait(&portq->portq_closecv, &portq->portq_mutex);
 136         }
 137         mutex_exit(&portq->portq_mutex);
 138 }
 139 
 140 /*
 141  * The port_close() function is called from standard close(2) when
 142  * the file descriptor is of type S_IFPORT/VPORT.
 143  * Port file descriptors behave like standard file descriptors. It means,
 144  * the port file/vnode is only destroyed on last close.
 145  * If the reference counter is > 1 then
 146  * - sources associated with the port will be notified about the close,
 147  * - objects associated with the port will be dissociated,
 148  * - pending and delivered events will be discarded.
 149  * On last close all references and caches will be removed. The vnode itself
 150  * will be destroyed with VOP_RELE().
 151  */
 152 /* ARGSUSED */
 153 static int
 154 port_close(struct vnode *vp, int flag, int count, offset_t offset, cred_t *cr,
 155     caller_context_t *ct)
 156 {
 157         port_t          *pp;
 158         port_queue_t    *portq;
 159         port_source_t   *ps;
 160         port_source_t   *ps_next;
 161         int             source;
 162 
 163         pp = VTOEP(vp);
 164         mutex_enter(&pp->port_mutex);
 165         if (pp->port_flags & PORT_CLOSED) {
 166                 mutex_exit(&pp->port_mutex);
 167                 return (0);
 168         }
 169         mutex_exit(&pp->port_mutex);
 170 
 171         portq = &pp->port_queue;
 172         if (count > 1) {
 173                 /*
 174                  * It is not the last close.
 175                  * Remove/free all event resources owned by the current proc
 176                  * First notify all with the port associated sources about the
 177                  * close(2). The last argument of the close callback function
 178                  * advises the source about the type of of the close.
 179                  * If the port was set in alert mode by the curren process then
 180                  * remove the alert mode.
 181                  */
 182 
 183                 /* check alert mode of the port */
 184                 mutex_enter(&portq->portq_mutex);
 185                 if ((portq->portq_flags & PORTQ_ALERT) &&
 186                     (portq->portq_alert.portal_pid == curproc->p_pid))
 187                         portq->portq_flags &= ~PORTQ_ALERT;
 188                 mutex_exit(&portq->portq_mutex);
 189 
 190                 /* notify all event sources about port_close() */
 191                 mutex_enter(&portq->portq_source_mutex);
 192                 for (source = 0; source < PORT_SCACHE_SIZE; source++) {
 193                         ps = portq->portq_scache[PORT_SHASH(source)];
 194                         for (; ps != NULL; ps = ps->portsrc_next) {
 195                                 if (ps->portsrc_close != NULL)
 196                                         (*ps->portsrc_close)
 197                                             (ps->portsrc_closearg, pp->port_fd,
 198                                             curproc->p_pid, 0);
 199                         }
 200                 }
 201                 mutex_exit(&portq->portq_source_mutex);
 202                 port_discard_events(&pp->port_queue);
 203                 return (0);
 204         }
 205 
 206         /*
 207          * We are executing the last close of the port -> discard everything
 208          * Make sure that all threads/processes accessing this port leave
 209          * the kernel immediately.
 210          */
 211 
 212         mutex_enter(&portq->portq_mutex);
 213         portq->portq_flags |= PORTQ_CLOSE;
 214         while (portq->portq_thrcnt > 0) {
 215                 if (portq->portq_thread != NULL)
 216                         cv_signal(&portq->portq_thread->portget_cv);
 217                 cv_wait(&portq->portq_closecv, &portq->portq_mutex);
 218         }
 219         mutex_exit(&portq->portq_mutex);
 220 
 221         /*
 222          * Send "last close" message to associated sources.
 223          * - new event allocation requests are being denied since uf_file entry
 224          *   was set to NULL in closeandsetf().
 225          * - all still allocated event structures must be returned to the
 226          *   port immediately:
 227          *      - call port_free_event(*event) or
 228          *      - call port_send_event(*event) to complete event operations
 229          *        which need activities in a dedicated process environment.
 230          * The port_close() function waits until all allocated event structures
 231          * are delivered back to the port.
 232          */
 233 
 234         mutex_enter(&portq->portq_source_mutex);
 235         for (source = 0; source < PORT_SCACHE_SIZE; source++) {
 236                 ps = portq->portq_scache[PORT_SHASH(source)];
 237                 for (; ps != NULL; ps = ps_next) {
 238                         ps_next = ps->portsrc_next;
 239                         if (ps->portsrc_close != NULL)
 240                                 (*ps->portsrc_close)(ps->portsrc_closearg,
 241                                     pp->port_fd, curproc->p_pid, 1);
 242                         kmem_free(ps, sizeof (port_source_t));
 243                 }
 244         }
 245         kmem_free(portq->portq_scache,
 246             PORT_SCACHE_SIZE * sizeof (port_source_t *));
 247         portq->portq_scache = NULL;
 248         mutex_exit(&portq->portq_source_mutex);
 249 
 250         mutex_enter(&portq->portq_mutex);
 251         /* Wait for outstanding events */
 252         while (pp->port_curr > portq->portq_nent)
 253                 cv_wait(&portq->portq_closecv, &portq->portq_mutex);
 254         mutex_exit(&portq->portq_mutex);
 255 
 256         /*
 257          * If PORT_SOURCE_FD objects were not associated with the port then
 258          * it is necessary to free the port_fdcache structure here.
 259          */
 260 
 261         if (portq->portq_pcp != NULL) {
 262                 mutex_destroy(&portq->portq_pcp->pc_lock);
 263                 kmem_free(portq->portq_pcp, sizeof (port_fdcache_t));
 264                 portq->portq_pcp = NULL;
 265         }
 266 
 267         /*
 268          * Now all events are passed back to the port,
 269          * discard remaining events in the port queue
 270          */
 271 
 272         port_close_events(portq);
 273         return (0);
 274 }
 275 
 276 /*
 277  * The port_poll() function is the VOP_POLL() entry of event ports.
 278  * Event ports return:
 279  * POLLIN  : events are available in the event queue
 280  * POLLOUT : event queue can still accept events
 281  */
 282 /*ARGSUSED*/
 283 static int
 284 port_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
 285     struct pollhead **phpp, caller_context_t *ct)
 286 {
 287         port_t          *pp;
 288         port_queue_t    *portq;
 289         short           levents;
 290 
 291         pp = VTOEP(vp);
 292         portq = &pp->port_queue;
 293         levents = 0;
 294         mutex_enter(&portq->portq_mutex);
 295         if (portq->portq_nent)
 296                 levents = POLLIN;
 297         if (pp->port_curr < pp->port_max_events)
 298                 levents |= POLLOUT;
 299         levents &= events;
 300         *reventsp = levents;
 301         if ((levents == 0 && !anyyet) || (events & POLLET)) {
 302                 *phpp = &pp->port_pollhd;
 303                 portq->portq_flags |= events & POLLIN ? PORTQ_POLLIN : 0;
 304                 portq->portq_flags |= events & POLLOUT ? PORTQ_POLLOUT : 0;
 305         }
 306         mutex_exit(&portq->portq_mutex);
 307         return (0);
 308 }
 309 
 310 
 311 /* ARGSUSED */
 312 static int
 313 port_getattr(struct vnode *vp, struct vattr *vap, int flags, cred_t *cr,
 314     caller_context_t *ct)
 315 {
 316         port_t  *pp;
 317         extern dev_t portdev;
 318 
 319         pp = VTOEP(vp);
 320 
 321         vap->va_type = vp->v_type;        /* vnode type (for create) */
 322         vap->va_mode = 0;            /* file access mode */
 323         vap->va_uid = pp->port_uid;       /* owner user id */
 324         vap->va_gid = pp->port_gid;       /* owner group id */
 325         vap->va_fsid = portdev;              /* file system id  */
 326         vap->va_nodeid = (ino64_t)0; /* node id */
 327         vap->va_nlink = vp->v_count;      /* number of references to file */
 328         vap->va_size = (u_offset_t)pp->port_queue.portq_nent; /* file size */
 329         vap->va_atime = pp->port_ctime;   /* time of last access */
 330         vap->va_mtime = pp->port_ctime;   /* time of last modification */
 331         vap->va_ctime = pp->port_ctime;   /* time file ``created'' */
 332         vap->va_rdev = portdev;              /* device the file represents */
 333         vap->va_blksize = 0;         /* fundamental block size */
 334         vap->va_nblocks = (fsblkcnt64_t)0;   /* # of blocks allocated */
 335         vap->va_seq = 0;             /* sequence number */
 336 
 337         return (0);
 338 }
 339 
 340 /*
 341  * Destroy the port.
 342  */
 343 /* ARGSUSED */
 344 static void
 345 port_inactive(struct vnode *vp, cred_t *cr, caller_context_t *ct)
 346 {
 347         port_t  *pp = VTOEP(vp);
 348         extern  port_kstat_t port_kstat;
 349 
 350         mutex_enter(&port_control.pc_mutex);
 351         port_control.pc_nents--;
 352         curproc->p_portcnt--;
 353         port_kstat.pks_ports.value.ui32--;
 354         mutex_exit(&port_control.pc_mutex);
 355         vn_free(vp);
 356         mutex_destroy(&pp->port_mutex);
 357         mutex_destroy(&pp->port_queue.portq_mutex);
 358         mutex_destroy(&pp->port_queue.portq_source_mutex);
 359         kmem_free(pp, sizeof (port_t));
 360 }
 361 
 362 /* ARGSUSED */
 363 static int
 364 port_access(struct vnode *vp, int mode, int flags, cred_t *cr,
 365     caller_context_t *ct)
 366 {
 367         return (0);
 368 }
 369 
 370 /* ARGSUSED */
 371 static int
 372 port_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
 373 {
 374         *vpp = vp;
 375         return (0);
 376 }