aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/char/tty_ldisc.c65
1 files changed, 39 insertions, 26 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index e48af9f79219..cbfacc0bbea5 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -145,6 +145,34 @@ int tty_unregister_ldisc(int disc)
145} 145}
146EXPORT_SYMBOL(tty_unregister_ldisc); 146EXPORT_SYMBOL(tty_unregister_ldisc);
147 147
148static struct tty_ldisc_ops *get_ldops(int disc)
149{
150 unsigned long flags;
151 struct tty_ldisc_ops *ldops, *ret;
152
153 spin_lock_irqsave(&tty_ldisc_lock, flags);
154 ret = ERR_PTR(-EINVAL);
155 ldops = tty_ldiscs[disc];
156 if (ldops) {
157 ret = ERR_PTR(-EAGAIN);
158 if (try_module_get(ldops->owner)) {
159 ldops->refcount++;
160 ret = ldops;
161 }
162 }
163 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
164 return ret;
165}
166
167static void put_ldops(struct tty_ldisc_ops *ldops)
168{
169 unsigned long flags;
170
171 spin_lock_irqsave(&tty_ldisc_lock, flags);
172 ldops->refcount--;
173 module_put(ldops->owner);
174 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
175}
148 176
149/** 177/**
150 * tty_ldisc_try_get - try and reference an ldisc 178 * tty_ldisc_try_get - try and reference an ldisc
@@ -156,36 +184,21 @@ EXPORT_SYMBOL(tty_unregister_ldisc);
156 184
157static struct tty_ldisc *tty_ldisc_try_get(int disc) 185static struct tty_ldisc *tty_ldisc_try_get(int disc)
158{ 186{
159 unsigned long flags;
160 struct tty_ldisc *ld; 187 struct tty_ldisc *ld;
161 struct tty_ldisc_ops *ldops; 188 struct tty_ldisc_ops *ldops;
162 int err = -EINVAL;
163 189
164 ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL); 190 ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
165 if (ld == NULL) 191 if (ld == NULL)
166 return ERR_PTR(-ENOMEM); 192 return ERR_PTR(-ENOMEM);
167 193
168 spin_lock_irqsave(&tty_ldisc_lock, flags); 194 ldops = get_ldops(disc);
169 ld->ops = NULL; 195 if (IS_ERR(ldops)) {
170 ldops = tty_ldiscs[disc];
171 /* Check the entry is defined */
172 if (ldops) {
173 /* If the module is being unloaded we can't use it */
174 if (!try_module_get(ldops->owner))
175 err = -EAGAIN;
176 else {
177 /* lock it */
178 ldops->refcount++;
179 ld->ops = ldops;
180 atomic_set(&ld->users, 1);
181 err = 0;
182 }
183 }
184 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
185 if (err) {
186 kfree(ld); 196 kfree(ld);
187 return ERR_PTR(err); 197 return ERR_CAST(ldops);
188 } 198 }
199
200 ld->ops = ldops;
201 atomic_set(&ld->users, 1);
189 return ld; 202 return ld;
190} 203}
191 204
@@ -234,13 +247,13 @@ static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
234static int tty_ldiscs_seq_show(struct seq_file *m, void *v) 247static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
235{ 248{
236 int i = *(loff_t *)v; 249 int i = *(loff_t *)v;
237 struct tty_ldisc *ld; 250 struct tty_ldisc_ops *ldops;
238 251
239 ld = tty_ldisc_try_get(i); 252 ldops = get_ldops(i);
240 if (IS_ERR(ld)) 253 if (IS_ERR(ldops))
241 return 0; 254 return 0;
242 seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i); 255 seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
243 put_ldisc(ld); 256 put_ldops(ldops);
244 return 0; 257 return 0;
245} 258}
246 259