Print this page
14249 pseudo-terminal nomenclature should reflect POSIX
Change-Id: Ib4a3cef899ff4c71b09cb0dc6878863c5e8357bc

Split Close
Expand all
Collapse all
          --- old/usr/src/uts/common/io/ptms_conf.c
          +++ new/usr/src/uts/common/io/ptms_conf.c
↓ open down ↓ 13 lines elided ↑ open up ↑
  14   14   * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15   15   * If applicable, add the following below this CDDL HEADER, with the
  16   16   * fields enclosed by brackets "[]" replaced with your own identifying
  17   17   * information: Portions Copyright [yyyy] [name of copyright owner]
  18   18   *
  19   19   * CDDL HEADER END
  20   20   */
  21   21  /*
  22   22   * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  23   23   * Use is subject to license terms.
       24 + * Copyright 2021 Oxide Computer Company
  24   25   */
  25   26  
  26   27  /*
  27      - * This file contains global data and code shared between master and slave parts
  28      - * of the pseudo-terminal driver.
       28 + * PSEUDO-TERMINAL COMMON DATA AND ROUTINES (PTM, PTS)
  29   29   *
  30      - * Pseudo terminals (or pt's for short) are allocated dynamically.
  31      - * pt's are put in the global ptms_slots array indexed by minor numbers.
       30 + * This file contains global data and code shared between manager and
       31 + * subsidiary parts of the pseudo-terminal driver.
  32   32   *
  33      - * The slots array is initially small (of the size NPTY_MIN). When more pt's are
       33 + * Pseudo-terminals (or ptys for short) are allocated dynamically.
       34 + * ptys are put in the global ptms_slots array indexed by minor numbers.
       35 + *
       36 + * The slots array is initially small (of the size NPTY_MIN). When more ptys are
  34   37   * needed than the slot array size, the larger slot array is allocated and all
  35      - * opened pt's move to the new one.
       38 + * opened ptys move to the new one.
  36   39   *
  37      - * Resource allocation:
  38   40   *
  39      - *      pt_ttys structures are allocated via pt_ttys_alloc, which uses
  40      - *              kmem_cache_alloc().
  41      - *      Minor number space is allocated via vmem_alloc() interface.
  42      - *      ptms_slots arrays are allocated via kmem_alloc().
       41 + * RESOURCE ALLOCATION
  43   42   *
  44      - *   Minors are started from 1 instead of 0 because vmem_alloc returns 0 in case
  45      - *   of failure. Also, in anticipation of removing clone device interface to
  46      - *   pseudo-terminal subsystem, minor 0 should not be used. (Potential future
  47      - *   development).
       43 + * - pt_ttys structures are allocated via pt_ttys_alloc, which uses
       44 + *   kmem_cache_alloc().
       45 + * - Minor number space is allocated via vmem_alloc() interface.
       46 + * - ptms_slots arrays are allocated via kmem_alloc().
  48   47   *
  49      - *   After the table slot size reaches pt_maxdelta, we stop 2^N extension
  50      - *   algorithm and start extending the slot table size by pt_maxdelta.
       48 + * Minors start from 1 instead of 0, because vmem_alloc() returns 0 in case of
       49 + * failure.  Also, in anticipation of removing the clone device interface to
       50 + * pseudo-terminal subsystem, minor 0 should not be used. (Potential future
       51 + * development).
  51   52   *
  52      - *   Device entries /dev/pts directory are created dynamically by the
  53      - *   /dev filesystem. We no longer call ddi_create_minor_node() on
  54      - *   behalf of the slave driver. The /dev filesystem creates /dev/pts
  55      - *   nodes based on the pt_ttys array.
       53 + * After the table slot size reaches pt_maxdelta, we stop 2^N extension
       54 + * algorithm and start extending the slot table size by pt_maxdelta.
  56   55   *
  57      - * Synchronization:
       56 + * Device entries /dev/pts directory are created dynamically by the /dev
       57 + * filesystem.  We no longer call ddi_create_minor_node() on behalf of the
       58 + * subsidiary driver.  The /dev filesystem creates /dev/pts nodes based on the
       59 + * pt_ttys array.
  58   60   *
  59      - *   All global data synchronization between ptm/pts is done via global
  60      - *   ptms_lock mutex which is implicitly initialized by declaring it global.
  61   61   *
  62      - *   Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
  63      - *   pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
       62 + * SYNCHRONIZATION
  64   63   *
  65      - *   PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
  66      - *   which allow reader locks to be reacquired by the same thread (usual
  67      - *   reader/writer locks can't be used for that purpose since it is illegal for
  68      - *   a thread to acquire a lock it already holds, even as a reader). The sole
  69      - *   purpose of these macros is to guarantee that the peer queue will not
  70      - *   disappear (due to closing peer) while it is used. It is safe to use
  71      - *   PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
  72      - *   they are not real locks but reference counts).
       64 + * All global data synchronization between ptm/pts is done via global ptms_lock
       65 + * mutex which is implicitly initialized by declaring it global.
  73   66   *
  74      - *   PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in master/slave
  75      - *   open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
  76      - *   be set to appropriate queues *after* qprocson() is called during open (to
  77      - *   prevent peer from accessing the queue with incomplete plumbing) and set to
  78      - *   NULL before qprocsoff() is called during close. Put and service procedures
  79      - *   use PT_ENTER_READ/PT_EXIT_READ to prevent peer closes.
       67 + * Individual fields of pt_ttys structure (except ptm_rdq, pts_rdq and
       68 + * pt_nullmsg) are protected by pt_ttys.pt_lock mutex.
  80   69   *
  81      - *   The pt_nullmsg field is only used in open/close routines and is also
  82      - *   protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
  83      - *   holds.
       70 + * PT_ENTER_READ/PT_ENTER_WRITE are reference counter based read-write locks
       71 + * which allow reader locks to be reacquired by the same thread (usual
       72 + * reader/writer locks can't be used for that purpose since it is illegal for a
       73 + * thread to acquire a lock it already holds, even as a reader). The sole
       74 + * purpose of these macros is to guarantee that the peer queue will not
       75 + * disappear (due to closing peer) while it is used. It is safe to use
       76 + * PT_ENTER_READ/PT_EXIT_READ brackets across calls like putq/putnext (since
       77 + * they are not real locks but reference counts).
  84   78   *
  85      - * Lock Ordering:
       79 + * PT_ENTER_WRITE/PT_EXIT_WRITE brackets are used ONLY in manager/subsidiary
       80 + * open/close paths to modify ptm_rdq and pts_rdq fields. These fields should
       81 + * be set to appropriate queues *after* qprocson() is called during open (to
       82 + * prevent peer from accessing the queue with incomplete plumbing) and set to
       83 + * NULL before qprocsoff() is called during close. Put and service procedures
       84 + * use PT_ENTER_READ/PT_EXIT_READ to prevent peer closes.
  86   85   *
  87      - *   If both ptms_lock and per-pty lock should be held, ptms_lock should always
  88      - *   be entered first, followed by per-pty lock.
       86 + * The pt_nullmsg field is only used in open/close routines and is also
       87 + * protected by PT_ENTER_WRITE/PT_EXIT_WRITE brackets to avoid extra mutex
       88 + * holds.
  89   89   *
  90      - * Global functions:
  91   90   *
       91 + * LOCK ORDERING
       92 + *
       93 + * If both ptms_lock and per-pty lock should be held, ptms_lock should always
       94 + * be entered first, followed by per-pty lock.
       95 + *
       96 + *
       97 + * GLOBAL FUNCTIONS
       98 + *
  92   99   * void ptms_init(void);
  93  100   *
  94  101   *      Called by pts/ptm _init entry points. It performes one-time
  95      - *      initialization needed for both pts and ptm. This initialization is done
  96      - *      here and not in ptms_initspace because all these data structures are not
      102 + *      initialization needed for both pts and ptm. This initialization is done
      103 + *      here and not in ptms_initspace because all these data structures are not
  97  104   *      needed if pseudo-terminals are not used in the system.
  98  105   *
  99  106   * struct pt_ttys *pt_ttys_alloc(void);
 100  107   *
 101  108   *      Allocate new minor number and pseudo-terminal entry. May sleep.
 102  109   *      New minor number is recorded in pt_minor field of the entry returned.
 103  110   *      This routine also initializes pt_minor and pt_state fields of the new
 104  111   *      pseudo-terminal and puts a pointer to it into ptms_slots array.
 105  112   *
 106  113   * struct pt_ttys *ptms_minor2ptty(minor_t minor)
↓ open down ↓ 3 lines elided ↑ open up ↑
 110  117   *
 111  118   * int ptms_minor_valid(minor_t minor, uid_t *ruid, gid_t *rgid)
 112  119   *
 113  120   *      Check if minor refers to an allocated pty in the current zone.
 114  121   *      Returns
 115  122   *               0 if not allocated or not for this zone.
 116  123   *               1 if an allocated pty in the current zone.
 117  124   *      Also returns owner of pty.
 118  125   *
 119  126   * int ptms_minor_exists(minor_t minor)
      127 + *
 120  128   *      Check if minor refers to an allocated pty (in any zone)
 121  129   *      Returns
 122  130   *              0 if not an allocated pty
 123  131   *              1 if an allocated pty
 124  132   *
 125  133   * void ptms_set_owner(minor_t minor, uid_t ruid, gid_t rgid)
 126  134   *
 127  135   *      Sets the owner associated with a pty.
 128  136   *
 129  137   * void ptms_close(struct pt_ttys *pt, uint_t flags_to_clear);
 130  138   *
 131  139   *      Clear flags_to_clear in pt and if no one owns it (PTMOPEN/PTSOPEN not
 132      - *      set) free pt entry and corresponding slot.
      140 + *      set) free pt entry and corresponding slot.
 133  141   *
 134      - * Tuneables and configuration:
 135  142   *
      143 + * TUNEABLES AND CONFIGURATION
      144 + *
 136  145   *      pt_cnt: minimum number of pseudo-terminals in the system. The system
 137  146   *              should provide at least this number of ptys (provided sufficient
 138      - *              memory is available). It is different from the older semantics
      147 + *              memory is available). It is different from the older semantics
 139  148   *              of pt_cnt meaning maximum number of ptys.
 140  149   *              Set to 0 by default.
 141  150   *
 142  151   *      pt_max_pty: Maximum number of pseudo-terminals in the system. The system
 143  152   *              should not allocate more ptys than pt_max_pty (although, it may
 144      - *              impose stricter maximum). Zero value means no user-defined
 145      - *              maximum. This is intended to be used as "denial-of-service"
      153 + *              impose stricter maximum). Zero value means no user-defined
      154 + *              maximum. This is intended to be used as "denial-of-service"
 146  155   *              protection.
 147  156   *              Set to 0 by default.
 148  157   *
 149      - *         Both pt_cnt and pt_max_pty may be modified during system lifetime
 150      - *         with their semantics preserved.
      158 + *              Both pt_cnt and pt_max_pty may be modified during system
      159 + *              lifetime with their semantics preserved.
 151  160   *
 152  161   *      pt_init_cnt: Initial size of ptms_slots array. Set to NPTY_INITIAL.
 153  162   *
 154  163   *      pt_ptyofmem: Approximate percentage of system memory that may be
 155  164   *              occupied by pty data structures. Initially set to NPTY_PERCENT.
 156  165   *              This variable is used once during initialization to estimate
 157      - *              maximum number of ptys in the system. The actual maximum is
      166 + *              maximum number of ptys in the system. The actual maximum is
 158  167   *              determined as minimum of pt_max_pty and calculated value.
 159  168   *
 160  169   *      pt_maxdelta: Maximum extension chunk of the slot table.
 161  170   */
 162  171  
 163  172  
 164  173  
 165  174  #include <sys/types.h>
 166  175  #include <sys/param.h>
 167  176  #include <sys/termios.h>
↓ open down ↓ 18 lines elided ↑ open up ↑
 186  195  
 187  196  #define NPTY_PERCENT 5
 188  197  
 189  198  /* Maximum increment of the slot table size */
 190  199  #define PTY_MAXDELTA 128
 191  200  
 192  201  /*
 193  202   * Tuneable variables.
 194  203   */
 195  204  uint_t  pt_cnt = 0;                     /* Minimum number of ptys */
 196      -size_t  pt_max_pty = 0;                 /* Maximum number of ptys */
      205 +size_t  pt_max_pty = 0;                 /* Maximum number of ptys */
 197  206  uint_t  pt_init_cnt = NPTY_INITIAL;     /* Initial number of ptms slots */
 198  207  uint_t  pt_pctofmem = NPTY_PERCENT;     /* Percent of memory to use for ptys */
 199  208  uint_t  pt_maxdelta = PTY_MAXDELTA;     /* Max increment for slot table size */
 200  209  
 201  210  /* Other global variables */
 202  211  
 203  212  kmutex_t ptms_lock;                     /* Global data access lock */
 204  213  
 205  214  /*
 206  215   * Slot array and its management variables
 207  216   */
 208  217  static struct pt_ttys **ptms_slots = NULL; /* Slots for actual pt structures */
 209  218  static size_t ptms_nslots = 0;          /* Size of slot array */
 210  219  static size_t ptms_ptymax = 0;          /* Maximum number of ptys */
 211  220  static size_t ptms_inuse = 0;           /* # of ptys currently allocated */
 212  221  
 213      -dev_info_t      *pts_dip = NULL;        /* set if slave is attached */
      222 +dev_info_t *pts_dip = NULL;             /* Set if subsidiary is attached */
 214  223  
 215  224  static struct kmem_cache *ptms_cache = NULL;    /* pty cache */
 216  225  
 217  226  static vmem_t *ptms_minor_arena = NULL; /* Arena for device minors */
 218  227  
 219  228  static uint_t ptms_roundup(uint_t);
 220  229  static int ptms_constructor(void *, void *, int);
 221  230  static void ptms_destructor(void *, void *);
 222  231  static minor_t ptms_grow(void);
 223  232  
 224  233  /*
 225      - * Total size occupied by one pty. Each pty master/slave pair consumes one
 226      - * pointer for ptms_slots array, one pt_ttys structure and one empty message
 227      - * preallocated for pts close.
      234 + * Total size occupied by one pty. Each pty manager/subsidiary pair consumes
      235 + * one pointer for ptms_slots array, one pt_ttys structure, and one empty
      236 + * message preallocated for pts close.
 228  237   */
 229  238  
 230  239  #define PTY_SIZE (sizeof (struct pt_ttys) + \
 231  240      sizeof (struct pt_ttys *) + \
 232  241      sizeof (dblk_t))
 233  242  
 234  243  #ifdef DEBUG
 235  244  int ptms_debug = 0;
 236  245  #define PTMOD_ID 5
 237  246  #endif
 238  247  
 239  248  /*
 240  249   * Clear all bits of x except the highest bit
 241  250   */
 242      -#define truncate(x)     ((x) <= 2 ? (x) : (1 << (highbit(x) - 1)))
      251 +#define truncate(x)     ((x) <= 2 ? (x) : (1 << (highbit(x) - 1)))
 243  252  
 244  253  /*
 245  254   * Roundup the number to the nearest power of 2
 246  255   */
 247  256  static uint_t
 248  257  ptms_roundup(uint_t x)
 249  258  {
 250  259          uint_t p = truncate(x); /* x with non-high bits stripped */
 251  260  
 252  261          /*
↓ open down ↓ 35 lines elided ↑ open up ↑
 288  297                  ptms_ptymax = ptms_roundup((pt_pctofmem * kmem_maxavail()) /
 289  298                      (100 * PTY_SIZE));
 290  299          }
 291  300          mutex_exit(&ptms_lock);
 292  301  }
 293  302  
 294  303  /*
 295  304   * This routine attaches the pts dip.
 296  305   */
 297  306  int
 298      -ptms_attach_slave(void)
      307 +ptms_attach_subsidiary(void)
 299  308  {
 300  309          if (pts_dip == NULL && i_ddi_attach_pseudo_node("pts") == NULL)
 301  310                  return (-1);
 302  311  
 303  312          ASSERT(pts_dip);
 304  313          return (0);
 305  314  }
 306  315  
 307  316  /*
 308  317   * Called from /dev fs. Checks if dip is attached,
 309  318   * and if it is, returns its major number.
 310  319   */
 311  320  major_t
 312      -ptms_slave_attached(void)
      321 +ptms_subsidiary_attached(void)
 313  322  {
 314  323          major_t maj = DDI_MAJOR_T_NONE;
 315  324  
 316  325          mutex_enter(&ptms_lock);
 317  326          if (pts_dip)
 318  327                  maj = ddi_driver_major(pts_dip);
 319  328          mutex_exit(&ptms_lock);
 320  329  
 321  330          return (maj);
 322  331  }
↓ open down ↓ 341 lines elided ↑ open up ↑
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX