18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * fs/hmdfs/inode_cloud_merge.c 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include "hmdfs_merge_view.h" 98c2ecf20Sopenharmony_ci#include <linux/atomic.h> 108c2ecf20Sopenharmony_ci#include <linux/fs.h> 118c2ecf20Sopenharmony_ci#include <linux/fs_stack.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/list.h> 148c2ecf20Sopenharmony_ci#include <linux/mount.h> 158c2ecf20Sopenharmony_ci#include <linux/namei.h> 168c2ecf20Sopenharmony_ci#include <linux/rwsem.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/types.h> 198c2ecf20Sopenharmony_ci#include "authority/authentication.h" 208c2ecf20Sopenharmony_ci#include "hmdfs_trace.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic struct inode *fill_inode_merge(struct super_block *sb, 238c2ecf20Sopenharmony_ci struct inode *parent_inode, 248c2ecf20Sopenharmony_ci struct dentry *child_dentry, 258c2ecf20Sopenharmony_ci struct dentry *lo_d_dentry) 268c2ecf20Sopenharmony_ci{ 278c2ecf20Sopenharmony_ci int ret = 0; 288c2ecf20Sopenharmony_ci struct dentry *fst_lo_d = NULL; 298c2ecf20Sopenharmony_ci struct hmdfs_inode_info *info = NULL; 308c2ecf20Sopenharmony_ci struct inode *inode = NULL; 318c2ecf20Sopenharmony_ci umode_t mode; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci if (lo_d_dentry) { 348c2ecf20Sopenharmony_ci fst_lo_d = lo_d_dentry; 358c2ecf20Sopenharmony_ci dget(fst_lo_d); 368c2ecf20Sopenharmony_ci } else { 378c2ecf20Sopenharmony_ci fst_lo_d = hmdfs_get_fst_lo_d(child_dentry); 388c2ecf20Sopenharmony_ci } 398c2ecf20Sopenharmony_ci if (!fst_lo_d) { 408c2ecf20Sopenharmony_ci inode = ERR_PTR(-EINVAL); 418c2ecf20Sopenharmony_ci goto out; 428c2ecf20Sopenharmony_ci } 438c2ecf20Sopenharmony_ci if (hmdfs_i(parent_inode)->inode_type == HMDFS_LAYER_ZERO) 448c2ecf20Sopenharmony_ci inode = hmdfs_iget_locked_root(sb, HMDFS_ROOT_MERGE_CLOUD, NULL, 458c2ecf20Sopenharmony_ci NULL); 468c2ecf20Sopenharmony_ci else 478c2ecf20Sopenharmony_ci inode = hmdfs_iget5_locked_cloud_merge(sb, fst_lo_d); 488c2ecf20Sopenharmony_ci if (!inode) { 498c2ecf20Sopenharmony_ci hmdfs_err("iget5_locked get inode NULL"); 508c2ecf20Sopenharmony_ci inode = ERR_PTR(-ENOMEM); 518c2ecf20Sopenharmony_ci goto out; 528c2ecf20Sopenharmony_ci } 538c2ecf20Sopenharmony_ci if (!(inode->i_state & I_NEW)) 548c2ecf20Sopenharmony_ci goto out; 558c2ecf20Sopenharmony_ci info = hmdfs_i(inode); 568c2ecf20Sopenharmony_ci if (hmdfs_i(parent_inode)->inode_type == HMDFS_LAYER_ZERO) 578c2ecf20Sopenharmony_ci info->inode_type = HMDFS_LAYER_FIRST_MERGE_CLOUD; 588c2ecf20Sopenharmony_ci else 598c2ecf20Sopenharmony_ci info->inode_type = HMDFS_LAYER_OTHER_MERGE_CLOUD; 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci inode->i_uid = USER_DATA_RW_UID; 628c2ecf20Sopenharmony_ci inode->i_gid = USER_DATA_RW_GID; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci update_inode_attr(inode, child_dentry); 658c2ecf20Sopenharmony_ci mode = d_inode(fst_lo_d)->i_mode; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (S_ISREG(mode)) { 688c2ecf20Sopenharmony_ci inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; 698c2ecf20Sopenharmony_ci inode->i_op = &hmdfs_file_iops_cloud_merge; 708c2ecf20Sopenharmony_ci inode->i_fop = &hmdfs_file_fops_merge; 718c2ecf20Sopenharmony_ci set_nlink(inode, 1); 728c2ecf20Sopenharmony_ci } else if (S_ISDIR(mode)) { 738c2ecf20Sopenharmony_ci inode->i_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IXOTH; 748c2ecf20Sopenharmony_ci inode->i_op = &hmdfs_dir_iops_cloud_merge; 758c2ecf20Sopenharmony_ci inode->i_fop = &hmdfs_dir_fops_merge; 768c2ecf20Sopenharmony_ci set_nlink(inode, get_num_comrades(child_dentry) + 2); 778c2ecf20Sopenharmony_ci } else { 788c2ecf20Sopenharmony_ci ret = -EIO; 798c2ecf20Sopenharmony_ci goto bad_inode; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci unlock_new_inode(inode); 838c2ecf20Sopenharmony_ciout: 848c2ecf20Sopenharmony_ci dput(fst_lo_d); 858c2ecf20Sopenharmony_ci return inode; 868c2ecf20Sopenharmony_cibad_inode: 878c2ecf20Sopenharmony_ci iget_failed(inode); 888c2ecf20Sopenharmony_ci return ERR_PTR(ret); 898c2ecf20Sopenharmony_ci} 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_cistatic struct hmdfs_dentry_comrade * 928c2ecf20Sopenharmony_cicloud_merge_lookup_comrade(struct hmdfs_sb_info *sbi, 938c2ecf20Sopenharmony_ci const char *name, 948c2ecf20Sopenharmony_ci int devid, 958c2ecf20Sopenharmony_ci unsigned int flags) 968c2ecf20Sopenharmony_ci{ 978c2ecf20Sopenharmony_ci int err; 988c2ecf20Sopenharmony_ci struct path root, path; 998c2ecf20Sopenharmony_ci struct hmdfs_dentry_comrade *comrade = NULL; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci err = kern_path(sbi->real_dst, LOOKUP_DIRECTORY, &root); 1028c2ecf20Sopenharmony_ci if (err) { 1038c2ecf20Sopenharmony_ci comrade = ERR_PTR(err); 1048c2ecf20Sopenharmony_ci goto out; 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci err = vfs_path_lookup(root.dentry, root.mnt, name, flags, &path); 1088c2ecf20Sopenharmony_ci if (err) { 1098c2ecf20Sopenharmony_ci comrade = ERR_PTR(err); 1108c2ecf20Sopenharmony_ci goto root_put; 1118c2ecf20Sopenharmony_ci } 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci comrade = alloc_comrade(path.dentry, devid); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci path_put(&path); 1168c2ecf20Sopenharmony_ciroot_put: 1178c2ecf20Sopenharmony_ci path_put(&root); 1188c2ecf20Sopenharmony_ciout: 1198c2ecf20Sopenharmony_ci return comrade; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic void merge_lookup_sync(struct hmdfs_dentry_info_merge *mdi, 1238c2ecf20Sopenharmony_ci struct hmdfs_sb_info *sbi, 1248c2ecf20Sopenharmony_ci int devid, 1258c2ecf20Sopenharmony_ci const char *name, 1268c2ecf20Sopenharmony_ci unsigned int flags) 1278c2ecf20Sopenharmony_ci{ 1288c2ecf20Sopenharmony_ci struct hmdfs_dentry_comrade *comrade; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci comrade = cloud_merge_lookup_comrade(sbi, name, devid, flags); 1318c2ecf20Sopenharmony_ci if (IS_ERR(comrade)) 1328c2ecf20Sopenharmony_ci return; 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci mutex_lock(&mdi->comrade_list_lock); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (!is_valid_comrade(mdi, hmdfs_cm(comrade))) 1378c2ecf20Sopenharmony_ci destroy_comrade(comrade); 1388c2ecf20Sopenharmony_ci else 1398c2ecf20Sopenharmony_ci link_comrade(&mdi->comrade_list, comrade); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci mutex_unlock(&mdi->comrade_list_lock); 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_cistatic int lookup_merge_normal(struct dentry *dentry, unsigned int flags) 1458c2ecf20Sopenharmony_ci{ 1468c2ecf20Sopenharmony_ci int ret = -ENOMEM; 1478c2ecf20Sopenharmony_ci int devid = -1; 1488c2ecf20Sopenharmony_ci struct dentry *pdentry = dget_parent(dentry); 1498c2ecf20Sopenharmony_ci struct hmdfs_dentry_info_merge *mdi = hmdfs_dm(dentry); 1508c2ecf20Sopenharmony_ci struct hmdfs_sb_info *sbi = hmdfs_sb(dentry->d_sb); 1518c2ecf20Sopenharmony_ci char *rname, *ppath, *cpath; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci rname = hmdfs_get_real_dname(dentry, &devid, &mdi->type); 1548c2ecf20Sopenharmony_ci if (unlikely(!rname)) { 1558c2ecf20Sopenharmony_ci goto out; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci ppath = hmdfs_merge_get_dentry_relative_path(pdentry); 1598c2ecf20Sopenharmony_ci if (unlikely(!ppath)) { 1608c2ecf20Sopenharmony_ci hmdfs_err("failed to get parent relative path"); 1618c2ecf20Sopenharmony_ci goto out_rname; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci cpath = kzalloc(PATH_MAX, GFP_KERNEL); 1658c2ecf20Sopenharmony_ci if (unlikely(!cpath)) { 1668c2ecf20Sopenharmony_ci hmdfs_err("failed to get child device_view path"); 1678c2ecf20Sopenharmony_ci goto out_ppath; 1688c2ecf20Sopenharmony_ci } 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (mdi->type != DT_REG || devid == 0) { 1718c2ecf20Sopenharmony_ci snprintf(cpath, PATH_MAX, "device_view/local%s/%s", ppath, 1728c2ecf20Sopenharmony_ci rname); 1738c2ecf20Sopenharmony_ci merge_lookup_sync(mdi, sbi, 0, cpath, flags); 1748c2ecf20Sopenharmony_ci } 1758c2ecf20Sopenharmony_ci if (mdi->type == DT_REG && !is_comrade_list_empty(mdi)) { 1768c2ecf20Sopenharmony_ci ret = 0; 1778c2ecf20Sopenharmony_ci goto found; 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci snprintf(cpath, PATH_MAX, "device_view/%s%s/%s", CLOUD_CID, 1818c2ecf20Sopenharmony_ci ppath, rname); 1828c2ecf20Sopenharmony_ci merge_lookup_sync(mdi, sbi, CLOUD_DEVICE, cpath, flags); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci ret = -ENOENT; 1858c2ecf20Sopenharmony_ci if (!is_comrade_list_empty(mdi)) 1868c2ecf20Sopenharmony_ci ret = 0; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cifound: 1898c2ecf20Sopenharmony_ci kfree(cpath); 1908c2ecf20Sopenharmony_ciout_ppath: 1918c2ecf20Sopenharmony_ci kfree(ppath); 1928c2ecf20Sopenharmony_ciout_rname: 1938c2ecf20Sopenharmony_ci kfree(rname); 1948c2ecf20Sopenharmony_ciout: 1958c2ecf20Sopenharmony_ci dput(pdentry); 1968c2ecf20Sopenharmony_ci return ret; 1978c2ecf20Sopenharmony_ci} 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci/** 2008c2ecf20Sopenharmony_ci * do_lookup_merge_root - lookup the root of the merge view(root/merge_view) 2018c2ecf20Sopenharmony_ci * 2028c2ecf20Sopenharmony_ci * It's common for a network filesystem to incur various of faults, so we 2038c2ecf20Sopenharmony_ci * intent to show mercy for faults here, except faults reported by the local. 2048c2ecf20Sopenharmony_ci */ 2058c2ecf20Sopenharmony_cistatic int do_lookup_cloud_merge_root(struct path path_dev, 2068c2ecf20Sopenharmony_ci struct dentry *child_dentry, unsigned int flags) 2078c2ecf20Sopenharmony_ci{ 2088c2ecf20Sopenharmony_ci struct hmdfs_dentry_comrade *comrade; 2098c2ecf20Sopenharmony_ci const int buf_len = 2108c2ecf20Sopenharmony_ci max((int)HMDFS_CID_SIZE + 1, (int)sizeof(DEVICE_VIEW_LOCAL)); 2118c2ecf20Sopenharmony_ci char *buf = kzalloc(buf_len, GFP_KERNEL); 2128c2ecf20Sopenharmony_ci LIST_HEAD(head); 2138c2ecf20Sopenharmony_ci int ret; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci if (!buf) 2168c2ecf20Sopenharmony_ci return -ENOMEM; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci // lookup real_dst/device_view/local 2198c2ecf20Sopenharmony_ci memcpy(buf, DEVICE_VIEW_LOCAL, sizeof(DEVICE_VIEW_LOCAL)); 2208c2ecf20Sopenharmony_ci comrade = lookup_comrade(path_dev, buf, HMDFS_DEVID_LOCAL, flags); 2218c2ecf20Sopenharmony_ci if (IS_ERR(comrade)) { 2228c2ecf20Sopenharmony_ci ret = PTR_ERR(comrade); 2238c2ecf20Sopenharmony_ci goto out; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci link_comrade(&head, comrade); 2268c2ecf20Sopenharmony_ci 2278c2ecf20Sopenharmony_ci memcpy(buf, CLOUD_CID, 6); 2288c2ecf20Sopenharmony_ci buf[5] = '\0'; 2298c2ecf20Sopenharmony_ci comrade = lookup_comrade(path_dev, buf, CLOUD_DEVICE, flags); 2308c2ecf20Sopenharmony_ci if (IS_ERR(comrade)) { 2318c2ecf20Sopenharmony_ci ret = 0; 2328c2ecf20Sopenharmony_ci goto out; 2338c2ecf20Sopenharmony_ci } 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci link_comrade(&head, comrade); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci assign_comrades_unlocked(child_dentry, &head); 2388c2ecf20Sopenharmony_ci ret = 0; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ciout: 2418c2ecf20Sopenharmony_ci kfree(buf); 2428c2ecf20Sopenharmony_ci return ret; 2438c2ecf20Sopenharmony_ci} 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_cistatic int lookup_cloud_merge_root(struct inode *root_inode, 2468c2ecf20Sopenharmony_ci struct dentry *child_dentry, unsigned int flags) 2478c2ecf20Sopenharmony_ci{ 2488c2ecf20Sopenharmony_ci struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb); 2498c2ecf20Sopenharmony_ci struct path path_dev; 2508c2ecf20Sopenharmony_ci int ret = -ENOENT; 2518c2ecf20Sopenharmony_ci int buf_len; 2528c2ecf20Sopenharmony_ci char *buf = NULL; 2538c2ecf20Sopenharmony_ci bool locked, down; 2548c2ecf20Sopenharmony_ci 2558c2ecf20Sopenharmony_ci // consider additional one slash and one '\0' 2568c2ecf20Sopenharmony_ci buf_len = strlen(sbi->real_dst) + 1 + sizeof(DEVICE_VIEW_ROOT); 2578c2ecf20Sopenharmony_ci if (buf_len > PATH_MAX) 2588c2ecf20Sopenharmony_ci return -ENAMETOOLONG; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci buf = kmalloc(buf_len, GFP_KERNEL); 2618c2ecf20Sopenharmony_ci if (unlikely(!buf)) 2628c2ecf20Sopenharmony_ci return -ENOMEM; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci sprintf(buf, "%s/%s", sbi->real_dst, DEVICE_VIEW_ROOT); 2658c2ecf20Sopenharmony_ci lock_root_inode_shared(root_inode, &locked, &down); 2668c2ecf20Sopenharmony_ci ret = hmdfs_get_path_in_sb(child_dentry->d_sb, buf, LOOKUP_DIRECTORY, 2678c2ecf20Sopenharmony_ci &path_dev); 2688c2ecf20Sopenharmony_ci if (ret) 2698c2ecf20Sopenharmony_ci goto free_buf; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci ret = do_lookup_cloud_merge_root(path_dev, child_dentry, flags); 2728c2ecf20Sopenharmony_ci path_put(&path_dev); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_cifree_buf: 2758c2ecf20Sopenharmony_ci kfree(buf); 2768c2ecf20Sopenharmony_ci restore_root_inode_sem(root_inode, locked, down); 2778c2ecf20Sopenharmony_ci return ret; 2788c2ecf20Sopenharmony_ci} 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci// do this in a map-reduce manner 2818c2ecf20Sopenharmony_cistruct dentry *hmdfs_lookup_cloud_merge(struct inode *parent_inode, 2828c2ecf20Sopenharmony_ci struct dentry *child_dentry, 2838c2ecf20Sopenharmony_ci unsigned int flags) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci bool create = flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET); 2868c2ecf20Sopenharmony_ci struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb); 2878c2ecf20Sopenharmony_ci struct hmdfs_inode_info *pii = hmdfs_i(parent_inode); 2888c2ecf20Sopenharmony_ci struct inode *child_inode = NULL; 2898c2ecf20Sopenharmony_ci struct dentry *ret_dentry = NULL; 2908c2ecf20Sopenharmony_ci int err = 0; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci /* 2938c2ecf20Sopenharmony_ci * Internal flags like LOOKUP_CREATE should not pass to device view. 2948c2ecf20Sopenharmony_ci * LOOKUP_REVAL is needed because dentry cache in hmdfs might be stale 2958c2ecf20Sopenharmony_ci * after rename in lower fs. LOOKUP_DIRECTORY is not needed because 2968c2ecf20Sopenharmony_ci * merge_view can do the judgement that whether result is directory or 2978c2ecf20Sopenharmony_ci * not. 2988c2ecf20Sopenharmony_ci */ 2998c2ecf20Sopenharmony_ci flags = flags & LOOKUP_REVAL; 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci child_dentry->d_fsdata = NULL; 3028c2ecf20Sopenharmony_ci 3038c2ecf20Sopenharmony_ci if (child_dentry->d_name.len > NAME_MAX) { 3048c2ecf20Sopenharmony_ci err = -ENAMETOOLONG; 3058c2ecf20Sopenharmony_ci goto out; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci err = init_hmdfs_dentry_info_merge(sbi, child_dentry); 3098c2ecf20Sopenharmony_ci if (unlikely(err)) 3108c2ecf20Sopenharmony_ci goto out; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci if (pii->inode_type == HMDFS_LAYER_ZERO) { 3138c2ecf20Sopenharmony_ci hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_FIRST_MERGE_CLOUD; 3148c2ecf20Sopenharmony_ci err = lookup_cloud_merge_root(parent_inode, child_dentry, flags); 3158c2ecf20Sopenharmony_ci } else { 3168c2ecf20Sopenharmony_ci hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_OTHER_MERGE_CLOUD; 3178c2ecf20Sopenharmony_ci err = lookup_merge_normal(child_dentry, flags); 3188c2ecf20Sopenharmony_ci } 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci if (!err) { 3218c2ecf20Sopenharmony_ci struct hmdfs_inode_info *info = NULL; 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci child_inode = fill_inode_merge(parent_inode->i_sb, parent_inode, 3248c2ecf20Sopenharmony_ci child_dentry, NULL); 3258c2ecf20Sopenharmony_ci if (IS_ERR(child_inode)) { 3268c2ecf20Sopenharmony_ci err = PTR_ERR(child_inode); 3278c2ecf20Sopenharmony_ci goto out; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci info = hmdfs_i(child_inode); 3308c2ecf20Sopenharmony_ci if (info->inode_type == HMDFS_LAYER_FIRST_MERGE) 3318c2ecf20Sopenharmony_ci hmdfs_root_inode_perm_init(child_inode); 3328c2ecf20Sopenharmony_ci else 3338c2ecf20Sopenharmony_ci check_and_fixup_ownership_remote(parent_inode, 3348c2ecf20Sopenharmony_ci child_inode, 3358c2ecf20Sopenharmony_ci child_dentry); 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci ret_dentry = d_splice_alias(child_inode, child_dentry); 3388c2ecf20Sopenharmony_ci if (IS_ERR(ret_dentry)) { 3398c2ecf20Sopenharmony_ci clear_comrades(child_dentry); 3408c2ecf20Sopenharmony_ci err = PTR_ERR(ret_dentry); 3418c2ecf20Sopenharmony_ci goto out; 3428c2ecf20Sopenharmony_ci } 3438c2ecf20Sopenharmony_ci if (ret_dentry) 3448c2ecf20Sopenharmony_ci child_dentry = ret_dentry; 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci goto out; 3478c2ecf20Sopenharmony_ci } 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci if ((err == -ENOENT) && create) 3508c2ecf20Sopenharmony_ci err = 0; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ciout: 3538c2ecf20Sopenharmony_ci return err ? ERR_PTR(err) : ret_dentry; 3548c2ecf20Sopenharmony_ci} 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ciconst struct inode_operations hmdfs_file_iops_cloud_merge = { 3578c2ecf20Sopenharmony_ci .getattr = hmdfs_getattr_merge, 3588c2ecf20Sopenharmony_ci .setattr = hmdfs_setattr_merge, 3598c2ecf20Sopenharmony_ci .permission = hmdfs_permission, 3608c2ecf20Sopenharmony_ci}; 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ciint do_mkdir_cloud_merge(struct inode *parent_inode, struct dentry *child_dentry, 3638c2ecf20Sopenharmony_ci umode_t mode, struct inode *lo_i_parent, 3648c2ecf20Sopenharmony_ci struct dentry *lo_d_child) 3658c2ecf20Sopenharmony_ci{ 3668c2ecf20Sopenharmony_ci int ret = 0; 3678c2ecf20Sopenharmony_ci struct super_block *sb = parent_inode->i_sb; 3688c2ecf20Sopenharmony_ci struct inode *child_inode = NULL; 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_ci ret = vfs_mkdir(lo_i_parent, lo_d_child, mode); 3718c2ecf20Sopenharmony_ci if (ret) 3728c2ecf20Sopenharmony_ci goto out; 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci child_inode = 3758c2ecf20Sopenharmony_ci fill_inode_merge(sb, parent_inode, child_dentry, lo_d_child); 3768c2ecf20Sopenharmony_ci if (IS_ERR(child_inode)) { 3778c2ecf20Sopenharmony_ci ret = PTR_ERR(child_inode); 3788c2ecf20Sopenharmony_ci goto out; 3798c2ecf20Sopenharmony_ci } 3808c2ecf20Sopenharmony_ci 3818c2ecf20Sopenharmony_ci d_add(child_dentry, child_inode); 3828c2ecf20Sopenharmony_ci /* nlink should be increased with the joining of children */ 3838c2ecf20Sopenharmony_ci set_nlink(parent_inode, 2); 3848c2ecf20Sopenharmony_ci hmdfs_update_meta(parent_inode); 3858c2ecf20Sopenharmony_ciout: 3868c2ecf20Sopenharmony_ci return ret; 3878c2ecf20Sopenharmony_ci} 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ciint do_create_cloud_merge(struct inode *parent_inode, struct dentry *child_dentry, 3908c2ecf20Sopenharmony_ci umode_t mode, bool want_excl, struct inode *lo_i_parent, 3918c2ecf20Sopenharmony_ci struct dentry *lo_d_child) 3928c2ecf20Sopenharmony_ci{ 3938c2ecf20Sopenharmony_ci int ret = 0; 3948c2ecf20Sopenharmony_ci struct super_block *sb = parent_inode->i_sb; 3958c2ecf20Sopenharmony_ci struct inode *child_inode = NULL; 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci ret = vfs_create(lo_i_parent, lo_d_child, mode, want_excl); 3988c2ecf20Sopenharmony_ci if (ret) 3998c2ecf20Sopenharmony_ci goto out; 4008c2ecf20Sopenharmony_ci 4018c2ecf20Sopenharmony_ci child_inode = 4028c2ecf20Sopenharmony_ci fill_inode_merge(sb, parent_inode, child_dentry, lo_d_child); 4038c2ecf20Sopenharmony_ci if (IS_ERR(child_inode)) { 4048c2ecf20Sopenharmony_ci ret = PTR_ERR(child_inode); 4058c2ecf20Sopenharmony_ci goto out; 4068c2ecf20Sopenharmony_ci } 4078c2ecf20Sopenharmony_ci 4088c2ecf20Sopenharmony_ci d_add(child_dentry, child_inode); 4098c2ecf20Sopenharmony_ci /* nlink should be increased with the joining of children */ 4108c2ecf20Sopenharmony_ci set_nlink(parent_inode, 2); 4118c2ecf20Sopenharmony_ci hmdfs_update_meta(parent_inode); 4128c2ecf20Sopenharmony_ciout: 4138c2ecf20Sopenharmony_ci return ret; 4148c2ecf20Sopenharmony_ci} 4158c2ecf20Sopenharmony_ci 4168c2ecf20Sopenharmony_ciint hmdfs_do_ops_cloud_merge(struct inode *i_parent, struct dentry *d_child, 4178c2ecf20Sopenharmony_ci struct dentry *lo_d_child, struct path path, 4188c2ecf20Sopenharmony_ci struct hmdfs_recursive_para *rec_op_para) 4198c2ecf20Sopenharmony_ci{ 4208c2ecf20Sopenharmony_ci int ret = 0; 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci if (rec_op_para->is_last) { 4238c2ecf20Sopenharmony_ci switch (rec_op_para->opcode) { 4248c2ecf20Sopenharmony_ci case F_MKDIR_MERGE: 4258c2ecf20Sopenharmony_ci ret = do_mkdir_cloud_merge(i_parent, d_child, 4268c2ecf20Sopenharmony_ci rec_op_para->mode, 4278c2ecf20Sopenharmony_ci d_inode(path.dentry), lo_d_child); 4288c2ecf20Sopenharmony_ci break; 4298c2ecf20Sopenharmony_ci case F_CREATE_MERGE: 4308c2ecf20Sopenharmony_ci ret = do_create_cloud_merge(i_parent, d_child, 4318c2ecf20Sopenharmony_ci rec_op_para->mode, 4328c2ecf20Sopenharmony_ci rec_op_para->want_excl, 4338c2ecf20Sopenharmony_ci d_inode(path.dentry), lo_d_child); 4348c2ecf20Sopenharmony_ci break; 4358c2ecf20Sopenharmony_ci default: 4368c2ecf20Sopenharmony_ci ret = -EINVAL; 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci } 4398c2ecf20Sopenharmony_ci } else { 4408c2ecf20Sopenharmony_ci ret = vfs_mkdir(d_inode(path.dentry), lo_d_child, 4418c2ecf20Sopenharmony_ci rec_op_para->mode); 4428c2ecf20Sopenharmony_ci } 4438c2ecf20Sopenharmony_ci if (ret) 4448c2ecf20Sopenharmony_ci hmdfs_err("vfs_ops failed, ops %d, err = %d", 4458c2ecf20Sopenharmony_ci rec_op_para->opcode, ret); 4468c2ecf20Sopenharmony_ci return ret; 4478c2ecf20Sopenharmony_ci} 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ciint hmdfs_create_lower_cloud_dentry(struct inode *i_parent, struct dentry *d_child, 4508c2ecf20Sopenharmony_ci struct dentry *lo_d_parent, bool is_dir, 4518c2ecf20Sopenharmony_ci struct hmdfs_recursive_para *rec_op_para) 4528c2ecf20Sopenharmony_ci{ 4538c2ecf20Sopenharmony_ci struct hmdfs_sb_info *sbi = i_parent->i_sb->s_fs_info; 4548c2ecf20Sopenharmony_ci struct hmdfs_dentry_comrade *new_comrade = NULL; 4558c2ecf20Sopenharmony_ci struct dentry *lo_d_child = NULL; 4568c2ecf20Sopenharmony_ci char *path_buf = kmalloc(PATH_MAX, GFP_KERNEL); 4578c2ecf20Sopenharmony_ci char *absolute_path_buf = kmalloc(PATH_MAX, GFP_KERNEL); 4588c2ecf20Sopenharmony_ci char *path_name = NULL; 4598c2ecf20Sopenharmony_ci struct path path = { .mnt = NULL, .dentry = NULL }; 4608c2ecf20Sopenharmony_ci int ret = 0; 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci if (unlikely(!path_buf || !absolute_path_buf)) { 4638c2ecf20Sopenharmony_ci ret = -ENOMEM; 4648c2ecf20Sopenharmony_ci goto out; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci path_name = dentry_path_raw(lo_d_parent, path_buf, PATH_MAX); 4688c2ecf20Sopenharmony_ci if (IS_ERR(path_name)) { 4698c2ecf20Sopenharmony_ci ret = PTR_ERR(path_name); 4708c2ecf20Sopenharmony_ci goto out; 4718c2ecf20Sopenharmony_ci } 4728c2ecf20Sopenharmony_ci if ((strlen(sbi->real_dst) + strlen(path_name) + 4738c2ecf20Sopenharmony_ci strlen(d_child->d_name.name) + 2) > PATH_MAX) { 4748c2ecf20Sopenharmony_ci ret = -ENAMETOOLONG; 4758c2ecf20Sopenharmony_ci goto out; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci 4788c2ecf20Sopenharmony_ci sprintf(absolute_path_buf, "%s%s/%s", sbi->real_dst, path_name, 4798c2ecf20Sopenharmony_ci d_child->d_name.name); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci if (is_dir) 4828c2ecf20Sopenharmony_ci lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf, 4838c2ecf20Sopenharmony_ci &path, LOOKUP_DIRECTORY); 4848c2ecf20Sopenharmony_ci else 4858c2ecf20Sopenharmony_ci lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf, 4868c2ecf20Sopenharmony_ci &path, 0); 4878c2ecf20Sopenharmony_ci if (IS_ERR(lo_d_child)) { 4888c2ecf20Sopenharmony_ci ret = PTR_ERR(lo_d_child); 4898c2ecf20Sopenharmony_ci goto out; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci // to ensure link_comrade after vfs_mkdir succeed 4928c2ecf20Sopenharmony_ci ret = hmdfs_do_ops_cloud_merge(i_parent, d_child, lo_d_child, path, 4938c2ecf20Sopenharmony_ci rec_op_para); 4948c2ecf20Sopenharmony_ci if (ret) 4958c2ecf20Sopenharmony_ci goto out_put; 4968c2ecf20Sopenharmony_ci new_comrade = alloc_comrade(lo_d_child, HMDFS_DEVID_LOCAL); 4978c2ecf20Sopenharmony_ci if (IS_ERR(new_comrade)) { 4988c2ecf20Sopenharmony_ci ret = PTR_ERR(new_comrade); 4998c2ecf20Sopenharmony_ci goto out_put; 5008c2ecf20Sopenharmony_ci } else { 5018c2ecf20Sopenharmony_ci link_comrade_unlocked(d_child, new_comrade); 5028c2ecf20Sopenharmony_ci } 5038c2ecf20Sopenharmony_ci 5048c2ecf20Sopenharmony_ci update_inode_attr(d_inode(d_child), d_child); 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ciout_put: 5078c2ecf20Sopenharmony_ci done_path_create(&path, lo_d_child); 5088c2ecf20Sopenharmony_ciout: 5098c2ecf20Sopenharmony_ci kfree(absolute_path_buf); 5108c2ecf20Sopenharmony_ci kfree(path_buf); 5118c2ecf20Sopenharmony_ci return ret; 5128c2ecf20Sopenharmony_ci} 5138c2ecf20Sopenharmony_ci 5148c2ecf20Sopenharmony_cistatic int create_lo_d_parent_recur(struct dentry *d_parent, 5158c2ecf20Sopenharmony_ci struct dentry *d_child, umode_t mode, 5168c2ecf20Sopenharmony_ci struct hmdfs_recursive_para *rec_op_para) 5178c2ecf20Sopenharmony_ci{ 5188c2ecf20Sopenharmony_ci struct dentry *lo_d_parent, *d_pparent; 5198c2ecf20Sopenharmony_ci int ret = 0; 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL); 5228c2ecf20Sopenharmony_ci if (!lo_d_parent) { 5238c2ecf20Sopenharmony_ci d_pparent = dget_parent(d_parent); 5248c2ecf20Sopenharmony_ci ret = create_lo_d_parent_recur(d_pparent, d_parent, 5258c2ecf20Sopenharmony_ci d_inode(d_parent)->i_mode, 5268c2ecf20Sopenharmony_ci rec_op_para); 5278c2ecf20Sopenharmony_ci dput(d_pparent); 5288c2ecf20Sopenharmony_ci if (ret) 5298c2ecf20Sopenharmony_ci goto out; 5308c2ecf20Sopenharmony_ci lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL); 5318c2ecf20Sopenharmony_ci if (!lo_d_parent) { 5328c2ecf20Sopenharmony_ci ret = -ENOENT; 5338c2ecf20Sopenharmony_ci goto out; 5348c2ecf20Sopenharmony_ci } 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci rec_op_para->is_last = false; 5378c2ecf20Sopenharmony_ci rec_op_para->mode = mode; 5388c2ecf20Sopenharmony_ci ret = hmdfs_create_lower_cloud_dentry(d_inode(d_parent), d_child, lo_d_parent, 5398c2ecf20Sopenharmony_ci true, rec_op_para); 5408c2ecf20Sopenharmony_ciout: 5418c2ecf20Sopenharmony_ci dput(lo_d_parent); 5428c2ecf20Sopenharmony_ci return ret; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ciint create_lo_d_cloud_child(struct inode *i_parent, struct dentry *d_child, 5468c2ecf20Sopenharmony_ci bool is_dir, struct hmdfs_recursive_para *rec_op_para) 5478c2ecf20Sopenharmony_ci{ 5488c2ecf20Sopenharmony_ci struct dentry *d_pparent, *lo_d_parent, *lo_d_child; 5498c2ecf20Sopenharmony_ci struct dentry *d_parent = dget_parent(d_child); 5508c2ecf20Sopenharmony_ci int ret = 0; 5518c2ecf20Sopenharmony_ci mode_t d_child_mode = rec_op_para->mode; 5528c2ecf20Sopenharmony_ci 5538c2ecf20Sopenharmony_ci lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL); 5548c2ecf20Sopenharmony_ci if (!lo_d_parent) { 5558c2ecf20Sopenharmony_ci d_pparent = dget_parent(d_parent); 5568c2ecf20Sopenharmony_ci ret = create_lo_d_parent_recur(d_pparent, d_parent, 5578c2ecf20Sopenharmony_ci d_inode(d_parent)->i_mode, 5588c2ecf20Sopenharmony_ci rec_op_para); 5598c2ecf20Sopenharmony_ci dput(d_pparent); 5608c2ecf20Sopenharmony_ci if (unlikely(ret)) { 5618c2ecf20Sopenharmony_ci lo_d_child = ERR_PTR(ret); 5628c2ecf20Sopenharmony_ci goto out; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL); 5658c2ecf20Sopenharmony_ci if (!lo_d_parent) { 5668c2ecf20Sopenharmony_ci lo_d_child = ERR_PTR(-ENOENT); 5678c2ecf20Sopenharmony_ci goto out; 5688c2ecf20Sopenharmony_ci } 5698c2ecf20Sopenharmony_ci } 5708c2ecf20Sopenharmony_ci rec_op_para->is_last = true; 5718c2ecf20Sopenharmony_ci rec_op_para->mode = d_child_mode; 5728c2ecf20Sopenharmony_ci ret = hmdfs_create_lower_cloud_dentry(i_parent, d_child, lo_d_parent, is_dir, 5738c2ecf20Sopenharmony_ci rec_op_para); 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ciout: 5768c2ecf20Sopenharmony_ci dput(d_parent); 5778c2ecf20Sopenharmony_ci dput(lo_d_parent); 5788c2ecf20Sopenharmony_ci return ret; 5798c2ecf20Sopenharmony_ci} 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ciint hmdfs_mkdir_cloud_merge(struct inode *dir, struct dentry *dentry, umode_t mode) 5828c2ecf20Sopenharmony_ci{ 5838c2ecf20Sopenharmony_ci int ret = 0; 5848c2ecf20Sopenharmony_ci struct hmdfs_recursive_para *rec_op_para = NULL; 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_ci // confict_name & file_type is checked by hmdfs_mkdir_local 5878c2ecf20Sopenharmony_ci if (hmdfs_file_type(dentry->d_name.name) != HMDFS_TYPE_COMMON) { 5888c2ecf20Sopenharmony_ci ret = -EACCES; 5898c2ecf20Sopenharmony_ci goto out; 5908c2ecf20Sopenharmony_ci } 5918c2ecf20Sopenharmony_ci rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL); 5928c2ecf20Sopenharmony_ci if (!rec_op_para) { 5938c2ecf20Sopenharmony_ci ret = -ENOMEM; 5948c2ecf20Sopenharmony_ci goto out; 5958c2ecf20Sopenharmony_ci } 5968c2ecf20Sopenharmony_ci 5978c2ecf20Sopenharmony_ci hmdfs_init_recursive_para(rec_op_para, F_MKDIR_MERGE, mode, false, 5988c2ecf20Sopenharmony_ci NULL); 5998c2ecf20Sopenharmony_ci ret = create_lo_d_cloud_child(dir, dentry, true, rec_op_para); 6008c2ecf20Sopenharmony_ciout: 6018c2ecf20Sopenharmony_ci hmdfs_trace_merge(trace_hmdfs_mkdir_merge, dir, dentry, ret); 6028c2ecf20Sopenharmony_ci if (ret) 6038c2ecf20Sopenharmony_ci d_drop(dentry); 6048c2ecf20Sopenharmony_ci kfree(rec_op_para); 6058c2ecf20Sopenharmony_ci return ret; 6068c2ecf20Sopenharmony_ci} 6078c2ecf20Sopenharmony_ci 6088c2ecf20Sopenharmony_ciint hmdfs_create_cloud_merge(struct inode *dir, struct dentry *dentry, umode_t mode, 6098c2ecf20Sopenharmony_ci bool want_excl) 6108c2ecf20Sopenharmony_ci{ 6118c2ecf20Sopenharmony_ci struct hmdfs_recursive_para *rec_op_para = NULL; 6128c2ecf20Sopenharmony_ci int ret = 0; 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL); 6158c2ecf20Sopenharmony_ci if (!rec_op_para) { 6168c2ecf20Sopenharmony_ci ret = -ENOMEM; 6178c2ecf20Sopenharmony_ci goto out; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci hmdfs_init_recursive_para(rec_op_para, F_CREATE_MERGE, mode, want_excl, 6208c2ecf20Sopenharmony_ci NULL); 6218c2ecf20Sopenharmony_ci // confict_name & file_type is checked by hmdfs_create_local 6228c2ecf20Sopenharmony_ci ret = create_lo_d_cloud_child(dir, dentry, false, rec_op_para); 6238c2ecf20Sopenharmony_ciout: 6248c2ecf20Sopenharmony_ci hmdfs_trace_merge(trace_hmdfs_create_merge, dir, dentry, ret); 6258c2ecf20Sopenharmony_ci if (ret) 6268c2ecf20Sopenharmony_ci d_drop(dentry); 6278c2ecf20Sopenharmony_ci kfree(rec_op_para); 6288c2ecf20Sopenharmony_ci return ret; 6298c2ecf20Sopenharmony_ci} 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_cistatic int rename_lo_d_cloud_child(struct hmdfs_rename_para *rename_para, 6328c2ecf20Sopenharmony_ci struct hmdfs_recursive_para *rec_op_para) 6338c2ecf20Sopenharmony_ci{ 6348c2ecf20Sopenharmony_ci struct dentry *d_pparent, *lo_d_parent; 6358c2ecf20Sopenharmony_ci struct dentry *d_parent = dget_parent(rename_para->new_dentry); 6368c2ecf20Sopenharmony_ci int ret = 0; 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL); 6398c2ecf20Sopenharmony_ci if (!lo_d_parent) { 6408c2ecf20Sopenharmony_ci d_pparent = dget_parent(d_parent); 6418c2ecf20Sopenharmony_ci ret = create_lo_d_parent_recur(d_pparent, d_parent, 6428c2ecf20Sopenharmony_ci d_inode(d_parent)->i_mode, 6438c2ecf20Sopenharmony_ci rec_op_para); 6448c2ecf20Sopenharmony_ci dput(d_pparent); 6458c2ecf20Sopenharmony_ci if (unlikely(ret)) 6468c2ecf20Sopenharmony_ci goto out; 6478c2ecf20Sopenharmony_ci lo_d_parent = hmdfs_get_lo_d(d_parent, HMDFS_DEVID_LOCAL); 6488c2ecf20Sopenharmony_ci if (!lo_d_parent) { 6498c2ecf20Sopenharmony_ci ret = -ENOENT; 6508c2ecf20Sopenharmony_ci goto out; 6518c2ecf20Sopenharmony_ci } 6528c2ecf20Sopenharmony_ci } 6538c2ecf20Sopenharmony_ci ret = do_rename_merge(rename_para->old_dir, rename_para->old_dentry, 6548c2ecf20Sopenharmony_ci rename_para->new_dir, rename_para->new_dentry, 6558c2ecf20Sopenharmony_ci rename_para->flags); 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ciout: 6588c2ecf20Sopenharmony_ci dput(d_parent); 6598c2ecf20Sopenharmony_ci dput(lo_d_parent); 6608c2ecf20Sopenharmony_ci return ret; 6618c2ecf20Sopenharmony_ci} 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_cistatic int hmdfs_rename_cloud_merge(struct inode *old_dir, 6648c2ecf20Sopenharmony_ci struct dentry *old_dentry, 6658c2ecf20Sopenharmony_ci struct inode *new_dir, 6668c2ecf20Sopenharmony_ci struct dentry *new_dentry, 6678c2ecf20Sopenharmony_ci unsigned int flags) 6688c2ecf20Sopenharmony_ci{ 6698c2ecf20Sopenharmony_ci struct hmdfs_recursive_para *rec_op_para = NULL; 6708c2ecf20Sopenharmony_ci struct hmdfs_rename_para rename_para = { old_dir, old_dentry, new_dir, 6718c2ecf20Sopenharmony_ci new_dentry, flags }; 6728c2ecf20Sopenharmony_ci int ret = 0; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci if (hmdfs_file_type(old_dentry->d_name.name) != HMDFS_TYPE_COMMON || 6758c2ecf20Sopenharmony_ci hmdfs_file_type(new_dentry->d_name.name) != HMDFS_TYPE_COMMON) { 6768c2ecf20Sopenharmony_ci ret = -EACCES; 6778c2ecf20Sopenharmony_ci goto rename_out; 6788c2ecf20Sopenharmony_ci } 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci if (hmdfs_i(old_dir)->inode_type != hmdfs_i(new_dir)->inode_type) { 6818c2ecf20Sopenharmony_ci hmdfs_err("in different view"); 6828c2ecf20Sopenharmony_ci ret = -EPERM; 6838c2ecf20Sopenharmony_ci goto rename_out; 6848c2ecf20Sopenharmony_ci } 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci rec_op_para = kmalloc(sizeof(*rec_op_para), GFP_KERNEL); 6878c2ecf20Sopenharmony_ci if (!rec_op_para) { 6888c2ecf20Sopenharmony_ci ret = -ENOMEM; 6898c2ecf20Sopenharmony_ci goto rename_out; 6908c2ecf20Sopenharmony_ci } 6918c2ecf20Sopenharmony_ci trace_hmdfs_rename_merge(old_dir, old_dentry, new_dir, new_dentry, 6928c2ecf20Sopenharmony_ci flags); 6938c2ecf20Sopenharmony_ci 6948c2ecf20Sopenharmony_ci hmdfs_init_recursive_para(rec_op_para, F_MKDIR_MERGE, 0, 0, NULL); 6958c2ecf20Sopenharmony_ci ret = rename_lo_d_cloud_child(&rename_para, rec_op_para); 6968c2ecf20Sopenharmony_ci if (ret != 0) { 6978c2ecf20Sopenharmony_ci d_drop(new_dentry); 6988c2ecf20Sopenharmony_ci } else { 6998c2ecf20Sopenharmony_ci hmdfs_update_meta(old_dir); 7008c2ecf20Sopenharmony_ci if (old_dir != new_dir) 7018c2ecf20Sopenharmony_ci hmdfs_update_meta(new_dir); 7028c2ecf20Sopenharmony_ci } 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci if (S_ISREG(old_dentry->d_inode->i_mode) && !ret) 7058c2ecf20Sopenharmony_ci d_invalidate(old_dentry); 7068c2ecf20Sopenharmony_cirename_out: 7078c2ecf20Sopenharmony_ci kfree(rec_op_para); 7088c2ecf20Sopenharmony_ci return ret; 7098c2ecf20Sopenharmony_ci} 7108c2ecf20Sopenharmony_ci 7118c2ecf20Sopenharmony_civoid hmdfs_update_meta(struct inode *dir) 7128c2ecf20Sopenharmony_ci{ 7138c2ecf20Sopenharmony_ci dir->i_ctime = dir->i_mtime = current_time(dir); 7148c2ecf20Sopenharmony_ci} 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ciconst struct inode_operations hmdfs_dir_iops_cloud_merge = { 7178c2ecf20Sopenharmony_ci .lookup = hmdfs_lookup_cloud_merge, 7188c2ecf20Sopenharmony_ci .mkdir = hmdfs_mkdir_cloud_merge, 7198c2ecf20Sopenharmony_ci .create = hmdfs_create_cloud_merge, 7208c2ecf20Sopenharmony_ci .rmdir = hmdfs_rmdir_merge, 7218c2ecf20Sopenharmony_ci .unlink = hmdfs_unlink_merge, 7228c2ecf20Sopenharmony_ci .rename = hmdfs_rename_cloud_merge, 7238c2ecf20Sopenharmony_ci .permission = hmdfs_permission, 7248c2ecf20Sopenharmony_ci}; 725