From 857f7a590489f8152c203bfb0625547fb2b25e4e Mon Sep 17 00:00:00 2001 From: liuzerun Date: Wed, 28 Jun 2023 13:27:24 +0000 Subject: [PATCH 1/2] file_remote_share --- fs/hmdfs/file_merge.c | 43 +++++++++++++++++++++++++++++++++++++++++++ fs/hmdfs/hmdfs.h | 8 ++++++++ 2 files changed, 51 insertions(+) diff --git a/fs/hmdfs/file_merge.c b/fs/hmdfs/file_merge.c index 8048a203a8e6..f5adee33b630 100644 --- a/fs/hmdfs/file_merge.c +++ b/fs/hmdfs/file_merge.c @@ -8,6 +8,7 @@ #include "hmdfs_merge_view.h" #include +#include #include "hmdfs.h" #include "hmdfs_trace.h" @@ -582,11 +583,53 @@ static long hmdfs_ioc_get_writeopen_cnt(struct file *filp, unsigned long arg) return put_user(wo_cnt, (int __user *)arg); } +static long hmdfs_ioc_get_drag_path(struct file *filp, unsigned long arg) +{ + int error = 0; + char localPath[NAME_MAX]; + char cloudPath[NAME_MAX]; + struct dentry *dentry; + struct path path; + struct hmdfs_drag_info hdi; + + if (!access_ok((struct hmdfs_drag_info __user *)arg, + sizeof(struct hmdfs_drag_info))) + return -EFAULT; + + if (copy_from_user(&hdi, (struct hmdfs_drag_info __user *)arg, + sizeof(hdi))) + return -EFAULT; + + if (!access_ok(hdi.localPath, hdi.localLen)) + return -EFAULT; + if (!access_ok(hdi.cloudPath, hdi.cloudLen)) + return -EFAULT; + if (copy_from_user(localPath, (char __user *)hdi.localPath, + hdi.localLen)) + return -EFAULT; + if (copy_from_user(cloudPath, (char __user *)hdi.cloudPath, + hdi.cloudLen)) + return -EFAULT; + hmdfs_info("localPath: %s", localPath); + hmdfs_info("localPath: %s", cloudPath); + + dentry = kern_path_create(AT_FDCWD, cloudPath, &path, 0); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + hmdfs_info("dentry finish"); + error = vfs_symlink(path.dentry->d_inode, dentry, localPath); + done_path_create(&path, dentry); + hmdfs_info("error: %d", error); + return error; +} + static long hmdfs_file_ioctl_merge(struct file *filp, unsigned int cmd, unsigned long arg) { switch (cmd) { case HMDFS_IOC_GET_WRITEOPEN_CNT: return hmdfs_ioc_get_writeopen_cnt(filp, arg); + case HMDFS_IOC_GET_DRAG_PATH: + return hmdfs_ioc_get_drag_path(filp, arg); default: return -ENOTTY; } diff --git a/fs/hmdfs/hmdfs.h b/fs/hmdfs/hmdfs.h index 14adb4fac1b7..cddf45ab07a0 100644 --- a/fs/hmdfs/hmdfs.h +++ b/fs/hmdfs/hmdfs.h @@ -30,6 +30,7 @@ #define HMDFS_IOC 0xf2 #define HMDFS_IOC_SET_SHARE_PATH _IOW(HMDFS_IOC, 1, struct hmdfs_share_control) #define HMDFS_IOC_GET_WRITEOPEN_CNT _IOR(HMDFS_IOC, 2, __u32) +#define HMDFS_IOC_GET_DRAG_PATH _IOR(HMDFS_IOC, 3, __u32) #define HMDFS_PAGE_SIZE 4096 #define HMDFS_PAGE_OFFSET 12 @@ -222,6 +223,13 @@ static inline bool hmdfs_is_stash_enabled(const struct hmdfs_sb_info *sbi) return sbi->s_offline_stash; } +struct hmdfs_drag_info{ + unsigned long localLen; + unsigned long localPath; + unsigned long cloudLen; + unsigned long cloudPath; +}; + struct setattr_info { loff_t size; unsigned int valid; -- Gitee From 0530f2d3f688000fa004f94b3143ad437717fc49 Mon Sep 17 00:00:00 2001 From: liuzerun Date: Mon, 3 Jul 2023 07:29:27 +0000 Subject: [PATCH 2/2] support symlink Signed-off-by: liuzerun --- fs/hmdfs/file_cloud.c | 2 +- fs/hmdfs/file_merge.c | 37 ++++-- fs/hmdfs/hmdfs.h | 8 +- fs/hmdfs/hmdfs_dentryfile.c | 30 ++++- fs/hmdfs/hmdfs_dentryfile.h | 1 + fs/hmdfs/hmdfs_merge_view.h | 1 + fs/hmdfs/hmdfs_server.c | 254 ++++++++++++++++++++++++++++++++++-- fs/hmdfs/hmdfs_trace.h | 6 + fs/hmdfs/inode_local.c | 57 +++++++- fs/hmdfs/inode_merge.c | 65 ++++++++- fs/hmdfs/inode_remote.c | 9 +- fs/hmdfs/stash.c | 4 +- 12 files changed, 436 insertions(+), 38 deletions(-) diff --git a/fs/hmdfs/file_cloud.c b/fs/hmdfs/file_cloud.c index f4506ec1510d..e7db1a20f45c 100644 --- a/fs/hmdfs/file_cloud.c +++ b/fs/hmdfs/file_cloud.c @@ -81,7 +81,7 @@ int hmdfs_file_open_cloud(struct inode *inode, struct file *file) return -ENOENT; } - lower_file = file_open_root(&root_path, dir_path, + lower_file = file_open_root(root_path.dentry, root_path.mnt, dir_path, file->f_flags, file->f_mode); path_put(&root_path); if (IS_ERR(lower_file)) { diff --git a/fs/hmdfs/file_merge.c b/fs/hmdfs/file_merge.c index f5adee33b630..ed805645f574 100644 --- a/fs/hmdfs/file_merge.c +++ b/fs/hmdfs/file_merge.c @@ -593,23 +593,40 @@ static long hmdfs_ioc_get_drag_path(struct file *filp, unsigned long arg) struct hmdfs_drag_info hdi; if (!access_ok((struct hmdfs_drag_info __user *)arg, - sizeof(struct hmdfs_drag_info))) + sizeof(struct hmdfs_drag_info))) { + hmdfs_info("hmdfs_ioc_get_drag_path: struct is not OK, error: -EFAULT"); return -EFAULT; + } if (copy_from_user(&hdi, (struct hmdfs_drag_info __user *)arg, - sizeof(hdi))) + sizeof(hdi))) { + hmdfs_info("hmdfs_ioc_get_drag_path: copy_from_user failed, error: -EFAULT"); return -EFAULT; + } + + hmdfs_info("localLen: %llu", hdi.localLen); + hmdfs_info("localLen: %llx", hdi.localPath); + hmdfs_info("localLen: %llu", hdi.cloudLen); + hmdfs_info("localLen: %llx", hdi.cloudPath); - if (!access_ok(hdi.localPath, hdi.localLen)) - return -EFAULT; - if (!access_ok(hdi.cloudPath, hdi.cloudLen)) - return -EFAULT; + if (!access_ok((char *)hdi.localPath, hdi.localLen)) { + hmdfs_info("hmdfs_ioc_get_drag_path: localPath is not OK, error: -EFAULT"); + return -EFAULT; + } + if (!access_ok((char *)hdi.cloudPath, hdi.cloudLen)) { + hmdfs_info("hmdfs_ioc_get_drag_path: cloudPath is not OK, error: -EFAULT"); + return -EFAULT; + } if (copy_from_user(localPath, (char __user *)hdi.localPath, - hdi.localLen)) + hdi.localLen)) { + hmdfs_info("hmdfs_ioc_get_drag_path: localPath failed, error: -EFAULT"); return -EFAULT; + } if (copy_from_user(cloudPath, (char __user *)hdi.cloudPath, - hdi.cloudLen)) + hdi.cloudLen)) { + hmdfs_info("hmdfs_ioc_get_drag_path: cloudPath failed, error: -EFAULT"); return -EFAULT; + } hmdfs_info("localPath: %s", localPath); hmdfs_info("localPath: %s", cloudPath); @@ -625,12 +642,15 @@ static long hmdfs_ioc_get_drag_path(struct file *filp, unsigned long arg) static long hmdfs_file_ioctl_merge(struct file *filp, unsigned int cmd, unsigned long arg) { + hmdfs_info("hmdfs_file_ioctl_merge"); switch (cmd) { case HMDFS_IOC_GET_WRITEOPEN_CNT: return hmdfs_ioc_get_writeopen_cnt(filp, arg); case HMDFS_IOC_GET_DRAG_PATH: + hmdfs_info("HMDFS_IOC_GET_WRITEOPEN_CNT"); return hmdfs_ioc_get_drag_path(filp, arg); default: + hmdfs_info("Case does not hit! error:-%d", ENOTTY); return -ENOTTY; } } @@ -649,6 +669,7 @@ const struct file_operations hmdfs_file_fops_merge = { .release = hmdfs_file_release_local, .fsync = hmdfs_fsync_local, .unlocked_ioctl = hmdfs_file_ioctl_merge, + .compat_ioctl = hmdfs_file_ioctl_merge, .splice_read = generic_file_splice_read, .splice_write = iter_file_splice_write, }; diff --git a/fs/hmdfs/hmdfs.h b/fs/hmdfs/hmdfs.h index cddf45ab07a0..181ba0a39ab2 100644 --- a/fs/hmdfs/hmdfs.h +++ b/fs/hmdfs/hmdfs.h @@ -224,10 +224,10 @@ static inline bool hmdfs_is_stash_enabled(const struct hmdfs_sb_info *sbi) } struct hmdfs_drag_info{ - unsigned long localLen; - unsigned long localPath; - unsigned long cloudLen; - unsigned long cloudPath; + uint64_t localLen; + uint64_t localPath; + uint64_t cloudLen; + uint64_t cloudPath; }; struct setattr_info { diff --git a/fs/hmdfs/hmdfs_dentryfile.c b/fs/hmdfs/hmdfs_dentryfile.c index 01efcba2f6ce..7d3f0a82659a 100644 --- a/fs/hmdfs/hmdfs_dentryfile.c +++ b/fs/hmdfs/hmdfs_dentryfile.c @@ -579,6 +579,9 @@ int read_dentry(struct hmdfs_sb_info *sbi, char *file_name, else if (S_ISREG(le16_to_cpu( dentry_group->nsl[j].i_mode))) file_type = DT_REG; + else if (S_ISLNK(le16_to_cpu( + dentry_group->nsl[j].i_mode))) + file_type = DT_LNK; else continue; @@ -770,17 +773,25 @@ struct hmdfs_dentry *hmdfs_find_dentry(struct dentry *child_dentry, } void update_dentry(struct hmdfs_dentry_group *d, struct dentry *child_dentry, - struct inode *inode, __u32 name_hash, unsigned int bit_pos) + struct inode *inode, struct super_block *hmdfs_sb, + __u32 name_hash, unsigned int bit_pos) { struct hmdfs_dentry *de; + struct hmdfs_dentry_info *gdi; const struct qstr name = child_dentry->d_name; int slots = get_dentry_slots(name.len); int i; unsigned long ino; __u32 igen; - ino = inode->i_ino; - igen = inode->i_generation; + gdi = hmdfs_sb == child_dentry->d_sb ? hmdfs_d(child_dentry) : NULL; + if (!gdi && S_ISLNK(d_inode(child_dentry)->i_mode)) { + ino = d_inode(child_dentry)->i_ino; + igen = d_inode(child_dentry)->i_generation; + } else { + ino = inode->i_ino; + igen = inode->i_generation; + } de = &d->nsl[bit_pos]; de->hash = cpu_to_le32(name_hash); @@ -791,7 +802,13 @@ void update_dentry(struct hmdfs_dentry_group *d, struct dentry *child_dentry, de->i_size = cpu_to_le64(inode->i_size); de->i_ino = cpu_to_le64(generate_u64_ino(ino, igen)); de->i_flag = 0; - de->i_mode = cpu_to_le16(inode->i_mode); + + if (gdi && hm_islnk(gdi->file_type)) + de->i_mode = cpu_to_le16(S_IFLNK); + else if (!gdi && S_ISLNK(d_inode(child_dentry)->i_mode)) + de->i_mode = d_inode(child_dentry)->i_mode; + else + de->i_mode = cpu_to_le16(inode->i_mode); for (i = 0; i < slots; i++) { __set_bit_le(bit_pos + i, d->bitmap); @@ -902,7 +919,8 @@ int create_dentry(struct dentry *child_dentry, struct inode *inode, goto find; add: pos = get_dentry_group_pos(bidx); - update_dentry(dentry_blk, child_dentry, inode, namehash, bit_pos); + update_dentry(dentry_blk, child_dentry, inode, sbi->sb, namehash, + bit_pos); size = cache_file_write(sbi, file, dentry_blk, sizeof(struct hmdfs_dentry_group), &pos); if (size != sizeof(struct hmdfs_dentry_group)) @@ -1043,7 +1061,7 @@ struct file *create_local_dentry_file_cache(struct hmdfs_sb_info *sbi) goto out; } - filp = file_open_root(&cache_dir, ".", + filp = file_open_root(cache_dir.dentry, cache_dir.mnt, ".", O_RDWR | O_LARGEFILE | O_TMPFILE, DENTRY_FILE_PERM); if (IS_ERR(filp)) diff --git a/fs/hmdfs/hmdfs_dentryfile.h b/fs/hmdfs/hmdfs_dentryfile.h index 72bb5954a8b4..fd2bdddffcc8 100644 --- a/fs/hmdfs/hmdfs_dentryfile.h +++ b/fs/hmdfs/hmdfs_dentryfile.h @@ -193,6 +193,7 @@ struct getdents_callback_real { struct file *file; struct hmdfs_sb_info *sbi; const char *dir; + struct list_head dir_ents; }; struct file *hmdfs_server_rebuild_dents(struct hmdfs_sb_info *sbi, diff --git a/fs/hmdfs/hmdfs_merge_view.h b/fs/hmdfs/hmdfs_merge_view.h index aeda4127d1cc..1e7eedffa697 100644 --- a/fs/hmdfs/hmdfs_merge_view.h +++ b/fs/hmdfs/hmdfs_merge_view.h @@ -241,6 +241,7 @@ struct dentry *hmdfs_get_fst_lo_d(struct dentry *dentry); extern const struct inode_operations hmdfs_file_iops_merge; extern const struct file_operations hmdfs_file_fops_merge; +extern const struct inode_operations hmdfs_symlink_iops_merge; extern const struct inode_operations hmdfs_dir_iops_merge; extern const struct file_operations hmdfs_dir_fops_merge; extern const struct inode_operations hmdfs_file_iops_cloud_merge; diff --git a/fs/hmdfs/hmdfs_server.c b/fs/hmdfs/hmdfs_server.c index 7e7460a7be6a..f46090b4a67f 100644 --- a/fs/hmdfs/hmdfs_server.c +++ b/fs/hmdfs/hmdfs_server.c @@ -23,6 +23,12 @@ #define HMDFS_MAX_HIDDEN_DIR 1 +enum { + HMDFS_NOT_HIDDEN_DIR = 0, + HMDFS_IS_HIDDEN_DIR, + HMDFS_IN_HIDDEN_DIR, +}; + struct hmdfs_open_info { struct file *file; struct inode *inode; @@ -73,6 +79,39 @@ void remove_file_from_conn(struct hmdfs_peer *conn, __u32 file_id) spin_unlock(lock); } +struct file *hmdfs_open_photokit_path(struct hmdfs_sb_info *sbi, + const char *path) +{ + struct file *file; + int err; + const char *root_name = sbi->local_dst; + char *real_path; + int path_len; + + path_len = strlen(root_name) + strlen(path) + 2; + if (path_len > PATH_MAX) { + err = -EINVAL; + return ERR_PTR(err); + } + real_path = kzalloc(path_len, GFP_KERNEL); + if (!real_path) { + err = -ENOMEM; + return ERR_PTR(err); + } + + sprintf(real_path, "%s%s", root_name, path); + file = filp_open(real_path, O_RDWR | O_LARGEFILE, 0644); + if (IS_ERR(file)) { + hmdfs_info("filp_open failed: %ld", PTR_ERR(file)); + } else { + hmdfs_info("get file with magic %lu", + file->f_inode->i_sb->s_magic); + } + + kfree(real_path); + return file; +} + struct file *hmdfs_open_path(struct hmdfs_sb_info *sbi, const char *path) { struct path root_path; @@ -85,7 +124,7 @@ struct file *hmdfs_open_path(struct hmdfs_sb_info *sbi, const char *path) hmdfs_info("kern_path failed: %d", err); return ERR_PTR(err); } - file = file_open_root(&root_path, path, + file = file_open_root(root_path.dentry, root_path.mnt, path, O_RDWR | O_LARGEFILE, 0644); path_put(&root_path); if (IS_ERR(file)) { @@ -157,6 +196,38 @@ void __init hmdfs_server_add_node_evt_cb(void) hmdfs_node_add_evt_cb(server_cb, ARRAY_SIZE(server_cb)); } +static int hmdfs_get_inode_by_name(struct hmdfs_peer *con, const char *filename, + uint64_t *ino) +{ + int ret = 0; + struct path root_path; + struct path dst_path; + struct inode *inode = NULL; + + ret = kern_path(con->sbi->local_dst, 0, &root_path); + if (ret) { + hmdfs_err("kern_path failed err = %d", ret); + return ret; + } + + ret = vfs_path_lookup(root_path.dentry, root_path.mnt, filename, 0, + &dst_path); + if (ret) { + path_put(&root_path); + return ret; + } + + inode = d_inode(dst_path.dentry); + if (con->sbi->sb == inode->i_sb) + inode = hmdfs_i(inode)->lower_inode; + *ino = generate_u64_ino(inode->i_ino, inode->i_generation); + + path_put(&dst_path); + path_put(&root_path); + + return 0; +} + static const char *datasl_str[] = { "s0", "s1", "s2", "s3", "s4" }; @@ -249,7 +320,10 @@ static struct file *hmdfs_open_file(struct hmdfs_peer *con, if (err) return ERR_PTR(err); } - file = hmdfs_open_path(con->sbi, filename); + if (hm_islnk(file_type)) + file = hmdfs_open_photokit_path(con->sbi, filename); + else + file = hmdfs_open_path(con->sbi, filename); if (IS_ERR(file)) { reset_item_opened_status(con->sbi, filename); @@ -402,8 +476,14 @@ static int hmdfs_get_open_info(struct hmdfs_peer *con, uint8_t file_type, info->stat_valid = true; } - info->real_ino = generate_u64_ino(info->inode->i_ino, - info->inode->i_generation); + if (hm_islnk(file_type)) { + ret = hmdfs_get_inode_by_name(con, filename, &info->real_ino); + if (ret) + return ret; + } else { + info->real_ino = generate_u64_ino(info->inode->i_ino, + info->inode->i_generation); + } return 0; } @@ -477,7 +557,8 @@ static int hmdfs_check_and_create(struct path *path_parent, } else { if (is_excl) err = -EEXIST; - else if (S_ISLNK(d_inode(dentry)->i_mode)) + else if (S_ISREG(d_inode(dentry)->i_mode) && + hm_islnk(hmdfs_d(dentry)->file_type)) err = -EINVAL; else if (S_ISDIR(d_inode(dentry)->i_mode)) err = -EISDIR; @@ -985,6 +1066,31 @@ void hmdfs_server_readdir(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, hmdfs_send_err_response(con, cmd, err); } +int is_hidden_dir(const char *dir) +{ + int i; + int hidden_len; + int dir_len; + static const char *hidden_dir[HMDFS_MAX_HIDDEN_DIR] = { + "/Android", + }; + + for (i = 0; i < HMDFS_MAX_HIDDEN_DIR; i++) { + if (!strcmp(dir, hidden_dir[i])) + return HMDFS_IS_HIDDEN_DIR; + + hidden_len = strlen(hidden_dir[i]); + dir_len = strlen(dir); + if (dir_len <= hidden_len) + continue; + else if (dir[hidden_len] == '/' && + !strncmp(dir, hidden_dir[i], hidden_len)) + return HMDFS_IN_HIDDEN_DIR; + } + + return HMDFS_NOT_HIDDEN_DIR; +} + void hmdfs_server_mkdir(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, void *data) { @@ -1149,6 +1255,50 @@ void hmdfs_server_rename(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, hmdfs_send_err_response(con, cmd, err); } +static int hmdfs_lookup_symlink(struct path *link_path, const char *path_fmt, + ... ) +{ + int ret; + va_list args; + char *path = kmalloc(PATH_MAX, GFP_KERNEL); + + if (!path) + return -ENOMEM; + + va_start(args, path_fmt); + ret = vsnprintf(path, PATH_MAX, path_fmt, args); + va_end(args); + + if(ret >= PATH_MAX) { + ret = -ENAMETOOLONG; + goto out; + } + + ret = kern_path(path, LOOKUP_FOLLOW, link_path); + if (ret) { + hmdfs_err("kern_path failed err = %d", ret); + goto out; + } + + if (!S_ISREG(d_inode(link_path->dentry)->i_mode)) { + hmdfs_err("path is dir symlink"); + path_put(link_path); + ret = -EOPNOTSUPP; + goto out; + } + +out: + kfree(path); + return ret; +} + +struct dir_entry_info { + struct list_head list; + char *name; + int name_len; + unsigned int d_type; +}; + static int hmdfs_filldir_real(struct dir_context *ctx, const char *name, int name_len, loff_t offset, u64 ino, unsigned int d_type) @@ -1201,6 +1351,61 @@ static int hmdfs_filldir_real(struct dir_context *ctx, const char *name, return 0; } +static void _do_create_dentry(struct getdents_callback_real *gc, + struct dir_entry_info *di) +{ + int res = 0; + struct dentry *child = NULL; + + inode_lock(d_inode(gc->parent_path->dentry)); + child = lookup_one_len(di->name, gc->parent_path->dentry, di->name_len); + inode_unlock(d_inode(gc->parent_path->dentry)); + if (IS_ERR(child)) { + res = PTR_ERR(child); + hmdfs_err("lookup faild because %d", res); + return; + } + + if (d_really_is_negative(child)) { + hmdfs_err("lookup faild because negative dentry"); + goto out; + } + + if (di->d_type == DT_REG || di->d_type == DT_DIR) { + create_dentry(child, d_inode(child), gc->file, gc->sbi); + gc->num++; + } else if (di->d_type == DT_LNK) { + struct path link_path; + + res = hmdfs_lookup_symlink(&link_path, "%s/%s/%s", + gc->sbi->local_src, gc->dir, + di->name); + if (!res) { + create_dentry(child, d_inode(link_path.dentry), + gc->file, gc->sbi); + path_put(&link_path); + gc->num++; + } else if (res == -ENOENT) { + create_dentry(child, d_inode(child), gc->file, gc->sbi); + gc->num++; + } + } +out: + dput(child); +} + +static void _gen_dir_dents_info(struct getdents_callback_real *gc) +{ + struct dir_entry_info *di = NULL, *tmp = NULL; + + list_for_each_entry_safe(di, tmp, &gc->dir_ents, list) { + _do_create_dentry(gc, di); + list_del(&di->list); + kfree(di->name); + kfree(di); + } +} + static void hmdfs_server_set_header(struct hmdfs_dcache_header *header, struct file *file, struct file *dentry_file) { @@ -1249,13 +1454,19 @@ struct file *hmdfs_server_rebuild_dents(struct hmdfs_sb_info *sbi, gc.parent_path = path; gc.file = dentry_file; + INIT_LIST_HEAD(&gc.dir_ents); + + if (is_hidden_dir(dir)) + goto write_header; err = iterate_dir(file, &(gc.ctx)); + _gen_dir_dents_info(&gc); if (err) { hmdfs_err("iterate_dir failed"); goto out; } +write_header: header.case_sensitive = sbi->s_case_sensitive; header.num = cpu_to_le64(gc.num); if (num) @@ -1315,6 +1526,27 @@ void hmdfs_server_writepage(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, hmdfs_server_check_writeback(hswb); } +static int hmdfs_lookup_linkpath(struct hmdfs_sb_info *sbi, + const char *path_name, struct path *dst_path) +{ + struct path link_path; + int err; + + err = hmdfs_lookup_symlink(&link_path, "%s/%s", sbi->local_dst, + path_name); + if (err) + return err; + + if (d_inode(link_path.dentry)->i_sb != sbi->sb) { + path_put(dst_path); + *dst_path = link_path; + } else { + path_put(&link_path); + } + + return 0; +} + static struct inode *hmdfs_verify_path(struct dentry *dentry, char *recv_buf, struct super_block *sb) { @@ -1382,8 +1614,11 @@ void hmdfs_server_setattr(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, } if (S_ISLNK(inode->i_mode)) { - err = -EPERM; - goto out_put_dst; + err = hmdfs_lookup_linkpath(con->sbi, recv->buf, &dst_path); + if(err == -ENOENT) + err = 0; + else if (err) + goto out_put_dst; } dentry = dst_path.dentry; @@ -1476,8 +1711,9 @@ void hmdfs_server_getattr(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, } if (S_ISLNK(inode->i_mode)) { - err = -EPERM; - goto out_put_dst; + err = hmdfs_lookup_linkpath(con->sbi, recv->buf, &dst_path); + if(err && err != -ENOENT) + goto out_put_dst; } err = vfs_getattr(&dst_path, &ks, STATX_BASIC_STATS | STATX_BTIME, 0); diff --git a/fs/hmdfs/hmdfs_trace.h b/fs/hmdfs/hmdfs_trace.h index 86478425aea8..dd89f750ccc5 100644 --- a/fs/hmdfs/hmdfs_trace.h +++ b/fs/hmdfs/hmdfs_trace.h @@ -203,6 +203,12 @@ define_hmdfs_lookup_op_end_event(hmdfs_mkdir_merge); define_hmdfs_lookup_op_end_event(hmdfs_rmdir_merge); define_hmdfs_lookup_op_end_event(hmdfs_create_merge); +define_hmdfs_lookup_op_end_event(hmdfs_symlink_merge); +define_hmdfs_lookup_op_end_event(hmdfs_symlink_local); + +define_hmdfs_lookup_op_end_event(hmdfs_get_link_merge); +define_hmdfs_lookup_op_end_event(hmdfs_get_link_local); + define_hmdfs_lookup_op_end_event(hmdfs_lookup_share); define_hmdfs_lookup_op_end_event(hmdfs_lookup_share_end); diff --git a/fs/hmdfs/inode_local.c b/fs/hmdfs/inode_local.c index 5d26f6dbbd02..c02302af238f 100644 --- a/fs/hmdfs/inode_local.c +++ b/fs/hmdfs/inode_local.c @@ -103,6 +103,9 @@ struct inode *fill_inode_local(struct super_block *sb, else if (S_ISREG(lower_inode->i_mode)) inode->i_mode = (lower_inode->i_mode & S_IFMT) | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + else if (S_ISLNK(lower_inode->i_mode)) + inode->i_mode = + S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; #ifdef CONFIG_HMDFS_FS_PERMISSION inode->i_uid = lower_inode->i_uid; @@ -124,6 +127,10 @@ struct inode *fill_inode_local(struct super_block *sb, } else if (S_ISREG(lower_inode->i_mode)) { inode->i_op = &hmdfs_file_iops_local; inode->i_fop = &hmdfs_file_fops_local; + } else if (S_ISLNK(lower_inode->i_mode)) { + inode->i_op = &hmdfs_symlink_iops_local; + inode->i_fop = &hmdfs_file_fops_local; + inode->i_size = i_size_read(lower_inode); } else { ret = -EIO; goto bad_inode; @@ -217,6 +224,12 @@ static int __lookup_nosensitive(struct path *lower_parent_path, return err; } +static inline void set_symlink_flag(struct hmdfs_dentry_info *gdi) +{ + gdi->file_type = HM_SYMLINK; +} + + struct dentry *hmdfs_lookup_local(struct inode *parent_inode, struct dentry *child_dentry, unsigned int flags) @@ -261,7 +274,8 @@ struct dentry *hmdfs_lookup_local(struct inode *parent_inode, child_inode = fill_inode_local(parent_inode->i_sb, d_inode(lower_path.dentry), child_dentry->d_name.name); - + if (S_ISLNK(d_inode(lower_path.dentry)->i_mode)) + set_symlink_flag(gdi); if (IS_ERR(child_inode)) { err = PTR_ERR(child_inode); ret = ERR_PTR(err); @@ -726,6 +740,40 @@ int hmdfs_rename_local(struct inode *old_dir, struct dentry *old_dentry, return err; } +static const char *hmdfs_get_link_local(struct dentry *dentry, + struct inode *inode, + struct delayed_call *done) +{ + const char *link = NULL; + struct dentry *lower_dentry = NULL; + struct inode *lower_inode = NULL; + struct path lower_path; + + if(!dentry) { + hmdfs_err("dentry MULL"); + link = ERR_PTR(-ECHILD); + goto link_out; + } + + hmdfs_get_lower_path(dentry, &lower_path); + lower_dentry = lower_path.dentry; + lower_inode = d_inode(lower_dentry); + if(!lower_inode->i_op || !lower_inode->i_op->get_link) { + hmdfs_err("The lower inode doesn't support get_link i_op"); + link = ERR_PTR(-EINVAL); + goto out; + } + + link = lower_inode->i_op->get_link(lower_dentry, lower_inode, done); + if(IS_ERR_OR_NULL(link)) + goto out; + fsstack_copy_attr_atime(inode, lower_inode); +out: + hmdfs_put_lower_path(&lower_path); +link_out: + return link; +} + static int hmdfs_setattr_local(struct dentry *dentry, struct iattr *ia) { struct inode *inode = d_inode(dentry); @@ -779,6 +827,7 @@ static int hmdfs_getattr_local(const struct path *path, struct kstat *stat, stat->gid = d_inode(path->dentry)->i_gid; hmdfs_put_lower_path(&lower_path); + hmdfs_info("hmdfs_getattr_local, ret: %d", ret); return ret; } @@ -899,6 +948,12 @@ const struct inode_operations hmdfs_dir_inode_ops_local = { .getattr = hmdfs_getattr_local, }; +const struct inode_operations hmdfs_symlink_iops_local = { + .get_link = hmdfs_get_link_local, + .permission = hmdfs_permission, + .setattr = hmdfs_setattr_local, +}; + const struct inode_operations hmdfs_dir_inode_ops_share = { .lookup = hmdfs_lookup_share, .permission = hmdfs_permission, diff --git a/fs/hmdfs/inode_merge.c b/fs/hmdfs/inode_merge.c index 17a7af217d8d..96f83b8539da 100644 --- a/fs/hmdfs/inode_merge.c +++ b/fs/hmdfs/inode_merge.c @@ -109,9 +109,9 @@ static struct inode *fill_inode_merge(struct super_block *sb, if (lo_d_dentry) { fst_lo_d = lo_d_dentry; dget(fst_lo_d); - } else { + } else fst_lo_d = hmdfs_get_fst_lo_d(child_dentry); - } + if (!fst_lo_d) { inode = ERR_PTR(-EINVAL); goto out; @@ -119,15 +119,20 @@ static struct inode *fill_inode_merge(struct super_block *sb, if (hmdfs_i(parent_inode)->inode_type == HMDFS_LAYER_ZERO) inode = hmdfs_iget_locked_root(sb, HMDFS_ROOT_MERGE, NULL, NULL); + else inode = hmdfs_iget5_locked_merge(sb, fst_lo_d); + if (!inode) { hmdfs_err("iget5_locked get inode NULL"); inode = ERR_PTR(-ENOMEM); goto out; } - if (!(inode->i_state & I_NEW)) + if (!(inode->i_state & I_NEW)){ + hmdfs_err("lzr !(inode->i_state & I_NEW)"); goto out; + } + info = hmdfs_i(inode); if (hmdfs_i(parent_inode)->inode_type == HMDFS_LAYER_ZERO) info->inode_type = HMDFS_LAYER_FIRST_MERGE; @@ -140,7 +145,14 @@ static struct inode *fill_inode_merge(struct super_block *sb, update_inode_attr(inode, child_dentry); mode = d_inode(fst_lo_d)->i_mode; - if (S_ISREG(mode)) { + + if (hm_islnk(hmdfs_d(fst_lo_d)->file_type) && + hmdfs_d(fst_lo_d)->device_id == 0) { + inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + inode->i_op = &hmdfs_symlink_iops_merge; + inode->i_fop = &hmdfs_file_fops_merge; + set_nlink(inode, 1); + } else if (S_ISREG(mode)) { inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; inode->i_op = &hmdfs_file_iops_merge; inode->i_fop = &hmdfs_file_fops_merge; @@ -725,6 +737,7 @@ struct dentry *hmdfs_lookup_merge(struct inode *parent_inode, err = init_hmdfs_dentry_info_merge(sbi, child_dentry); if (unlikely(err)) goto out; + if (pii->inode_type == HMDFS_LAYER_ZERO) { hmdfs_dm(child_dentry)->dentry_type = HMDFS_LAYER_FIRST_MERGE; @@ -760,7 +773,7 @@ struct dentry *hmdfs_lookup_merge(struct inode *parent_inode, if ((err == -ENOENT) && create) err = 0; - + out: hmdfs_trace_merge(trace_hmdfs_lookup_merge_end, parent_inode, child_dentry, err); @@ -1385,6 +1398,48 @@ int hmdfs_rename_merge(struct inode *old_dir, struct dentry *old_dentry, return ret; } +static const char *hmdfs_get_link_merge(struct dentry *dentry, + struct inode *inode, + struct delayed_call *done) +{ + const char *link = NULL; + struct dentry *lower_dentry = NULL; + struct inode *lower_inode = NULL; + + if(!dentry) { + hmdfs_err("dentry MULL"); + link = ERR_PTR(-EINVAL); + goto link_out; + } + + lower_dentry = hmdfs_get_fst_lo_d(dentry); + if(!lower_dentry) { + WARN_ON(1); + link = ERR_PTR(-EINVAL); + goto out; + } + lower_inode = d_inode(lower_dentry); + if(!lower_inode->i_op || !lower_inode->i_op->get_link) { + hmdfs_err("lower inode hold no operations"); + link = ERR_PTR(-EINVAL); + goto out; + } + + link = lower_inode->i_op->get_link(lower_dentry, lower_inode, done); + if(IS_ERR_OR_NULL(link)) + goto out; + fsstack_copy_attr_atime(inode, lower_inode); +out: + dput(lower_dentry); +link_out: + return link; +} + +const struct inode_operations hmdfs_symlink_iops_merge = { + .get_link = hmdfs_get_link_merge, + .permission = hmdfs_permission, +}; + const struct inode_operations hmdfs_dir_iops_merge = { .lookup = hmdfs_lookup_merge, .mkdir = hmdfs_mkdir_merge, diff --git a/fs/hmdfs/inode_remote.c b/fs/hmdfs/inode_remote.c index 2670e3e81891..8ac934dbbdc6 100644 --- a/fs/hmdfs/inode_remote.c +++ b/fs/hmdfs/inode_remote.c @@ -375,12 +375,15 @@ struct inode *fill_inode_remote(struct super_block *sb, struct hmdfs_peer *con, inode->i_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IXOTH; else if (S_ISREG(mode)) inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + else if (S_ISLNK(mode)) + inode->i_mode = S_IFREG | S_IRWXU | S_IRWXG; else { + hmdfs_info("fill_inode_remote: ret=%d", -EIO); ret = -EIO; goto bad_inode; } - if (S_ISREG(mode)) { + if (S_ISREG(mode) || S_ISLNK(mode)) { inode->i_op = con->conn_operations->remote_file_iops; inode->i_fop = con->conn_operations->remote_file_fops; inode->i_size = res->i_size; @@ -446,7 +449,9 @@ static struct dentry *hmdfs_lookup_remote_dentry(struct inode *parent_inode, lookup_result = hmdfs_lookup_by_con(con, child_dentry, &qstr, flags, relative_path); if (lookup_result != NULL) { - if (in_share_dir(child_dentry)) + if (S_ISLNK(lookup_result->i_mode)) + gdi->file_type = HM_SYMLINK; + else if (in_share_dir(child_dentry)) gdi->file_type = HM_SHARE; inode = fill_inode_remote(sb, con, lookup_result, parent_inode); ret = d_splice_alias(inode, child_dentry); diff --git a/fs/hmdfs/stash.c b/fs/hmdfs/stash.c index 413720404cc7..1ac2580afffa 100644 --- a/fs/hmdfs/stash.c +++ b/fs/hmdfs/stash.c @@ -1261,7 +1261,7 @@ static int hmdfs_open_restore_dst_file(struct hmdfs_file_restore_ctx *ctx, goto out; /* Error comes from connection or server ? */ - dst = file_open_root(&ctx->dst_root_path, + dst = file_open_root(ctx->dst_root_path.dentry, ctx->dst_root_path.mnt, ctx->dst, O_LARGEFILE | rw_flag, 0); if (IS_ERR(dst)) { err = PTR_ERR(dst); @@ -2179,7 +2179,7 @@ hmdfs_need_rebuild_inode_stash_status(struct hmdfs_peer *conn, umode_t mode) { return hmdfs_is_stash_enabled(conn->sbi) && READ_ONCE(conn->need_rebuild_stash_list) && - S_ISREG(mode); + (S_ISREG(mode) || S_ISLNK(mode)); } void hmdfs_remote_init_stash_status(struct hmdfs_peer *conn, -- Gitee