Skip to content

Commit e9aba51

Browse files
koct9igregkh
authored andcommitted
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 <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent a4834c1 commit e9aba51

2 files changed

Lines changed: 31 additions & 4 deletions

File tree

fs/devpts/inode.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,9 @@
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[] = {
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 {
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 = {
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)
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)
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)
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 @@ int devpts_new_index(struct inode *ptmx_inode)
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 @@ int devpts_new_index(struct inode *ptmx_inode)
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);

include/linux/tty.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
* hardcoded at present.)
5353
*/
5454
#define NR_UNIX98_PTY_DEFAULT 4096 /* Default maximum for Unix98 ptys */
55+
#define NR_UNIX98_PTY_RESERVE 1024 /* Default reserve for main devpts */
5556
#define NR_UNIX98_PTY_MAX (1 << MINORBITS) /* Absolute limit */
5657

5758
/*

0 commit comments

Comments
 (0)