Merge lp://staging/~ion/ubuntu/lucid/mountall/parallel-checks into lp://staging/ubuntu/lucid/mountall

Proposed by Johan Kiviniemi
Status: Merged
Merged at revision: not available
Proposed branch: lp://staging/~ion/ubuntu/lucid/mountall/parallel-checks
Merge into: lp://staging/ubuntu/lucid/mountall
Diff against target: 451 lines (+183/-145)
3 files modified
debian/changelog (+7/-0)
src/ioprio.h (+26/-0)
src/mountall.c (+150/-145)
To merge this branch: bzr merge lp://staging/~ion/ubuntu/lucid/mountall/parallel-checks
Reviewer Review Type Date Requested Status
Scott James Remnant (Canonical) Pending
Review via email: mp+15555@code.staging.launchpad.net
To post a comment you must log in.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'debian/changelog'
2--- debian/changelog 2009-11-29 20:16:17 +0000
3+++ debian/changelog 2009-12-02 14:30:25 +0000
4@@ -1,3 +1,10 @@
5+mountall (1.2~) UNRELEASED; urgency=low
6+
7+ * Start all fsck instances in parallel, but set their priorities so that
8+ thrashing is avoided (LP: #491389).
9+
10+ -- Johan Kiviniemi <debian@johan.kiviniemi.name> Wed, 14 Oct 2009 00:58:21 +0300
11+
12 mountall (1.1) lucid; urgency=low
13
14 * Update to use external libnih.
15
16=== added file 'src/ioprio.h'
17--- src/ioprio.h 1970-01-01 00:00:00 +0000
18+++ src/ioprio.h 2009-12-02 14:30:25 +0000
19@@ -0,0 +1,26 @@
20+#include <sys/syscall.h>
21+
22+enum {
23+ IOPRIO_CLASS_NONE,
24+ IOPRIO_CLASS_RT,
25+ IOPRIO_CLASS_BE,
26+ IOPRIO_CLASS_IDLE,
27+};
28+
29+enum {
30+ IOPRIO_WHO_PROCESS = 1,
31+ IOPRIO_WHO_PGRP,
32+ IOPRIO_WHO_USER,
33+};
34+
35+#define IOPRIO_CLASS_SHIFT 13
36+
37+#define IOPRIO_PRIO_VALUE(klass, data) \
38+ (((klass) << IOPRIO_CLASS_SHIFT) | (data))
39+
40+#define IOPRIO_NORM 4
41+
42+static inline int
43+ioprio_set (int which, int who, int ioprio) {
44+ return syscall (__NR_ioprio_set, which, who, ioprio);
45+}
46
47=== modified file 'src/mountall.c'
48--- src/mountall.c 2009-10-26 09:07:31 +0000
49+++ src/mountall.c 2009-12-02 14:30:25 +0000
50@@ -69,6 +69,8 @@
51 #include <nih-dbus/dbus_proxy.h>
52 #include <nih-dbus/errors.h>
53
54+#include "ioprio.h"
55+
56 #include "dbus/upstart.h"
57 #include "com.ubuntu.Upstart.h"
58 #include "com.ubuntu.Upstart.Job.h"
59@@ -185,11 +187,7 @@
60 void run_swapon (Mount *mnt);
61 void run_swapon_finished (Mount *mnt, pid_t pid, int status);
62
63-int fsck_lock (Mount *mnt);
64-void fsck_unlock (Mount *mnt);
65-void queue_fsck (Mount *mnt);
66-void run_fsck_queue (void);
67-int run_fsck (Mount *mnt);
68+void run_fsck (Mount *mnt);
69 void run_fsck_finished (Mount *mnt, pid_t pid, int status);
70
71 void write_mtab (void);
72@@ -328,24 +326,6 @@
73 size_t num_filesystems = 0;
74
75 /**
76- * fsck_queue:
77- *
78- * Rather than check filesystems immediately, we lock out devices so that
79- * we only thrash any given disk once at a time. This list holds the queue
80- * of mounts to be checked, each entry is an NihListEntry with the data item
81- * pointing to the Mount.
82- **/
83-NihList *fsck_queue = NULL;
84-
85-/**
86- * fsck_locks:
87- *
88- * This is the hash table of held fsck device locks, each entry is an
89- * NihListEntry with the device id in the str member.
90- **/
91-NihHash *fsck_locks = NULL;
92-
93-/**
94 * procs:
95 *
96 * List of processes we're currently waiting to complete, each entry in
97@@ -354,6 +334,16 @@
98 NihList *procs = NULL;
99
100 /**
101+ * checks:
102+ *
103+ * List of active fsck instances, sorted by the priority (highest priority
104+ * first).
105+ *
106+ * Each entry is a NihListEntry with a Mount object as the data member.
107+ **/
108+NihList *checks = NULL;
109+
110+/**
111 * written_mtab:
112 *
113 * TRUE once we've successfully written /etc/mtab.
114@@ -1109,6 +1099,17 @@
115 }
116 }
117
118+static int
119+mount_priority (Mount *mnt)
120+{
121+ nih_assert (mnt != NULL);
122+
123+ if (mnt->tag > TAG_OTHER)
124+ return 1;
125+
126+ return 0;
127+}
128+
129 void
130 mount_policy (void)
131 {
132@@ -1518,7 +1519,7 @@
133 * swapon or mount as appropriate.
134 */
135 if (! mnt->ready) {
136- queue_fsck (mnt);
137+ run_fsck (mnt);
138 } else if (is_swap (mnt)) {
139 mount_event (mnt);
140 run_swapon (mnt);
141@@ -1562,6 +1563,9 @@
142 } else if (! pid) {
143 nih_local char *msg = NULL;
144
145+ if (setpgid (0, 0) < 0)
146+ nih_warn ("setpgid: %s", strerror (errno));
147+
148 for (char * const *arg = args; arg && *arg; arg++)
149 NIH_MUST (nih_strcat_sprintf (&msg, NULL, msg ? " %s" : "%s", *arg));
150
151@@ -2057,63 +2061,124 @@
152 }
153 }
154
155-/* Returns: TRUE if the devices were successfully locked; FALSE if something
156- * else had already locked one or more of them.
157- */
158-int
159-fsck_lock (Mount *mnt)
160-{
161- nih_assert (mnt != NULL);
162-
163- update_physical_dev_ids (mnt);
164-
165- NIH_HASH_FOREACH (mnt->physical_dev_ids, iter) {
166- char *dev_id = ((NihListEntry *)iter)->str;
167-
168- if (nih_hash_lookup (fsck_locks, dev_id))
169- return FALSE;
170- }
171-
172- NIH_HASH_FOREACH (mnt->physical_dev_ids, iter) {
173- char * dev_id = ((NihListEntry *)iter)->str;
174- NihListEntry *entry;
175-
176- entry = NIH_MUST (nih_list_entry_new (fsck_locks));
177- entry->str = NIH_MUST (nih_strdup (entry, dev_id));
178-
179- nih_hash_add (fsck_locks, &entry->entry);
180-
181- nih_debug ("%s: lock dev_id %s", mnt->mountpoint, dev_id);
182- }
183-
184- return TRUE;
185-}
186-
187-void
188-fsck_unlock (Mount *mnt)
189-{
190- nih_assert (mnt != NULL);
191-
192- if (! mnt->physical_dev_ids)
193- return;
194-
195- NIH_HASH_FOREACH (mnt->physical_dev_ids, iter) {
196- char * dev_id = ((NihListEntry *)iter)->str;
197- NihListEntry *entry;
198-
199- entry = (NihListEntry *)nih_hash_lookup (fsck_locks, dev_id);
200- nih_assert (entry != NULL);
201-
202- nih_free (entry);
203-
204- nih_debug ("%s: unlock dev_id %s", mnt->mountpoint, dev_id);
205- }
206-}
207-
208-void
209-queue_fsck (Mount *mnt)
210+static void
211+checks_update_priorities (void)
212+{
213+ nih_local NihHash *locks = NULL;
214+
215+ int ioprio_normal,
216+ ioprio_low;
217+
218+ ioprio_normal = IOPRIO_PRIO_VALUE (IOPRIO_CLASS_BE, IOPRIO_NORM);
219+ ioprio_low = IOPRIO_PRIO_VALUE (IOPRIO_CLASS_IDLE, 7);
220+
221+ locks = NIH_MUST (nih_hash_string_new (NULL, 10));
222+
223+ nih_debug ("updating check priorities");
224+
225+ NIH_LIST_FOREACH (checks, iter) {
226+ Mount *mnt = ((NihListEntry *)iter)->data;
227+ int low_prio = FALSE;
228+
229+ update_physical_dev_ids (mnt);
230+
231+ /* Set low_prio if something else has already locked one of the
232+ * dev_ids.
233+ */
234+ NIH_HASH_FOREACH (mnt->physical_dev_ids, diter) {
235+ char *dev_id = ((NihListEntry *)diter)->str;
236+
237+ if (nih_hash_lookup (locks, dev_id)) {
238+ low_prio = TRUE;
239+ break;
240+ }
241+ }
242+
243+ if (! low_prio) {
244+ /* Lock the dev_ids. */
245+ NIH_HASH_FOREACH (mnt->physical_dev_ids, diter) {
246+ char * dev_id;
247+ NihListEntry *entry;
248+
249+ dev_id = ((NihListEntry *)diter)->str;
250+
251+ entry = NIH_MUST (nih_list_entry_new (locks));
252+ entry->str = dev_id;
253+ nih_ref (entry->str, entry);
254+
255+ nih_hash_add (locks, &entry->entry);
256+ }
257+ }
258+
259+ nih_debug ("%s: priority %s",
260+ mnt->mountpoint, low_prio ? "low" : "normal");
261+
262+ if (setpriority (PRIO_PGRP, mnt->fsck_pid,
263+ low_prio ? 19 : 0) < 0)
264+ nih_warn ("setpriority %d: %s",
265+ mnt->fsck_pid, strerror (errno));
266+
267+ if (ioprio_set (IOPRIO_WHO_PGRP, mnt->fsck_pid,
268+ low_prio ? ioprio_low : ioprio_normal) < 0)
269+ nih_warn ("ioprio_set %d: %s",
270+ mnt->fsck_pid, strerror (errno));
271+ }
272+}
273+
274+static void
275+checks_add (Mount *mnt)
276 {
277 NihListEntry *entry;
278+ NihList * add_before;
279+ int mnt_prio;
280+
281+ nih_assert (mnt != NULL);
282+
283+ /* Find the first item that has a lower priority than mnt and add mnt
284+ * immediately before it, or at the end of the list if no such item was
285+ * found.
286+ */
287+
288+ mnt_prio = mount_priority (mnt);
289+
290+ add_before = checks;
291+
292+ NIH_LIST_FOREACH (checks, iter) {
293+ Mount *imnt = ((NihListEntry *)iter)->data;
294+
295+ if (mount_priority (imnt) < mnt_prio) {
296+ add_before = &((NihListEntry *)iter)->entry;
297+ break;
298+ }
299+ }
300+
301+ entry = NIH_MUST (nih_list_entry_new (checks));
302+ entry->data = mnt;
303+
304+ nih_list_add (add_before, &entry->entry);
305+
306+ checks_update_priorities ();
307+}
308+
309+static void
310+checks_remove (Mount *mnt)
311+{
312+ nih_assert (mnt != NULL);
313+
314+ NIH_LIST_FOREACH_SAFE (checks, iter)
315+ if (((NihListEntry *)iter)->data == mnt)
316+ nih_free (iter);
317+
318+ checks_update_priorities ();
319+}
320+
321+void
322+run_fsck (Mount *mnt)
323+{
324+ nih_local char **args = NULL;
325+ size_t args_len = 0;
326+ int fds[2];
327+ int flags;
328
329 nih_assert (mnt != NULL);
330
331@@ -2151,64 +2216,6 @@
332 return;
333 }
334
335- NIH_LIST_FOREACH (fsck_queue, iter) {
336- NihListEntry *entry = (NihListEntry *)iter;
337- Mount * qmnt = (Mount *)entry->data;
338-
339- if (mnt != qmnt)
340- continue;
341-
342- nih_debug ("%s: check already queued",
343- is_swap (mnt) ? mnt->device : mnt->mountpoint);
344- return;
345- }
346-
347- entry = NIH_MUST (nih_list_entry_new (fsck_queue));
348- entry->data = mnt;
349- nih_list_add (fsck_queue, &entry->entry);
350-
351- nih_debug ("%s: queuing check",
352- is_swap (mnt) ? mnt->device : mnt->mountpoint);
353-
354- run_fsck_queue ();
355-}
356-
357-void
358-run_fsck_queue (void)
359-{
360- NIH_LIST_FOREACH_SAFE (fsck_queue, iter) {
361- NihListEntry *entry = (NihListEntry *)iter;
362- Mount * mnt = (Mount *)entry->data;
363-
364- if (run_fsck (mnt)) {
365- nih_free (entry);
366- nih_debug ("%s: dequeuing check",
367- is_swap (mnt) ? mnt->device : mnt->mountpoint);
368- }
369- }
370-}
371-
372-/* Returns: TRUE if the check can be dequeued, FALSE if it should be retried
373- * later.
374- */
375-int
376-run_fsck (Mount *mnt)
377-{
378- nih_local char **args = NULL;
379- size_t args_len = 0;
380- int fds[2];
381- int flags;
382-
383- nih_assert (mnt != NULL);
384- nih_assert (mnt->device != NULL);
385- nih_assert (mnt->type != NULL);
386-
387- if (! fsck_lock (mnt))
388- /* Another instance has already locked one or more of the
389- * physical devices.
390- */
391- return FALSE;
392-
393 nih_info ("checking %s", mnt->mountpoint);
394
395 /* Create a pipe to receive progress indication */
396@@ -2247,14 +2254,14 @@
397 mnt->fsck_progress = -1;
398 mnt->fsck_pid = spawn (mnt, args, FALSE, run_fsck_finished);
399
400+ checks_add (mnt);
401+
402 /* Close writing end, reading end is left open inside the NihIo
403 * structure watching it until the remote end is closed by fsck
404 * finishing.
405 */
406 if (fds[1] >= 0)
407 close (fds[1]);
408-
409- return TRUE;
410 }
411
412 void
413@@ -2265,6 +2272,8 @@
414 nih_assert (mnt != NULL);
415 nih_assert (mnt->fsck_pid == pid);
416
417+ checks_remove (mnt);
418+
419 mnt->fsck_pid = -1;
420 mnt->fsck_progress = -1;
421
422@@ -2299,9 +2308,6 @@
423 mnt->mountpoint);
424 }
425
426- fsck_unlock (mnt);
427- run_fsck_queue ();
428-
429 mnt->ready = TRUE;
430 try_mount (mnt, FALSE);
431 }
432@@ -2620,7 +2626,7 @@
433
434 mnt->physical_dev_ids_needed = TRUE;
435
436- queue_fsck (mnt);
437+ run_fsck (mnt);
438 }
439 }
440
441@@ -3566,9 +3572,8 @@
442 track_usplash ();
443
444 mounts = NIH_MUST (nih_list_new (NULL));
445- fsck_queue = NIH_MUST (nih_list_new (NULL));
446- fsck_locks = NIH_MUST (nih_hash_string_new (NULL, 10));
447 procs = NIH_MUST (nih_list_new (NULL));
448+ checks = NIH_MUST (nih_list_new (NULL));
449
450 /* Parse /proc/filesystems to find out which filesystems don't
451 * have devices.

Subscribers

People subscribed via source and target branches

to all changes: