162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * fs/hmdfs/file_merge.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020-2021 Huawei Device Co., Ltd. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include "hmdfs_merge_view.h" 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/file.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "hmdfs.h" 1362306a36Sopenharmony_ci#include "hmdfs_trace.h" 1462306a36Sopenharmony_ci#include "authority/authentication.h" 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistruct hmdfs_iterate_callback_merge { 1762306a36Sopenharmony_ci struct dir_context ctx; 1862306a36Sopenharmony_ci struct dir_context *caller; 1962306a36Sopenharmony_ci /* 2062306a36Sopenharmony_ci * Record the return value of 'caller->actor': 2162306a36Sopenharmony_ci * 2262306a36Sopenharmony_ci * false, buffer is exhausted 2362306a36Sopenharmony_ci * false, current task is pending 2462306a36Sopenharmony_ci * false, something is wrong 2562306a36Sopenharmony_ci * true, success and can do more 2662306a36Sopenharmony_ci */ 2762306a36Sopenharmony_ci bool result ; 2862306a36Sopenharmony_ci struct rb_root *root; 2962306a36Sopenharmony_ci uint64_t dev_id; 3062306a36Sopenharmony_ci}; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_cistruct hmdfs_cache_entry { 3362306a36Sopenharmony_ci struct rb_node rb_node; 3462306a36Sopenharmony_ci int name_len; 3562306a36Sopenharmony_ci char *name; 3662306a36Sopenharmony_ci int file_type; 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_cistruct hmdfs_user_info { 4062306a36Sopenharmony_ci char *local_path; 4162306a36Sopenharmony_ci char *distributed_path; 4262306a36Sopenharmony_ci char *bundle_name; 4362306a36Sopenharmony_ci}; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_cistruct hmdfs_cache_entry *allocate_entry(const char *name, int namelen, 4662306a36Sopenharmony_ci int d_type) 4762306a36Sopenharmony_ci{ 4862306a36Sopenharmony_ci struct hmdfs_cache_entry *data; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_ci data = kmalloc(sizeof(*data), GFP_KERNEL); 5162306a36Sopenharmony_ci if (!data) 5262306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci data->name = kstrndup(name, namelen, GFP_KERNEL); 5562306a36Sopenharmony_ci if (!data->name) { 5662306a36Sopenharmony_ci kfree(data); 5762306a36Sopenharmony_ci return ERR_PTR(-ENOMEM); 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci data->name_len = namelen; 6162306a36Sopenharmony_ci data->file_type = d_type; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci return data; 6462306a36Sopenharmony_ci} 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciint insert_filename(struct rb_root *root, struct hmdfs_cache_entry **new_entry) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct rb_node *parent = NULL; 6962306a36Sopenharmony_ci struct rb_node **new_node = &(root->rb_node); 7062306a36Sopenharmony_ci int cmp_res = 0; 7162306a36Sopenharmony_ci struct hmdfs_cache_entry *data = *new_entry; 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci while (*new_node) { 7462306a36Sopenharmony_ci struct hmdfs_cache_entry *entry = container_of( 7562306a36Sopenharmony_ci *new_node, struct hmdfs_cache_entry, rb_node); 7662306a36Sopenharmony_ci parent = *new_node; 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (data->name_len < entry->name_len) 7962306a36Sopenharmony_ci cmp_res = -1; 8062306a36Sopenharmony_ci else if (data->name_len > entry->name_len) 8162306a36Sopenharmony_ci cmp_res = 1; 8262306a36Sopenharmony_ci else 8362306a36Sopenharmony_ci cmp_res = strncmp(data->name, entry->name, 8462306a36Sopenharmony_ci data->name_len); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (!cmp_res) { 8762306a36Sopenharmony_ci kfree(data->name); 8862306a36Sopenharmony_ci kfree(data); 8962306a36Sopenharmony_ci *new_entry = entry; 9062306a36Sopenharmony_ci return entry->file_type; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (cmp_res < 0) 9462306a36Sopenharmony_ci new_node = &((*new_node)->rb_left); 9562306a36Sopenharmony_ci else if (cmp_res > 0) 9662306a36Sopenharmony_ci new_node = &((*new_node)->rb_right); 9762306a36Sopenharmony_ci } 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci rb_link_node(&data->rb_node, parent, new_node); 10062306a36Sopenharmony_ci rb_insert_color(&data->rb_node, root); 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci return 0; 10362306a36Sopenharmony_ci} 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cistatic void recursive_delete(struct rb_node *node) 10662306a36Sopenharmony_ci{ 10762306a36Sopenharmony_ci struct hmdfs_cache_entry *entry = NULL; 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if (!node) 11062306a36Sopenharmony_ci return; 11162306a36Sopenharmony_ci 11262306a36Sopenharmony_ci recursive_delete(node->rb_left); 11362306a36Sopenharmony_ci recursive_delete(node->rb_right); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci entry = container_of(node, struct hmdfs_cache_entry, rb_node); 11662306a36Sopenharmony_ci kfree(entry->name); 11762306a36Sopenharmony_ci kfree(entry); 11862306a36Sopenharmony_ci} 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_cistatic void destroy_tree(struct rb_root *root) 12162306a36Sopenharmony_ci{ 12262306a36Sopenharmony_ci if (!root) 12362306a36Sopenharmony_ci return; 12462306a36Sopenharmony_ci recursive_delete(root->rb_node); 12562306a36Sopenharmony_ci root->rb_node = NULL; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic void delete_filename(struct rb_root *root, 12962306a36Sopenharmony_ci struct hmdfs_cache_entry *data) 13062306a36Sopenharmony_ci{ 13162306a36Sopenharmony_ci struct rb_node **node = &(root->rb_node); 13262306a36Sopenharmony_ci struct hmdfs_cache_entry *entry = NULL; 13362306a36Sopenharmony_ci int cmp_res = 0; 13462306a36Sopenharmony_ci 13562306a36Sopenharmony_ci while (*node) { 13662306a36Sopenharmony_ci entry = container_of(*node, struct hmdfs_cache_entry, rb_node); 13762306a36Sopenharmony_ci if (data->name_len < entry->name_len) 13862306a36Sopenharmony_ci cmp_res = -1; 13962306a36Sopenharmony_ci else if (data->name_len > entry->name_len) 14062306a36Sopenharmony_ci cmp_res = 1; 14162306a36Sopenharmony_ci else 14262306a36Sopenharmony_ci cmp_res = strncmp(data->name, entry->name, 14362306a36Sopenharmony_ci data->name_len); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (!cmp_res) 14662306a36Sopenharmony_ci goto found; 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (cmp_res < 0) 14962306a36Sopenharmony_ci node = &((*node)->rb_left); 15062306a36Sopenharmony_ci else if (cmp_res > 0) 15162306a36Sopenharmony_ci node = &((*node)->rb_right); 15262306a36Sopenharmony_ci } 15362306a36Sopenharmony_ci return; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_cifound: 15662306a36Sopenharmony_ci rb_erase(*node, root); 15762306a36Sopenharmony_ci kfree(entry->name); 15862306a36Sopenharmony_ci kfree(entry); 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic void rename_conflicting_file(char *dentry_name, int *len, 16262306a36Sopenharmony_ci unsigned int dev_id) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci int i = *len - 1; 16562306a36Sopenharmony_ci int dot_pos = -1; 16662306a36Sopenharmony_ci char *buffer; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci buffer = kzalloc(DENTRY_NAME_MAX_LEN, GFP_KERNEL); 16962306a36Sopenharmony_ci if (!buffer) 17062306a36Sopenharmony_ci return; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci while (i >= 0) { 17362306a36Sopenharmony_ci if (dentry_name[i] == '/') 17462306a36Sopenharmony_ci break; 17562306a36Sopenharmony_ci if (dentry_name[i] == '.') { 17662306a36Sopenharmony_ci // TODO: 这个修改同步到 CT01 17762306a36Sopenharmony_ci dot_pos = i; 17862306a36Sopenharmony_ci break; 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci i--; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci if (dot_pos == -1) { 18462306a36Sopenharmony_ci snprintf(dentry_name + *len, DENTRY_NAME_MAX_LEN - *len, 18562306a36Sopenharmony_ci CONFLICTING_FILE_SUFFIX, dev_id); 18662306a36Sopenharmony_ci goto done; 18762306a36Sopenharmony_ci } 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci for (i = 0; i < *len - dot_pos; i++) 19062306a36Sopenharmony_ci buffer[i] = dentry_name[i + dot_pos]; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci buffer[i] = '\0'; 19362306a36Sopenharmony_ci snprintf(dentry_name + dot_pos, DENTRY_NAME_MAX_LEN - dot_pos, 19462306a36Sopenharmony_ci CONFLICTING_FILE_SUFFIX, dev_id); 19562306a36Sopenharmony_ci strcat(dentry_name, buffer); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_cidone: 19862306a36Sopenharmony_ci *len = strlen(dentry_name); 19962306a36Sopenharmony_ci kfree(buffer); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_cistatic void rename_conflicting_directory(char *dentry_name, int *len) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci snprintf(dentry_name + *len, DENTRY_NAME_MAX_LEN - *len, 20562306a36Sopenharmony_ci CONFLICTING_DIR_SUFFIX); 20662306a36Sopenharmony_ci *len += strlen(CONFLICTING_DIR_SUFFIX); 20762306a36Sopenharmony_ci} 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_cistatic bool hmdfs_actor_merge(struct dir_context *ctx, const char *name, 21062306a36Sopenharmony_ci int namelen, long long offset, unsigned long long ino, 21162306a36Sopenharmony_ci unsigned int d_type) 21262306a36Sopenharmony_ci{ 21362306a36Sopenharmony_ci bool ret = true; 21462306a36Sopenharmony_ci int insert_res = 0; 21562306a36Sopenharmony_ci int max_devid_len = 2; 21662306a36Sopenharmony_ci char *dentry_name = NULL; 21762306a36Sopenharmony_ci int dentry_len = namelen; 21862306a36Sopenharmony_ci struct hmdfs_cache_entry *cache_entry = NULL; 21962306a36Sopenharmony_ci struct hmdfs_iterate_callback_merge *iterate_callback_merge = NULL; 22062306a36Sopenharmony_ci struct dir_context *org_ctx = NULL; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (hmdfs_file_type(name) != HMDFS_TYPE_COMMON) { 22362306a36Sopenharmony_ci /* 22462306a36Sopenharmony_ci * return true here, so that the caller can continue to next 22562306a36Sopenharmony_ci * dentry even if failed on this dentry somehow. 22662306a36Sopenharmony_ci */ 22762306a36Sopenharmony_ci return true; 22862306a36Sopenharmony_ci } 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_ci if (namelen > NAME_MAX) 23262306a36Sopenharmony_ci return false; 23362306a36Sopenharmony_ci dentry_name = kzalloc(NAME_MAX + 1, GFP_KERNEL); 23462306a36Sopenharmony_ci if (!dentry_name) 23562306a36Sopenharmony_ci return false; 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci strncpy(dentry_name, name, dentry_len); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci cache_entry = allocate_entry(dentry_name, dentry_len, d_type); 24062306a36Sopenharmony_ci if (IS_ERR(cache_entry)) { 24162306a36Sopenharmony_ci ret = PTR_ERR(cache_entry); 24262306a36Sopenharmony_ci goto done; 24362306a36Sopenharmony_ci } 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci iterate_callback_merge = 24662306a36Sopenharmony_ci container_of(ctx, struct hmdfs_iterate_callback_merge, ctx); 24762306a36Sopenharmony_ci insert_res = 24862306a36Sopenharmony_ci insert_filename(iterate_callback_merge->root, &cache_entry); 24962306a36Sopenharmony_ci if (d_type == DT_DIR && insert_res == DT_DIR) { 25062306a36Sopenharmony_ci goto done; 25162306a36Sopenharmony_ci } else if (d_type == DT_DIR && 25262306a36Sopenharmony_ci (insert_res == DT_REG || insert_res == DT_LNK)) { 25362306a36Sopenharmony_ci if (strlen(CONFLICTING_DIR_SUFFIX) > NAME_MAX - dentry_len) { 25462306a36Sopenharmony_ci ret = false; 25562306a36Sopenharmony_ci goto delete; 25662306a36Sopenharmony_ci } 25762306a36Sopenharmony_ci rename_conflicting_directory(dentry_name, &dentry_len); 25862306a36Sopenharmony_ci cache_entry->file_type = DT_DIR; 25962306a36Sopenharmony_ci } else if ((d_type == DT_REG || d_type == DT_LNK) && insert_res > 0) { 26062306a36Sopenharmony_ci if (strlen(CONFLICTING_FILE_SUFFIX) + max_devid_len > 26162306a36Sopenharmony_ci NAME_MAX - dentry_len) { 26262306a36Sopenharmony_ci ret = false; 26362306a36Sopenharmony_ci goto delete; 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci rename_conflicting_file(dentry_name, &dentry_len, 26662306a36Sopenharmony_ci iterate_callback_merge->dev_id); 26762306a36Sopenharmony_ci } 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci org_ctx = iterate_callback_merge->caller; 27062306a36Sopenharmony_ci ret = org_ctx->actor(org_ctx, dentry_name, dentry_len, org_ctx->pos, 27162306a36Sopenharmony_ci ino, d_type); 27262306a36Sopenharmony_ci /* 27362306a36Sopenharmony_ci * Record original return value, so that the caller can be aware of 27462306a36Sopenharmony_ci * different situations. 27562306a36Sopenharmony_ci */ 27662306a36Sopenharmony_ci iterate_callback_merge->result = ret; 27762306a36Sopenharmony_ci if (!ret && d_type == DT_DIR && cache_entry->file_type == DT_DIR && 27862306a36Sopenharmony_ci (insert_res == DT_REG || insert_res == DT_LNK)) 27962306a36Sopenharmony_ci cache_entry->file_type = DT_REG; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_cidelete: 28262306a36Sopenharmony_ci if (!ret && !insert_res) 28362306a36Sopenharmony_ci delete_filename(iterate_callback_merge->root, cache_entry); 28462306a36Sopenharmony_cidone: 28562306a36Sopenharmony_ci kfree(dentry_name); 28662306a36Sopenharmony_ci return ret; 28762306a36Sopenharmony_ci} 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_cistruct hmdfs_file_info * 29062306a36Sopenharmony_ciget_next_hmdfs_file_info(struct hmdfs_file_info *fi_head, int device_id) 29162306a36Sopenharmony_ci{ 29262306a36Sopenharmony_ci struct hmdfs_file_info *fi_iter = NULL; 29362306a36Sopenharmony_ci struct hmdfs_file_info *fi_result = NULL; 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci mutex_lock(&fi_head->comrade_list_lock); 29662306a36Sopenharmony_ci list_for_each_entry_safe(fi_iter, fi_result, &(fi_head->comrade_list), 29762306a36Sopenharmony_ci comrade_list) { 29862306a36Sopenharmony_ci if (fi_iter->device_id == device_id) 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci } 30162306a36Sopenharmony_ci mutex_unlock(&fi_head->comrade_list_lock); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci return fi_result != fi_head ? fi_result : NULL; 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_cistruct hmdfs_file_info *get_hmdfs_file_info(struct hmdfs_file_info *fi_head, 30762306a36Sopenharmony_ci int device_id) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct hmdfs_file_info *fi_iter = NULL; 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_ci mutex_lock(&fi_head->comrade_list_lock); 31262306a36Sopenharmony_ci list_for_each_entry(fi_iter, &(fi_head->comrade_list), comrade_list) { 31362306a36Sopenharmony_ci if (fi_iter->device_id == device_id) { 31462306a36Sopenharmony_ci mutex_unlock(&fi_head->comrade_list_lock); 31562306a36Sopenharmony_ci return fi_iter; 31662306a36Sopenharmony_ci } 31762306a36Sopenharmony_ci } 31862306a36Sopenharmony_ci mutex_unlock(&fi_head->comrade_list_lock); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci return NULL; 32162306a36Sopenharmony_ci} 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ciint hmdfs_iterate_merge(struct file *file, struct dir_context *ctx) 32462306a36Sopenharmony_ci{ 32562306a36Sopenharmony_ci int err = 0; 32662306a36Sopenharmony_ci struct hmdfs_file_info *fi_head = hmdfs_f(file); 32762306a36Sopenharmony_ci struct hmdfs_file_info *fi_iter = NULL; 32862306a36Sopenharmony_ci struct file *lower_file_iter = NULL; 32962306a36Sopenharmony_ci loff_t start_pos = ctx->pos; 33062306a36Sopenharmony_ci unsigned long device_id = (unsigned long)((ctx->pos) << 1 >> 33162306a36Sopenharmony_ci (POS_BIT_NUM - DEV_ID_BIT_NUM)); 33262306a36Sopenharmony_ci struct hmdfs_iterate_callback_merge ctx_merge = { 33362306a36Sopenharmony_ci .ctx.actor = hmdfs_actor_merge, 33462306a36Sopenharmony_ci .caller = ctx, 33562306a36Sopenharmony_ci .root = &fi_head->root, 33662306a36Sopenharmony_ci .dev_id = device_id 33762306a36Sopenharmony_ci }; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci /* pos = -1 indicates that all devices have been traversed 34062306a36Sopenharmony_ci * or an error has occurred. 34162306a36Sopenharmony_ci */ 34262306a36Sopenharmony_ci if (ctx->pos == -1) 34362306a36Sopenharmony_ci return 0; 34462306a36Sopenharmony_ci 34562306a36Sopenharmony_ci fi_iter = get_hmdfs_file_info(fi_head, device_id); 34662306a36Sopenharmony_ci if (!fi_iter) { 34762306a36Sopenharmony_ci fi_iter = get_next_hmdfs_file_info(fi_head, device_id); 34862306a36Sopenharmony_ci // dev_id is changed, parameter is set 0 to get next file info 34962306a36Sopenharmony_ci if (fi_iter) 35062306a36Sopenharmony_ci ctx_merge.ctx.pos = 35162306a36Sopenharmony_ci hmdfs_set_pos(fi_iter->device_id, 0, 0); 35262306a36Sopenharmony_ci } 35362306a36Sopenharmony_ci while (fi_iter) { 35462306a36Sopenharmony_ci ctx_merge.dev_id = fi_iter->device_id; 35562306a36Sopenharmony_ci device_id = ctx_merge.dev_id; 35662306a36Sopenharmony_ci lower_file_iter = fi_iter->lower_file; 35762306a36Sopenharmony_ci lower_file_iter->f_pos = file->f_pos; 35862306a36Sopenharmony_ci err = iterate_dir(lower_file_iter, &ctx_merge.ctx); 35962306a36Sopenharmony_ci file->f_pos = lower_file_iter->f_pos; 36062306a36Sopenharmony_ci ctx->pos = file->f_pos; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci if (err) 36362306a36Sopenharmony_ci goto done; 36462306a36Sopenharmony_ci /* 36562306a36Sopenharmony_ci * ctx->actor return nonzero means buffer is exhausted or 36662306a36Sopenharmony_ci * something is wrong, thus we should not continue. 36762306a36Sopenharmony_ci */ 36862306a36Sopenharmony_ci if (ctx_merge.result) 36962306a36Sopenharmony_ci goto done; 37062306a36Sopenharmony_ci fi_iter = get_next_hmdfs_file_info(fi_head, device_id); 37162306a36Sopenharmony_ci if (fi_iter) { 37262306a36Sopenharmony_ci file->f_pos = hmdfs_set_pos(fi_iter->device_id, 0, 0); 37362306a36Sopenharmony_ci ctx->pos = file->f_pos; 37462306a36Sopenharmony_ci } 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_cidone: 37762306a36Sopenharmony_ci trace_hmdfs_iterate_merge(file->f_path.dentry, start_pos, ctx->pos, 37862306a36Sopenharmony_ci err); 37962306a36Sopenharmony_ci return err; 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ciint do_dir_open_merge(struct file *file, const struct cred *cred, 38362306a36Sopenharmony_ci struct hmdfs_file_info *fi_head) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci int ret = -EINVAL; 38662306a36Sopenharmony_ci struct hmdfs_dentry_info_merge *dim = hmdfs_dm(file->f_path.dentry); 38762306a36Sopenharmony_ci struct hmdfs_dentry_comrade *comrade = NULL; 38862306a36Sopenharmony_ci struct hmdfs_file_info *fi = NULL; 38962306a36Sopenharmony_ci struct path lo_p = { .mnt = file->f_path.mnt }; 39062306a36Sopenharmony_ci struct file *lower_file = NULL; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci if (IS_ERR_OR_NULL(cred)) 39362306a36Sopenharmony_ci return ret; 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci wait_event(dim->wait_queue, !has_merge_lookup_work(dim)); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci mutex_lock(&dim->comrade_list_lock); 39862306a36Sopenharmony_ci list_for_each_entry(comrade, &(dim->comrade_list), list) { 39962306a36Sopenharmony_ci fi = kzalloc(sizeof(*fi), GFP_KERNEL); 40062306a36Sopenharmony_ci if (!fi) { 40162306a36Sopenharmony_ci ret = ret ? -ENOMEM : 0; 40262306a36Sopenharmony_ci continue; // allow some dir to fail to open 40362306a36Sopenharmony_ci } 40462306a36Sopenharmony_ci lo_p.dentry = comrade->lo_d; 40562306a36Sopenharmony_ci // make sure that dentry will not be dentry_kill before open 40662306a36Sopenharmony_ci dget(lo_p.dentry); 40762306a36Sopenharmony_ci if (unlikely(d_is_negative(lo_p.dentry))) { 40862306a36Sopenharmony_ci hmdfs_info("dentry is negative, try again"); 40962306a36Sopenharmony_ci kfree(fi); 41062306a36Sopenharmony_ci dput(lo_p.dentry); 41162306a36Sopenharmony_ci continue; // skip this device 41262306a36Sopenharmony_ci } 41362306a36Sopenharmony_ci lower_file = dentry_open(&lo_p, file->f_flags, cred); 41462306a36Sopenharmony_ci dput(lo_p.dentry); 41562306a36Sopenharmony_ci if (IS_ERR(lower_file)) { 41662306a36Sopenharmony_ci kfree(fi); 41762306a36Sopenharmony_ci continue; 41862306a36Sopenharmony_ci } 41962306a36Sopenharmony_ci ret = 0; 42062306a36Sopenharmony_ci fi->device_id = comrade->dev_id; 42162306a36Sopenharmony_ci fi->lower_file = lower_file; 42262306a36Sopenharmony_ci mutex_lock(&fi_head->comrade_list_lock); 42362306a36Sopenharmony_ci list_add_tail(&fi->comrade_list, &fi_head->comrade_list); 42462306a36Sopenharmony_ci mutex_unlock(&fi_head->comrade_list_lock); 42562306a36Sopenharmony_ci } 42662306a36Sopenharmony_ci mutex_unlock(&dim->comrade_list_lock); 42762306a36Sopenharmony_ci return ret; 42862306a36Sopenharmony_ci} 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ciint hmdfs_dir_open_merge(struct inode *inode, struct file *file) 43162306a36Sopenharmony_ci{ 43262306a36Sopenharmony_ci int ret = 0; 43362306a36Sopenharmony_ci struct hmdfs_file_info *fi = NULL; 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci fi = kzalloc(sizeof(*fi), GFP_KERNEL); 43662306a36Sopenharmony_ci if (!fi) 43762306a36Sopenharmony_ci return -ENOMEM; 43862306a36Sopenharmony_ci 43962306a36Sopenharmony_ci file->private_data = fi; 44062306a36Sopenharmony_ci fi->root = RB_ROOT; 44162306a36Sopenharmony_ci mutex_init(&fi->comrade_list_lock); 44262306a36Sopenharmony_ci INIT_LIST_HEAD(&fi->comrade_list); 44362306a36Sopenharmony_ci 44462306a36Sopenharmony_ci ret = do_dir_open_merge(file, hmdfs_sb(inode->i_sb)->cred, fi); 44562306a36Sopenharmony_ci if (ret) 44662306a36Sopenharmony_ci kfree(fi); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci return ret; 44962306a36Sopenharmony_ci} 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ciint hmdfs_dir_release_merge(struct inode *inode, struct file *file) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci struct hmdfs_file_info *fi_head = hmdfs_f(file); 45462306a36Sopenharmony_ci struct hmdfs_file_info *fi_iter = NULL; 45562306a36Sopenharmony_ci struct hmdfs_file_info *fi_temp = NULL; 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci mutex_lock(&fi_head->comrade_list_lock); 45862306a36Sopenharmony_ci list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list), 45962306a36Sopenharmony_ci comrade_list) { 46062306a36Sopenharmony_ci list_del_init(&(fi_iter->comrade_list)); 46162306a36Sopenharmony_ci fput(fi_iter->lower_file); 46262306a36Sopenharmony_ci kfree(fi_iter); 46362306a36Sopenharmony_ci } 46462306a36Sopenharmony_ci mutex_unlock(&fi_head->comrade_list_lock); 46562306a36Sopenharmony_ci destroy_tree(&fi_head->root); 46662306a36Sopenharmony_ci file->private_data = NULL; 46762306a36Sopenharmony_ci kfree(fi_head); 46862306a36Sopenharmony_ci 46962306a36Sopenharmony_ci return 0; 47062306a36Sopenharmony_ci} 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_cistatic long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg); 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cilong hmdfs_dir_unlocked_ioctl_merge(struct file *file, unsigned int cmd, 47562306a36Sopenharmony_ci unsigned long arg) 47662306a36Sopenharmony_ci{ 47762306a36Sopenharmony_ci struct hmdfs_file_info *fi_head = hmdfs_f(file); 47862306a36Sopenharmony_ci struct hmdfs_file_info *fi_iter = NULL; 47962306a36Sopenharmony_ci struct hmdfs_file_info *fi_temp = NULL; 48062306a36Sopenharmony_ci struct file *lower_file = NULL; 48162306a36Sopenharmony_ci int error = -ENOTTY; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (cmd == HMDFS_IOC_GET_DST_PATH) 48462306a36Sopenharmony_ci return hmdfs_ioc_get_dst_path(file, arg); 48562306a36Sopenharmony_ci mutex_lock(&fi_head->comrade_list_lock); 48662306a36Sopenharmony_ci list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list), 48762306a36Sopenharmony_ci comrade_list) { 48862306a36Sopenharmony_ci if (fi_iter->device_id == 0) { 48962306a36Sopenharmony_ci lower_file = fi_iter->lower_file; 49062306a36Sopenharmony_ci if (lower_file->f_op->unlocked_ioctl) 49162306a36Sopenharmony_ci error = lower_file->f_op->unlocked_ioctl( 49262306a36Sopenharmony_ci lower_file, cmd, arg); 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci } 49562306a36Sopenharmony_ci } 49662306a36Sopenharmony_ci mutex_unlock(&fi_head->comrade_list_lock); 49762306a36Sopenharmony_ci return error; 49862306a36Sopenharmony_ci} 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_cilong hmdfs_dir_compat_ioctl_merge(struct file *file, unsigned int cmd, 50162306a36Sopenharmony_ci unsigned long arg) 50262306a36Sopenharmony_ci{ 50362306a36Sopenharmony_ci struct hmdfs_file_info *fi_head = hmdfs_f(file); 50462306a36Sopenharmony_ci struct hmdfs_file_info *fi_iter = NULL; 50562306a36Sopenharmony_ci struct hmdfs_file_info *fi_temp = NULL; 50662306a36Sopenharmony_ci struct file *lower_file = NULL; 50762306a36Sopenharmony_ci int error = -ENOTTY; 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci if (cmd == HMDFS_IOC_GET_DST_PATH) 51062306a36Sopenharmony_ci return hmdfs_ioc_get_dst_path(file, arg); 51162306a36Sopenharmony_ci mutex_lock(&fi_head->comrade_list_lock); 51262306a36Sopenharmony_ci list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list), 51362306a36Sopenharmony_ci comrade_list) { 51462306a36Sopenharmony_ci if (fi_iter->device_id == 0) { 51562306a36Sopenharmony_ci lower_file = fi_iter->lower_file; 51662306a36Sopenharmony_ci if (lower_file->f_op->compat_ioctl) 51762306a36Sopenharmony_ci error = lower_file->f_op->compat_ioctl( 51862306a36Sopenharmony_ci lower_file, cmd, arg); 51962306a36Sopenharmony_ci break; 52062306a36Sopenharmony_ci } 52162306a36Sopenharmony_ci } 52262306a36Sopenharmony_ci mutex_unlock(&fi_head->comrade_list_lock); 52362306a36Sopenharmony_ci return error; 52462306a36Sopenharmony_ci} 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ciconst struct file_operations hmdfs_dir_fops_merge = { 52762306a36Sopenharmony_ci .owner = THIS_MODULE, 52862306a36Sopenharmony_ci .iterate_shared = hmdfs_iterate_merge, 52962306a36Sopenharmony_ci .open = hmdfs_dir_open_merge, 53062306a36Sopenharmony_ci .release = hmdfs_dir_release_merge, 53162306a36Sopenharmony_ci .unlocked_ioctl = hmdfs_dir_unlocked_ioctl_merge, 53262306a36Sopenharmony_ci .compat_ioctl = hmdfs_dir_compat_ioctl_merge, 53362306a36Sopenharmony_ci}; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_cistatic ssize_t hmdfs_merge_read_iter(struct kiocb *iocb, struct iov_iter *iter) 53662306a36Sopenharmony_ci{ 53762306a36Sopenharmony_ci return hmdfs_do_read_iter(iocb->ki_filp, iter, &iocb->ki_pos); 53862306a36Sopenharmony_ci} 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_cissize_t hmdfs_merge_write_iter(struct kiocb *iocb, struct iov_iter *iter) 54162306a36Sopenharmony_ci{ 54262306a36Sopenharmony_ci return hmdfs_do_write_iter(iocb->ki_filp, iter, &iocb->ki_pos); 54362306a36Sopenharmony_ci} 54462306a36Sopenharmony_ci 54562306a36Sopenharmony_ciint hmdfs_file_open_merge(struct inode *inode, struct file *file) 54662306a36Sopenharmony_ci{ 54762306a36Sopenharmony_ci int err = 0; 54862306a36Sopenharmony_ci struct file *lower_file = NULL; 54962306a36Sopenharmony_ci struct path lo_p = { .mnt = file->f_path.mnt }; 55062306a36Sopenharmony_ci struct super_block *sb = inode->i_sb; 55162306a36Sopenharmony_ci const struct cred *cred = hmdfs_sb(sb)->cred; 55262306a36Sopenharmony_ci struct hmdfs_file_info *gfi = NULL; 55362306a36Sopenharmony_ci struct dentry *parent = NULL; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci lo_p.dentry = hmdfs_get_fst_lo_d(file->f_path.dentry); 55662306a36Sopenharmony_ci if (!lo_p.dentry) { 55762306a36Sopenharmony_ci err = -EINVAL; 55862306a36Sopenharmony_ci goto out_err; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci gfi = kzalloc(sizeof(*gfi), GFP_KERNEL); 56262306a36Sopenharmony_ci if (!gfi) { 56362306a36Sopenharmony_ci err = -ENOMEM; 56462306a36Sopenharmony_ci goto out_err; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci 56762306a36Sopenharmony_ci parent = dget_parent(file->f_path.dentry); 56862306a36Sopenharmony_ci lower_file = dentry_open(&lo_p, file->f_flags, cred); 56962306a36Sopenharmony_ci if (IS_ERR(lower_file)) { 57062306a36Sopenharmony_ci err = PTR_ERR(lower_file); 57162306a36Sopenharmony_ci kfree(gfi); 57262306a36Sopenharmony_ci } else { 57362306a36Sopenharmony_ci gfi->lower_file = lower_file; 57462306a36Sopenharmony_ci file->private_data = gfi; 57562306a36Sopenharmony_ci hmdfs_update_upper_file(file, lower_file); 57662306a36Sopenharmony_ci } 57762306a36Sopenharmony_ci dput(parent); 57862306a36Sopenharmony_ciout_err: 57962306a36Sopenharmony_ci dput(lo_p.dentry); 58062306a36Sopenharmony_ci return err; 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_ciint hmdfs_file_flush_merge(struct file *file, fl_owner_t id) 58462306a36Sopenharmony_ci{ 58562306a36Sopenharmony_ci struct hmdfs_file_info *gfi = hmdfs_f(file); 58662306a36Sopenharmony_ci struct file *lower_file = gfi->lower_file; 58762306a36Sopenharmony_ci 58862306a36Sopenharmony_ci if (lower_file->f_op->flush) 58962306a36Sopenharmony_ci return lower_file->f_op->flush(lower_file, id); 59062306a36Sopenharmony_ci 59162306a36Sopenharmony_ci return 0; 59262306a36Sopenharmony_ci} 59362306a36Sopenharmony_ci 59462306a36Sopenharmony_cistatic long hmdfs_ioc_get_writeopen_cnt(struct file *filp, unsigned long arg) 59562306a36Sopenharmony_ci{ 59662306a36Sopenharmony_ci struct hmdfs_file_info *gfi = hmdfs_f(filp); 59762306a36Sopenharmony_ci struct file *lower_file = gfi->lower_file; 59862306a36Sopenharmony_ci struct inode *lower_inode = file_inode(lower_file); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci u32 wo_cnt = atomic_read(&(hmdfs_i(lower_inode))->write_opened); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci return put_user(wo_cnt, (int __user *)arg); 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic int copy_string_from_user(unsigned long pos, unsigned long len, 60662306a36Sopenharmony_ci char **data) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci char *tmp_data; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (len >= PATH_MAX) 61162306a36Sopenharmony_ci return -EINVAL; 61262306a36Sopenharmony_ci if (!access_ok((char __user *)pos, len)) 61362306a36Sopenharmony_ci return -EFAULT; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci tmp_data = kzalloc(len + 1, GFP_KERNEL); 61662306a36Sopenharmony_ci if (!tmp_data) 61762306a36Sopenharmony_ci return -ENOMEM; 61862306a36Sopenharmony_ci *data = tmp_data; 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci if (copy_from_user(tmp_data, (char __user *)pos, len)) 62162306a36Sopenharmony_ci return -EFAULT; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci return 0; 62462306a36Sopenharmony_ci} 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_cistatic int hmdfs_get_info_from_user(unsigned long pos, 62762306a36Sopenharmony_ci struct hmdfs_dst_info *hdi, struct hmdfs_user_info *data) 62862306a36Sopenharmony_ci{ 62962306a36Sopenharmony_ci int ret = 0; 63062306a36Sopenharmony_ci 63162306a36Sopenharmony_ci if (!access_ok((struct hmdfs_dst_info __user *)pos, 63262306a36Sopenharmony_ci sizeof(struct hmdfs_dst_info))) 63362306a36Sopenharmony_ci return -ENOMEM; 63462306a36Sopenharmony_ci if (copy_from_user(hdi, (struct hmdfs_dst_info __user *)pos, 63562306a36Sopenharmony_ci sizeof(struct hmdfs_dst_info))) 63662306a36Sopenharmony_ci return -EFAULT; 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci ret = copy_string_from_user(hdi->local_path_pos, hdi->local_path_len, 63962306a36Sopenharmony_ci &data->local_path); 64062306a36Sopenharmony_ci if (ret != 0) 64162306a36Sopenharmony_ci return ret; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci ret = copy_string_from_user(hdi->distributed_path_pos, 64462306a36Sopenharmony_ci hdi->distributed_path_len, 64562306a36Sopenharmony_ci &data->distributed_path); 64662306a36Sopenharmony_ci if (ret != 0) 64762306a36Sopenharmony_ci return ret; 64862306a36Sopenharmony_ci 64962306a36Sopenharmony_ci ret = copy_string_from_user(hdi->bundle_name_pos, hdi->bundle_name_len, 65062306a36Sopenharmony_ci &data->bundle_name); 65162306a36Sopenharmony_ci if (ret != 0) 65262306a36Sopenharmony_ci return ret; 65362306a36Sopenharmony_ci 65462306a36Sopenharmony_ci return 0; 65562306a36Sopenharmony_ci} 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_cistatic const struct cred *change_cred(struct dentry *dentry, 65862306a36Sopenharmony_ci const char *bundle_name) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci int bid; 66162306a36Sopenharmony_ci struct cred *cred = NULL; 66262306a36Sopenharmony_ci const struct cred *old_cred = NULL; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci cred = prepare_creds(); 66562306a36Sopenharmony_ci if (!cred) { 66662306a36Sopenharmony_ci return NULL; 66762306a36Sopenharmony_ci } 66862306a36Sopenharmony_ci bid = get_bundle_uid(hmdfs_sb(dentry->d_sb), bundle_name); 66962306a36Sopenharmony_ci if (bid != 0) { 67062306a36Sopenharmony_ci cred->fsuid = KUIDT_INIT(bid); 67162306a36Sopenharmony_ci cred->fsgid = KGIDT_INIT(bid); 67262306a36Sopenharmony_ci old_cred = override_creds(cred); 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci return old_cred; 67662306a36Sopenharmony_ci} 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_cistatic int get_file_size(const char *path_value, uint64_t pos) 67962306a36Sopenharmony_ci{ 68062306a36Sopenharmony_ci int ret; 68162306a36Sopenharmony_ci uint64_t size; 68262306a36Sopenharmony_ci struct path path; 68362306a36Sopenharmony_ci struct kstat buf; 68462306a36Sopenharmony_ci 68562306a36Sopenharmony_ci ret = kern_path(path_value, 0, &path); 68662306a36Sopenharmony_ci if (ret) 68762306a36Sopenharmony_ci return ret; 68862306a36Sopenharmony_ci ret = vfs_getattr(&path, &buf, STATX_BASIC_STATS | STATX_BTIME, 0); 68962306a36Sopenharmony_ci path_put(&path); 69062306a36Sopenharmony_ci if (ret) { 69162306a36Sopenharmony_ci hmdfs_err("call vfs_getattr failed, err %d", ret); 69262306a36Sopenharmony_ci return ret; 69362306a36Sopenharmony_ci } 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci size = buf.size; 69662306a36Sopenharmony_ci ret = copy_to_user((uint64_t __user *)pos, &size, sizeof(uint64_t)); 69762306a36Sopenharmony_ci return ret; 69862306a36Sopenharmony_ci} 69962306a36Sopenharmony_ci 70062306a36Sopenharmony_cistatic int create_link_file(struct hmdfs_user_info *data) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci int ret; 70362306a36Sopenharmony_ci struct dentry *dentry; 70462306a36Sopenharmony_ci struct path path; 70562306a36Sopenharmony_ci 70662306a36Sopenharmony_ci ret = kern_path(data->distributed_path, 0, &path); 70762306a36Sopenharmony_ci if (ret == 0){ 70862306a36Sopenharmony_ci path_put(&path); 70962306a36Sopenharmony_ci return ret; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci dentry = kern_path_create(AT_FDCWD, data->distributed_path, &path, 0); 71362306a36Sopenharmony_ci if (IS_ERR(dentry)) 71462306a36Sopenharmony_ci return PTR_ERR(dentry); 71562306a36Sopenharmony_ci ret = vfs_symlink(&nop_mnt_idmap, path.dentry->d_inode, dentry, data->local_path); 71662306a36Sopenharmony_ci done_path_create(&path, dentry); 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci return ret; 71962306a36Sopenharmony_ci} 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_cistatic int create_dir(const char *path_value, mode_t mode) 72262306a36Sopenharmony_ci{ 72362306a36Sopenharmony_ci int err = 0; 72462306a36Sopenharmony_ci struct path path; 72562306a36Sopenharmony_ci struct dentry *dentry; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci dentry = kern_path_create(AT_FDCWD, path_value, &path, LOOKUP_DIRECTORY); 72862306a36Sopenharmony_ci if(PTR_ERR(dentry) == -EEXIST) 72962306a36Sopenharmony_ci return 0; 73062306a36Sopenharmony_ci if (IS_ERR(dentry)) 73162306a36Sopenharmony_ci return PTR_ERR(dentry); 73262306a36Sopenharmony_ci 73362306a36Sopenharmony_ci err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode); 73462306a36Sopenharmony_ci if (err && err != -EEXIST) 73562306a36Sopenharmony_ci hmdfs_err("vfs_mkdir failed, err = %d", err); 73662306a36Sopenharmony_ci done_path_create(&path, dentry); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci return err; 73962306a36Sopenharmony_ci} 74062306a36Sopenharmony_ci 74162306a36Sopenharmony_cistatic int create_dir_recursive(const char *path_value, mode_t mode) 74262306a36Sopenharmony_ci{ 74362306a36Sopenharmony_ci int err = 0; 74462306a36Sopenharmony_ci char *tmp_path = kstrdup(path_value, GFP_KERNEL); 74562306a36Sopenharmony_ci char *p = tmp_path; 74662306a36Sopenharmony_ci 74762306a36Sopenharmony_ci if (!tmp_path) 74862306a36Sopenharmony_ci return -ENOMEM; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (*p == '/') 75162306a36Sopenharmony_ci p++; 75262306a36Sopenharmony_ci 75362306a36Sopenharmony_ci while (*p) { 75462306a36Sopenharmony_ci if (*p == '/') { 75562306a36Sopenharmony_ci *p = '\0'; 75662306a36Sopenharmony_ci err = create_dir(tmp_path, mode); 75762306a36Sopenharmony_ci if (err != 0) 75862306a36Sopenharmony_ci break; 75962306a36Sopenharmony_ci *p = '/'; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci p++; 76262306a36Sopenharmony_ci } 76362306a36Sopenharmony_ci 76462306a36Sopenharmony_ci kfree(tmp_path); 76562306a36Sopenharmony_ci return err; 76662306a36Sopenharmony_ci} 76762306a36Sopenharmony_ci 76862306a36Sopenharmony_cistatic long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg) 76962306a36Sopenharmony_ci{ 77062306a36Sopenharmony_ci int ret = 0; 77162306a36Sopenharmony_ci const struct cred *old_cred; 77262306a36Sopenharmony_ci struct hmdfs_dst_info hdi; 77362306a36Sopenharmony_ci struct hmdfs_user_info *data; 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 77662306a36Sopenharmony_ci if (!data) { 77762306a36Sopenharmony_ci ret = -ENOMEM; 77862306a36Sopenharmony_ci goto err_free_data; 77962306a36Sopenharmony_ci } 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci ret = hmdfs_get_info_from_user(arg, &hdi, data); 78262306a36Sopenharmony_ci if (ret != 0) 78362306a36Sopenharmony_ci goto err_free_all; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci old_cred = change_cred(filp->f_path.dentry, data->bundle_name); 78662306a36Sopenharmony_ci if (!old_cred) { 78762306a36Sopenharmony_ci ret = -EACCES; 78862306a36Sopenharmony_ci goto err_free_all; 78962306a36Sopenharmony_ci } 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci ret = create_dir_recursive(data->distributed_path, DIR_MODE); 79262306a36Sopenharmony_ci if (ret != 0) 79362306a36Sopenharmony_ci goto err_revert; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci ret = create_link_file(data); 79662306a36Sopenharmony_ci if (ret != 0 && ret != -EEXIST) 79762306a36Sopenharmony_ci goto err_revert; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci ret = get_file_size(data->local_path, hdi.size); 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_cierr_revert: 80262306a36Sopenharmony_ci revert_creds(old_cred); 80362306a36Sopenharmony_cierr_free_all: 80462306a36Sopenharmony_ci kfree(data->local_path); 80562306a36Sopenharmony_ci kfree(data->distributed_path); 80662306a36Sopenharmony_ci kfree(data->bundle_name); 80762306a36Sopenharmony_cierr_free_data: 80862306a36Sopenharmony_ci kfree(data); 80962306a36Sopenharmony_ci return ret; 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_cistatic long hmdfs_file_ioctl_merge(struct file *filp, unsigned int cmd, unsigned long arg) 81362306a36Sopenharmony_ci{ 81462306a36Sopenharmony_ci switch (cmd) { 81562306a36Sopenharmony_ci case HMDFS_IOC_GET_WRITEOPEN_CNT: 81662306a36Sopenharmony_ci return hmdfs_ioc_get_writeopen_cnt(filp, arg); 81762306a36Sopenharmony_ci case HMDFS_IOC_GET_DST_PATH: 81862306a36Sopenharmony_ci return hmdfs_ioc_get_dst_path(filp, arg); 81962306a36Sopenharmony_ci default: 82062306a36Sopenharmony_ci return -ENOTTY; 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci} 82362306a36Sopenharmony_ci 82462306a36Sopenharmony_ci/* Transparent transmission of parameters to device_view level, 82562306a36Sopenharmony_ci * so file operations are same as device_view local operations. 82662306a36Sopenharmony_ci */ 82762306a36Sopenharmony_ciconst struct file_operations hmdfs_file_fops_merge = { 82862306a36Sopenharmony_ci .owner = THIS_MODULE, 82962306a36Sopenharmony_ci .llseek = hmdfs_file_llseek_local, 83062306a36Sopenharmony_ci .read_iter = hmdfs_merge_read_iter, 83162306a36Sopenharmony_ci .write_iter = hmdfs_merge_write_iter, 83262306a36Sopenharmony_ci .mmap = hmdfs_file_mmap_local, 83362306a36Sopenharmony_ci .open = hmdfs_file_open_merge, 83462306a36Sopenharmony_ci .flush = hmdfs_file_flush_merge, 83562306a36Sopenharmony_ci .release = hmdfs_file_release_local, 83662306a36Sopenharmony_ci .fsync = hmdfs_fsync_local, 83762306a36Sopenharmony_ci .unlocked_ioctl = hmdfs_file_ioctl_merge, 83862306a36Sopenharmony_ci .compat_ioctl = hmdfs_file_ioctl_merge, 83962306a36Sopenharmony_ci .splice_read = copy_splice_read, 84062306a36Sopenharmony_ci .splice_write = iter_file_splice_write, 84162306a36Sopenharmony_ci}; 842