diff --git a/fs/hmdfs/Makefile b/fs/hmdfs/Makefile index 48a64acc8331c364a73711ea0041ae05af017602..20896e71636a0d95dca219e44e41e15589e94309 100644 --- a/fs/hmdfs/Makefile +++ b/fs/hmdfs/Makefile @@ -5,6 +5,7 @@ hmdfs-y := main.o super.o inode.o dentry.o inode_root.o file_merge.o hmdfs-y += hmdfs_client.o hmdfs_server.o inode_local.o inode_remote.o hmdfs-y += inode_merge.o hmdfs_dentryfile.o file_root.o file_remote.o hmdfs-y += file_local.o client_writeback.o server_writeback.o stash.o +hmdfs-y += hmdfs_share.o hmdfs-y += comm/device_node.o comm/message_verify.o comm/node_cb.o hmdfs-y += comm/connection.o comm/socket_adapter.o comm/transport.o diff --git a/fs/hmdfs/file_local.c b/fs/hmdfs/file_local.c index 2b9c64a82bfa1a9adf611b9b42b055e038a8fa60..47f39e392ce8ac87e2e96f7f1128a2da22779e65 100644 --- a/fs/hmdfs/file_local.c +++ b/fs/hmdfs/file_local.c @@ -17,6 +17,7 @@ #include "hmdfs_dentryfile.h" #include "hmdfs_device_view.h" #include "hmdfs_merge_view.h" +#include "hmdfs_share.h" #include "hmdfs_trace.h" int hmdfs_file_open_local(struct inode *inode, struct file *file) @@ -274,185 +275,80 @@ static int hmdfs_dir_release_local(struct inode *inode, struct file *file) return 0; } -static inline bool hmdfs_is_dst_path(struct path *src, struct path *dst) -{ - return (src->dentry == dst->dentry) && (src->mnt == dst->mnt); -} - -bool hmdfs_is_share_file(struct file *file) -{ - struct file *cur_file = file; - struct hmdfs_dentry_info *gdi; - struct hmdfs_file_info *gfi; - - while (cur_file->f_inode->i_sb->s_magic == HMDFS_SUPER_MAGIC) { - gdi = hmdfs_d(cur_file->f_path.dentry); - gfi = hmdfs_f(cur_file); - if (hm_isshare(gdi->file_type)) - return true; - if (gfi->lower_file) - cur_file = gfi->lower_file; - else - break; - } - - return false; -} - -bool hmdfs_is_share_item_still_valid(struct hmdfs_share_item *item) -{ - if (kref_read(&item->ref) == 1 && time_after(jiffies, item->timeout)) - return false; - - return true; -} - -inline void release_share_item(struct hmdfs_share_item *item) -{ - kfree(item->relative_path.name); - fput(item->file); - kfree(item); -} - -void hmdfs_remove_share_item(struct kref *ref) -{ - struct hmdfs_share_item *item = - container_of(ref, struct hmdfs_share_item, ref); - - list_del(&item->list); - release_share_item(item); -} - -struct hmdfs_share_item *hmdfs_lookup_share_item(struct hmdfs_share_table *st, - struct qstr *cur_relative_path) -{ - struct hmdfs_share_item *item, *tmp; - - list_for_each_entry_safe(item, tmp, &st->item_list_head, list) { - if (hmdfs_is_share_item_still_valid(item)) { - if (qstr_eq(&item->relative_path, cur_relative_path)) - return item; - } else { - kref_put(&item->ref, hmdfs_remove_share_item); - st->item_cnt--; - } - } - - return NULL; -} - -inline void set_item_timeout(struct hmdfs_share_item *item) -{ - item->timeout = jiffies + HZ * HMDFS_SHARE_ITEM_TIMEOUT_S; -} - -static int hmdfs_insert_share_item(struct hmdfs_share_table *st, - struct qstr *relative_path, struct file *file, char *cid) -{ - struct hmdfs_share_item *new_item = NULL; - int ret = 0; - - if (st->item_cnt >= st->max_cnt) { - ret = -EMFILE; - goto out; - } - - new_item = kmalloc(sizeof(*new_item), GFP_KERNEL); - if (new_item) { - new_item->file = file; - get_file(file); - new_item->relative_path = *relative_path; - memcpy(new_item->cid, cid, HMDFS_CID_SIZE); - kref_init(&new_item->ref); - list_add_tail(&new_item->list, &st->item_list_head); - set_item_timeout(new_item); - st->item_cnt++; - } else { - ret = -ENOMEM; - } - -out: - return ret; -} - -static int hmdfs_update_share_item(struct hmdfs_share_item *item, - struct file *file, char *cid) -{ - /* if not the same file, we need to update struct file */ - if (!hmdfs_is_dst_path(&file->f_path, &item->file->f_path)) { - fput(item->file); - item->file = file; - get_file(file); - } - memcpy(item->cid, cid, HMDFS_CID_SIZE); - set_item_timeout(item); - - return 0; -} +const struct file_operations hmdfs_dir_ops_local = { + .owner = THIS_MODULE, + .iterate = hmdfs_iterate_local, + .open = hmdfs_dir_open_local, + .release = hmdfs_dir_release_local, + .fsync = hmdfs_fsync_local, +}; -static int hmdfs_add_to_share_table(struct file *file, - struct hmdfs_sb_info *sbi, struct hmdfs_share_control *sc) +static int __hmdfs_ioc_set_share_path(struct file *file, + struct hmdfs_share_control *sc) { - struct fd src = fdget(sc->src_fd); + struct super_block *sb = file->f_inode->i_sb; + struct hmdfs_sb_info *sbi = hmdfs_sb(sb); struct hmdfs_share_table *st = &sbi->share_table; struct hmdfs_share_item *item; struct dentry *dentry; - const char *dir_path, *cur_path; + const char *dir_path, *full_path; struct qstr relative_path; + struct fd src; int err = 0; + src = fdget(sc->src_fd); if (!src.file) return -EBADF; + /* only reg file can be shared */ if (!S_ISREG(src.file->f_inode->i_mode)) { err = -EPERM; goto err_out; } + /* share file is not allowed to be shared */ if (hmdfs_is_share_file(src.file)) { err = -EPERM; goto err_out; } - dir_path = hmdfs_get_dentry_relative_path(file->f_path.dentry); - if (unlikely(!dir_path)) { - err = -ENOMEM; - goto err_out; - } - dentry = src.file->f_path.dentry; if (dentry->d_name.len > NAME_MAX) { - kfree(dir_path); err = -ENAMETOOLONG; goto err_out; } - cur_path = hmdfs_connect_path(dir_path, dentry->d_name.name); - if (unlikely(!cur_path)) { - kfree(dir_path); + dir_path = hmdfs_get_dentry_relative_path(file->f_path.dentry); + if (unlikely(!dir_path)) { err = -ENOMEM; goto err_out; } - relative_path.name = cur_path; - relative_path.len = strlen(cur_path); + + full_path = hmdfs_connect_path(dir_path, dentry->d_name.name); + if (unlikely(!full_path)) { + err = -ENOMEM; + goto free_dir; + } + relative_path.name = full_path; + relative_path.len = strlen(full_path); spin_lock(&sbi->share_table.item_list_lock); item = hmdfs_lookup_share_item(st, &relative_path); - if (!item) - err = hmdfs_insert_share_item(st, &relative_path, - src.file, sc->cid); - else { - if (kref_read(&item->ref) != 1) - err = -EEXIST; - else - hmdfs_update_share_item(item, src.file, sc->cid); + if (!item) { + err = insert_share_item(st, &relative_path, src.file, sc->cid); + goto unlock; } - spin_unlock(&sbi->share_table.item_list_lock); - if (err < 0) - kfree(cur_path); - kfree(dir_path); + if (item->opened) + err = -EEXIST; + else + update_share_item(item, src.file, sc->cid); +unlock: + spin_unlock(&sbi->share_table.item_list_lock); + kfree(full_path); +free_dir: + kfree(dir_path); err_out: fdput(src); return err; @@ -461,21 +357,16 @@ static int hmdfs_add_to_share_table(struct file *file, static int hmdfs_ioc_set_share_path(struct file *file, unsigned long arg) { struct hmdfs_share_control sc; - struct super_block *sb = file->f_inode->i_sb; - struct hmdfs_sb_info *sbi = hmdfs_sb(sb); - int error; if (copy_from_user(&sc, (struct hmdfs_share_control __user *)arg, - sizeof(sc))) + sizeof(sc))) return -EFAULT; - error = hmdfs_add_to_share_table(file, sbi, &sc); - - return error; + return __hmdfs_ioc_set_share_path(file, &sc); } static long hmdfs_dir_ioctl_local(struct file *file, unsigned int cmd, - unsigned long arg) + unsigned long arg) { switch (cmd) { case HMDFS_IOC_SET_SHARE_PATH: @@ -485,14 +376,6 @@ static long hmdfs_dir_ioctl_local(struct file *file, unsigned int cmd, } } -const struct file_operations hmdfs_dir_ops_local = { - .owner = THIS_MODULE, - .iterate = hmdfs_iterate_local, - .open = hmdfs_dir_open_local, - .release = hmdfs_dir_release_local, - .fsync = hmdfs_fsync_local, -}; - const struct file_operations hmdfs_dir_ops_share = { .owner = THIS_MODULE, .iterate = hmdfs_iterate_local, diff --git a/fs/hmdfs/hmdfs.h b/fs/hmdfs/hmdfs.h index 0c5cce32e30a665ddc94bd35dd9d9f0a1e490791..9157c55ba3927da555d2ddfa2d12f24de8f2ea40 100644 --- a/fs/hmdfs/hmdfs.h +++ b/fs/hmdfs/hmdfs.h @@ -55,13 +55,6 @@ #define HMDFS_READPAGES_NR_MAX 32 -#define HMDFS_SHARE_ITEM_TIMEOUT_S 60 -#define HMDFS_SHARE_ITEMS_MAX 4 - -#define HMDFS_IOC 0xf2 -#define HMDFS_IOC_SET_SHARE_PATH _IOW(HMDFS_IOC, 1, \ - struct hmdfs_share_control) - #define HMDFS_CID_SIZE 64 enum { @@ -98,18 +91,10 @@ struct hmdfs_syncfs_info { spinlock_t list_lock; }; -struct hmdfs_share_item { - struct file *file; - struct qstr relative_path; - char cid[HMDFS_CID_SIZE]; - unsigned long timeout; - struct kref ref; - struct list_head list; -}; - struct hmdfs_share_table { struct list_head item_list_head; spinlock_t item_list_lock; + struct workqueue_struct *share_item_timeout_wq; int item_cnt; int max_cnt; }; @@ -221,11 +206,6 @@ struct hmdfs_sb_info { unsigned int user_id; }; -struct hmdfs_share_control { - __u32 src_fd; - char cid[HMDFS_CID_SIZE]; -}; - static inline struct hmdfs_sb_info *hmdfs_sb(struct super_block *sb) { return sb->s_fs_info; @@ -326,19 +306,6 @@ static inline bool qstr_eq(const struct qstr *q1, const struct qstr *q2) return q1->len == q2->len && !strncmp(q1->name, q2->name, q2->len); } -bool hmdfs_is_share_file(struct file *file); - -bool hmdfs_is_share_item_still_valid(struct hmdfs_share_item *item); - -inline void release_share_item(struct hmdfs_share_item *item); - -void hmdfs_remove_share_item(struct kref *ref); - -struct hmdfs_share_item *hmdfs_lookup_share_item(struct hmdfs_share_table *st, - struct qstr *cur_relative_path); - -inline void set_item_timeout(struct hmdfs_share_item *item); - /***************************************************************************** * log print helpers *****************************************************************************/ diff --git a/fs/hmdfs/hmdfs_server.c b/fs/hmdfs/hmdfs_server.c index ccf8170b9b4dbaf73265dd10ff53f23e2d5dbcb5..dcb15c8b64466fa2c18ba4aa1b326beebaebf8eb 100644 --- a/fs/hmdfs/hmdfs_server.c +++ b/fs/hmdfs/hmdfs_server.c @@ -16,6 +16,7 @@ #include "authority/authentication.h" #include "hmdfs.h" #include "hmdfs_dentryfile.h" +#include "hmdfs_share.h" #include "hmdfs_trace.h" #include "server_writeback.h" #include "comm/node_cb.h" @@ -99,28 +100,6 @@ struct file *hmdfs_open_path(struct hmdfs_sb_info *sbi, const char *path) return file; } -inline bool is_dst_device(char *src_cid, char *dst_cid) -{ - return strncmp(src_cid, dst_cid, HMDFS_CID_SIZE) == 0 ? true : false; -} - -void hmdfs_clear_share_item_offline(struct hmdfs_peer *conn) -{ - struct hmdfs_sb_info *sbi = conn->sbi; - struct hmdfs_share_item *item, *tmp; - - spin_lock(&sbi->share_table.item_list_lock); - list_for_each_entry_safe(item, tmp, &sbi->share_table.item_list_head, - list) { - if (is_dst_device(item->cid, conn->cid)) { - list_del(&item->list); - release_share_item(item); - sbi->share_table.item_cnt--; - } - } - spin_unlock(&sbi->share_table.item_list_lock); -} - inline void hmdfs_close_path(struct file *file) { fput(file); @@ -246,30 +225,11 @@ static int check_sec_level(struct hmdfs_peer *node, const char *file_name) return ret; } -static int hmdfs_check_share_access_permission(struct hmdfs_sb_info *sbi, - const char *filename, char *cid, struct hmdfs_share_item **item) -{ - struct qstr candidate = QSTR_INIT(filename, strlen(filename)); - int ret = -ENOENT; - - spin_lock(&sbi->share_table.item_list_lock); - *item = hmdfs_lookup_share_item(&sbi->share_table, &candidate); - if (*item && is_dst_device((*item)->cid, cid)) { - spin_unlock(&sbi->share_table.item_list_lock); - return 0; - } else - *item = NULL; - spin_unlock(&sbi->share_table.item_list_lock); - - return ret; -} - static struct file *hmdfs_open_file(struct hmdfs_peer *con, const char *filename, uint8_t file_type, int *file_id) { struct file *file = NULL; - struct hmdfs_share_item *item = NULL; int err = 0; int id; @@ -285,27 +245,26 @@ static struct file *hmdfs_open_file(struct hmdfs_peer *con, if (hm_isshare(file_type)) { err = hmdfs_check_share_access_permission(con->sbi, - filename, con->cid, &item); + filename, con->cid); if (err) return ERR_PTR(err); } file = hmdfs_open_path(con->sbi, filename); - if (IS_ERR(file)) + if (IS_ERR(file)) { + reset_item_opened_status(con->sbi, filename); return file; + } id = insert_file_into_conn(con, file); if (id < 0) { hmdfs_err("file_id alloc failed! err=%d", id); + reset_item_opened_status(con->sbi, filename); hmdfs_close_path(file); return ERR_PTR(id); } *file_id = id; - /* get item to avoid timeout */ - if (item) - kref_get(&item->ref); - return file; } @@ -678,42 +637,6 @@ void hmdfs_server_atomic_open(struct hmdfs_peer *con, kfree(resp); } -void hmdfs_close_share_item(struct hmdfs_sb_info *sbi, struct file *file, - char *cid) -{ - struct qstr relativepath; - const char *path_name; - struct hmdfs_share_item *item = NULL; - - path_name = hmdfs_get_dentry_relative_path(file->f_path.dentry); - if (unlikely(!path_name)) { - hmdfs_err("get dentry relative path error"); - return; - } - - relativepath.name = path_name; - relativepath.len = strlen(path_name); - - item = hmdfs_lookup_share_item(&sbi->share_table, &relativepath); - - if (item) { - if (unlikely(!is_dst_device(item->cid, cid))) { - hmdfs_err("item not right"); - goto err_out; - } - - if (unlikely(kref_read(&item->ref) == 1)) - hmdfs_err("item ref error"); - - set_item_timeout(item); - kref_put(&item->ref, hmdfs_remove_share_item); - } else - hmdfs_err("cannot get share item %s", relativepath.name); - -err_out: - kfree(path_name); -} - void hmdfs_server_release(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, void *data) { diff --git a/fs/hmdfs/hmdfs_share.c b/fs/hmdfs/hmdfs_share.c new file mode 100644 index 0000000000000000000000000000000000000000..03f6c8898948ac8c46fe774b976173641ab74bb1 --- /dev/null +++ b/fs/hmdfs/hmdfs_share.c @@ -0,0 +1,318 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * fs/hmdfs/inode_share.h + * + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + */ + +#include "hmdfs_share.h" + +static inline bool hmdfs_is_dst_path(struct path *src, struct path *dst) +{ + return (src->dentry == dst->dentry) && (src->mnt == dst->mnt); +} + +static inline bool is_dst_device(char *src_cid, char *dst_cid) +{ + return strncmp(src_cid, dst_cid, HMDFS_CID_SIZE) == 0; +} + +bool hmdfs_is_share_file(struct file *file) +{ + struct file *cur_file = file; + struct hmdfs_dentry_info *gdi; + struct hmdfs_file_info *gfi; + + while (cur_file->f_inode->i_sb->s_magic == HMDFS_SUPER_MAGIC) { + gdi = hmdfs_d(cur_file->f_path.dentry); + gfi = hmdfs_f(cur_file); + if (hm_isshare(gdi->file_type)) + return true; + if (gfi->lower_file) + cur_file = gfi->lower_file; + else + break; + } + + return false; +} + +static void remove_and_release_share_item(struct hmdfs_share_item *item) +{ + list_del(&item->list); + item->hst->item_cnt--; + fput(item->file); + kfree(item->relative_path.name); + kfree(item); +} + +static inline bool is_share_item_timeout(struct hmdfs_share_item *item) +{ + return !item->opened && item->timeout; +} + +struct hmdfs_share_item *hmdfs_lookup_share_item(struct hmdfs_share_table *st, + struct qstr *cur_relative_path) +{ + struct hmdfs_share_item *item, *tmp; + + list_for_each_entry_safe(item, tmp, &st->item_list_head, list) { + if (is_share_item_timeout(item)){ + remove_and_release_share_item(item); + } else { + if (qstr_eq(&item->relative_path, cur_relative_path)) + return item; + } + } + + return NULL; +} + +static void share_item_timeout_work(struct work_struct *work) { + struct hmdfs_share_item *item = + container_of(work, struct hmdfs_share_item, d_work.work); + + item->timeout = true; +} + +int insert_share_item(struct hmdfs_share_table *st, struct qstr *relative_path, + struct file *file, char *cid) +{ + struct hmdfs_share_item *new_item = NULL; + char *path_name; + int err = 0; + + if (st->item_cnt >= st->max_cnt) { + err = -EMFILE; + goto err_out; + } + + path_name = kzalloc(PATH_MAX, GFP_KERNEL); + if (unlikely(!path_name)) { + err = -EMFILE; + goto err_out; + } + strcpy(path_name, relative_path->name); + + new_item = kmalloc(sizeof(*new_item), GFP_KERNEL); + if (unlikely(!new_item)) { + err = -ENOMEM; + kfree(path_name); + goto err_out; + } + + new_item->file = file; + get_file(file); + new_item->relative_path.name = path_name; + new_item->relative_path.len = relative_path->len; + memcpy(new_item->cid, cid, HMDFS_CID_SIZE); + new_item->opened = false; + new_item->timeout = false; + list_add_tail(&new_item->list, &st->item_list_head); + new_item->hst = st; + + INIT_DELAYED_WORK(&new_item->d_work, share_item_timeout_work); + queue_delayed_work(new_item->hst->share_item_timeout_wq, + &new_item->d_work, HZ * HMDFS_SHARE_ITEM_TIMEOUT_S); + + st->item_cnt++; + +err_out: + return err; +} + +void update_share_item(struct hmdfs_share_item *item, struct file *file, + char *cid) +{ + /* if not the same file, we need to update struct file */ + if (!hmdfs_is_dst_path(&file->f_path, &item->file->f_path)) { + fput(item->file); + get_file(file); + item->file = file; + } + memcpy(item->cid, cid, HMDFS_CID_SIZE); + + if (!cancel_delayed_work_sync(&item->d_work)) + item->timeout = false; + + queue_delayed_work(item->hst->share_item_timeout_wq, &item->d_work, + HZ * HMDFS_SHARE_ITEM_TIMEOUT_S); +} + +bool in_share_dir(struct dentry *child_dentry) +{ + struct dentry *parent_dentry = dget_parent(child_dentry); + bool ret = false; + + if (!strncmp(parent_dentry->d_name.name, SHARE_RESERVED_DIR, + strlen(SHARE_RESERVED_DIR))) + ret = true; + + dput(parent_dentry); + return ret; +} + +inline bool is_share_dir(struct inode *inode, const char *name) +{ + return (S_ISDIR(inode->i_mode) && + !strncmp(name, SHARE_RESERVED_DIR, strlen(SHARE_RESERVED_DIR))); +} + +int get_path_from_share_table(struct hmdfs_sb_info *sbi, + struct dentry *cur_dentry, + struct path *src_path) +{ + struct hmdfs_share_item *item; + const char *path_name; + struct qstr relative_path; + int err = 0; + + path_name = hmdfs_get_dentry_relative_path(cur_dentry); + if (unlikely(!path_name)) { + err = -ENOMEM; + goto err_out; + } + relative_path.name = path_name; + relative_path.len = strlen(path_name); + + spin_lock(&sbi->share_table.item_list_lock); + item = hmdfs_lookup_share_item(&sbi->share_table, &relative_path); + if (!item) { + err = -ENOENT; + goto unlock; + } + path_get(&item->file->f_path); + *src_path = item->file->f_path; +unlock: + spin_unlock(&sbi->share_table.item_list_lock); + kfree(path_name); +err_out: + return err; +} + +void hmdfs_clear_share_item_offline(struct hmdfs_peer *conn) +{ + struct hmdfs_sb_info *sbi = conn->sbi; + struct hmdfs_share_item *item, *tmp; + + spin_lock(&sbi->share_table.item_list_lock); + list_for_each_entry_safe(item, tmp, &sbi->share_table.item_list_head, + list) { + if (is_dst_device(item->cid, conn->cid)) { + /* release the item that was not closed properly */ + if (item->opened) + remove_and_release_share_item(item); + } + } + spin_unlock(&sbi->share_table.item_list_lock); +} + +void reset_item_opened_status(struct hmdfs_sb_info *sbi, const char *filename) +{ + struct qstr candidate = QSTR_INIT(filename, strlen(filename)); + struct hmdfs_share_item *item = NULL; + + spin_lock(&sbi->share_table.item_list_lock); + item = hmdfs_lookup_share_item(&sbi->share_table, &candidate); + if (item) { + item->opened = false; + queue_delayed_work(item->hst->share_item_timeout_wq, + &item->d_work, HZ * HMDFS_SHARE_ITEM_TIMEOUT_S); + } + spin_unlock(&sbi->share_table.item_list_lock); +} + +void hmdfs_close_share_item(struct hmdfs_sb_info *sbi, struct file *file, + char *cid) +{ + struct qstr relativepath; + const char *path_name; + struct hmdfs_share_item *item = NULL; + + path_name = hmdfs_get_dentry_relative_path(file->f_path.dentry); + if (unlikely(!path_name)) { + hmdfs_err("get dentry relative path error"); + return; + } + + relativepath.name = path_name; + relativepath.len = strlen(path_name); + + spin_lock(&sbi->share_table.item_list_lock); + item = hmdfs_lookup_share_item(&sbi->share_table, &relativepath); + if (unlikely(!item)) { + hmdfs_err("cannot get share item %s", relativepath.name); + goto unlock; + } + + if (unlikely(!is_dst_device(item->cid, cid))) { + hmdfs_err("item not right, dst cid is: %s", item->cid); + goto unlock; + } + + /* + * After remote close, we shoule reset the opened status and restart + * delayed timeout work. + */ + item->opened = false; + queue_delayed_work(item->hst->share_item_timeout_wq, &item->d_work, + HZ * HMDFS_SHARE_ITEM_TIMEOUT_S); + +unlock: + spin_unlock(&sbi->share_table.item_list_lock); + kfree(path_name); +} + +int hmdfs_check_share_access_permission(struct hmdfs_sb_info *sbi, + const char *filename, + char *cid) +{ + struct qstr candidate = QSTR_INIT(filename, strlen(filename)); + struct hmdfs_share_item *item = NULL; + int ret = -ENOENT; + + spin_lock(&sbi->share_table.item_list_lock); + item = hmdfs_lookup_share_item(&sbi->share_table, &candidate); + /* + * When cid matches, we set the item status opened and canel + * its delayed work to ensure that the open process can get + * the correct path + */ + if (item && is_dst_device(item->cid, cid)) { + item->opened = true; + if (!cancel_delayed_work_sync(&item->d_work)) { + item->timeout = false; + } + ret = 0; + } + spin_unlock(&sbi->share_table.item_list_lock); + + return ret; +} + + +void hmdfs_init_share_table(struct hmdfs_sb_info *sbi) +{ + spin_lock_init(&sbi->share_table.item_list_lock); + INIT_LIST_HEAD(&sbi->share_table.item_list_head); + sbi->share_table.item_cnt = 0; + sbi->share_table.max_cnt = HMDFS_SHARE_ITEMS_MAX; + sbi->share_table.share_item_timeout_wq = + create_singlethread_workqueue("share_item_timeout_wq"); +} + +void hmdfs_clear_share_table(struct hmdfs_sb_info *sbi) +{ + struct hmdfs_share_table *st = &sbi->share_table; + struct hmdfs_share_item *item, *tmp; + + spin_lock(&sbi->share_table.item_list_lock); + list_for_each_entry_safe(item, tmp, &sbi->share_table.item_list_head, + list) { + flush_delayed_work(&item->d_work); + remove_and_release_share_item(item); + } + spin_unlock(&sbi->share_table.item_list_lock); + + destroy_workqueue(st->share_item_timeout_wq); +} diff --git a/fs/hmdfs/hmdfs_share.h b/fs/hmdfs/hmdfs_share.h new file mode 100644 index 0000000000000000000000000000000000000000..c5d708d50bfc831e1c94b73d2a1f8bf7668ccf50 --- /dev/null +++ b/fs/hmdfs/hmdfs_share.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * fs/hmdfs/hmdfs_share.h + * + * Copyright (c) 2021-2022 Huawei Device Co., Ltd. + */ + +#ifndef HMDFS_SHARE_H +#define HMDFS_SHARE_H + +#include +#include +#include + +#include "hmdfs_device_view.h" +#include "comm/connection.h" + +#define HMDFS_SHARE_ITEM_TIMEOUT_S 60 +#define HMDFS_SHARE_ITEMS_MAX 4 + +#define HMDFS_IOC 0xf2 +#define HMDFS_IOC_SET_SHARE_PATH _IOW(HMDFS_IOC, 1, \ + struct hmdfs_share_control) + +#define SHARE_RESERVED_DIR ".share" + +struct hmdfs_share_control { + __u32 src_fd; + char cid[HMDFS_CID_SIZE]; +}; + +struct hmdfs_share_item { + struct file *file; + struct qstr relative_path; + char cid[HMDFS_CID_SIZE]; + bool opened; + bool timeout; + struct list_head list; + struct delayed_work d_work; + struct hmdfs_share_table *hst; +}; + +bool hmdfs_is_share_file(struct file *file); +struct hmdfs_share_item *hmdfs_lookup_share_item(struct hmdfs_share_table *st, + struct qstr *cur_relative_path); +int insert_share_item(struct hmdfs_share_table *st, struct qstr *relative_path, + struct file *file, char *cid); +void update_share_item(struct hmdfs_share_item *item, struct file *file, + char *cid); +bool in_share_dir(struct dentry *child_dentry); +inline bool is_share_dir(struct inode *inode, const char *name); +int get_path_from_share_table(struct hmdfs_sb_info *sbi, + struct dentry *cur_dentry, struct path *src_path); + +void hmdfs_clear_share_item_offline(struct hmdfs_peer *conn); +void reset_item_opened_status(struct hmdfs_sb_info *sbi, const char *filename); +void hmdfs_close_share_item(struct hmdfs_sb_info *sbi, struct file *file, + char *cid); +int hmdfs_check_share_access_permission(struct hmdfs_sb_info *sbi, + const char *filename, char *cid); + +void hmdfs_init_share_table(struct hmdfs_sb_info *sbi); +void hmdfs_clear_share_table(struct hmdfs_sb_info *sbi); + +#endif // HMDFS_SHARE_H diff --git a/fs/hmdfs/inode_local.c b/fs/hmdfs/inode_local.c index 04388c808c970dce864afebfec7c386871ef20c7..2470c5f81aec8615ae69e97a982aa6faa5f93b37 100644 --- a/fs/hmdfs/inode_local.c +++ b/fs/hmdfs/inode_local.c @@ -18,6 +18,7 @@ #include "hmdfs_client.h" #include "hmdfs_dentryfile.h" #include "hmdfs_device_view.h" +#include "hmdfs_share.h" #include "hmdfs_trace.h" extern struct kmem_cache *hmdfs_dentry_cachep; @@ -61,13 +62,10 @@ static inline void set_sharefile_flag(struct hmdfs_dentry_info *gdi) gdi->file_type = HM_SHARE; } -static inline void check_and_fixup_share_ops(struct inode *inode, +static void check_and_fixup_share_ops(struct inode *inode, const char *name) { - const char *share_dir = ".share"; - - if (S_ISDIR(inode->i_mode) && - !strncmp(name, share_dir, strlen(share_dir))) { + if (is_share_dir(inode, name)) { inode->i_op = &hmdfs_dir_inode_ops_share; inode->i_fop = &hmdfs_dir_ops_share; } @@ -800,39 +798,6 @@ static ssize_t hmdfs_local_listxattr(struct dentry *dentry, char *list, return res; } - -int hmdfs_get_path_from_share_table(struct hmdfs_sb_info *sbi, - struct dentry *cur_dentry, struct path *src_path) -{ - struct hmdfs_share_item *item; - const char *path_name; - struct qstr relative_path; - int err = 0; - - path_name = hmdfs_get_dentry_relative_path(cur_dentry); - if (unlikely(!path_name)) { - err = -ENOMEM; - goto err_out; - } - relative_path.name = path_name; - relative_path.len = strlen(path_name); - - spin_lock(&sbi->share_table.item_list_lock); - item = hmdfs_lookup_share_item(&sbi->share_table, &relative_path); - if (!item) { - spin_unlock(&sbi->share_table.item_list_lock); - err = -ENOENT; - goto err_out; - } - *src_path = item->file->f_path; - path_get(src_path); - - kfree(path_name); - spin_unlock(&sbi->share_table.item_list_lock); -err_out: - return err; -} - struct dentry *hmdfs_lookup_share(struct inode *parent_inode, struct dentry *child_dentry, unsigned int flags) { @@ -855,7 +820,7 @@ struct dentry *hmdfs_lookup_share(struct inode *parent_inode, goto err_out; } - err = hmdfs_get_path_from_share_table(sbi, child_dentry, &src_path); + err = get_path_from_share_table(sbi, child_dentry, &src_path); if (err) { ret = ERR_PTR(err); goto err_out; @@ -883,8 +848,6 @@ struct dentry *hmdfs_lookup_share(struct inode *parent_inode, check_and_fixup_ownership(parent_inode, child_inode); err_out: - if (!err) - hmdfs_set_time(child_dentry, jiffies); trace_hmdfs_lookup_share_end(parent_inode, child_dentry, err); return ret; } diff --git a/fs/hmdfs/inode_remote.c b/fs/hmdfs/inode_remote.c index 0a4493455e0f913673a364ea29d3bc73267131fb..73d459bf45337dd24577acf9e0195228717b51e8 100644 --- a/fs/hmdfs/inode_remote.c +++ b/fs/hmdfs/inode_remote.c @@ -14,6 +14,7 @@ #include "hmdfs.h" #include "hmdfs_client.h" #include "hmdfs_dentryfile.h" +#include "hmdfs_share.h" #include "hmdfs_trace.h" #include "authority/authentication.h" #include "stash.h" @@ -402,19 +403,6 @@ struct inode *fill_inode_remote(struct super_block *sb, struct hmdfs_peer *con, return ERR_PTR(ret); } -static bool in_share_dir(struct dentry *child_dentry) -{ - struct dentry *parent_dentry = dget_parent(child_dentry); - bool ret = false; - const char *share_dir = ".share"; - - if (!strncmp(parent_dentry->d_name.name, share_dir, strlen(share_dir))) - ret = true; - - dput(parent_dentry); - return ret; -} - static struct dentry *hmdfs_lookup_remote_dentry(struct inode *parent_inode, struct dentry *child_dentry, int flags) diff --git a/fs/hmdfs/main.c b/fs/hmdfs/main.c index f692cfa8974787891ed4d3521764a717522b008b..d0a41061bb2f343317232f54e8a4d8255c1e5673 100644 --- a/fs/hmdfs/main.c +++ b/fs/hmdfs/main.c @@ -27,6 +27,7 @@ #include "comm/socket_adapter.h" #include "hmdfs_merge_view.h" #include "server_writeback.h" +#include "hmdfs_share.h" #include "comm/node_cb.h" #include "stash.h" @@ -241,6 +242,7 @@ void hmdfs_put_super(struct super_block *sb) hmdfs_cfn_destroy(sbi); hmdfs_unregister_sysfs(sbi); hmdfs_connections_stop(sbi); + hmdfs_clear_share_table(sbi); hmdfs_destroy_server_writeback(sbi); hmdfs_exit_stash(sbi); atomic_dec(&lower_sb->s_active); @@ -660,14 +662,6 @@ static void hmdfs_init_cmd_timeout(struct hmdfs_sb_info *sbi) set_cmd_timeout(sbi, F_LISTXATTR, TIMEOUT_COMMON); } -static void init_share_table(struct hmdfs_sb_info *sbi) -{ - spin_lock_init(&sbi->share_table.item_list_lock); - INIT_LIST_HEAD(&sbi->share_table.item_list_head); - sbi->share_table.item_cnt = 0; - sbi->share_table.max_cnt = HMDFS_SHARE_ITEMS_MAX; -} - static int hmdfs_init_sbi(struct hmdfs_sb_info *sbi) { int ret; @@ -718,7 +712,7 @@ static int hmdfs_init_sbi(struct hmdfs_sb_info *sbi) mutex_init(&sbi->connections.node_lock); INIT_LIST_HEAD(&sbi->connections.node_list); - init_share_table(sbi); + hmdfs_init_share_table(sbi); init_waitqueue_head(&sbi->async_readdir_wq); INIT_LIST_HEAD(&sbi->async_readdir_msg_list); INIT_LIST_HEAD(&sbi->async_readdir_work_list);