aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/char/tty_ldisc.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char/tty_ldisc.c')
-rw-r--r--drivers/char/tty_ldisc.c82
1 files changed, 42 insertions, 40 deletions
diff --git a/drivers/char/tty_ldisc.c b/drivers/char/tty_ldisc.c
index e48af9f79219..aafdbaebc16a 100644
--- a/drivers/char/tty_ldisc.c
+++ b/drivers/char/tty_ldisc.c
@@ -145,48 +145,33 @@ int tty_unregister_ldisc(int disc)
145} 145}
146EXPORT_SYMBOL(tty_unregister_ldisc); 146EXPORT_SYMBOL(tty_unregister_ldisc);
147 147
148 148static struct tty_ldisc_ops *get_ldops(int disc)
149/**
150 * tty_ldisc_try_get - try and reference an ldisc
151 * @disc: ldisc number
152 *
153 * Attempt to open and lock a line discipline into place. Return
154 * the line discipline refcounted or an error.
155 */
156
157static struct tty_ldisc *tty_ldisc_try_get(int disc)
158{ 149{
159 unsigned long flags; 150 unsigned long flags;
160 struct tty_ldisc *ld; 151 struct tty_ldisc_ops *ldops, *ret;
161 struct tty_ldisc_ops *ldops;
162 int err = -EINVAL;
163
164 ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
165 if (ld == NULL)
166 return ERR_PTR(-ENOMEM);
167 152
168 spin_lock_irqsave(&tty_ldisc_lock, flags); 153 spin_lock_irqsave(&tty_ldisc_lock, flags);
169 ld->ops = NULL; 154 ret = ERR_PTR(-EINVAL);
170 ldops = tty_ldiscs[disc]; 155 ldops = tty_ldiscs[disc];
171 /* Check the entry is defined */
172 if (ldops) { 156 if (ldops) {
173 /* If the module is being unloaded we can't use it */ 157 ret = ERR_PTR(-EAGAIN);
174 if (!try_module_get(ldops->owner)) 158 if (try_module_get(ldops->owner)) {
175 err = -EAGAIN;
176 else {
177 /* lock it */
178 ldops->refcount++; 159 ldops->refcount++;
179 ld->ops = ldops; 160 ret = ldops;
180 atomic_set(&ld->users, 1);
181 err = 0;
182 } 161 }
183 } 162 }
184 spin_unlock_irqrestore(&tty_ldisc_lock, flags); 163 spin_unlock_irqrestore(&tty_ldisc_lock, flags);
185 if (err) { 164 return ret;
186 kfree(ld); 165}
187 return ERR_PTR(err); 166
188 } 167static void put_ldops(struct tty_ldisc_ops *ldops)
189 return ld; 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);
190} 175}
191 176
192/** 177/**
@@ -205,14 +190,31 @@ static struct tty_ldisc *tty_ldisc_try_get(int disc)
205static struct tty_ldisc *tty_ldisc_get(int disc) 190static struct tty_ldisc *tty_ldisc_get(int disc)
206{ 191{
207 struct tty_ldisc *ld; 192 struct tty_ldisc *ld;
193 struct tty_ldisc_ops *ldops;
208 194
209 if (disc < N_TTY || disc >= NR_LDISCS) 195 if (disc < N_TTY || disc >= NR_LDISCS)
210 return ERR_PTR(-EINVAL); 196 return ERR_PTR(-EINVAL);
211 ld = tty_ldisc_try_get(disc); 197
212 if (IS_ERR(ld)) { 198 /*
199 * Get the ldisc ops - we may need to request them to be loaded
200 * dynamically and try again.
201 */
202 ldops = get_ldops(disc);
203 if (IS_ERR(ldops)) {
213 request_module("tty-ldisc-%d", disc); 204 request_module("tty-ldisc-%d", disc);
214 ld = tty_ldisc_try_get(disc); 205 ldops = get_ldops(disc);
206 if (IS_ERR(ldops))
207 return ERR_CAST(ldops);
215 } 208 }
209
210 ld = kmalloc(sizeof(struct tty_ldisc), GFP_KERNEL);
211 if (ld == NULL) {
212 put_ldops(ldops);
213 return ERR_PTR(-ENOMEM);
214 }
215
216 ld->ops = ldops;
217 atomic_set(&ld->users, 1);
216 return ld; 218 return ld;
217} 219}
218 220
@@ -234,13 +236,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) 236static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
235{ 237{
236 int i = *(loff_t *)v; 238 int i = *(loff_t *)v;
237 struct tty_ldisc *ld; 239 struct tty_ldisc_ops *ldops;
238 240
239 ld = tty_ldisc_try_get(i); 241 ldops = get_ldops(i);
240 if (IS_ERR(ld)) 242 if (IS_ERR(ldops))
241 return 0; 243 return 0;
242 seq_printf(m, "%-10s %2d\n", ld->ops->name ? ld->ops->name : "???", i); 244 seq_printf(m, "%-10s %2d\n", ldops->name ? ldops->name : "???", i);
243 put_ldisc(ld); 245 put_ldops(ldops);
244 return 0; 246 return 0;
245} 247}
246 248