diff options
| -rw-r--r-- | fs/devpts/inode.c | 34 | ||||
| -rw-r--r-- | include/linux/tty.h | 1 |
2 files changed, 31 insertions, 4 deletions
diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index c2c7317d5687..1c6f908e38ca 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c | |||
| @@ -41,8 +41,9 @@ | |||
| 41 | * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. | 41 | * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly. |
| 42 | */ | 42 | */ |
| 43 | static int pty_limit = NR_UNIX98_PTY_DEFAULT; | 43 | static int pty_limit = NR_UNIX98_PTY_DEFAULT; |
| 44 | static int pty_reserve = NR_UNIX98_PTY_RESERVE; | ||
| 44 | static int pty_limit_min; | 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 | static int pty_count; | 47 | static int pty_count; |
| 47 | 48 | ||
| 48 | static struct ctl_table pty_table[] = { | 49 | static struct ctl_table pty_table[] = { |
| @@ -55,6 +56,14 @@ static struct ctl_table pty_table[] = { | |||
| 55 | .extra1 = &pty_limit_min, | 56 | .extra1 = &pty_limit_min, |
| 56 | .extra2 = &pty_limit_max, | 57 | .extra2 = &pty_limit_max, |
| 57 | }, { | 58 | }, { |
| 59 | .procname = "reserve", | ||
| 60 | .maxlen = sizeof(int), | ||
| 61 | .mode = 0644, | ||
| 62 | .data = &pty_reserve, | ||
| 63 | .proc_handler = proc_dointvec_minmax, | ||
| 64 | .extra1 = &pty_limit_min, | ||
| 65 | .extra2 = &pty_limit_max, | ||
| 66 | }, { | ||
| 58 | .procname = "nr", | 67 | .procname = "nr", |
| 59 | .maxlen = sizeof(int), | 68 | .maxlen = sizeof(int), |
| 60 | .mode = 0444, | 69 | .mode = 0444, |
| @@ -94,10 +103,11 @@ struct pts_mount_opts { | |||
| 94 | umode_t mode; | 103 | umode_t mode; |
| 95 | umode_t ptmxmode; | 104 | umode_t ptmxmode; |
| 96 | int newinstance; | 105 | int newinstance; |
| 106 | int max; | ||
| 97 | }; | 107 | }; |
| 98 | 108 | ||
| 99 | enum { | 109 | enum { |
| 100 | Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, | 110 | Opt_uid, Opt_gid, Opt_mode, Opt_ptmxmode, Opt_newinstance, Opt_max, |
| 101 | Opt_err | 111 | Opt_err |
| 102 | }; | 112 | }; |
| 103 | 113 | ||
| @@ -108,6 +118,7 @@ static const match_table_t tokens = { | |||
| 108 | #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES | 118 | #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES |
| 109 | {Opt_ptmxmode, "ptmxmode=%o"}, | 119 | {Opt_ptmxmode, "ptmxmode=%o"}, |
| 110 | {Opt_newinstance, "newinstance"}, | 120 | {Opt_newinstance, "newinstance"}, |
| 121 | {Opt_max, "max=%d"}, | ||
| 111 | #endif | 122 | #endif |
| 112 | {Opt_err, NULL} | 123 | {Opt_err, NULL} |
| 113 | }; | 124 | }; |
| @@ -154,6 +165,7 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) | |||
| 154 | opts->gid = 0; | 165 | opts->gid = 0; |
| 155 | opts->mode = DEVPTS_DEFAULT_MODE; | 166 | opts->mode = DEVPTS_DEFAULT_MODE; |
| 156 | opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; | 167 | opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE; |
| 168 | opts->max = NR_UNIX98_PTY_MAX; | ||
| 157 | 169 | ||
| 158 | /* newinstance makes sense only on initial mount */ | 170 | /* newinstance makes sense only on initial mount */ |
| 159 | if (op == PARSE_MOUNT) | 171 | if (op == PARSE_MOUNT) |
| @@ -197,6 +209,12 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) | |||
| 197 | if (op == PARSE_MOUNT) | 209 | if (op == PARSE_MOUNT) |
| 198 | opts->newinstance = 1; | 210 | opts->newinstance = 1; |
| 199 | break; | 211 | break; |
| 212 | case Opt_max: | ||
| 213 | if (match_int(&args[0], &option) || | ||
| 214 | option < 0 || option > NR_UNIX98_PTY_MAX) | ||
| 215 | return -EINVAL; | ||
| 216 | opts->max = option; | ||
| 217 | break; | ||
| 200 | #endif | 218 | #endif |
| 201 | default: | 219 | default: |
| 202 | printk(KERN_ERR "devpts: called with bogus options\n"); | 220 | printk(KERN_ERR "devpts: called with bogus options\n"); |
| @@ -303,6 +321,8 @@ static int devpts_show_options(struct seq_file *seq, struct dentry *root) | |||
| 303 | seq_printf(seq, ",mode=%03o", opts->mode); | 321 | seq_printf(seq, ",mode=%03o", opts->mode); |
| 304 | #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES | 322 | #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES |
| 305 | seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); | 323 | seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode); |
| 324 | if (opts->max < NR_UNIX98_PTY_MAX) | ||
| 325 | seq_printf(seq, ",max=%d", opts->max); | ||
| 306 | #endif | 326 | #endif |
| 307 | 327 | ||
| 308 | return 0; | 328 | return 0; |
| @@ -483,6 +503,12 @@ retry: | |||
| 483 | return -ENOMEM; | 503 | return -ENOMEM; |
| 484 | 504 | ||
| 485 | mutex_lock(&allocated_ptys_lock); | 505 | mutex_lock(&allocated_ptys_lock); |
| 506 | if (pty_count >= pty_limit - | ||
| 507 | (fsi->mount_opts.newinstance ? pty_reserve : 0)) { | ||
| 508 | mutex_unlock(&allocated_ptys_lock); | ||
| 509 | return -ENOSPC; | ||
| 510 | } | ||
| 511 | |||
| 486 | ida_ret = ida_get_new(&fsi->allocated_ptys, &index); | 512 | ida_ret = ida_get_new(&fsi->allocated_ptys, &index); |
| 487 | if (ida_ret < 0) { | 513 | if (ida_ret < 0) { |
| 488 | mutex_unlock(&allocated_ptys_lock); | 514 | mutex_unlock(&allocated_ptys_lock); |
| @@ -491,10 +517,10 @@ retry: | |||
| 491 | return -EIO; | 517 | return -EIO; |
| 492 | } | 518 | } |
| 493 | 519 | ||
| 494 | if (index >= pty_limit) { | 520 | if (index >= fsi->mount_opts.max) { |
| 495 | ida_remove(&fsi->allocated_ptys, index); | 521 | ida_remove(&fsi->allocated_ptys, index); |
| 496 | mutex_unlock(&allocated_ptys_lock); | 522 | mutex_unlock(&allocated_ptys_lock); |
| 497 | return -EIO; | 523 | return -ENOSPC; |
| 498 | } | 524 | } |
| 499 | pty_count++; | 525 | pty_count++; |
| 500 | mutex_unlock(&allocated_ptys_lock); | 526 | mutex_unlock(&allocated_ptys_lock); |
diff --git a/include/linux/tty.h b/include/linux/tty.h index d3ebd765b548..d40774188203 100644 --- a/include/linux/tty.h +++ b/include/linux/tty.h | |||
| @@ -52,6 +52,7 @@ | |||
| 52 | * hardcoded at present.) | 52 | * hardcoded at present.) |
| 53 | */ | 53 | */ |
| 54 | #define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */ | 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 | #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ | 56 | #define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */ |
| 56 | 57 | ||
| 57 | /* | 58 | /* |
