1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
|
/* Support for periodic syncing
Copyright (C) 1995,96,99,2002 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.org>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2, or (at
your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
#include <errno.h>
#include <cthreads.h>
#include <unistd.h>
#include <hurd/fsys.h>
#include "priv.h"
/* A user-readable variable reflecting the last set sync interval. */
int diskfs_sync_interval = 0;
/* The thread that's doing the syncing. */
static cthread_t periodic_sync_thread;
/* This port represents the periodic sync service as if it were
an RPC. We can use ports_inhibit_port_rpcs on this port to guarantee
that the periodic_sync_thread is quiescent. */
static struct port_info *pi;
static void periodic_sync ();
/* Establish a thread to sync the filesystem every INTERVAL seconds, or
never, if INTERVAL is zero. If an error occurs creating the thread, it is
returned, otherwise 0. Subsequent calls will create a new thread and
(eventually) get rid of the old one; the old thread won't do any more
syncs, regardless. */
error_t
diskfs_set_sync_interval (int interval)
{
error_t err = 0;
if (! pi)
{
err = ports_create_port (diskfs_control_class, diskfs_port_bucket,
sizeof (struct port_info), &pi);
if (err)
return err;
}
err = ports_inhibit_port_rpcs (pi);
if (err)
return err;
/* Here we just set the new thread; any existing thread will notice when it
wakes up and go away silently. */
if (interval == 0)
periodic_sync_thread = 0;
else
{
periodic_sync_thread =
cthread_fork ((cthread_fn_t)periodic_sync, (any_t)(intptr_t)interval);
if (periodic_sync_thread)
cthread_detach (periodic_sync_thread);
else
err = ENOMEM;
}
if (!err)
diskfs_sync_interval = interval;
ports_resume_port_rpcs (pi);
return err;
}
/* ---------------------------------------------------------------- */
/* Sync the filesystem (pointed to by the variable CONTROL_PORT above) every
INTERVAL seconds, as long as it's in the thread pointed to by the global
variable PERIODIC_SYNC_THREAD. */
static void
periodic_sync (int interval)
{
for (;;)
{
error_t err;
struct rpc_info link;
/* This acts as a lock against creation of a new sync thread
while we are in the process of syncing. */
err = ports_begin_rpc (pi, 0, &link);
if (periodic_sync_thread != cthread_self ())
{
/* We've been superseded as the sync thread. Just die silently. */
ports_end_rpc (pi, &link);
return;
}
if (! err)
{
if (! diskfs_readonly)
{
rwlock_reader_lock (&diskfs_fsys_lock);
/* Only sync if we need to, to avoid clearing the clean flag
when it's just been set. Any other thread doing a sync
will have held the lock while it did its work. */
if (_diskfs_diskdirty)
{
diskfs_sync_everything (0);
diskfs_set_hypermetadata (0, 0);
}
rwlock_reader_unlock (&diskfs_fsys_lock);
}
ports_end_rpc (pi, &link);
}
/* Wait until next time. */
sleep (interval);
}
}
|