block: Add PrivateMount and PrivateUnmount 75/99875/8
authorpr.jung <pr.jung@samsung.com>
Thu, 24 Nov 2016 09:59:54 +0000 (18:59 +0900)
committerpr.jung <pr.jung@samsung.com>
Thu, 8 Dec 2016 09:13:54 +0000 (18:13 +0900)
- When block device is mounted using PrivateMount,
other operation request is limited.
Only format request by same pid and
unmount & remove request when device is removed physically
is processed after PrivateMount

Change-Id: I0f02d76d05bc807f85cd4a546e5f976bbf6e294c
Signed-off-by: pr.jung <pr.jung@samsung.com>
src/block/block.c

index fd399aa..2b50a3d 100644 (file)
@@ -104,6 +104,12 @@ enum block_dev_operation {
        BLOCK_DEV_REMOVE,
 };
 
+enum private_operation_state {
+       REQ_NORMAL,
+       REQ_PRIVATE,
+       REQ_PRIVATE_FORMAT,
+};
+
 struct operation_queue {
        enum block_dev_operation op;
        DBusMessage *msg;
@@ -116,6 +122,9 @@ struct block_device {
        dd_list *op_queue;
        int thread_id;          /* Current thread ID */
        bool removed;           /* True when device is physically removed but operation is not precessed yet */
+       enum private_operation_state on_private_op;
+       bool mount_point_updated;
+       pid_t private_pid;
 };
 
 struct format_data {
@@ -639,7 +648,8 @@ static int update_block_data(struct block_data *data,
                const char *fs_type,
                const char *fs_version,
                const char *fs_uuid_enc,
-               const char *readonly)
+               const char *readonly,
+               bool mount_point_updated)
 {
        if (!data)
                return -EINVAL;
@@ -666,8 +676,10 @@ static int update_block_data(struct block_data *data,
 
        /* generate_mount_path function should be invoked
         * after fs_uuid_enc is updated */
-       free(data->mount_point);
-       data->mount_point = generate_mount_path(data);
+       if (!mount_point_updated) {
+               free(data->mount_point);
+               data->mount_point = generate_mount_path(data);
+       }
 
        data->readonly = false;
        if (readonly)
@@ -692,6 +704,9 @@ static struct block_device *make_block_device(struct block_data *data)
        bdev->data = data;
        bdev->thread_id = -1;
        bdev->removed = false;
+       bdev->on_private_op = REQ_NORMAL;
+       bdev->private_pid = 0;
+       bdev->mount_point_updated = false;
 
        return bdev;
 }
@@ -859,7 +874,19 @@ static Eina_Bool pipe_cb(void *data, Ecore_Fd_Handler *fdh)
        broadcast_block_info(pdata.op, pdata.bdev->data, pdata.result);
 
        /* Broadcast outside with Block iface */
-       signal_device_changed(pdata.bdev, pdata.op);
+       if (pdata.bdev->on_private_op == REQ_NORMAL)
+               signal_device_changed(pdata.bdev, pdata.op);
+       else if (pdata.bdev->on_private_op == REQ_PRIVATE) {
+               if (pdata.op == BLOCK_DEV_UNMOUNT) {
+                       pdata.bdev->on_private_op = REQ_NORMAL;
+                       _D("Private operation state: %d", pdata.bdev->on_private_op);
+               }
+       } else {
+               if (pdata.op == BLOCK_DEV_MOUNT) {
+                       pdata.bdev->on_private_op = REQ_PRIVATE;
+                       _D("Private operation state: %d", pdata.bdev->on_private_op);
+               }
+       }
 
        if (pdata.op == BLOCK_DEV_REMOVE) {
                thread_id = pdata.bdev->thread_id;
@@ -933,7 +960,7 @@ static bool check_rw_mount(const char *szPath)
        return true;
 }
 
-static int retrieve_udev_device(struct block_data *data)
+static int retrieve_udev_device(struct block_data *data, bool mount_point_updated)
 {
        struct udev *udev;
        struct udev_device *dev;
@@ -960,7 +987,8 @@ static int retrieve_udev_device(struct block_data *data)
                        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"));
+                       udev_device_get_sysattr_value(dev, "ro"),
+                       mount_point_updated);
        if (r < 0)
                _E("fail to update block data for %s", data->devnode);
 
@@ -1085,10 +1113,13 @@ static int change_mount_point(struct block_device *bdev,
 
        /* If the mount path already exists, the path cannot be used */
        if (mount_point &&
-               access(mount_point, F_OK) != 0)
+               access(mount_point, F_OK) != 0) {
                data->mount_point = strdup(mount_point);
-       else
+               bdev->mount_point_updated = true;
+       } else {
                data->mount_point = generate_mount_path(data);
+               bdev->mount_point_updated = false;
+       }
 
        return 0;
 }
@@ -1249,7 +1280,7 @@ out:
 }
 
 static int block_format(struct block_data *data,
-               const char *fs_type)
+               const char *fs_type, bool mount_point_updated)
 {
        const struct block_fs_ops *fs;
        dd_list *elem;
@@ -1285,7 +1316,7 @@ static int block_format(struct block_data *data,
 
        /* need to update the partition data.
         * It can be changed in doing format. */
-       retrieve_udev_device(data);
+       retrieve_udev_device(data, mount_point_updated);
 
 out:
        return r;
@@ -1314,7 +1345,7 @@ static int format_block_device(struct block_device *bdev,
                }
        }
 
-       r = block_format(data, fs_type);
+       r = block_format(data, fs_type, bdev->mount_point_updated);
        if (r < 0)
                _E("fail to format %s device : %d", data->devnode, r);
 
@@ -1810,6 +1841,7 @@ static int add_operation(struct block_device *bdev,
        if (!bdev)
                return -EINVAL;
 
+
        _D("Add operation (%s, %s)",
                        get_operation_char(operation, name, sizeof(name)),
                        bdev->data->devnode);
@@ -2017,6 +2049,11 @@ static int remove_block_device(struct udev_device *dev, const char *devnode)
        BLOCK_FLAG_SET(bdev->data, UNMOUNT_UNSAFE);
 
        bdev->removed = true;
+       if (bdev->on_private_op) {
+               bdev->on_private_op = REQ_NORMAL;
+               _D("Private operation state: %d", bdev->on_private_op);
+       }
+
        ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
        if (ret < 0) {
                _E("Failed to add operation (unmount %s)", devnode);
@@ -2339,7 +2376,7 @@ static void uevent_block_handler(struct udev_device *dev)
 }
 
 static DBusMessage *request_mount_block(E_DBus_Object *obj,
-               DBusMessage *msg)
+               DBusMessage *msg, bool onprivate)
 {
        struct block_device *bdev;
        char *mount_point;
@@ -2355,12 +2392,17 @@ static DBusMessage *request_mount_block(E_DBus_Object *obj,
                        DBUS_TYPE_INVALID);
        if (!ret)
                goto out;
+
        bdev = find_block_device_by_id(id);
        if (!bdev) {
                _E("Failed to find (%d) in the device list", id);
                ret = -ENOENT;
                goto out;
        }
+       if (bdev->on_private_op != REQ_NORMAL) {
+               ret = -EPERM;
+               goto out;
+       }
 
        if (bdev->data->state == BLOCK_MOUNT) {
                _I("%s is already mounted", bdev->data->devnode);
@@ -2368,6 +2410,18 @@ static DBusMessage *request_mount_block(E_DBus_Object *obj,
                goto out;
        }
 
+       if (onprivate) {
+               bdev->on_private_op = REQ_PRIVATE;
+               bdev->private_pid = get_edbus_sender_pid(msg);
+               _D("Private operation state: %d", bdev->on_private_op);
+       } else {
+               if (bdev->on_private_op != REQ_NORMAL) {
+                       _E("Failed to process mount operation");
+                       ret = -EPERM;
+                       goto out;
+               }
+       }
+
        /* if requester want to use a specific mount point */
        if (mount_point && strncmp(mount_point, "", 1) != 0) {
                ret = change_mount_point(bdev, mount_point);
@@ -2392,10 +2446,23 @@ out:
        return make_reply_message(msg, ret);
 }
 
-static DBusMessage *request_unmount_block(E_DBus_Object *obj,
+static DBusMessage *request_public_mount_block(E_DBus_Object *obj,
                DBusMessage *msg)
 {
+       return request_mount_block(obj, msg, false);
+}
+
+static DBusMessage *request_private_mount_block(E_DBus_Object *obj,
+               DBusMessage *msg)
+{
+       return request_mount_block(obj, msg, true);
+}
+
+static DBusMessage *request_unmount_block(E_DBus_Object *obj,
+               DBusMessage *msg, bool onprivate)
+{
        struct block_device *bdev;
+       pid_t pid;
        long option;
        int id;
        int ret = -EBADMSG;
@@ -2409,6 +2476,7 @@ static DBusMessage *request_unmount_block(E_DBus_Object *obj,
                        DBUS_TYPE_INVALID);
        if (!ret)
                goto out;
+
        bdev = find_block_device_by_id(id);
        if (!bdev) {
                _E("Failed to find (%d) in the device list", id);
@@ -2416,6 +2484,21 @@ static DBusMessage *request_unmount_block(E_DBus_Object *obj,
                goto out;
        }
 
+       if (onprivate) {
+               pid = get_edbus_sender_pid(msg);
+               if (bdev->on_private_op == REQ_NORMAL || (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid)) {
+                       _E("Failed to process private unmount operation");
+                       ret = -EPERM;
+                       goto out;
+               }
+       } else {
+               if (bdev->on_private_op != REQ_NORMAL) {
+                       _E("Failed to process unmount operation");
+                       ret = -EPERM;
+                       goto out;
+               }
+       }
+
        ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, msg, (void *)option);
        if (ret < 0) {
                _E("Failed to add operation (unmount %s)", bdev->data->devnode);
@@ -2428,11 +2511,24 @@ out:
        return make_reply_message(msg, ret);
 }
 
+static DBusMessage *request_public_unmount_block(E_DBus_Object *obj,
+               DBusMessage *msg)
+{
+       return request_unmount_block(obj, msg, false);
+}
+
+static DBusMessage *request_private_unmount_block(E_DBus_Object *obj,
+               DBusMessage *msg)
+{
+       return request_unmount_block(obj, msg, true);
+}
+
 static DBusMessage *request_format_block(E_DBus_Object *obj,
                DBusMessage *msg)
 {
        struct block_device *bdev;
        struct format_data *fdata;
+       pid_t pid;
        int id;
        int option;
        int ret = -EBADMSG;
@@ -2447,11 +2543,18 @@ static DBusMessage *request_format_block(E_DBus_Object *obj,
                        DBUS_TYPE_INVALID);
        if (!ret)
                goto out;
+
        bdev = find_block_device_by_id(id);
        if (!bdev) {
                _E("Failed to find (%d) in the device list", id);
                goto out;
        }
+       pid = get_edbus_sender_pid(msg);
+       if (bdev->on_private_op != REQ_NORMAL && pid != bdev->private_pid) {
+               _E("Failed to format on private state");
+               ret = -EPERM;
+               goto out;
+       }
 
        fdata = get_format_data(NULL, option);
        if (!fdata) {
@@ -2459,8 +2562,12 @@ static DBusMessage *request_format_block(E_DBus_Object *obj,
                goto out;
        }
 
-       prev_state =  bdev->data->state;
+       prev_state = bdev->data->state;
        if (prev_state == BLOCK_MOUNT) {
+               if (bdev->on_private_op == REQ_PRIVATE) {
+                       bdev->on_private_op = REQ_PRIVATE_FORMAT;
+                       _D("Private operation state: %d", bdev->on_private_op);
+               }
                ret = add_operation(bdev, BLOCK_DEV_UNMOUNT, NULL, (void *)UNMOUNT_FORCE);
                if (ret < 0) {
                        _E("Failed to add operation (unmount %s)", bdev->data->devnode);
@@ -2825,11 +2932,13 @@ static const struct edbus_method manager_methods[] = {
        { "ShowDeviceList", NULL,               NULL, request_show_device_list },
        { "GetDeviceList" ,  "s", "a(issssssisibii)", request_get_device_list },
        { "GetDeviceList2",  "s",  "a(issssssisibi)", request_get_device_list_2 },
-       { "Mount",          "is",                "i", request_mount_block },
-       { "Unmount",        "ii",                "i", request_unmount_block },
+       { "Mount",          "is",                "i", request_public_mount_block },
+       { "Unmount",        "ii",                "i", request_public_unmount_block },
        { "Format",         "ii",                "i", request_format_block },
        { "GetDeviceInfo",   "i",  "(issssssisibii)", request_get_device_info },
        { "GetMmcPrimary" , NULL, "(issssssisibii)" , request_get_mmc_primary },
+       { "PrivateMount",    "is",                "i", request_private_mount_block },
+       { "PrivateUnmount",  "ii",                "i", request_private_unmount_block },
 };
 
 static int load_config(struct parse_result *result, void *user_data)