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 2020 Joyent, Inc.
  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                 port_t *pp = pkevp->portkev_port;
 119 
 120                 portq->portq_nent--;
 121                 list_remove(&portq->portq_list, pkevp);
 122                 if (pkevp->portkev_callback) {
 123                         (void) (*pkevp->portkev_callback)(pkevp->portkev_arg,
 124                             &events, pkevp->portkev_pid, PORT_CALLBACK_CLOSE,
 125                             pkevp);
 126                 }
 127                 /*
 128                  * Don't drop the portq_mutex, but instead perform the
 129                  * decrement of port_curr in advance of calling
 130                  * port_free_event_local().  We do need to reacquire
 131                  * portq_mutex so we can properly wait for any
 132                  * pollwakeup()-signalled threads to finish up.
 133                  */
 134                 if (--pp->port_curr < pp->port_max_events)
 135                         cv_signal(&pp->port_cv);
 136                 port_free_event_local(pkevp, B_FALSE);
 137                 mutex_enter(&portq->portq_mutex);
 138         }
 139 
 140         /*
 141          * Wait for any thread in pollwakeup(), accessing this port to
 142          * finish.
 143          */
 144         while (portq->portq_flags & PORTQ_POLLWK_PEND) {
 145                 cv_wait(&portq->portq_closecv, &portq->portq_mutex);
 146         }
 147         mutex_exit(&portq->portq_mutex);
 148 }
 149 
 150 /*
 151  * The port_close() function is called from standard close(2) when
 152  * the file descriptor is of type S_IFPORT/VPORT.
 153  * Port file descriptors behave like standard file descriptors. It means,
 154  * the port file/vnode is only destroyed on last close.
 155  * If the reference counter is > 1 then
 156  * - sources associated with the port will be notified about the close,
 157  * - objects associated with the port will be dissociated,
 158  * - pending and delivered events will be discarded.
 159  * On last close all references and caches will be removed. The vnode itself
 160  * will be destroyed with VOP_RELE().
 161  */
 162 /* ARGSUSED */
 163 static int
 164 port_close(struct vnode *vp, int flag, int count, offset_t offset, cred_t *cr,
 165     caller_context_t *ct)
 166 {
 167         port_t          *pp;
 168         port_queue_t    *portq;
 169         port_source_t   *ps;
 170         port_source_t   *ps_next;
 171         int             source;
 172 
 173         pp = VTOEP(vp);
 174         mutex_enter(&pp->port_mutex);
 175         if (pp->port_flags & PORT_CLOSED) {
 176                 mutex_exit(&pp->port_mutex);
 177                 return (0);
 178         }
 179         mutex_exit(&pp->port_mutex);
 180 
 181         portq = &pp->port_queue;
 182         if (count > 1) {
 183                 /*
 184                  * It is not the last close.
 185                  * Remove/free all event resources owned by the current proc
 186                  * First notify all with the port associated sources about the
 187                  * close(2). The last argument of the close callback function
 188                  * advises the source about the type of of the close.
 189                  * If the port was set in alert mode by the curren process then
 190                  * remove the alert mode.
 191                  */
 192 
 193                 /* check alert mode of the port */
 194                 mutex_enter(&portq->portq_mutex);
 195                 if ((portq->portq_flags & PORTQ_ALERT) &&
 196                     (portq->portq_alert.portal_pid == curproc->p_pid))
 197                         portq->portq_flags &= ~PORTQ_ALERT;
 198                 mutex_exit(&portq->portq_mutex);
 199 
 200                 /* notify all event sources about port_close() */
 201                 mutex_enter(&portq->portq_source_mutex);
 202                 for (source = 0; source < PORT_SCACHE_SIZE; source++) {
 203                         ps = portq->portq_scache[PORT_SHASH(source)];
 204                         for (; ps != NULL; ps = ps->portsrc_next) {
 205                                 if (ps->portsrc_close != NULL)
 206                                         (*ps->portsrc_close)
 207                                             (ps->portsrc_closearg, pp->port_fd,
 208                                             curproc->p_pid, 0);
 209                         }
 210                 }
 211                 mutex_exit(&portq->portq_source_mutex);
 212                 port_discard_events(&pp->port_queue);
 213                 return (0);
 214         }
 215 
 216         /*
 217          * We are executing the last close of the port -> discard everything
 218          * Make sure that all threads/processes accessing this port leave
 219          * the kernel immediately.
 220          */
 221 
 222         mutex_enter(&portq->portq_mutex);
 223         portq->portq_flags |= PORTQ_CLOSE;
 224         while (portq->portq_thrcnt > 0) {
 225                 if (portq->portq_thread != NULL)
 226                         cv_signal(&portq->portq_thread->portget_cv);
 227                 cv_wait(&portq->portq_closecv, &portq->portq_mutex);
 228         }
 229         mutex_exit(&portq->portq_mutex);
 230 
 231         /*
 232          * Send "last close" message to associated sources.
 233          * - new event allocation requests are being denied since uf_file entry
 234          *   was set to NULL in closeandsetf().
 235          * - all still allocated event structures must be returned to the
 236          *   port immediately:
 237          *      - call port_free_event(*event) or
 238          *      - call port_send_event(*event) to complete event operations
 239          *        which need activities in a dedicated process environment.
 240          * The port_close() function waits until all allocated event structures
 241          * are delivered back to the port.
 242          */
 243 
 244         mutex_enter(&portq->portq_source_mutex);
 245         for (source = 0; source < PORT_SCACHE_SIZE; source++) {
 246                 ps = portq->portq_scache[PORT_SHASH(source)];
 247                 for (; ps != NULL; ps = ps_next) {
 248                         ps_next = ps->portsrc_next;
 249                         if (ps->portsrc_close != NULL)
 250                                 (*ps->portsrc_close)(ps->portsrc_closearg,
 251                                     pp->port_fd, curproc->p_pid, 1);
 252                         kmem_free(ps, sizeof (port_source_t));
 253                 }
 254         }
 255         kmem_free(portq->portq_scache,
 256             PORT_SCACHE_SIZE * sizeof (port_source_t *));
 257         portq->portq_scache = NULL;
 258         mutex_exit(&portq->portq_source_mutex);
 259 
 260         mutex_enter(&portq->portq_mutex);
 261         /* Wait for outstanding events */
 262         while (pp->port_curr > portq->portq_nent)
 263                 cv_wait(&portq->portq_closecv, &portq->portq_mutex);
 264         mutex_exit(&portq->portq_mutex);
 265 
 266         /*
 267          * If PORT_SOURCE_FD objects were not associated with the port then
 268          * it is necessary to free the port_fdcache structure here.
 269          */
 270 
 271         if (portq->portq_pcp != NULL) {
 272                 mutex_destroy(&portq->portq_pcp->pc_lock);
 273                 kmem_free(portq->portq_pcp, sizeof (port_fdcache_t));
 274                 portq->portq_pcp = NULL;
 275         }
 276 
 277         /*
 278          * Now all events are passed back to the port,
 279          * discard remaining events in the port queue
 280          */
 281 
 282         port_close_events(portq);
 283         return (0);
 284 }
 285 
 286 /*
 287  * The port_poll() function is the VOP_POLL() entry of event ports.
 288  * Event ports return:
 289  * POLLIN  : events are available in the event queue
 290  * POLLOUT : event queue can still accept events
 291  */
 292 /*ARGSUSED*/
 293 static int
 294 port_poll(vnode_t *vp, short events, int anyyet, short *reventsp,
 295     struct pollhead **phpp, caller_context_t *ct)
 296 {
 297         port_t          *pp;
 298         port_queue_t    *portq;
 299         short           levents;
 300 
 301         pp = VTOEP(vp);
 302         portq = &pp->port_queue;
 303         levents = 0;
 304         mutex_enter(&portq->portq_mutex);
 305         if (portq->portq_nent)
 306                 levents = POLLIN;
 307         if (pp->port_curr < pp->port_max_events)
 308                 levents |= POLLOUT;
 309         levents &= events;
 310         *reventsp = levents;
 311         if ((levents == 0 && !anyyet) || (events & POLLET)) {
 312                 *phpp = &pp->port_pollhd;
 313                 portq->portq_flags |= events & POLLIN ? PORTQ_POLLIN : 0;
 314                 portq->portq_flags |= events & POLLOUT ? PORTQ_POLLOUT : 0;
 315         }
 316         mutex_exit(&portq->portq_mutex);
 317         return (0);
 318 }
 319 
 320 
 321 /* ARGSUSED */
 322 static int
 323 port_getattr(struct vnode *vp, struct vattr *vap, int flags, cred_t *cr,
 324     caller_context_t *ct)
 325 {
 326         port_t  *pp;
 327         extern dev_t portdev;
 328 
 329         pp = VTOEP(vp);
 330 
 331         vap->va_type = vp->v_type;        /* vnode type (for create) */
 332         vap->va_mode = 0;            /* file access mode */
 333         vap->va_uid = pp->port_uid;       /* owner user id */
 334         vap->va_gid = pp->port_gid;       /* owner group id */
 335         vap->va_fsid = portdev;              /* file system id  */
 336         vap->va_nodeid = (ino64_t)0; /* node id */
 337         vap->va_nlink = vp->v_count;      /* number of references to file */
 338         vap->va_size = (u_offset_t)pp->port_queue.portq_nent; /* file size */
 339         vap->va_atime = pp->port_ctime;   /* time of last access */
 340         vap->va_mtime = pp->port_ctime;   /* time of last modification */
 341         vap->va_ctime = pp->port_ctime;   /* time file ``created'' */
 342         vap->va_rdev = portdev;              /* device the file represents */
 343         vap->va_blksize = 0;         /* fundamental block size */
 344         vap->va_nblocks = (fsblkcnt64_t)0;   /* # of blocks allocated */
 345         vap->va_seq = 0;             /* sequence number */
 346 
 347         return (0);
 348 }
 349 
 350 /*
 351  * Destroy the port.
 352  */
 353 /* ARGSUSED */
 354 static void
 355 port_inactive(struct vnode *vp, cred_t *cr, caller_context_t *ct)
 356 {
 357         port_t  *pp = VTOEP(vp);
 358         extern  port_kstat_t port_kstat;
 359 
 360         mutex_enter(&port_control.pc_mutex);
 361         port_control.pc_nents--;
 362         curproc->p_portcnt--;
 363         port_kstat.pks_ports.value.ui32--;
 364         mutex_exit(&port_control.pc_mutex);
 365         vn_free(vp);
 366         mutex_destroy(&pp->port_mutex);
 367         mutex_destroy(&pp->port_queue.portq_mutex);
 368         mutex_destroy(&pp->port_queue.portq_source_mutex);
 369         kmem_free(pp, sizeof (port_t));
 370 }
 371 
 372 /* ARGSUSED */
 373 static int
 374 port_access(struct vnode *vp, int mode, int flags, cred_t *cr,
 375     caller_context_t *ct)
 376 {
 377         return (0);
 378 }
 379 
 380 /* ARGSUSED */
 381 static int
 382 port_realvp(vnode_t *vp, vnode_t **vpp, caller_context_t *ct)
 383 {
 384         *vpp = vp;
 385         return (0);
 386 }