~ubuntu-branches/ubuntu/precise/autofs5/precise

« back to all changes in this revision

Viewing changes to .pc/autofs-5.0.5-more-code-analysis-corrections.patch/daemon/state.c

  • Committer: Bazaar Package Importer
  • Author(s): Chuck Short
  • Date: 2011-07-03 14:35:46 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20110703143546-nej26krjij0rf792
Tags: 5.0.6-0ubuntu1
* New upstream release:
  - Dropped upstream patches 
  - Refreshed debian/patches/17ld.patch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* ----------------------------------------------------------------------- *
2
 
 *
3
 
 *  state.c - state machine functions.
4
 
 *
5
 
 *   Copyright 2006 Ian Kent <raven@themaw.net> - All Rights Reserved
6
 
 *
7
 
 *   This program is free software; you can redistribute it and/or modify
8
 
 *   it under the terms of the GNU General Public License as published by
9
 
 *   the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
10
 
 *   USA; either version 2 of the License, or (at your option) any later
11
 
 *   version; incorporated herein by reference.
12
 
 *
13
 
 * ----------------------------------------------------------------------- */
14
 
 
15
 
#include <sys/ioctl.h>
16
 
 
17
 
#include "automount.h"
18
 
 
19
 
/* Attribute to create detached thread */
20
 
extern pthread_attr_t th_attr_detached;
21
 
 
22
 
struct state_queue {
23
 
        pthread_t thid;
24
 
        struct list_head list;
25
 
        struct list_head pending;
26
 
        struct autofs_point *ap;
27
 
        enum states state;
28
 
        unsigned int busy;
29
 
        unsigned int done;
30
 
        unsigned int cancel;
31
 
};
32
 
 
33
 
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
34
 
static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
35
 
static unsigned int signaled = 0;
36
 
static LIST_HEAD(state_queue);
37
 
 
38
 
static void st_set_thid(struct autofs_point *, pthread_t);
39
 
static void st_set_done(struct autofs_point *ap);
40
 
 
41
 
void st_mutex_lock(void)
42
 
{
43
 
        int status = pthread_mutex_lock(&mutex);
44
 
        if (status)
45
 
                fatal(status);
46
 
}
47
 
 
48
 
void st_mutex_unlock(void)
49
 
{
50
 
        int status = pthread_mutex_unlock(&mutex);
51
 
        if (status)
52
 
                fatal(status);
53
 
}
54
 
 
55
 
void dump_state_queue(void)
56
 
{
57
 
        struct list_head *head = &state_queue;
58
 
        struct list_head *p, *q;
59
 
 
60
 
        logmsg("dumping queue");
61
 
 
62
 
        list_for_each(p, head) {
63
 
                struct state_queue *entry;
64
 
 
65
 
                entry = list_entry(p, struct state_queue, list);
66
 
                logmsg("queue list head path %s state %d busy %d",
67
 
                      entry->ap->path, entry->state, entry->busy);
68
 
 
69
 
                list_for_each(q, &entry->pending) {
70
 
                        struct state_queue *this;
71
 
 
72
 
                        this = list_entry(q, struct state_queue, pending);
73
 
                        logmsg("queue list entry path %s state %d busy %d",
74
 
                              this->ap->path, this->state, this->busy);
75
 
                }
76
 
        }
77
 
}
78
 
 
79
 
void nextstate(int statefd, enum states next)
80
 
{
81
 
        char buf[MAX_ERR_BUF];
82
 
 
83
 
        if (write(statefd, &next, sizeof(next)) != sizeof(next)) {
84
 
                char *estr = strerror_r(errno, buf, MAX_ERR_BUF);
85
 
                logerr("write failed %s", estr);
86
 
        }
87
 
}
88
 
 
89
 
/*
90
 
 * Handle expire thread cleanup and return the next state the system
91
 
 * should enter as a result.
92
 
 */
93
 
void expire_cleanup(void *arg)
94
 
{
95
 
        struct ioctl_ops *ops = get_ioctl_ops();
96
 
        pthread_t thid = pthread_self();
97
 
        struct expire_args *ec;
98
 
        struct autofs_point *ap;
99
 
        int success;
100
 
        enum states next = ST_INVAL;
101
 
 
102
 
        ec = (struct expire_args *) arg;
103
 
        ap = ec->ap;
104
 
        success = ec->status;
105
 
 
106
 
        st_mutex_lock();
107
 
 
108
 
        debug(ap->logopt,
109
 
              "got thid %lu path %s stat %d",
110
 
              (unsigned long) thid, ap->path, success);
111
 
 
112
 
        /* Check to see if expire process finished */
113
 
        if (thid == ap->exp_thread) {
114
 
                unsigned int idle;
115
 
                int rv;
116
 
 
117
 
                ap->exp_thread = 0;
118
 
 
119
 
                switch (ap->state) {
120
 
                case ST_EXPIRE:
121
 
                        /* FALLTHROUGH */
122
 
                case ST_PRUNE:
123
 
                        /*
124
 
                         * If we're a submount and we've just pruned or
125
 
                         * expired everything away, try to shut down.
126
 
                         *
127
 
                         * Since we use the the fact that a mount will not
128
 
                         * expire for at least ap->exp_timeout to avoid a
129
 
                         * mount <-> expire race we need to wait before
130
 
                         * letting a submount expire away. We also need
131
 
                         * them to go away fairly quickly so the owner
132
 
                         * mount expires in a reasonable time. Just skip
133
 
                         * one expire check after it's no longer busy before
134
 
                         * allowing it to shutdown.
135
 
                         */
136
 
                        if (ap->submount && !success) {
137
 
                                rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle);
138
 
                                if (!rv && idle && ap->submount > 1) {
139
 
                                        next = ST_SHUTDOWN_PENDING;
140
 
                                        break;
141
 
                                }
142
 
 
143
 
                                if (ap->submount++ == 0)
144
 
                                        ap->submount = 2;
145
 
                        }
146
 
 
147
 
                        if (!ap->submount)
148
 
                                alarm_add(ap, ap->exp_runfreq);
149
 
 
150
 
                        /* FALLTHROUGH */
151
 
 
152
 
                case ST_READY:
153
 
                        next = ST_READY;
154
 
                        break;
155
 
 
156
 
                case ST_SHUTDOWN_PENDING:
157
 
                        /*
158
 
                         * If we reveive a mount request while trying to
159
 
                         * shutdown return to ready state unless we have
160
 
                         * been signaled to shutdown.
161
 
                         */
162
 
                        rv = ops->askumount(ap->logopt, ap->ioctlfd, &idle);
163
 
                        if (!idle && !ap->shutdown) {
164
 
                                next = ST_READY;
165
 
                                if (!ap->submount)
166
 
                                        alarm_add(ap, ap->exp_runfreq);
167
 
                                break;
168
 
                        }
169
 
 
170
 
                        next = ST_SHUTDOWN;
171
 
#ifdef ENABLE_IGNORE_BUSY_MOUNTS
172
 
                        break;
173
 
#else
174
 
                        if (success == 0)
175
 
                                break;
176
 
 
177
 
                        /* Failed shutdown returns to ready */
178
 
                        warn(ap->logopt, "filesystem %s still busy", ap->path);
179
 
                        if (!ap->submount)
180
 
                                alarm_add(ap, ap->exp_runfreq);
181
 
                        next = ST_READY;
182
 
                        break;
183
 
#endif
184
 
 
185
 
                case ST_SHUTDOWN_FORCE:
186
 
                        next = ST_SHUTDOWN;
187
 
                        break;
188
 
 
189
 
                default:
190
 
                        error(ap->logopt, "bad state %d", ap->state);
191
 
                }
192
 
 
193
 
                if (next != ST_INVAL) {
194
 
                        debug(ap->logopt,
195
 
                          "sigchld: exp %lu finished, switching from %d to %d",
196
 
                          (unsigned long) thid, ap->state, next);
197
 
                }
198
 
        }
199
 
 
200
 
        if (next != ST_INVAL)
201
 
                __st_add_task(ap, next);
202
 
 
203
 
        st_set_done(ap);
204
 
 
205
 
        st_mutex_unlock();
206
 
 
207
 
        return;
208
 
}
209
 
 
210
 
static unsigned int st_ready(struct autofs_point *ap)
211
 
{
212
 
        debug(ap->logopt,
213
 
              "st_ready(): state = %d path %s", ap->state, ap->path);
214
 
 
215
 
        ap->shutdown = 0;
216
 
        ap->state = ST_READY;
217
 
 
218
 
        return 1;
219
 
}
220
 
 
221
 
enum expire {
222
 
        EXP_ERROR,
223
 
        EXP_STARTED,
224
 
        EXP_PARTIAL
225
 
};
226
 
 
227
 
/*
228
 
 * Generate expiry messages.  If "now" is true, timeouts are ignored.
229
 
 *
230
 
 * Returns: ERROR       - error
231
 
 *          STARTED     - expiry process started
232
 
 *          DONE        - nothing to expire
233
 
 *          PARTIAL     - partial expire
234
 
 */
235
 
 
236
 
void expire_proc_cleanup(void *arg)
237
 
{
238
 
        struct expire_args *ea;
239
 
        int status;
240
 
 
241
 
        ea = (struct expire_args *) arg;
242
 
 
243
 
        status = pthread_mutex_unlock(&ea->mutex);
244
 
        if (status)
245
 
                fatal(status);
246
 
 
247
 
        status = pthread_cond_destroy(&ea->cond);
248
 
        if (status)
249
 
                fatal(status);
250
 
 
251
 
        status = pthread_mutex_destroy(&ea->mutex);
252
 
        if (status)
253
 
                fatal(status);
254
 
 
255
 
        free(ea);
256
 
 
257
 
        return;
258
 
}
259
 
 
260
 
static enum expire expire_proc(struct autofs_point *ap, int now)
261
 
{
262
 
        pthread_t thid;
263
 
        struct expire_args *ea;
264
 
        void *(*expire)(void *);
265
 
        int status;
266
 
 
267
 
        assert(ap->exp_thread == 0);
268
 
 
269
 
        ea = malloc(sizeof(struct expire_args));
270
 
        if (!ea) {
271
 
                error(ap->logopt, "failed to malloc expire cond struct");
272
 
                return EXP_ERROR;
273
 
        }
274
 
 
275
 
        status = pthread_mutex_init(&ea->mutex, NULL);
276
 
        if (status)
277
 
                fatal(status);
278
 
 
279
 
        status = pthread_cond_init(&ea->cond, NULL);
280
 
        if (status)
281
 
                fatal(status);
282
 
 
283
 
        status = pthread_mutex_lock(&ea->mutex);
284
 
        if (status)
285
 
                fatal(status);
286
 
 
287
 
        ea->ap = ap;
288
 
        ea->when = now;
289
 
        ea->status = 1;
290
 
 
291
 
        if (ap->type == LKP_INDIRECT)
292
 
                expire = expire_proc_indirect;
293
 
        else
294
 
                expire = expire_proc_direct;
295
 
 
296
 
        status = pthread_create(&thid, &th_attr_detached, expire, ea);
297
 
        if (status) {
298
 
                error(ap->logopt,
299
 
                      "expire thread create for %s failed", ap->path);
300
 
                expire_proc_cleanup((void *) ea);
301
 
                return EXP_ERROR;
302
 
        }
303
 
        ap->exp_thread = thid;
304
 
        st_set_thid(ap, thid);
305
 
 
306
 
        pthread_cleanup_push(expire_proc_cleanup, ea);
307
 
 
308
 
        debug(ap->logopt, "exp_proc = %lu path %s",
309
 
                (unsigned long) ap->exp_thread, ap->path);
310
 
 
311
 
        ea->signaled = 0;
312
 
        while (!ea->signaled) {
313
 
                status = pthread_cond_wait(&ea->cond, &ea->mutex);
314
 
                if (status)
315
 
                        fatal(status);
316
 
        }
317
 
 
318
 
        pthread_cleanup_pop(1);
319
 
 
320
 
        return EXP_STARTED;
321
 
}
322
 
 
323
 
static void do_readmap_cleanup(void *arg)
324
 
{
325
 
        struct readmap_args *ra;
326
 
        struct autofs_point *ap;
327
 
 
328
 
        ra = (struct readmap_args *) arg;
329
 
 
330
 
        ap = ra->ap;
331
 
 
332
 
        st_mutex_lock();
333
 
 
334
 
        ap->readmap_thread = 0;
335
 
        st_ready(ap);
336
 
        st_set_done(ap);
337
 
 
338
 
        if (!ap->submount)
339
 
                alarm_add(ap, ap->exp_runfreq);
340
 
 
341
 
        st_mutex_unlock();
342
 
 
343
 
        free(ra);
344
 
 
345
 
        return;
346
 
}
347
 
 
348
 
static void tree_mnts_cleanup(void *arg)
349
 
{
350
 
        struct mnt_list *mnts = (struct mnt_list *) arg;
351
 
        tree_free_mnt_tree(mnts);
352
 
        return;
353
 
}
354
 
 
355
 
static void do_readmap_mount(struct autofs_point *ap, struct mnt_list *mnts,
356
 
                             struct map_source *map, struct mapent *me, time_t now)
357
 
{
358
 
        struct mapent_cache *nc;
359
 
        struct mapent *ne, *nested, *valid;
360
 
 
361
 
        nc = ap->entry->master->nc;
362
 
 
363
 
        ne = cache_lookup_distinct(nc, me->key);
364
 
        if (!ne) {
365
 
                nested = cache_partial_match(nc, me->key);
366
 
                if (nested) {
367
 
                        error(ap->logopt,
368
 
                              "removing invalid nested null entry %s",
369
 
                              nested->key);
370
 
                        nested = cache_partial_match(nc, me->key);
371
 
                        if (nested)
372
 
                                cache_delete(nc, nested->key);
373
 
                }
374
 
        }
375
 
 
376
 
        if (me->age < now || (ne && map->master_line > ne->age)) {
377
 
                /*
378
 
                 * The map instance may have changed, such as the map name or
379
 
                 * the mount options, but the direct map entry may still exist
380
 
                 * in one of the other maps. If so then update the new cache
381
 
                 * entry device and inode so we can find it at lookup. Later,
382
 
                 * the mount for the new cache entry will just update the
383
 
                 * timeout.
384
 
                 *
385
 
                 * TODO: how do we recognise these orphaned map instances. We
386
 
                 * can't just delete these instances when the cache becomes
387
 
                 * empty because that is a valid state for a master map entry.
388
 
                 * This is becuase of the requirement to continue running with
389
 
                 * an empty cache awaiting a map re-load.
390
 
                 */
391
 
                valid = lookup_source_valid_mapent(ap, me->key, LKP_DISTINCT);
392
 
                if (valid && valid->mc == me->mc) {
393
 
                        /*
394
 
                         * We've found a map entry that has been removed from
395
 
                         * the current cache so there is no need to update it.
396
 
                         * The stale entry will be dealt with when we prune the
397
 
                         * cache later.
398
 
                         */
399
 
                        cache_unlock(valid->mc);
400
 
                        valid = NULL;
401
 
                }
402
 
                if (valid) {
403
 
                        struct mapent_cache *vmc = valid->mc;
404
 
                        cache_unlock(vmc);
405
 
                        debug(ap->logopt,
406
 
                             "updating cache entry for valid direct trigger %s",
407
 
                             me->key);
408
 
                        cache_writelock(vmc);
409
 
                        valid = cache_lookup_distinct(vmc, me->key);
410
 
                        /* Take over the mount if there is one */
411
 
                        valid->ioctlfd = me->ioctlfd;
412
 
                        me->ioctlfd = -1;
413
 
                        /* Set device and inode number of the new mapent */
414
 
                        cache_set_ino_index(vmc, me->key, me->dev, me->ino);
415
 
                        cache_unlock(vmc);
416
 
                } else if (!tree_is_mounted(mnts, me->key, MNTS_REAL))
417
 
                        do_umount_autofs_direct(ap, mnts, me);
418
 
                else
419
 
                        debug(ap->logopt,
420
 
                              "%s is mounted", me->key);
421
 
        } else
422
 
                do_mount_autofs_direct(ap, mnts, me);
423
 
 
424
 
        return;
425
 
}
426
 
 
427
 
static void *do_readmap(void *arg)
428
 
{
429
 
        struct autofs_point *ap;
430
 
        struct map_source *map;
431
 
        struct mapent_cache *nc, *mc;
432
 
        struct readmap_args *ra;
433
 
        struct mnt_list *mnts;
434
 
        int status;
435
 
        time_t now;
436
 
 
437
 
        ra = (struct readmap_args *) arg;
438
 
 
439
 
        status = pthread_mutex_lock(&ra->mutex);
440
 
        if (status)
441
 
                fatal(status);
442
 
 
443
 
        ap = ra->ap;
444
 
        now = ra->now;
445
 
 
446
 
        ra->signaled = 1;
447
 
        status = pthread_cond_signal(&ra->cond);
448
 
        if (status) {
449
 
                error(ap->logopt, "failed to signal expire condition");
450
 
                pthread_mutex_unlock(&ra->mutex);
451
 
                fatal(status);
452
 
        }
453
 
 
454
 
        status = pthread_mutex_unlock(&ra->mutex);
455
 
        if (status)
456
 
                fatal(status);
457
 
 
458
 
        pthread_cleanup_push(do_readmap_cleanup, ra);
459
 
 
460
 
        info(ap->logopt, "re-reading map for %s", ap->path);
461
 
 
462
 
        pthread_cleanup_push(master_mutex_lock_cleanup, NULL);
463
 
        master_mutex_lock();
464
 
        status = lookup_nss_read_map(ap, NULL, now);
465
 
        if (!status)
466
 
                pthread_exit(NULL);
467
 
        pthread_cleanup_pop(1);
468
 
 
469
 
        if (ap->type == LKP_INDIRECT) {
470
 
                lookup_prune_cache(ap, now);
471
 
                status = lookup_ghost(ap, ap->path);
472
 
        } else {
473
 
                struct mapent *me;
474
 
 
475
 
                mnts = tree_make_mnt_tree(_PROC_MOUNTS, "/");
476
 
                pthread_cleanup_push(tree_mnts_cleanup, mnts);
477
 
                pthread_cleanup_push(master_source_lock_cleanup, ap->entry);
478
 
                master_source_readlock(ap->entry);
479
 
                nc = ap->entry->master->nc;
480
 
                cache_readlock(nc);
481
 
                pthread_cleanup_push(cache_lock_cleanup, nc);
482
 
                map = ap->entry->maps;
483
 
                while (map) {
484
 
                        /* Is map source up to date or no longer valid */
485
 
                        if (!map->stale) {
486
 
                                map = map->next;
487
 
                                continue;
488
 
                        }
489
 
                        mc = map->mc;
490
 
                        pthread_cleanup_push(cache_lock_cleanup, mc);
491
 
                        cache_readlock(mc);
492
 
                        me = cache_enumerate(mc, NULL);
493
 
                        while (me) {
494
 
                                do_readmap_mount(ap, mnts, map, me, now);
495
 
                                me = cache_enumerate(mc, me);
496
 
                        }
497
 
                        lookup_prune_one_cache(ap, map->mc, now);
498
 
                        pthread_cleanup_pop(1);
499
 
                        map->stale = 0;
500
 
                        map = map->next;
501
 
                }
502
 
                pthread_cleanup_pop(1);
503
 
                pthread_cleanup_pop(1);
504
 
                pthread_cleanup_pop(1);
505
 
                lookup_prune_cache(ap, now);
506
 
        }
507
 
 
508
 
        pthread_cleanup_pop(1);
509
 
 
510
 
        return NULL;
511
 
}
512
 
 
513
 
static void st_readmap_cleanup(void *arg)
514
 
{
515
 
        struct readmap_args *ra;
516
 
        int status;
517
 
 
518
 
        ra = (struct readmap_args *) arg;
519
 
 
520
 
        status = pthread_mutex_unlock(&ra->mutex);
521
 
        if (status)
522
 
                fatal(status);
523
 
 
524
 
        status = pthread_cond_destroy(&ra->cond);
525
 
        if (status)
526
 
                fatal(status);
527
 
 
528
 
        status = pthread_mutex_destroy(&ra->mutex);
529
 
        if (status)
530
 
                fatal(status);
531
 
 
532
 
        return;
533
 
}
534
 
 
535
 
static unsigned int st_readmap(struct autofs_point *ap)
536
 
{
537
 
        pthread_t thid;
538
 
        struct readmap_args *ra;
539
 
        int status;
540
 
        int now = time(NULL);
541
 
 
542
 
        debug(ap->logopt, "state %d path %s", ap->state, ap->path);
543
 
 
544
 
        assert(ap->state == ST_READY);
545
 
        assert(ap->readmap_thread == 0);
546
 
 
547
 
        ap->state = ST_READMAP;
548
 
 
549
 
        ra = malloc(sizeof(struct readmap_args));
550
 
        if (!ra) {
551
 
                error(ap->logopt, "failed to malloc reamap cond struct");
552
 
                /* It didn't work: return to ready */
553
 
                st_ready(ap);
554
 
                if (!ap->submount)
555
 
                        alarm_add(ap, ap->exp_runfreq);
556
 
                return 0;
557
 
        }
558
 
 
559
 
        status = pthread_mutex_init(&ra->mutex, NULL);
560
 
        if (status)
561
 
                fatal(status);
562
 
 
563
 
        status = pthread_cond_init(&ra->cond, NULL);
564
 
        if (status)
565
 
                fatal(status);
566
 
 
567
 
        status = pthread_mutex_lock(&ra->mutex);
568
 
        if (status)
569
 
                fatal(status);
570
 
 
571
 
        ra->ap = ap;
572
 
        ra->now = now;
573
 
 
574
 
        status = pthread_create(&thid, &th_attr_detached, do_readmap, ra);
575
 
        if (status) {
576
 
                error(ap->logopt, "read map thread create failed");
577
 
                st_readmap_cleanup(ra);
578
 
                free(ra);
579
 
                /* It didn't work: return to ready */
580
 
                st_ready(ap);
581
 
                if (!ap->submount)
582
 
                        alarm_add(ap, ap->exp_runfreq);
583
 
                return 0;
584
 
        }
585
 
        ap->readmap_thread = thid;
586
 
        st_set_thid(ap, thid);
587
 
 
588
 
        pthread_cleanup_push(st_readmap_cleanup, ra);
589
 
 
590
 
        ra->signaled = 0;
591
 
        while (!ra->signaled) {
592
 
                status = pthread_cond_wait(&ra->cond, &ra->mutex);
593
 
                if (status)
594
 
                        fatal(status);
595
 
        }
596
 
 
597
 
        pthread_cleanup_pop(1);
598
 
 
599
 
        return 1;
600
 
}
601
 
 
602
 
static unsigned int st_prepare_shutdown(struct autofs_point *ap)
603
 
{
604
 
        int exp;
605
 
 
606
 
        debug(ap->logopt, "state %d path %s", ap->state, ap->path);
607
 
 
608
 
        assert(ap->state == ST_READY || ap->state == ST_EXPIRE);
609
 
        ap->state = ST_SHUTDOWN_PENDING;
610
 
 
611
 
        /* Unmount everything */
612
 
        exp = expire_proc(ap, 1);
613
 
        switch (exp) {
614
 
        case EXP_ERROR:
615
 
        case EXP_PARTIAL:
616
 
                /* It didn't work: return to ready */
617
 
                if (!ap->submount)
618
 
                        alarm_add(ap, ap->exp_runfreq);
619
 
                st_ready(ap);
620
 
                return 0;
621
 
 
622
 
        case EXP_STARTED:
623
 
                return 1;
624
 
        }
625
 
        return 0;
626
 
}
627
 
 
628
 
static unsigned int st_force_shutdown(struct autofs_point *ap)
629
 
{
630
 
        int exp;
631
 
 
632
 
        debug(ap->logopt, "state %d path %s", ap->state, ap->path);
633
 
 
634
 
        assert(ap->state == ST_READY || ap->state == ST_EXPIRE);
635
 
        ap->state = ST_SHUTDOWN_FORCE;
636
 
 
637
 
        /* Unmount everything */
638
 
        exp = expire_proc(ap, 1);
639
 
        switch (exp) {
640
 
        case EXP_ERROR:
641
 
        case EXP_PARTIAL:
642
 
                /* It didn't work: return to ready */
643
 
                if (!ap->submount)
644
 
                        alarm_add(ap, ap->exp_runfreq);
645
 
                st_ready(ap);
646
 
                return 0;
647
 
 
648
 
        case EXP_STARTED:
649
 
                return 1;
650
 
        }
651
 
        return 0;
652
 
}
653
 
 
654
 
static unsigned int st_shutdown(struct autofs_point *ap)
655
 
{
656
 
        debug(ap->logopt, "state %d path %s", ap->state, ap->path);
657
 
 
658
 
        assert(ap->state == ST_SHUTDOWN_PENDING || ap->state == ST_SHUTDOWN_FORCE);
659
 
 
660
 
        ap->state = ST_SHUTDOWN;
661
 
        nextstate(ap->state_pipe[1], ST_SHUTDOWN);
662
 
 
663
 
        return 0;
664
 
}
665
 
 
666
 
static unsigned int st_prune(struct autofs_point *ap)
667
 
{
668
 
        debug(ap->logopt, "state %d path %s", ap->state, ap->path);
669
 
 
670
 
        assert(ap->state == ST_READY);
671
 
        ap->state = ST_PRUNE;
672
 
 
673
 
        switch (expire_proc(ap, 1)) {
674
 
        case EXP_ERROR:
675
 
        case EXP_PARTIAL:
676
 
                if (!ap->submount)
677
 
                        alarm_add(ap, ap->exp_runfreq);
678
 
                st_ready(ap);
679
 
                return 0;
680
 
 
681
 
        case EXP_STARTED:
682
 
                return 1;
683
 
        }
684
 
        return 0;
685
 
}
686
 
 
687
 
static unsigned int st_expire(struct autofs_point *ap)
688
 
{
689
 
        debug(ap->logopt, "state %d path %s", ap->state, ap->path);
690
 
 
691
 
        assert(ap->state == ST_READY);
692
 
        ap->state = ST_EXPIRE;
693
 
 
694
 
        switch (expire_proc(ap, 0)) {
695
 
        case EXP_ERROR:
696
 
        case EXP_PARTIAL:
697
 
                if (!ap->submount)
698
 
                        alarm_add(ap, ap->exp_runfreq);
699
 
                st_ready(ap);
700
 
                return 0;
701
 
 
702
 
        case EXP_STARTED:
703
 
                return 1;
704
 
        }
705
 
        return 0;
706
 
}
707
 
 
708
 
static struct state_queue *st_alloc_task(struct autofs_point *ap, enum states state)
709
 
{
710
 
        struct state_queue *task;
711
 
 
712
 
        task = malloc(sizeof(struct state_queue));
713
 
        if (!task)
714
 
                return NULL;
715
 
        memset(task, 0, sizeof(struct state_queue));
716
 
 
717
 
        task->ap = ap;
718
 
        task->state = state;
719
 
 
720
 
        INIT_LIST_HEAD(&task->list);
721
 
        INIT_LIST_HEAD(&task->pending);
722
 
 
723
 
        return task;
724
 
}
725
 
 
726
 
/*
727
 
 * Insert alarm entry on ordered list.
728
 
 * State queue mutex and ap state mutex, in that order, must be held.
729
 
 */
730
 
int __st_add_task(struct autofs_point *ap, enum states state)
731
 
{
732
 
        struct list_head *head;
733
 
        struct list_head *p, *q;
734
 
        struct state_queue *new;
735
 
        unsigned int empty = 1;
736
 
        int status;
737
 
 
738
 
        /* Task termination marker, poke state machine */
739
 
        if (state == ST_READY) {
740
 
                st_ready(ap);
741
 
 
742
 
                signaled = 1;
743
 
                status = pthread_cond_signal(&cond);
744
 
                if (status)
745
 
                        fatal(status);
746
 
 
747
 
                return 1;
748
 
        }
749
 
 
750
 
        if (ap->state == ST_SHUTDOWN)
751
 
                return 1;
752
 
 
753
 
        if (state == ST_SHUTDOWN)
754
 
                return st_shutdown(ap);
755
 
 
756
 
        head = &state_queue;
757
 
 
758
 
        /* Add to task queue for autofs_point ? */
759
 
        list_for_each(p, head) {
760
 
                struct state_queue *task;
761
 
 
762
 
                task = list_entry(p, struct state_queue, list);
763
 
 
764
 
                if (task->ap != ap)
765
 
                        continue;
766
 
 
767
 
                empty = 0;
768
 
 
769
 
                /* Don't add duplicate tasks */
770
 
                if ((task->state == state && !task->done) ||
771
 
                   (ap->state == ST_SHUTDOWN_PENDING ||
772
 
                    ap->state == ST_SHUTDOWN_FORCE))
773
 
                        break;
774
 
 
775
 
                /* No pending tasks */
776
 
                if (list_empty(&task->pending)) {
777
 
                        new = st_alloc_task(ap, state);
778
 
                        if (new)
779
 
                                list_add_tail(&new->pending, &task->pending);
780
 
                        goto done;
781
 
                }
782
 
 
783
 
                list_for_each(q, &task->pending) {
784
 
                        struct state_queue *p_task;
785
 
 
786
 
                        p_task = list_entry(q, struct state_queue, pending);
787
 
 
788
 
                        if (p_task->state == state ||
789
 
                           (ap->state == ST_SHUTDOWN_PENDING ||
790
 
                            ap->state == ST_SHUTDOWN_FORCE))
791
 
                                goto done;
792
 
                }
793
 
 
794
 
                new = st_alloc_task(ap, state);
795
 
                if (new)
796
 
                        list_add_tail(&new->pending, &task->pending);
797
 
done:
798
 
                break;
799
 
        }
800
 
 
801
 
        if (empty) {
802
 
                new = st_alloc_task(ap, state);
803
 
                if (new)
804
 
                        list_add(&new->list, head);
805
 
        }
806
 
 
807
 
        /* Added task, encourage state machine */
808
 
        signaled = 1;
809
 
        status = pthread_cond_signal(&cond);
810
 
        if (status)
811
 
                fatal(status);
812
 
 
813
 
        return 1;
814
 
}
815
 
 
816
 
int st_add_task(struct autofs_point *ap, enum states state)
817
 
{
818
 
        int ret;
819
 
 
820
 
        st_mutex_lock();
821
 
        ret = __st_add_task(ap, state);
822
 
        st_mutex_unlock();
823
 
 
824
 
        return ret;
825
 
}
826
 
 
827
 
/*
828
 
 * Remove state queue tasks for ap.
829
 
 * State queue mutex and ap state mutex, in that order, must be held.
830
 
 */
831
 
void st_remove_tasks(struct autofs_point *ap)
832
 
{
833
 
        struct list_head *head;
834
 
        struct list_head *p, *q;
835
 
        struct state_queue *task, *waiting;
836
 
        int status;
837
 
 
838
 
        st_mutex_lock();
839
 
 
840
 
        head = &state_queue;
841
 
 
842
 
        if (list_empty(head)) {
843
 
                st_mutex_unlock();
844
 
                return;
845
 
        }
846
 
 
847
 
        p = head->next;
848
 
        while (p != head) {
849
 
                task = list_entry(p, struct state_queue, list);
850
 
                p = p->next;
851
 
 
852
 
                if (task->ap != ap)
853
 
                        continue;
854
 
 
855
 
                if (task->busy) {
856
 
                        /* We only cancel readmap, prune and expire */
857
 
                        if (task->state == ST_EXPIRE ||
858
 
                            task->state == ST_PRUNE ||
859
 
                            task->state == ST_READMAP)
860
 
                                task->cancel = 1;
861
 
                }
862
 
 
863
 
                q = (&task->pending)->next;
864
 
                while(q != &task->pending) {
865
 
                        waiting = list_entry(q, struct state_queue, pending);
866
 
                        q = q->next;
867
 
 
868
 
                        /* Don't remove existing shutdown task */
869
 
                        if (waiting->state != ST_SHUTDOWN_PENDING &&
870
 
                            waiting->state != ST_SHUTDOWN_FORCE) {
871
 
                                list_del(&waiting->pending);
872
 
                                free(waiting);
873
 
                        }
874
 
                }
875
 
        }
876
 
 
877
 
        signaled = 1;
878
 
        status = pthread_cond_signal(&cond);
879
 
        if (status)
880
 
                fatal(status);
881
 
 
882
 
        st_mutex_unlock();
883
 
 
884
 
        return;
885
 
}
886
 
 
887
 
static int st_task_active(struct autofs_point *ap, enum states state)
888
 
{
889
 
        struct list_head *head;
890
 
        struct list_head *p, *q;
891
 
        struct state_queue *task, *waiting;
892
 
        unsigned int active = 0;
893
 
 
894
 
        st_mutex_lock();
895
 
 
896
 
        head = &state_queue;
897
 
 
898
 
        list_for_each(p, head) {
899
 
                task = list_entry(p, struct state_queue, list);
900
 
 
901
 
                if (task->ap != ap)
902
 
                        continue;
903
 
 
904
 
                if (task->state == state) {
905
 
                        active = 1;
906
 
                        break;
907
 
                }
908
 
 
909
 
                if (state == ST_ANY) {
910
 
                        active = 1;
911
 
                        break;
912
 
                }
913
 
 
914
 
                list_for_each(q, &task->pending) {
915
 
                        waiting = list_entry(q, struct state_queue, pending);
916
 
 
917
 
                        if (waiting->state == state) {
918
 
                                active = 1;
919
 
                                break;
920
 
                        }
921
 
 
922
 
                        if (state == ST_ANY) {
923
 
                                active = 1;
924
 
                                break;
925
 
                        }
926
 
                }
927
 
        }
928
 
 
929
 
        st_mutex_unlock();
930
 
 
931
 
        return active;
932
 
}
933
 
 
934
 
int st_wait_task(struct autofs_point *ap, enum states state, unsigned int seconds)
935
 
{
936
 
        unsigned int wait = 0;
937
 
        unsigned int duration = 0;
938
 
        int ret = 0;
939
 
 
940
 
        while (1) {
941
 
                struct timespec t = { 0, 200000000 };
942
 
                struct timespec r;
943
 
 
944
 
                while (nanosleep(&t, &r) == -1 && errno == EINTR)
945
 
                        memcpy(&t, &r, sizeof(struct timespec));
946
 
 
947
 
                if (wait++ == 4) {
948
 
                        wait = 0;
949
 
                        duration++;
950
 
                }
951
 
 
952
 
                if (!st_task_active(ap, state)) {
953
 
                        ret = 1;
954
 
                        break;
955
 
                }
956
 
 
957
 
                if (seconds && duration >= seconds)
958
 
                        break;
959
 
        }
960
 
 
961
 
        return ret;
962
 
}
963
 
 
964
 
int st_wait_state(struct autofs_point *ap, enum states state)
965
 
{
966
 
        while (1) {
967
 
                struct timespec t = { 0, 200000000 };
968
 
                struct timespec r;
969
 
 
970
 
                while (nanosleep(&t, &r) == -1 && errno == EINTR)
971
 
                        memcpy(&t, &r, sizeof(struct timespec));
972
 
 
973
 
                st_mutex_lock();
974
 
                if (ap->state == state) {
975
 
                        st_mutex_unlock();
976
 
                        return 1;
977
 
                }
978
 
                st_mutex_unlock();
979
 
        }
980
 
 
981
 
        return 0;
982
 
}
983
 
 
984
 
 
985
 
static int run_state_task(struct state_queue *task)
986
 
{
987
 
        struct autofs_point *ap;
988
 
        enum states next_state, state;
989
 
        unsigned long ret = 0;
990
 
 
991
 
        ap = task->ap;
992
 
        next_state = task->state;
993
 
 
994
 
        state = ap->state;
995
 
 
996
 
        if (next_state != state) {
997
 
                switch (next_state) {
998
 
                case ST_PRUNE:
999
 
                        ret = st_prune(ap);
1000
 
                        break;
1001
 
 
1002
 
                case ST_EXPIRE:
1003
 
                        ret = st_expire(ap);
1004
 
                        break;
1005
 
 
1006
 
                case ST_READMAP:
1007
 
                        ret = st_readmap(ap);
1008
 
                        break;
1009
 
 
1010
 
                case ST_SHUTDOWN_PENDING:
1011
 
                        ret = st_prepare_shutdown(ap);
1012
 
                        break;
1013
 
 
1014
 
                case ST_SHUTDOWN_FORCE:
1015
 
                        ret = st_force_shutdown(ap);
1016
 
                        break;
1017
 
 
1018
 
                default:
1019
 
                        error(ap->logopt, "bad next state %d", next_state);
1020
 
                }
1021
 
        }
1022
 
 
1023
 
        return ret;
1024
 
}
1025
 
 
1026
 
static void st_set_thid(struct autofs_point *ap, pthread_t thid)
1027
 
{
1028
 
        struct list_head *p, *head = &state_queue;
1029
 
        struct state_queue *task;
1030
 
 
1031
 
        list_for_each(p, head) {
1032
 
                task = list_entry(p, struct state_queue, list);
1033
 
                if (task->ap == ap) {
1034
 
                        task->thid = thid;
1035
 
                        break;
1036
 
                }
1037
 
        }
1038
 
        return;
1039
 
}
1040
 
 
1041
 
/* Requires state mutex to be held */
1042
 
static void st_set_done(struct autofs_point *ap)
1043
 
{
1044
 
        struct list_head *p, *head;
1045
 
        struct state_queue *task;
1046
 
 
1047
 
        head = &state_queue;
1048
 
        list_for_each(p, head) {
1049
 
                task = list_entry(p, struct state_queue, list);
1050
 
                if (task->ap == ap) {
1051
 
                        task->done = 1;
1052
 
                        break;
1053
 
                }
1054
 
        }
1055
 
 
1056
 
        return;
1057
 
}
1058
 
 
1059
 
static void *st_queue_handler(void *arg)
1060
 
{
1061
 
        struct list_head *head;
1062
 
        struct list_head *p;
1063
 
        struct timespec wait;
1064
 
        struct timeval now;
1065
 
        int status, ret;
1066
 
 
1067
 
        st_mutex_lock();
1068
 
 
1069
 
        while (1) {
1070
 
                /*
1071
 
                 * If the state queue list is empty, wait until an
1072
 
                 * entry is added.
1073
 
                 */
1074
 
                head = &state_queue;
1075
 
                gettimeofday(&now, NULL);
1076
 
                wait.tv_sec = now.tv_sec + 1;
1077
 
                wait.tv_nsec = now.tv_usec * 1000;
1078
 
 
1079
 
                while (list_empty(head)) {
1080
 
                        status = pthread_cond_timedwait(&cond, &mutex, &wait);
1081
 
                        if (status) {
1082
 
                                if (status == ETIMEDOUT)
1083
 
                                        break;
1084
 
                                fatal(status);
1085
 
                        }
1086
 
                }
1087
 
 
1088
 
                p = head->next;
1089
 
                while(p != head) {
1090
 
                        struct state_queue *task;
1091
 
 
1092
 
                        task = list_entry(p, struct state_queue, list);
1093
 
                        p = p->next;
1094
 
 
1095
 
                        if (task->cancel) {
1096
 
                                list_del(&task->list);
1097
 
                                free(task);
1098
 
                                continue;
1099
 
                        }
1100
 
 
1101
 
                        task->busy = 1;
1102
 
 
1103
 
                        ret = run_state_task(task);
1104
 
                        if (!ret) {
1105
 
                                list_del(&task->list);
1106
 
                                free(task);
1107
 
                        }
1108
 
                }
1109
 
 
1110
 
                while (1) {
1111
 
                        gettimeofday(&now, NULL);
1112
 
                        wait.tv_sec = now.tv_sec + 1;
1113
 
                        wait.tv_nsec = now.tv_usec * 1000;
1114
 
 
1115
 
                        signaled = 0;
1116
 
                        while (!signaled) {
1117
 
                                status = pthread_cond_timedwait(&cond, &mutex, &wait);
1118
 
                                if (status) {
1119
 
                                        if (status == ETIMEDOUT)
1120
 
                                                break;
1121
 
                                        fatal(status);
1122
 
                                }
1123
 
                        }
1124
 
 
1125
 
                        head = &state_queue;
1126
 
                        p = head->next;
1127
 
                        while (p != head) {
1128
 
                                struct state_queue *task, *next;
1129
 
 
1130
 
                                task = list_entry(p, struct state_queue, list);
1131
 
                                p = p->next;
1132
 
 
1133
 
                                if (!task->busy) {
1134
 
                                        /* Start a new task */
1135
 
                                        task->busy = 1;
1136
 
 
1137
 
                                        ret = run_state_task(task);
1138
 
                                        if (!ret)
1139
 
                                                goto remove;
1140
 
                                        continue;
1141
 
                                }
1142
 
 
1143
 
                                /* Still starting up */
1144
 
                                if (!task->thid)
1145
 
                                        continue;
1146
 
 
1147
 
                                if (task->cancel) {
1148
 
                                        pthread_cancel(task->thid);
1149
 
                                        task->cancel = 0;
1150
 
                                        continue;
1151
 
                                }
1152
 
 
1153
 
                                /* Still busy */
1154
 
                                if (!task->done)
1155
 
                                        continue;
1156
 
 
1157
 
remove:
1158
 
                                /* No more tasks for this queue */
1159
 
                                if (list_empty(&task->pending)) {
1160
 
                                        list_del(&task->list);
1161
 
                                        free(task);
1162
 
                                        continue;
1163
 
                                }
1164
 
 
1165
 
                                /* Next task */
1166
 
                                next = list_entry((&task->pending)->next,
1167
 
                                                        struct state_queue, pending);
1168
 
 
1169
 
                                list_del_init(&next->pending);
1170
 
                                list_add_tail(&next->list, p);
1171
 
 
1172
 
                                list_del(&task->list);
1173
 
                                free(task);
1174
 
                        }
1175
 
 
1176
 
                        if (list_empty(head))
1177
 
                                break;
1178
 
                }
1179
 
        }
1180
 
}
1181
 
 
1182
 
int st_start_handler(void)
1183
 
{
1184
 
        pthread_t thid;
1185
 
        pthread_attr_t attrs;
1186
 
        pthread_attr_t *pattrs = &attrs;
1187
 
        int status;
1188
 
 
1189
 
        status = pthread_attr_init(pattrs);
1190
 
        if (status)
1191
 
                pattrs = NULL;
1192
 
        else {
1193
 
                pthread_attr_setdetachstate(pattrs, PTHREAD_CREATE_DETACHED);
1194
 
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
1195
 
                pthread_attr_setstacksize(pattrs, PTHREAD_STACK_MIN*4);
1196
 
#endif
1197
 
        }
1198
 
 
1199
 
        status = pthread_create(&thid, pattrs, st_queue_handler, NULL);
1200
 
 
1201
 
        pthread_attr_destroy(pattrs);
1202
 
 
1203
 
        return !status;
1204
 
}
1205