OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [autofs4/] [waitq.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* -*- c -*- --------------------------------------------------------------- *
2
 *
3
 * linux/fs/autofs/waitq.c
4
 *
5
 *  Copyright 1997-1998 Transmeta Corporation -- All Rights Reserved
6
 *  Copyright 2001-2006 Ian Kent <raven@themaw.net>
7
 *
8
 * This file is part of the Linux kernel and is made available under
9
 * the terms of the GNU General Public License, version 2, or at your
10
 * option, any later version, incorporated herein by reference.
11
 *
12
 * ------------------------------------------------------------------------- */
13
 
14
#include <linux/slab.h>
15
#include <linux/time.h>
16
#include <linux/signal.h>
17
#include <linux/file.h>
18
#include "autofs_i.h"
19
 
20
/* We make this a static variable rather than a part of the superblock; it
21
   is better if we don't reassign numbers easily even across filesystems */
22
static autofs_wqt_t autofs4_next_wait_queue = 1;
23
 
24
/* These are the signals we allow interrupting a pending mount */
25
#define SHUTDOWN_SIGS   (sigmask(SIGKILL) | sigmask(SIGINT) | sigmask(SIGQUIT))
26
 
27
void autofs4_catatonic_mode(struct autofs_sb_info *sbi)
28
{
29
        struct autofs_wait_queue *wq, *nwq;
30
 
31
        DPRINTK("entering catatonic mode");
32
 
33
        sbi->catatonic = 1;
34
        wq = sbi->queues;
35
        sbi->queues = NULL;     /* Erase all wait queues */
36
        while (wq) {
37
                nwq = wq->next;
38
                wq->status = -ENOENT; /* Magic is gone - report failure */
39
                kfree(wq->name);
40
                wq->name = NULL;
41
                wake_up_interruptible(&wq->queue);
42
                wq = nwq;
43
        }
44
        fput(sbi->pipe);        /* Close the pipe */
45
        sbi->pipe = NULL;
46
}
47
 
48
static int autofs4_write(struct file *file, const void *addr, int bytes)
49
{
50
        unsigned long sigpipe, flags;
51
        mm_segment_t fs;
52
        const char *data = (const char *)addr;
53
        ssize_t wr = 0;
54
 
55
        /** WARNING: this is not safe for writing more than PIPE_BUF bytes! **/
56
 
57
        sigpipe = sigismember(&current->pending.signal, SIGPIPE);
58
 
59
        /* Save pointer to user space and point back to kernel space */
60
        fs = get_fs();
61
        set_fs(KERNEL_DS);
62
 
63
        while (bytes &&
64
               (wr = file->f_op->write(file,data,bytes,&file->f_pos)) > 0) {
65
                data += wr;
66
                bytes -= wr;
67
        }
68
 
69
        set_fs(fs);
70
 
71
        /* Keep the currently executing process from receiving a
72
           SIGPIPE unless it was already supposed to get one */
73
        if (wr == -EPIPE && !sigpipe) {
74
                spin_lock_irqsave(&current->sighand->siglock, flags);
75
                sigdelset(&current->pending.signal, SIGPIPE);
76
                recalc_sigpending();
77
                spin_unlock_irqrestore(&current->sighand->siglock, flags);
78
        }
79
 
80
        return (bytes > 0);
81
}
82
 
83
static void autofs4_notify_daemon(struct autofs_sb_info *sbi,
84
                                 struct autofs_wait_queue *wq,
85
                                 int type)
86
{
87
        union {
88
                struct autofs_packet_hdr hdr;
89
                union autofs_packet_union v4_pkt;
90
                union autofs_v5_packet_union v5_pkt;
91
        } pkt;
92
        size_t pktsz;
93
 
94
        DPRINTK("wait id = 0x%08lx, name = %.*s, type=%d",
95
                wq->wait_queue_token, wq->len, wq->name, type);
96
 
97
        memset(&pkt,0,sizeof pkt); /* For security reasons */
98
 
99
        pkt.hdr.proto_version = sbi->version;
100
        pkt.hdr.type = type;
101
        switch (type) {
102
        /* Kernel protocol v4 missing and expire packets */
103
        case autofs_ptype_missing:
104
        {
105
                struct autofs_packet_missing *mp = &pkt.v4_pkt.missing;
106
 
107
                pktsz = sizeof(*mp);
108
 
109
                mp->wait_queue_token = wq->wait_queue_token;
110
                mp->len = wq->len;
111
                memcpy(mp->name, wq->name, wq->len);
112
                mp->name[wq->len] = '\0';
113
                break;
114
        }
115
        case autofs_ptype_expire_multi:
116
        {
117
                struct autofs_packet_expire_multi *ep = &pkt.v4_pkt.expire_multi;
118
 
119
                pktsz = sizeof(*ep);
120
 
121
                ep->wait_queue_token = wq->wait_queue_token;
122
                ep->len = wq->len;
123
                memcpy(ep->name, wq->name, wq->len);
124
                ep->name[wq->len] = '\0';
125
                break;
126
        }
127
        /*
128
         * Kernel protocol v5 packet for handling indirect and direct
129
         * mount missing and expire requests
130
         */
131
        case autofs_ptype_missing_indirect:
132
        case autofs_ptype_expire_indirect:
133
        case autofs_ptype_missing_direct:
134
        case autofs_ptype_expire_direct:
135
        {
136
                struct autofs_v5_packet *packet = &pkt.v5_pkt.v5_packet;
137
 
138
                pktsz = sizeof(*packet);
139
 
140
                packet->wait_queue_token = wq->wait_queue_token;
141
                packet->len = wq->len;
142
                memcpy(packet->name, wq->name, wq->len);
143
                packet->name[wq->len] = '\0';
144
                packet->dev = wq->dev;
145
                packet->ino = wq->ino;
146
                packet->uid = wq->uid;
147
                packet->gid = wq->gid;
148
                packet->pid = wq->pid;
149
                packet->tgid = wq->tgid;
150
                break;
151
        }
152
        default:
153
                printk("autofs4_notify_daemon: bad type %d!\n", type);
154
                return;
155
        }
156
 
157
        if (autofs4_write(sbi->pipe, &pkt, pktsz))
158
                autofs4_catatonic_mode(sbi);
159
}
160
 
161
static int autofs4_getpath(struct autofs_sb_info *sbi,
162
                           struct dentry *dentry, char **name)
163
{
164
        struct dentry *root = sbi->sb->s_root;
165
        struct dentry *tmp;
166
        char *buf = *name;
167
        char *p;
168
        int len = 0;
169
 
170
        spin_lock(&dcache_lock);
171
        for (tmp = dentry ; tmp != root ; tmp = tmp->d_parent)
172
                len += tmp->d_name.len + 1;
173
 
174
        if (--len > NAME_MAX) {
175
                spin_unlock(&dcache_lock);
176
                return 0;
177
        }
178
 
179
        *(buf + len) = '\0';
180
        p = buf + len - dentry->d_name.len;
181
        strncpy(p, dentry->d_name.name, dentry->d_name.len);
182
 
183
        for (tmp = dentry->d_parent; tmp != root ; tmp = tmp->d_parent) {
184
                *(--p) = '/';
185
                p -= tmp->d_name.len;
186
                strncpy(p, tmp->d_name.name, tmp->d_name.len);
187
        }
188
        spin_unlock(&dcache_lock);
189
 
190
        return len;
191
}
192
 
193
static struct autofs_wait_queue *
194
autofs4_find_wait(struct autofs_sb_info *sbi,
195
                  char *name, unsigned int hash, unsigned int len)
196
{
197
        struct autofs_wait_queue *wq;
198
 
199
        for (wq = sbi->queues; wq; wq = wq->next) {
200
                if (wq->hash == hash &&
201
                    wq->len == len &&
202
                    wq->name && !memcmp(wq->name, name, len))
203
                        break;
204
        }
205
        return wq;
206
}
207
 
208
int autofs4_wait(struct autofs_sb_info *sbi, struct dentry *dentry,
209
                enum autofs_notify notify)
210
{
211
        struct autofs_info *ino;
212
        struct autofs_wait_queue *wq;
213
        char *name;
214
        unsigned int len = 0;
215
        unsigned int hash = 0;
216
        int status, type;
217
 
218
        /* In catatonic mode, we don't wait for nobody */
219
        if (sbi->catatonic)
220
                return -ENOENT;
221
 
222
        name = kmalloc(NAME_MAX + 1, GFP_KERNEL);
223
        if (!name)
224
                return -ENOMEM;
225
 
226
        /* If this is a direct mount request create a dummy name */
227
        if (IS_ROOT(dentry) && (sbi->type & AUTOFS_TYPE_DIRECT))
228
                len = sprintf(name, "%p", dentry);
229
        else {
230
                len = autofs4_getpath(sbi, dentry, &name);
231
                if (!len) {
232
                        kfree(name);
233
                        return -ENOENT;
234
                }
235
        }
236
        hash = full_name_hash(name, len);
237
 
238
        if (mutex_lock_interruptible(&sbi->wq_mutex)) {
239
                kfree(name);
240
                return -EINTR;
241
        }
242
 
243
        wq = autofs4_find_wait(sbi, name, hash, len);
244
        ino = autofs4_dentry_ino(dentry);
245
        if (!wq && ino && notify == NFY_NONE) {
246
                /*
247
                 * Either we've betean the pending expire to post it's
248
                 * wait or it finished while we waited on the mutex.
249
                 * So we need to wait till either, the wait appears
250
                 * or the expire finishes.
251
                 */
252
 
253
                while (ino->flags & AUTOFS_INF_EXPIRING) {
254
                        mutex_unlock(&sbi->wq_mutex);
255
                        schedule_timeout_interruptible(HZ/10);
256
                        if (mutex_lock_interruptible(&sbi->wq_mutex)) {
257
                                kfree(name);
258
                                return -EINTR;
259
                        }
260
                        wq = autofs4_find_wait(sbi, name, hash, len);
261
                        if (wq)
262
                                break;
263
                }
264
 
265
                /*
266
                 * Not ideal but the status has already gone. Of the two
267
                 * cases where we wait on NFY_NONE neither depend on the
268
                 * return status of the wait.
269
                 */
270
                if (!wq) {
271
                        kfree(name);
272
                        mutex_unlock(&sbi->wq_mutex);
273
                        return 0;
274
                }
275
        }
276
 
277
        if (!wq) {
278
                /* Create a new wait queue */
279
                wq = kmalloc(sizeof(struct autofs_wait_queue),GFP_KERNEL);
280
                if (!wq) {
281
                        kfree(name);
282
                        mutex_unlock(&sbi->wq_mutex);
283
                        return -ENOMEM;
284
                }
285
 
286
                wq->wait_queue_token = autofs4_next_wait_queue;
287
                if (++autofs4_next_wait_queue == 0)
288
                        autofs4_next_wait_queue = 1;
289
                wq->next = sbi->queues;
290
                sbi->queues = wq;
291
                init_waitqueue_head(&wq->queue);
292
                wq->hash = hash;
293
                wq->name = name;
294
                wq->len = len;
295
                wq->dev = autofs4_get_dev(sbi);
296
                wq->ino = autofs4_get_ino(sbi);
297
                wq->uid = current->uid;
298
                wq->gid = current->gid;
299
                wq->pid = current->pid;
300
                wq->tgid = current->tgid;
301
                wq->status = -EINTR; /* Status return if interrupted */
302
                atomic_set(&wq->wait_ctr, 2);
303
                mutex_unlock(&sbi->wq_mutex);
304
 
305
                if (sbi->version < 5) {
306
                        if (notify == NFY_MOUNT)
307
                                type = autofs_ptype_missing;
308
                        else
309
                                type = autofs_ptype_expire_multi;
310
                } else {
311
                        if (notify == NFY_MOUNT)
312
                                type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
313
                                        autofs_ptype_missing_direct :
314
                                         autofs_ptype_missing_indirect;
315
                        else
316
                                type = (sbi->type & AUTOFS_TYPE_DIRECT) ?
317
                                        autofs_ptype_expire_direct :
318
                                        autofs_ptype_expire_indirect;
319
                }
320
 
321
                DPRINTK("new wait id = 0x%08lx, name = %.*s, nfy=%d\n",
322
                        (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
323
 
324
                /* autofs4_notify_daemon() may block */
325
                autofs4_notify_daemon(sbi, wq, type);
326
        } else {
327
                atomic_inc(&wq->wait_ctr);
328
                mutex_unlock(&sbi->wq_mutex);
329
                kfree(name);
330
                DPRINTK("existing wait id = 0x%08lx, name = %.*s, nfy=%d",
331
                        (unsigned long) wq->wait_queue_token, wq->len, wq->name, notify);
332
        }
333
 
334
        /* wq->name is NULL if and only if the lock is already released */
335
 
336
        if (sbi->catatonic) {
337
                /* We might have slept, so check again for catatonic mode */
338
                wq->status = -ENOENT;
339
                kfree(wq->name);
340
                wq->name = NULL;
341
        }
342
 
343
        if (wq->name) {
344
                /* Block all but "shutdown" signals while waiting */
345
                sigset_t oldset;
346
                unsigned long irqflags;
347
 
348
                spin_lock_irqsave(&current->sighand->siglock, irqflags);
349
                oldset = current->blocked;
350
                siginitsetinv(&current->blocked, SHUTDOWN_SIGS & ~oldset.sig[0]);
351
                recalc_sigpending();
352
                spin_unlock_irqrestore(&current->sighand->siglock, irqflags);
353
 
354
                wait_event_interruptible(wq->queue, wq->name == NULL);
355
 
356
                spin_lock_irqsave(&current->sighand->siglock, irqflags);
357
                current->blocked = oldset;
358
                recalc_sigpending();
359
                spin_unlock_irqrestore(&current->sighand->siglock, irqflags);
360
        } else {
361
                DPRINTK("skipped sleeping");
362
        }
363
 
364
        status = wq->status;
365
 
366
        /* Are we the last process to need status? */
367
        if (atomic_dec_and_test(&wq->wait_ctr))
368
                kfree(wq);
369
 
370
        return status;
371
}
372
 
373
 
374
int autofs4_wait_release(struct autofs_sb_info *sbi, autofs_wqt_t wait_queue_token, int status)
375
{
376
        struct autofs_wait_queue *wq, **wql;
377
 
378
        mutex_lock(&sbi->wq_mutex);
379
        for (wql = &sbi->queues; (wq = *wql) != NULL; wql = &wq->next) {
380
                if (wq->wait_queue_token == wait_queue_token)
381
                        break;
382
        }
383
 
384
        if (!wq) {
385
                mutex_unlock(&sbi->wq_mutex);
386
                return -EINVAL;
387
        }
388
 
389
        *wql = wq->next;        /* Unlink from chain */
390
        mutex_unlock(&sbi->wq_mutex);
391
        kfree(wq->name);
392
        wq->name = NULL;        /* Do not wait on this queue */
393
 
394
        wq->status = status;
395
 
396
        if (atomic_dec_and_test(&wq->wait_ctr)) /* Is anyone still waiting for this guy? */
397
                kfree(wq);
398
        else
399
                wake_up_interruptible(&wq->queue);
400
 
401
        return 0;
402
}
403
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.