1/* -*- c -*- --------------------------------------------------------------- * 2 * 3 * linux/fs/autofs/waitq.c 4 * 5 * Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved 6 * 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. 10 * 11 * ------------------------------------------------------------------------- */ 12 13#include <linux/slab.h> 14#include <linux/sched.h> 15#include <linux/signal.h> 16#include <linux/file.h> 17#include "autofs_i.h" 18 19/* We make this a static variable rather than a part of the superblock; it 20 is better if we don't reassign numbers easily even across filesystems */ 21static autofs_wqt_t autofs4_next_wait_queue = 1; 22 23/* These are the signals we allow interrupting a pending mount */ 24#define SHUTDOWN_SIGS (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT)) 25 26void autofs4_catatonic_mode(struct autofs_sb_info *sbi) 27{ 28 struct autofs_wait_queue *wq, *nwq; 29 30 DPRINTK(("autofs: entering catatonic mode\n")); 31 32 sbi->catatonic = 1; 33 wq = sbi->queues; 34 sbi->queues = NULL; /* Erase all wait queues */ 35 while ( wq ) { 36 nwq = wq->next; 37 wq->status = -ENOENT; /* Magic is gone - report failure */ 38 kfree(wq->name); 39 wq->name = NULL; 40 wake_up(&wq->queue); 41 wq = nwq; 42 } 43 if (sbi->pipe) { 44 fput(sbi->pipe); /* Close the pipe */ 45 sbi->pipe = NULL; 46 } 47 48 shrink_dcache_sb(sbi->sb); 49} 50 51static int autofs4_write(struct file *file, const void *addr, int bytes) 52{ 53 unsigned long sigpipe, flags; 54 mm_segment_t fs; 55 const char *data = (const char *)addr; 56 ssize_t wr = 0; 57 58 /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/ 59 60 sigpipe = sigismember(¤t->pending.signal, SIGPIPE); 61 62 /* Save pointer to user space and point back to kernel space */ 63 fs = get_fs(); 64 set_fs(KERNEL_DS); 65 66 while (bytes && 67 (wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) { 68 data += wr; 69 bytes -= wr; 70 } 71 72 set_fs(fs); 73 74 /* Keep the currently executing process from receiving a 75 SIGPIPE unless it was already supposed to get one */ 76 if (wr == -EPIPE && !sigpipe) { 77 spin_lock_irqsave(¤t->sigmask_lock, flags); 78 sigdelset(¤t->pending.signal, SIGPIPE); 79 recalc_sigpending(current); 80 spin_unlock_irqrestore(¤t->sigmask_lock, flags); 81 } 82 83 return (bytes > 0); 84} 85 86static void autofs4_notify_daemon(struct autofs_sb_info *sbi, 87 struct autofs_wait_queue *wq, 88 int type) 89{ 90 union autofs_packet_union pkt; 91 size_t pktsz; 92 93 DPRINTK(("autofs_notify: wait id = 0x%08lx, name = %.*s, type=%d\n", 94 wq->wait_queue_token, wq->len, wq->name, type)); 95 96 memset(&pkt,0,sizeof pkt); /* For security reasons */ 97 98 pkt.hdr.proto_version = sbi->version; 99 pkt.hdr.type = type; 100 if (type == autofs_ptype_missing) { 101 struct autofs_packet_missing *mp = &pkt.missing; 102 103 pktsz = sizeof(*mp); 104 105 mp->wait_queue_token = wq->wait_queue_token; 106 mp->len = wq->len; 107 memcpy(mp->name, wq->name, wq->len); 108 mp->name[wq->len] = '\0'; 109 } else if (type == autofs_ptype_expire_multi) { 110 struct autofs_packet_expire_multi *ep = &pkt.expire_multi; 111 112 pktsz = sizeof(*ep); 113 114 ep->wait_queue_token = wq->wait_queue_token; 115 ep->len = wq->len; 116 memcpy(ep->name, wq->name, wq->len); 117 ep->name[wq->len] = '\0'; 118 } else { 119 printk("autofs_notify_daemon: bad type %d!\n", type); 120 return; 121 } 122 123 if (autofs4_write(sbi->pipe, &pkt, pktsz)) 124 autofs4_catatonic_mode(sbi); 125} 126 127int autofs4_wait(struct autofs_sb_info *sbi, struct qstr *name, 128 enum autofs_notify notify) 129{ 130 struct autofs_wait_queue *wq; 131 int status; 132 133 /* In catatonic mode, we don't wait for nobody */ 134 if ( sbi->catatonic ) 135 return -ENOENT; 136 137 /* We shouldn't be able to get here, but just in case */ 138 if ( name->len > NAME_MAX ) 139 return -ENOENT; 140 141 for ( wq = sbi->queues ; wq ; wq = wq->next ) { 142 if ( wq->hash == name->hash && 143 wq->len == name->len && 144 wq->name && !memcmp(wq->name,name->name,name->len) ) 145 break; 146 } 147 148 if ( !wq ) { 149 /* Create a new wait queue */ 150 wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL); 151 if ( !wq ) 152 return -ENOMEM; 153 154 wq->name = kmalloc(name->len,GFP_KERNEL); 155 if ( !wq->name ) { 156 kfree(wq); 157 return -ENOMEM; 158 } 159 wq->wait_queue_token = autofs4_next_wait_queue; 160 if (++autofs4_next_wait_queue == 0) 161 autofs4_next_wait_queue = 1; 162 init_waitqueue_head(&wq->queue); 163 wq->hash = name->hash; 164 wq->len = name->len; 165 wq->status = -EINTR; /* Status return if interrupted */ 166 memcpy(wq->name, name->name, name->len); 167 wq->next = sbi->queues; 168 sbi->queues = wq; 169 170 DPRINTK(("autofs_wait: new wait id = 0x%08lx, name = %.*s, nfy=%d\n", 171 wq->wait_queue_token, wq->len, wq->name, notify)); 172 /* autofs4_notify_daemon() may block */ 173 wq->wait_ctr = 2; 174 if (notify != NFY_NONE) { 175 autofs4_notify_daemon(sbi,wq, 176 notify == NFY_MOUNT ? autofs_ptype_missing : 177 autofs_ptype_expire_multi); 178 } 179 } else { 180 wq->wait_ctr++; 181 DPRINTK(("autofs_wait: existing wait id = 0x%08lx, name = %.*s, nfy=%d\n", 182 wq->wait_queue_token, wq->len, wq->name, notify)); 183 } 184 185 /* wq->name is NULL if and only if the lock is already released */ 186 187 if ( sbi->catatonic ) { 188 /* We might have slept, so check again for catatonic mode */ 189 wq->status = -ENOENT; 190 if ( wq->name ) { 191 kfree(wq->name); 192 wq->name = NULL; 193 } 194 } 195 196 if ( wq->name ) { 197 /* Block all but "shutdown" signals while waiting */ 198 sigset_t oldset; 199 unsigned long irqflags; 200 201 spin_lock_irqsave(¤t->sigmask_lock, irqflags); 202 oldset = current->blocked; 203 siginitsetinv(¤t->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]); 204 recalc_sigpending(current); 205 spin_unlock_irqrestore(¤t->sigmask_lock, irqflags); 206 207 interruptible_sleep_on(&wq->queue); 208 209 spin_lock_irqsave(¤t->sigmask_lock, irqflags); 210 current->blocked = oldset; 211 recalc_sigpending(current); 212 spin_unlock_irqrestore(¤t->sigmask_lock, irqflags); 213 } else { 214 DPRINTK(("autofs_wait: skipped sleeping\n")); 215 } 216 217 status = wq->status; 218 219 if (--wq->wait_ctr == 0) /* Are we the last process to need status? */ 220 kfree(wq); 221 222 return status; 223} 224 225 226int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_token, int status) 227{ 228 struct autofs_wait_queue *wq, **wql; 229 230 for ( wql = &sbi->queues ; (wq = *wql) ; wql = &wq->next ) { 231 if ( wq->wait_queue_token == wait_queue_token ) 232 break; 233 } 234 if ( !wq ) 235 return -EINVAL; 236 237 *wql = wq->next; /* Unlink from chain */ 238 kfree(wq->name); 239 wq->name = NULL; /* Do not wait on this queue */ 240 241 wq->status = status; 242 243 if (--wq->wait_ctr == 0) /* Is anyone still waiting for this guy? */ 244 kfree(wq); 245 else 246 wake_up(&wq->queue); 247 248 return 0; 249} 250 251