From 56a1ea1637eba0b7166bc2974d4f1e99291bbe09 Mon Sep 17 00:00:00 2001 From: liqiang Date: Wed, 3 Jan 2024 16:08:51 +0800 Subject: [PATCH] optimized qtfs options data and logic of get link Signed-off-by: liqiang --- qtfs/include/symbol_wrapper.h | 2 + qtfs/qtfs/ops.h | 1 - qtfs/qtfs/proc.c | 7 - qtfs/qtfs/qtfs-mod.c | 2 + qtfs/qtfs/qtfs-mod.h | 3 + qtfs/qtfs/sb.c | 284 +++++++++++++++++++++++------- qtfs/qtfs/syscall.c | 48 ++++- qtfs/qtfs_common/symbol_wrapper.c | 3 + qtfs/rexec/rexec.h | 2 - 9 files changed, 280 insertions(+), 72 deletions(-) diff --git a/qtfs/include/symbol_wrapper.h b/qtfs/include/symbol_wrapper.h index f6ea28c..44927e5 100644 --- a/qtfs/include/symbol_wrapper.h +++ b/qtfs/include/symbol_wrapper.h @@ -26,6 +26,8 @@ struct qtfs_kallsyms { int (*__close_fd)(struct files_struct *, int); #endif struct task_struct *(*find_get_task_by_vpid)(pid_t nr); + long (*do_mount)(const char *, const char __user *, + const char *, unsigned long, void *); }; extern struct qtfs_kallsyms qtfs_kern_syms; diff --git a/qtfs/qtfs/ops.h b/qtfs/qtfs/ops.h index 7493d3d..d42b523 100644 --- a/qtfs/qtfs/ops.h +++ b/qtfs/qtfs/ops.h @@ -24,7 +24,6 @@ extern struct file_operations qtfs_proc_file_ops; extern struct inode_operations qtfs_proc_sym_ops; extern struct file_operations qtfsfifo_ops; -enum qtfs_type qtfs_get_type(char *str); bool is_sb_proc(struct super_block *sb); struct inode *qtfs_iget(struct super_block *sb, struct inode_info *ii); diff --git a/qtfs/qtfs/proc.c b/qtfs/qtfs/proc.c index deea1c8..863fcc2 100644 --- a/qtfs/qtfs/proc.c +++ b/qtfs/qtfs/proc.c @@ -34,13 +34,6 @@ int qtfs_proc_getattr(struct user_namespace *mnt_userns, const struct path *path int qtfs_proc_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsigned int flags); #endif -enum qtfs_type qtfs_get_type(char *str) -{ - if (str && !strcmp(str, "proc")) - return QTFS_PROC; - return QTFS_NORMAL; -} - bool is_sb_proc(struct super_block *sb) { struct qtfs_fs_info *qfi = NULL; diff --git a/qtfs/qtfs/qtfs-mod.c b/qtfs/qtfs/qtfs-mod.c index d49e9a2..0ce43fb 100644 --- a/qtfs/qtfs/qtfs-mod.c +++ b/qtfs/qtfs/qtfs-mod.c @@ -266,6 +266,7 @@ static int __init qtfs_init(void) if (ret) { goto utils_register_err; } + qtfs_sb_init(); qtfs_info("QTFS file system register success!\n"); return 0; utils_register_err: @@ -317,6 +318,7 @@ static void __exit qtfs_exit(void) qtfs_utils_destroy(); kmem_cache_destroy(qtfs_inode_priv_cache); qtfs_syscall_replace_stop(); + qtfs_sb_fini(); qtfs_info("QTFS file system unregister success!\n"); return; } diff --git a/qtfs/qtfs/qtfs-mod.h b/qtfs/qtfs/qtfs-mod.h index 21d2f2d..d767adb 100644 --- a/qtfs/qtfs/qtfs-mod.h +++ b/qtfs/qtfs/qtfs-mod.h @@ -81,6 +81,7 @@ struct qtfs_inode { }; struct qtfs_fs_info { + struct list_head list; char peer_path[NAME_MAX]; char *mnt_path; @@ -193,6 +194,8 @@ void qtfs_utils_destroy(void); void qtfs_whitelist_clearall(void); void qtfs_whitelist_initset(void); __poll_t qtfs_poll(struct file *filp, poll_table *wait); +void qtfs_sb_init(void); +void qtfs_sb_fini(void); #endif diff --git a/qtfs/qtfs/sb.c b/qtfs/qtfs/sb.c index 77ff15b..5f00b08 100644 --- a/qtfs/qtfs/sb.c +++ b/qtfs/qtfs/sb.c @@ -33,6 +33,9 @@ #define CURRENT_TIME(inode) (current_time(inode)) static struct inode_operations qtfs_inode_ops; static struct inode_operations qtfs_symlink_inode_ops; +// 串联所有qtfs的super block中的priv信息 +static struct list_head qtfs_sb_priv_list; + struct inode *qtfs_iget(struct super_block *sb, struct inode_info *ii); extern ssize_t qtfs_xattr_list(struct dentry *dentry, char *buffer, size_t buffer_size); static void qtfs_copy_kstat_inode(struct inode *inode, struct kstat *stat) @@ -46,6 +49,17 @@ static void qtfs_copy_kstat_inode(struct inode *inode, struct kstat *stat) inode->i_ctime = stat->ctime; } +void qtfs_sb_init(void) +{ + INIT_LIST_HEAD(&qtfs_sb_priv_list); + return; +} + +void qtfs_sb_fini(void) +{ + return; +} + int qtfs_statfs(struct dentry *dentry, struct kstatfs *buf) { struct qtfs_conn_var_s *pvar = qtfs_conn_get_param(); @@ -98,52 +112,6 @@ static inline struct qtfs_fs_info *qtfs_priv_byinode(struct inode *inode) return sb->s_fs_info; } -static inline char *qtfs_mountpoint_path_init(struct dentry *dentry, struct path *path, char *mnt_file) -{ - char *name = NULL; - char *ret; - char *mnt_point; - size_t len; - struct qtfs_fs_info *fsinfo = qtfs_priv_byinode(d_inode(dentry)); - if (fsinfo && fsinfo->mnt_path) { - return fsinfo->mnt_path; - } - name = __getname(); - if (!name) { - return ERR_PTR(-ENOMEM); - } - path_get(path); - ret = qtfs_kern_syms.d_absolute_path(path, name, MAX_PATH_LEN); - qtfs_debug("mntfile:%s absolute:%s", mnt_file, ret); - if (IS_ERR_OR_NULL(ret)) { - qtfs_err("d_absolute_path failed:%ld", QTFS_PTR_ERR(ret)); - } else { - if (strcmp(ret, mnt_file) != 0 && strcmp(mnt_file, "/")) { - mnt_point = strstr(ret, mnt_file); - qtfs_info("mnt point:%s", mnt_point); - if (mnt_point) { - *mnt_point = '\0'; - } else { - qtfs_err("Failed to get mount root path"); - } - } - len = strlen(ret); - if (len == 0) { - qtfs_err("mount path len invalid."); - goto end; - } - fsinfo->mnt_path = (char *)kmalloc(len + 1, GFP_KERNEL); - if (fsinfo->mnt_path) { - strlcpy(fsinfo->mnt_path, ret, len + 1); - } - qtfs_debug("d_absolute_path get mnt path:%s", fsinfo->mnt_path); - } -end: - path_put(path); - __putname(name); - return fsinfo->mnt_path; -} - struct getdents_callback64 { struct dir_context ctx; struct linux_dirent64 __user * current_dir; @@ -1315,7 +1283,6 @@ int qtfs_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsi struct qtfs_conn_var_s *pvar = qtfs_conn_get_param(); struct qtreq_getattr *req; struct qtrsp_getattr *rsp; - char *mnt_path = NULL; struct inode *inode = path->dentry->d_inode; int ret; @@ -1328,11 +1295,6 @@ int qtfs_getattr(const struct path *path, struct kstat *stat, u32 req_mask, unsi QTFS_FULLNAME(req->path, path->dentry, sizeof(req->path)); req->request_mask = req_mask; req->query_flags = flags; - mnt_path = qtfs_mountpoint_path_init(path->dentry, (struct path*)path, req->path); - if (IS_ERR(mnt_path)) { - qtfs_conn_put_param(pvar); - return PTR_ERR(mnt_path); - } rsp = qtfs_remote_run(pvar, QTFS_REQ_GETATTR, QTFS_SEND_SIZE(struct qtreq_getattr, req->path)); if (IS_ERR_OR_NULL(rsp)) { qtfs_conn_put_param(pvar); @@ -1411,6 +1373,115 @@ int qtfs_setattr(struct dentry *dentry, struct iattr *attr) qtfs_conn_put_param(pvar); return 0; } + +static const char *qtfs_link_inv_prefix = "[Invalid link:qtfs not mount]"; +static inline void qtfs_invalid_link(char *link) +{ + strcpy(link, qtfs_link_inv_prefix); +} + +/* + *link: 空buf,带出最终在本地算完的link + *local_path: 本端link文件路径 + *peer_link: 从server得到的link文件在对端的link指向 +*/ +__attribute__((unused)) static char *qtfs_peer_link_exchange(struct delayed_call *done, struct dentry *dentry, char *local_path, char *peer_link) +{ + // 两种情况: + // link是绝对路径,需要查询本地这个绝对路径有没有被挂载成 + // qtfs,如果没有,则显示一个无效字符串[QTFS NOT MOUNT]加 + // server侧的link字符串提示用户挂载该目录才能访问 + // + // link是相对路径,需要根据文件目录找到在本地的相对路径目 + // 录并且查看它是否被挂载为QTFS,如果没有挂载则同上显示。 + // + // 以上两种情况,如果链接目录已被挂载,则正常显示 + /* 绝对路径 */ + struct list_head *entry; + struct path path; + int ret; + char *link; + struct qtfs_fs_info *fsinfo; + char *name = kmalloc(PATH_MAX, GFP_KERNEL); + if (!name) { + qtfs_err("get name failed."); + return ERR_PTR(-ENOMEM); + } + memset(name, 0, PATH_MAX); + if (peer_link[0] == '.') { + if (strnlen(local_path, PATH_MAX) + strnlen(peer_link, PATH_MAX) >= PATH_MAX) { + qtfs_err("local path and peer link len too long"); + kfree(name); + return ERR_PTR(-EFAULT); + } + strncat(name, local_path, strlen(local_path) - strlen(dentry->d_name.name)); + strcat(name, peer_link); + } else if (peer_link[0] == '/') { + list_for_each(entry, &qtfs_sb_priv_list) { + fsinfo = (struct qtfs_fs_info *)entry; + if (fsinfo->mnt_path == NULL) { + qtfs_err("mount sb peer path:%s mnt path is NULL.", fsinfo->peer_path); + continue; + } + if (memcmp(fsinfo->peer_path, peer_link, strlen(fsinfo->peer_path)) == 0) { + // finded the valid qtfs mount path of this link + strcat(name, fsinfo->mnt_path); + // 多一个/不多,少一个/有问题,后面都会转成标准路径 + strcat(name, "/"); + strcat(name, &peer_link[strlen(fsinfo->peer_path)]); + goto local_abs; + } + } + // 没有发现匹配的peer_path,则绝对路径无效 + qtfs_invalid_link(name); + strcat(name, peer_link); + set_delayed_call(done, kfree_link, name); + qtfs_info("get link local abs:%s peer:%s local origin:%s", name, peer_link, local_path); + return name; + } else { + strcpy(name, peer_link); + set_delayed_call(done, kfree_link, name); + qtfs_info("get link local abs:%s peer:%s local origin:%s", name, peer_link, local_path); + return name; + } + +local_abs: + qtfs_info("get link local abs:%s peer:%s local origin:%s", name, peer_link, local_path); + // 获得了local绝对路径name + ret = kern_path(name, 0, &path); + if (ret) { + qtfs_err("open path:%s failed", name); + goto invalid_link; + } + link = qtfs_kern_syms.d_absolute_path(&path, name, PATH_MAX); + if (IS_ERR_OR_NULL(link)) { + qtfs_err("get absolute path failed, name:%s", name); + path_put(&path); + goto invalid_link; + } + ret = strlen(link); + if (path.mnt && path.mnt->mnt_sb && + path.mnt->mnt_sb->s_type && path.mnt->mnt_sb->s_type->name && + strcmp(path.mnt->mnt_sb->s_type->name, QTFS_FSTYPE_NAME) == 0) { + // link in qtfs is valid + path_put(&path); + memmove(name, link, strlen(link)); + name[ret] = 0; + set_delayed_call(done, kfree_link, name); + return name; + } + qtfs_err("get link:%s not in qtfs", link); + + path_put(&path); +invalid_link: + // not in qtfs + qtfs_invalid_link(name); + strncpy(&name[strlen(qtfs_link_inv_prefix)], peer_link, PATH_MAX - strlen(qtfs_link_inv_prefix)); + name[strlen(qtfs_link_inv_prefix) + strlen(peer_link)] = 0; + set_delayed_call(done, kfree_link, name); + return name; +} + const char *qtfs_getlink(struct dentry *dentry, struct inode *inode, struct delayed_call *done) { @@ -1453,23 +1524,23 @@ const char *qtfs_getlink(struct dentry *dentry, qtfs_conn_put_param(pvar); return ERR_PTR(-ENOENT); } - len = strlen(rsp->path) + 1; + len = strlen(qtfs_link_inv_prefix) + strlen(rsp->path) + 1; if (len > MAX_PATH_LEN || len == 0) { qtfs_err("qtfs getlink failed. path name too long:%s - %s\n", fsinfo->mnt_path, rsp->path); qtfs_conn_put_param(pvar); return ERR_PTR(-EINVAL); } - link = kmalloc(len, GFP_KERNEL); + //link = qtfs_peer_link_exchange(done, dentry, req->path, rsp->path); + // 暂不做任何处理,如果local挂载目录和远端目录不一致则软链接访问有可能有问题 + link = kstrndup(rsp->path, MAX_PATH_LEN, GFP_KERNEL); if (!link) { + qtfs_err("get link:%s and failed to create local memory.", rsp->path); qtfs_conn_put_param(pvar); return ERR_PTR(-ENOMEM); } - memset(link, 0, len); - strcat(link, rsp->path); - qtfs_info("get link success <%s>\n", link); - - set_delayed_call(done, kfree_link, link); + qtfs_info("get link exchange peer:%s to local <%s>\n", req->path, link); qtfs_conn_put_param(pvar); + set_delayed_call(done, kfree_link, link); return link; } @@ -1647,6 +1718,8 @@ static int qtfs_fill_super(struct super_block *sb, void *priv_data, int silent) if (err) { qtfs_err("qtfs fill super bdi setup err:%d.\n", err); } + INIT_LIST_HEAD(&priv->list); + list_add(&priv->list, &qtfs_sb_priv_list); sb->s_fs_info = priv; sb->s_op = &qtfs_ops; sb->s_time_gran = 1; @@ -1656,6 +1729,91 @@ static int qtfs_fill_super(struct super_block *sb, void *priv_data, int silent) return 0; } +/* + qtfs -o data内容格式: + "mntpoint,proc,key:value" + "/mount/point/path,proc,qtfs_server_ip:x.x.x.x,qtfs_server_port:xxxx" + + qtfs_get_data_options使用方法: + input: + data: data + key: prefix key in options + return: + memdup string of key:value + os: The caller need to release memory +*/ +#define MAX_KEY_LEN 32 +static char *qtfs_get_data_options(void *data_orig, char *key) +{ + unsigned long keylen = 0; + char *finded = NULL; + char *next_deli = NULL; + // ignore mount point path + char *data = strchr((const char *)data_orig, ','); + if (data == NULL || key == NULL) { + return NULL; + } + while (finded == NULL && data != NULL) { + if (data[0] == ',') + data++; + // key no match + if (data[0] == '\0') + return NULL; + // cur options not match + if (strncmp(key, data, strlen(key)) != 0) { + data = strchr(data, ','); + continue; + } + // key matched + next_deli = strchr(data, ','); + if (next_deli == NULL) { + keylen = strlen(data); + } else { + keylen = (unsigned long)(next_deli - data); + } + finded = kmemdup_nul(data, keylen, GFP_KERNEL); + if (finded == NULL) { + qtfs_err("get option key:%s memdup failed.", key); + } + break; + } + return finded; +} + +static int qtfs_get_mnt_path(struct qtfs_fs_info *priv, void *data) +{ + unsigned long mntlen; + char *delimiter; + char *qtfs_data = (char *)data; + if (priv == NULL || qtfs_data == NULL) { + qtfs_err("priv:%lx or data:%lx is invalid!", (unsigned long)priv, (unsigned long)data); + return -1; + } + delimiter = strchr(qtfs_data, ','); + if (delimiter == NULL) { + priv->mnt_path = kstrndup(qtfs_data, MAX_PATH_LEN, GFP_KERNEL); + if (!priv->mnt_path) + return -1; + return 0; + } + mntlen = (unsigned long)(delimiter - qtfs_data); + priv->mnt_path = kmemdup_nul(data, mntlen, GFP_KERNEL); + if (!priv->mnt_path) + return -1; + return 0; +} + +enum qtfs_type qtfs_get_type(void *data) +{ + char *proctype = qtfs_get_data_options(data, "proc"); + if (proctype && !strcmp(proctype, "proc")) { + kfree(proctype); + return QTFS_PROC; + } + kfree(proctype); + return QTFS_NORMAL; +} + struct dentry *qtfs_fs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { @@ -1688,9 +1846,12 @@ struct dentry *qtfs_fs_mount(struct file_system_type *fs_type, } memset(priv, 0, sizeof(struct qtfs_fs_info)); - priv->type = qtfs_get_type((char *)data); + priv->type = qtfs_get_type(data); strlcpy(priv->peer_path, dev_name, NAME_MAX); - priv->mnt_path = NULL; + if (qtfs_get_mnt_path(priv, data) != 0) { + qtfs_err("get qtfs mnt path failed, dev name:%s, data:%s", dev_name, (char *)data); + return ERR_PTR(-EFAULT); + } ret = mount_nodev(fs_type, flags, (void *)priv, qtfs_fill_super); if (IS_ERR_OR_NULL(ret)) { @@ -1706,6 +1867,7 @@ struct dentry *qtfs_fs_mount(struct file_system_type *fs_type, void qtfs_kill_sb(struct super_block *sb) { struct qtfs_fs_info *fsinfo = sb->s_fs_info; + list_del(&fsinfo->list); if (fsinfo->mnt_path) { kfree(fsinfo->mnt_path); fsinfo->mnt_path = NULL; diff --git a/qtfs/qtfs/syscall.c b/qtfs/qtfs/syscall.c index e4ee26e..aab2b62 100644 --- a/qtfs/qtfs/syscall.c +++ b/qtfs/qtfs/syscall.c @@ -39,6 +39,35 @@ static char *qtfs_copy_mount_string(const void __user *data) return data ? strndup_user(data, PATH_MAX) : NULL; } +static void *qtfs_copy_dir_and_data(const void __user *dir, const void __user *data) +{ + void *data_ret; + char *dir_data; + long dir_len; + long data_len; + int ret; + dir_len = strnlen_user(dir, MAX_PATH_LEN); + if (!dir_len) + return ERR_PTR(-EFAULT); + data_len = strnlen_user(data, MAX_PATH_LEN - dir_len - 1); + data_ret = memdup_user(dir, data_len + dir_len); + if (IS_ERR_OR_NULL(data_ret)) { + return ERR_PTR(-ENOMEM); + } + dir_data = (char *)data_ret; + if (data_len == 0) + return data_ret; + // first data unit is qtfs dir name, strcat data behind dir name + dir_data[dir_len - 1] = ','; + ret = copy_from_user(&dir_data[dir_len], data, data_len); + if (ret) { + kfree(data_ret); + return ERR_PTR(-ENOMEM); + } + dir_data[dir_len + data_len] = '\0'; + return data_ret; +} + static inline int qtfs_fstype_judgment(char __user *dir) { struct path path; @@ -188,6 +217,7 @@ __SYSCALL_DEFINEx(5, _qtfs_mount, char __user *, dev_name, char __user *, dir_na char *kernel_type; char *kernel_dev; void *options = NULL; + void *qtfs_data; // if both dev_name and dir_name are qtfs, it is a remote mount operator. kernel_type = qtfs_copy_mount_string(type); @@ -205,7 +235,20 @@ __SYSCALL_DEFINEx(5, _qtfs_mount, char __user *, dev_name, char __user *, dir_na if (IS_ERR(options)) goto out_data; - // if both dev_name and dir_name are qtfs, it is a remote mount operator, + // for qtfs mount path, give it to fs in *data + if (kernel_type != NULL && strncmp(kernel_type, QTFS_FSTYPE_NAME, strlen(QTFS_FSTYPE_NAME)) == 0) { + qtfs_data = qtfs_copy_dir_and_data(dir_name, data); + if (IS_ERR(qtfs_data)) { + qtfs_err("failed to get dir and data for qtfs:%ld", PTR_ERR(qtfs_data)); + ret = PTR_ERR(qtfs_data); + goto qtfs_mount; + } + ret = qtfs_kern_syms.do_mount(kernel_dev, dir_name, kernel_type, flags, qtfs_data); + kfree(qtfs_data); + goto qtfs_mount; + } + + // if dir_name is qtfs, it is a remote mount if (qtfs_fstype_judgment(dir_name) == 1) { ret = qtfs_remote_mount(kernel_dev, dir_name, kernel_type, flags, options); goto remote_mount; @@ -213,10 +256,13 @@ __SYSCALL_DEFINEx(5, _qtfs_mount, char __user *, dev_name, char __user *, dir_na ret = qtfs_syscall_mount(dev_name, dir_name, type, flags, data); +qtfs_mount: + remote_mount: kfree(options); out_data: kfree(kernel_dev); + out_dev: kfree(kernel_type); out_type: diff --git a/qtfs/qtfs_common/symbol_wrapper.c b/qtfs/qtfs_common/symbol_wrapper.c index c7b7122..143bee2 100644 --- a/qtfs/qtfs_common/symbol_wrapper.c +++ b/qtfs/qtfs_common/symbol_wrapper.c @@ -121,6 +121,9 @@ int qtfs_kallsyms_hack_init(void) KSYMS_NULL_RETURN(qtfs_kern_syms.d_absolute_path); KSYMS(find_get_task_by_vpid, struct task_struct *(*)(pid_t nr)); KSYMS_NULL_RETURN(qtfs_kern_syms.find_get_task_by_vpid); + KSYMS(do_mount, long (*)(const char *, const char __user *, + const char *, unsigned long, void *)); + KSYMS_NULL_RETURN(qtfs_kern_syms.do_mount); #if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 11, 0)) KSYMS(__close_fd, int (*)(struct files_struct *, int)); diff --git a/qtfs/rexec/rexec.h b/qtfs/rexec/rexec.h index acd6cca..7ab23a4 100644 --- a/qtfs/rexec/rexec.h +++ b/qtfs/rexec/rexec.h @@ -78,8 +78,6 @@ static inline void rexec_log_init() } else if (strcmp(logfile, "std") == 0) { rexec_logfile = stderr; return; - } else { - printf("REXEC_LOG_FILE cannot be set to any value other than std\n"); } retry: rexec_logfile = fopen(logfile, "a"); -- Gitee