History

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.

Konstantin Khlebnikov committed 14 years ago

Commit e9aba511 parent a4834c12 files · +31 −4Browse files

Showing the changes to fs/devpts (1 of 2 files). Show all

Unified · Split

fs/devpts/inode.c+30−4
@@ -41,8 +41,9 @@ · 40 unmodified lines
4141 * Otherwise one can eat up all kernel memory by opening /dev/ptmx repeatedly.
4242 */
4343 static int pty_limit = NR_UNIX98_PTY_DEFAULT;
44+static int pty_reserve = NR_UNIX98_PTY_RESERVE;
4445 static int pty_limit_min;
45−static int pty_limit_max = NR_UNIX98_PTY_MAX;
46+static int pty_limit_max = INT_MAX;
4647 static int pty_count;
4748
4849 static struct ctl_table pty_table[] = {
@@ -54,6 +55,14 @@ static struct ctl_table pty_table[] = { · 5 unmodified lines
5455 .proc_handler = proc_dointvec_minmax,
5556 .extra1 = &pty_limit_min,
5657 .extra2 = &pty_limit_max,
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,
5766 }, {
5867 .procname = "nr",
5968 .maxlen = sizeof(int),
@@ -94,10 +103,11 @@ struct pts_mount_opts { · 34 unmodified lines
94103 umode_t mode;
95104 umode_t ptmxmode;
96105 int newinstance;
106+ int max;
97107 };
98108
99109 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,
101111 Opt_err
102112 };
103113
@@ -108,6 +118,7 @@ static const match_table_t tokens = { · 4 unmodified lines
108118 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
109119 {Opt_ptmxmode, "ptmxmode=%o"},
110120 {Opt_newinstance, "newinstance"},
121+ {Opt_max, "max=%d"},
111122 #endif
112123 {Opt_err, NULL}
113124 };
@@ -154,6 +165,7 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) · 40 unmodified lines
154165 opts->gid = 0;
155166 opts->mode = DEVPTS_DEFAULT_MODE;
156167 opts->ptmxmode = DEVPTS_DEFAULT_PTMX_MODE;
168+ opts->max = NR_UNIX98_PTY_MAX;
157169
158170 /* newinstance makes sense only on initial mount */
159171 if (op == PARSE_MOUNT)
@@ -197,6 +209,12 @@ static int parse_mount_options(char *data, int op, struct pts_mount_opts *opts) · 37 unmodified lines
197209 if (op == PARSE_MOUNT)
198210 opts->newinstance = 1;
199211 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;
200218 #endif
201219 default:
202220 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) · 100 unmodified lines
303321 seq_printf(seq, ",mode=%03o", opts->mode);
304322 #ifdef CONFIG_DEVPTS_MULTIPLE_INSTANCES
305323 seq_printf(seq, ",ptmxmode=%03o", opts->ptmxmode);
324+ if (opts->max < NR_UNIX98_PTY_MAX)
325+ seq_printf(seq, ",max=%d", opts->max);
306326 #endif
307327
308328 return 0;
@@ -483,6 +503,12 @@ retry: · 174 unmodified lines
483503 return -ENOMEM;
484504
485505 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+
486512 ida_ret = ida_get_new(&fsi->allocated_ptys, &index);
487513 if (ida_ret < 0) {
488514 mutex_unlock(&allocated_ptys_lock);
@@ -491,10 +517,10 @@ retry: · 2 unmodified lines
491517 return -EIO;
492518 }
493519
494− if (index >= pty_limit) {
520+ if (index >= fsi->mount_opts.max) {
495521 ida_remove(&fsi->allocated_ptys, index);
496522 mutex_unlock(&allocated_ptys_lock);
497− return -EIO;
523+ return -ENOSPC;
498524 }
499525 pty_count++;
500526 mutex_unlock(&allocated_ptys_lock);