Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sys/fs/autofs/autofs.c
39483 views
1
/*-
2
* Copyright (c) 2014 The FreeBSD Foundation
3
*
4
* This software was developed by Edward Tomasz Napierala under sponsorship
5
* from the FreeBSD Foundation.
6
*
7
* Redistribution and use in source and binary forms, with or without
8
* modification, are permitted provided that the following conditions
9
* are met:
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
* 2. Redistributions in binary form must reproduce the above copyright
13
* notice, this list of conditions and the following disclaimer in the
14
* documentation and/or other materials provided with the distribution.
15
*
16
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
* SUCH DAMAGE.
27
*
28
*/
29
/*-
30
* Copyright (c) 1989, 1991, 1993, 1995
31
* The Regents of the University of California. All rights reserved.
32
*
33
* This code is derived from software contributed to Berkeley by
34
* Rick Macklem at The University of Guelph.
35
*
36
* Redistribution and use in source and binary forms, with or without
37
* modification, are permitted provided that the following conditions
38
* are met:
39
* 1. Redistributions of source code must retain the above copyright
40
* notice, this list of conditions and the following disclaimer.
41
* 2. Redistributions in binary form must reproduce the above copyright
42
* notice, this list of conditions and the following disclaimer in the
43
* documentation and/or other materials provided with the distribution.
44
* 3. Neither the name of the University nor the names of its contributors
45
* may be used to endorse or promote products derived from this software
46
* without specific prior written permission.
47
*
48
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58
* SUCH DAMAGE.
59
*
60
*/
61
62
#include <sys/param.h>
63
#include <sys/systm.h>
64
#include <sys/buf.h>
65
#include <sys/conf.h>
66
#include <sys/dirent.h>
67
#include <sys/ioccom.h>
68
#include <sys/kernel.h>
69
#include <sys/module.h>
70
#include <sys/mount.h>
71
#include <sys/refcount.h>
72
#include <sys/sx.h>
73
#include <sys/sysctl.h>
74
#include <sys/syscallsubr.h>
75
#include <sys/taskqueue.h>
76
#include <sys/tree.h>
77
#include <sys/vnode.h>
78
#include <machine/atomic.h>
79
#include <vm/uma.h>
80
81
#include <fs/autofs/autofs.h>
82
#include <fs/autofs/autofs_ioctl.h>
83
84
MALLOC_DEFINE(M_AUTOFS, "autofs", "Automounter filesystem");
85
86
uma_zone_t autofs_request_zone;
87
uma_zone_t autofs_node_zone;
88
89
static int autofs_open(struct cdev *dev, int flags, int fmt,
90
struct thread *td);
91
static int autofs_close(struct cdev *dev, int flag, int fmt,
92
struct thread *td);
93
static int autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg,
94
int mode, struct thread *td);
95
96
static struct cdevsw autofs_cdevsw = {
97
.d_version = D_VERSION,
98
.d_open = autofs_open,
99
.d_close = autofs_close,
100
.d_ioctl = autofs_ioctl,
101
.d_name = "autofs",
102
};
103
104
/*
105
* List of signals that can interrupt an autofs trigger. Might be a good
106
* idea to keep it synchronised with list in sys/fs/nfs/nfs_commonkrpc.c.
107
*/
108
int autofs_sig_set[] = {
109
SIGINT,
110
SIGTERM,
111
SIGHUP,
112
SIGKILL,
113
SIGQUIT
114
};
115
116
struct autofs_softc *autofs_softc;
117
118
SYSCTL_NODE(_vfs, OID_AUTO, autofs, CTLFLAG_RD | CTLFLAG_MPSAFE, 0,
119
"Automounter filesystem");
120
int autofs_debug = 1;
121
TUNABLE_INT("vfs.autofs.debug", &autofs_debug);
122
SYSCTL_INT(_vfs_autofs, OID_AUTO, debug, CTLFLAG_RWTUN,
123
&autofs_debug, 1, "Enable debug messages");
124
int autofs_mount_on_stat = 0;
125
TUNABLE_INT("vfs.autofs.mount_on_stat", &autofs_mount_on_stat);
126
SYSCTL_INT(_vfs_autofs, OID_AUTO, mount_on_stat, CTLFLAG_RWTUN,
127
&autofs_mount_on_stat, 0, "Trigger mount on stat(2) on mountpoint");
128
int autofs_timeout = 30;
129
TUNABLE_INT("vfs.autofs.timeout", &autofs_timeout);
130
SYSCTL_INT(_vfs_autofs, OID_AUTO, timeout, CTLFLAG_RWTUN,
131
&autofs_timeout, 30, "Number of seconds to wait for automountd(8)");
132
int autofs_cache = 600;
133
TUNABLE_INT("vfs.autofs.cache", &autofs_cache);
134
SYSCTL_INT(_vfs_autofs, OID_AUTO, cache, CTLFLAG_RWTUN,
135
&autofs_cache, 600, "Number of seconds to wait before reinvoking "
136
"automountd(8) for any given file or directory");
137
int autofs_retry_attempts = 3;
138
TUNABLE_INT("vfs.autofs.retry_attempts", &autofs_retry_attempts);
139
SYSCTL_INT(_vfs_autofs, OID_AUTO, retry_attempts, CTLFLAG_RWTUN,
140
&autofs_retry_attempts, 3, "Number of attempts before failing mount");
141
int autofs_retry_delay = 1;
142
TUNABLE_INT("vfs.autofs.retry_delay", &autofs_retry_delay);
143
SYSCTL_INT(_vfs_autofs, OID_AUTO, retry_delay, CTLFLAG_RWTUN,
144
&autofs_retry_delay, 1, "Number of seconds before retrying");
145
int autofs_interruptible = 1;
146
TUNABLE_INT("vfs.autofs.interruptible", &autofs_interruptible);
147
SYSCTL_INT(_vfs_autofs, OID_AUTO, interruptible, CTLFLAG_RWTUN,
148
&autofs_interruptible, 1, "Allow requests to be interrupted by signal");
149
150
static int
151
autofs_node_cmp(const struct autofs_node *a, const struct autofs_node *b)
152
{
153
154
return (strcmp(a->an_name, b->an_name));
155
}
156
157
RB_GENERATE(autofs_node_tree, autofs_node, an_link, autofs_node_cmp);
158
159
int
160
autofs_init(struct vfsconf *vfsp)
161
{
162
int error;
163
164
KASSERT(autofs_softc == NULL,
165
("softc %p, should be NULL", autofs_softc));
166
167
autofs_softc = malloc(sizeof(*autofs_softc), M_AUTOFS,
168
M_WAITOK | M_ZERO);
169
170
autofs_request_zone = uma_zcreate("autofs_request",
171
sizeof(struct autofs_request), NULL, NULL, NULL, NULL,
172
UMA_ALIGN_PTR, 0);
173
autofs_node_zone = uma_zcreate("autofs_node",
174
sizeof(struct autofs_node), NULL, NULL, NULL, NULL,
175
UMA_ALIGN_PTR, 0);
176
177
TAILQ_INIT(&autofs_softc->sc_requests);
178
cv_init(&autofs_softc->sc_cv, "autofscv");
179
sx_init(&autofs_softc->sc_lock, "autofslk");
180
181
error = make_dev_p(MAKEDEV_CHECKNAME, &autofs_softc->sc_cdev,
182
&autofs_cdevsw, NULL, UID_ROOT, GID_WHEEL, 0600, "autofs");
183
if (error != 0) {
184
AUTOFS_WARN("failed to create device node, error %d", error);
185
uma_zdestroy(autofs_request_zone);
186
uma_zdestroy(autofs_node_zone);
187
free(autofs_softc, M_AUTOFS);
188
189
return (error);
190
}
191
autofs_softc->sc_cdev->si_drv1 = autofs_softc;
192
193
return (0);
194
}
195
196
int
197
autofs_uninit(struct vfsconf *vfsp)
198
{
199
200
sx_xlock(&autofs_softc->sc_lock);
201
if (autofs_softc->sc_dev_opened) {
202
sx_xunlock(&autofs_softc->sc_lock);
203
return (EBUSY);
204
}
205
if (autofs_softc->sc_cdev != NULL)
206
destroy_dev(autofs_softc->sc_cdev);
207
208
uma_zdestroy(autofs_request_zone);
209
uma_zdestroy(autofs_node_zone);
210
211
sx_xunlock(&autofs_softc->sc_lock);
212
/*
213
* XXX: Race with open?
214
*/
215
free(autofs_softc, M_AUTOFS);
216
217
return (0);
218
}
219
220
bool
221
autofs_ignore_thread(const struct thread *td)
222
{
223
struct proc *p;
224
225
p = td->td_proc;
226
227
if (autofs_softc->sc_dev_opened == false)
228
return (false);
229
230
PROC_LOCK(p);
231
if (p->p_session->s_sid == autofs_softc->sc_dev_sid) {
232
PROC_UNLOCK(p);
233
return (true);
234
}
235
PROC_UNLOCK(p);
236
237
return (false);
238
}
239
240
static char *
241
autofs_path(struct autofs_node *anp)
242
{
243
struct autofs_mount *amp;
244
char *path, *tmp;
245
246
amp = anp->an_mount;
247
248
path = strdup("", M_AUTOFS);
249
for (; anp->an_parent != NULL; anp = anp->an_parent) {
250
tmp = malloc(strlen(anp->an_name) + strlen(path) + 2,
251
M_AUTOFS, M_WAITOK);
252
strcpy(tmp, anp->an_name);
253
strcat(tmp, "/");
254
strcat(tmp, path);
255
free(path, M_AUTOFS);
256
path = tmp;
257
}
258
259
tmp = malloc(strlen(amp->am_mountpoint) + strlen(path) + 2,
260
M_AUTOFS, M_WAITOK);
261
strcpy(tmp, amp->am_mountpoint);
262
strcat(tmp, "/");
263
strcat(tmp, path);
264
free(path, M_AUTOFS);
265
path = tmp;
266
267
return (path);
268
}
269
270
static void
271
autofs_task(void *context, int pending)
272
{
273
struct autofs_request *ar;
274
275
ar = context;
276
277
sx_xlock(&autofs_softc->sc_lock);
278
AUTOFS_WARN("request %d for %s timed out after %d seconds",
279
ar->ar_id, ar->ar_path, autofs_timeout);
280
/*
281
* XXX: EIO perhaps?
282
*/
283
ar->ar_error = ETIMEDOUT;
284
ar->ar_wildcards = true;
285
ar->ar_done = true;
286
ar->ar_in_progress = false;
287
cv_broadcast(&autofs_softc->sc_cv);
288
sx_xunlock(&autofs_softc->sc_lock);
289
}
290
291
bool
292
autofs_cached(struct autofs_node *anp, const char *component, int componentlen)
293
{
294
int error;
295
struct autofs_mount *amp;
296
297
amp = anp->an_mount;
298
299
AUTOFS_ASSERT_UNLOCKED(amp);
300
301
/*
302
* For root node we need to request automountd(8) assistance even
303
* if the node is marked as cached, but the requested top-level
304
* directory does not exist. This is necessary for wildcard indirect
305
* map keys to work. We don't do this if we know that there are
306
* no wildcards.
307
*/
308
if (anp->an_parent == NULL && componentlen != 0 && anp->an_wildcards) {
309
AUTOFS_SLOCK(amp);
310
error = autofs_node_find(anp, component, componentlen, NULL);
311
AUTOFS_SUNLOCK(amp);
312
if (error != 0)
313
return (false);
314
}
315
316
return (anp->an_cached);
317
}
318
319
static void
320
autofs_cache_callout(void *context)
321
{
322
struct autofs_node *anp;
323
324
anp = context;
325
anp->an_cached = false;
326
}
327
328
void
329
autofs_flush(struct autofs_mount *amp)
330
{
331
332
/*
333
* XXX: This will do for now, but ideally we should iterate
334
* over all the nodes.
335
*/
336
amp->am_root->an_cached = false;
337
AUTOFS_DEBUG("%s flushed", amp->am_mountpoint);
338
}
339
340
/*
341
* The set/restore sigmask functions are used to (temporarily) overwrite
342
* the thread td_sigmask during triggering.
343
*/
344
static void
345
autofs_set_sigmask(sigset_t *oldset)
346
{
347
sigset_t newset;
348
int i;
349
350
SIGFILLSET(newset);
351
/* Remove the autofs set of signals from newset */
352
PROC_LOCK(curproc);
353
mtx_lock(&curproc->p_sigacts->ps_mtx);
354
for (i = 0 ; i < nitems(autofs_sig_set); i++) {
355
/*
356
* But make sure we leave the ones already masked
357
* by the process, i.e. remove the signal from the
358
* temporary signalmask only if it wasn't already
359
* in p_sigmask.
360
*/
361
if (!SIGISMEMBER(curthread->td_sigmask, autofs_sig_set[i]) &&
362
!SIGISMEMBER(curproc->p_sigacts->ps_sigignore,
363
autofs_sig_set[i])) {
364
SIGDELSET(newset, autofs_sig_set[i]);
365
}
366
}
367
mtx_unlock(&curproc->p_sigacts->ps_mtx);
368
kern_sigprocmask(curthread, SIG_SETMASK, &newset, oldset,
369
SIGPROCMASK_PROC_LOCKED);
370
PROC_UNLOCK(curproc);
371
}
372
373
static void
374
autofs_restore_sigmask(sigset_t *set)
375
{
376
377
kern_sigprocmask(curthread, SIG_SETMASK, set, NULL, 0);
378
}
379
380
static int
381
autofs_trigger_one(struct autofs_node *anp,
382
const char *component, int componentlen)
383
{
384
sigset_t oldset;
385
struct autofs_mount *amp;
386
struct autofs_node *firstanp;
387
struct autofs_request *ar;
388
char *key, *path;
389
int error = 0, request_error, last;
390
bool wildcards;
391
392
amp = anp->an_mount;
393
394
sx_assert(&autofs_softc->sc_lock, SA_XLOCKED);
395
396
if (anp->an_parent == NULL) {
397
key = strndup(component, componentlen, M_AUTOFS);
398
} else {
399
for (firstanp = anp; firstanp->an_parent->an_parent != NULL;
400
firstanp = firstanp->an_parent)
401
continue;
402
key = strdup(firstanp->an_name, M_AUTOFS);
403
}
404
405
path = autofs_path(anp);
406
407
TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
408
if (strcmp(ar->ar_path, path) != 0)
409
continue;
410
if (strcmp(ar->ar_key, key) != 0)
411
continue;
412
413
KASSERT(strcmp(ar->ar_from, amp->am_from) == 0,
414
("from changed; %s != %s", ar->ar_from, amp->am_from));
415
KASSERT(strcmp(ar->ar_prefix, amp->am_prefix) == 0,
416
("prefix changed; %s != %s",
417
ar->ar_prefix, amp->am_prefix));
418
KASSERT(strcmp(ar->ar_options, amp->am_options) == 0,
419
("options changed; %s != %s",
420
ar->ar_options, amp->am_options));
421
422
break;
423
}
424
425
if (ar != NULL) {
426
refcount_acquire(&ar->ar_refcount);
427
} else {
428
ar = uma_zalloc(autofs_request_zone, M_WAITOK | M_ZERO);
429
ar->ar_mount = amp;
430
431
ar->ar_id =
432
atomic_fetchadd_int(&autofs_softc->sc_last_request_id, 1);
433
strlcpy(ar->ar_from, amp->am_from, sizeof(ar->ar_from));
434
strlcpy(ar->ar_path, path, sizeof(ar->ar_path));
435
strlcpy(ar->ar_prefix, amp->am_prefix, sizeof(ar->ar_prefix));
436
strlcpy(ar->ar_key, key, sizeof(ar->ar_key));
437
strlcpy(ar->ar_options,
438
amp->am_options, sizeof(ar->ar_options));
439
440
TIMEOUT_TASK_INIT(taskqueue_thread, &ar->ar_task, 0,
441
autofs_task, ar);
442
taskqueue_enqueue_timeout(taskqueue_thread, &ar->ar_task,
443
autofs_timeout * hz);
444
refcount_init(&ar->ar_refcount, 1);
445
TAILQ_INSERT_TAIL(&autofs_softc->sc_requests, ar, ar_next);
446
}
447
448
cv_broadcast(&autofs_softc->sc_cv);
449
while (ar->ar_done == false) {
450
if (autofs_interruptible != 0) {
451
autofs_set_sigmask(&oldset);
452
error = cv_wait_sig(&autofs_softc->sc_cv,
453
&autofs_softc->sc_lock);
454
autofs_restore_sigmask(&oldset);
455
if (error != 0) {
456
AUTOFS_WARN("cv_wait_sig for %s failed "
457
"with error %d", ar->ar_path, error);
458
break;
459
}
460
} else {
461
cv_wait(&autofs_softc->sc_cv, &autofs_softc->sc_lock);
462
}
463
}
464
465
request_error = ar->ar_error;
466
if (request_error != 0) {
467
AUTOFS_WARN("request for %s completed with error %d, "
468
"pid %d (%s)", ar->ar_path, request_error,
469
curproc->p_pid, curproc->p_comm);
470
}
471
472
wildcards = ar->ar_wildcards;
473
474
last = refcount_release(&ar->ar_refcount);
475
if (last) {
476
TAILQ_REMOVE(&autofs_softc->sc_requests, ar, ar_next);
477
/*
478
* Unlock the sc_lock, so that autofs_task() can complete.
479
*/
480
sx_xunlock(&autofs_softc->sc_lock);
481
taskqueue_cancel_timeout(taskqueue_thread, &ar->ar_task, NULL);
482
taskqueue_drain_timeout(taskqueue_thread, &ar->ar_task);
483
uma_zfree(autofs_request_zone, ar);
484
sx_xlock(&autofs_softc->sc_lock);
485
}
486
487
/*
488
* Note that we do not do negative caching on purpose. This
489
* way the user can retry access at any time, e.g. after fixing
490
* the failure reason, without waiting for cache timer to expire.
491
*/
492
if (error == 0 && request_error == 0 && autofs_cache > 0) {
493
anp->an_cached = true;
494
anp->an_wildcards = wildcards;
495
callout_reset(&anp->an_callout, autofs_cache * hz,
496
autofs_cache_callout, anp);
497
}
498
499
free(key, M_AUTOFS);
500
free(path, M_AUTOFS);
501
502
if (error != 0)
503
return (error);
504
return (request_error);
505
}
506
507
/*
508
* Send request to automountd(8) and wait for completion.
509
*/
510
int
511
autofs_trigger(struct autofs_node *anp,
512
const char *component, int componentlen)
513
{
514
int error;
515
516
for (;;) {
517
error = autofs_trigger_one(anp, component, componentlen);
518
if (error == 0) {
519
anp->an_retries = 0;
520
return (0);
521
}
522
if (error == EINTR || error == ERESTART) {
523
AUTOFS_DEBUG("trigger interrupted by signal, "
524
"not retrying");
525
anp->an_retries = 0;
526
return (error);
527
}
528
anp->an_retries++;
529
if (anp->an_retries >= autofs_retry_attempts) {
530
AUTOFS_DEBUG("trigger failed %d times; returning "
531
"error %d", anp->an_retries, error);
532
anp->an_retries = 0;
533
return (error);
534
}
535
AUTOFS_DEBUG("trigger failed with error %d; will retry in "
536
"%d seconds, %d attempts left", error, autofs_retry_delay,
537
autofs_retry_attempts - anp->an_retries);
538
sx_xunlock(&autofs_softc->sc_lock);
539
pause("autofs_retry", autofs_retry_delay * hz);
540
sx_xlock(&autofs_softc->sc_lock);
541
}
542
}
543
544
static int
545
autofs_ioctl_request(struct autofs_daemon_request *adr)
546
{
547
struct autofs_request *ar;
548
int error;
549
550
sx_xlock(&autofs_softc->sc_lock);
551
for (;;) {
552
TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
553
if (ar->ar_done)
554
continue;
555
if (ar->ar_in_progress)
556
continue;
557
558
break;
559
}
560
561
if (ar != NULL)
562
break;
563
564
error = cv_wait_sig(&autofs_softc->sc_cv,
565
&autofs_softc->sc_lock);
566
if (error != 0) {
567
sx_xunlock(&autofs_softc->sc_lock);
568
return (error);
569
}
570
}
571
572
ar->ar_in_progress = true;
573
sx_xunlock(&autofs_softc->sc_lock);
574
575
adr->adr_id = ar->ar_id;
576
strlcpy(adr->adr_from, ar->ar_from, sizeof(adr->adr_from));
577
strlcpy(adr->adr_path, ar->ar_path, sizeof(adr->adr_path));
578
strlcpy(adr->adr_prefix, ar->ar_prefix, sizeof(adr->adr_prefix));
579
strlcpy(adr->adr_key, ar->ar_key, sizeof(adr->adr_key));
580
strlcpy(adr->adr_options, ar->ar_options, sizeof(adr->adr_options));
581
582
PROC_LOCK(curproc);
583
autofs_softc->sc_dev_sid = curproc->p_session->s_sid;
584
PROC_UNLOCK(curproc);
585
586
return (0);
587
}
588
589
static int
590
autofs_ioctl_done_101(struct autofs_daemon_done_101 *add)
591
{
592
struct autofs_request *ar;
593
594
sx_xlock(&autofs_softc->sc_lock);
595
TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
596
if (ar->ar_id == add->add_id)
597
break;
598
}
599
600
if (ar == NULL) {
601
sx_xunlock(&autofs_softc->sc_lock);
602
AUTOFS_DEBUG("id %d not found", add->add_id);
603
return (ESRCH);
604
}
605
606
ar->ar_error = add->add_error;
607
ar->ar_wildcards = true;
608
ar->ar_done = true;
609
ar->ar_in_progress = false;
610
cv_broadcast(&autofs_softc->sc_cv);
611
612
sx_xunlock(&autofs_softc->sc_lock);
613
614
return (0);
615
}
616
617
static int
618
autofs_ioctl_done(struct autofs_daemon_done *add)
619
{
620
struct autofs_request *ar;
621
622
sx_xlock(&autofs_softc->sc_lock);
623
TAILQ_FOREACH(ar, &autofs_softc->sc_requests, ar_next) {
624
if (ar->ar_id == add->add_id)
625
break;
626
}
627
628
if (ar == NULL) {
629
sx_xunlock(&autofs_softc->sc_lock);
630
AUTOFS_DEBUG("id %d not found", add->add_id);
631
return (ESRCH);
632
}
633
634
ar->ar_error = add->add_error;
635
ar->ar_wildcards = add->add_wildcards;
636
ar->ar_done = true;
637
ar->ar_in_progress = false;
638
cv_broadcast(&autofs_softc->sc_cv);
639
640
sx_xunlock(&autofs_softc->sc_lock);
641
642
return (0);
643
}
644
645
static int
646
autofs_open(struct cdev *dev, int flags, int fmt, struct thread *td)
647
{
648
649
sx_xlock(&autofs_softc->sc_lock);
650
/*
651
* We must never block automountd(8) and its descendants, and we use
652
* session ID to determine that: we store session id of the process
653
* that opened the device, and then compare it with session ids
654
* of triggering processes. This means running a second automountd(8)
655
* instance would break the previous one. The check below prevents
656
* it from happening.
657
*/
658
if (autofs_softc->sc_dev_opened) {
659
sx_xunlock(&autofs_softc->sc_lock);
660
return (EBUSY);
661
}
662
663
autofs_softc->sc_dev_opened = true;
664
sx_xunlock(&autofs_softc->sc_lock);
665
666
return (0);
667
}
668
669
static int
670
autofs_close(struct cdev *dev, int flag, int fmt, struct thread *td)
671
{
672
673
sx_xlock(&autofs_softc->sc_lock);
674
KASSERT(autofs_softc->sc_dev_opened, ("not opened?"));
675
autofs_softc->sc_dev_opened = false;
676
sx_xunlock(&autofs_softc->sc_lock);
677
678
return (0);
679
}
680
681
static int
682
autofs_ioctl(struct cdev *dev, u_long cmd, caddr_t arg, int mode,
683
struct thread *td)
684
{
685
686
KASSERT(autofs_softc->sc_dev_opened, ("not opened?"));
687
688
switch (cmd) {
689
case AUTOFSREQUEST:
690
return (autofs_ioctl_request(
691
(struct autofs_daemon_request *)arg));
692
case AUTOFSDONE101:
693
return (autofs_ioctl_done_101(
694
(struct autofs_daemon_done_101 *)arg));
695
case AUTOFSDONE:
696
return (autofs_ioctl_done(
697
(struct autofs_daemon_done *)arg));
698
default:
699
AUTOFS_DEBUG("invalid cmd %lx", cmd);
700
return (EINVAL);
701
}
702
}
703
704