diff options
-rw-r--r-- | drivers/char/tty_ldisc.c | 17 |
1 files changed, 12 insertions, 5 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c index be55dfcf59ac..1733d3439ad2 100644 --- a/drivers/char/tty_ldisc.c +++ b/drivers/char/tty_ldisc.c | |||
@@ -55,25 +55,32 @@ static inline struct tty_ldisc *get_ldisc(struct tty_ldisc *ld) | |||
55 | return ld; | 55 | return ld; |
56 | } | 56 | } |
57 | 57 | ||
58 | static inline void put_ldisc(struct tty_ldisc *ld) | 58 | static void put_ldisc(struct tty_ldisc *ld) |
59 | { | 59 | { |
60 | unsigned long flags; | ||
61 | |||
60 | if (WARN_ON_ONCE(!ld)) | 62 | if (WARN_ON_ONCE(!ld)) |
61 | return; | 63 | return; |
62 | 64 | ||
63 | /* | 65 | /* |
64 | * If this is the last user, free the ldisc, and | 66 | * If this is the last user, free the ldisc, and |
65 | * release the ldisc ops. | 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. | ||
66 | */ | 71 | */ |
67 | if (atomic_dec_and_test(&ld->users)) { | 72 | local_irq_save(flags); |
68 | unsigned long flags; | 73 | if (atomic_dec_and_lock(&ld->users, &tty_ldisc_lock)) { |
69 | struct tty_ldisc_ops *ldo = ld->ops; | 74 | struct tty_ldisc_ops *ldo = ld->ops; |
70 | 75 | ||
71 | kfree(ld); | ||
72 | spin_lock_irqsave(&tty_ldisc_lock, flags); | ||
73 | ldo->refcount--; | 76 | ldo->refcount--; |
74 | module_put(ldo->owner); | 77 | module_put(ldo->owner); |
75 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); | 78 | spin_unlock_irqrestore(&tty_ldisc_lock, flags); |
79 | |||
80 | kfree(ld); | ||
81 | return; | ||
76 | } | 82 | } |
83 | local_irq_restore(flags); | ||
77 | } | 84 | } |
78 | 85 | ||
79 | /** | 86 | /** |