diff --git a/fs/hmdfs/hmdfs_merge_view.h b/fs/hmdfs/hmdfs_merge_view.h index 940741a5b920341697455bcbb58111d76fe449ff..2218baec1ec8bfcaf37ba18aac74d2062b630dd5 100644 --- a/fs/hmdfs/hmdfs_merge_view.h +++ b/fs/hmdfs/hmdfs_merge_view.h @@ -112,7 +112,7 @@ void update_inode_attr(struct inode *inode, struct dentry *child_dentry); int get_num_comrades(struct dentry *dentry); void assign_comrades_unlocked(struct dentry *child_dentry, struct list_head *onstack_comrades_head); -struct hmdfs_dentry_comrade *lookup_comrade(struct path lower_path, +struct hmdfs_dentry_comrade *lookup_comrade(struct dentry *lower_dentry, const char *d_name, int dev_id, unsigned int flags); diff --git a/fs/hmdfs/inode.c b/fs/hmdfs/inode.c index 33cc8c7419d5c89ee3292df056f6164907b65972..1a03f3072378c49f32f8ed08dcd3ead8ac467ce8 100644 --- a/fs/hmdfs/inode.c +++ b/fs/hmdfs/inode.c @@ -4,6 +4,7 @@ * * Copyright (c) 2020-2021 Huawei Device Co., Ltd. */ +#include #include "hmdfs_device_view.h" #include "inode.h" @@ -354,4 +355,37 @@ void hmdfs_update_upper_file(struct file *upper_file, struct file *lower_file) i_size_write(upper_file->f_inode, lower_size); truncate_inode_pages(upper_file->f_inode->i_mapping, 0); } +} + +struct dentry *lookup_multi_dir(struct dentry *root_dentry, + const char *name, + unsigned int flags) +{ + struct dentry *current_dentry = root_dentry; + struct dentry *ret_dentry = NULL; + const char *start = name; + const char *end = NULL; + + if (*start) { + dget(root_dentry); + } + + while (*start) { + if (*start == '/') { + start = start + 1; + continue; + } + end = strchr(start, '/'); + if (!end) + end = start + strlen(start); + ret_dentry = lookup_one_len(start, current_dentry, end - start); + if (IS_ERR(ret_dentry)) { + dput(current_dentry); + return ret_dentry; + } + dput(current_dentry); + current_dentry = ret_dentry; + start = end; + } + return ret_dentry; } \ No newline at end of file diff --git a/fs/hmdfs/inode.h b/fs/hmdfs/inode.h index fb9bd2929d581e6e48dee17bd369962869440e02..78346806c2185c91fc307811fc0c5f5c6abcc5df 100644 --- a/fs/hmdfs/inode.h +++ b/fs/hmdfs/inode.h @@ -261,4 +261,8 @@ struct inode *hmdfs_iget5_locked_cloud(struct super_block *sb, void hmdfs_update_upper_file(struct file *upper_file, struct file *lower_file); uint32_t make_ino_raw_cloud(uint8_t *cloud_id); + +struct dentry *lookup_multi_dir(struct dentry *root_dentry, + const char *name, + unsigned int flags); #endif // INODE_H diff --git a/fs/hmdfs/inode_merge.c b/fs/hmdfs/inode_merge.c index 7c1e1e4f8539adf339c4633ddbf0b0dc8f54833a..296b89aa7412ef64339151917e10cea87c049766 100644 --- a/fs/hmdfs/inode_merge.c +++ b/fs/hmdfs/inode_merge.c @@ -217,22 +217,25 @@ void assign_comrades_unlocked(struct dentry *child_dentry, mutex_unlock(&cdi->comrade_list_lock); } -struct hmdfs_dentry_comrade *lookup_comrade(struct path lower_path, +struct hmdfs_dentry_comrade *lookup_comrade(struct dentry *lower_dentry, const char *d_name, int dev_id, unsigned int flags) { - struct path path; + struct dentry *dentry = NULL; struct hmdfs_dentry_comrade *comrade = NULL; - int err; - err = vfs_path_lookup(lower_path.dentry, lower_path.mnt, d_name, flags, - &path); - if (err) - return ERR_PTR(err); + dentry = lookup_multi_dir(lower_dentry, d_name, flags); + if (d_is_negative(dentry)) { + dput(dentry); + dentry = ERR_PTR(-ENOENT); + } + if (dentry == NULL || IS_ERR(dentry)) { + return ERR_PTR(PTR_ERR(dentry)); + } - comrade = alloc_comrade(path.dentry, dev_id); - path_put(&path); + comrade = alloc_comrade(dentry, dev_id); + dput(dentry); return comrade; } @@ -346,28 +349,23 @@ static struct hmdfs_dentry_comrade *merge_lookup_comrade( struct hmdfs_sb_info *sbi, const char *name, int devid, unsigned int flags) { - int err; - struct path root, path; + struct dentry *dentry = NULL; struct hmdfs_dentry_comrade *comrade = NULL; const struct cred *old_cred = hmdfs_override_creds(sbi->cred); - err = kern_path(sbi->real_dst, LOOKUP_DIRECTORY, &root); - if (err) { - comrade = ERR_PTR(err); + dentry = lookup_multi_dir(sbi->sb->s_root, name, flags); + if (d_is_negative(dentry)) { + dput(dentry); + dentry = ERR_PTR(-ENOENT); + } + if (dentry == NULL || IS_ERR(dentry)) { + comrade = ERR_PTR(PTR_ERR(dentry)); goto out; } - err = vfs_path_lookup(root.dentry, root.mnt, name, flags, &path); - if (err) { - comrade = ERR_PTR(err); - goto root_put; - } + comrade = alloc_comrade(dentry, devid); + dput(dentry); - comrade = alloc_comrade(path.dentry, devid); - - path_put(&path); -root_put: - path_put(&root); out: hmdfs_revert_creds(old_cred); return comrade; @@ -550,7 +548,7 @@ static int lookup_merge_normal(struct dentry *dentry, unsigned int flags) * It's common for a network filesystem to incur various of faults, so we * intent to show mercy for faults here, except faults reported by the local. */ -static int do_lookup_merge_root(struct path path_dev, +static int do_lookup_merge_root(struct dentry *dentry_dev, struct dentry *child_dentry, unsigned int flags) { struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb); @@ -567,7 +565,7 @@ static int do_lookup_merge_root(struct path path_dev, // lookup real_dst/device_view/local memcpy(buf, DEVICE_VIEW_LOCAL, sizeof(DEVICE_VIEW_LOCAL)); - comrade = lookup_comrade(path_dev, buf, HMDFS_DEVID_LOCAL, flags); + comrade = lookup_comrade(dentry_dev, buf, HMDFS_DEVID_LOCAL, flags); if (IS_ERR(comrade)) { ret = PTR_ERR(comrade); goto out; @@ -579,7 +577,7 @@ static int do_lookup_merge_root(struct path path_dev, list_for_each_entry(peer, &sbi->connections.node_list, list) { mutex_unlock(&sbi->connections.node_lock); memcpy(buf, peer->cid, HMDFS_CID_SIZE); - comrade = lookup_comrade(path_dev, buf, peer->device_id, flags); + comrade = lookup_comrade(dentry_dev, buf, peer->device_id, flags); if (IS_ERR(comrade)) continue; @@ -641,33 +639,25 @@ static int lookup_merge_root(struct inode *root_inode, struct dentry *child_dentry, unsigned int flags) { struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb); - struct path path_dev; + struct dentry *dentry_dev = NULL; int ret = -ENOENT; - int buf_len; - char *buf = NULL; bool locked, down; - // consider additional one slash and one '\0' - buf_len = strlen(sbi->real_dst) + 1 + sizeof(DEVICE_VIEW_ROOT); - if (buf_len > PATH_MAX) - return -ENAMETOOLONG; - - buf = kmalloc(buf_len, GFP_KERNEL); - if (unlikely(!buf)) - return -ENOMEM; - - sprintf(buf, "%s/%s", sbi->real_dst, DEVICE_VIEW_ROOT); lock_root_inode_shared(root_inode, &locked, &down); - ret = hmdfs_get_path_in_sb(child_dentry->d_sb, buf, LOOKUP_DIRECTORY, - &path_dev); - if (ret) - goto free_buf; + dentry_dev = lookup_multi_dir(sbi->sb->s_root, DEVICE_VIEW_ROOT, flags); + if (d_is_negative(dentry_dev)) { + dput(dentry_dev); + dentry_dev = ERR_PTR(-ENOENT); + } + if (dentry_dev == NULL || IS_ERR(dentry_dev)) { + ret = PTR_ERR(dentry_dev); + goto out; + } - ret = do_lookup_merge_root(path_dev, child_dentry, flags); - path_put(&path_dev); + ret = do_lookup_merge_root(dentry_dev, child_dentry, flags); + dput(dentry_dev); -free_buf: - kfree(buf); +out: restore_root_inode_sem(root_inode, locked, down); return ret; } @@ -893,7 +883,7 @@ int do_create_merge(struct inode *parent_inode, struct dentry *child_dentry, } int hmdfs_do_ops_merge(struct inode *i_parent, struct dentry *d_child, - struct dentry *lo_d_child, struct path path, + struct dentry *lo_d_child, struct dentry *lo_d_parent, struct hmdfs_recursive_para *rec_op_para) { int ret = 0; @@ -903,20 +893,20 @@ int hmdfs_do_ops_merge(struct inode *i_parent, struct dentry *d_child, case F_MKDIR_MERGE: ret = do_mkdir_merge(i_parent, d_child, rec_op_para->mode, - d_inode(path.dentry), lo_d_child); + d_inode(lo_d_parent), lo_d_child); break; case F_CREATE_MERGE: ret = do_create_merge(i_parent, d_child, rec_op_para->mode, rec_op_para->want_excl, - d_inode(path.dentry), lo_d_child); + d_inode(lo_d_parent), lo_d_child); break; default: ret = -EINVAL; break; } } else { - ret = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), lo_d_child, + ret = vfs_mkdir(&nop_mnt_idmap, d_inode(lo_d_parent), lo_d_child, rec_op_para->mode); } if (ret) @@ -935,7 +925,6 @@ int hmdfs_create_lower_dentry(struct inode *i_parent, struct dentry *d_child, char *path_buf = kmalloc(PATH_MAX, GFP_KERNEL); char *absolute_path_buf = kmalloc(PATH_MAX, GFP_KERNEL); char *path_name = NULL; - struct path path = { .mnt = NULL, .dentry = NULL }; int ret = 0; if (unlikely(!path_buf || !absolute_path_buf)) { @@ -948,28 +937,28 @@ int hmdfs_create_lower_dentry(struct inode *i_parent, struct dentry *d_child, ret = PTR_ERR(path_name); goto out; } - if ((strlen(sbi->real_dst) + strlen(path_name) + - strlen(d_child->d_name.name) + 2) > PATH_MAX) { + if ((strlen(path_name) + strlen(d_child->d_name.name) + 1) > PATH_MAX) { ret = -ENAMETOOLONG; goto out; } - sprintf(absolute_path_buf, "%s%s/%s", sbi->real_dst, path_name, - d_child->d_name.name); + sprintf(absolute_path_buf, "%s/%s", path_name, d_child->d_name.name); if (is_dir) - lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf, - &path, LOOKUP_DIRECTORY); + lo_d_child = lookup_multi_dir(sbi->sb->s_root, absolute_path_buf, LOOKUP_DIRECTORY); else - lo_d_child = kern_path_create(AT_FDCWD, absolute_path_buf, - &path, 0); - if (IS_ERR(lo_d_child)) { + lo_d_child = lookup_multi_dir(sbi->sb->s_root, absolute_path_buf, 0); + + if (lo_d_child == NULL || IS_ERR(lo_d_child)) { ret = PTR_ERR(lo_d_child); goto out; } + if (d_is_positive(lo_d_child)) { + ret = -EEXIST; + goto out_put; + } // to ensure link_comrade after vfs_mkdir succeed - ret = hmdfs_do_ops_merge(i_parent, d_child, lo_d_child, path, - rec_op_para); + ret = hmdfs_do_ops_merge(i_parent, d_child, lo_d_child, lo_d_parent, rec_op_para); if (ret) goto out_put; new_comrade = alloc_comrade(lo_d_child, HMDFS_DEVID_LOCAL); @@ -983,7 +972,7 @@ int hmdfs_create_lower_dentry(struct inode *i_parent, struct dentry *d_child, update_inode_attr(d_inode(d_child), d_child); out_put: - done_path_create(&path, lo_d_child); + dput(lo_d_child); out: kfree(absolute_path_buf); kfree(path_buf); @@ -1242,7 +1231,6 @@ int do_rename_merge(struct inode *old_dir, struct dentry *old_dentry, struct hmdfs_sb_info *sbi = (old_dir->i_sb)->s_fs_info; struct hmdfs_dentry_info_merge *dim = hmdfs_dm(old_dentry); struct hmdfs_dentry_comrade *comrade = NULL, *new_comrade = NULL; - struct path lo_p_new = { .mnt = NULL, .dentry = NULL }; struct inode *lo_i_old_dir = NULL, *lo_i_new_dir = NULL; struct dentry *lo_d_old_dir = NULL, *lo_d_old = NULL, *lo_d_new_dir = NULL, *lo_d_new = NULL; @@ -1282,26 +1270,26 @@ int do_rename_merge(struct inode *old_dir, struct dentry *old_dentry, continue; } - if (strlen(sbi->real_dst) + strlen(path_name) + - strlen(new_dentry->d_name.name) + 2 > PATH_MAX) { + if (strlen(path_name) + strlen(new_dentry->d_name.name) + 1 > PATH_MAX) { ret = -ENAMETOOLONG; goto out; } - snprintf(abs_path_buf, PATH_MAX, "%s%s/%s", sbi->real_dst, - path_name, new_dentry->d_name.name); + snprintf(abs_path_buf, PATH_MAX, "%s/%s", path_name, new_dentry->d_name.name); if (S_ISDIR(d_inode(old_dentry)->i_mode)) - lo_d_new = kern_path_create(AT_FDCWD, abs_path_buf, - &lo_p_new, - LOOKUP_DIRECTORY); + lo_d_new = lookup_multi_dir(sbi->sb->s_root, abs_path_buf, LOOKUP_DIRECTORY); else - lo_d_new = kern_path_create(AT_FDCWD, abs_path_buf, - &lo_p_new, 0); - if (IS_ERR(lo_d_new)) { + lo_d_new = lookup_multi_dir(sbi->sb->s_root, abs_path_buf, 0); + + if (lo_d_new == NULL || IS_ERR(lo_d_new)) { ret = PTR_ERR(lo_d_new); goto out; } - + if (d_is_positive(lo_d_new)) { + ret = -EEXIST; + dput(lo_d_new); + goto out; + } lo_d_new_dir = dget_parent(lo_d_new); lo_i_new_dir = d_inode(lo_d_new_dir); lo_d_old_dir = dget_parent(lo_d_old); @@ -1316,7 +1304,7 @@ int do_rename_merge(struct inode *old_dir, struct dentry *old_dentry, rename_data.flags = flags; ret = vfs_rename(&rename_data); - new_comrade = alloc_comrade(lo_p_new.dentry, comrade->dev_id); + new_comrade = alloc_comrade(lo_d_new_dir, comrade->dev_id); if (IS_ERR(new_comrade)) { ret = PTR_ERR(new_comrade); goto no_comrade; @@ -1324,7 +1312,7 @@ int do_rename_merge(struct inode *old_dir, struct dentry *old_dentry, link_comrade_unlocked(new_dentry, new_comrade); no_comrade: - done_path_create(&lo_p_new, lo_d_new); + dput(lo_d_new); dput(lo_d_old_dir); dput(lo_d_new_dir); }