1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * fs/hmdfs/file_root.c
4 *
5 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
6 */
7
8 #include <linux/fs_stack.h>
9 #include <linux/mount.h>
10 #include <linux/namei.h>
11
12 #include "authority/authentication.h"
13 #include "comm/socket_adapter.h"
14 #include "comm/transport.h"
15 #include "hmdfs.h"
16 #include "hmdfs_dentryfile.h"
17 #include "hmdfs_device_view.h"
18
19 #define DEVICE_VIEW_CTX_POS 2
20 #define MERGE_VIEW_CTX_POS 3
21 #define CLOUD_MERGE_VIEW_CTX_POS 4
22 #define ROOT_DIR_INO_START 20000000
23
24 // used by hmdfs_device_iterate functions
25 #define DEVICE_VIEW_INO_START 20000002
26 #define LOCAL_DEVICE_CTX_POS 2
27 #define CLOUD_DEVICE_CTX_POS 3
28
get_next_con(struct hmdfs_sb_info * sbi,unsigned long current_dev_id)29 struct hmdfs_peer *get_next_con(struct hmdfs_sb_info *sbi,
30 unsigned long current_dev_id)
31 {
32 struct hmdfs_peer *con = NULL;
33 struct hmdfs_peer *next_con = NULL;
34 struct list_head *head, *node;
35
36 mutex_lock(&sbi->connections.node_lock);
37 head = &sbi->connections.node_list;
38 if (current_dev_id == 0) {
39 node = head->next;
40 if (node == head)
41 goto done;
42 next_con = container_of(node, struct hmdfs_peer, list);
43 if (next_con->status == NODE_STAT_ONLINE)
44 goto done;
45 current_dev_id = next_con->device_id;
46 next_con = NULL;
47 }
48
49 list_for_each_entry(con, &sbi->connections.node_list, list) {
50 if ((con->device_id & 0xFFFF) == (current_dev_id & 0xFFFF)) {
51 node = con->list.next;
52 if (node == head)
53 goto done;
54 next_con = container_of(node, struct hmdfs_peer, list);
55 if (next_con->status == NODE_STAT_ONLINE)
56 goto done;
57 current_dev_id = next_con->device_id;
58 next_con = NULL;
59 }
60 }
61 done:
62 if (next_con)
63 peer_get(next_con);
64 mutex_unlock(&sbi->connections.node_lock);
65 return next_con;
66 }
67
hmdfs_device_iterate(struct file * file,struct dir_context * ctx)68 int hmdfs_device_iterate(struct file *file, struct dir_context *ctx)
69 {
70 int err = 0;
71 uint64_t ino_start = DEVICE_VIEW_INO_START;
72 struct hmdfs_peer *next_con = NULL;
73 unsigned long dev_id = 0;
74 struct hmdfs_peer *con = NULL;
75 char *remote_device_name = NULL;
76
77 if (ctx->pos != 0)
78 goto out;
79 dir_emit_dots(file, ctx);
80
81 if (ctx->pos == LOCAL_DEVICE_CTX_POS) {
82 err = dir_emit(ctx, DEVICE_VIEW_LOCAL,
83 sizeof(DEVICE_VIEW_LOCAL) - 1, ino_start++,
84 DT_DIR);
85 if (!err)
86 goto out;
87 (ctx->pos)++;
88 }
89
90 if (ctx->pos == CLOUD_DEVICE_CTX_POS) {
91 err = dir_emit(ctx, DEVICE_VIEW_CLOUD,
92 sizeof(DEVICE_VIEW_CLOUD) - 1, ino_start++,
93 DT_DIR);
94 if (!err)
95 goto out;
96 (ctx->pos)++;
97 }
98
99 next_con = get_next_con(file->f_inode->i_sb->s_fs_info, 0);
100 if (!next_con)
101 goto out;
102
103 dev_id = next_con->device_id;
104 peer_put(next_con);
105 con = hmdfs_lookup_from_devid(file->f_inode->i_sb->s_fs_info, dev_id);
106 remote_device_name = kmalloc(HMDFS_CID_SIZE + 1, GFP_KERNEL);
107 if (!remote_device_name) {
108 err = -ENOMEM;
109 goto out;
110 }
111 while (con) {
112 peer_put(con);
113 snprintf(remote_device_name, HMDFS_CID_SIZE + 1, "%s",
114 con->cid);
115 if (!dir_emit(ctx, remote_device_name,
116 strlen(remote_device_name), ino_start++, DT_DIR))
117 goto done;
118
119 (ctx->pos)++;
120 con = get_next_con(file->f_inode->i_sb->s_fs_info, dev_id);
121 if (!con)
122 goto done;
123
124 dev_id = con->device_id;
125 }
126 done:
127 kfree(remote_device_name);
128 out:
129 if (err <= 0)
130 ctx->pos = -1;
131
132 return err;
133 }
134
hmdfs_root_iterate(struct file * file,struct dir_context * ctx)135 int hmdfs_root_iterate(struct file *file, struct dir_context *ctx)
136 {
137 uint64_t ino_start = ROOT_DIR_INO_START;
138 struct hmdfs_sb_info *sbi = file_inode(file)->i_sb->s_fs_info;
139
140 if (!dir_emit_dots(file, ctx))
141 return 0;
142 if (ctx->pos == DEVICE_VIEW_CTX_POS) {
143 if (!dir_emit(ctx, DEVICE_VIEW_ROOT,
144 sizeof(DEVICE_VIEW_ROOT) - 1, ino_start, DT_DIR))
145 return 0;
146 ino_start++;
147 ctx->pos = MERGE_VIEW_CTX_POS;
148 }
149 if (sbi->s_merge_switch && ctx->pos == MERGE_VIEW_CTX_POS) {
150 if (!dir_emit(ctx, MERGE_VIEW_ROOT, sizeof(MERGE_VIEW_ROOT) - 1,
151 ino_start, DT_DIR))
152 return 0;
153 ino_start++;
154 (ctx->pos)++;
155 }
156 if (sbi->s_merge_switch && ctx->pos == CLOUD_MERGE_VIEW_CTX_POS) {
157 if (!dir_emit(ctx, CLOUD_MERGE_VIEW_ROOT, sizeof(CLOUD_MERGE_VIEW_ROOT) - 1,
158 ino_start, DT_DIR))
159 return 0;
160 ino_start++;
161 (ctx->pos)++;
162 }
163 return 0;
164 }
165
166 const struct file_operations hmdfs_root_fops = {
167 .owner = THIS_MODULE,
168 .iterate = hmdfs_root_iterate,
169 };
170
171 const struct file_operations hmdfs_device_fops = {
172 .owner = THIS_MODULE,
173 .iterate = hmdfs_device_iterate,
174 };
175