blob: c3ce8d174010865e94e3e667f2c9cf48b7161989 [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"))) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800106 LOGE("Error opening /proc/mounts (%s)", strerror(errno));
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800107 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
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800128int volmgr_set_volume_key(char *mount_point, unsigned char *key)
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800129{
130 volume_t *v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
131
132 if (!v)
133 return -ENOENT;
134
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800135 if (v->media_type != media_devmapper) {
136 LOGE("Cannot set key on a non devmapper volume");
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800137 pthread_mutex_unlock(&v->lock);
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800138 return -EINVAL;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800139 }
140
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800141 memcpy(v->dm->key, key, sizeof(v->dm->key));
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800142 pthread_mutex_unlock(&v->lock);
143 return 0;
144}
145
146int volmgr_format_volume(char *mount_point)
147{
148 int rc;
149 volume_t *v;
150
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800151 LOG_VOL("volmgr_format_volume(%s):", mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800152
153 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
154
155 if (!v)
156 return -ENOENT;
157
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800158 if (v->state == volstate_mounted ||
159 v->state == volstate_mounted_ro ||
160 v->state == volstate_ums ||
161 v->state == volstate_checking) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800162 LOGE("Can't format '%s', currently in state %d", mount_point, v->state);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800163 pthread_mutex_unlock(&v->lock);
164 return -EBUSY;
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800165 } else if (v->state == volstate_nomedia &&
166 v->media_type != media_devmapper) {
167 LOGE("Can't format '%s', (no media)", mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800168 pthread_mutex_unlock(&v->lock);
169 return -ENOMEDIUM;
170 }
171
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800172 // XXX:Reject if the underlying source media is not present
173
174 if (v->media_type == media_devmapper) {
175 if ((rc = devmapper_genesis(v->dm)) < 0) {
176 LOGE("devmapper genesis failed for %s (%d)", mount_point, rc);
177 pthread_mutex_unlock(&v->lock);
178 return rc;
179 }
180 } else {
181 if ((rc = initialize_mbr(v->dev->disk)) < 0) {
182 LOGE("MBR init failed for %s (%d)", mount_point, rc);
183 pthread_mutex_unlock(&v->lock);
184 return rc;
185 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800186 }
187
188 volume_setstate(v, volstate_formatting);
189 pthread_mutex_unlock(&v->lock);
190 return rc;
191}
192
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800193int volmgr_bootstrap(void)
194{
195 int rc;
196
197 if ((rc = volmgr_readconfig("/system/etc/vold.conf")) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800198 LOGE("Unable to process config");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800199 return rc;
200 }
201
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800202 /*
203 * Check to see if any of our volumes is mounted
204 */
205 volume_t *v = vol_root;
206 while (v) {
207 if (_mountpoint_mounted(v->mount_point)) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800208 LOG_VOL("Volume '%s' already mounted at startup", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800209 v->state = volstate_mounted;
210 }
211 v = v->next;
212 }
213
214 return 0;
215}
216
217int volmgr_safe_mode(boolean enable)
218{
219 if (enable == safe_mode)
220 return 0;
221
222 safe_mode = enable;
223
224 volume_t *v = vol_root;
225 int rc;
226
227 while (v) {
228 pthread_mutex_lock(&v->lock);
229 if (v->state == volstate_mounted && v->fs) {
230 rc = v->fs->mount_fn(v->dev, v, safe_mode);
231 if (!rc) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800232 LOG_VOL("Safe mode %s on %s", (enable ? "enabled" : "disabled"), v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800233 } else {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800234 LOGE("Failed to %s safe-mode on %s (%s)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800235 (enable ? "enable" : "disable" ), v->mount_point, strerror(-rc));
236 }
237 }
238
239 pthread_mutex_unlock(&v->lock);
240 v = v->next;
241 }
242
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800243 return 0;
244}
245
246int volmgr_send_states(void)
247{
248 volume_t *vol_scan = vol_root;
249 int rc;
250
251 while (vol_scan) {
252 pthread_mutex_lock(&vol_scan->lock);
253 if ((rc = volume_send_state(vol_scan)) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800254 LOGE("Error sending state to framework (%d)", rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800255 }
256 pthread_mutex_unlock(&vol_scan->lock);
257 vol_scan = vol_scan->next;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800258 break; // XXX:
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800259 }
260
261 return 0;
262}
263
264/*
265 * Called when a block device is ready to be
266 * evaluated by the volume manager.
267 */
268int volmgr_consider_disk(blkdev_t *dev)
269{
270 volume_t *vol;
271
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800272 if (!(vol = volmgr_lookup_volume_by_mediapath(dev->media->devpath, true)))
273 return 0;
274
275 pthread_mutex_lock(&vol->lock);
276
277 if (vol->state == volstate_mounted) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800278 LOGE("Volume %s already mounted (did we just crash?)", vol->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800279 pthread_mutex_unlock(&vol->lock);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800280 return 0;
281 }
282
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800283 int rc = _volmgr_consider_disk_and_vol(vol, dev);
284 pthread_mutex_unlock(&vol->lock);
285 return rc;
286}
287
288int volmgr_start_volume_by_mountpoint(char *mount_point)
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800289{
290 volume_t *v;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800291
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800292 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
293 if (!v)
294 return -ENOENT;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800295
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800296 if (v->media_type == media_devmapper) {
297 if (devmapper_start(v->dm) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800298 LOGE("volmgr failed to start devmapper volume '%s'",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800299 v->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800300 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800301 } else if (v->media_type == media_mmc) {
302 if (!v->dev) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800303 LOGE("Cannot start volume '%s' (volume is not bound)", mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800304 pthread_mutex_unlock(&v->lock);
305 return -ENOENT;
306 }
307
308 if (_volmgr_consider_disk_and_vol(v, v->dev->disk) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800309 LOGE("volmgr failed to start volume '%s'", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800310 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800311 }
312
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800313 pthread_mutex_unlock(&v->lock);
314 return 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800315}
316
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800317static void _cb_volstopped_for_devmapper_teardown(volume_t *v, void *arg)
318{
319 devmapper_stop(v->dm);
320 volume_setstate(v, volstate_nomedia);
321 pthread_mutex_unlock(&v->lock);
322}
323
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800324int volmgr_stop_volume_by_mountpoint(char *mount_point)
325{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800326 int rc;
327 volume_t *v;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800328
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800329 v = volmgr_lookup_volume_by_mountpoint(mount_point, true);
330 if (!v)
331 return -ENOENT;
332
333 if (v->state == volstate_mounted)
334 volmgr_send_eject_request(v);
335
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800336 if (v->media_type == media_devmapper)
337 rc = volmgr_shutdown_volume(v, _cb_volstopped_for_devmapper_teardown, false);
338 else
339 rc = volmgr_shutdown_volume(v, NULL, true);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800340
341 /*
342 * If shutdown returns -EINPROGRESS,
343 * do *not* release the lock as
344 * it is now owned by the reaper thread
345 */
346 if (rc != -EINPROGRESS) {
347 if (rc)
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800348 LOGE("unable to shutdown volume '%s'", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800349 pthread_mutex_unlock(&v->lock);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800350 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800351 return 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800352}
353
354int volmgr_notify_eject(blkdev_t *dev, void (* cb) (blkdev_t *))
355{
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800356 LOG_VOL("Volmgr notified of %d:%d eject", dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800357
358 volume_t *v;
The Android Open Source Project261ed752009-02-19 10:57:36 -0800359 int rc;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800360
361 // XXX: Partitioning support is going to need us to stop *all*
362 // devices in this volume
363 if (!(v = volmgr_lookup_volume_by_dev(dev))) {
364 if (cb)
365 cb(dev);
366 return 0;
367 }
368
369 pthread_mutex_lock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800370
371 volume_state_t old_state = v->state;
372
373 if (v->state == volstate_mounted ||
374 v->state == volstate_ums ||
The Android Open Source Project261ed752009-02-19 10:57:36 -0800375 v->state == volstate_checking) {
376
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800377 volume_setstate(v, volstate_badremoval);
The Android Open Source Project261ed752009-02-19 10:57:36 -0800378
379 /*
380 * Stop any devmapper volumes which
381 * are using us as a source
382 * XXX: We may need to enforce stricter
383 * order here
384 */
385 volume_t *dmvol = vol_root;
386 while (dmvol) {
387 if ((dmvol->media_type == media_devmapper) &&
388 (dmvol->dm->src_type == dmsrc_loopback) &&
389 (!strncmp(dmvol->dm->type_data.loop.loop_src,
390 v->mount_point, strlen(v->mount_point)))) {
391
392 pthread_mutex_lock(&dmvol->lock);
393 if (dmvol->state != volstate_nomedia) {
394 rc = volmgr_shutdown_volume(dmvol, _cb_volstopped_for_devmapper_teardown, false);
395 if (rc != -EINPROGRESS) {
396 if (rc)
397 LOGE("unable to shutdown volume '%s'", v->mount_point);
398 pthread_mutex_unlock(&dmvol->lock);
399 }
400 } else
401 pthread_mutex_unlock(&dmvol->lock);
402 }
403 dmvol = dmvol->next;
404 }
405
406 } else if (v->state == volstate_formatting) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800407 /*
408 * The device is being ejected due to
409 * kernel disk revalidation.
410 */
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800411 LOG_VOL("Volmgr ignoring eject of %d:%d (volume formatting)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800412 dev->major, dev->minor);
413 if (cb)
414 cb(dev);
415 pthread_mutex_unlock(&v->lock);
416 return 0;
417 } else
418 volume_setstate(v, volstate_nomedia);
419
420 if (old_state == volstate_ums) {
421 ums_disable(v->ums_path);
422 pthread_mutex_unlock(&v->lock);
423 } else {
424 int rc = volmgr_stop_volume(v, _cb_volume_stopped_for_eject, cb, false);
425 if (rc != -EINPROGRESS) {
426 if (rc)
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800427 LOGE("unable to shutdown volume '%s'", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800428 pthread_mutex_unlock(&v->lock);
429 }
430 }
431 return 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800432}
433
434static void _cb_volume_stopped_for_eject(volume_t *v, void *arg)
435{
436 void (* eject_cb) (blkdev_t *) = arg;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800437
438#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800439 LOG_VOL("Volume %s has been stopped for eject", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800440#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800441
The Android Open Source Project261ed752009-02-19 10:57:36 -0800442 if (eject_cb)
443 eject_cb(v->dev);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800444 v->dev = NULL; // Clear dev because its being ejected
445}
446
447/*
448 * Instructs the volume manager to enable or disable USB mass storage
449 * on any volumes configured to use it.
450 */
451int volmgr_enable_ums(boolean enable)
452{
453 volume_t *v = vol_root;
454
455 while(v) {
456 if (v->ums_path) {
457 int rc;
458
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800459 if (enable) {
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800460 pthread_mutex_lock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800461 if (v->state == volstate_mounted)
462 volmgr_send_eject_request(v);
463 else if (v->state == volstate_ums) {
464 pthread_mutex_unlock(&v->lock);
465 goto next_vol;
466 }
467
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800468 // Stop the volume, and enable UMS in the callback
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800469 rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable, false);
470 if (rc != -EINPROGRESS) {
471 if (rc)
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800472 LOGE("unable to shutdown volume '%s'", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800473 pthread_mutex_unlock(&v->lock);
474 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800475 } else {
476 // Disable UMS
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800477 pthread_mutex_lock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800478 if (v->state != volstate_ums) {
479 pthread_mutex_unlock(&v->lock);
480 goto next_vol;
481 }
482
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800483 if ((rc = ums_disable(v->ums_path)) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800484 LOGE("unable to disable ums on '%s'", v->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800485 pthread_mutex_unlock(&v->lock);
486 continue;
487 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800488
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800489 LOG_VOL("Kick-starting volume %d:%d after UMS disable",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800490 v->dev->disk->major, v->dev->disk->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800491 // Start volume
492 if ((rc = _volmgr_consider_disk_and_vol(v, v->dev->disk)) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800493 LOGE("volmgr failed to consider disk %d:%d",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800494 v->dev->disk->major, v->dev->disk->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800495 }
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800496 pthread_mutex_unlock(&v->lock);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800497 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800498 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800499 next_vol:
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800500 v = v->next;
501 }
502 return 0;
503}
504
505/*
506 * Static functions
507 */
508
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800509static int volmgr_send_eject_request(volume_t *v)
510{
511 return send_msg_with_data(VOLD_EVT_EJECTING, v->mount_point);
512}
513
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800514// vol->lock must be held!
515static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev)
516{
517 int rc = 0;
518
519#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800520 LOG_VOL("volmgr_consider_disk_and_vol(%s, %d:%d):", vol->mount_point,
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800521 dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800522#endif
523
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800524 if (vol->state == volstate_unknown ||
525 vol->state == volstate_mounted ||
526 vol->state == volstate_mounted_ro ||
527 vol->state == volstate_damaged) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800528 LOGE("Cannot consider volume '%s' because it is in state '%d",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800529 vol->mount_point, vol->state);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800530 return -EADDRINUSE;
531 }
532
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800533 if (vol->state == volstate_formatting) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800534 LOG_VOL("Evaluating dev '%s' for formattable filesystems for '%s'",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800535 dev->devpath, vol->mount_point);
536 /*
537 * Since we only support creating 1 partition (right now),
538 * we can just lookup the target by devno
539 */
540 blkdev_t *part = blkdev_lookup_by_devno(dev->major, 1);
541 if (!part) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800542 part = blkdev_lookup_by_devno(dev->major, 0);
543 if (!part) {
544 LOGE("Unable to find device to format");
545 return -ENODEV;
546 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800547 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800548
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800549 if ((rc = format_partition(part,
550 vol->media_type == media_devmapper ?
551 FORMAT_TYPE_EXT2 : FORMAT_TYPE_FAT32)) < 0) {
552 LOGE("format failed (%d)", rc);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800553 return rc;
554 }
555
556 }
557
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800558 LOG_VOL("Evaluating dev '%s' for mountable filesystems for '%s'",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800559 dev->devpath, vol->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800560
561 if (dev->nr_parts == 0) {
562 rc = _volmgr_start(vol, dev);
563#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800564 LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d", vol->mount_point,
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800565 dev->major, dev->minor, rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800566#endif
567 } else {
568 /*
569 * Device has multiple partitions
570 * This is where interesting partition policies could be implemented.
571 * For now just try them in sequence until one succeeds
572 */
573
574 rc = -ENODEV;
575 int i;
576 for (i = 0; i < dev->nr_parts; i++) {
577 blkdev_t *part = blkdev_lookup_by_devno(dev->major, (i+1));
578 if (!part) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800579 LOGE("Error - unable to lookup partition for blkdev %d:%d", dev->major, (i+1));
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800580 continue;
581 }
582 rc = _volmgr_start(vol, part);
583#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800584 LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800585 vol->mount_point, part->major, part->minor, rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800586#endif
587 if (!rc)
588 break;
589 }
590
591 if (rc == -ENODEV) {
592 // Assert to make sure each partition had a backing blkdev
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800593 LOGE("Internal consistency error");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800594 return 0;
595 }
596 }
597
598 if (rc == -ENODATA) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800599 LOGE("Device %d:%d contains no usable filesystems",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800600 dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800601 rc = 0;
602 }
603
604 return rc;
605}
606
607static void volmgr_reaper_thread_sighandler(int signo)
608{
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800609 LOGE("Volume reaper thread got signal %d", signo);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800610}
611
612static void __reaper_cleanup(void *arg)
613{
614 volume_t *vol = (volume_t *) arg;
615
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800616 if (vol->worker_args.reaper_args.cb)
617 vol->worker_args.reaper_args.cb(vol, vol->worker_args.reaper_args.cb_arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800618
619 vol->worker_running = false;
620
621 // Wake up anyone that was waiting on this thread
622 pthread_mutex_unlock(&vol->worker_sem);
623
624 // Unlock the volume
625 pthread_mutex_unlock(&vol->lock);
626}
627
628static void *volmgr_reaper_thread(void *arg)
629{
630 volume_t *vol = (volume_t *) arg;
631
632 pthread_cleanup_push(__reaper_cleanup, arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800633
634 vol->worker_running = true;
635 vol->worker_pid = getpid();
636
637 struct sigaction actions;
638
639 memset(&actions, 0, sizeof(actions));
640 sigemptyset(&actions.sa_mask);
641 actions.sa_flags = 0;
642 actions.sa_handler = volmgr_reaper_thread_sighandler;
643 sigaction(SIGUSR1, &actions, NULL);
644
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800645 LOG_VOL("Reaper here - working on %s", vol->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800646
647 boolean send_sig_kill = false;
648 int i, rc;
649
650 for (i = 0; i < 10; i++) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800651 errno = 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800652 rc = umount(vol->mount_point);
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800653 LOG_VOL("volmngr reaper umount(%s) attempt %d (%s)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800654 vol->mount_point, i + 1, strerror(errno));
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800655 if (!rc)
656 break;
657 if (rc && (errno == EINVAL || errno == ENOENT)) {
658 rc = 0;
659 break;
660 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800661 sleep(1);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800662 if (i >= 4) {
663 KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0);
664 if (!send_sig_kill)
665 send_sig_kill = true;
666 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800667 }
668
669 if (!rc) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800670 LOG_VOL("Reaper sucessfully unmounted %s", vol->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800671 vol->fs = NULL;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800672 volume_setstate(vol, volstate_unmounted);
673 } else {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800674 LOGE("Unable to unmount!! (%d)", rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800675 }
676
677 out:
678 pthread_cleanup_pop(1);
679 pthread_exit(NULL);
680 return NULL;
681}
682
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800683// vol->lock must be held!
684static 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 -0800685{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800686
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800687 if (vol->worker_running) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800688 LOGE("Worker thread is currently running.. waiting..");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800689 pthread_mutex_lock(&vol->worker_sem);
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800690 LOG_VOL("Worker thread now available");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800691 }
692
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800693 vol->worker_args.reaper_args.cb = cb;
694 vol->worker_args.reaper_args.cb_arg = arg;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800695
696 pthread_attr_t attr;
697 pthread_attr_init(&attr);
698 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
699
700 pthread_create(&vol->worker_thread, &attr, volmgr_reaper_thread, vol);
701}
702
703static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange)
704{
705 int i, rc;
706
707 if (v->state == volstate_mounted || v->state == volstate_badremoval) {
708 // Try to unmount right away (5 retries)
709 for (i = 0; i < 5; i++) {
710 rc = umount(v->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800711 if (!rc)
712 break;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800713
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800714 if (rc && (errno == EINVAL || errno == ENOENT)) {
715 rc = 0;
716 break;
717 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800718
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800719 LOG_VOL("volmngr quick stop umount(%s) attempt %d (%s)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800720 v->mount_point, i + 1, strerror(errno));
721
722 if (i == 0)
723 usleep(1000 * 250); // First failure, sleep for 250 ms
724 else
725 sched_yield();
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800726 }
727
728 if (!rc) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800729 LOG_VOL("volmgr_stop_volume(%s): Volume unmounted sucessfully",
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800730 v->mount_point);
731 if (emit_statechange)
732 volume_setstate(v, volstate_unmounted);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800733 v->fs = NULL;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800734 goto out_cb_immed;
735 }
736
737 /*
738 * Since the volume is still in use, dispatch the stopping to
739 * a thread
740 */
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800741 LOG_VOL("Volume %s is busy (%d) - uncaging the reaper", v->mount_point, rc);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800742 volmgr_uncage_reaper(v, cb, arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800743 return -EINPROGRESS;
744 } else if (v->state == volstate_checking) {
745 volume_setstate(v, volstate_unmounted);
746 if (v->worker_running) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800747 LOG_VOL("Cancelling worker thread");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800748 pthread_kill(v->worker_thread, SIGUSR1);
749 } else
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800750 LOGE("Strange... we were in checking state but worker thread wasn't running..");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800751 goto out_cb_immed;
752 }
753
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800754 out_cb_immed:
755 if (cb)
756 cb(v, arg);
757 return 0;
758}
759
760
761/*
762 * Gracefully stop a volume
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800763 * v->lock must be held!
764 * if we return -EINPROGRESS, do NOT release the lock as the reaper
765 * is using the volume
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800766 */
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800767static 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 -0800768{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800769 return volmgr_stop_volume(v, cb, NULL, emit_statechange);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800770}
771
772static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg)
773{
774 void (* shutdown_cb) (volume_t *) = arg;
775
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800776#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800777 LOG_VOL("Volume %s has been stopped for shutdown", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800778#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800779 shutdown_cb(v);
780}
781
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800782
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800783/*
784 * Called when a volume is sucessfully unmounted for UMS enable
785 */
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800786static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg)
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800787{
788 int rc;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800789 char *devdir_path;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800790
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800791#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800792 LOG_VOL("_cb_volstopped_for_ums_enable(%s):", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800793#endif
794 devdir_path = blkdev_get_devpath(v->dev->disk);
795
796 if ((rc = ums_enable(devdir_path, v->ums_path)) < 0) {
797 free(devdir_path);
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800798 LOGE("Error enabling ums (%d)", rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800799 return;
800 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800801 free(devdir_path);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800802 volume_setstate(v, volstate_ums);
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800803 pthread_mutex_unlock(&v->lock);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800804}
805
806static int volmgr_readconfig(char *cfg_path)
807{
808 cnode *root = config_node("", "");
809 cnode *node;
810
811 config_load_file(root, cfg_path);
812 node = root->first_child;
813
814 while (node) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800815 if (!strncmp(node->name, "volume_", 7))
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800816 volmgr_config_volume(node);
817 else
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800818 LOGE("Skipping unknown configuration node '%s'", node->name);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800819 node = node->next;
820 }
821 return 0;
822}
823
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800824static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path)
825{
826 int i;
827
828#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800829 LOG_VOL("volmgr_add_mediapath_to_volume(%p, %s):", v, media_path);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800830#endif
831 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
832 if (!v->media_paths[i]) {
833 v->media_paths[i] = strdup(media_path);
834 return;
835 }
836 }
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800837 LOGE("Unable to add media path '%s' to volume (out of media slots)", media_path);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800838}
839
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800840static int volmgr_config_volume(cnode *node)
841{
842 volume_t *new;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800843 int rc = 0, i;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800844
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800845 char *dm_src, *dm_src_type, *dm_tgt, *dm_param, *dm_tgtfs;
846 uint32_t dm_size_mb = 0;
847
848 dm_src = dm_src_type = dm_tgt = dm_param = dm_tgtfs = NULL;
849#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800850 LOG_VOL("volmgr_configure_volume(%s):", node->name);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800851#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800852 if (!(new = malloc(sizeof(volume_t))))
853 return -ENOMEM;
854 memset(new, 0, sizeof(volume_t));
855
856 new->state = volstate_nomedia;
857 pthread_mutex_init(&new->lock, NULL);
858 pthread_mutex_init(&new->worker_sem, NULL);
859
860 cnode *child = node->first_child;
861
862 while (child) {
863 if (!strcmp(child->name, "media_path"))
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800864 volmgr_add_mediapath_to_volume(new, child->value);
865 else if (!strcmp(child->name, "emu_media_path"))
866 volmgr_add_mediapath_to_volume(new, child->value);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800867 else if (!strcmp(child->name, "media_type")) {
868 if (!strcmp(child->value, "mmc"))
869 new->media_type = media_mmc;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800870 else if (!strcmp(child->value, "devmapper"))
871 new->media_type = media_devmapper;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800872 else {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800873 LOGE("Invalid media type '%s'", child->value);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800874 rc = -EINVAL;
875 goto out_free;
876 }
877 } else if (!strcmp(child->name, "mount_point"))
878 new->mount_point = strdup(child->value);
879 else if (!strcmp(child->name, "ums_path"))
880 new->ums_path = strdup(child->value);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800881 else if (!strcmp(child->name, "dm_src"))
882 dm_src = strdup(child->value);
883 else if (!strcmp(child->name, "dm_src_type"))
884 dm_src_type = strdup(child->value);
885 else if (!strcmp(child->name, "dm_src_size_mb"))
886 dm_size_mb = atoi(child->value);
887 else if (!strcmp(child->name, "dm_target"))
888 dm_tgt = strdup(child->value);
889 else if (!strcmp(child->name, "dm_target_params"))
890 dm_param = strdup(child->value);
891 else if (!strcmp(child->name, "dm_target_fs"))
892 dm_tgtfs = strdup(child->value);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800893 else
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800894 LOGE("Ignoring unknown config entry '%s'", child->name);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800895 child = child->next;
896 }
897
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800898 if (new->media_type == media_mmc) {
899 if (!new->media_paths[0] || !new->mount_point || new->media_type == media_unknown) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800900 LOGE("Required configuration parameter missing for mmc volume");
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800901 rc = -EINVAL;
902 goto out_free;
903 }
904 } else if (new->media_type == media_devmapper) {
905 if (!dm_src || !dm_src_type || !dm_tgt ||
906 !dm_param || !dm_tgtfs || !dm_size_mb) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800907 LOGE("Required configuration parameter missing for devmapper volume");
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800908 rc = -EINVAL;
909 goto out_free;
910 }
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800911
912 char dm_mediapath[255];
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800913 if (!(new->dm = devmapper_init(dm_src, dm_src_type, dm_size_mb,
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800914 dm_tgt, dm_param, dm_tgtfs, dm_mediapath))) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800915 LOGE("Unable to initialize devmapping");
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800916 goto out_free;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800917 }
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800918 LOG_VOL("media path for devmapper volume = '%s'", dm_mediapath);
919 volmgr_add_mediapath_to_volume(new, dm_mediapath);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800920 }
921
922 if (!vol_root)
923 vol_root = new;
924 else {
925 volume_t *scan = vol_root;
926 while (scan->next)
927 scan = scan->next;
928 scan->next = new;
929 }
930
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800931 if (dm_src)
932 free(dm_src);
933 if (dm_src_type)
934 free(dm_src_type);
935 if (dm_tgt)
936 free(dm_tgt);
937 if (dm_param)
938 free(dm_param);
939 if (dm_tgtfs)
940 free(dm_tgtfs);
941
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800942 return rc;
943
944 out_free:
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800945
946 if (dm_src)
947 free(dm_src);
948 if (dm_src_type)
949 free(dm_src_type);
950 if (dm_tgt)
951 free(dm_tgt);
952 if (dm_param)
953 free(dm_param);
954 if (dm_tgtfs)
955 free(dm_tgtfs);
956
957
958 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
959 if (new->media_paths[i])
960 free(new->media_paths[i]);
961 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800962 if (new->mount_point)
963 free(new->mount_point);
964 if (new->ums_path)
965 free(new->ums_path);
966 return rc;
967}
968
969static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev)
970{
971 volume_t *scan = vol_root;
972 while(scan) {
973 if (scan->dev == dev)
974 return scan;
975 scan = scan->next;
976 }
977 return NULL;
978}
979
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800980static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked)
981{
982 volume_t *v = vol_root;
983
984 while(v) {
985 pthread_mutex_lock(&v->lock);
986 if (!strcmp(v->mount_point, mount_point)) {
987 if (!leave_locked)
988 pthread_mutex_unlock(&v->lock);
989 return v;
990 }
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800991 pthread_mutex_unlock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800992 v = v->next;
993 }
994 return NULL;
995}
996
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800997static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy)
998{
999 volume_t *scan = vol_root;
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001000 int i;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001001
1002 while (scan) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001003
1004 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
1005 if (!scan->media_paths[i])
1006 continue;
1007
1008 if (fuzzy && !strncmp(media_path, scan->media_paths[i], strlen(scan->media_paths[i])))
1009 return scan;
1010 else if (!fuzzy && !strcmp(media_path, scan->media_paths[i]))
1011 return scan;
1012 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001013
1014 scan = scan->next;
1015 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001016 return NULL;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001017}
1018
1019/*
1020 * Attempt to bring a volume online
1021 * Returns: 0 on success, errno on failure, with the following exceptions:
1022 * - ENODATA - Unsupported filesystem type / blank
1023 * vol->lock MUST be held!
1024 */
1025static int _volmgr_start(volume_t *vol, blkdev_t *dev)
1026{
1027 struct volmgr_fstable_entry *fs;
1028 int rc = ENODATA;
1029
1030#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001031 LOG_VOL("_volmgr_start(%s, %d:%d):", vol->mount_point,
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001032 dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001033#endif
1034
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001035 if (vol->state == volstate_mounted) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001036 LOGE("Unable to start volume '%s' (already mounted)", vol->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001037 return -EBUSY;
1038 }
1039
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001040 for (fs = fs_table; fs->name; fs++) {
1041 if (!fs->identify_fn(dev))
1042 break;
1043 }
1044
1045 if (!fs) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001046 LOGE("No supported filesystems on %d:%d", dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001047 volume_setstate(vol, volstate_nofs);
1048 return -ENODATA;
1049 }
1050
1051 return volmgr_start_fs(fs, vol, dev);
1052}
1053
1054// vol->lock MUST be held!
1055static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev)
1056{
1057 /*
1058 * Spawn a thread to do the actual checking / mounting in
1059 */
1060
1061 if (vol->worker_running) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001062 LOGE("Worker thread is currently running.. waiting..");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001063 pthread_mutex_lock(&vol->worker_sem);
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001064 LOG_VOL("Worker thread now available");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001065 }
1066
1067 vol->dev = dev;
1068
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001069 vol->worker_args.start_args.fs = fs;
1070 vol->worker_args.start_args.dev = dev;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001071
1072 pthread_attr_t attr;
1073 pthread_attr_init(&attr);
1074 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1075
1076 pthread_create(&vol->worker_thread, &attr, volmgr_start_fs_thread, vol);
1077
1078 return 0;
1079}
1080
1081static void __start_fs_thread_lock_cleanup(void *arg)
1082{
1083 volume_t *vol = (volume_t *) arg;
1084
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001085#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001086 LOG_VOL("__start_fs_thread_lock_cleanup(%s):", vol->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001087#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001088
1089 vol->worker_running = false;
1090
1091 // Wake up anyone that was waiting on this thread
1092 pthread_mutex_unlock(&vol->worker_sem);
1093
1094 // Unlock the volume
1095 pthread_mutex_unlock(&vol->lock);
1096}
1097
1098static void *volmgr_start_fs_thread(void *arg)
1099{
1100 volume_t *vol = (volume_t *) arg;
1101
1102 pthread_cleanup_push(__start_fs_thread_lock_cleanup, arg);
1103 pthread_mutex_lock(&vol->lock);
1104
1105 vol->worker_running = true;
1106 vol->worker_pid = getpid();
1107
1108 struct sigaction actions;
1109
1110 memset(&actions, 0, sizeof(actions));
1111 sigemptyset(&actions.sa_mask);
1112 actions.sa_flags = 0;
1113 actions.sa_handler = volmgr_start_fs_thread_sighandler;
1114 sigaction(SIGUSR1, &actions, NULL);
1115
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001116 struct volmgr_fstable_entry *fs = vol->worker_args.start_args.fs;
1117 blkdev_t *dev = vol->worker_args.start_args.dev;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001118 int rc;
1119
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001120#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001121 LOG_VOL("Worker thread pid %d starting %s fs %d:%d on %s", getpid(),
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001122 fs->name, dev->major, dev->minor, vol->mount_point);
1123#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001124
1125 if (fs->check_fn) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001126#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001127 LOG_VOL("Starting %s filesystem check on %d:%d", fs->name,
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001128 dev->major, dev->minor);
1129#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001130 volume_setstate(vol, volstate_checking);
1131 pthread_mutex_unlock(&vol->lock);
1132 rc = fs->check_fn(dev);
1133 pthread_mutex_lock(&vol->lock);
1134 if (vol->state != volstate_checking) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001135 LOG_VOL("filesystem check aborted");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001136 goto out;
1137 }
1138
1139 if (rc < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001140 LOGE("%s filesystem check failed on %d:%d (%s)", fs->name,
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001141 dev->major, dev->minor, strerror(-rc));
1142 if (rc == -ENODATA) {
1143 volume_setstate(vol, volstate_nofs);
1144 goto out;
1145 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001146 goto out_unmountable;
1147 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001148#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001149 LOG_VOL("%s filesystem check of %d:%d OK", fs->name,
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001150 dev->major, dev->minor);
1151#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001152 }
1153
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001154 rc = fs->mount_fn(dev, vol, safe_mode);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001155 if (!rc) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001156 LOG_VOL("Sucessfully mounted %s filesystem %d:%d on %s (safe-mode %s)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001157 fs->name, dev->major, dev->minor, vol->mount_point,
1158 (safe_mode ? "on" : "off"));
1159 vol->fs = fs;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001160 volume_setstate(vol, volstate_mounted);
1161 goto out;
1162 }
1163
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001164 LOGE("%s filesystem mount of %d:%d failed (%d)", fs->name, dev->major,
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001165 dev->minor, rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001166
1167 out_unmountable:
1168 volume_setstate(vol, volstate_damaged);
1169 out:
1170 pthread_cleanup_pop(1);
1171 pthread_exit(NULL);
1172 return NULL;
1173}
1174
1175static void volmgr_start_fs_thread_sighandler(int signo)
1176{
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001177 LOGE("Volume startup thread got signal %d", signo);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001178}
1179
1180static void volume_setstate(volume_t *vol, volume_state_t state)
1181{
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001182 if (state == vol->state)
1183 return;
1184
1185#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001186 LOG_VOL("Volume %s state change from %d -> %d", vol->mount_point, vol->state, state);
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001187#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001188
1189 vol->state = state;
1190
1191 char *prop_val = conv_volstate_to_propstr(vol->state);
1192
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001193 if (prop_val) {
1194 property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val);
1195 volume_send_state(vol);
1196 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001197}
1198
1199static int volume_send_state(volume_t *vol)
1200{
1201 char *event = conv_volstate_to_eventstr(vol->state);
1202
1203 return send_msg_with_data(event, vol->mount_point);
1204}
1205
1206static char *conv_volstate_to_eventstr(volume_state_t state)
1207{
1208 int i;
1209
1210 for (i = 0; volume_state_strings[i].event != NULL; i++) {
1211 if (volume_state_strings[i].state == state)
1212 break;
1213 }
1214
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001215 return volume_state_strings[i].event;
1216}
1217
1218static char *conv_volstate_to_propstr(volume_state_t state)
1219{
1220 int i;
1221
1222 for (i = 0; volume_state_strings[i].event != NULL; i++) {
1223 if (volume_state_strings[i].state == state)
1224 break;
1225 }
1226
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001227 return volume_state_strings[i].property_val;
1228}
1229