blob: 8e79b3809ef63271fa5db44ba7a36b0ccb2ac41e [file] [log] [blame]
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001
2/*
3 * Copyright (C) 2008 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include <stdlib.h>
19#include <string.h>
20#include <errno.h>
21#include <dirent.h>
22#include <unistd.h>
23#include <sched.h>
24
25#include <sys/mount.h>
26
27#include <cutils/config_utils.h>
28#include <cutils/properties.h>
29
30#include "vold.h"
31#include "volmgr.h"
32#include "blkdev.h"
33#include "ums.h"
The Android Open Source Project13f797d2009-02-10 15:44:07 -080034#include "format.h"
35#include "devmapper.h"
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080036
37#include "volmgr_ext3.h"
38#include "volmgr_vfat.h"
39
40#define DEBUG_VOLMGR 0
41
The Android Open Source Project13f797d2009-02-10 15:44:07 -080042static volume_t *vol_root = NULL;
43static boolean safe_mode = true;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080044
45static struct volmgr_fstable_entry fs_table[] = {
The Android Open Source Project13f797d2009-02-10 15:44:07 -080046 { "ext3", ext_identify, ext_check, ext_mount , true },
47 { "vfat", vfat_identify, vfat_check, vfat_mount , false },
48 { NULL, NULL, NULL, NULL , false}
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080049};
50
51struct _volume_state_event_map {
52 volume_state_t state;
53 char *event;
54 char *property_val;
55};
56
57static struct _volume_state_event_map volume_state_strings[] = {
58 { volstate_unknown, "volstate_unknown:", "unknown" },
59 { volstate_nomedia, VOLD_EVT_NOMEDIA, VOLD_ES_PVAL_NOMEDIA },
60 { volstate_unmounted, VOLD_EVT_UNMOUNTED, VOLD_ES_PVAL_UNMOUNTED },
61 { volstate_checking, VOLD_EVT_CHECKING, VOLD_ES_PVAL_CHECKING },
62 { volstate_mounted, VOLD_EVT_MOUNTED, VOLD_ES_PVAL_MOUNTED },
63 { volstate_mounted_ro, VOLD_EVT_MOUNTED_RO, VOLD_ES_PVAL_MOUNTED_RO },
64 { volstate_badremoval, VOLD_EVT_BADREMOVAL, VOLD_ES_PVAL_BADREMOVAL },
65 { volstate_damaged, VOLD_EVT_DAMAGED, VOLD_ES_PVAL_DAMAGED },
66 { volstate_nofs, VOLD_EVT_NOFS, VOLD_ES_PVAL_NOFS },
67 { volstate_ums, VOLD_EVT_UMS, VOLD_ES_PVAL_UMS },
68 { 0, NULL, NULL }
69};
70
71
72static int volmgr_readconfig(char *cfg_path);
73static int volmgr_config_volume(cnode *node);
74static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy);
75static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev);
76static int _volmgr_start(volume_t *vol, blkdev_t *dev);
77static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev);
78static void *volmgr_start_fs_thread(void *arg);
79static void volmgr_start_fs_thread_sighandler(int signo);
80static void volume_setstate(volume_t *vol, volume_state_t state);
81static char *conv_volstate_to_eventstr(volume_state_t state);
82static char *conv_volstate_to_propstr(volume_state_t state);
83static int volume_send_state(volume_t *vol);
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -080084static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080085static int _volmgr_enable_ums(volume_t *);
The Android Open Source Project13f797d2009-02-10 15:44:07 -080086static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *arg), boolean emit_statechange);
87static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080088static void _cb_volume_stopped_for_eject(volume_t *v, void *arg);
89static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg);
90static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev);
The Android Open Source Project13f797d2009-02-10 15:44:07 -080091static void volmgr_uncage_reaper(volume_t *vol, void (* cb) (volume_t *, void *arg), void *arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -080092static void volmgr_reaper_thread_sighandler(int signo);
The Android Open Source Project13f797d2009-02-10 15:44:07 -080093static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path);
94static int volmgr_send_eject_request(volume_t *v);
95static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked);
96
97static boolean _mountpoint_mounted(char *mp)
98{
99 char device[256];
100 char mount_path[256];
101 char rest[256];
102 FILE *fp;
103 char line[1024];
104
105 if (!(fp = fopen("/proc/mounts", "r"))) {
106 LOGE("Error opening /proc/mounts (%s)\n", strerror(errno));
107 return false;
108 }
109
110 while(fgets(line, sizeof(line), fp)) {
111 line[strlen(line)-1] = '\0';
112 sscanf(line, "%255s %255s %255s\n", device, mount_path, rest);
113 if (!strcmp(mount_path, mp)) {
114 fclose(fp);
115 return true;
116 }
117
118 }
119
120 fclose(fp);
121 return false;
122}
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800123
124/*
125 * Public functions
126 */
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800127
128int volmgr_set_volume_key(char *mount_point, unsigned char *key, unsigned int keysize)
129{
130 volume_t *v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
131
132 if (!v)
133 return -ENOENT;
134
135 if (v->key)
136 free(v->key);
137
138 if (!(v->key = malloc(keysize))) {
139 pthread_mutex_unlock(&v->lock);
140 return -ENOMEM;
141 }
142
143 memcpy(v->key, key, keysize);
144 pthread_mutex_unlock(&v->lock);
145 return 0;
146}
147
148int volmgr_format_volume(char *mount_point)
149{
150 int rc;
151 volume_t *v;
152
153 LOG_VOL("volmgr_format_volume(%s):\n", mount_point);
154
155 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
156
157 if (!v)
158 return -ENOENT;
159
160
161 if (v->state == volstate_mounted ||
162 v->state == volstate_mounted_ro ||
163 v->state == volstate_ums ||
164 v->state == volstate_checking) {
165 LOGE("Can't format '%s', currently in state %d\n", mount_point, v->state);
166 pthread_mutex_unlock(&v->lock);
167 return -EBUSY;
168 } else if (v->state == volstate_nomedia) {
169 LOGE("Can't format '%s', (no media)\n", mount_point);
170 pthread_mutex_unlock(&v->lock);
171 return -ENOMEDIUM;
172 }
173
174 if ((rc = initialize_mbr(v->dev->disk)) < 0) {
175 LOGE("MBR init failed for %s (%d)\n", mount_point, rc);
176 pthread_mutex_unlock(&v->lock);
177 return rc;
178 }
179
180 volume_setstate(v, volstate_formatting);
181 pthread_mutex_unlock(&v->lock);
182 return rc;
183}
184
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800185int volmgr_bootstrap(void)
186{
187 int rc;
188
189 if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) {
190 LOGE("Unable to process config\n");
191 return rc;
192 }
193
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800194 /*
195 * Check to see if any of our volumes is mounted
196 */
197 volume_t *v = vol_root;
198 while (v) {
199 if (_mountpoint_mounted(v->mount_point)) {
200 LOG_VOL("Volume '%s' already mounted at startup\n", v->mount_point);
201 v->state = volstate_mounted;
202 }
203 v = v->next;
204 }
205
206 return 0;
207}
208
209int volmgr_safe_mode(boolean enable)
210{
211 if (enable == safe_mode)
212 return 0;
213
214 safe_mode = enable;
215
216 volume_t *v = vol_root;
217 int rc;
218
219 while (v) {
220 pthread_mutex_lock(&v->lock);
221 if (v->state == volstate_mounted && v->fs) {
222 rc = v->fs->mount_fn(v->dev, v, safe_mode);
223 if (!rc) {
224 LOG_VOL("Safe mode %s on %s\n", (enable ? "enabled" : "disabled"), v->mount_point);
225 } else {
226 LOGE("Failed to %s safe-mode on %s (%s)\n",
227 (enable ? "enable" : "disable" ), v->mount_point, strerror(-rc));
228 }
229 }
230
231 pthread_mutex_unlock(&v->lock);
232 v = v->next;
233 }
234
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800235 return 0;
236}
237
238int volmgr_send_states(void)
239{
240 volume_t *vol_scan = vol_root;
241 int rc;
242
243 while (vol_scan) {
244 pthread_mutex_lock(&vol_scan->lock);
245 if ((rc = volume_send_state(vol_scan)) < 0) {
246 LOGE("Error sending state to framework (%d)\n", rc);
247 }
248 pthread_mutex_unlock(&vol_scan->lock);
249 vol_scan = vol_scan->next;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800250 break; // XXX:
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800251 }
252
253 return 0;
254}
255
256/*
257 * Called when a block device is ready to be
258 * evaluated by the volume manager.
259 */
260int volmgr_consider_disk(blkdev_t *dev)
261{
262 volume_t *vol;
263
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800264 if (!(vol = volmgr_lookup_volume_by_mediapath(dev->media->devpath, true)))
265 return 0;
266
267 pthread_mutex_lock(&vol->lock);
268
269 if (vol->state == volstate_mounted) {
270 LOGE("Volume %s already mounted (did we just crash?)\n", vol->mount_point);
271 pthread_mutex_unlock(&vol->lock);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800272 return 0;
273 }
274
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800275 int rc = _volmgr_consider_disk_and_vol(vol, dev);
276 pthread_mutex_unlock(&vol->lock);
277 return rc;
278}
279
280int volmgr_start_volume_by_mountpoint(char *mount_point)
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800281{
282 volume_t *v;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800283
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800284LOG_VOL("volmgr_start_volume_by_mountpoint(%s):", mount_point);
285 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
286 if (!v)
287 return -ENOENT;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800288
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800289LOG_VOL("volmgr_start_volume_by_mountpoint(%s): got %p", mount_point, v);
290 if (v->media_type == media_devmapper) {
291 if (devmapper_start(v->dm) < 0) {
292 LOGE("volmgr failed to start devmapper volume '%s'\n",
293 v->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800294 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800295 } else if (v->media_type == media_mmc) {
296 if (!v->dev) {
297 LOGE("Cannot start volume '%s' (volume is not bound)\n", mount_point);
298 pthread_mutex_unlock(&v->lock);
299 return -ENOENT;
300 }
301
302 if (_volmgr_consider_disk_and_vol(v, v->dev->disk) < 0) {
303 LOGE("volmgr failed to start volume '%s'\n", v->mount_point);
304 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800305 }
306
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800307 pthread_mutex_unlock(&v->lock);
308 return 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800309}
310
311int volmgr_stop_volume_by_mountpoint(char *mount_point)
312{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800313 int rc;
314 volume_t *v;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800315
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800316 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
317 if (!v)
318 return -ENOENT;
319
320 if (v->state == volstate_mounted)
321 volmgr_send_eject_request(v);
322
323 rc = volmgr_shutdown_volume(v, NULL, true);
324
325 /*
326 * If shutdown returns -EINPROGRESS,
327 * do *not* release the lock as
328 * it is now owned by the reaper thread
329 */
330 if (rc != -EINPROGRESS) {
331 if (rc)
332 LOGE("unable to shutdown volume '%s'\n", v->mount_point);
333 pthread_mutex_unlock(&v->lock);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800334 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800335 return 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800336}
337
338int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *))
339{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800340 LOG_VOL("Volmgr notified of %d:%d eject\n", dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800341
342 volume_t *v;
343
344 // XXX: Partitioning support is going to need us to stop *all*
345 // devices in this volume
346 if (!(v = volmgr_lookup_volume_by_dev(dev))) {
347 if (cb)
348 cb(dev);
349 return 0;
350 }
351
352 pthread_mutex_lock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800353
354 volume_state_t old_state = v->state;
355
356 if (v->state == volstate_mounted ||
357 v->state == volstate_ums ||
358 v->state == volstate_checking)
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800359 volume_setstate(v, volstate_badremoval);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800360 else if (v->state == volstate_formatting) {
361 /*
362 * The device is being ejected due to
363 * kernel disk revalidation.
364 */
365 LOG_VOL("Volmgr ignoring eject of %d:%d (volume formatting)\n",
366 dev->major, dev->minor);
367 if (cb)
368 cb(dev);
369 pthread_mutex_unlock(&v->lock);
370 return 0;
371 } else
372 volume_setstate(v, volstate_nomedia);
373
374 if (old_state == volstate_ums) {
375 ums_disable(v->ums_path);
376 pthread_mutex_unlock(&v->lock);
377 } else {
378 int rc = volmgr_stop_volume(v, _cb_volume_stopped_for_eject, cb, false);
379 if (rc != -EINPROGRESS) {
380 if (rc)
381 LOGE("unable to shutdown volume '%s'\n", v->mount_point);
382 pthread_mutex_unlock(&v->lock);
383 }
384 }
385 return 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800386}
387
388static void _cb_volume_stopped_for_eject(volume_t *v, void *arg)
389{
390 void (* eject_cb) (blkdev_t *) = arg;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800391
392#if DEBUG_VOLMGR
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800393 LOG_VOL("Volume %s has been stopped for eject\n", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800394#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800395
396 eject_cb(v->dev);
397 v->dev = NULL; // Clear dev because its being ejected
398}
399
400/*
401 * Instructs the volume manager to enable or disable USB mass storage
402 * on any volumes configured to use it.
403 */
404int volmgr_enable_ums(boolean enable)
405{
406 volume_t *v = vol_root;
407
408 while(v) {
409 if (v->ums_path) {
410 int rc;
411
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800412 if (enable) {
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800413 pthread_mutex_lock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800414 if (v->state == volstate_mounted)
415 volmgr_send_eject_request(v);
416 else if (v->state == volstate_ums) {
417 pthread_mutex_unlock(&v->lock);
418 goto next_vol;
419 }
420
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800421 // Stop the volume, and enable UMS in the callback
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800422 rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable, false);
423 if (rc != -EINPROGRESS) {
424 if (rc)
425 LOGE("unable to shutdown volume '%s'\n", v->mount_point);
426 pthread_mutex_unlock(&v->lock);
427 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800428 } else {
429 // Disable UMS
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800430 pthread_mutex_lock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800431 if (v->state != volstate_ums) {
432 pthread_mutex_unlock(&v->lock);
433 goto next_vol;
434 }
435
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800436 if ((rc = ums_disable(v->ums_path)) < 0) {
437 LOGE("unable to disable ums on '%s'\n", v->mount_point);
438 pthread_mutex_unlock(&v->lock);
439 continue;
440 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800441
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800442 LOG_VOL("Kick-starting volume %d:%d after UMS disable\n",
443 v->dev->disk->major, v->dev->disk->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800444 // Start volume
445 if ((rc = _volmgr_consider_disk_and_vol(v, v->dev->disk)) < 0) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800446 LOGE("volmgr failed to consider disk %d:%d\n",
447 v->dev->disk->major, v->dev->disk->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800448 }
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800449 pthread_mutex_unlock(&v->lock);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800450 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800451 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800452 next_vol:
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800453 v = v->next;
454 }
455 return 0;
456}
457
458/*
459 * Static functions
460 */
461
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800462static int volmgr_send_eject_request(volume_t *v)
463{
464 return send_msg_with_data(VOLD_EVT_EJECTING, v->mount_point);
465}
466
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800467// vol->lock must be held!
468static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev)
469{
470 int rc = 0;
471
472#if DEBUG_VOLMGR
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800473 LOG_VOL("volmgr_consider_disk_and_vol(%s, %d:%d):\n", vol->mount_point,
474 dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800475#endif
476
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800477 if (vol->state == volstate_unknown ||
478 vol->state == volstate_mounted ||
479 vol->state == volstate_mounted_ro ||
480 vol->state == volstate_damaged) {
481 LOGE("Cannot consider volume '%s' because it is in state '%d\n",
482 vol->mount_point, vol->state);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800483 return -EADDRINUSE;
484 }
485
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800486 if (vol->state == volstate_formatting) {
487 LOG_VOL("Evaluating dev '%s' for formattable filesystems for '%s'\n",
488 dev->devpath, vol->mount_point);
489 /*
490 * Since we only support creating 1 partition (right now),
491 * we can just lookup the target by devno
492 */
493 blkdev_t *part = blkdev_lookup_by_devno(dev->major, 1);
494 if (!part) {
495 LOGE("Can't find partition to format!\n");
496 return -ENOENT;
497 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800498
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800499 if ((rc = format_partition(part)) < 0) {
500 LOGE("format failed (%d)\n", rc);
501 return rc;
502 }
503
504 }
505
506 LOG_VOL("Evaluating dev '%s' for mountable filesystems for '%s'\n",
507 dev->devpath, vol->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800508
509 if (dev->nr_parts == 0) {
510 rc = _volmgr_start(vol, dev);
511#if DEBUG_VOLMGR
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800512 LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d\n", vol->mount_point,
513 dev->major, dev->minor, rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800514#endif
515 } else {
516 /*
517 * Device has multiple partitions
518 * This is where interesting partition policies could be implemented.
519 * For now just try them in sequence until one succeeds
520 */
521
522 rc = -ENODEV;
523 int i;
524 for (i = 0; i < dev->nr_parts; i++) {
525 blkdev_t *part = blkdev_lookup_by_devno(dev->major, (i+1));
526 if (!part) {
527 LOGE("Error - unable to lookup partition for blkdev %d:%d\n", dev->major, (i+1));
528 continue;
529 }
530 rc = _volmgr_start(vol, part);
531#if DEBUG_VOLMGR
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800532 LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d\n",
533 vol->mount_point, part->major, part->minor, rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800534#endif
535 if (!rc)
536 break;
537 }
538
539 if (rc == -ENODEV) {
540 // Assert to make sure each partition had a backing blkdev
541 LOGE("Internal consistency error\n");
542 return 0;
543 }
544 }
545
546 if (rc == -ENODATA) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800547 LOGE("Device %d:%d contains no usable filesystems\n",
548 dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800549 rc = 0;
550 }
551
552 return rc;
553}
554
555static void volmgr_reaper_thread_sighandler(int signo)
556{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800557 LOGE("Volume reaper thread got signal %d\n", signo);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800558}
559
560static void __reaper_cleanup(void *arg)
561{
562 volume_t *vol = (volume_t *) arg;
563
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800564 if (vol->worker_args.reaper_args.cb)
565 vol->worker_args.reaper_args.cb(vol, vol->worker_args.reaper_args.cb_arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800566
567 vol->worker_running = false;
568
569 // Wake up anyone that was waiting on this thread
570 pthread_mutex_unlock(&vol->worker_sem);
571
572 // Unlock the volume
573 pthread_mutex_unlock(&vol->lock);
574}
575
576static void *volmgr_reaper_thread(void *arg)
577{
578 volume_t *vol = (volume_t *) arg;
579
580 pthread_cleanup_push(__reaper_cleanup, arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800581
582 vol->worker_running = true;
583 vol->worker_pid = getpid();
584
585 struct sigaction actions;
586
587 memset(&actions, 0, sizeof(actions));
588 sigemptyset(&actions.sa_mask);
589 actions.sa_flags = 0;
590 actions.sa_handler = volmgr_reaper_thread_sighandler;
591 sigaction(SIGUSR1, &actions, NULL);
592
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800593 LOG_VOL("Reaper here - working on %s\n", vol->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800594
595 boolean send_sig_kill = false;
596 int i, rc;
597
598 for (i = 0; i < 10; i++) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800599 errno = 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800600 rc = umount(vol->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800601 LOG_VOL("volmngr reaper umount(%s) attempt %d (%s)\n",
602 vol->mount_point, i + 1, strerror(errno));
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800603 if (!rc)
604 break;
605 if (rc && (errno == EINVAL || errno == ENOENT)) {
606 rc = 0;
607 break;
608 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800609 sleep(1);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800610 if (i >= 4) {
611 KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0);
612 if (!send_sig_kill)
613 send_sig_kill = true;
614 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800615 }
616
617 if (!rc) {
618 LOG_VOL("Reaper sucessfully unmounted %s\n", vol->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800619 vol->fs = NULL;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800620 volume_setstate(vol, volstate_unmounted);
621 } else {
622 LOGE("Unable to unmount!! (%d)\n", rc);
623 }
624
625 out:
626 pthread_cleanup_pop(1);
627 pthread_exit(NULL);
628 return NULL;
629}
630
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800631// vol->lock must be held!
632static void volmgr_uncage_reaper(volume_t *vol, void (* cb) (volume_t *, void *arg), void *arg)
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800633{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800634
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800635 if (vol->worker_running) {
636 LOGE("Worker thread is currently running.. waiting..\n");
637 pthread_mutex_lock(&vol->worker_sem);
638 LOG_VOL("Worker thread now available\n");
639 }
640
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800641 vol->worker_args.reaper_args.cb = cb;
642 vol->worker_args.reaper_args.cb_arg = arg;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800643
644 pthread_attr_t attr;
645 pthread_attr_init(&attr);
646 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
647
648 pthread_create(&vol->worker_thread, &attr, volmgr_reaper_thread, vol);
649}
650
651static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange)
652{
653 int i, rc;
654
655 if (v->state == volstate_mounted || v->state == volstate_badremoval) {
656 // Try to unmount right away (5 retries)
657 for (i = 0; i < 5; i++) {
658 rc = umount(v->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800659 if (!rc)
660 break;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800661
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800662 if (rc && (errno == EINVAL || errno == ENOENT)) {
663 rc = 0;
664 break;
665 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800666
667 LOG_VOL("volmngr quick stop umount(%s) attempt %d (%s)\n",
668 v->mount_point, i + 1, strerror(errno));
669
670 if (i == 0)
671 usleep(1000 * 250); // First failure, sleep for 250 ms
672 else
673 sched_yield();
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800674 }
675
676 if (!rc) {
677 LOG_VOL("volmgr_stop_volume(%s): Volume unmounted sucessfully\n",
678 v->mount_point);
679 if (emit_statechange)
680 volume_setstate(v, volstate_unmounted);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800681 v->fs = NULL;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800682 goto out_cb_immed;
683 }
684
685 /*
686 * Since the volume is still in use, dispatch the stopping to
687 * a thread
688 */
689 LOG_VOL("Volume %s is busy (%d) - uncaging the reaper\n", v->mount_point, rc);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800690 volmgr_uncage_reaper(v, cb, arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800691 return -EINPROGRESS;
692 } else if (v->state == volstate_checking) {
693 volume_setstate(v, volstate_unmounted);
694 if (v->worker_running) {
695 LOG_VOL("Cancelling worker thread\n");
696 pthread_kill(v->worker_thread, SIGUSR1);
697 } else
698 LOGE("Strange... we were in checking state but worker thread wasn't running..\n");
699 goto out_cb_immed;
700 }
701
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800702 out_cb_immed:
703 if (cb)
704 cb(v, arg);
705 return 0;
706}
707
708
709/*
710 * Gracefully stop a volume
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800711 * v->lock must be held!
712 * if we return -EINPROGRESS, do NOT release the lock as the reaper
713 * is using the volume
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800714 */
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800715static int volmgr_shutdown_volume(volume_t *v, void (* cb) (volume_t *, void *), boolean emit_statechange)
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800716{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800717 return volmgr_stop_volume(v, cb, NULL, emit_statechange);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800718}
719
720static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg)
721{
722 void (* shutdown_cb) (volume_t *) = arg;
723
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800724#if DEBUG_VOLMGR
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800725 LOG_VOL("Volume %s has been stopped for shutdown\n", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800726#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800727 shutdown_cb(v);
728}
729
730/*
731 * Called when a volume is sucessfully unmounted for UMS enable
732 */
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800733static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg)
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800734{
735 int rc;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800736 char *devdir_path;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800737
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800738#if DEBUG_VOLMGR
739 LOG_VOL("_cb_volstopped_for_ums_enable(%s):\n", v->mount_point);
740#endif
741 devdir_path = blkdev_get_devpath(v->dev->disk);
742
743 if ((rc = ums_enable(devdir_path, v->ums_path)) < 0) {
744 free(devdir_path);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800745 LOGE("Error enabling ums (%d)\n", rc);
746 return;
747 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800748 free(devdir_path);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800749 volume_setstate(v, volstate_ums);
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800750 pthread_mutex_unlock(&v->lock);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800751}
752
753static int volmgr_readconfig(char *cfg_path)
754{
755 cnode *root = config_node("", "");
756 cnode *node;
757
758 config_load_file(root, cfg_path);
759 node = root->first_child;
760
761 while (node) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800762 if (!strncmp(node->name, "volume_", 7))
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800763 volmgr_config_volume(node);
764 else
765 LOGE("Skipping unknown configuration node '%s'\n", node->name);
766 node = node->next;
767 }
768 return 0;
769}
770
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800771static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path)
772{
773 int i;
774
775#if DEBUG_VOLMGR
776 LOG_VOL("volmgr_add_mediapath_to_volume(%p, %s):\n", v, media_path);
777#endif
778 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
779 if (!v->media_paths[i]) {
780 v->media_paths[i] = strdup(media_path);
781 return;
782 }
783 }
784 LOGE("Unable to add media path '%s' to volume (out of media slots)\n", media_path);
785}
786
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800787static int volmgr_config_volume(cnode *node)
788{
789 volume_t *new;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800790 int rc = 0, i;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800791
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800792 char *dm_src, *dm_src_type, *dm_tgt, *dm_param, *dm_tgtfs;
793 uint32_t dm_size_mb = 0;
794
795 dm_src = dm_src_type = dm_tgt = dm_param = dm_tgtfs = NULL;
796#if DEBUG_VOLMGR
797 LOG_VOL("volmgr_configure_volume(%s):\n", node->name);
798#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800799 if (!(new = malloc(sizeof(volume_t))))
800 return -ENOMEM;
801 memset(new, 0, sizeof(volume_t));
802
803 new->state = volstate_nomedia;
804 pthread_mutex_init(&new->lock, NULL);
805 pthread_mutex_init(&new->worker_sem, NULL);
806
807 cnode *child = node->first_child;
808
809 while (child) {
810 if (!strcmp(child->name, "media_path"))
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800811 volmgr_add_mediapath_to_volume(new, child->value);
812 else if (!strcmp(child->name, "emu_media_path"))
813 volmgr_add_mediapath_to_volume(new, child->value);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800814 else if (!strcmp(child->name, "media_type")) {
815 if (!strcmp(child->value, "mmc"))
816 new->media_type = media_mmc;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800817 else if (!strcmp(child->value, "devmapper"))
818 new->media_type = media_devmapper;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800819 else {
820 LOGE("Invalid media type '%s'\n", child->value);
821 rc = -EINVAL;
822 goto out_free;
823 }
824 } else if (!strcmp(child->name, "mount_point"))
825 new->mount_point = strdup(child->value);
826 else if (!strcmp(child->name, "ums_path"))
827 new->ums_path = strdup(child->value);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800828 else if (!strcmp(child->name, "dm_src"))
829 dm_src = strdup(child->value);
830 else if (!strcmp(child->name, "dm_src_type"))
831 dm_src_type = strdup(child->value);
832 else if (!strcmp(child->name, "dm_src_size_mb"))
833 dm_size_mb = atoi(child->value);
834 else if (!strcmp(child->name, "dm_target"))
835 dm_tgt = strdup(child->value);
836 else if (!strcmp(child->name, "dm_target_params"))
837 dm_param = strdup(child->value);
838 else if (!strcmp(child->name, "dm_target_fs"))
839 dm_tgtfs = strdup(child->value);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800840 else
841 LOGE("Ignoring unknown config entry '%s'\n", child->name);
842 child = child->next;
843 }
844
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800845 if (new->media_type == media_mmc) {
846 if (!new->media_paths[0] || !new->mount_point || new->media_type == media_unknown) {
847 LOGE("Required configuration parameter missing for mmc volume\n");
848 rc = -EINVAL;
849 goto out_free;
850 }
851 } else if (new->media_type == media_devmapper) {
852 if (!dm_src || !dm_src_type || !dm_tgt ||
853 !dm_param || !dm_tgtfs || !dm_size_mb) {
854 LOGE("Required configuration parameter missing for devmapper volume\n");
855 rc = -EINVAL;
856 goto out_free;
857 }
858 if (!(new->dm = devmapper_init(dm_src, dm_src_type, dm_size_mb,
859 dm_tgt, dm_param, dm_tgtfs))) {
860 LOGE("Unable to initialize devmapping");
861 goto out_free;
862 }
863
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800864 }
865
866 if (!vol_root)
867 vol_root = new;
868 else {
869 volume_t *scan = vol_root;
870 while (scan->next)
871 scan = scan->next;
872 scan->next = new;
873 }
874
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800875 if (dm_src)
876 free(dm_src);
877 if (dm_src_type)
878 free(dm_src_type);
879 if (dm_tgt)
880 free(dm_tgt);
881 if (dm_param)
882 free(dm_param);
883 if (dm_tgtfs)
884 free(dm_tgtfs);
885
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800886 return rc;
887
888 out_free:
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800889
890 if (dm_src)
891 free(dm_src);
892 if (dm_src_type)
893 free(dm_src_type);
894 if (dm_tgt)
895 free(dm_tgt);
896 if (dm_param)
897 free(dm_param);
898 if (dm_tgtfs)
899 free(dm_tgtfs);
900
901
902 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
903 if (new->media_paths[i])
904 free(new->media_paths[i]);
905 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800906 if (new->mount_point)
907 free(new->mount_point);
908 if (new->ums_path)
909 free(new->ums_path);
910 return rc;
911}
912
913static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev)
914{
915 volume_t *scan = vol_root;
916 while(scan) {
917 if (scan->dev == dev)
918 return scan;
919 scan = scan->next;
920 }
921 return NULL;
922}
923
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800924static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked)
925{
926 volume_t *v = vol_root;
927
928 while(v) {
929 pthread_mutex_lock(&v->lock);
930 if (!strcmp(v->mount_point, mount_point)) {
931 if (!leave_locked)
932 pthread_mutex_unlock(&v->lock);
933 return v;
934 }
935 v = v->next;
936 }
937 return NULL;
938}
939
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800940static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy)
941{
942 volume_t *scan = vol_root;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800943 int i;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800944
945 while (scan) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800946
947 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
948 if (!scan->media_paths[i])
949 continue;
950
951 if (fuzzy && !strncmp(media_path, scan->media_paths[i], strlen(scan->media_paths[i])))
952 return scan;
953 else if (!fuzzy && !strcmp(media_path, scan->media_paths[i]))
954 return scan;
955 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800956
957 scan = scan->next;
958 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800959 return NULL;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800960}
961
962/*
963 * Attempt to bring a volume online
964 * Returns: 0 on success, errno on failure, with the following exceptions:
965 * - ENODATA - Unsupported filesystem type / blank
966 * vol->lock MUST be held!
967 */
968static int _volmgr_start(volume_t *vol, blkdev_t *dev)
969{
970 struct volmgr_fstable_entry *fs;
971 int rc = ENODATA;
972
973#if DEBUG_VOLMGR
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800974 LOG_VOL("_volmgr_start(%s, %d:%d):\n", vol->mount_point,
975 dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800976#endif
977
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800978 if (vol->state == volstate_mounted) {
979 LOGE("Unable to start volume '%s' (already mounted)\n", vol->mount_point);
980 return -EBUSY;
981 }
982
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800983 for (fs = fs_table; fs->name; fs++) {
984 if (!fs->identify_fn(dev))
985 break;
986 }
987
988 if (!fs) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800989 LOGE("No supported filesystems on %d:%d\n", dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800990 volume_setstate(vol, volstate_nofs);
991 return -ENODATA;
992 }
993
994 return volmgr_start_fs(fs, vol, dev);
995}
996
997// vol->lock MUST be held!
998static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev)
999{
1000 /*
1001 * Spawn a thread to do the actual checking / mounting in
1002 */
1003
1004 if (vol->worker_running) {
1005 LOGE("Worker thread is currently running.. waiting..\n");
1006 pthread_mutex_lock(&vol->worker_sem);
1007 LOG_VOL("Worker thread now available\n");
1008 }
1009
1010 vol->dev = dev;
1011
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001012 vol->worker_args.start_args.fs = fs;
1013 vol->worker_args.start_args.dev = dev;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001014
1015 pthread_attr_t attr;
1016 pthread_attr_init(&attr);
1017 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1018
1019 pthread_create(&vol->worker_thread, &attr, volmgr_start_fs_thread, vol);
1020
1021 return 0;
1022}
1023
1024static void __start_fs_thread_lock_cleanup(void *arg)
1025{
1026 volume_t *vol = (volume_t *) arg;
1027
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001028#if DEBUG_VOLMGR
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001029 LOG_VOL("__start_fs_thread_lock_cleanup(%s):\n", vol->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001030#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001031
1032 vol->worker_running = false;
1033
1034 // Wake up anyone that was waiting on this thread
1035 pthread_mutex_unlock(&vol->worker_sem);
1036
1037 // Unlock the volume
1038 pthread_mutex_unlock(&vol->lock);
1039}
1040
1041static void *volmgr_start_fs_thread(void *arg)
1042{
1043 volume_t *vol = (volume_t *) arg;
1044
1045 pthread_cleanup_push(__start_fs_thread_lock_cleanup, arg);
1046 pthread_mutex_lock(&vol->lock);
1047
1048 vol->worker_running = true;
1049 vol->worker_pid = getpid();
1050
1051 struct sigaction actions;
1052
1053 memset(&actions, 0, sizeof(actions));
1054 sigemptyset(&actions.sa_mask);
1055 actions.sa_flags = 0;
1056 actions.sa_handler = volmgr_start_fs_thread_sighandler;
1057 sigaction(SIGUSR1, &actions, NULL);
1058
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001059 struct volmgr_fstable_entry *fs = vol->worker_args.start_args.fs;
1060 blkdev_t *dev = vol->worker_args.start_args.dev;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001061 int rc;
1062
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001063#if DEBUG_VOLMGR
1064 LOG_VOL("Worker thread pid %d starting %s fs %d:%d on %s\n", getpid(),
1065 fs->name, dev->major, dev->minor, vol->mount_point);
1066#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001067
1068 if (fs->check_fn) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001069#if DEBUG_VOLMGR
1070 LOG_VOL("Starting %s filesystem check on %d:%d\n", fs->name,
1071 dev->major, dev->minor);
1072#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001073 volume_setstate(vol, volstate_checking);
1074 pthread_mutex_unlock(&vol->lock);
1075 rc = fs->check_fn(dev);
1076 pthread_mutex_lock(&vol->lock);
1077 if (vol->state != volstate_checking) {
1078 LOG_VOL("filesystem check aborted\n");
1079 goto out;
1080 }
1081
1082 if (rc < 0) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001083 LOGE("%s filesystem check failed on %d:%d (%s)\n", fs->name,
1084 dev->major, dev->minor, strerror(-rc));
1085 if (rc == -ENODATA) {
1086 volume_setstate(vol, volstate_nofs);
1087 goto out;
1088 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001089 goto out_unmountable;
1090 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001091#if DEBUG_VOLMGR
1092 LOG_VOL("%s filesystem check of %d:%d OK\n", fs->name,
1093 dev->major, dev->minor);
1094#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001095 }
1096
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001097 rc = fs->mount_fn(dev, vol, safe_mode);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001098 if (!rc) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001099 LOG_VOL("Sucessfully mounted %s filesystem %d:%d on %s (safe-mode %s)\n",
1100 fs->name, dev->major, dev->minor, vol->mount_point,
1101 (safe_mode ? "on" : "off"));
1102 vol->fs = fs;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001103 volume_setstate(vol, volstate_mounted);
1104 goto out;
1105 }
1106
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001107 LOGE("%s filesystem mount of %d:%d failed (%d)\n", fs->name, dev->major,
1108 dev->minor, rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001109
1110 out_unmountable:
1111 volume_setstate(vol, volstate_damaged);
1112 out:
1113 pthread_cleanup_pop(1);
1114 pthread_exit(NULL);
1115 return NULL;
1116}
1117
1118static void volmgr_start_fs_thread_sighandler(int signo)
1119{
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001120 LOGE("Volume startup thread got signal %d\n", signo);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001121}
1122
1123static void volume_setstate(volume_t *vol, volume_state_t state)
1124{
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001125 if (state == vol->state)
1126 return;
1127
1128#if DEBUG_VOLMGR
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001129 LOG_VOL("Volume %s state change from %d -> %d\n", vol->mount_point, vol->state, state);
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001130#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001131
1132 vol->state = state;
1133
1134 char *prop_val = conv_volstate_to_propstr(vol->state);
1135
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001136 if (prop_val) {
1137 property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val);
1138 volume_send_state(vol);
1139 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001140}
1141
1142static int volume_send_state(volume_t *vol)
1143{
1144 char *event = conv_volstate_to_eventstr(vol->state);
1145
1146 return send_msg_with_data(event, vol->mount_point);
1147}
1148
1149static char *conv_volstate_to_eventstr(volume_state_t state)
1150{
1151 int i;
1152
1153 for (i = 0; volume_state_strings[i].event != NULL; i++) {
1154 if (volume_state_strings[i].state == state)
1155 break;
1156 }
1157
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001158 return volume_state_strings[i].event;
1159}
1160
1161static char *conv_volstate_to_propstr(volume_state_t state)
1162{
1163 int i;
1164
1165 for (i = 0; volume_state_strings[i].event != NULL; i++) {
1166 if (volume_state_strings[i].state == state)
1167 break;
1168 }
1169
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001170 return volume_state_strings[i].property_val;
1171}
1172