summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiyoung Yun <jy910.yun@samsung.com>2015-05-26 14:32:24 +0900
committerJiyoung Yun <jy910.yun@samsung.com>2015-05-29 17:23:51 +0900
commit981f9b524fec1872cc1a89922208533123d98c0f (patch)
tree9e872cd9d2fc05b04475cc15710d1060504c07f9
parent7807bd9c91e0069a7f873ef70afd33abca8e4992 (diff)
downloaddeviced-981f9b524fec1872cc1a89922208533123d98c0f.tar.gz
deviced-981f9b524fec1872cc1a89922208533123d98c0f.tar.bz2
deviced-981f9b524fec1872cc1a89922208533123d98c0f.zip
block: Add format operation
When user request to format a specific block device, it will format the device and update the related information. The uuid is always updated by formatting. Change-Id: I35eb468e53204e2d833b59ef71a7f6a5cd0a006c Signed-off-by: Jiyoung Yun <jy910.yun@samsung.com>
-rw-r--r--src/block/block.c238
-rw-r--r--src/block/block.h5
2 files changed, 243 insertions, 0 deletions
diff --git a/src/block/block.c b/src/block/block.c
index fc8b6e40..0426b8b6 100644
--- a/src/block/block.c
+++ b/src/block/block.c
@@ -67,6 +67,12 @@ struct block_device {
struct block_data *data;
};
+struct format_data {
+ struct block_device *bdev;
+ char *fs_type;
+ enum unmount_operation option;
+};
+
static dd_list *fs_head;
static dd_list *block_dev_list;
static dd_list *block_ops_list;
@@ -147,6 +153,7 @@ static void broadcast_block_info(enum block_dev_operation op,
/* Whole data in struct block_data should be freed. */
static struct block_data *make_block_data(const char *devnode,
+ const char *syspath,
const char *fs_usage,
const char *fs_type,
const char *fs_version,
@@ -162,6 +169,8 @@ static struct block_data *make_block_data(const char *devnode,
if (devnode)
data->devnode = strdup(devnode);
+ if (syspath)
+ data->syspath = strdup(syspath);
if (fs_usage)
data->fs_usage = strdup(fs_usage);
if (fs_type)
@@ -193,6 +202,7 @@ static void free_block_data(struct block_data *data)
if (!data)
return;
free(data->devnode);
+ free(data->syspath);
free(data->fs_usage);
free(data->fs_type);
free(data->fs_version);
@@ -201,6 +211,51 @@ static void free_block_data(struct block_data *data)
free(data);
}
+static int update_block_data(struct block_data *data,
+ const char *fs_usage,
+ const char *fs_type,
+ const char *fs_version,
+ const char *fs_uuid_enc,
+ const char *readonly)
+{
+ const char *str;
+
+ if (!data)
+ return -EINVAL;
+
+ free(data->fs_usage);
+ data->fs_usage = NULL;
+ if (fs_usage)
+ data->fs_usage = strdup(fs_usage);
+
+ free(data->fs_type);
+ data->fs_type = NULL;
+ if (fs_type)
+ data->fs_type = strdup(fs_type);
+
+ free(data->fs_version);
+ data->fs_version = NULL;
+ if (fs_version)
+ data->fs_version = strdup(fs_version);
+
+ free(data->fs_uuid_enc);
+ data->fs_uuid_enc = NULL;
+ free(data->mount_point);
+ data->mount_point = NULL;
+ if (fs_uuid_enc) {
+ data->fs_uuid_enc = strdup(fs_uuid_enc);
+ str = tzplatform_mkpath(TZ_SYS_STORAGE, fs_uuid_enc);
+ if (str)
+ data->mount_point = strdup(str);
+ }
+
+ data->readonly = false;
+ if (readonly)
+ data->readonly = atoi(readonly);
+
+ return 0;
+}
+
static struct block_device *make_block_device(struct block_data *data)
{
struct block_device *bdev;
@@ -269,6 +324,42 @@ static bool check_rw_mount(const char *szPath)
return true;
}
+static int retrieve_udev_device(struct block_data *data)
+{
+ struct udev *udev;
+ struct udev_device *dev;
+ int r;
+
+ if (!data)
+ return -EINVAL;
+
+ udev = udev_new();
+ if (!udev) {
+ _E("fail to create udev library context");
+ return -EPERM;
+ }
+
+ dev = udev_device_new_from_syspath(udev, data->syspath);
+ if (!dev) {
+ _E("fail to create new udev device");
+ udev_unref(udev);
+ return -EPERM;
+ }
+
+ r = update_block_data(data,
+ udev_device_get_property_value(dev, "ID_FS_USAGE"),
+ udev_device_get_property_value(dev, "ID_FS_TYPE"),
+ udev_device_get_property_value(dev, "ID_FS_VERSION"),
+ udev_device_get_property_value(dev, "ID_FS_UUID_ENC"),
+ udev_device_get_sysattr_value(dev, "ro"));
+ if (r < 0)
+ _E("fail to update block data for %s", data->devnode);
+
+ udev_device_unref(dev);
+ udev_unref(udev);
+ return r;
+}
+
static int block_mount(struct block_data *data)
{
struct block_fs_ops *fs;
@@ -505,6 +596,151 @@ out:
return r;
}
+static int block_format(struct block_data *data,
+ const char *fs_type)
+{
+ const struct block_fs_ops *fs;
+ dd_list *elem;
+ int len;
+ int r;
+
+ if (!data || !data->devnode || !data->mount_point)
+ return -EINVAL;
+
+ if (!fs_type)
+ fs_type = data->fs_type;
+
+ fs = NULL;
+ len = strlen(fs_type);
+ DD_LIST_FOREACH(fs_head, elem, fs) {
+ if (!strncmp(fs->name, fs_type, len))
+ break;
+ }
+
+ if (!fs) {
+ _E("not supported file system(%s)", fs_type);
+ return -ENOTSUP;
+ }
+
+ _I("format path : %s", data->devnode);
+ fs->check(data->devnode);
+ r = fs->format(data->devnode);
+ if (r < 0) {
+ _E("fail to format block data for %s", data->devnode);
+ goto out;
+ }
+
+ /* need to update the partition data.
+ * It can be changed in doing format. */
+ retrieve_udev_device(data);
+
+out:
+ return r;
+}
+
+/* runs in thread */
+static void *format_start(void *arg)
+{
+ struct format_data *fdata = (struct format_data *)arg;
+ struct block_device *bdev;
+ struct block_data *data;
+ int r;
+ int t;
+
+ assert(fdata);
+ assert(fdata->bdev);
+ assert(fdata->bdev->data);
+
+ bdev = fdata->bdev;
+ data = bdev->data;
+
+ _I("Format Start : (%s -> %s)",
+ data->devnode, data->mount_point);
+
+ pthread_mutex_lock(&bdev->mutex);
+
+ if (data->state == BLOCK_MOUNT) {
+ r = block_unmount(data, fdata->option);
+ if (r < 0) {
+ _E("fail to unmount %s device : %d", data->devnode, r);
+ goto out;
+ }
+ data->state = BLOCK_UNMOUNT;
+ }
+
+ r = block_format(data, fdata->fs_type);
+ if (r < 0)
+ _E("fail to format %s device : %d", data->devnode, r);
+
+ /* mount block device even if format is failed */
+ t = block_mount(data);
+ if (t != -EROFS && t < 0) {
+ _E("fail to mount %s device : %d", data->devnode, t);
+ goto out;
+ }
+
+ if (t == -EROFS)
+ data->readonly = true;
+
+ data->state = BLOCK_MOUNT;
+
+out:
+ _I("%s result : %s, %d", __func__, data->devnode, r);
+ pthread_mutex_unlock(&bdev->mutex);
+
+ /* Broadcast to mmc and usb storage module */
+ broadcast_block_info(BLOCK_DEV_FORMAT, data, r);
+
+ free(fdata);
+
+ return NULL;
+}
+
+int format_block_device(const char *devnode,
+ const char *fs_type,
+ enum unmount_operation option)
+{
+ struct block_device *bdev;
+ struct block_data *data;
+ struct format_data *fdata;
+ pthread_t th;
+ int r;
+
+ if (!devnode) {
+ _E("invalid parameter");
+ return -EINVAL;
+ }
+
+ bdev = find_block_device(devnode);
+ if (!bdev || !bdev->data) {
+ _E("fail to find block data for %s", devnode);
+ return -ENODEV;
+ }
+
+ data = bdev->data;
+ fdata = malloc(sizeof(struct format_data));
+ if (!fdata) {
+ _E("fail to allocate format data for %s", data->devnode);
+ return -EPERM;
+ }
+
+ fdata->bdev = bdev;
+ if (fs_type)
+ fdata->fs_type = strdup(fs_type);
+ else
+ fdata->fs_type = NULL;
+ fdata->option = option;
+
+ r = pthread_create(&th, NULL, format_start, fdata);
+ if (r != 0) {
+ _E("fail to create thread for %s", data->devnode);
+ return -EPERM;
+ }
+
+ pthread_detach(th);
+ return 0;
+}
+
static bool disk_is_partitioned_by_kernel(struct udev_device *dev)
{
DIR *dp;
@@ -591,6 +827,7 @@ static int add_block_device(struct udev_device *dev, const char *devnode)
}
data = make_block_data(devnode,
+ udev_device_get_syspath(dev),
udev_device_get_property_value(dev, "ID_FS_USAGE"),
udev_device_get_property_value(dev, "ID_FS_TYPE"),
udev_device_get_property_value(dev, "ID_FS_VERSION"),
@@ -730,6 +967,7 @@ static void show_block_device_list(void)
if (!data)
continue;
_D("%s:", data->devnode);
+ _D("\tSyspath: %s", data->syspath);
_D("\tBlock type: %s",
(data->block_type == BLOCK_MMC_DEV ?
"mmc" : "scsi"));
diff --git a/src/block/block.h b/src/block/block.h
index 9e0fe671..36f0827b 100644
--- a/src/block/block.h
+++ b/src/block/block.h
@@ -70,6 +70,7 @@ enum unmount_operation {
struct block_data {
enum block_device_type block_type;
char *devnode;
+ char *syspath;
char *fs_usage;
char *fs_type;
char *fs_version;
@@ -105,5 +106,9 @@ static void __DESTRUCTOR__ block_dev_exit(void) \
int mount_block_device(const char *devnode);
int unmount_block_device(const char *devnode,
enum unmount_operation option);
+/* if fs_type is null, it will use the exisiting fs type */
+int format_block_device(const char *devnode,
+ const char *fs_type,
+ enum unmount_operation option);
#endif /* __BLOCK_H__ */