Merge git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6

* git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty-2.6:
tty-ldisc: be more careful in 'put_ldisc' locking
tty-ldisc: turn ldisc user count into a proper refcount
tty-ldisc: make refcount be atomic_t 'users' count

+54 -100
+53 -99
drivers/char/tty_ldisc.c
··· 48 48 /* Line disc dispatch table */ 49 49 static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; 50 50 51 + static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld) 52 + { 53 + if (ld) 54 + atomic_inc(&ld->users); 55 + return ld; 56 + } 57 + 58 + static void put_ldisc(struct tty_ldisc *ld) 59 + { 60 + unsigned long flags; 61 + 62 + if (WARN_ON_ONCE(!ld)) 63 + return; 64 + 65 + /* 66 + * If this is the last user, free the ldisc, and 67 + * release the ldisc ops. 68 + * 69 + * We really want an "atomic_dec_and_lock_irqsave()", 70 + * but we don't have it, so this does it by hand. 71 + */ 72 + local_irq_save(flags); 73 + if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) { 74 + struct tty_ldisc_ops *ldo = ld->ops; 75 + 76 + ldo->refcount--; 77 + module_put(ldo->owner); 78 + spin_unlock_irqrestore(&tty_ldisc_lock, flags); 79 + 80 + kfree(ld); 81 + return; 82 + } 83 + local_irq_restore(flags); 84 + } 85 + 51 86 /** 52 87 * tty_register_ldisc - install a line discipline 53 88 * @disc: ldisc number ··· 177 142 /* lock it */ 178 143 ldops->refcount++; 179 144 ld->ops = ldops; 180 - ld->refcount = 0; 145 + atomic_set(&ld->users, 1); 181 146 err = 0; 182 147 } 183 148 } ··· 216 181 return ld; 217 182 } 218 183 219 - /** 220 - * tty_ldisc_put - drop ldisc reference 221 - * @ld: ldisc 222 - * 223 - * Drop a reference to a line discipline. Manage refcounts and 224 - * module usage counts. Free the ldisc once the recount hits zero. 225 - * 226 - * Locking: 227 - * takes tty_ldisc_lock to guard against ldisc races 228 - */ 229 - 230 - static void tty_ldisc_put(struct tty_ldisc *ld) 231 - { 232 - unsigned long flags; 233 - int disc = ld->ops->num; 234 - struct tty_ldisc_ops *ldo; 235 - 236 - BUG_ON(disc < N_TTY || disc >= NR_LDISCS); 237 - 238 - spin_lock_irqsave(&tty_ldisc_lock, flags); 239 - ldo = tty_ldiscs[disc]; 240 - BUG_ON(ldo->refcount == 0); 241 - ldo->refcount--; 242 - module_put(ldo->owner); 243 - spin_unlock_irqrestore(&tty_ldisc_lock, flags); 244 - WARN_ON(ld->refcount); 245 - kfree(ld); 246 - } 247 - 248 184 static void *tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos) 249 185 { 250 186 return (*pos < NR_LDISCS) ? pos : NULL; ··· 240 234 if (IS_ERR(ld)) 241 235 return 0; 242 236 seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i); 243 - tty_ldisc_put(ld); 237 + put_ldisc(ld); 244 238 return 0; 245 239 } 246 240 ··· 294 288 * Locking: takes tty_ldisc_lock 295 289 */ 296 290 297 - static int tty_ldisc_try(struct tty_struct *tty) 291 + static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty) 298 292 { 299 293 unsigned long flags; 300 294 struct tty_ldisc *ld; 301 - int ret = 0; 302 295 303 296 spin_lock_irqsave(&tty_ldisc_lock, flags); 304 - ld = tty->ldisc; 305 - if (test_bit(TTY_LDISC, &tty->flags)) { 306 - ld->refcount++; 307 - ret = 1; 308 - } 297 + ld = NULL; 298 + if (test_bit(TTY_LDISC, &tty->flags)) 299 + ld = get_ldisc(tty->ldisc); 309 300 spin_unlock_irqrestore(&tty_ldisc_lock, flags); 310 - return ret; 301 + return ld; 311 302 } 312 303 313 304 /** ··· 325 322 326 323 struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty) 327 324 { 325 + struct tty_ldisc *ld; 326 + 328 327 /* wait_event is a macro */ 329 - wait_event(tty_ldisc_wait, tty_ldisc_try(tty)); 330 - WARN_ON(tty->ldisc->refcount == 0); 331 - return tty->ldisc; 328 + wait_event(tty_ldisc_wait, (ld = tty_ldisc_try(tty)) != NULL); 329 + return ld; 332 330 } 333 331 EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait); 334 332 ··· 346 342 347 343 struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty) 348 344 { 349 - if (tty_ldisc_try(tty)) 350 - return tty->ldisc; 351 - return NULL; 345 + return tty_ldisc_try(tty); 352 346 } 353 347 EXPORT_SYMBOL_GPL(tty_ldisc_ref); 354 348 ··· 362 360 363 361 void tty_ldisc_deref(struct tty_ldisc *ld) 364 362 { 365 - unsigned long flags; 366 - 367 - BUG_ON(ld == NULL); 368 - 369 - spin_lock_irqsave(&tty_ldisc_lock, flags); 370 - if (ld->refcount == 0) 371 - printk(KERN_ERR "tty_ldisc_deref: no references.\n"); 372 - else 373 - ld->refcount--; 374 - if (ld->refcount == 0) 375 - wake_up(&tty_ldisc_wait); 376 - spin_unlock_irqrestore(&tty_ldisc_lock, flags); 363 + put_ldisc(ld); 377 364 } 378 365 EXPORT_SYMBOL_GPL(tty_ldisc_deref); 366 + 367 + static inline void tty_ldisc_put(struct tty_ldisc *ld) 368 + { 369 + put_ldisc(ld); 370 + } 379 371 380 372 /** 381 373 * tty_ldisc_enable - allow ldisc use ··· 519 523 } 520 524 521 525 /** 522 - * tty_ldisc_wait_idle - wait for the ldisc to become idle 523 - * @tty: tty to wait for 524 - * 525 - * Wait for the line discipline to become idle. The discipline must 526 - * have been halted for this to guarantee it remains idle. 527 - * 528 - * tty_ldisc_lock protects the ref counts currently. 529 - */ 530 - 531 - static int tty_ldisc_wait_idle(struct tty_struct *tty) 532 - { 533 - unsigned long flags; 534 - spin_lock_irqsave(&tty_ldisc_lock, flags); 535 - while (tty->ldisc->refcount) { 536 - spin_unlock_irqrestore(&tty_ldisc_lock, flags); 537 - if (wait_event_timeout(tty_ldisc_wait, 538 - tty->ldisc->refcount == 0, 5 * HZ) == 0) 539 - return -EBUSY; 540 - spin_lock_irqsave(&tty_ldisc_lock, flags); 541 - } 542 - spin_unlock_irqrestore(&tty_ldisc_lock, flags); 543 - return 0; 544 - } 545 - 546 - /** 547 526 * tty_set_ldisc - set line discipline 548 527 * @tty: the terminal to set 549 528 * @ldisc: the line discipline ··· 612 641 mutex_unlock(&tty->ldisc_mutex); 613 642 614 643 flush_scheduled_work(); 615 - 616 - /* Let any existing reference holders finish */ 617 - retval = tty_ldisc_wait_idle(tty); 618 - if (retval < 0) { 619 - clear_bit(TTY_LDISC_CHANGING, &tty->flags); 620 - tty_ldisc_put(new_ldisc); 621 - return retval; 622 - } 623 644 624 645 mutex_lock(&tty->ldisc_mutex); 625 646 if (test_bit(TTY_HUPPED, &tty->flags)) { ··· 758 795 if (tty->ldisc) { /* Not yet closed */ 759 796 /* Switch back to N_TTY */ 760 797 tty_ldisc_halt(tty); 761 - tty_ldisc_wait_idle(tty); 762 798 tty_ldisc_reinit(tty); 763 799 /* At this point we have a closed ldisc and we want to 764 800 reopen it. We could defer this to the next open but ··· 821 859 822 860 tty_ldisc_halt(tty); 823 861 flush_scheduled_work(); 824 - 825 - /* 826 - * Wait for any short term users (we know they are just driver 827 - * side waiters as the file is closing so user count on the file 828 - * side is zero. 829 - */ 830 - 831 - tty_ldisc_wait_idle(tty); 832 862 833 863 mutex_lock(&tty->ldisc_mutex); 834 864 /*
+1 -1
include/linux/tty_ldisc.h
··· 144 144 145 145 struct tty_ldisc { 146 146 struct tty_ldisc_ops *ops; 147 - int refcount; 147 + atomic_t users; 148 148 }; 149 149 150 150 #define TTY_LDISC_MAGIC 0x5403