blob: 0cec8256bd9d6be8ffed4bb22069b6608c4a57d9 [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;
359
360 // XXX: Partitioning support is going to need us to stop *all*
361 // devices in this volume
362 if (!(v = volmgr_lookup_volume_by_dev(dev))) {
363 if (cb)
364 cb(dev);
365 return 0;
366 }
367
368 pthread_mutex_lock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800369
370 volume_state_t old_state = v->state;
371
372 if (v->state == volstate_mounted ||
373 v->state == volstate_ums ||
374 v->state == volstate_checking)
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800375 volume_setstate(v, volstate_badremoval);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800376 else if (v->state == volstate_formatting) {
377 /*
378 * The device is being ejected due to
379 * kernel disk revalidation.
380 */
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800381 LOG_VOL("Volmgr ignoring eject of %d:%d (volume formatting)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800382 dev->major, dev->minor);
383 if (cb)
384 cb(dev);
385 pthread_mutex_unlock(&v->lock);
386 return 0;
387 } else
388 volume_setstate(v, volstate_nomedia);
389
390 if (old_state == volstate_ums) {
391 ums_disable(v->ums_path);
392 pthread_mutex_unlock(&v->lock);
393 } else {
394 int rc = volmgr_stop_volume(v, _cb_volume_stopped_for_eject, cb, false);
395 if (rc != -EINPROGRESS) {
396 if (rc)
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800397 LOGE("unable to shutdown volume '%s'", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800398 pthread_mutex_unlock(&v->lock);
399 }
400 }
401 return 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800402}
403
404static void _cb_volume_stopped_for_eject(volume_t *v, void *arg)
405{
406 void (* eject_cb) (blkdev_t *) = arg;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800407
408#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800409 LOG_VOL("Volume %s has been stopped for eject", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800410#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800411
412 eject_cb(v->dev);
413 v->dev = NULL; // Clear dev because its being ejected
414}
415
416/*
417 * Instructs the volume manager to enable or disable USB mass storage
418 * on any volumes configured to use it.
419 */
420int volmgr_enable_ums(boolean enable)
421{
422 volume_t *v = vol_root;
423
424 while(v) {
425 if (v->ums_path) {
426 int rc;
427
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800428 if (enable) {
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800429 pthread_mutex_lock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800430 if (v->state == volstate_mounted)
431 volmgr_send_eject_request(v);
432 else if (v->state == volstate_ums) {
433 pthread_mutex_unlock(&v->lock);
434 goto next_vol;
435 }
436
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800437 // Stop the volume, and enable UMS in the callback
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800438 rc = volmgr_shutdown_volume(v, _cb_volstopped_for_ums_enable, false);
439 if (rc != -EINPROGRESS) {
440 if (rc)
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800441 LOGE("unable to shutdown volume '%s'", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800442 pthread_mutex_unlock(&v->lock);
443 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800444 } else {
445 // Disable UMS
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800446 pthread_mutex_lock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800447 if (v->state != volstate_ums) {
448 pthread_mutex_unlock(&v->lock);
449 goto next_vol;
450 }
451
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800452 if ((rc = ums_disable(v->ums_path)) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800453 LOGE("unable to disable ums on '%s'", v->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800454 pthread_mutex_unlock(&v->lock);
455 continue;
456 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800457
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800458 LOG_VOL("Kick-starting volume %d:%d after UMS disable",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800459 v->dev->disk->major, v->dev->disk->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800460 // Start volume
461 if ((rc = _volmgr_consider_disk_and_vol(v, v->dev->disk)) < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800462 LOGE("volmgr failed to consider disk %d:%d",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800463 v->dev->disk->major, v->dev->disk->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800464 }
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800465 pthread_mutex_unlock(&v->lock);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800466 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800467 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800468 next_vol:
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800469 v = v->next;
470 }
471 return 0;
472}
473
474/*
475 * Static functions
476 */
477
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800478static int volmgr_send_eject_request(volume_t *v)
479{
480 return send_msg_with_data(VOLD_EVT_EJECTING, v->mount_point);
481}
482
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800483// vol->lock must be held!
484static int _volmgr_consider_disk_and_vol(volume_t *vol, blkdev_t *dev)
485{
486 int rc = 0;
487
488#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800489 LOG_VOL("volmgr_consider_disk_and_vol(%s, %d:%d):", vol->mount_point,
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800490 dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800491#endif
492
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800493 if (vol->state == volstate_unknown ||
494 vol->state == volstate_mounted ||
495 vol->state == volstate_mounted_ro ||
496 vol->state == volstate_damaged) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800497 LOGE("Cannot consider volume '%s' because it is in state '%d",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800498 vol->mount_point, vol->state);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800499 return -EADDRINUSE;
500 }
501
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800502 if (vol->state == volstate_formatting) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800503 LOG_VOL("Evaluating dev '%s' for formattable filesystems for '%s'",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800504 dev->devpath, vol->mount_point);
505 /*
506 * Since we only support creating 1 partition (right now),
507 * we can just lookup the target by devno
508 */
509 blkdev_t *part = blkdev_lookup_by_devno(dev->major, 1);
510 if (!part) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800511 part = blkdev_lookup_by_devno(dev->major, 0);
512 if (!part) {
513 LOGE("Unable to find device to format");
514 return -ENODEV;
515 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800516 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800517
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800518 if ((rc = format_partition(part,
519 vol->media_type == media_devmapper ?
520 FORMAT_TYPE_EXT2 : FORMAT_TYPE_FAT32)) < 0) {
521 LOGE("format failed (%d)", rc);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800522 return rc;
523 }
524
525 }
526
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800527 LOG_VOL("Evaluating dev '%s' for mountable filesystems for '%s'",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800528 dev->devpath, vol->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800529
530 if (dev->nr_parts == 0) {
531 rc = _volmgr_start(vol, dev);
532#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800533 LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d", vol->mount_point,
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800534 dev->major, dev->minor, rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800535#endif
536 } else {
537 /*
538 * Device has multiple partitions
539 * This is where interesting partition policies could be implemented.
540 * For now just try them in sequence until one succeeds
541 */
542
543 rc = -ENODEV;
544 int i;
545 for (i = 0; i < dev->nr_parts; i++) {
546 blkdev_t *part = blkdev_lookup_by_devno(dev->major, (i+1));
547 if (!part) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800548 LOGE("Error - unable to lookup partition for blkdev %d:%d", dev->major, (i+1));
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800549 continue;
550 }
551 rc = _volmgr_start(vol, part);
552#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800553 LOG_VOL("_volmgr_start(%s, %d:%d) rc = %d",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800554 vol->mount_point, part->major, part->minor, rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800555#endif
556 if (!rc)
557 break;
558 }
559
560 if (rc == -ENODEV) {
561 // Assert to make sure each partition had a backing blkdev
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800562 LOGE("Internal consistency error");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800563 return 0;
564 }
565 }
566
567 if (rc == -ENODATA) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800568 LOGE("Device %d:%d contains no usable filesystems",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800569 dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800570 rc = 0;
571 }
572
573 return rc;
574}
575
576static void volmgr_reaper_thread_sighandler(int signo)
577{
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800578 LOGE("Volume reaper thread got signal %d", signo);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800579}
580
581static void __reaper_cleanup(void *arg)
582{
583 volume_t *vol = (volume_t *) arg;
584
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800585 if (vol->worker_args.reaper_args.cb)
586 vol->worker_args.reaper_args.cb(vol, vol->worker_args.reaper_args.cb_arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800587
588 vol->worker_running = false;
589
590 // Wake up anyone that was waiting on this thread
591 pthread_mutex_unlock(&vol->worker_sem);
592
593 // Unlock the volume
594 pthread_mutex_unlock(&vol->lock);
595}
596
597static void *volmgr_reaper_thread(void *arg)
598{
599 volume_t *vol = (volume_t *) arg;
600
601 pthread_cleanup_push(__reaper_cleanup, arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800602
603 vol->worker_running = true;
604 vol->worker_pid = getpid();
605
606 struct sigaction actions;
607
608 memset(&actions, 0, sizeof(actions));
609 sigemptyset(&actions.sa_mask);
610 actions.sa_flags = 0;
611 actions.sa_handler = volmgr_reaper_thread_sighandler;
612 sigaction(SIGUSR1, &actions, NULL);
613
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800614 LOG_VOL("Reaper here - working on %s", vol->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800615
616 boolean send_sig_kill = false;
617 int i, rc;
618
619 for (i = 0; i < 10; i++) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800620 errno = 0;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800621 rc = umount(vol->mount_point);
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800622 LOG_VOL("volmngr reaper umount(%s) attempt %d (%s)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800623 vol->mount_point, i + 1, strerror(errno));
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800624 if (!rc)
625 break;
626 if (rc && (errno == EINVAL || errno == ENOENT)) {
627 rc = 0;
628 break;
629 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800630 sleep(1);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800631 if (i >= 4) {
632 KillProcessesWithOpenFiles(vol->mount_point, send_sig_kill, NULL, 0);
633 if (!send_sig_kill)
634 send_sig_kill = true;
635 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800636 }
637
638 if (!rc) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800639 LOG_VOL("Reaper sucessfully unmounted %s", vol->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800640 vol->fs = NULL;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800641 volume_setstate(vol, volstate_unmounted);
642 } else {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800643 LOGE("Unable to unmount!! (%d)", rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800644 }
645
646 out:
647 pthread_cleanup_pop(1);
648 pthread_exit(NULL);
649 return NULL;
650}
651
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800652// vol->lock must be held!
653static 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 -0800654{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800655
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800656 if (vol->worker_running) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800657 LOGE("Worker thread is currently running.. waiting..");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800658 pthread_mutex_lock(&vol->worker_sem);
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800659 LOG_VOL("Worker thread now available");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800660 }
661
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800662 vol->worker_args.reaper_args.cb = cb;
663 vol->worker_args.reaper_args.cb_arg = arg;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800664
665 pthread_attr_t attr;
666 pthread_attr_init(&attr);
667 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
668
669 pthread_create(&vol->worker_thread, &attr, volmgr_reaper_thread, vol);
670}
671
672static int volmgr_stop_volume(volume_t *v, void (*cb) (volume_t *, void *), void *arg, boolean emit_statechange)
673{
674 int i, rc;
675
676 if (v->state == volstate_mounted || v->state == volstate_badremoval) {
677 // Try to unmount right away (5 retries)
678 for (i = 0; i < 5; i++) {
679 rc = umount(v->mount_point);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800680 if (!rc)
681 break;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800682
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800683 if (rc && (errno == EINVAL || errno == ENOENT)) {
684 rc = 0;
685 break;
686 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800687
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800688 LOG_VOL("volmngr quick stop umount(%s) attempt %d (%s)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800689 v->mount_point, i + 1, strerror(errno));
690
691 if (i == 0)
692 usleep(1000 * 250); // First failure, sleep for 250 ms
693 else
694 sched_yield();
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800695 }
696
697 if (!rc) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800698 LOG_VOL("volmgr_stop_volume(%s): Volume unmounted sucessfully",
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800699 v->mount_point);
700 if (emit_statechange)
701 volume_setstate(v, volstate_unmounted);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800702 v->fs = NULL;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800703 goto out_cb_immed;
704 }
705
706 /*
707 * Since the volume is still in use, dispatch the stopping to
708 * a thread
709 */
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800710 LOG_VOL("Volume %s is busy (%d) - uncaging the reaper", v->mount_point, rc);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800711 volmgr_uncage_reaper(v, cb, arg);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800712 return -EINPROGRESS;
713 } else if (v->state == volstate_checking) {
714 volume_setstate(v, volstate_unmounted);
715 if (v->worker_running) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800716 LOG_VOL("Cancelling worker thread");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800717 pthread_kill(v->worker_thread, SIGUSR1);
718 } else
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800719 LOGE("Strange... we were in checking state but worker thread wasn't running..");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800720 goto out_cb_immed;
721 }
722
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800723 out_cb_immed:
724 if (cb)
725 cb(v, arg);
726 return 0;
727}
728
729
730/*
731 * Gracefully stop a volume
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800732 * v->lock must be held!
733 * if we return -EINPROGRESS, do NOT release the lock as the reaper
734 * is using the volume
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800735 */
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800736static 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 -0800737{
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800738 return volmgr_stop_volume(v, cb, NULL, emit_statechange);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800739}
740
741static void _cb_volume_stopped_for_shutdown(volume_t *v, void *arg)
742{
743 void (* shutdown_cb) (volume_t *) = arg;
744
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800745#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800746 LOG_VOL("Volume %s has been stopped for shutdown", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800747#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800748 shutdown_cb(v);
749}
750
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800751
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800752/*
753 * Called when a volume is sucessfully unmounted for UMS enable
754 */
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800755static void _cb_volstopped_for_ums_enable(volume_t *v, void *arg)
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800756{
757 int rc;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800758 char *devdir_path;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800759
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800760#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800761 LOG_VOL("_cb_volstopped_for_ums_enable(%s):", v->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800762#endif
763 devdir_path = blkdev_get_devpath(v->dev->disk);
764
765 if ((rc = ums_enable(devdir_path, v->ums_path)) < 0) {
766 free(devdir_path);
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800767 LOGE("Error enabling ums (%d)", rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800768 return;
769 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800770 free(devdir_path);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800771 volume_setstate(v, volstate_ums);
The Android Open Source Projectdcf3ce22009-01-22 00:13:45 -0800772 pthread_mutex_unlock(&v->lock);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800773}
774
775static int volmgr_readconfig(char *cfg_path)
776{
777 cnode *root = config_node("", "");
778 cnode *node;
779
780 config_load_file(root, cfg_path);
781 node = root->first_child;
782
783 while (node) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800784 if (!strncmp(node->name, "volume_", 7))
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800785 volmgr_config_volume(node);
786 else
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800787 LOGE("Skipping unknown configuration node '%s'", node->name);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800788 node = node->next;
789 }
790 return 0;
791}
792
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800793static void volmgr_add_mediapath_to_volume(volume_t *v, char *media_path)
794{
795 int i;
796
797#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800798 LOG_VOL("volmgr_add_mediapath_to_volume(%p, %s):", v, media_path);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800799#endif
800 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
801 if (!v->media_paths[i]) {
802 v->media_paths[i] = strdup(media_path);
803 return;
804 }
805 }
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800806 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 -0800807}
808
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800809static int volmgr_config_volume(cnode *node)
810{
811 volume_t *new;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800812 int rc = 0, i;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800813
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800814 char *dm_src, *dm_src_type, *dm_tgt, *dm_param, *dm_tgtfs;
815 uint32_t dm_size_mb = 0;
816
817 dm_src = dm_src_type = dm_tgt = dm_param = dm_tgtfs = NULL;
818#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800819 LOG_VOL("volmgr_configure_volume(%s):", node->name);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800820#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800821 if (!(new = malloc(sizeof(volume_t))))
822 return -ENOMEM;
823 memset(new, 0, sizeof(volume_t));
824
825 new->state = volstate_nomedia;
826 pthread_mutex_init(&new->lock, NULL);
827 pthread_mutex_init(&new->worker_sem, NULL);
828
829 cnode *child = node->first_child;
830
831 while (child) {
832 if (!strcmp(child->name, "media_path"))
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800833 volmgr_add_mediapath_to_volume(new, child->value);
834 else if (!strcmp(child->name, "emu_media_path"))
835 volmgr_add_mediapath_to_volume(new, child->value);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800836 else if (!strcmp(child->name, "media_type")) {
837 if (!strcmp(child->value, "mmc"))
838 new->media_type = media_mmc;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800839 else if (!strcmp(child->value, "devmapper"))
840 new->media_type = media_devmapper;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800841 else {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800842 LOGE("Invalid media type '%s'", child->value);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800843 rc = -EINVAL;
844 goto out_free;
845 }
846 } else if (!strcmp(child->name, "mount_point"))
847 new->mount_point = strdup(child->value);
848 else if (!strcmp(child->name, "ums_path"))
849 new->ums_path = strdup(child->value);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800850 else if (!strcmp(child->name, "dm_src"))
851 dm_src = strdup(child->value);
852 else if (!strcmp(child->name, "dm_src_type"))
853 dm_src_type = strdup(child->value);
854 else if (!strcmp(child->name, "dm_src_size_mb"))
855 dm_size_mb = atoi(child->value);
856 else if (!strcmp(child->name, "dm_target"))
857 dm_tgt = strdup(child->value);
858 else if (!strcmp(child->name, "dm_target_params"))
859 dm_param = strdup(child->value);
860 else if (!strcmp(child->name, "dm_target_fs"))
861 dm_tgtfs = strdup(child->value);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800862 else
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800863 LOGE("Ignoring unknown config entry '%s'", child->name);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800864 child = child->next;
865 }
866
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800867 if (new->media_type == media_mmc) {
868 if (!new->media_paths[0] || !new->mount_point || new->media_type == media_unknown) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800869 LOGE("Required configuration parameter missing for mmc volume");
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800870 rc = -EINVAL;
871 goto out_free;
872 }
873 } else if (new->media_type == media_devmapper) {
874 if (!dm_src || !dm_src_type || !dm_tgt ||
875 !dm_param || !dm_tgtfs || !dm_size_mb) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800876 LOGE("Required configuration parameter missing for devmapper volume");
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800877 rc = -EINVAL;
878 goto out_free;
879 }
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800880
881 char dm_mediapath[255];
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800882 if (!(new->dm = devmapper_init(dm_src, dm_src_type, dm_size_mb,
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800883 dm_tgt, dm_param, dm_tgtfs, dm_mediapath))) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800884 LOGE("Unable to initialize devmapping");
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800885 goto out_free;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800886 }
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800887 LOG_VOL("media path for devmapper volume = '%s'", dm_mediapath);
888 volmgr_add_mediapath_to_volume(new, dm_mediapath);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800889 }
890
891 if (!vol_root)
892 vol_root = new;
893 else {
894 volume_t *scan = vol_root;
895 while (scan->next)
896 scan = scan->next;
897 scan->next = new;
898 }
899
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800900 if (dm_src)
901 free(dm_src);
902 if (dm_src_type)
903 free(dm_src_type);
904 if (dm_tgt)
905 free(dm_tgt);
906 if (dm_param)
907 free(dm_param);
908 if (dm_tgtfs)
909 free(dm_tgtfs);
910
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800911 return rc;
912
913 out_free:
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800914
915 if (dm_src)
916 free(dm_src);
917 if (dm_src_type)
918 free(dm_src_type);
919 if (dm_tgt)
920 free(dm_tgt);
921 if (dm_param)
922 free(dm_param);
923 if (dm_tgtfs)
924 free(dm_tgtfs);
925
926
927 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
928 if (new->media_paths[i])
929 free(new->media_paths[i]);
930 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800931 if (new->mount_point)
932 free(new->mount_point);
933 if (new->ums_path)
934 free(new->ums_path);
935 return rc;
936}
937
938static volume_t *volmgr_lookup_volume_by_dev(blkdev_t *dev)
939{
940 volume_t *scan = vol_root;
941 while(scan) {
942 if (scan->dev == dev)
943 return scan;
944 scan = scan->next;
945 }
946 return NULL;
947}
948
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800949static volume_t *volmgr_lookup_volume_by_mountpoint(char *mount_point, boolean leave_locked)
950{
951 volume_t *v = vol_root;
952
953 while(v) {
954 pthread_mutex_lock(&v->lock);
955 if (!strcmp(v->mount_point, mount_point)) {
956 if (!leave_locked)
957 pthread_mutex_unlock(&v->lock);
958 return v;
959 }
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -0800960 pthread_mutex_unlock(&v->lock);
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800961 v = v->next;
962 }
963 return NULL;
964}
965
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800966static volume_t *volmgr_lookup_volume_by_mediapath(char *media_path, boolean fuzzy)
967{
968 volume_t *scan = vol_root;
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800969 int i;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800970
971 while (scan) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800972
973 for (i = 0; i < VOLMGR_MAX_MEDIAPATHS_PER_VOLUME; i++) {
974 if (!scan->media_paths[i])
975 continue;
976
977 if (fuzzy && !strncmp(media_path, scan->media_paths[i], strlen(scan->media_paths[i])))
978 return scan;
979 else if (!fuzzy && !strcmp(media_path, scan->media_paths[i]))
980 return scan;
981 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800982
983 scan = scan->next;
984 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -0800985 return NULL;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -0800986}
987
988/*
989 * Attempt to bring a volume online
990 * Returns: 0 on success, errno on failure, with the following exceptions:
991 * - ENODATA - Unsupported filesystem type / blank
992 * vol->lock MUST be held!
993 */
994static int _volmgr_start(volume_t *vol, blkdev_t *dev)
995{
996 struct volmgr_fstable_entry *fs;
997 int rc = ENODATA;
998
999#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001000 LOG_VOL("_volmgr_start(%s, %d:%d):", vol->mount_point,
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001001 dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001002#endif
1003
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001004 if (vol->state == volstate_mounted) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001005 LOGE("Unable to start volume '%s' (already mounted)", vol->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001006 return -EBUSY;
1007 }
1008
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001009 for (fs = fs_table; fs->name; fs++) {
1010 if (!fs->identify_fn(dev))
1011 break;
1012 }
1013
1014 if (!fs) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001015 LOGE("No supported filesystems on %d:%d", dev->major, dev->minor);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001016 volume_setstate(vol, volstate_nofs);
1017 return -ENODATA;
1018 }
1019
1020 return volmgr_start_fs(fs, vol, dev);
1021}
1022
1023// vol->lock MUST be held!
1024static int volmgr_start_fs(struct volmgr_fstable_entry *fs, volume_t *vol, blkdev_t *dev)
1025{
1026 /*
1027 * Spawn a thread to do the actual checking / mounting in
1028 */
1029
1030 if (vol->worker_running) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001031 LOGE("Worker thread is currently running.. waiting..");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001032 pthread_mutex_lock(&vol->worker_sem);
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001033 LOG_VOL("Worker thread now available");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001034 }
1035
1036 vol->dev = dev;
1037
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001038 vol->worker_args.start_args.fs = fs;
1039 vol->worker_args.start_args.dev = dev;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001040
1041 pthread_attr_t attr;
1042 pthread_attr_init(&attr);
1043 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
1044
1045 pthread_create(&vol->worker_thread, &attr, volmgr_start_fs_thread, vol);
1046
1047 return 0;
1048}
1049
1050static void __start_fs_thread_lock_cleanup(void *arg)
1051{
1052 volume_t *vol = (volume_t *) arg;
1053
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001054#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001055 LOG_VOL("__start_fs_thread_lock_cleanup(%s):", vol->mount_point);
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001056#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001057
1058 vol->worker_running = false;
1059
1060 // Wake up anyone that was waiting on this thread
1061 pthread_mutex_unlock(&vol->worker_sem);
1062
1063 // Unlock the volume
1064 pthread_mutex_unlock(&vol->lock);
1065}
1066
1067static void *volmgr_start_fs_thread(void *arg)
1068{
1069 volume_t *vol = (volume_t *) arg;
1070
1071 pthread_cleanup_push(__start_fs_thread_lock_cleanup, arg);
1072 pthread_mutex_lock(&vol->lock);
1073
1074 vol->worker_running = true;
1075 vol->worker_pid = getpid();
1076
1077 struct sigaction actions;
1078
1079 memset(&actions, 0, sizeof(actions));
1080 sigemptyset(&actions.sa_mask);
1081 actions.sa_flags = 0;
1082 actions.sa_handler = volmgr_start_fs_thread_sighandler;
1083 sigaction(SIGUSR1, &actions, NULL);
1084
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001085 struct volmgr_fstable_entry *fs = vol->worker_args.start_args.fs;
1086 blkdev_t *dev = vol->worker_args.start_args.dev;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001087 int rc;
1088
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001089#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001090 LOG_VOL("Worker thread pid %d starting %s fs %d:%d on %s", getpid(),
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001091 fs->name, dev->major, dev->minor, vol->mount_point);
1092#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001093
1094 if (fs->check_fn) {
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001095#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001096 LOG_VOL("Starting %s filesystem check on %d:%d", fs->name,
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001097 dev->major, dev->minor);
1098#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001099 volume_setstate(vol, volstate_checking);
1100 pthread_mutex_unlock(&vol->lock);
1101 rc = fs->check_fn(dev);
1102 pthread_mutex_lock(&vol->lock);
1103 if (vol->state != volstate_checking) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001104 LOG_VOL("filesystem check aborted");
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001105 goto out;
1106 }
1107
1108 if (rc < 0) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001109 LOGE("%s filesystem check failed on %d:%d (%s)", fs->name,
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001110 dev->major, dev->minor, strerror(-rc));
1111 if (rc == -ENODATA) {
1112 volume_setstate(vol, volstate_nofs);
1113 goto out;
1114 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001115 goto out_unmountable;
1116 }
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001117#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001118 LOG_VOL("%s filesystem check of %d:%d OK", fs->name,
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001119 dev->major, dev->minor);
1120#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001121 }
1122
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001123 rc = fs->mount_fn(dev, vol, safe_mode);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001124 if (!rc) {
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001125 LOG_VOL("Sucessfully mounted %s filesystem %d:%d on %s (safe-mode %s)",
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001126 fs->name, dev->major, dev->minor, vol->mount_point,
1127 (safe_mode ? "on" : "off"));
1128 vol->fs = fs;
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001129 volume_setstate(vol, volstate_mounted);
1130 goto out;
1131 }
1132
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001133 LOGE("%s filesystem mount of %d:%d failed (%d)", fs->name, dev->major,
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001134 dev->minor, rc);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001135
1136 out_unmountable:
1137 volume_setstate(vol, volstate_damaged);
1138 out:
1139 pthread_cleanup_pop(1);
1140 pthread_exit(NULL);
1141 return NULL;
1142}
1143
1144static void volmgr_start_fs_thread_sighandler(int signo)
1145{
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001146 LOGE("Volume startup thread got signal %d", signo);
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001147}
1148
1149static void volume_setstate(volume_t *vol, volume_state_t state)
1150{
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001151 if (state == vol->state)
1152 return;
1153
1154#if DEBUG_VOLMGR
The Android Open Source Project1b8e5a62009-02-13 12:57:54 -08001155 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 -08001156#endif
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001157
1158 vol->state = state;
1159
1160 char *prop_val = conv_volstate_to_propstr(vol->state);
1161
The Android Open Source Project13f797d2009-02-10 15:44:07 -08001162 if (prop_val) {
1163 property_set(PROP_EXTERNAL_STORAGE_STATE, prop_val);
1164 volume_send_state(vol);
1165 }
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001166}
1167
1168static int volume_send_state(volume_t *vol)
1169{
1170 char *event = conv_volstate_to_eventstr(vol->state);
1171
1172 return send_msg_with_data(event, vol->mount_point);
1173}
1174
1175static char *conv_volstate_to_eventstr(volume_state_t state)
1176{
1177 int i;
1178
1179 for (i = 0; volume_state_strings[i].event != NULL; i++) {
1180 if (volume_state_strings[i].state == state)
1181 break;
1182 }
1183
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001184 return volume_state_strings[i].event;
1185}
1186
1187static char *conv_volstate_to_propstr(volume_state_t state)
1188{
1189 int i;
1190
1191 for (i = 0; volume_state_strings[i].event != NULL; i++) {
1192 if (volume_state_strings[i].state == state)
1193 break;
1194 }
1195
The Android Open Source Project8ac3a132009-01-20 14:04:01 -08001196 return volume_state_strings[i].property_val;
1197}
1198