Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tty: rework pty count limiting

After adding devpts multiple-insrances sysctl kernel.pty.max limit pty count for
each devpts instance independently, while kernel.pty.nr shows total pty count.

This patch restores sysctl kernel.pty.max as global limit (4096 by default),
adds pty reseve for main devpts (mounted without "newinstance" argument),
and new sysctl to tune it: kernel.pty.reserve (1024 by default)

Also it adds devpts mount option "max=%d" to limit pty count for each devpts
instance independently. (by default NR_UNIX98_PTY_MAX == 2^20)

Thus devpts instances in containers cannot eat up all available pty even if we didn't
set any limits, while with "max" argument we can adjust limits more precisely.

Plus, now open("/dev/ptmx") return -ENOSPC in case lack of pty indexes,
this is more informative than -EIO.

Signed-off-by: Konstantin Khlebnikov <khlebnikov@openvz.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

authored by

Konstantin Khlebnikov and committed by
Greg Kroah-Hartman
e9aba515 a4834c10

+31 -4
+30 -4
fs/devpts/inode.c
··· 41 41 * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. 42 42 */ 43 43 static int pty_limit = NR_UNIX98_PTY_DEFAULT; 44 + static int pty_reserve = NR_UNIX98_PTY_RESERVE; 44 45 static int pty_limit_min; 45 - static int pty_limit_max = NR_UNIX98_PTY_MAX; 46 + static int pty_limit_max = INT_MAX; 46 47 static int pty_count; 47 48 48 49 static struct ctl_table pty_table[] = { ··· 52 51 .maxlen = sizeof(int), 53 52 .mode = 0644, 54 53 .data = &pty_limit, 54 + .proc_handler = proc_dointvec_minmax, 55 + .extra1 = &pty_limit_min, 56 + .extra2 = &pty_limit_max, 57 + }, { 58 + .procname = "reserve", 59 + .maxlen = sizeof(int), 60 + .mode = 0644, 61 + .data = &pty_reserve, 55 62 .proc_handler = proc_dointvec_minmax, 56 63 .extra1 = &pty_limit_min, 57 64 .extra2 = &pty_limit_max, ··· 103 94 umode_t mode; 104 95 umode_t ptmxmode; 105 96 int newinstance; 97 + int max; 106 98 }; 107 99 108 100 enum { 109 - Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, 101 + Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, Opt_max, 110 102 Opt_err 111 103 }; 112 104 ··· 118 108 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES 119 109 {Opt_ptmxmode, "ptmxmode=%o"}, 120 110 {Opt_newinstance, "newinstance"}, 111 + {Opt_max, "max=%d"}, 121 112 #endif 122 113 {Opt_err, NULL} 123 114 }; ··· 165 154 opts->gid = 0; 166 155 opts->mode = DEVPTS_DEFAULT_MODE; 167 156 opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; 157 + opts->max = NR_UNIX98_PTY_MAX; 168 158 169 159 /* newinstance makes sense only on initial mount */ 170 160 if (op == PARSE_MOUNT) ··· 208 196 /* newinstance makes sense only on initial mount */ 209 197 if (op == PARSE_MOUNT) 210 198 opts->newinstance = 1; 199 + break; 200 + case Opt_max: 201 + if (match_int(&args[0], &option) || 202 + option < 0 || option > NR_UNIX98_PTY_MAX) 203 + return -EINVAL; 204 + opts->max = option; 211 205 break; 212 206 #endif 213 207 default: ··· 321 303 seq_printf(seq, ",mode=%03o", opts->mode); 322 304 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES 323 305 seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); 306 + if (opts->max < NR_UNIX98_PTY_MAX) 307 + seq_printf(seq, ",max=%d", opts->max); 324 308 #endif 325 309 326 310 return 0; ··· 503 483 return -ENOMEM; 504 484 505 485 mutex_lock(&allocated_ptys_lock); 486 + if (pty_count >= pty_limit - 487 + (fsi->mount_opts.newinstance ? pty_reserve : 0)) { 488 + mutex_unlock(&allocated_ptys_lock); 489 + return -ENOSPC; 490 + } 491 + 506 492 ida_ret = ida_get_new(&fsi->allocated_ptys, &index); 507 493 if (ida_ret < 0) { 508 494 mutex_unlock(&allocated_ptys_lock); ··· 517 491 return -EIO; 518 492 } 519 493 520 - if (index >= pty_limit) { 494 + if (index >= fsi->mount_opts.max) { 521 495 ida_remove(&fsi->allocated_ptys, index); 522 496 mutex_unlock(&allocated_ptys_lock); 523 - return -EIO; 497 + return -ENOSPC; 524 498 } 525 499 pty_count++; 526 500 mutex_unlock(&allocated_ptys_lock);
+1
include/linux/tty.h
··· 52 52 * hardcoded at present.) 53 53 */ 54 54 #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ 55 + #define NR_UNIX98_PTY_RESERVE 1024 /* Default reserve for main devpts */ 55 56 #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ 56 57 57 58 /*