diff --git a/fs/hmdfs/file_local.c b/fs/hmdfs/file_local.c index 893c6edbc93b40002add2edfcb136afc1cbce61e..bef62b2c04f3da1379662d94edf3f33bf525838b 100644 --- a/fs/hmdfs/file_local.c +++ b/fs/hmdfs/file_local.c @@ -237,6 +237,217 @@ 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; +} + +static int hmdfs_add_to_share_table(struct file *file, + struct hmdfs_sb_info *sbi, struct hmdfs_share_control *sc) +{ + struct fd src = fdget(sc->src_fd); + struct hmdfs_share_table *st = &sbi->share_table; + struct hmdfs_share_item *item; + struct dentry *dentry; + const char *dir_path, *cur_path; + struct qstr relative_path; + int err = 0; + + if (!src.file) + return -EBADF; + + if (!S_ISREG(src.file->f_inode->i_mode)) { + err = -EPERM; + goto err_out; + } + + 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); + err = -ENOMEM; + goto err_out; + } + relative_path.name = cur_path; + relative_path.len = strlen(cur_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); + } + spin_unlock(&sbi->share_table.item_list_lock); + + if (err < 0) + kfree(cur_path); + kfree(dir_path); + +err_out: + fdput(src); + return err; +} + +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))) + return -EFAULT; + + error = hmdfs_add_to_share_table(file, sbi, &sc); + + return error; +} + +static long hmdfs_dir_ioctl_local(struct file *file, unsigned int cmd, + unsigned long arg) +{ + switch (cmd) { + case HMDFS_IOC_SET_SHARE_PATH: + return hmdfs_ioc_set_share_path(file, arg); + default: + return -ENOTTY; + } +} + const struct file_operations hmdfs_dir_ops_local = { .owner = THIS_MODULE, .iterate = hmdfs_iterate_local, @@ -244,3 +455,13 @@ const struct file_operations hmdfs_dir_ops_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, + .open = hmdfs_dir_open_local, + .release = hmdfs_dir_release_local, + .fsync = hmdfs_fsync_local, + .unlocked_ioctl = hmdfs_dir_ioctl_local, + .compat_ioctl = hmdfs_dir_ioctl_local, +}; diff --git a/fs/hmdfs/file_merge.c b/fs/hmdfs/file_merge.c index 2708f2ba24affe375973660b782dfebb06fd29d3..237bb9e806d95a23e09befc3d142e3374ae84fb3 100644 --- a/fs/hmdfs/file_merge.c +++ b/fs/hmdfs/file_merge.c @@ -454,11 +454,57 @@ int hmdfs_dir_release_merge(struct inode *inode, struct file *file) return 0; } +long hmdfs_dir_unlocked_ioctl_merge(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct hmdfs_file_info *fi_head = hmdfs_f(file); + struct hmdfs_file_info *fi_iter = NULL; + struct hmdfs_file_info *fi_temp = NULL; + struct file *lower_file = NULL; + int error = -ENOTTY; + + mutex_lock(&fi_head->comrade_list_lock); + list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list), + comrade_list) { + if (fi_iter->device_id == 0) { + lower_file = fi_iter->lower_file; + error = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg); + break; + } + } + mutex_unlock(&fi_head->comrade_list_lock); + return error; +} + +long hmdfs_dir_compat_ioctl_merge(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct hmdfs_file_info *fi_head = hmdfs_f(file); + struct hmdfs_file_info *fi_iter = NULL; + struct hmdfs_file_info *fi_temp = NULL; + struct file *lower_file = NULL; + int error = -ENOTTY; + + mutex_lock(&fi_head->comrade_list_lock); + list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list), + comrade_list) { + if (fi_iter->device_id == 0) { + lower_file = fi_iter->lower_file; + error = lower_file->f_op->compat_ioctl(lower_file, cmd, arg); + break; + } + } + mutex_unlock(&fi_head->comrade_list_lock); + return error; +} + const struct file_operations hmdfs_dir_fops_merge = { .owner = THIS_MODULE, .iterate = hmdfs_iterate_merge, .open = hmdfs_dir_open_merge, .release = hmdfs_dir_release_merge, + .unlocked_ioctl = hmdfs_dir_unlocked_ioctl_merge, + .compat_ioctl = hmdfs_dir_compat_ioctl_merge, }; int hmdfs_file_open_merge(struct inode *inode, struct file *file) diff --git a/fs/hmdfs/hmdfs.h b/fs/hmdfs/hmdfs.h index 9b5d456e12174c0597811143cb548d82eda03223..4228bb64c43eca5b9e0ddfbfb41b26529c7eb287 100644 --- a/fs/hmdfs/hmdfs.h +++ b/fs/hmdfs/hmdfs.h @@ -56,6 +56,15 @@ #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 { HMDFS_FEATURE_READPAGES = 1ULL << 0, HMDFS_FEATURE_READPAGES_OPEN = 1ULL << 1, @@ -90,6 +99,22 @@ 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; + int item_cnt; + int max_cnt; +}; + struct hmdfs_sb_info { /* list for all registered superblocks */ struct list_head list; @@ -178,6 +203,9 @@ struct hmdfs_sb_info { /* dentry cache */ bool s_dentry_cache; + /* share table */ + struct hmdfs_share_table share_table; + /* msgs that are waiting for remote */ struct list_head async_readdir_msg_list; /* protect async_readdir_msg_list */ @@ -195,6 +223,11 @@ 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; @@ -290,6 +323,24 @@ static inline bool qstr_case_eq(const struct qstr *q1, const struct qstr *q2) return q1->len == q2->len && str_n_case_eq(q1->name, q2->name, q2->len); } +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_device_view.h b/fs/hmdfs/hmdfs_device_view.h index dcc49fb89597e0d62504aa47ffd5d45766f0f65b..fc77ef9ebcbd4cc4635cc349903ad58aa45ce21b 100644 --- a/fs/hmdfs/hmdfs_device_view.h +++ b/fs/hmdfs/hmdfs_device_view.h @@ -29,6 +29,7 @@ enum HMDFS_FILE_TYPE { HM_REG = 0, HM_SYMLINK = 1, + HM_SHARE = 2, HM_MAX_FILE_TYPE = 0XFF }; @@ -87,7 +88,9 @@ extern const struct inode_operations hmdfs_file_iops_local; extern const struct file_operations hmdfs_file_fops_local; extern const struct inode_operations hmdfs_dir_inode_ops_local; extern const struct file_operations hmdfs_dir_ops_local; +extern const struct file_operations hmdfs_dir_ops_share; extern const struct inode_operations hmdfs_symlink_iops_local; +extern const struct inode_operations hmdfs_dir_inode_ops_share; /* remote device operation */ extern const struct inode_operations hmdfs_dev_file_iops_remote; @@ -147,6 +150,12 @@ static inline bool hm_islnk(uint8_t file_type) { return (file_type == HM_SYMLINK); } + +static inline bool hm_isshare(uint8_t file_type) +{ + return (file_type == HM_SHARE); +} + struct inode *fill_inode_remote(struct super_block *sb, struct hmdfs_peer *con, struct hmdfs_lookup_ret *lookup_result, struct inode *dir); @@ -155,7 +164,7 @@ struct hmdfs_lookup_ret *get_remote_inode_info(struct hmdfs_peer *con, unsigned int flags); void hmdfs_set_time(struct dentry *dentry, unsigned long time); struct inode *fill_inode_local(struct super_block *sb, - struct inode *lower_inode); + struct inode *lower_inode, const char *name); struct inode *fill_root_inode(struct super_block *sb, struct inode *lower_inode); struct inode *fill_device_inode(struct super_block *sb, diff --git a/fs/hmdfs/hmdfs_server.c b/fs/hmdfs/hmdfs_server.c index 4da2fc70c1a5fc237c74b38c7e8ef3545bff9a63..dd4508b80e8eda2d1d70ce317fb43277800a16c9 100644 --- a/fs/hmdfs/hmdfs_server.c +++ b/fs/hmdfs/hmdfs_server.c @@ -133,6 +133,28 @@ 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); @@ -163,6 +185,8 @@ void hmdfs_server_offline_notify(struct hmdfs_peer *conn, int evt, cond_resched(); } + hmdfs_clear_share_item_offline(conn); + /* Reinitialize idr */ next = idr_get_cursor(idr); idr_destroy(idr); @@ -288,11 +312,31 @@ 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; if (!filename) { @@ -307,8 +351,15 @@ static struct file *hmdfs_open_file(struct hmdfs_peer *con, if (hm_islnk(file_type)) file = hmdfs_open_photokit_path(con->sbi, filename); - else + else { + if (hm_isshare(file_type)) { + err = hmdfs_check_share_access_permission(con->sbi, + filename, con->cid, &item); + if (err) + return ERR_PTR(err); + } file = hmdfs_open_path(con->sbi, filename); + } if (IS_ERR(file)) return file; @@ -320,6 +371,10 @@ static struct file *hmdfs_open_file(struct hmdfs_peer *con, } *file_id = id; + /* get item to avoid timeout */ + if (item) + kref_get(&item->ref); + return file; } @@ -715,6 +770,42 @@ 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) { @@ -732,6 +823,10 @@ void hmdfs_server_release(struct hmdfs_peer *con, struct hmdfs_head_cmd *cmd, ret = PTR_ERR(file); goto out; } + + if (hmdfs_is_share_file(file)) + hmdfs_close_share_item(con->sbi, file, con->cid); + /* put the reference acquired by get_file_by_fid_and_ver() */ hmdfs_close_path(file); hmdfs_info("close %u", file_id); diff --git a/fs/hmdfs/hmdfs_trace.h b/fs/hmdfs/hmdfs_trace.h index 205bf697c35741590e0df9cc17b5df995358f8a9..51ecdb9abbc4911051adb73a5cc17c15d8a32ab8 100644 --- a/fs/hmdfs/hmdfs_trace.h +++ b/fs/hmdfs/hmdfs_trace.h @@ -202,6 +202,8 @@ 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_lookup_share); +define_hmdfs_lookup_op_end_event(hmdfs_lookup_share_end); define_hmdfs_lookup_op_end_event(hmdfs_symlink_merge); define_hmdfs_lookup_op_end_event(hmdfs_symlink_local); diff --git a/fs/hmdfs/inode_local.c b/fs/hmdfs/inode_local.c index c302d320de484dd04205df187f04868c57cb7a3b..cfbe67fe98dbf64a13933196bc3783a246b4137f 100644 --- a/fs/hmdfs/inode_local.c +++ b/fs/hmdfs/inode_local.c @@ -66,8 +66,25 @@ static inline void set_symlink_flag(struct hmdfs_dentry_info *gdi) gdi->file_type = HM_SYMLINK; } +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, + const char *name) +{ + const char *share_dir = ".share"; + + if (S_ISDIR(inode->i_mode) && + !strncmp(name, share_dir, strlen(share_dir))) { + inode->i_op = &hmdfs_dir_inode_ops_share; + inode->i_fop = &hmdfs_dir_ops_share; + } +} + struct inode *fill_inode_local(struct super_block *sb, - struct inode *lower_inode) + struct inode *lower_inode, const char *name) { struct inode *inode; struct hmdfs_inode_info *info; @@ -125,6 +142,7 @@ struct inode *fill_inode_local(struct super_block *sb, } fsstack_copy_inode_size(inode, lower_inode); + check_and_fixup_share_ops(inode, name); unlock_new_inode(inode); return inode; } @@ -250,7 +268,8 @@ struct dentry *hmdfs_lookup_local(struct inode *parent_inode, } else if (!err) { hmdfs_set_lower_path(child_dentry, &lower_path); child_inode = fill_inode_local(parent_inode->i_sb, - d_inode(lower_path.dentry)); + 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)) { @@ -337,7 +356,7 @@ int hmdfs_mkdir_local_dentry(struct inode *dir, struct dentry *dentry, #ifdef CONFIG_HMDFS_FS_PERMISSION error = hmdfs_persist_perm(lower_dentry, &child_perm); #endif - child_inode = fill_inode_local(sb, lower_inode); + child_inode = fill_inode_local(sb, lower_inode, dentry->d_name.name); if (IS_ERR(child_inode)) { error = PTR_ERR(child_inode); goto out; @@ -425,7 +444,7 @@ int hmdfs_create_local_dentry(struct inode *dir, struct dentry *dentry, #ifdef CONFIG_HMDFS_FS_PERMISSION error = hmdfs_persist_perm(lower_dentry, &child_perm); #endif - child_inode = fill_inode_local(sb, lower_inode); + child_inode = fill_inode_local(sb, lower_inode, dentry->d_name.name); if (IS_ERR(child_inode)) { error = PTR_ERR(child_inode); goto out_created; @@ -767,7 +786,8 @@ int hmdfs_symlink_local(struct inode *dir, struct dentry *dentry, #ifdef CONFIG_HMDFS_FS_PERMISSION err = hmdfs_persist_perm(lower_dentry, &child_perm); #endif - child_inode = fill_inode_local(dir->i_sb, d_inode(lower_dentry)); + child_inode = fill_inode_local(dir->i_sb, d_inode(lower_dentry), + dentry->d_name.name); if (IS_ERR(child_inode)) { err = PTR_ERR(child_inode); goto out_err; @@ -932,6 +952,95 @@ 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) +{ + const struct qstr *d_name = &child_dentry->d_name; + int err = 0; + struct dentry *ret = NULL; + struct hmdfs_sb_info *sbi = hmdfs_sb(child_dentry->d_sb); + struct path src_path; + struct inode *child_inode = NULL; + + trace_hmdfs_lookup_share(parent_inode, child_dentry, flags); + if (d_name->len > NAME_MAX) { + ret = ERR_PTR(-ENAMETOOLONG); + goto err_out; + } + + err = init_hmdfs_dentry_info(sbi, child_dentry, HMDFS_LAYER_OTHER_LOCAL); + if (err) { + ret = ERR_PTR(err); + goto err_out; + } + + err = hmdfs_get_path_from_share_table(sbi, child_dentry, &src_path); + if (err) { + ret = ERR_PTR(err); + goto err_out; + } + + hmdfs_set_lower_path(child_dentry, &src_path); + child_inode = fill_inode_local(parent_inode->i_sb, + d_inode(src_path.dentry), d_name->name); + + set_sharefile_flag(hmdfs_d(child_dentry)); + + if (IS_ERR(child_inode)) { + err = PTR_ERR(child_inode); + ret = ERR_PTR(err); + hmdfs_put_reset_lower_path(child_dentry); + goto err_out; + } + ret = d_splice_alias(child_inode, child_dentry); + if (IS_ERR(ret)) { + err = PTR_ERR(ret); + hmdfs_put_reset_lower_path(child_dentry); + goto err_out; + } + + check_and_fixup_ownership(parent_inode, child_inode, + src_path.dentry, d_name->name); + +err_out: + if (!err) + hmdfs_set_time(child_dentry, jiffies); + trace_hmdfs_lookup_share_end(parent_inode, child_dentry, err); + return ret; +} + const struct inode_operations hmdfs_symlink_iops_local = { .get_link = hmdfs_get_link_local, .permission = hmdfs_permission, @@ -951,6 +1060,11 @@ const struct inode_operations hmdfs_dir_inode_ops_local = { .getattr = hmdfs_getattr_local, }; +const struct inode_operations hmdfs_dir_inode_ops_share = { + .lookup = hmdfs_lookup_share, + .permission = hmdfs_permission, +}; + const struct inode_operations hmdfs_file_iops_local = { .setattr = hmdfs_setattr_local, .getattr = hmdfs_getattr_local, diff --git a/fs/hmdfs/inode_remote.c b/fs/hmdfs/inode_remote.c index 98a0e34c2253cee0b09eaa0207b15ef2725d15ba..78f04bdc4813985a9c1f10c1d546bca84cd038ac 100644 --- a/fs/hmdfs/inode_remote.c +++ b/fs/hmdfs/inode_remote.c @@ -392,6 +392,19 @@ struct inode *fill_inode_remote(struct super_block *sb, struct hmdfs_peer *con, return inode; } +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) @@ -436,6 +449,8 @@ static struct dentry *hmdfs_lookup_remote_dentry(struct inode *parent_inode, if (lookup_result != NULL) { if (S_ISLNK(lookup_result->i_mode)) gdi->file_type = HM_SYMLINK; + 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); if (!IS_ERR_OR_NULL(ret)) diff --git a/fs/hmdfs/main.c b/fs/hmdfs/main.c index efc952a36afd6a6e0467bdbb027464ed65c0e8c4..a490d069d239ebe101fb790a70df6a42a0b6a602 100644 --- a/fs/hmdfs/main.c +++ b/fs/hmdfs/main.c @@ -661,6 +661,14 @@ 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; @@ -711,6 +719,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); init_waitqueue_head(&sbi->async_readdir_wq); INIT_LIST_HEAD(&sbi->async_readdir_msg_list); INIT_LIST_HEAD(&sbi->async_readdir_work_list);