| 1 | // SPDX-License-Identifier: GPL-2.0 | 
|---|
| 2 | #include <linux/types.h> | 
|---|
| 3 | #include <linux/errno.h> | 
|---|
| 4 | #include <linux/kmod.h> | 
|---|
| 5 | #include <linux/sched.h> | 
|---|
| 6 | #include <linux/interrupt.h> | 
|---|
| 7 | #include <linux/tty.h> | 
|---|
| 8 | #include <linux/tty_driver.h> | 
|---|
| 9 | #include <linux/file.h> | 
|---|
| 10 | #include <linux/mm.h> | 
|---|
| 11 | #include <linux/string.h> | 
|---|
| 12 | #include <linux/slab.h> | 
|---|
| 13 | #include <linux/poll.h> | 
|---|
| 14 | #include <linux/proc_fs.h> | 
|---|
| 15 | #include <linux/module.h> | 
|---|
| 16 | #include <linux/device.h> | 
|---|
| 17 | #include <linux/wait.h> | 
|---|
| 18 | #include <linux/bitops.h> | 
|---|
| 19 | #include <linux/seq_file.h> | 
|---|
| 20 | #include <linux/uaccess.h> | 
|---|
| 21 | #include <linux/ratelimit.h> | 
|---|
| 22 | #include "tty.h" | 
|---|
| 23 |  | 
|---|
| 24 | #undef LDISC_DEBUG_HANGUP | 
|---|
| 25 |  | 
|---|
| 26 | #ifdef LDISC_DEBUG_HANGUP | 
|---|
| 27 | #define tty_ldisc_debug(tty, f, args...)	tty_debug(tty, f, ##args) | 
|---|
| 28 | #else | 
|---|
| 29 | #define tty_ldisc_debug(tty, f, args...) | 
|---|
| 30 | #endif | 
|---|
| 31 |  | 
|---|
| 32 | /* lockdep nested classes for tty->ldisc_sem */ | 
|---|
| 33 | enum { | 
|---|
| 34 | LDISC_SEM_NORMAL, | 
|---|
| 35 | LDISC_SEM_OTHER, | 
|---|
| 36 | }; | 
|---|
| 37 |  | 
|---|
| 38 |  | 
|---|
| 39 | /* | 
|---|
| 40 | *	This guards the refcounted line discipline lists. The lock | 
|---|
| 41 | *	must be taken with irqs off because there are hangup path | 
|---|
| 42 | *	callers who will do ldisc lookups and cannot sleep. | 
|---|
| 43 | */ | 
|---|
| 44 |  | 
|---|
| 45 | static DEFINE_RAW_SPINLOCK(tty_ldiscs_lock); | 
|---|
| 46 | /* Line disc dispatch table */ | 
|---|
| 47 | static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; | 
|---|
| 48 |  | 
|---|
| 49 | /** | 
|---|
| 50 | * tty_register_ldisc	-	install a line discipline | 
|---|
| 51 | * @new_ldisc: pointer to the ldisc object | 
|---|
| 52 | * | 
|---|
| 53 | * Installs a new line discipline into the kernel. The discipline is set up as | 
|---|
| 54 | * unreferenced and then made available to the kernel from this point onwards. | 
|---|
| 55 | * | 
|---|
| 56 | * Locking: takes %tty_ldiscs_lock to guard against ldisc races | 
|---|
| 57 | */ | 
|---|
| 58 | int tty_register_ldisc(struct tty_ldisc_ops *new_ldisc) | 
|---|
| 59 | { | 
|---|
| 60 | unsigned long flags; | 
|---|
| 61 |  | 
|---|
| 62 | if (new_ldisc->num < N_TTY || new_ldisc->num >= NR_LDISCS) | 
|---|
| 63 | return -EINVAL; | 
|---|
| 64 |  | 
|---|
| 65 | raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); | 
|---|
| 66 | tty_ldiscs[new_ldisc->num] = new_ldisc; | 
|---|
| 67 | raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); | 
|---|
| 68 |  | 
|---|
| 69 | return 0; | 
|---|
| 70 | } | 
|---|
| 71 | EXPORT_SYMBOL(tty_register_ldisc); | 
|---|
| 72 |  | 
|---|
| 73 | /** | 
|---|
| 74 | * tty_unregister_ldisc	-	unload a line discipline | 
|---|
| 75 | * @ldisc: ldisc number | 
|---|
| 76 | * | 
|---|
| 77 | * Remove a line discipline from the kernel providing it is not currently in | 
|---|
| 78 | * use. | 
|---|
| 79 | * | 
|---|
| 80 | * Locking: takes %tty_ldiscs_lock to guard against ldisc races | 
|---|
| 81 | */ | 
|---|
| 82 |  | 
|---|
| 83 | void tty_unregister_ldisc(struct tty_ldisc_ops *ldisc) | 
|---|
| 84 | { | 
|---|
| 85 | unsigned long flags; | 
|---|
| 86 |  | 
|---|
| 87 | raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); | 
|---|
| 88 | tty_ldiscs[ldisc->num] = NULL; | 
|---|
| 89 | raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); | 
|---|
| 90 | } | 
|---|
| 91 | EXPORT_SYMBOL(tty_unregister_ldisc); | 
|---|
| 92 |  | 
|---|
| 93 | static struct tty_ldisc_ops *get_ldops(int disc) | 
|---|
| 94 | { | 
|---|
| 95 | unsigned long flags; | 
|---|
| 96 | struct tty_ldisc_ops *ldops, *ret; | 
|---|
| 97 |  | 
|---|
| 98 | raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); | 
|---|
| 99 | ret = ERR_PTR(error: -EINVAL); | 
|---|
| 100 | ldops = tty_ldiscs[disc]; | 
|---|
| 101 | if (ldops) { | 
|---|
| 102 | ret = ERR_PTR(error: -EAGAIN); | 
|---|
| 103 | if (try_module_get(module: ldops->owner)) | 
|---|
| 104 | ret = ldops; | 
|---|
| 105 | } | 
|---|
| 106 | raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); | 
|---|
| 107 | return ret; | 
|---|
| 108 | } | 
|---|
| 109 |  | 
|---|
| 110 | static void put_ldops(struct tty_ldisc_ops *ldops) | 
|---|
| 111 | { | 
|---|
| 112 | unsigned long flags; | 
|---|
| 113 |  | 
|---|
| 114 | raw_spin_lock_irqsave(&tty_ldiscs_lock, flags); | 
|---|
| 115 | module_put(module: ldops->owner); | 
|---|
| 116 | raw_spin_unlock_irqrestore(&tty_ldiscs_lock, flags); | 
|---|
| 117 | } | 
|---|
| 118 |  | 
|---|
| 119 | int tty_ldisc_autoload = IS_BUILTIN(CONFIG_LDISC_AUTOLOAD); | 
|---|
| 120 |  | 
|---|
| 121 | /** | 
|---|
| 122 | * tty_ldisc_get	-	take a reference to an ldisc | 
|---|
| 123 | * @tty: tty device | 
|---|
| 124 | * @disc: ldisc number | 
|---|
| 125 | * | 
|---|
| 126 | * Takes a reference to a line discipline. Deals with refcounts and module | 
|---|
| 127 | * locking counts. If the discipline is not available, its module loaded, if | 
|---|
| 128 | * possible. | 
|---|
| 129 | * | 
|---|
| 130 | * Returns: | 
|---|
| 131 | * * -%EINVAL if the discipline index is not [%N_TTY .. %NR_LDISCS] or if the | 
|---|
| 132 | *   discipline is not registered | 
|---|
| 133 | * * -%EAGAIN if request_module() failed to load or register the discipline | 
|---|
| 134 | * * -%ENOMEM if allocation failure | 
|---|
| 135 | * * Otherwise, returns a pointer to the discipline and bumps the ref count | 
|---|
| 136 | * | 
|---|
| 137 | * Locking: takes %tty_ldiscs_lock to guard against ldisc races | 
|---|
| 138 | */ | 
|---|
| 139 | static struct tty_ldisc *tty_ldisc_get(struct tty_struct *tty, int disc) | 
|---|
| 140 | { | 
|---|
| 141 | struct tty_ldisc *ld; | 
|---|
| 142 | struct tty_ldisc_ops *ldops; | 
|---|
| 143 |  | 
|---|
| 144 | if (disc < N_TTY || disc >= NR_LDISCS) | 
|---|
| 145 | return ERR_PTR(error: -EINVAL); | 
|---|
| 146 |  | 
|---|
| 147 | /* | 
|---|
| 148 | * Get the ldisc ops - we may need to request them to be loaded | 
|---|
| 149 | * dynamically and try again. | 
|---|
| 150 | */ | 
|---|
| 151 | ldops = get_ldops(disc); | 
|---|
| 152 | if (IS_ERR(ptr: ldops)) { | 
|---|
| 153 | if (!capable(CAP_SYS_MODULE) && !tty_ldisc_autoload) | 
|---|
| 154 | return ERR_PTR(error: -EPERM); | 
|---|
| 155 | request_module( "tty-ldisc-%d", disc); | 
|---|
| 156 | ldops = get_ldops(disc); | 
|---|
| 157 | if (IS_ERR(ptr: ldops)) | 
|---|
| 158 | return ERR_CAST(ptr: ldops); | 
|---|
| 159 | } | 
|---|
| 160 |  | 
|---|
| 161 | /* | 
|---|
| 162 | * There is no way to handle allocation failure of only 16 bytes. | 
|---|
| 163 | * Let's simplify error handling and save more memory. | 
|---|
| 164 | */ | 
|---|
| 165 | ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL | __GFP_NOFAIL); | 
|---|
| 166 | ld->ops = ldops; | 
|---|
| 167 | ld->tty = tty; | 
|---|
| 168 |  | 
|---|
| 169 | return ld; | 
|---|
| 170 | } | 
|---|
| 171 |  | 
|---|
| 172 | /** | 
|---|
| 173 | * tty_ldisc_put	-	release the ldisc | 
|---|
| 174 | * @ld: lisdsc to release | 
|---|
| 175 | * | 
|---|
| 176 | * Complement of tty_ldisc_get(). | 
|---|
| 177 | */ | 
|---|
| 178 | static void tty_ldisc_put(struct tty_ldisc *ld) | 
|---|
| 179 | { | 
|---|
| 180 | if (WARN_ON_ONCE(!ld)) | 
|---|
| 181 | return; | 
|---|
| 182 |  | 
|---|
| 183 | put_ldops(ldops: ld->ops); | 
|---|
| 184 | kfree(objp: ld); | 
|---|
| 185 | } | 
|---|
| 186 |  | 
|---|
| 187 | static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) | 
|---|
| 188 | { | 
|---|
| 189 | return (*pos < NR_LDISCS) ? pos : NULL; | 
|---|
| 190 | } | 
|---|
| 191 |  | 
|---|
| 192 | static void *tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos) | 
|---|
| 193 | { | 
|---|
| 194 | (*pos)++; | 
|---|
| 195 | return (*pos < NR_LDISCS) ? pos : NULL; | 
|---|
| 196 | } | 
|---|
| 197 |  | 
|---|
| 198 | static void tty_ldiscs_seq_stop(struct seq_file *m, void *v) | 
|---|
| 199 | { | 
|---|
| 200 | } | 
|---|
| 201 |  | 
|---|
| 202 | static int tty_ldiscs_seq_show(struct seq_file *m, void *v) | 
|---|
| 203 | { | 
|---|
| 204 | int i = *(loff_t *)v; | 
|---|
| 205 | struct tty_ldisc_ops *ldops; | 
|---|
| 206 |  | 
|---|
| 207 | ldops = get_ldops(disc: i); | 
|---|
| 208 | if (IS_ERR(ptr: ldops)) | 
|---|
| 209 | return 0; | 
|---|
| 210 | seq_printf(m, fmt: "%-10s %2d\n", ldops->name ? ldops->name : "???", i); | 
|---|
| 211 | put_ldops(ldops); | 
|---|
| 212 | return 0; | 
|---|
| 213 | } | 
|---|
| 214 |  | 
|---|
| 215 | const struct seq_operations tty_ldiscs_seq_ops = { | 
|---|
| 216 | .start	= tty_ldiscs_seq_start, | 
|---|
| 217 | .next	= tty_ldiscs_seq_next, | 
|---|
| 218 | .stop	= tty_ldiscs_seq_stop, | 
|---|
| 219 | .show	= tty_ldiscs_seq_show, | 
|---|
| 220 | }; | 
|---|
| 221 |  | 
|---|
| 222 | /** | 
|---|
| 223 | * tty_ldisc_ref_wait	-	wait for the tty ldisc | 
|---|
| 224 | * @tty: tty device | 
|---|
| 225 | * | 
|---|
| 226 | * Dereference the line discipline for the terminal and take a reference to it. | 
|---|
| 227 | * If the line discipline is in flux then wait patiently until it changes. | 
|---|
| 228 | * | 
|---|
| 229 | * Returns: %NULL if the tty has been hungup and not re-opened with a new file | 
|---|
| 230 | * descriptor, otherwise valid ldisc reference | 
|---|
| 231 | * | 
|---|
| 232 | * Note 1: Must not be called from an IRQ/timer context. The caller must also | 
|---|
| 233 | * be careful not to hold other locks that will deadlock against a discipline | 
|---|
| 234 | * change, such as an existing ldisc reference (which we check for). | 
|---|
| 235 | * | 
|---|
| 236 | * Note 2: a file_operations routine (read/poll/write) should use this function | 
|---|
| 237 | * to wait for any ldisc lifetime events to finish. | 
|---|
| 238 | */ | 
|---|
| 239 | struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) | 
|---|
| 240 | { | 
|---|
| 241 | struct tty_ldisc *ld; | 
|---|
| 242 |  | 
|---|
| 243 | ldsem_down_read(sem: &tty->ldisc_sem, MAX_SCHEDULE_TIMEOUT); | 
|---|
| 244 | ld = tty->ldisc; | 
|---|
| 245 | if (!ld) | 
|---|
| 246 | ldsem_up_read(sem: &tty->ldisc_sem); | 
|---|
| 247 | return ld; | 
|---|
| 248 | } | 
|---|
| 249 | EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); | 
|---|
| 250 |  | 
|---|
| 251 | /** | 
|---|
| 252 | * tty_ldisc_ref	-	get the tty ldisc | 
|---|
| 253 | * @tty: tty device | 
|---|
| 254 | * | 
|---|
| 255 | * Dereference the line discipline for the terminal and take a reference to it. | 
|---|
| 256 | * If the line discipline is in flux then return %NULL. Can be called from IRQ | 
|---|
| 257 | * and timer functions. | 
|---|
| 258 | */ | 
|---|
| 259 | struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) | 
|---|
| 260 | { | 
|---|
| 261 | struct tty_ldisc *ld = NULL; | 
|---|
| 262 |  | 
|---|
| 263 | if (ldsem_down_read_trylock(sem: &tty->ldisc_sem)) { | 
|---|
| 264 | ld = tty->ldisc; | 
|---|
| 265 | if (!ld) | 
|---|
| 266 | ldsem_up_read(sem: &tty->ldisc_sem); | 
|---|
| 267 | } | 
|---|
| 268 | return ld; | 
|---|
| 269 | } | 
|---|
| 270 | EXPORT_SYMBOL_GPL(tty_ldisc_ref); | 
|---|
| 271 |  | 
|---|
| 272 | /** | 
|---|
| 273 | * tty_ldisc_deref	-	free a tty ldisc reference | 
|---|
| 274 | * @ld: reference to free up | 
|---|
| 275 | * | 
|---|
| 276 | * Undoes the effect of tty_ldisc_ref() or tty_ldisc_ref_wait(). May be called | 
|---|
| 277 | * in IRQ context. | 
|---|
| 278 | */ | 
|---|
| 279 | void tty_ldisc_deref(struct tty_ldisc *ld) | 
|---|
| 280 | { | 
|---|
| 281 | ldsem_up_read(sem: &ld->tty->ldisc_sem); | 
|---|
| 282 | } | 
|---|
| 283 | EXPORT_SYMBOL_GPL(tty_ldisc_deref); | 
|---|
| 284 |  | 
|---|
| 285 |  | 
|---|
| 286 | static inline int | 
|---|
| 287 | __tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) | 
|---|
| 288 | { | 
|---|
| 289 | return ldsem_down_write(sem: &tty->ldisc_sem, timeout); | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 | static inline int | 
|---|
| 293 | __tty_ldisc_lock_nested(struct tty_struct *tty, unsigned long timeout) | 
|---|
| 294 | { | 
|---|
| 295 | return ldsem_down_write_nested(&tty->ldisc_sem, | 
|---|
| 296 | LDISC_SEM_OTHER, timeout); | 
|---|
| 297 | } | 
|---|
| 298 |  | 
|---|
| 299 | static inline void __tty_ldisc_unlock(struct tty_struct *tty) | 
|---|
| 300 | { | 
|---|
| 301 | ldsem_up_write(sem: &tty->ldisc_sem); | 
|---|
| 302 | } | 
|---|
| 303 |  | 
|---|
| 304 | int tty_ldisc_lock(struct tty_struct *tty, unsigned long timeout) | 
|---|
| 305 | { | 
|---|
| 306 | int ret; | 
|---|
| 307 |  | 
|---|
| 308 | /* Kindly asking blocked readers to release the read side */ | 
|---|
| 309 | set_bit(nr: TTY_LDISC_CHANGING, addr: &tty->flags); | 
|---|
| 310 | wake_up_interruptible_all(&tty->read_wait); | 
|---|
| 311 | wake_up_interruptible_all(&tty->write_wait); | 
|---|
| 312 |  | 
|---|
| 313 | ret = __tty_ldisc_lock(tty, timeout); | 
|---|
| 314 | if (!ret) | 
|---|
| 315 | return -EBUSY; | 
|---|
| 316 | set_bit(nr: TTY_LDISC_HALTED, addr: &tty->flags); | 
|---|
| 317 | return 0; | 
|---|
| 318 | } | 
|---|
| 319 |  | 
|---|
| 320 | void tty_ldisc_unlock(struct tty_struct *tty) | 
|---|
| 321 | { | 
|---|
| 322 | clear_bit(nr: TTY_LDISC_HALTED, addr: &tty->flags); | 
|---|
| 323 | /* Can be cleared here - ldisc_unlock will wake up writers firstly */ | 
|---|
| 324 | clear_bit(nr: TTY_LDISC_CHANGING, addr: &tty->flags); | 
|---|
| 325 | __tty_ldisc_unlock(tty); | 
|---|
| 326 | } | 
|---|
| 327 |  | 
|---|
| 328 | static int | 
|---|
| 329 | tty_ldisc_lock_pair_timeout(struct tty_struct *tty, struct tty_struct *tty2, | 
|---|
| 330 | unsigned long timeout) | 
|---|
| 331 | { | 
|---|
| 332 | int ret; | 
|---|
| 333 |  | 
|---|
| 334 | if (tty < tty2) { | 
|---|
| 335 | ret = __tty_ldisc_lock(tty, timeout); | 
|---|
| 336 | if (ret) { | 
|---|
| 337 | ret = __tty_ldisc_lock_nested(tty: tty2, timeout); | 
|---|
| 338 | if (!ret) | 
|---|
| 339 | __tty_ldisc_unlock(tty); | 
|---|
| 340 | } | 
|---|
| 341 | } else { | 
|---|
| 342 | /* if this is possible, it has lots of implications */ | 
|---|
| 343 | WARN_ON_ONCE(tty == tty2); | 
|---|
| 344 | if (tty2 && tty != tty2) { | 
|---|
| 345 | ret = __tty_ldisc_lock(tty: tty2, timeout); | 
|---|
| 346 | if (ret) { | 
|---|
| 347 | ret = __tty_ldisc_lock_nested(tty, timeout); | 
|---|
| 348 | if (!ret) | 
|---|
| 349 | __tty_ldisc_unlock(tty: tty2); | 
|---|
| 350 | } | 
|---|
| 351 | } else | 
|---|
| 352 | ret = __tty_ldisc_lock(tty, timeout); | 
|---|
| 353 | } | 
|---|
| 354 |  | 
|---|
| 355 | if (!ret) | 
|---|
| 356 | return -EBUSY; | 
|---|
| 357 |  | 
|---|
| 358 | set_bit(nr: TTY_LDISC_HALTED, addr: &tty->flags); | 
|---|
| 359 | if (tty2) | 
|---|
| 360 | set_bit(nr: TTY_LDISC_HALTED, addr: &tty2->flags); | 
|---|
| 361 | return 0; | 
|---|
| 362 | } | 
|---|
| 363 |  | 
|---|
| 364 | static void tty_ldisc_lock_pair(struct tty_struct *tty, struct tty_struct *tty2) | 
|---|
| 365 | { | 
|---|
| 366 | tty_ldisc_lock_pair_timeout(tty, tty2, MAX_SCHEDULE_TIMEOUT); | 
|---|
| 367 | } | 
|---|
| 368 |  | 
|---|
| 369 | static void tty_ldisc_unlock_pair(struct tty_struct *tty, | 
|---|
| 370 | struct tty_struct *tty2) | 
|---|
| 371 | { | 
|---|
| 372 | __tty_ldisc_unlock(tty); | 
|---|
| 373 | if (tty2) | 
|---|
| 374 | __tty_ldisc_unlock(tty: tty2); | 
|---|
| 375 | } | 
|---|
| 376 |  | 
|---|
| 377 | /** | 
|---|
| 378 | * tty_ldisc_flush		-	flush line discipline queue | 
|---|
| 379 | * @tty: tty to flush ldisc for | 
|---|
| 380 | * | 
|---|
| 381 | * Flush the line discipline queue (if any) and the tty flip buffers for this | 
|---|
| 382 | * @tty. | 
|---|
| 383 | */ | 
|---|
| 384 | void tty_ldisc_flush(struct tty_struct *tty) | 
|---|
| 385 | { | 
|---|
| 386 | struct tty_ldisc *ld = tty_ldisc_ref(tty); | 
|---|
| 387 |  | 
|---|
| 388 | tty_buffer_flush(tty, ld); | 
|---|
| 389 | if (ld) | 
|---|
| 390 | tty_ldisc_deref(ld); | 
|---|
| 391 | } | 
|---|
| 392 | EXPORT_SYMBOL_GPL(tty_ldisc_flush); | 
|---|
| 393 |  | 
|---|
| 394 | /** | 
|---|
| 395 | * tty_set_termios_ldisc	-	set ldisc field | 
|---|
| 396 | * @tty: tty structure | 
|---|
| 397 | * @disc: line discipline number | 
|---|
| 398 | * | 
|---|
| 399 | * This is probably overkill for real world processors but they are not on hot | 
|---|
| 400 | * paths so a little discipline won't do any harm. | 
|---|
| 401 | * | 
|---|
| 402 | * The line discipline-related tty_struct fields are reset to prevent the ldisc | 
|---|
| 403 | * driver from re-using stale information for the new ldisc instance. | 
|---|
| 404 | * | 
|---|
| 405 | * Locking: takes termios_rwsem | 
|---|
| 406 | */ | 
|---|
| 407 | static void tty_set_termios_ldisc(struct tty_struct *tty, int disc) | 
|---|
| 408 | { | 
|---|
| 409 | down_write(sem: &tty->termios_rwsem); | 
|---|
| 410 | tty->termios.c_line = disc; | 
|---|
| 411 | up_write(sem: &tty->termios_rwsem); | 
|---|
| 412 |  | 
|---|
| 413 | tty->disc_data = NULL; | 
|---|
| 414 | tty->receive_room = 0; | 
|---|
| 415 | } | 
|---|
| 416 |  | 
|---|
| 417 | /** | 
|---|
| 418 | * tty_ldisc_open		-	open a line discipline | 
|---|
| 419 | * @tty: tty we are opening the ldisc on | 
|---|
| 420 | * @ld: discipline to open | 
|---|
| 421 | * | 
|---|
| 422 | * A helper opening method. Also a convenient debugging and check point. | 
|---|
| 423 | * | 
|---|
| 424 | * Locking: always called with BTM already held. | 
|---|
| 425 | */ | 
|---|
| 426 | static int tty_ldisc_open(struct tty_struct *tty, struct tty_ldisc *ld) | 
|---|
| 427 | { | 
|---|
| 428 | WARN_ON(test_and_set_bit(TTY_LDISC_OPEN, &tty->flags)); | 
|---|
| 429 | if (ld->ops->open) { | 
|---|
| 430 | int ret; | 
|---|
| 431 | /* BTM here locks versus a hangup event */ | 
|---|
| 432 | ret = ld->ops->open(tty); | 
|---|
| 433 | if (ret) | 
|---|
| 434 | clear_bit(nr: TTY_LDISC_OPEN, addr: &tty->flags); | 
|---|
| 435 |  | 
|---|
| 436 | tty_ldisc_debug(tty, "%p: opened\n", ld); | 
|---|
| 437 | return ret; | 
|---|
| 438 | } | 
|---|
| 439 | return 0; | 
|---|
| 440 | } | 
|---|
| 441 |  | 
|---|
| 442 | /** | 
|---|
| 443 | * tty_ldisc_close		-	close a line discipline | 
|---|
| 444 | * @tty: tty we are opening the ldisc on | 
|---|
| 445 | * @ld: discipline to close | 
|---|
| 446 | * | 
|---|
| 447 | * A helper close method. Also a convenient debugging and check point. | 
|---|
| 448 | */ | 
|---|
| 449 | static void tty_ldisc_close(struct tty_struct *tty, struct tty_ldisc *ld) | 
|---|
| 450 | { | 
|---|
| 451 | lockdep_assert_held_write(&tty->ldisc_sem); | 
|---|
| 452 | WARN_ON(!test_bit(TTY_LDISC_OPEN, &tty->flags)); | 
|---|
| 453 | clear_bit(nr: TTY_LDISC_OPEN, addr: &tty->flags); | 
|---|
| 454 | if (ld->ops->close) | 
|---|
| 455 | ld->ops->close(tty); | 
|---|
| 456 | tty_ldisc_debug(tty, "%p: closed\n", ld); | 
|---|
| 457 | } | 
|---|
| 458 |  | 
|---|
| 459 | /** | 
|---|
| 460 | * tty_ldisc_failto	-	helper for ldisc failback | 
|---|
| 461 | * @tty: tty to open the ldisc on | 
|---|
| 462 | * @ld: ldisc we are trying to fail back to | 
|---|
| 463 | * | 
|---|
| 464 | * Helper to try and recover a tty when switching back to the old ldisc fails | 
|---|
| 465 | * and we need something attached. | 
|---|
| 466 | */ | 
|---|
| 467 | static int tty_ldisc_failto(struct tty_struct *tty, int ld) | 
|---|
| 468 | { | 
|---|
| 469 | struct tty_ldisc *disc = tty_ldisc_get(tty, disc: ld); | 
|---|
| 470 | int r; | 
|---|
| 471 |  | 
|---|
| 472 | lockdep_assert_held_write(&tty->ldisc_sem); | 
|---|
| 473 | if (IS_ERR(ptr: disc)) | 
|---|
| 474 | return PTR_ERR(ptr: disc); | 
|---|
| 475 | tty->ldisc = disc; | 
|---|
| 476 | tty_set_termios_ldisc(tty, disc: ld); | 
|---|
| 477 | r = tty_ldisc_open(tty, ld: disc); | 
|---|
| 478 | if (r < 0) | 
|---|
| 479 | tty_ldisc_put(ld: disc); | 
|---|
| 480 | return r; | 
|---|
| 481 | } | 
|---|
| 482 |  | 
|---|
| 483 | /** | 
|---|
| 484 | * tty_ldisc_restore	-	helper for tty ldisc change | 
|---|
| 485 | * @tty: tty to recover | 
|---|
| 486 | * @old: previous ldisc | 
|---|
| 487 | * | 
|---|
| 488 | * Restore the previous line discipline or %N_TTY when a line discipline change | 
|---|
| 489 | * fails due to an open error | 
|---|
| 490 | */ | 
|---|
| 491 | static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) | 
|---|
| 492 | { | 
|---|
| 493 | /* There is an outstanding reference here so this is safe */ | 
|---|
| 494 | if (tty_ldisc_failto(tty, ld: old->ops->num) < 0) { | 
|---|
| 495 | const char *name = tty_name(tty); | 
|---|
| 496 |  | 
|---|
| 497 | pr_warn( "Falling back ldisc for %s.\n", name); | 
|---|
| 498 | /* | 
|---|
| 499 | * The traditional behaviour is to fall back to N_TTY, we | 
|---|
| 500 | * want to avoid falling back to N_NULL unless we have no | 
|---|
| 501 | * choice to avoid the risk of breaking anything | 
|---|
| 502 | */ | 
|---|
| 503 | if (tty_ldisc_failto(tty, N_TTY) < 0 && | 
|---|
| 504 | tty_ldisc_failto(tty, N_NULL) < 0) | 
|---|
| 505 | panic(fmt: "Couldn't open N_NULL ldisc for %s.", name); | 
|---|
| 506 | } | 
|---|
| 507 | } | 
|---|
| 508 |  | 
|---|
| 509 | /** | 
|---|
| 510 | * tty_set_ldisc		-	set line discipline | 
|---|
| 511 | * @tty: the terminal to set | 
|---|
| 512 | * @disc: the line discipline number | 
|---|
| 513 | * | 
|---|
| 514 | * Set the discipline of a tty line. Must be called from a process context. The | 
|---|
| 515 | * ldisc change logic has to protect itself against any overlapping ldisc | 
|---|
| 516 | * change (including on the other end of pty pairs), the close of one side of a | 
|---|
| 517 | * tty/pty pair, and eventually hangup. | 
|---|
| 518 | */ | 
|---|
| 519 | int tty_set_ldisc(struct tty_struct *tty, int disc) | 
|---|
| 520 | { | 
|---|
| 521 | int retval; | 
|---|
| 522 | struct tty_ldisc *old_ldisc, *new_ldisc; | 
|---|
| 523 |  | 
|---|
| 524 | new_ldisc = tty_ldisc_get(tty, disc); | 
|---|
| 525 | if (IS_ERR(ptr: new_ldisc)) | 
|---|
| 526 | return PTR_ERR(ptr: new_ldisc); | 
|---|
| 527 |  | 
|---|
| 528 | tty_lock(tty); | 
|---|
| 529 | retval = tty_ldisc_lock(tty, timeout: 5 * HZ); | 
|---|
| 530 | if (retval) | 
|---|
| 531 | goto err; | 
|---|
| 532 |  | 
|---|
| 533 | if (!tty->ldisc) { | 
|---|
| 534 | retval = -EIO; | 
|---|
| 535 | goto out; | 
|---|
| 536 | } | 
|---|
| 537 |  | 
|---|
| 538 | /* Check the no-op case */ | 
|---|
| 539 | if (tty->ldisc->ops->num == disc) | 
|---|
| 540 | goto out; | 
|---|
| 541 |  | 
|---|
| 542 | if (test_bit(TTY_HUPPED, &tty->flags)) { | 
|---|
| 543 | /* We were raced by hangup */ | 
|---|
| 544 | retval = -EIO; | 
|---|
| 545 | goto out; | 
|---|
| 546 | } | 
|---|
| 547 |  | 
|---|
| 548 | if (tty->ops->ldisc_ok) { | 
|---|
| 549 | retval = tty->ops->ldisc_ok(tty, disc); | 
|---|
| 550 | if (retval) | 
|---|
| 551 | goto out; | 
|---|
| 552 | } | 
|---|
| 553 |  | 
|---|
| 554 | old_ldisc = tty->ldisc; | 
|---|
| 555 |  | 
|---|
| 556 | /* Shutdown the old discipline. */ | 
|---|
| 557 | tty_ldisc_close(tty, ld: old_ldisc); | 
|---|
| 558 |  | 
|---|
| 559 | /* Now set up the new line discipline. */ | 
|---|
| 560 | tty->ldisc = new_ldisc; | 
|---|
| 561 | tty_set_termios_ldisc(tty, disc); | 
|---|
| 562 |  | 
|---|
| 563 | retval = tty_ldisc_open(tty, ld: new_ldisc); | 
|---|
| 564 | if (retval < 0) { | 
|---|
| 565 | /* Back to the old one or N_TTY if we can't */ | 
|---|
| 566 | tty_ldisc_put(ld: new_ldisc); | 
|---|
| 567 | tty_ldisc_restore(tty, old: old_ldisc); | 
|---|
| 568 | } | 
|---|
| 569 |  | 
|---|
| 570 | if (tty->ldisc->ops->num != old_ldisc->ops->num && tty->ops->set_ldisc) { | 
|---|
| 571 | down_read(sem: &tty->termios_rwsem); | 
|---|
| 572 | tty->ops->set_ldisc(tty); | 
|---|
| 573 | up_read(sem: &tty->termios_rwsem); | 
|---|
| 574 | } | 
|---|
| 575 |  | 
|---|
| 576 | /* | 
|---|
| 577 | * At this point we hold a reference to the new ldisc and a | 
|---|
| 578 | * reference to the old ldisc, or we hold two references to | 
|---|
| 579 | * the old ldisc (if it was restored as part of error cleanup | 
|---|
| 580 | * above). In either case, releasing a single reference from | 
|---|
| 581 | * the old ldisc is correct. | 
|---|
| 582 | */ | 
|---|
| 583 | new_ldisc = old_ldisc; | 
|---|
| 584 | out: | 
|---|
| 585 | tty_ldisc_unlock(tty); | 
|---|
| 586 |  | 
|---|
| 587 | /* | 
|---|
| 588 | * Restart the work queue in case no characters kick it off. Safe if | 
|---|
| 589 | * already running | 
|---|
| 590 | */ | 
|---|
| 591 | tty_buffer_restart_work(port: tty->port); | 
|---|
| 592 | err: | 
|---|
| 593 | tty_ldisc_put(ld: new_ldisc);	/* drop the extra reference */ | 
|---|
| 594 | tty_unlock(tty); | 
|---|
| 595 | return retval; | 
|---|
| 596 | } | 
|---|
| 597 | EXPORT_SYMBOL_GPL(tty_set_ldisc); | 
|---|
| 598 |  | 
|---|
| 599 | /** | 
|---|
| 600 | * tty_ldisc_kill	-	teardown ldisc | 
|---|
| 601 | * @tty: tty being released | 
|---|
| 602 | * | 
|---|
| 603 | * Perform final close of the ldisc and reset @tty->ldisc | 
|---|
| 604 | */ | 
|---|
| 605 | static void tty_ldisc_kill(struct tty_struct *tty) | 
|---|
| 606 | { | 
|---|
| 607 | lockdep_assert_held_write(&tty->ldisc_sem); | 
|---|
| 608 | if (!tty->ldisc) | 
|---|
| 609 | return; | 
|---|
| 610 | /* | 
|---|
| 611 | * Now kill off the ldisc | 
|---|
| 612 | */ | 
|---|
| 613 | tty_ldisc_close(tty, ld: tty->ldisc); | 
|---|
| 614 | tty_ldisc_put(ld: tty->ldisc); | 
|---|
| 615 | /* Force an oops if we mess this up */ | 
|---|
| 616 | tty->ldisc = NULL; | 
|---|
| 617 | } | 
|---|
| 618 |  | 
|---|
| 619 | /** | 
|---|
| 620 | * tty_reset_termios	-	reset terminal state | 
|---|
| 621 | * @tty: tty to reset | 
|---|
| 622 | * | 
|---|
| 623 | * Restore a terminal to the driver default state. | 
|---|
| 624 | */ | 
|---|
| 625 | static void tty_reset_termios(struct tty_struct *tty) | 
|---|
| 626 | { | 
|---|
| 627 | down_write(sem: &tty->termios_rwsem); | 
|---|
| 628 | tty->termios = tty->driver->init_termios; | 
|---|
| 629 | tty->termios.c_ispeed = tty_termios_input_baud_rate(termios: &tty->termios); | 
|---|
| 630 | tty->termios.c_ospeed = tty_termios_baud_rate(termios: &tty->termios); | 
|---|
| 631 | up_write(sem: &tty->termios_rwsem); | 
|---|
| 632 | } | 
|---|
| 633 |  | 
|---|
| 634 |  | 
|---|
| 635 | /** | 
|---|
| 636 | * tty_ldisc_reinit	-	reinitialise the tty ldisc | 
|---|
| 637 | * @tty: tty to reinit | 
|---|
| 638 | * @disc: line discipline to reinitialize | 
|---|
| 639 | * | 
|---|
| 640 | * Completely reinitialize the line discipline state, by closing the current | 
|---|
| 641 | * instance, if there is one, and opening a new instance. If an error occurs | 
|---|
| 642 | * opening the new non-%N_TTY instance, the instance is dropped and @tty->ldisc | 
|---|
| 643 | * reset to %NULL. The caller can then retry with %N_TTY instead. | 
|---|
| 644 | * | 
|---|
| 645 | * Returns: 0 if successful, otherwise error code < 0 | 
|---|
| 646 | */ | 
|---|
| 647 | int tty_ldisc_reinit(struct tty_struct *tty, int disc) | 
|---|
| 648 | { | 
|---|
| 649 | struct tty_ldisc *ld; | 
|---|
| 650 | int retval; | 
|---|
| 651 |  | 
|---|
| 652 | lockdep_assert_held_write(&tty->ldisc_sem); | 
|---|
| 653 | ld = tty_ldisc_get(tty, disc); | 
|---|
| 654 | if (IS_ERR(ptr: ld)) { | 
|---|
| 655 | BUG_ON(disc == N_TTY); | 
|---|
| 656 | return PTR_ERR(ptr: ld); | 
|---|
| 657 | } | 
|---|
| 658 |  | 
|---|
| 659 | if (tty->ldisc) { | 
|---|
| 660 | tty_ldisc_close(tty, ld: tty->ldisc); | 
|---|
| 661 | tty_ldisc_put(ld: tty->ldisc); | 
|---|
| 662 | } | 
|---|
| 663 |  | 
|---|
| 664 | /* switch the line discipline */ | 
|---|
| 665 | tty->ldisc = ld; | 
|---|
| 666 | tty_set_termios_ldisc(tty, disc); | 
|---|
| 667 | retval = tty_ldisc_open(tty, ld: tty->ldisc); | 
|---|
| 668 | if (retval) { | 
|---|
| 669 | tty_ldisc_put(ld: tty->ldisc); | 
|---|
| 670 | tty->ldisc = NULL; | 
|---|
| 671 | } | 
|---|
| 672 | return retval; | 
|---|
| 673 | } | 
|---|
| 674 |  | 
|---|
| 675 | /** | 
|---|
| 676 | * tty_ldisc_hangup	-	hangup ldisc reset | 
|---|
| 677 | * @tty: tty being hung up | 
|---|
| 678 | * @reinit: whether to re-initialise the tty | 
|---|
| 679 | * | 
|---|
| 680 | * Some tty devices reset their termios when they receive a hangup event. In | 
|---|
| 681 | * that situation we must also switch back to %N_TTY properly before we reset | 
|---|
| 682 | * the termios data. | 
|---|
| 683 | * | 
|---|
| 684 | * Locking: We can take the ldisc mutex as the rest of the code is careful to | 
|---|
| 685 | * allow for this. | 
|---|
| 686 | * | 
|---|
| 687 | * In the pty pair case this occurs in the close() path of the tty itself so we | 
|---|
| 688 | * must be careful about locking rules. | 
|---|
| 689 | */ | 
|---|
| 690 | void tty_ldisc_hangup(struct tty_struct *tty, bool reinit) | 
|---|
| 691 | { | 
|---|
| 692 | struct tty_ldisc *ld; | 
|---|
| 693 |  | 
|---|
| 694 | tty_ldisc_debug(tty, "%p: hangup\n", tty->ldisc); | 
|---|
| 695 |  | 
|---|
| 696 | ld = tty_ldisc_ref(tty); | 
|---|
| 697 | if (ld != NULL) { | 
|---|
| 698 | if (ld->ops->flush_buffer) | 
|---|
| 699 | ld->ops->flush_buffer(tty); | 
|---|
| 700 | tty_driver_flush_buffer(tty); | 
|---|
| 701 | if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && | 
|---|
| 702 | ld->ops->write_wakeup) | 
|---|
| 703 | ld->ops->write_wakeup(tty); | 
|---|
| 704 | if (ld->ops->hangup) | 
|---|
| 705 | ld->ops->hangup(tty); | 
|---|
| 706 | tty_ldisc_deref(ld); | 
|---|
| 707 | } | 
|---|
| 708 |  | 
|---|
| 709 | wake_up_interruptible_poll(&tty->write_wait, EPOLLOUT); | 
|---|
| 710 | wake_up_interruptible_poll(&tty->read_wait, EPOLLIN); | 
|---|
| 711 |  | 
|---|
| 712 | /* | 
|---|
| 713 | * Shutdown the current line discipline, and reset it to | 
|---|
| 714 | * N_TTY if need be. | 
|---|
| 715 | * | 
|---|
| 716 | * Avoid racing set_ldisc or tty_ldisc_release | 
|---|
| 717 | */ | 
|---|
| 718 | tty_ldisc_lock(tty, MAX_SCHEDULE_TIMEOUT); | 
|---|
| 719 |  | 
|---|
| 720 | if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) | 
|---|
| 721 | tty_reset_termios(tty); | 
|---|
| 722 |  | 
|---|
| 723 | if (tty->ldisc) { | 
|---|
| 724 | if (reinit) { | 
|---|
| 725 | if (tty_ldisc_reinit(tty, disc: tty->termios.c_line) < 0 && | 
|---|
| 726 | tty_ldisc_reinit(tty, N_TTY) < 0) | 
|---|
| 727 | WARN_ON(tty_ldisc_reinit(tty, N_NULL) < 0); | 
|---|
| 728 | } else | 
|---|
| 729 | tty_ldisc_kill(tty); | 
|---|
| 730 | } | 
|---|
| 731 | tty_ldisc_unlock(tty); | 
|---|
| 732 | } | 
|---|
| 733 |  | 
|---|
| 734 | /** | 
|---|
| 735 | * tty_ldisc_setup	-	open line discipline | 
|---|
| 736 | * @tty: tty being shut down | 
|---|
| 737 | * @o_tty: pair tty for pty/tty pairs | 
|---|
| 738 | * | 
|---|
| 739 | * Called during the initial open of a tty/pty pair in order to set up the line | 
|---|
| 740 | * disciplines and bind them to the @tty. This has no locking issues as the | 
|---|
| 741 | * device isn't yet active. | 
|---|
| 742 | */ | 
|---|
| 743 | int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) | 
|---|
| 744 | { | 
|---|
| 745 | int retval = tty_ldisc_open(tty, ld: tty->ldisc); | 
|---|
| 746 |  | 
|---|
| 747 | if (retval) | 
|---|
| 748 | return retval; | 
|---|
| 749 |  | 
|---|
| 750 | if (o_tty) { | 
|---|
| 751 | /* | 
|---|
| 752 | * Called without o_tty->ldisc_sem held, as o_tty has been | 
|---|
| 753 | * just allocated and no one has a reference to it. | 
|---|
| 754 | */ | 
|---|
| 755 | retval = tty_ldisc_open(tty: o_tty, ld: o_tty->ldisc); | 
|---|
| 756 | if (retval) { | 
|---|
| 757 | tty_ldisc_close(tty, ld: tty->ldisc); | 
|---|
| 758 | return retval; | 
|---|
| 759 | } | 
|---|
| 760 | } | 
|---|
| 761 | return 0; | 
|---|
| 762 | } | 
|---|
| 763 |  | 
|---|
| 764 | /** | 
|---|
| 765 | * tty_ldisc_release	-	release line discipline | 
|---|
| 766 | * @tty: tty being shut down (or one end of pty pair) | 
|---|
| 767 | * | 
|---|
| 768 | * Called during the final close of a tty or a pty pair in order to shut down | 
|---|
| 769 | * the line discpline layer. On exit, each tty's ldisc is %NULL. | 
|---|
| 770 | */ | 
|---|
| 771 | void tty_ldisc_release(struct tty_struct *tty) | 
|---|
| 772 | { | 
|---|
| 773 | struct tty_struct *o_tty = tty->link; | 
|---|
| 774 |  | 
|---|
| 775 | /* | 
|---|
| 776 | * Shutdown this line discipline. As this is the final close, | 
|---|
| 777 | * it does not race with the set_ldisc code path. | 
|---|
| 778 | */ | 
|---|
| 779 |  | 
|---|
| 780 | tty_ldisc_lock_pair(tty, tty2: o_tty); | 
|---|
| 781 | tty_ldisc_kill(tty); | 
|---|
| 782 | if (o_tty) | 
|---|
| 783 | tty_ldisc_kill(tty: o_tty); | 
|---|
| 784 | tty_ldisc_unlock_pair(tty, tty2: o_tty); | 
|---|
| 785 |  | 
|---|
| 786 | /* | 
|---|
| 787 | * And the memory resources remaining (buffers, termios) will be | 
|---|
| 788 | * disposed of when the kref hits zero | 
|---|
| 789 | */ | 
|---|
| 790 |  | 
|---|
| 791 | tty_ldisc_debug(tty, "released\n"); | 
|---|
| 792 | } | 
|---|
| 793 |  | 
|---|
| 794 | /** | 
|---|
| 795 | * tty_ldisc_init	-	ldisc setup for new tty | 
|---|
| 796 | * @tty: tty being allocated | 
|---|
| 797 | * | 
|---|
| 798 | * Set up the line discipline objects for a newly allocated tty. Note that the | 
|---|
| 799 | * tty structure is not completely set up when this call is made. | 
|---|
| 800 | */ | 
|---|
| 801 | int tty_ldisc_init(struct tty_struct *tty) | 
|---|
| 802 | { | 
|---|
| 803 | struct tty_ldisc *ld = tty_ldisc_get(tty, N_TTY); | 
|---|
| 804 |  | 
|---|
| 805 | if (IS_ERR(ptr: ld)) | 
|---|
| 806 | return PTR_ERR(ptr: ld); | 
|---|
| 807 | tty->ldisc = ld; | 
|---|
| 808 | return 0; | 
|---|
| 809 | } | 
|---|
| 810 |  | 
|---|
| 811 | /** | 
|---|
| 812 | * tty_ldisc_deinit	-	ldisc cleanup for new tty | 
|---|
| 813 | * @tty: tty that was allocated recently | 
|---|
| 814 | * | 
|---|
| 815 | * The tty structure must not be completely set up (tty_ldisc_setup()) when | 
|---|
| 816 | * this call is made. | 
|---|
| 817 | */ | 
|---|
| 818 | void tty_ldisc_deinit(struct tty_struct *tty) | 
|---|
| 819 | { | 
|---|
| 820 | /* no ldisc_sem, tty is being destroyed */ | 
|---|
| 821 | if (tty->ldisc) | 
|---|
| 822 | tty_ldisc_put(ld: tty->ldisc); | 
|---|
| 823 | tty->ldisc = NULL; | 
|---|
| 824 | } | 
|---|
| 825 |  | 
|---|