diff options
Diffstat (limited to 'drivers/tty/tty_ldisc.c')
-rw-r--r-- | drivers/tty/tty_ldisc.c | 47 |
1 files changed, 26 insertions, 21 deletions
diff --git a/drivers/tty/tty_ldisc.c b/drivers/tty/tty_ldisc.c index 0f2a2c5e704c..c5782294e532 100644 --- a/drivers/tty/tty_ldisc.c +++ b/drivers/tty/tty_ldisc.c | |||
@@ -26,7 +26,7 @@ | |||
26 | * callers who will do ldisc lookups and cannot sleep. | 26 | * callers who will do ldisc lookups and cannot sleep. |
27 | */ | 27 | */ |
28 | 28 | ||
29 | static DEFINE_SPINLOCK(tty_ldisc_lock); | 29 | static DEFINE_RAW_SPINLOCK(tty_ldisc_lock); |
30 | static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); | 30 | static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait); |
31 | /* Line disc dispatch table */ | 31 | /* Line disc dispatch table */ |
32 | static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; | 32 | static struct tty_ldisc_ops *tty_ldiscs[NR_LDISCS]; |
@@ -49,21 +49,21 @@ static void put_ldisc(struct tty_ldisc *ld) | |||
49 | * If this is the last user, free the ldisc, and | 49 | * If this is the last user, free the ldisc, and |
50 | * release the ldisc ops. | 50 | * release the ldisc ops. |
51 | * | 51 | * |
52 | * We really want an "atomic_dec_and_lock_irqsave()", | 52 | * We really want an "atomic_dec_and_raw_lock_irqsave()", |
53 | * but we don't have it, so this does it by hand. | 53 | * but we don't have it, so this does it by hand. |
54 | */ | 54 | */ |
55 | local_irq_save(flags); | 55 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); |
56 | if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) { | 56 | if (atomic_dec_and_test(&ld->users)) { |
57 | struct tty_ldisc_ops *ldo = ld->ops; | 57 | struct tty_ldisc_ops *ldo = ld->ops; |
58 | 58 | ||
59 | ldo->refcount--; | 59 | ldo->refcount--; |
60 | module_put(ldo->owner); | 60 | module_put(ldo->owner); |
61 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 61 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
62 | 62 | ||
63 | kfree(ld); | 63 | kfree(ld); |
64 | return; | 64 | return; |
65 | } | 65 | } |
66 | local_irq_restore(flags); | 66 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
67 | wake_up(&ld->wq_idle); | 67 | wake_up(&ld->wq_idle); |
68 | } | 68 | } |
69 | 69 | ||
@@ -88,11 +88,11 @@ int tty_register_ldisc(int disc, struct tty_ldisc_ops *new_ldisc) | |||
88 | if (disc < N_TTY || disc >= NR_LDISCS) | 88 | if (disc < N_TTY || disc >= NR_LDISCS) |
89 | return -EINVAL; | 89 | return -EINVAL; |
90 | 90 | ||
91 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 91 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); |
92 | tty_ldiscs[disc] = new_ldisc; | 92 | tty_ldiscs[disc] = new_ldisc; |
93 | new_ldisc->num = disc; | 93 | new_ldisc->num = disc; |
94 | new_ldisc->refcount = 0; | 94 | new_ldisc->refcount = 0; |
95 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 95 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
96 | 96 | ||
97 | return ret; | 97 | return ret; |
98 | } | 98 | } |
@@ -118,12 +118,12 @@ int tty_unregister_ldisc(int disc) | |||
118 | if (disc < N_TTY || disc >= NR_LDISCS) | 118 | if (disc < N_TTY || disc >= NR_LDISCS) |
119 | return -EINVAL; | 119 | return -EINVAL; |
120 | 120 | ||
121 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 121 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); |
122 | if (tty_ldiscs[disc]->refcount) | 122 | if (tty_ldiscs[disc]->refcount) |
123 | ret = -EBUSY; | 123 | ret = -EBUSY; |
124 | else | 124 | else |
125 | tty_ldiscs[disc] = NULL; | 125 | tty_ldiscs[disc] = NULL; |
126 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 126 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
127 | 127 | ||
128 | return ret; | 128 | return ret; |
129 | } | 129 | } |
@@ -134,7 +134,7 @@ static struct tty_ldisc_ops *get_ldops(int disc) | |||
134 | unsigned long flags; | 134 | unsigned long flags; |
135 | struct tty_ldisc_ops *ldops, *ret; | 135 | struct tty_ldisc_ops *ldops, *ret; |
136 | 136 | ||
137 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 137 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); |
138 | ret = ERR_PTR(-EINVAL); | 138 | ret = ERR_PTR(-EINVAL); |
139 | ldops = tty_ldiscs[disc]; | 139 | ldops = tty_ldiscs[disc]; |
140 | if (ldops) { | 140 | if (ldops) { |
@@ -144,7 +144,7 @@ static struct tty_ldisc_ops *get_ldops(int disc) | |||
144 | ret = ldops; | 144 | ret = ldops; |
145 | } | 145 | } |
146 | } | 146 | } |
147 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 147 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
148 | return ret; | 148 | return ret; |
149 | } | 149 | } |
150 | 150 | ||
@@ -152,10 +152,10 @@ static void put_ldops(struct tty_ldisc_ops *ldops) | |||
152 | { | 152 | { |
153 | unsigned long flags; | 153 | unsigned long flags; |
154 | 154 | ||
155 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 155 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); |
156 | ldops->refcount--; | 156 | ldops->refcount--; |
157 | module_put(ldops->owner); | 157 | module_put(ldops->owner); |
158 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 158 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
159 | } | 159 | } |
160 | 160 | ||
161 | /** | 161 | /** |
@@ -287,11 +287,11 @@ static struct tty_ldisc *tty_ldisc_try(struct tty_struct *tty) | |||
287 | unsigned long flags; | 287 | unsigned long flags; |
288 | struct tty_ldisc *ld; | 288 | struct tty_ldisc *ld; |
289 | 289 | ||
290 | spin_lock_irqsave(&tty_ldisc_lock, flags); | 290 | raw_spin_lock_irqsave(&tty_ldisc_lock, flags); |
291 | ld = NULL; | 291 | ld = NULL; |
292 | if (test_bit(TTY_LDISC, &tty->flags)) | 292 | if (test_bit(TTY_LDISC, &tty->flags)) |
293 | ld = get_ldisc(tty->ldisc); | 293 | ld = get_ldisc(tty->ldisc); |
294 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 294 | raw_spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
295 | return ld; | 295 | return ld; |
296 | } | 296 | } |
297 | 297 | ||
@@ -512,7 +512,7 @@ static void tty_ldisc_restore(struct tty_struct *tty, struct tty_ldisc *old) | |||
512 | static int tty_ldisc_halt(struct tty_struct *tty) | 512 | static int tty_ldisc_halt(struct tty_struct *tty) |
513 | { | 513 | { |
514 | clear_bit(TTY_LDISC, &tty->flags); | 514 | clear_bit(TTY_LDISC, &tty->flags); |
515 | return cancel_work_sync(&tty->buf.work); | 515 | return cancel_work_sync(&tty->port->buf.work); |
516 | } | 516 | } |
517 | 517 | ||
518 | /** | 518 | /** |
@@ -525,7 +525,7 @@ static void tty_ldisc_flush_works(struct tty_struct *tty) | |||
525 | { | 525 | { |
526 | flush_work(&tty->hangup_work); | 526 | flush_work(&tty->hangup_work); |
527 | flush_work(&tty->SAK_work); | 527 | flush_work(&tty->SAK_work); |
528 | flush_work(&tty->buf.work); | 528 | flush_work(&tty->port->buf.work); |
529 | } | 529 | } |
530 | 530 | ||
531 | /** | 531 | /** |
@@ -704,9 +704,9 @@ enable: | |||
704 | /* Restart the work queue in case no characters kick it off. Safe if | 704 | /* Restart the work queue in case no characters kick it off. Safe if |
705 | already running */ | 705 | already running */ |
706 | if (work) | 706 | if (work) |
707 | schedule_work(&tty->buf.work); | 707 | schedule_work(&tty->port->buf.work); |
708 | if (o_work) | 708 | if (o_work) |
709 | schedule_work(&o_tty->buf.work); | 709 | schedule_work(&o_tty->port->buf.work); |
710 | mutex_unlock(&tty->ldisc_mutex); | 710 | mutex_unlock(&tty->ldisc_mutex); |
711 | tty_unlock(tty); | 711 | tty_unlock(tty); |
712 | return retval; | 712 | return retval; |
@@ -817,7 +817,7 @@ void tty_ldisc_hangup(struct tty_struct *tty) | |||
817 | */ | 817 | */ |
818 | clear_bit(TTY_LDISC, &tty->flags); | 818 | clear_bit(TTY_LDISC, &tty->flags); |
819 | tty_unlock(tty); | 819 | tty_unlock(tty); |
820 | cancel_work_sync(&tty->buf.work); | 820 | cancel_work_sync(&tty->port->buf.work); |
821 | mutex_unlock(&tty->ldisc_mutex); | 821 | mutex_unlock(&tty->ldisc_mutex); |
822 | retry: | 822 | retry: |
823 | tty_lock(tty); | 823 | tty_lock(tty); |
@@ -897,6 +897,11 @@ int tty_ldisc_setup(struct tty_struct *tty, struct tty_struct *o_tty) | |||
897 | 897 | ||
898 | static void tty_ldisc_kill(struct tty_struct *tty) | 898 | static void tty_ldisc_kill(struct tty_struct *tty) |
899 | { | 899 | { |
900 | /* There cannot be users from userspace now. But there still might be | ||
901 | * drivers holding a reference via tty_ldisc_ref. Do not steal them the | ||
902 | * ldisc until they are done. */ | ||
903 | tty_ldisc_wait_idle(tty, MAX_SCHEDULE_TIMEOUT); | ||
904 | |||
900 | mutex_lock(&tty->ldisc_mutex); | 905 | mutex_lock(&tty->ldisc_mutex); |
901 | /* | 906 | /* |
902 | * Now kill off the ldisc | 907 | * Now kill off the ldisc |