1 /* -*- linux-c -*- --------------------------------------------------------- *
3 * linux/fs/autofs/waitq.c
5 * Copyright 1997 Transmeta Corporation -- All Rights Reserved
7 * This file is part of the Linux kernel and is made available under
8 * the terms of the GNU General Public License, version 2, or at your
9 * option, any later version, incorporated herein by reference.
11 * ------------------------------------------------------------------------- */
13 #include <linux/malloc.h>
14 #include <linux/sched.h>
15 #include <linux/signal.h>
16 #include <linux/file.h>
21 #error Only i386 implemented
24 static inline int sane_pointer(void *p
)
26 return (p
== NULL
) || ((unsigned) p
> 0xc0000000);
29 void autofs_check_waitlist_integrity(struct autofs_sb_info
*sbi
, char *op
)
31 struct autofs_wait_queue
**wqp
, *wq
;
33 if ( sbi
->magic
!= AUTOFS_SBI_MAGIC
) {
34 printk("autofs: CHECK_WAITLIST with bogus sbi pointer: %p\n",
40 while ( (wq
= *wqp
) ) {
41 if ( !sane_pointer(wq
) ) {
42 printk("autofs(%s): wait queue pointer corrupt: ", op
);
48 } while ( sane_pointer(*wqp
) );
59 /* We make this a static variable rather than a part of the superblock; it
60 is better if we don't reassign numbers easily even across filesystems */
61 static int autofs_next_wait_queue
= 1;
63 void autofs_catatonic_mode(struct autofs_sb_info
*sbi
)
65 struct autofs_wait_queue
*wq
, *nwq
;
67 DPRINTK(("autofs: entering catatonic mode\n"));
71 sbi
->queues
= NULL
; /* Erase all wait queues */
74 wq
->status
= -ENOENT
; /* Magic is gone - report failure */
80 fput(sbi
->pipe
, sbi
->pipe
->f_inode
); /* Close the pipe */
83 static int autofs_write(struct file
*file
, const void *addr
, int bytes
)
86 unsigned long old_signal
;
87 const char *data
= (const char *)addr
;
90 /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/
92 /* Save pointer to user space and point back to kernel space */
96 old_signal
= current
->signal
;
98 while ( bytes
&& (written
= file
->f_op
->write(file
->f_inode
,file
,data
,bytes
)) > 0 ) {
103 if ( written
== -EPIPE
&& !(old_signal
& (1 << (SIGPIPE
-1))) ) {
104 /* Keep the currently executing process from receiving a
105 SIGPIPE unless it was already supposed to get one */
106 current
->signal
&= ~(1 << (SIGPIPE
-1));
113 static void autofs_notify_daemon(struct autofs_sb_info
*sbi
, struct autofs_wait_queue
*wq
)
115 struct autofs_packet_missing pkt
;
117 DPRINTK(("autofs_wait: wait id = 0x%08lx, name = ", wq
->wait_queue_token
));
118 autofs_say(wq
->name
,wq
->len
);
120 memset(&pkt
,0,sizeof pkt
); /* For security reasons */
122 pkt
.hdr
.proto_version
= AUTOFS_PROTO_VERSION
;
123 pkt
.hdr
.type
= autofs_ptype_missing
;
124 pkt
.wait_queue_token
= wq
->wait_queue_token
;
126 memcpy(pkt
.name
, wq
->name
, pkt
.len
);
127 pkt
.name
[pkt
.len
] = '\0';
129 if ( autofs_write(sbi
->pipe
,&pkt
,sizeof(struct autofs_packet_missing
)) )
130 autofs_catatonic_mode(sbi
);
133 int autofs_wait(struct autofs_sb_info
*sbi
, autofs_hash_t hash
, const char *name
, int len
)
135 struct autofs_wait_queue
*wq
;
138 CHECK_WAITLIST(sbi
,"wait");
140 for ( wq
= sbi
->queues
; wq
; wq
= wq
->next
) {
141 if ( wq
->hash
== hash
&&
143 wq
->name
&& !memcmp(wq
->name
,name
,len
) )
148 /* Create a new wait queue */
149 wq
= kmalloc(sizeof(struct autofs_wait_queue
),GFP_KERNEL
);
153 wq
->name
= kmalloc(len
,GFP_KERNEL
);
158 wq
->wait_queue_token
= autofs_next_wait_queue
++;
159 init_waitqueue(&wq
->queue
);
162 wq
->status
= -EINTR
; /* Status return if interrupted */
163 memcpy(wq
->name
, name
, len
);
164 wq
->next
= sbi
->queues
;
167 /* autofs_notify_daemon() may block */
169 autofs_notify_daemon(sbi
,wq
);
174 /* wq->name is NULL if and only if the lock is released */
175 interruptible_sleep_on(&wq
->queue
);
177 DPRINTK(("autofs_wait: skipped sleeping\n"));
182 if ( ! --wq
->wait_ctr
) /* Are we the last process to need status? */
189 int autofs_wait_release(struct autofs_sb_info
*sbi
, unsigned long wait_queue_token
, int status
)
191 struct autofs_wait_queue
*wq
, **wql
;
193 CHECK_WAITLIST(sbi
,"release");
195 for ( wql
= &sbi
->queues
; (wq
= *wql
) ; wql
= &wq
->next
) {
196 if ( wq
->wait_queue_token
== wait_queue_token
)
202 *wql
= wq
->next
; /* Unlink from chain */
204 wq
->name
= NULL
; /* Do not wait on this queue */