4 * Copyright (c) 2012 - 2015 Samsung Electronics Co., Ltd.
6 * Licensed under the Apache License, Version 2.0 (the License);
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
27 #include <sys/mount.h>
28 #include <sys/statvfs.h>
32 #include <sys/statfs.h>
39 #include <tzplatform_config.h>
40 #include <app2ext_interface.h>
42 #include <blkid/blkid.h>
44 #include <glib/gstdio.h>
46 #include <libsyscommon/libgdbus.h>
47 #include <libsyscommon/ini-parser.h>
48 #include <libsyscommon/list.h>
49 #ifdef EXTENDED_STORAGE
54 #include "module-intf.h"
57 #include "fd_handler.h"
60 #include "storaged_common.h"
63 * TODO Assume root device is always mmcblk0*.
65 #define MMC_PATH "*/mmcblk[0-9]*"
66 #define MMC_PARTITION_PATH "mmcblk[0-9]p[0-9]"
67 /* Emulator send devlink for sdcard as \*\/sdcard\/\* */
68 #define MMC_LINK_PATH "*/sdcard/*"
69 #define SCSI_PATH "*/sd[a-z]*"
70 #define SCSI_PARTITION_PATH "sd[a-z][0-9]"
71 #define SCSI_PARTITION_LENGTH 9
72 #define EXTENDEDSD_NODE_PATH "/dev/mapper/extendedsd"
74 #define FILESYSTEM_NAME "filesystem"
76 #define DEV_PREFIX "/dev/"
79 #define UNMOUNT_RETRY 5
80 #define TIMEOUT_MAKE_OBJECT 500 /* milliseconds */
82 #define SIGNAL_POWEROFF_STATE "ChangeState"
83 #define METHOD_ADD_POWEROFF_WAIT "AddPowerOffWait"
84 #define METHOD_REMOVE_POWEROFF_WAIT "RemovePowerOffWait"
86 #define BLOCK_DEVICE_ADDED "DeviceAdded"
87 #define BLOCK_DEVICE_REMOVED "DeviceRemoved"
88 #define BLOCK_DEVICE_BLOCKED "DeviceBlocked"
89 #define BLOCK_DEVICE_CHANGED "DeviceChanged"
91 #define BLOCK_TYPE_MMC "mmc"
92 #define BLOCK_TYPE_SCSI "scsi"
93 #define BLOCK_TYPE_ALL "all"
95 #define BLOCK_MMC_NODE_PREFIX "SDCard"
96 #define BLOCK_SCSI_NODE_PREFIX "USBDrive"
98 #define BLOCK_CONF_FILE "/etc/storaged/block.conf"
100 #define EXTERNAL_STORAGE_PATH "/run/storaged/external-storage"
101 #define EXTENDED_INTERNAL_PATH "/run/storaged/extended-internal-sd"
104 #define EXTENDEDSD_MOUNT_PATH "/opt/extendedsd"
106 #define VFAT_NAME "vfat"
107 #define EXFAT_NAME "exfat"
108 #define EXT4_NAME "ext4"
109 #define LUKS_NAME "crypto_LUKS"
110 #define EXTENDEDSD_NAME "extendedsd"
112 /* Minimum value of block id */
113 #define BLOCK_ID_MIN 10
114 /* For 2.4 Backward Compatibility */
115 #define EXT_PRIMARY_SD_FIXID 1
117 /* Maximum number of thread */
120 #define SPEEDCHECK_SIZE 16
121 #define SPEEDCHECK_CRITERION 4 /* MB/s */
123 #define PKGDIR_BUS_NAME "org.tizen.pkgdir_tool"
124 #define PKGDIR_PATH "/org/tizen/pkgdir_tool"
125 #define PKGDIR_INTERFACE "org.tizen.pkgdir_tool"
127 #define POPUP_KEY_CONTENT "_SYSPOPUP_CONTENT_"
128 #define VIEWTYPE_KEY "viewtype"
129 #define DEVPATH_KEY "dev_path"
130 #define MAPPING_NODE_KEY "mapping_node"
131 #define INSERT_SD_CARD "INSERT_SD_CARD"
133 #define MMC_POPUP_NOTI "SDcardNoti"
134 #define MMC_INSERTED "inserted"
135 #define MMC_REMOVED "removed"
137 #define ARRAY_SIZE(name) (sizeof(name)/sizeof(name[0]))
139 #define FILE_NAME_LEN_MAX 255
141 enum block_dev_operation {
150 enum private_operation_state {
156 struct operation_queue {
157 enum block_dev_operation op;
158 GDBusMethodInvocation *invocation;
163 struct block_device {
164 struct block_data *data;
166 int thread_id; /* Current thread ID */
167 bool removed; /* True when device is physically removed but operation is not precessed yet */
168 enum private_operation_state on_private_op;
169 bool mount_point_updated;
174 struct block_device *bdev;
176 enum unmount_operation option;
180 enum block_dev_operation op;
181 struct block_device *bdev;
185 static struct block_conf {
187 bool extendedinternal;
188 } block_conf[BLOCK_EXTENDEDSD_DEV + 1];
190 static struct manage_thread {
191 GList *th_node_list; /* List of devnode which thread dealt with. Only main thread access */
192 GList *block_dev_list; /* Use thread mutex */
194 pthread_mutex_t mutex;
196 int num_dev; /* Number of devices which thread holds. Only main thread access */
197 int op_len; /* Number of operation of thread. Use thread mutex */
198 int thread_id; /* Never changed */
200 } th_manager[THREAD_MAX];
202 char mmc_default_path[][FILE_NAME_LEN_MAX + 1] = {
209 #define DIR_NUM ((int)(sizeof(mmc_default_path)/sizeof(mmc_default_path[0])))
211 static GList *fs_head;
212 static GList *block_ops_list;
215 static fd_handler_h phandler;
216 static bool block_control = false;
217 static bool block_boot = false;
218 static pthread_mutex_t pipe_mutex = PTHREAD_MUTEX_INITIALIZER;
219 static bool add_poweroff_wait = false;
221 /* Assume there is only one physical internal storage */
222 static int dev_internal = -1;
223 static char dev_internal_scsi = '\0';
224 static char dev_internal_emul = '\0';
226 static int block_start(void *data);
227 static int block_stop(void *data);
229 static int add_operation(struct block_device *bdev,
230 enum block_dev_operation operation,
231 GDBusMethodInvocation *invocation, void *data);
232 static void remove_operation(struct block_device *bdev);
233 static void check_removed(struct block_device *bdev, GList **queue, struct operation_queue **op);
234 static bool check_unmount(struct block_device *bdev, GList **queue, struct operation_queue **op);
235 static int change_mount_point(struct block_device *bdev, const char *mount_point);
236 static void terminate_threads(void);
238 #define nullstr(x) (x ? x : "")
239 static GVariant *block_data_to_gvariant(struct block_data *data, int flags);
241 #define block_send_dbus_reply(invocation, result) if (invocation) {g_dbus_method_invocation_return_value(invocation, g_variant_new("(i)", result)); }
243 static void uevent_block_handler(struct udev_device *dev);
244 static struct uevent_handler uh = {
245 .subsystem = BLOCK_SUBSYSTEM,
246 .uevent_func = uevent_block_handler,
249 static void __CONSTRUCTOR__ smack_check(void)
254 fp = fopen("/proc/filesystems", "r");
258 while (fgets(buf, sizeof(buf), fp) != NULL) {
259 if (strstr(buf, "smackfs")) {
268 void add_fs(const struct block_fs_ops *fs)
270 SYS_G_LIST_APPEND(fs_head, (void *)fs);
273 void remove_fs(const struct block_fs_ops *fs)
275 SYS_G_LIST_REMOVE(fs_head, (void *)fs);
278 const struct block_fs_ops *find_fs(enum block_fs_type type)
280 struct block_fs_ops *fs;
283 SYS_G_LIST_FOREACH(fs_head, elem, fs) {
284 if (fs->type == type)
290 void add_block_dev(const struct block_dev_ops *ops)
292 SYS_G_LIST_APPEND(block_ops_list, (void *)ops);
295 void remove_block_dev(const struct block_dev_ops *ops)
297 SYS_G_LIST_REMOVE(block_ops_list, (void *)ops);
300 static void broadcast_block_info(enum block_dev_operation op,
301 struct block_data *data, int result)
303 struct block_dev_ops *ops;
306 if (data->primary != true)
309 SYS_G_LIST_FOREACH(block_ops_list, elem, ops) {
310 int data_block_type = (data->block_type == BLOCK_EXTENDEDSD_DEV)
311 ? BLOCK_MMC_DEV : data->block_type;
313 if (ops->block_type != data_block_type)
315 // TODO What happend on extended internal storage case?
316 if (op == BLOCK_DEV_MOUNT) {
317 ops->mounted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
318 } else if (op == BLOCK_DEV_UNMOUNT) {
319 ops->unmounted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
320 } else if (op == BLOCK_DEV_FORMAT) {
321 ops->formatted(data, result, data->block_type == BLOCK_EXTENDEDSD_DEV);
322 } else if (op == BLOCK_DEV_INSERT)
324 else if (op == BLOCK_DEV_REMOVE)
329 // Called by MainThread - Insert
330 static int block_get_new_id(void)
332 static int id = BLOCK_ID_MIN;
333 struct block_device *bdev;
338 for (i = 0 ; i < INT_MAX ; i++) {
340 for (j = 0; j < THREAD_MAX; j++) {
341 pthread_mutex_lock(&(th_manager[j].mutex));
342 SYS_G_LIST_FOREACH(th_manager[j].block_dev_list, elem, bdev) {
343 if (bdev->data->id == id) {
348 pthread_mutex_unlock(&(th_manager[j].mutex));
363 static void remove_file(int id, bool extendedsd)
365 char file_name[PATH_LEN];
372 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
374 snprintf(file_name, sizeof(file_name), EXTERNAL_STORAGE_PATH"/%d", id);
376 ret_val = remove(file_name);
378 _E("Failed to remove '%s': %d", file_name, errno);
381 static void create_file(int id, char *mount_point, bool extendedsd)
384 char file_name[PATH_LEN];
390 snprintf(file_name, PATH_LEN, EXTENDED_INTERNAL_PATH"/%d", id);
392 snprintf(file_name, PATH_LEN, EXTERNAL_STORAGE_PATH"/%d", id);
394 fp = fopen(file_name, "w+");
396 fprintf(fp, "%s", mount_point);
399 _E("Failed to open '%s'.", file_name);
402 static void broadcast_device_blocked(struct block_device *bdev)
404 struct block_data *data;
407 if (!bdev || !bdev->data)
412 ret_dbus = gdbus_signal_emit(NULL,
413 STORAGED_PATH_BLOCK_MANAGER,
414 STORAGED_INTERFACE_BLOCK_MANAGER,
415 BLOCK_DEVICE_BLOCKED,
416 block_data_to_gvariant(data, 0));
418 _E("Failed to send dbus signal");
421 static void broadcast_device_changed(struct block_device *bdev,
422 enum block_dev_operation op)
424 struct block_data *data;
425 GVariant *param = NULL;
426 const char *signal_name = NULL;
430 if (!bdev || !bdev->data) {
431 _E("Failed to broadcast device changed signal. op(%d)", op);
437 /* set flags and signal name */
439 case BLOCK_DEV_MOUNT:
440 BLOCK_GET_MOUNT_FLAGS(data, flags);
441 signal_name = BLOCK_DEVICE_CHANGED;
443 case BLOCK_DEV_UNMOUNT:
444 BLOCK_GET_UNMOUNT_FLAGS(data, flags);
445 signal_name = BLOCK_DEVICE_CHANGED;
447 case BLOCK_DEV_FORMAT:
448 BLOCK_GET_FORMAT_FLAGS(data, flags);
449 signal_name = BLOCK_DEVICE_CHANGED;
451 case BLOCK_DEV_INSERT:
453 signal_name = BLOCK_DEVICE_ADDED;
455 case BLOCK_DEV_REMOVE:
457 signal_name = BLOCK_DEVICE_REMOVED;
461 _E("Failed to broadcast device changed signal. op(%d)", op);
465 /* Broadcast outside with BlockManager iface */
466 param = block_data_to_gvariant(data, flags);
468 ret_dbus = gdbus_signal_emit(NULL,
469 STORAGED_PATH_BLOCK_MANAGER,
470 STORAGED_INTERFACE_BLOCK_MANAGER,
474 _E("Failed to broadcast device changed signal. op(%d)", op);
477 static int get_mmc_mount_node(char *devnode, char *node, size_t len)
479 char *name = devnode;
480 int dev = -1, part = -1;
481 char emul[32] = { 0, };
488 sscanf(name, "mmcblk%dp%d", &dev, &part);
491 snprintf(node, len, "%s%c", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1);
493 snprintf(node, len, "%s%c%d", BLOCK_MMC_NODE_PREFIX, dev + 'A' - 1, part);
498 sscanf(name, "vd%31s", emul);
501 for (i = 0 ; i < strlen(emul) ; i++)
502 emul[i] = toupper(emul[i]);
503 snprintf(node, len, "%s%s", BLOCK_MMC_NODE_PREFIX, emul);
507 static int get_scsi_mount_node(char *devnode, char *node, size_t len)
515 snprintf(dev, sizeof(dev), "%s", devnode);
517 if (!strstr(dev, "sd"))
521 name += strlen("sd");
523 for (i = 0 ; i < strlen(name) ; i++)
524 name[i] = toupper(name[i]);
525 snprintf(node, len, "%s%s", BLOCK_SCSI_NODE_PREFIX, name);
530 static char *generate_mount_path(struct block_data *data)
533 char *name, node[64];
536 if (!data || !data->devnode || !data->fs_usage || (strcmp(data->fs_usage, FILESYSTEM_NAME) && strncmp(data->fs_usage, "crypto", strlen("crypto"))))
539 name = strrchr(data->devnode, '/');
544 switch (data->block_type) {
546 ret_val = get_mmc_mount_node(name, node, sizeof(node));
549 ret_val = get_scsi_mount_node(name, node, sizeof(node));
551 case BLOCK_EXTENDEDSD_DEV:
552 return strdup(EXTENDEDSD_MOUNT_PATH);
554 _E("Invalid block type(%d).", data->block_type);
560 str = tzplatform_mkpath(TZ_SYS_MEDIA, node);
566 _E("Invalid devnode(%s).", data->devnode ? data->devnode : "NULL");
570 static bool check_primary_partition(const char *devnode)
572 struct block_fs_ops *fs;
575 const char *filesystem = NULL;
585 if (fnmatch(MMC_LINK_PATH, devnode, 0) &&
586 fnmatch(MMC_PATH, devnode, 0) &&
587 fnmatch(SCSI_PATH, devnode, 0) &&
588 fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0))
591 temp = strrchr(devnode, '/');
594 if (fnmatch("/"SCSI_PARTITION_PATH, temp, 0) &&
595 fnmatch("/"MMC_PARTITION_PATH, temp, 0))
598 /* Emulator support only one partition */
602 snprintf(str, sizeof(str), "%s", devnode);
607 for (i = 1; i <= 9; ++i) {
608 if ((ret_val = snprintf(str2, sizeof(str2), "%s%d", str, i)) > sizeof(str2) - 1) {
609 _E("Filename is longer than buffer. Need %d size of buffer.", ret_val + 1);
613 if (access(str2, R_OK) != 0)
616 probe = blkid_new_probe_from_filename(str2);
619 if (blkid_do_probe(probe) != 0)
622 ret_val = blkid_probe_lookup_value(probe, "TYPE", &filesystem, &fs_len);
624 blkid_free_probe(probe);
627 SYS_G_LIST_FOREACH(fs_head, elem, fs) {
628 if (!strncmp(fs->name, filesystem, fs_len)) {
633 blkid_free_probe(probe);
639 if (found && !strncmp(devnode, str2, strlen(str2) + 1))
645 /* Whole data in struct block_data should be freed. */
646 static struct block_data *make_block_data(const char *devnode,
648 const char *fs_usage,
650 const char *fs_version,
651 const char *fs_uuid_enc,
652 const char *readonly)
654 struct block_data *data;
656 /* devnode is unique value so it should exist. */
661 _I("Unknown fs type.");
663 data = calloc(1, sizeof(struct block_data));
665 _E("Failed to calloc().");
669 data->devnode = strdup(devnode);
671 data->syspath = strdup(syspath);
673 data->fs_usage = strdup(fs_usage);
675 data->fs_type = strdup(fs_type);
677 data->fs_version = strdup(fs_version);
679 data->fs_uuid_enc = strdup(fs_uuid_enc);
681 data->readonly = atoi(readonly);
682 data->primary = check_primary_partition(devnode);
684 /* TODO should we know block dev type? */
685 if (!fnmatch(MMC_LINK_PATH, devnode, 0))
686 data->block_type = BLOCK_MMC_DEV;
687 else if (!fnmatch(MMC_PATH, devnode, 0))
688 data->block_type = BLOCK_MMC_DEV;
689 else if (!fnmatch(SCSI_PATH, devnode, 0))
690 data->block_type = BLOCK_SCSI_DEV;
691 else if (!fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0))
692 data->block_type = BLOCK_EXTENDEDSD_DEV;
694 data->block_type = -1;
696 data->mount_point = generate_mount_path(data);
697 BLOCK_FLAG_CLEAR_ALL(data);
699 /* for 2.4 backward compatibility */
700 // What if storage id 1 is existed? (multi sdcard case)
701 if (data->primary == true && data->block_type == BLOCK_MMC_DEV &&
702 data->fs_usage && !strcmp(data->fs_usage, FILESYSTEM_NAME))
703 data->id = EXT_PRIMARY_SD_FIXID;
705 data->id = block_get_new_id();
710 static void free_block_data(struct block_data *data)
716 free(data->fs_usage);
718 free(data->fs_version);
719 free(data->fs_uuid_enc);
720 free(data->mount_point);
724 static int update_block_data(struct block_data *data,
725 const char *fs_usage,
727 const char *fs_version,
728 const char *fs_uuid_enc,
729 const char *readonly,
730 bool mount_point_updated)
735 free(data->fs_usage);
736 data->fs_usage = NULL;
738 data->fs_usage = strdup(fs_usage);
741 data->fs_type = NULL;
743 data->fs_type = strdup(fs_type);
745 free(data->fs_version);
746 data->fs_version = NULL;
748 data->fs_version = strdup(fs_version);
750 free(data->fs_uuid_enc);
751 data->fs_uuid_enc = NULL;
753 data->fs_uuid_enc = strdup(fs_uuid_enc);
755 /* generate_mount_path function should be invoked
756 * after fs_uuid_enc is updated */
757 if (!mount_point_updated) {
758 free(data->mount_point);
759 data->mount_point = generate_mount_path(data);
762 data->readonly = false;
764 data->readonly = atoi(readonly);
766 BLOCK_FLAG_MOUNT_CLEAR(data);
771 static struct block_device *make_block_device(struct block_data *data)
773 struct block_device *bdev;
778 bdev = calloc(1, sizeof(struct block_device));
783 bdev->thread_id = -1;
784 bdev->removed = false;
785 bdev->on_private_op = REQ_NORMAL;
786 bdev->private_pid = 0;
787 bdev->mount_point_updated = false;
792 // Called by MainThread - Remove DevNode
793 static void free_block_device(struct block_device *bdev)
796 struct operation_queue *op;
802 thread_id = bdev->thread_id;
803 if (thread_id < 0 || thread_id >= THREAD_MAX)
806 pthread_mutex_lock(&(th_manager[thread_id].mutex));
808 th_manager[thread_id].num_dev--;
809 SYS_G_LIST_REMOVE(th_manager[thread_id].block_dev_list, bdev);
810 free_block_data(bdev->data);
812 SYS_G_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
814 th_manager[thread_id].op_len--;
815 SYS_G_LIST_REMOVE(bdev->op_queue, op);
818 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
823 // Called By MainThread - Remove Device
824 static struct block_device *find_block_device(const char *devnode)
826 struct block_device *bdev;
831 len = strlen(devnode) + 1;
832 for (i = 0; i < THREAD_MAX; i++) {
833 pthread_mutex_lock(&(th_manager[i].mutex));
834 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
835 if (bdev->data && !bdev->removed &&
836 !strncmp(bdev->data->devnode, devnode, len)) {
837 pthread_mutex_unlock(&(th_manager[i].mutex));
841 pthread_mutex_unlock(&(th_manager[i].mutex));
847 // Called By MainThread - Remove Device
848 static struct block_device *find_block_device_path(const char *mount_point)
850 struct block_device *bdev;
855 len = strlen(mount_point) + 1;
856 for (i = 0; i < THREAD_MAX; i++) {
857 pthread_mutex_lock(&(th_manager[i].mutex));
858 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
859 if (bdev->data && !bdev->removed &&
860 (bdev->data->mount_point != NULL && !strncmp(bdev->data->mount_point, mount_point, len))) {
861 pthread_mutex_unlock(&(th_manager[i].mutex));
865 pthread_mutex_unlock(&(th_manager[i].mutex));
871 // Called By MainThread - Mount,Unmount,Format,GetInfo
872 static struct block_device *find_block_device_by_id(int id)
874 struct block_device *bdev;
878 for (i = 0; i < THREAD_MAX; i++) {
879 pthread_mutex_lock(&(th_manager[i].mutex));
880 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
885 if (bdev->data->id == id) {
886 pthread_mutex_unlock(&(th_manager[i].mutex));
890 pthread_mutex_unlock(&(th_manager[i].mutex));
896 static const char *get_operation_char(enum block_dev_operation op)
899 case BLOCK_DEV_MOUNT:
902 case BLOCK_DEV_UNMOUNT:
905 case BLOCK_DEV_FORMAT:
908 case BLOCK_DEV_INSERT:
911 case BLOCK_DEV_REMOVE:
914 case BLOCK_LUKS_CLOSE:
918 _E("Invalid operation(%d).", op);
922 void mmc_make_default_path(const char *mount_path)
926 char mmc_path[FILE_NAME_LEN_MAX + 1] = {0, };
928 for (i = 0; i < DIR_NUM; ++i) {
929 if ((ret_val = snprintf(mmc_path, sizeof(mmc_path), "%s/%s", mount_path, mmc_default_path[i])) > sizeof(mmc_path) - 1) {
930 _E("Path is longer than buffer. Need %d size of buffer.", ret_val + 1);
934 if (!g_file_test(mmc_path, G_FILE_TEST_IS_DIR)) {
935 _D("Path(%s) did not exist.", mmc_path);
936 ret_val = mkdir(mmc_path, 0777);
938 _E("Failed to mkdir: %d", errno);
940 /*this fuction for emulator*/
941 /*at the first time, the directroies are made permission 755*/
942 ret_val = chmod(mmc_path, 0777);
944 _E("Failed to chmod: %d", errno);
946 ret_val = chown(mmc_path, 0, 10001);
948 _E("Failed to chown: %d", errno);
953 static void create_external_apps_directory(void)
957 ret_dbus = gdbus_call_async(PKGDIR_BUS_NAME, PKGDIR_PATH,
958 PKGDIR_INTERFACE, "CreateExternalDirsForAllPkgs", NULL);
960 _E("Failed to create external directory.");
963 static int pipe_trigger(enum block_dev_operation op,
964 struct block_device *bdev, int result)
966 struct pipe_data pdata = { op, bdev, result };
969 _D("op=%s bdev=%p result=%d",
970 get_operation_char(pdata.op),
971 pdata.bdev, pdata.result);
973 // Multi thread should not write at the same time
974 pthread_mutex_lock(&pipe_mutex);
975 n = write(pfds[1], &pdata, sizeof(struct pipe_data));
976 pthread_mutex_unlock(&pipe_mutex);
978 return (n != sizeof(struct pipe_data)) ? -EPERM : 0;
981 static bool pipe_cb(int fd, void *data)
983 struct pipe_data pdata = {0,};
988 n = read(fd, &pdata, sizeof(pdata));
989 if (n != sizeof(pdata) || !pdata.bdev) {
990 _E("Failed to read struct pipe data.");
994 _I("op=%s bdev=%p result=%d",
995 get_operation_char(pdata.op),
996 pdata.bdev, pdata.result);
998 if (pdata.op == BLOCK_LUKS_CLOSE)
1001 if (pdata.op == BLOCK_DEV_MOUNT && pdata.result < 0) {
1002 if (pdata.bdev->data->state == BLOCK_UNMOUNT) {
1003 ret_val = change_mount_point(pdata.bdev, "");
1004 /* Modify /run/external-storage/id file */
1006 if (pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV)
1007 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, true);
1009 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, false);
1015 if (pdata.op == BLOCK_DEV_MOUNT && (pdata.result == 0)) {
1016 /* Create file for block device /run/external-storage/id */
1017 create_file(pdata.bdev->data->id, pdata.bdev->data->mount_point, pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV);
1020 if (pdata.op == BLOCK_DEV_MOUNT &&
1021 pdata.bdev->data->state == BLOCK_MOUNT &&
1022 pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
1023 pdata.bdev->data->primary) {
1024 create_external_apps_directory();
1025 mmc_make_default_path(pdata.bdev->data->mount_point);
1027 ret_val = gdbus_call_sync_with_reply_int(POPUP_BUS_NAME,
1029 POPUP_INTERFACE_NOTI,
1031 g_variant_new("(s)", MMC_INSERTED),
1034 _E("Failed to popup: %d", ret_val);
1037 if (pdata.op == BLOCK_DEV_UNMOUNT) {
1038 /* Remove file for block device /run/xxxxxx/id */
1039 remove_file(pdata.bdev->data->id, pdata.bdev->data->block_type == BLOCK_EXTENDEDSD_DEV);
1041 if (pdata.bdev->data->block_type == BLOCK_MMC_DEV &&
1042 pdata.bdev->data->primary &&
1043 BLOCK_IS_FLAG_SET(pdata.bdev->data, UNMOUNT_UNSAFE)) {
1045 ret_val = gdbus_call_sync_with_reply_int(POPUP_BUS_NAME,
1047 POPUP_INTERFACE_NOTI,
1049 g_variant_new("(s)", MMC_REMOVED),
1052 _E("Failed to popup: %d", ret_val);
1056 /* Broadcast to mmc and usb storage module */
1057 broadcast_block_info(pdata.op, pdata.bdev->data, pdata.result);
1059 /* Broadcast outside with Block iface */
1060 if (pdata.bdev->on_private_op == REQ_NORMAL)
1061 broadcast_device_changed(pdata.bdev, pdata.op);
1062 else if (pdata.bdev->on_private_op == REQ_PRIVATE) {
1063 if (pdata.op == BLOCK_DEV_UNMOUNT) {
1064 pdata.bdev->on_private_op = REQ_NORMAL;
1065 _D("Private operation state(%d).", pdata.bdev->on_private_op);
1068 if (pdata.op == BLOCK_DEV_MOUNT) {
1069 pdata.bdev->on_private_op = REQ_PRIVATE;
1070 _D("Private operation state(%d).", pdata.bdev->on_private_op);
1074 if (pdata.op == BLOCK_DEV_REMOVE) {
1075 thread_id = pdata.bdev->thread_id;
1076 if (thread_id < 0 || thread_id >= THREAD_MAX)
1078 free_block_device(pdata.bdev);
1085 static int pipe_init(void)
1089 ret_val = pipe2(pfds, O_CLOEXEC);
1093 ret_val = add_fd_read_handler(pfds[0], pipe_cb,
1094 NULL, NULL, &phandler);
1096 _E("Failed to add pipe handler: %d", ret_val);
1103 static void pipe_exit(void)
1106 remove_fd_read_handler(&phandler);
1116 static int mmc_check_and_unmount(const char *path)
1124 while (mount_check(path)) {
1128 if (retry > UNMOUNT_RETRY)
1135 static bool check_rw_mount(const char *szPath)
1137 struct statvfs mount_stat;
1139 if (!statvfs(szPath, &mount_stat)) {
1140 if ((mount_stat.f_flag & ST_RDONLY) == ST_RDONLY)
1146 static int retrieve_udev_device(struct block_data *data, bool mount_point_updated)
1149 struct udev_device *dev;
1150 const char *fs_type;
1151 const char *fs_usage;
1158 for (wait = 0; wait < 10; wait++) {
1161 _E("Failed to create udev library context.");
1165 dev = udev_device_new_from_syspath(udev, data->syspath);
1167 _E("Failed to create new udev device.");
1172 fs_type = udev_device_get_property_value(dev, "ID_FS_TYPE");
1173 fs_usage = udev_device_get_property_value(dev, "ID_FS_USAGE");
1174 /* fs_usage for crpto_LUKS is crypto */
1175 if (!fs_type || (strncmp(fs_type, VFAT_NAME, strlen(VFAT_NAME)) && strncmp(fs_type, EXT4_NAME, strlen(EXT4_NAME))))
1177 else if (!fs_usage || strncmp(FILESYSTEM_NAME, fs_usage, strlen(FILESYSTEM_NAME)))
1182 udev_device_unref(dev);
1186 r = update_block_data(data,
1187 udev_device_get_property_value(dev, "ID_FS_USAGE"),
1188 udev_device_get_property_value(dev, "ID_FS_TYPE"),
1189 udev_device_get_property_value(dev, "ID_FS_VERSION"),
1190 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
1191 udev_device_get_sysattr_value(dev, "ro"),
1192 mount_point_updated);
1194 _E("Failed to update block data for %s.", data->devnode);
1196 udev_device_unref(dev);
1201 static int block_mount(struct block_data *data)
1203 struct block_fs_ops *fs;
1208 if (!data || !data->devnode || !data->mount_point)
1211 /* check existing mounted */
1212 if (mount_check(data->mount_point))
1215 /* create mount point */
1216 if (access(data->mount_point, R_OK) != 0) {
1217 if (mkdir(data->mount_point, 0755) < 0)
1221 /* check matched file system */
1222 if (!data->fs_usage ||
1223 strncmp(data->fs_usage, FILESYSTEM_NAME,
1224 sizeof(FILESYSTEM_NAME)) != 0) {
1229 if (!data->fs_type) {
1230 _E("There is no file system.");
1231 BLOCK_FLAG_SET(data, FS_EMPTY);
1237 len = strlen(data->fs_type) + 1;
1238 SYS_G_LIST_FOREACH(fs_head, elem, fs) {
1239 if (!strncmp(fs->name, data->fs_type, len))
1244 _E("Not supported file system(%s).", data->fs_type);
1245 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1250 if (data->block_type == BLOCK_EXTENDEDSD_DEV)
1251 r = fs->mount(false, data->devnode, data->mount_point);
1253 r = fs->mount(smack, data->devnode, data->mount_point);
1256 BLOCK_FLAG_SET(data, FS_BROKEN);
1261 r = check_rw_mount(data->mount_point);
1268 rmdir(data->mount_point);
1272 static int mount_start(struct block_device *bdev)
1274 struct block_data *data;
1282 _I("Mount Start (%s -> %s).",
1283 data->devnode, data->mount_point);
1285 /* mount operation */
1286 r = block_mount(data);
1287 if (r != -EROFS && r < 0) {
1288 _E("Failed to mount device(%s): %d", data->devnode, r);
1293 data->readonly = true;
1294 BLOCK_FLAG_SET(data, MOUNT_READONLY);
1297 data->state = BLOCK_MOUNT;
1299 if (data->block_type == BLOCK_MMC_DEV) {
1300 /* app2ext_migrate_legacy_all has dbus method call to deviced */
1301 ret_val = app2ext_migrate_legacy_all();
1303 _E("Failed to app2ext.");
1307 if (r < 0 && r != -EROFS)
1308 data->state = BLOCK_UNMOUNT;
1310 _I("%s result=%s: %d", __func__, data->devnode, r);
1312 if (pipe_trigger(BLOCK_DEV_MOUNT, bdev, r) < 0)
1313 _E("Failed to trigger pipe.");
1318 static int change_mount_point(struct block_device *bdev,
1319 const char *mount_point)
1321 struct block_data *data;
1327 free(data->mount_point);
1329 /* If the mount path already exists, the path cannot be used */
1331 access(mount_point, F_OK) != 0) {
1332 data->mount_point = strdup(mount_point);
1333 bdev->mount_point_updated = true;
1335 data->mount_point = generate_mount_path(data);
1336 bdev->mount_point_updated = false;
1342 static int mount_block_device(struct block_device *bdev)
1344 struct block_data *data;
1347 if (!bdev || !bdev->data)
1351 if (data->state == BLOCK_MOUNT) {
1352 _I("%s is already mounted.", data->devnode);
1356 if (!block_conf[data->block_type].multimount &&
1358 _I("Not support multi mount by config info.");
1362 r = mount_start(bdev);
1364 _E("Failed to mount %s.", data->devnode);
1371 static int block_unmount(struct block_device *bdev,
1372 enum unmount_operation option)
1374 struct block_data *data;
1377 if (!bdev || !bdev->data || !bdev->data->mount_point)
1382 if (bdev->on_private_op == REQ_NORMAL)
1383 broadcast_device_blocked(bdev);
1385 /* it must called before unmounting mmc */
1386 r = mmc_check_and_unmount(data->mount_point);
1389 if (option == UNMOUNT_NORMAL) {
1390 _I("Failed to unmount with normal option: %d", r);
1394 _I("Execute force unmount.");
1395 /* Force Unmount Scenario */
1398 * should unmount the below vconf key. */
1399 if ((data->block_type == BLOCK_MMC_DEV ||
1400 data->block_type == BLOCK_EXTENDEDSD_DEV) &&
1402 /* At first, notify to other app who already access sdcard */
1403 _I("Notify to other app who already access sdcard.");
1404 vconf_set_int(VCONFKEY_SYSMAN_MMC_STATUS,
1405 VCONFKEY_SYSMAN_MMC_INSERTED_NOT_MOUNTED);
1407 /* Wait for 700 msec to release open files */
1413 if (umount2(data->mount_point, MNT_DETACH) != 0) {
1414 _I("Failed to unmount with lazy option: %m");
1418 while (retry++ < UNMOUNT_RETRY) {
1419 _I("Kill app with SIGTERM.");
1420 terminate_process(data->devnode, false);
1423 if (!is_in_use_partition(data->devnode))
1426 _I("Kill app with SIGKILL.");
1427 terminate_process(data->devnode, true);
1430 if (!is_in_use_partition(data->devnode))
1437 data->state = BLOCK_UNMOUNT;
1439 if (rmdir(data->mount_point) < 0)
1440 _E("Failed to remove '%s' directory.", data->mount_point);
1445 static int unmount_block_device(struct block_device *bdev,
1446 enum unmount_operation option)
1448 struct block_data *data;
1451 if (!bdev || !bdev->data)
1455 if (data->state == BLOCK_UNMOUNT) {
1456 _I("%s is already unmounted.", data->devnode);
1457 r = mmc_check_and_unmount(data->mount_point);
1459 _E("The path was existed, but could not delete it(%s).",
1464 _I("Unmount Start. '%s' -> '%s'.",
1465 data->devnode, data->mount_point);
1467 r = block_unmount(bdev, option);
1469 _E("Failed to unmount %s device: %d", data->devnode, r);
1473 BLOCK_FLAG_MOUNT_CLEAR(data);
1476 _I("%s result=%s: %d", __func__, data->devnode, r);
1478 if (pipe_trigger(BLOCK_DEV_UNMOUNT, bdev, r) < 0)
1479 _E("Failed to trigger pipe.");
1484 static int block_format(struct block_data *data,
1485 const char *fs_type, bool mount_point_updated)
1487 const struct block_fs_ops *fs;
1493 if (!data || !data->devnode || !data->mount_point)
1496 if (data->block_type == BLOCK_EXTENDEDSD_DEV)
1502 fstype = data->fs_type;
1506 if (!strcmp(fstype, EXFAT_NAME))
1510 len = strlen(fstype);
1511 SYS_G_LIST_FOREACH(fs_head, elem, fs) {
1512 if (!strncmp(fs->name, fstype, len))
1516 if (!fs || !fs->format) {
1517 BLOCK_FLAG_SET(data, FS_NOT_SUPPORTED);
1518 _E("Not supported file system(%s).", fstype);
1522 _I("Format path=%s", data->devnode);
1523 r = fs->format(data->devnode);
1525 _E("Failed to format block data for %s.", data->devnode);
1529 /* need to update the partition data.
1530 * It can be changed in doing format. */
1531 retrieve_udev_device(data, mount_point_updated);
1536 static int format_block_device(struct block_device *bdev,
1537 const char *fs_type,
1538 enum unmount_operation option)
1540 struct block_data *data;
1548 _I("Format Start. '%s' -> '%s'.",
1549 data->devnode, data->mount_point);
1551 if (data->state == BLOCK_MOUNT) {
1552 r = block_unmount(bdev, option);
1554 _E("Failed to unmount %s device: %d", data->devnode, r);
1559 r = block_format(data, fs_type, bdev->mount_point_updated);
1561 _E("Failed to format %s device: %d", data->devnode, r);
1564 _I("%s result=%s: %d", __func__, data->devnode, r);
1566 r = pipe_trigger(BLOCK_DEV_FORMAT, bdev, r);
1568 _E("Failed to trigger pipe.");
1573 static struct format_data *get_format_data(
1574 const char *fs_type, enum unmount_operation option)
1576 struct format_data *fdata;
1578 fdata = (struct format_data *)malloc(sizeof(struct format_data));
1580 _E("Failed to allocate format data.");
1585 fdata->fs_type = strdup(fs_type);
1587 fdata->fs_type = NULL;
1588 fdata->option = option;
1593 static void release_format_data(struct format_data *data)
1597 free(data->fs_type);
1602 // Called by BlockThread - Real Mount Op
1603 static int block_mount_device(struct block_device *bdev, void *data)
1612 thread_id = bdev->thread_id;
1613 if (thread_id < 0 || thread_id >= THREAD_MAX)
1615 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1616 l = SYS_G_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1617 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1619 _E("'%s' does not exist in the device list.", bdev->data->devnode);
1623 /* mount automatically */
1624 ret = mount_block_device(bdev);
1626 _E("Failed to mount block device for %s.", bdev->data->devnode);
1631 // Called by BlockThread - Real Format Op
1632 static int block_format_device(struct block_device *bdev, void *data)
1637 struct format_data *fdata = (struct format_data *)data;
1639 if (!bdev || !fdata) {
1644 thread_id = bdev->thread_id;
1645 if (thread_id < 0 || thread_id >= THREAD_MAX)
1647 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1648 l = SYS_G_LIST_FIND(th_manager[thread_id].block_dev_list, bdev);
1649 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1651 _E("'%s' does not exist in the device list.", bdev->data->devnode);
1656 ret = format_block_device(bdev, fdata->fs_type, fdata->option);
1658 _E("Failed to format block device for %s.", bdev->data->devnode);
1661 release_format_data(fdata);
1666 // Called by BlockThread - Real Unmount Op
1667 static int block_unmount_device(struct block_device *bdev, void *data)
1670 long option = (long)data;
1675 ret = unmount_block_device(bdev, option);
1677 _E("Failed to unmount block device(%s).", bdev->data->devnode);
1684 /* Called by BlockThread - Remove Operation
1685 Direct Call at BlockThread
1686 Previously this function was called by MainThread. However, it will increase complexity.
1687 Need thread lock before to call remove_operation
1689 static void remove_operation(struct block_device *bdev)
1691 struct operation_queue *op;
1697 thread_id = bdev->thread_id;
1698 if (thread_id < 0 || thread_id >= THREAD_MAX)
1701 SYS_G_LIST_FOREACH_SAFE(bdev->op_queue, l, next, op) {
1703 _D("Remove operation(%s, %s).",
1704 get_operation_char(op->op),
1705 bdev->data->devnode);
1707 SYS_G_LIST_REMOVE(bdev->op_queue, op);
1713 // Called by BlockThread
1714 static void check_removed(struct block_device *bdev, GList **queue, struct operation_queue **op)
1716 struct operation_queue *temp;
1729 thread_id = bdev->thread_id;
1730 if (thread_id < 0 || thread_id >= THREAD_MAX)
1733 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1735 SYS_G_LIST_FOREACH(*queue, l, temp) {
1736 if (temp->op == BLOCK_DEV_REMOVE) {
1741 th_manager[thread_id].op_len--;
1742 block_send_dbus_reply((*op)->invocation, 0);
1745 remove_operation(bdev);
1746 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1749 // Called by BlockThread
1750 static bool check_unmount(struct block_device *bdev, GList **queue, struct operation_queue **op)
1752 struct operation_queue *temp;
1755 bool unmounted = false;
1766 thread_id = bdev->thread_id;
1767 if (thread_id < 0 || thread_id >= THREAD_MAX)
1770 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1771 SYS_G_LIST_FOREACH(*queue, l, temp) {
1772 if (temp->op == BLOCK_DEV_UNMOUNT) {
1774 _D("Operation queue has unmount operation.");
1778 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1783 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1785 SYS_G_LIST_FOREACH(*queue, l, temp) {
1786 if (temp->op == BLOCK_DEV_UNMOUNT) {
1791 th_manager[thread_id].op_len--;
1792 block_send_dbus_reply((*op)->invocation, 0);
1795 remove_operation(bdev);
1796 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1801 // Called by BlockThread
1802 static void trigger_operation(struct block_device *bdev, GList *queue, struct operation_queue *op)
1806 char devnode[PATH_MAX];
1807 enum block_dev_operation operation;
1808 bool unmounted = false;
1815 thread_id = bdev->thread_id;
1816 if (thread_id < 0 || thread_id >= THREAD_MAX)
1819 snprintf(devnode, sizeof(devnode), "%s", bdev->data->devnode);
1829 _D("Thread id(%d) Trigger operation(%s, %s)", thread_id,
1830 get_operation_char(operation), devnode);
1833 if (operation == BLOCK_DEV_INSERT && bdev->removed) {
1834 check_removed(bdev, &queue, &op);
1836 _D("Trigger operation again(%s, %s).",
1837 get_operation_char(operation), devnode);
1839 if (operation == BLOCK_DEV_MOUNT) {
1840 unmounted = check_unmount(bdev, &queue, &op);
1843 _D("Trigger operation again(%s, %s).",
1844 get_operation_char(operation), devnode);
1848 switch (operation) {
1849 case BLOCK_DEV_INSERT:
1851 case BLOCK_DEV_MOUNT:
1852 ret_val = block_mount_device(bdev, op->data);
1853 _D("Mount '%s': %d", devnode, ret_val);
1855 case BLOCK_DEV_FORMAT:
1856 ret_val = block_format_device(bdev, op->data);
1857 _D("Format '%s': %d", devnode, ret_val);
1859 case BLOCK_DEV_UNMOUNT:
1860 ret_val = block_unmount_device(bdev, op->data);
1861 _D("Unmount '%s': %d", devnode, ret_val);
1863 case BLOCK_DEV_REMOVE:
1866 case BLOCK_LUKS_CLOSE:
1867 #ifdef EXTENDED_STORAGE
1868 ret_val = ode_luks_close_sync(EXTENDEDSD_NAME);
1870 _E("Failed on ode_luks_close(%s).", EXTENDEDSD_NAME);
1874 _E("Operation type(%d) is invalid.", op->op);
1880 * during checking the queue length */
1881 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1884 th_manager[thread_id].op_len--;
1886 block_send_dbus_reply(op->invocation, ret_val);
1888 queue = bdev->op_queue;
1889 if (queue != NULL) {
1890 queue = SYS_G_LIST_NEXT(queue);
1892 op = SYS_G_LIST_NTH(queue, 0);
1898 remove_operation(bdev);
1900 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1903 if (operation == BLOCK_DEV_INSERT || operation == BLOCK_DEV_REMOVE || operation == BLOCK_LUKS_CLOSE) {
1904 if (pipe_trigger(operation, bdev, 0) < 0)
1905 _E("Failed to trigger pipe.");
1912 // Called by BlockThread
1913 static void *block_th_start(void *arg)
1915 struct block_device *temp;
1916 struct manage_thread *th = (struct manage_thread *)arg;
1917 struct operation_queue *op = NULL;
1919 GList *queue = NULL;
1924 thread_id = th->thread_id;
1925 if (thread_id < 0 || thread_id >= THREAD_MAX) {
1926 _E("Thread Number=%d.", th->thread_id);
1931 pthread_mutex_lock(&(th_manager[thread_id].mutex));
1932 if (th_manager[thread_id].op_len == 0) {
1933 _D("Operation queue of thread is empty.");
1934 pthread_cond_wait(&(th_manager[thread_id].cond), &(th_manager[thread_id].mutex));
1935 _D("Wake up thread=%d.", thread_id);
1938 SYS_G_LIST_FOREACH(th_manager[thread_id].block_dev_list, elem, temp) {
1939 queue = temp->op_queue;
1941 op = SYS_G_LIST_NTH(queue, 0);
1943 _D("Operation queue for device %s is Empty.", temp->data->devnode);
1947 queue = SYS_G_LIST_NEXT(queue);
1955 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
1957 if (op && !op->done)
1958 trigger_operation(temp, queue, op);
1963 // This function will be refactored later
1964 // Especially, we don't need to keep th_node_list.
1965 static int find_thread(char *devnode)
1972 int i, len, min, min_num;
1973 int dev_mmc = -1, part = -1, num;
1976 if (!fnmatch("*/"MMC_PARTITION_PATH, devnode, 0)) {
1977 sscanf(devnode, "/dev/mmcblk%dp%d", &dev_mmc, &part);
1984 snprintf(str, len, "/dev/mmcblk%d", dev_mmc);
1985 th_node = strdup(str);
1986 } else if (!fnmatch("*/"SCSI_PARTITION_PATH, devnode, 0)) {
1987 sscanf(devnode, "/dev/sd%c%d", &dev_scsi, &part);
1988 snprintf(str, SCSI_PARTITION_LENGTH, "/dev/sd%c", dev_scsi);
1989 th_node = strdup(str);
1991 th_node = strdup(devnode);
1993 len = strlen(th_node) + 1;
1996 for (i = 0; i < THREAD_MAX; i++) {
1997 SYS_G_LIST_FOREACH(th_manager[i].th_node_list, elem, temp) {
1998 if (!strncmp(temp, th_node, len)) {
2003 if (th_manager[i].num_dev < min_num) {
2004 min_num = th_manager[i].num_dev;
2009 if (min >= 0 && min < THREAD_MAX) {
2010 SYS_G_LIST_APPEND(th_manager[min].th_node_list, th_node);
2014 _E("Failed to find thread.");
2015 SYS_G_LIST_APPEND(th_manager[0].th_node_list, th_node);
2019 /* Only Main thread is permmited */
2020 // Called by MainThread
2021 static int add_operation(struct block_device *bdev,
2022 enum block_dev_operation operation,
2023 GDBusMethodInvocation *invocation, void *data)
2025 struct operation_queue *op;
2034 _I("Add operation(%s, %s).",
2035 get_operation_char(operation),
2036 bdev->data->devnode);
2038 thread_id = bdev->thread_id;
2039 if (thread_id < 0 || thread_id >= THREAD_MAX) {
2040 _E("Failed to find thread to add.");
2044 op = (struct operation_queue *)malloc(sizeof(struct operation_queue));
2046 _E("Failed to malloc.");
2052 op->invocation = invocation;
2054 /* Need to disble app2ext whenever unmounting mmc */
2055 /* app2ext_disable_all_external_pkgs inside a critical section need to be avoided. */
2056 if (operation == BLOCK_DEV_UNMOUNT &&
2057 bdev->data->state == BLOCK_MOUNT &&
2058 bdev->data->block_type == BLOCK_MMC_DEV &&
2059 bdev->data->primary)
2060 if (app2ext_disable_all_external_pkgs() < 0)
2061 _E("Failed to app2ext_disable_all_external_pkgs().");
2064 * during adding queue and checking the queue length */
2065 pthread_mutex_lock(&(th_manager[thread_id].mutex));
2067 /* Only modified between lock and unlock of mutex */
2070 start_th = th_manager[thread_id].start_th;
2071 SYS_G_LIST_APPEND(bdev->op_queue, op);
2072 th_manager[thread_id].op_len++;
2074 if (th_manager[thread_id].op_len == 1 && start_th)
2075 pthread_cond_signal(&(th_manager[thread_id].cond));
2077 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2081 _D("Start new thread for block device.");
2082 th_manager[thread_id].start_th = true;
2083 ret_val = pthread_create(&(th_manager[thread_id].th), NULL, block_th_start, &th_manager[thread_id]);
2085 _E("Failed to create thread for %s.", bdev->data->devnode);
2089 pthread_detach(th_manager[thread_id].th);
2095 static bool disk_is_partitioned_by_kernel(struct udev_device *dev)
2098 struct dirent entry;
2100 const char *syspath;
2103 syspath = udev_device_get_syspath(dev);
2107 dp = opendir(syspath);
2109 _E("Failed to open '%s'.", syspath);
2113 /* TODO compare devname and d_name */
2114 while (readdir_r(dp, &entry, &dir) == 0 && dir != NULL) {
2115 if (!fnmatch(MMC_PARTITION_PATH, dir->d_name, 0) ||
2116 !fnmatch(SCSI_PARTITION_PATH, dir->d_name, 0)) {
2128 static bool check_partition(struct udev_device *dev)
2130 const char *devtype;
2131 const char *part_table_type;
2132 const char *fs_usage;
2135 /* only consider disk type, never partitions */
2136 devtype = udev_device_get_devtype(dev);
2140 if (strncmp(devtype, BLOCK_DEVTYPE_DISK,
2141 sizeof(BLOCK_DEVTYPE_DISK)) != 0)
2144 part_table_type = udev_device_get_property_value(dev,
2145 "ID_PART_TABLE_TYPE");
2146 if (part_table_type) {
2147 fs_usage = udev_device_get_property_value(dev,
2150 strncmp(fs_usage, FILESYSTEM_NAME, sizeof(FILESYSTEM_NAME)) == 0) {
2151 if (!disk_is_partitioned_by_kernel(dev))
2158 if (disk_is_partitioned_by_kernel(dev)) {
2167 // Called by MainThread
2168 static int add_block_device(struct udev_device *dev, const char *devnode, bool mapper)
2170 struct block_data *data;
2171 struct block_device *bdev;
2172 //char id_string[PATH_LEN];
2176 bool need_format = false;
2178 partition = check_partition(dev);
2180 /* if there is a partition, skip this request */
2181 _I("%s device has partitions, skip this time.", devnode);
2185 if (mapper && !udev_device_get_property_value(dev, "ID_FS_TYPE")) {
2186 char syspath[128] = {0};
2189 r = rindex(udev_device_get_syspath(dev), '/');
2190 if (!r) return -ENODEV;
2192 snprintf(syspath, sizeof(syspath), "/sys/block%s", r);
2194 data = make_block_data(devnode,
2199 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2200 udev_device_get_sysattr_value(dev, "ro"));
2203 data = make_block_data(devnode,
2204 udev_device_get_syspath(dev),
2205 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2206 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2207 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2208 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2209 udev_device_get_sysattr_value(dev, "ro"));
2213 _E("Failed to make block data for %s.", devnode);
2217 if (!block_conf[data->block_type].multimount && !data->primary &&
2218 data->fs_usage && !strcmp(data->fs_usage, FILESYSTEM_NAME)) {
2219 _D("Not support multi mount by config info.");
2220 free_block_data(data);
2224 if (!block_control) {
2225 if (!mapper && strncmp(data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2226 _D("Block module is disabled.");
2227 free_block_data(data);
2233 bdev = make_block_device(data);
2235 _E("Failed to make block device for %s.", devnode);
2236 free_block_data(data);
2240 thread_id = find_thread(bdev->data->devnode);
2241 if (thread_id < 0 || thread_id >= THREAD_MAX) {
2242 _E("Failed to find thread to add.");
2243 free_block_device(bdev);
2246 bdev->thread_id = thread_id;
2248 pthread_mutex_lock(&(th_manager[thread_id].mutex));
2249 th_manager[thread_id].num_dev++;
2250 SYS_G_LIST_APPEND(th_manager[thread_id].block_dev_list, bdev);
2251 pthread_mutex_unlock(&(th_manager[thread_id].mutex));
2254 struct format_data *fdata;
2256 fdata = get_format_data(NULL, UNMOUNT_FORCE);
2258 _E("Failed to get format data.");
2262 ret = add_operation(bdev, BLOCK_DEV_FORMAT, NULL, (void *)fdata);
2264 _E("Failed to add operation(format, %s).", bdev->data->devnode);
2265 release_format_data(fdata);
2269 if (!bdev->data->fs_type) {
2270 _E("Unformatted Storage.");
2271 free_block_device(bdev);
2273 } else if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2274 // bdev->data->block_type = BLOCK_EXTENDEDSD_DEV;
2275 bdev->data->primary = true;
2276 _D("Need to unlock encrypted sdcard.");
2277 // ---- ODE UI launch ----
2278 ret = launch_system_app(POPUP_DEFAULT
2281 , "unlockextendedsd"
2285 , bdev->data->devnode
2289 _E("Failed to launch popup.");
2291 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2293 _E("Failed to add operation(insert, %s).", devnode);
2294 free_block_device(bdev);
2299 } else if (mapper && !strncmp(bdev->data->fs_type, EXT4_NAME, strlen(EXT4_NAME))) {
2300 bdev->data->block_type = BLOCK_EXTENDEDSD_DEV;
2301 ret = change_mount_point(bdev, EXTENDEDSD_MOUNT_PATH);
2304 free_block_device(bdev);
2309 ret = add_operation(bdev, BLOCK_DEV_INSERT, NULL, (void *)data);
2311 _E("Failed to add operation(insert, %s).", devnode);
2312 free_block_device(bdev);
2316 // Not a regular filesystem -> skip mounting
2317 if (!bdev->data->fs_usage || strcmp(bdev->data->fs_usage, FILESYSTEM_NAME)) {
2318 _I("Not a filesystem. Not mounting.");
2322 ret = add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL);
2324 _E("Failed to add operation(mount, %s).", devnode);
2330 static int remove_block_device(struct udev_device *dev, const char *devnode)
2332 struct block_device *bdev;
2333 struct block_device *bdev_extended;
2336 bdev = find_block_device(devnode);
2338 _E("Failed to find block data for %s.", devnode);
2342 BLOCK_FLAG_SET(bdev->data, UNMOUNT_UNSAFE);
2344 bdev->removed = true;
2345 if (bdev->on_private_op != REQ_NORMAL) {
2346 bdev->on_private_op = REQ_NORMAL;
2347 _D("Private operation state(%d).", bdev->on_private_op);
2350 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2351 bdev_extended = find_block_device_path(EXTENDEDSD_MOUNT_PATH);
2353 if (bdev_extended) {
2354 BLOCK_FLAG_SET(bdev_extended->data, UNMOUNT_UNSAFE);
2356 bdev_extended->removed = true;
2357 if (bdev_extended->on_private_op != REQ_NORMAL) {
2358 bdev_extended->on_private_op = REQ_NORMAL;
2359 _D("Private operation state(%d).", bdev_extended->on_private_op);
2362 ret = add_operation(bdev_extended, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2364 _E("Failed to add operation(unmount, %s).", devnode);
2368 ret = add_operation(bdev_extended, BLOCK_LUKS_CLOSE, NULL, NULL);
2370 _E("Failed to add operation(luks_close, %s).", devnode);
2374 ret = add_operation(bdev_extended, BLOCK_DEV_REMOVE, NULL, NULL);
2376 _E("Failed to add operation(remove, %s).", devnode);
2380 _E("Failed to find block data for extended sd card.");
2383 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2385 _E("Failed to add operation(unmount, %s).", devnode);
2389 ret = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2391 _E("Failed to add operation(remove, %s).", devnode);
2398 static int get_internal_storage_number(void)
2400 struct libmnt_table *t = NULL;
2401 struct libmnt_fs *fs;
2404 int r = 0, dev_temp;
2406 if ((!is_emulator() && (dev_internal >= 0 || dev_internal_scsi != '\0')) ||
2407 (is_emulator() && dev_internal_emul != '\0'))
2410 t = mnt_new_table();
2414 r = mnt_table_parse_mtab(t, NULL);
2420 fs = mnt_table_find_target(t, ROOT_DIR, MNT_ITER_BACKWARD);
2426 temp = mnt_fs_get_srcpath(fs);
2432 name = strrchr(temp, '/');
2439 /* Boot from USB is not handled */
2440 if (!is_emulator()) {
2441 if (!fnmatch(MMC_PATH, temp, 0))
2442 sscanf(name, "mmcblk%d", &dev_internal);
2443 else if (!fnmatch(SCSI_PATH, temp, 0))
2444 sscanf(name, "sd%c", &dev_internal_scsi);
2446 if (!fnmatch(MMC_LINK_PATH, temp, 0))
2447 sscanf(name, "vd%c%d", &dev_internal_emul, &dev_temp);
2449 dev_internal_emul = '\0';
2457 static int check_external_storage(const char* devnode)
2459 char dev_scsi = '\0';
2462 int dev_num = -1, dev_temp;
2467 name = strrchr(devnode, '/');
2471 if (!is_emulator()) {
2472 if (!fnmatch(MMC_PATH, devnode, 0)) {
2473 sscanf(name, "mmcblk%d", &dev_num);
2474 if (dev_internal == dev_num) {
2475 _D("%s is internal storage.", devnode);
2478 } else if (!fnmatch(SCSI_PATH, devnode, 0)) {
2479 sscanf(name, "sd%c", &dev_scsi);
2480 if (dev_internal_scsi == dev_scsi) {
2481 _D("%s is internal storage.", devnode);
2486 if (!fnmatch(MMC_LINK_PATH, devnode, 0)) {
2487 sscanf(name, "vd%c%d", &emul, &dev_temp);
2488 if (dev_internal_emul == emul) {
2489 _D("%s is internal storage.", devnode);
2498 static int check_already_handled(const char* devnode)
2500 struct block_device *bdev;
2501 struct block_data *data;
2505 for (i = 0; i < THREAD_MAX; i++) {
2506 pthread_mutex_lock(&(th_manager[i].mutex));
2507 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2513 if (!strncmp(data->devnode, devnode, strlen(devnode) + 1)) {
2514 pthread_mutex_unlock(&(th_manager[i].mutex));
2518 pthread_mutex_unlock(&(th_manager[i].mutex));
2524 static int block_init_from_udev_enumerate(void)
2527 struct udev_enumerate *enumerate;
2528 struct udev_list_entry *list_entry, *list_sub_entry;
2529 struct udev_device *dev;
2530 const char *syspath;
2531 const char *devnode;
2536 _E("Failed to create udev library context.");
2540 /* create a list of the devices in the 'usb' subsystem */
2541 enumerate = udev_enumerate_new(udev);
2543 _E("Failed to create an enumeration context.");
2547 udev_enumerate_add_match_subsystem(enumerate, BLOCK_SUBSYSTEM);
2548 udev_enumerate_add_match_property(enumerate,
2549 UDEV_DEVTYPE, BLOCK_DEVTYPE_DISK);
2550 udev_enumerate_add_match_property(enumerate,
2551 UDEV_DEVTYPE, BLOCK_DEVTYPE_PARTITION);
2552 udev_enumerate_scan_devices(enumerate);
2554 udev_list_entry_foreach(list_entry,
2555 udev_enumerate_get_list_entry(enumerate)) {
2556 syspath = udev_list_entry_get_name(list_entry);
2560 dev = udev_device_new_from_syspath(
2561 udev_enumerate_get_udev(enumerate),
2567 udev_list_entry_foreach(list_sub_entry,
2568 udev_device_get_devlinks_list_entry(dev)) {
2569 const char *devlink = udev_list_entry_get_name(list_sub_entry);
2570 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2577 devnode = udev_device_get_devnode(dev);
2579 udev_device_unref(dev);
2583 if (fnmatch(MMC_PATH, devnode, 0) &&
2584 fnmatch(SCSI_PATH, devnode, 0) &&
2585 fnmatch(EXTENDEDSD_NODE_PATH, devnode, 0)) {
2586 udev_device_unref(dev);
2591 r = check_external_storage(devnode);
2593 udev_device_unref(dev);
2597 r = check_already_handled(devnode);
2599 _I("%s is already handled.", devnode);
2600 udev_device_unref(dev);
2604 _I("%s device add.", devnode);
2605 add_block_device(dev, devnode, false);
2607 udev_device_unref(dev);
2610 udev_enumerate_unref(enumerate);
2615 // Called by MainThread
2616 static void show_block_device_list(void)
2618 struct block_device *bdev;
2619 struct block_data *data;
2623 for (i = 0; i < THREAD_MAX; i++) {
2624 pthread_mutex_lock(&(th_manager[i].mutex));
2625 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
2631 _D("%s:", data->devnode);
2632 _D("\tSyspath=%s", data->syspath);
2633 _D("\tBlock type=%d", data->block_type);
2634 _D("\tFs type=%s", data->fs_type);
2635 _D("\tFs usage=%s", data->fs_usage);
2636 _D("\tFs version=%s", data->fs_version);
2637 _D("\tFs uuid enc=%s", data->fs_uuid_enc);
2639 (data->readonly ? "true" : "false"));
2640 _D("\tMount point=%s", data->mount_point);
2641 _D("\tMount state=%s",
2642 (data->state == BLOCK_MOUNT ?
2643 "mount" : "unmount"));
2645 (data->primary ? "true" : "false"));
2646 _D("\tID=%d", data->id);
2648 pthread_mutex_unlock(&(th_manager[i].mutex));
2652 // Called by MainThread
2653 static void remove_whole_block_device(void)
2655 struct block_device *bdev;
2661 for (i = 0; i < THREAD_MAX; i++) {
2663 pthread_mutex_lock(&(th_manager[i].mutex));
2664 SYS_G_LIST_FOREACH_SAFE(th_manager[i].block_dev_list, elem, next, bdev) {
2665 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2666 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
2668 if (bdev->removed == false)
2671 pthread_mutex_unlock(&(th_manager[i].mutex));
2673 if (bdev && bdev->removed == false) {
2674 bdev->removed = true;
2675 r = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
2677 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
2679 r = add_operation(bdev, BLOCK_DEV_REMOVE, NULL, NULL);
2681 _E("Failed to add operation(remove, %s).", bdev->data->devnode);
2688 static void add_poweroff_wait_cb(GVariant *var, void *user_data, GError *err)
2690 int ret_val = -ENOMSG;
2695 if (!g_variant_get_safe(var, "(i)", &ret_val))
2696 _E("Failed to get(%s): no message", g_variant_get_type_string(var));
2699 add_poweroff_wait = true;
2701 g_variant_unref(var);
2704 static void booting_done(void)
2706 static int done = 0;
2712 _I("Booting done.");
2714 /* register mmc uevent control routine */
2715 ret_val = register_udev_uevent_control(&uh);
2717 _E("Failed to register block uevent: %d", ret_val);
2719 block_control = true;
2720 /* if there is the attached device, try to mount */
2721 block_init_from_udev_enumerate();
2723 ret_val = gdbus_call_async_with_reply(DEVICED_BUS_NAME,
2724 DEVICED_PATH_POWEROFF,
2725 DEVICED_INTERFACE_POWEROFF,
2726 METHOD_ADD_POWEROFF_WAIT,
2728 add_poweroff_wait_cb,
2731 _E("Failed to call "METHOD_ADD_POWEROFF_WAIT" method.");
2736 static void block_poweroff(GDBusConnection *conn,
2737 const gchar *sender,
2744 static int status = 0;
2751 /* unregister mmc uevent control routine */
2752 unregister_udev_uevent_control(&uh);
2753 remove_whole_block_device();
2754 terminate_threads();
2756 if (add_poweroff_wait) {
2757 ret_dbus = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
2758 DEVICED_PATH_POWEROFF,
2759 DEVICED_INTERFACE_POWEROFF,
2760 METHOD_REMOVE_POWEROFF_WAIT,
2763 _E("Failed to call "METHOD_REMOVE_POWEROFF_WAIT" method.");
2765 add_poweroff_wait = false;
2769 static void uevent_block_handler(struct udev_device *dev)
2771 const char *devnode = NULL;
2773 struct udev_list_entry *list_entry;
2775 bool mapper = false;
2777 udev_list_entry_foreach(list_entry, udev_device_get_devlinks_list_entry(dev)) {
2778 const char *devlink = udev_list_entry_get_name(list_entry);
2779 if (!fnmatch(MMC_LINK_PATH, devlink, 0)) {
2783 if (!fnmatch(EXTENDEDSD_NODE_PATH, devlink, 0)) {
2791 devnode = udev_device_get_devnode(dev);
2795 if (fnmatch(MMC_PATH, devnode, 0) &&
2796 fnmatch(SCSI_PATH, devnode, 0))
2800 r = check_external_storage(devnode);
2804 action = udev_device_get_action(dev);
2808 _I("%s device %s.", devnode, action);
2809 if (!strncmp(action, UDEV_ADD, sizeof(UDEV_ADD)) ||
2810 (mapper && !strcmp(action, UDEV_CHANGE))) {
2811 r = check_already_handled(devnode);
2813 _I("%s is already handled.", devnode);
2817 add_block_device(dev, devnode, mapper);
2818 } else if (!strncmp(action, UDEV_REMOVE, sizeof(UDEV_REMOVE))) {
2819 remove_block_device(dev, devnode);
2820 } else if (!strncmp(action, UDEV_CHANGE, sizeof(UDEV_CHANGE))) {
2821 struct block_device *bdev;
2822 bdev = find_block_device(devnode);
2824 _E("Failed to find block data for %s.", devnode);
2827 if (!udev_device_get_property_value(dev, "ID_FS_TYPE"))
2830 r = update_block_data(bdev->data,
2831 udev_device_get_property_value(dev, "ID_FS_USAGE"),
2832 udev_device_get_property_value(dev, "ID_FS_TYPE"),
2833 udev_device_get_property_value(dev, "ID_FS_VERSION"),
2834 udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
2835 udev_device_get_sysattr_value(dev, "ro"),
2838 _E("Failed to update block data for %s.", bdev->data->devnode);
2839 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
2840 _I("Filesystem type(crypto_LUKS) is updated.");
2841 if (bdev->data->fs_usage)
2842 _I("fs_usage=%s", bdev->data->fs_usage);
2846 static GVariant *request_mount_block(GDBusConnection *conn,
2847 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2848 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data, bool onprivate)
2850 struct block_device *bdev;
2851 char *mount_point = NULL;
2855 if (!block_control) {
2856 _D("Block module is disabled.");
2861 g_variant_get(param, "(is)", &id, &mount_point);
2863 bdev = find_block_device_by_id(id);
2865 _E("Failed to find (%d) in the device list.", id);
2870 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
2871 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2872 _D("Mount dbus request for extended internal storage is blocked.");
2877 if (bdev->on_private_op != REQ_NORMAL) {
2882 if (bdev->data->state == BLOCK_MOUNT) {
2883 _I("%s is already mounted.", bdev->data->devnode);
2889 bdev->on_private_op = REQ_PRIVATE;
2890 bdev->private_pid = gdbus_connection_get_sender_pid(NULL, sender);
2891 _D("Private operation state(%d). pid=%d.", bdev->on_private_op, bdev->private_pid);
2894 /* if requester want to use a specific mount point */
2895 if (mount_point && strncmp(mount_point, "", 1) != 0) {
2896 ret = change_mount_point(bdev, mount_point);
2903 ret = add_operation(bdev, BLOCK_DEV_MOUNT, invocation, NULL);
2905 _E("Failed to add operation(mount, %s).", bdev->data->devnode);
2909 g_free(mount_point);
2913 g_free(mount_point);
2914 return g_variant_new("(i)", ret);
2917 static GVariant *request_public_mount_block(GDBusConnection *conn,
2918 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2919 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2921 return request_mount_block(conn, sender, path, iface, name, param, invocation, user_data, false);
2924 static GVariant *request_private_mount_block(GDBusConnection *conn,
2925 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2926 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
2928 return request_mount_block(conn, sender, path, iface, name, param, invocation, user_data, true);
2931 static GVariant *request_unmount_block(GDBusConnection *conn,
2932 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2933 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data, bool onprivate)
2935 struct block_device *bdev;
2941 if (!block_control) {
2942 _D("Block module is disabled.");
2947 g_variant_get(param, "(ii)", &id, &option);
2949 bdev = find_block_device_by_id(id);
2951 _E("Failed to find (%d) in the device list.", id);
2956 /* Unmount dbus call is needed when app proceeds extended internal -> portable storage */
2957 if (!strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
2958 _D("Unmount dbus request for extended internal storage is blocked.");
2964 pid = gdbus_connection_get_sender_pid(NULL, sender);
2965 if (bdev->on_private_op == REQ_NORMAL || (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid)) {
2966 _E("Failed to process private unmount operation pid=%d private_pid=%d.", pid, bdev->private_pid);
2971 if (bdev->on_private_op != REQ_NORMAL) {
2972 _E("Failed to process unmount operation.");
2978 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, invocation, (void *)option);
2980 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
2984 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV) {
2985 ret = add_operation(bdev, BLOCK_LUKS_CLOSE, NULL, NULL);
2987 _E("Failed to add operation(luks_close, %s).", bdev->data->devnode);
2993 return g_variant_new("(i)", ret);
2996 static GVariant *request_public_unmount_block(GDBusConnection *conn,
2997 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
2998 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3000 return request_unmount_block(conn, sender, path, iface, name, param, invocation, user_data, false);
3003 static GVariant *request_private_unmount_block(GDBusConnection *conn,
3004 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3005 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3007 return request_unmount_block(conn, sender, path, iface, name, param, invocation, user_data, true);
3010 static GVariant *request_format_block(GDBusConnection *conn,
3011 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3012 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3014 struct block_device *bdev;
3015 struct format_data *fdata;
3022 if (!block_control) {
3023 _D("Block module is disabled.");
3028 g_variant_get(param, "(ii)", &id, &option);
3030 bdev = find_block_device_by_id(id);
3032 _E("Failed to find (%d) in the device list.", id);
3036 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV ||
3037 !strncmp(bdev->data->fs_type, LUKS_NAME, strlen(LUKS_NAME))) {
3038 _D("Format dbus request for extended internal storage is blocked.");
3043 pid = gdbus_connection_get_sender_pid(NULL, sender);
3044 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
3045 _E("Failed to format on private state.");
3050 fdata = get_format_data(NULL, option);
3052 _E("Failed to get format data.");
3056 prev_state = bdev->data->state;
3057 if (prev_state == BLOCK_MOUNT) {
3058 if (bdev->on_private_op == REQ_PRIVATE) {
3059 bdev->on_private_op = REQ_PRIVATE_FORMAT;
3060 _D("Private operation state(%d)", bdev->on_private_op);
3062 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
3064 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
3065 release_format_data(fdata);
3070 ret = add_operation(bdev, BLOCK_DEV_FORMAT, invocation, (void *)fdata);
3072 _E("Failed to add operation(format, %s).", bdev->data->devnode);
3073 release_format_data(fdata);
3076 /* Maintain previous state of mount/unmount */
3077 if (prev_state == BLOCK_MOUNT) {
3078 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
3079 _E("Failed to add operation(mount, %s).", bdev->data->devnode);
3087 return g_variant_new("(i)", ret);
3090 static GVariant *request_format_block_type(GDBusConnection *conn,
3091 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3092 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3094 struct block_device *bdev;
3095 struct format_data *fdata;
3103 if (!block_control) {
3104 _D("Block module is disabled.");
3109 g_variant_get(param, "(iis)", &id, &option, &type);
3111 bdev = find_block_device_by_id(id);
3113 _E("Failed to find (%d) in the device list.", id);
3117 /* FormatwithType dbus call is needed when app proceeds extended internal -> portable storage */
3118 if (bdev->data->block_type == BLOCK_EXTENDEDSD_DEV) {
3119 _D("FormatwithType dbus request for extended internal storage is blocked.");
3124 pid = gdbus_connection_get_sender_pid(NULL, sender);
3125 if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
3126 _E("Failed to format on private state.");
3131 fdata = get_format_data(type, option);
3133 _E("Failed to get format data.");
3137 prev_state = bdev->data->state;
3138 if (prev_state == BLOCK_MOUNT) {
3139 if (bdev->on_private_op == REQ_PRIVATE) {
3140 bdev->on_private_op = REQ_PRIVATE_FORMAT;
3141 _D("Private operation state(%d).", bdev->on_private_op);
3143 ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
3145 _E("Failed to add operation(unmount, %s).", bdev->data->devnode);
3146 release_format_data(fdata);
3151 ret = add_operation(bdev, BLOCK_DEV_FORMAT, invocation, (void *)fdata);
3153 _E("Failed to add operation(format, %s).", bdev->data->devnode);
3154 release_format_data(fdata);
3157 /* Maintain previous state of mount/unmount */
3158 if (prev_state == BLOCK_MOUNT) {
3159 if (add_operation(bdev, BLOCK_DEV_MOUNT, NULL, NULL) < 0) {
3160 _E("Failed to add operation(mount, %s).", bdev->data->devnode);
3170 return g_variant_new("(i)", ret);
3173 static GVariant *block_data_to_gvariant(struct block_data *data, int flags)
3176 return gdbus_new_g_variant_tuple();
3178 return g_variant_new("(issssssisibii)",
3180 nullstr(data->devnode),
3181 nullstr(data->syspath),
3182 nullstr(data->fs_usage),
3183 nullstr(data->fs_type),
3184 nullstr(data->fs_version),
3185 nullstr(data->fs_uuid_enc),
3187 nullstr(data->mount_point),
3190 flags >= 0 ? flags : data->flags,
3194 //static int add_device_to_struct_iter(struct block_data *data, DBusMessageIter *iter)
3196 // //DBusMessageIter piter;
3198 // //if (!data || !iter)
3199 // // return -EINVAL;
3201 // //dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
3202 // //add_device_to_iter(data, &piter);
3203 // //dbus_message_iter_close_container(iter, &piter);
3208 //static int add_device_to_iter_2(struct block_data *data, DBusMessageIter *iter)
3210 // DBusMessageIter piter;
3211 // char *str_null = "";
3213 // if (!data || !iter)
3216 // //dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT, NULL, &piter);
3217 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3218 // // &(data->block_type));
3219 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3220 // // data->devnode ? &(data->devnode) : &str_null);
3221 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3222 // // data->syspath ? &(data->syspath) : &str_null);
3223 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3224 // // data->fs_usage ? &(data->fs_usage) : &str_null);
3225 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3226 // // data->fs_type ? &(data->fs_type) : &str_null);
3227 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3228 // // data->fs_version ? &(data->fs_version) : &str_null);
3229 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3230 // // data->fs_uuid_enc ? &(data->fs_uuid_enc) : &str_null);
3231 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3232 // // &(data->readonly));
3233 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_STRING,
3234 // // data->mount_point ? &(data->mount_point) : &str_null);
3235 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3236 // // &(data->state));
3237 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_BOOLEAN,
3238 // // &(data->primary));
3239 // //dbus_message_iter_append_basic(&piter, DBUS_TYPE_INT32,
3240 // // &(data->flags));
3241 // //dbus_message_iter_close_container(iter, &piter);
3246 static GVariant *request_get_device_info(GDBusConnection *conn,
3247 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3248 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3250 struct block_device *bdev = NULL;
3251 struct block_data *data = NULL;
3252 struct block_data nodata = {0,};
3255 g_variant_get(param, "(i)", &id);
3257 bdev = find_block_device_by_id(id);
3266 nodata.id = -ENODEV;
3270 return block_data_to_gvariant(data, -1);
3273 static GVariant *request_show_device_list(GDBusConnection *conn,
3274 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3275 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3277 show_block_device_list();
3278 return gdbus_new_g_variant_tuple();
3281 static enum block_device_type get_bdev_type_from_type_string(const char *type_str)
3284 return BLOCK_UNKNOWN_DEV;
3286 if (strcmp(type_str, BLOCK_TYPE_SCSI) == 0)
3287 return BLOCK_SCSI_DEV;
3288 if (strcmp(type_str, BLOCK_TYPE_MMC) == 0)
3289 return BLOCK_MMC_DEV;
3290 if (strcmp(type_str, BLOCK_TYPE_ALL) == 0)
3291 return BLOCK_ALL_DEV;
3293 return BLOCK_UNKNOWN_DEV;
3296 // Called by MainThread
3297 static GVariant *request_get_device_list(GDBusConnection *conn,
3298 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3299 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3301 GVariant *reply = NULL;
3302 struct block_device *bdev;
3303 struct block_data *data;
3306 enum block_device_type block_type;
3308 GVariantBuilder *builder = NULL;
3309 const char *error = NULL;
3311 g_variant_get(param, "(s)", &type);
3313 _D("Block (%s) device list is requested.", type);
3315 block_type = get_bdev_type_from_type_string(type);
3316 if (block_type == BLOCK_UNKNOWN_DEV) {
3317 _E("Invalid type (%s) is requested.", type);
3318 error = "Invalid type is requested";
3322 builder = g_variant_builder_new(G_VARIANT_TYPE("a(issssssisibii)"));
3324 for (i = 0; i < THREAD_MAX; i++) {
3325 pthread_mutex_lock(&(th_manager[i].mutex));
3326 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3327 if (!bdev->data || bdev->removed)
3332 if (block_type != BLOCK_ALL_DEV) {
3333 if (data->block_type != block_type)
3337 g_variant_builder_add(builder, "(issssssisibii)",
3339 nullstr(data->devnode),
3340 nullstr(data->syspath),
3341 nullstr(data->fs_usage),
3342 nullstr(data->fs_type),
3343 nullstr(data->fs_version),
3344 nullstr(data->fs_uuid_enc),
3346 nullstr(data->mount_point),
3352 pthread_mutex_unlock(&(th_manager[i].mutex));
3355 reply = g_variant_new("(a(issssssisibii))", builder);
3357 g_variant_builder_unref(builder);
3363 g_dbus_method_invocation_return_error(invocation,
3364 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3369 // Called by MainThread
3370 static GVariant *request_get_device_list_2(GDBusConnection *conn,
3371 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3372 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3374 GVariant *reply = NULL;
3375 struct block_device *bdev;
3376 struct block_data *data;
3379 enum block_device_type block_type;
3381 GVariantBuilder *builder = NULL;
3382 const char *error = NULL;
3384 g_variant_get(param, "(s)", &type);
3386 _E("Delivered type is NULL.");
3387 error = "Delivered type is NULL";
3391 _D("Block (%s) device list is requested.", type);
3393 block_type = get_bdev_type_from_type_string(type);
3394 if (block_type == BLOCK_UNKNOWN_DEV) {
3395 _E("Invalid type (%s) is requested.", type);
3396 error = "Invalid type is requested";
3400 builder = g_variant_builder_new(G_VARIANT_TYPE("a(issssssisibi)"));
3402 for (i = 0; i < THREAD_MAX; i++) {
3403 pthread_mutex_lock(&(th_manager[i].mutex));
3404 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3405 if (!bdev->data || bdev->removed)
3410 if (block_type != BLOCK_ALL_DEV) {
3411 if (data->block_type != block_type)
3415 g_variant_builder_add(builder, "(issssssisibi)",
3417 nullstr(data->devnode),
3418 nullstr(data->syspath),
3419 nullstr(data->fs_usage),
3420 nullstr(data->fs_type),
3421 nullstr(data->fs_version),
3422 nullstr(data->fs_uuid_enc),
3424 nullstr(data->mount_point),
3429 pthread_mutex_unlock(&(th_manager[i].mutex));
3432 reply = g_variant_new("(a(issssssisibi))", builder);
3434 g_variant_builder_unref(builder);
3440 g_dbus_method_invocation_return_error(invocation,
3441 G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
3446 static GVariant *request_get_mmc_primary(GDBusConnection *conn,
3447 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3448 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3450 struct block_device *bdev;
3451 struct block_data *data = NULL, nodata = {0,};
3456 for (i = 0; i < THREAD_MAX; i++) {
3457 pthread_mutex_lock(&(th_manager[i].mutex));
3458 SYS_G_LIST_FOREACH(th_manager[i].block_dev_list, elem, bdev) {
3464 if (data->block_type != BLOCK_MMC_DEV &&
3465 data->block_type != BLOCK_EXTENDEDSD_DEV)
3469 // Return mapper node(/dev/mapper/extendedsd) for primary mmc (not /dev/mmcblk1p1(ex))
3470 if (!strncmp(data->fs_type, LUKS_NAME, strlen(LUKS_NAME)))
3475 pthread_mutex_unlock(&(th_manager[i].mutex));
3481 nodata.id = -ENODEV;
3485 return block_data_to_gvariant(data, -1);
3488 static GVariant *request_check_speed(GDBusConnection *conn,
3489 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3490 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3492 struct timespec start_time, end_time;
3493 struct block_device *bdev;
3494 struct block_data *data;
3502 g_variant_get(param, "(i)", &id);
3504 bdev = find_block_device_by_id(id);
3515 _D("Speed check %s.", data->devnode);
3516 fd = open(data->devnode, O_RDONLY | O_DIRECT);
3518 _E("Failed to open fd(%s): %d", data->devnode, errno);
3522 ret_val = posix_memalign((void**)&buf, 4096, SPEEDCHECK_SIZE << 20);
3524 _E("Failed to posix_memalign().");
3529 clock_gettime(CLOCK_REALTIME, &start_time);
3530 _I("Start time=%lu.%lu", start_time.tv_sec, start_time.tv_nsec);
3531 ret_val = read(fd, buf, SPEEDCHECK_SIZE << 20);
3532 clock_gettime(CLOCK_REALTIME, &end_time);
3533 _I("End time=%lu.%lu", end_time.tv_sec, end_time.tv_nsec);
3538 _E("Failed to read(): %d", errno);
3543 time_diff = end_time.tv_sec - start_time.tv_sec;
3544 if (time_diff > 0 && (SPEEDCHECK_SIZE / time_diff < SPEEDCHECK_CRITERION)) {
3552 return g_variant_new("(i)", result);
3556 static GVariant *request_control_block(GDBusConnection *conn,
3557 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3558 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3563 g_variant_get(param, "(i)", &enable);
3567 _I("Control block disable.");
3572 _I("Control block enable.");
3577 _E("Control block. Wrong request by client.");
3582 return g_variant_new("(i)", result);
3585 static GVariant *request_getcontrol_block(GDBusConnection *conn,
3586 const gchar *sender, const gchar *path, const gchar *iface, const gchar *name,
3587 GVariant *param, GDBusMethodInvocation *invocation, gpointer user_data)
3591 _I("Get control block.");
3593 result = block_control;
3595 return g_variant_new("(i)", result);
3599 Method name Method call format string Reply format string
3600 { "ShowDeviceList", NULL, NULL, request_show_device_list },
3601 { "GetDeviceList", "s", "a(issssssisibii)", request_get_device_list },
3602 { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
3603 { "Mount", "is", "i", request_public_mount_block },
3604 { "Unmoun, "ii", "i", request_public_unmount_block },
3605 { "Format", "ii", "i", request_format_block },
3606 { "GetDeviceInfo", "i", "(issssssisibii)", request_get_device_info },
3607 { "GetMmcPrimary", NULL, "(issssssisibii)" , request_get_mmc_primary },
3608 { "PrivateMount", "is", "i", request_private_mount_block },
3609 { "PrivateUnmount", "ii", "i", request_private_unmount_block },
3612 static const dbus_method_s manager_methods[] = {
3613 { "ShowDeviceList", NULL, NULL, request_show_device_list },
3614 { "GetDeviceList" , "s", "a(issssssisibii)", request_get_device_list },
3615 { "GetDeviceList2", "s", "a(issssssisibi)", request_get_device_list_2 },
3616 { "Mount", "is", "i", request_public_mount_block },
3617 { "Unmount", "ii", "i", request_public_unmount_block },
3618 { "Format", "ii", "i", request_format_block },
3619 { "FormatwithType", "iis", "i", request_format_block_type },
3620 { "GetDeviceInfo", "i", "issssssisibii", request_get_device_info },
3621 { "GetMmcPrimary", NULL, "issssssisibii", request_get_mmc_primary },
3622 { "PrivateMount", "is", "i", request_private_mount_block },
3623 { "PrivateUnmount", "ii", "i", request_private_unmount_block },
3624 { "CheckSpeed", "i", "i", request_check_speed },
3625 { "Control", "i", "i", request_control_block },
3626 { "GetControl", NULL, "i", request_getcontrol_block },
3629 static const dbus_interface_u block_interface = {
3630 .name = STORAGED_INTERFACE_BLOCK_MANAGER,
3631 .methods = manager_methods,
3632 .nr_methods = ARRAY_SIZE(manager_methods),
3635 static int load_config(struct parse_result *result, void *user_data)
3639 if (MATCH(result->section, "Block"))
3642 if (MATCH(result->section, "SCSI"))
3643 index = BLOCK_SCSI_DEV;
3644 else if (MATCH(result->section, "MMC"))
3645 index = BLOCK_MMC_DEV;
3646 else if (MATCH(result->section, "Mapper"))
3647 index = BLOCK_EXTENDEDSD_DEV;
3651 if (MATCH(result->name, "Multimount"))
3652 block_conf[index].multimount =
3653 (MATCH(result->value, "yes") ? true : false);
3654 if (MATCH(result->name, "ExtendedInternalStorage"))
3655 block_conf[index].extendedinternal =
3656 (MATCH(result->value, "yes") ? true : false);
3662 static int mount_root_path_tmpfs(void)
3667 root = tzplatform_getenv(TZ_SYS_MEDIA);
3671 if (access(root, F_OK) != 0)
3674 if (mount_check(root))
3677 ret_val = mount("tmpfs", root, "tmpfs", 0, "smackfsroot=System::Shared");
3680 _E("Failed to mount tmpfs: %d", ret_val);
3687 #define mount_root_path_tmpfs() 0
3690 static guint id_block_poweroff;
3692 static void block_init(void *data)
3700 ret_val = config_parse(BLOCK_CONF_FILE, load_config, NULL);
3702 _E("Failed to load '%s'. Use default value.", BLOCK_CONF_FILE);
3704 ret_val = mount_root_path_tmpfs();
3706 _E("Failed to mount tmpfs to root mount path: %d", ret_val);
3708 /* register block manager object and interface */
3709 ret_val = gdbus_register_object(NULL, STORAGED_PATH_BLOCK_MANAGER, &block_interface);
3711 _E("Failed to register block interface and methods: %d", ret_val);
3714 ret_val = pipe_init();
3716 _E("Failed to init pipe.");
3718 for (i = 0; i < THREAD_MAX; i++) {
3719 th_manager[i].num_dev = 0;
3720 th_manager[i].op_len = 0;
3721 th_manager[i].start_th = false;
3722 th_manager[i].thread_id = i;
3723 pthread_mutex_init(&(th_manager[i].mutex), NULL);
3724 pthread_cond_init(&(th_manager[i].cond), NULL);
3727 ret_val = remove_directory(EXTERNAL_STORAGE_PATH);
3729 _E("Failed to remove directory.");
3730 ret_val = mkdir(EXTERNAL_STORAGE_PATH, 0755);
3732 _E("Failed to make directory: %d", errno);
3734 ret_val = remove_directory(EXTENDED_INTERNAL_PATH);
3736 _E("Failed to remove directory.");
3737 ret_val = mkdir(EXTENDED_INTERNAL_PATH, 0755);
3739 _E("Failed to make directory: %d", errno);
3741 ret_val = get_internal_storage_number();
3743 _E("Failed to get internal storage number.");
3745 id_block_poweroff = gdbus_signal_subscribe(NULL, DEVICED_PATH_POWEROFF,
3746 DEVICED_INTERFACE_POWEROFF,
3747 SIGNAL_POWEROFF_STATE,
3748 block_poweroff, NULL, NULL);
3752 static void terminate_threads(void)
3754 GList *elem, *elem_next;
3757 const int WAIT_TIME = 10;
3759 for (i = 0; i < THREAD_MAX; i++) {
3760 if (th_manager[i].start_th) {
3762 while ((th_manager[i].op_len != 0) && (count < WAIT_TIME)) {
3763 _I("Thread(%d) job is not finished. Wait a second.", th_manager[i].thread_id);
3767 pthread_cancel(th_manager[i].th);
3768 pthread_join(th_manager[i].th, NULL);
3770 SYS_G_LIST_FOREACH_SAFE(th_manager[i].th_node_list, elem, elem_next, temp) {
3771 SYS_G_LIST_REMOVE(th_manager[i].th_node_list, temp);
3777 static void block_exit(void *data)
3783 /* unregister notifier for below each event */
3784 gdbus_signal_unsubscribe(NULL, id_block_poweroff);
3786 /* unregister mmc uevent control routine */
3787 ret_val = unregister_udev_uevent_control(&uh);
3789 _E("Failed to unregister block uevent: %d", ret_val);
3791 /* remove remaining blocks */
3792 remove_whole_block_device();
3794 terminate_threads();
3799 if (add_poweroff_wait) {
3800 ret_val = gdbus_call_sync_with_reply_int(DEVICED_BUS_NAME,
3801 DEVICED_PATH_POWEROFF,
3802 DEVICED_INTERFACE_POWEROFF,
3803 METHOD_REMOVE_POWEROFF_WAIT,
3806 _E("Failed to call "METHOD_REMOVE_POWEROFF_WAIT" method.");
3808 add_poweroff_wait = false;
3811 block_control = false;
3814 static int block_start(void *data)
3817 _E("Cannot be started. Booting is not ready.");
3821 if (block_control) {
3822 _I("Already started.");
3826 block_control = true;
3828 block_init_from_udev_enumerate();
3834 static int block_stop(void *data)
3837 _E("Cannot be stopped. Booting is not ready.");
3841 if (!block_control) {
3842 _I("Already stopped.");
3846 /* remove the existing blocks */
3847 remove_whole_block_device();
3849 block_control = false;
3855 static storaged_module_interface block_module = {
3859 .start = block_start,
3863 __attribute__ ((visibility("default")))storaged_module_interface *
3864 storaged_get_module_interface(void)
3866 return &block_module;