1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * fs/hmdfs/file_cloud.c
4 *
5 * Copyright (c) 2023-2023 Huawei Device Co., Ltd.
6 */
7
8 #include <linux/backing-dev.h>
9 #include <linux/file.h>
10 #include <linux/fs.h>
11 #include <linux/namei.h>
12 #include <linux/page-flags.h>
13 #include <linux/pagemap.h>
14 #include <linux/pagevec.h>
15 #include <linux/sched/signal.h>
16 #include <linux/slab.h>
17 #include <linux/wait.h>
18
19 #include "file_remote.h"
20
21 #include "comm/socket_adapter.h"
22 #include "hmdfs.h"
23 #include "hmdfs_client.h"
24 #include "hmdfs_dentryfile.h"
25 #include "hmdfs_dentryfile_cloud.h"
26 #include "hmdfs_trace.h"
27
28 static const struct vm_operations_struct hmdfs_cloud_vm_ops = {
29 .fault = filemap_fault,
30 .map_pages = filemap_map_pages,
31 .page_mkwrite = NULL,
32 };
33
hmdfs_file_read_iter_cloud(struct kiocb * iocb,struct iov_iter * iter)34 static ssize_t hmdfs_file_read_iter_cloud(struct kiocb *iocb,
35 struct iov_iter *iter)
36 {
37 ssize_t ret = -ENOENT;
38 struct file *filp = iocb->ki_filp;
39 struct hmdfs_file_info *gfi = filp->private_data;
40 struct file *lower_file = NULL;
41
42 if (gfi)
43 lower_file = gfi->lower_file;
44
45 if (lower_file) {
46 kiocb_clone(iocb, iocb, lower_file);
47 ret = vfs_iter_read(lower_file, iter, &iocb->ki_pos, 0);
48 }
49
50 return ret;
51 }
52
hmdfs_file_open_cloud(struct inode * inode,struct file * file)53 int hmdfs_file_open_cloud(struct inode *inode, struct file *file)
54 {
55 const char *dir_path;
56 struct hmdfs_sb_info *sbi = inode->i_sb->s_fs_info;
57 struct path root_path;
58 struct file *lower_file;
59 int err = 0;
60
61 struct hmdfs_file_info *gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
62 if (!gfi)
63 return -ENOMEM;
64
65 if (!sbi->cloud_dir) {
66 hmdfs_info("no cloud_dir");
67 kfree(gfi);
68 return -EPERM;
69 }
70
71 err = kern_path(sbi->cloud_dir, 0, &root_path);
72 if (err) {
73 hmdfs_info("kern_path failed: %d", err);
74 kfree(gfi);
75 return err;
76 }
77
78 dir_path = hmdfs_get_dentry_relative_path(file->f_path.dentry);
79 if(!dir_path) {
80 hmdfs_err("get cloud path failed");
81 kfree(gfi);
82 return -ENOENT;
83 }
84
85 lower_file = file_open_root(&root_path, dir_path,
86 file->f_flags, file->f_mode);
87 path_put(&root_path);
88 if (IS_ERR(lower_file)) {
89 hmdfs_info("file_open_root failed: %ld", PTR_ERR(lower_file));
90 err = PTR_ERR(lower_file);
91 kfree(gfi);
92 } else {
93 gfi->lower_file = lower_file;
94 file->private_data = gfi;
95 }
96 kfree(dir_path);
97 return err;
98 }
99
hmdfs_file_release_cloud(struct inode * inode,struct file * file)100 int hmdfs_file_release_cloud(struct inode *inode, struct file *file)
101 {
102 struct hmdfs_file_info *gfi = hmdfs_f(file);
103
104 file->private_data = NULL;
105 fput(gfi->lower_file);
106 kfree(gfi);
107 return 0;
108 }
109
hmdfs_file_flush_cloud(struct file * file,fl_owner_t id)110 static int hmdfs_file_flush_cloud(struct file *file, fl_owner_t id)
111 {
112 struct hmdfs_file_info *gfi = hmdfs_f(file);
113
114 if(!gfi || !gfi->lower_file)
115 return 0;
116
117 if (gfi->lower_file->f_op->flush)
118 return gfi->lower_file->f_op->flush(gfi->lower_file, id);
119 return 0;
120 }
121
hmdfs_file_mmap_cloud(struct file * file,struct vm_area_struct * vma)122 int hmdfs_file_mmap_cloud(struct file *file, struct vm_area_struct *vma)
123 {
124 struct hmdfs_file_info *private_data = file->private_data;
125 struct file *realfile = NULL;
126 int ret;
127
128 if (!private_data)
129 return -EINVAL;
130
131 realfile = private_data->lower_file;
132 if (!realfile)
133 return -EINVAL;
134
135 if (!realfile->f_op->mmap)
136 return -ENODEV;
137
138 if (WARN_ON(file != vma->vm_file))
139 return -EIO;
140
141 vma->vm_file = get_file(realfile);
142 ret = call_mmap(vma->vm_file, vma);
143 if (ret)
144 fput(realfile);
145 else
146 fput(file);
147
148 file_accessed(file);
149
150 return ret;
151 }
152
153 const struct file_operations hmdfs_dev_file_fops_cloud = {
154 .owner = THIS_MODULE,
155 .llseek = generic_file_llseek,
156 .read_iter = hmdfs_file_read_iter_cloud,
157 .write_iter = NULL,
158 .mmap = hmdfs_file_mmap_cloud,
159 .open = hmdfs_file_open_cloud,
160 .release = hmdfs_file_release_cloud,
161 .flush = hmdfs_file_flush_cloud,
162 .fsync = NULL,
163 .splice_read = NULL,
164 .splice_write = NULL,
165 };
166
167
168 const struct address_space_operations hmdfs_dev_file_aops_cloud = {
169 .readpage = NULL,
170 .write_begin = NULL,
171 .write_end = NULL,
172 .writepage = NULL,
173 .set_page_dirty = NULL,
174 };
175
analysis_dentry_file_from_cloud(struct hmdfs_sb_info * sbi,struct file * file,struct file * handler,struct dir_context * ctx)176 int analysis_dentry_file_from_cloud(struct hmdfs_sb_info *sbi,
177 struct file *file, struct file *handler,
178 struct dir_context *ctx)
179 {
180 struct hmdfs_dentry_group_cloud *dentry_group = NULL;
181 loff_t pos = ctx->pos;
182 unsigned long dev_id = (unsigned long)((pos << 1) >> (POS_BIT_NUM - DEV_ID_BIT_NUM));
183 unsigned long group_id = (unsigned long)((pos << (1 + DEV_ID_BIT_NUM)) >>
184 (POS_BIT_NUM - GROUP_ID_BIT_NUM));
185 loff_t offset = pos & OFFSET_BIT_MASK;
186 int group_num = 0;
187 char *dentry_name = NULL;
188 int iterate_result = 0;
189 int i, j;
190
191 dentry_group = kzalloc(sizeof(*dentry_group), GFP_KERNEL);
192
193 if (!dentry_group)
194 return -ENOMEM;
195
196 if (IS_ERR_OR_NULL(handler)) {
197 kfree(dentry_group);
198 return -ENOENT;
199 }
200
201 group_num = get_dentry_group_cnt(file_inode(handler));
202 dentry_name = kzalloc(DENTRY_NAME_MAX_LEN, GFP_KERNEL);
203 if (!dentry_name) {
204 kfree(dentry_group);
205 return -ENOMEM;
206 }
207
208 for (i = group_id; i < group_num; i++) {
209 int ret = hmdfs_metainfo_read(sbi, handler, dentry_group,
210 sizeof(struct hmdfs_dentry_group_cloud),
211 i);
212 if (ret != sizeof(struct hmdfs_dentry_group_cloud)) {
213 hmdfs_err("read dentry group failed ret:%d", ret);
214 goto done;
215 }
216
217 for (j = offset; j < DENTRY_PER_GROUP_CLOUD; j++) {
218 int len;
219 int file_type = DT_UNKNOWN;
220 bool is_continue;
221
222 len = le16_to_cpu(dentry_group->nsl[j].namelen);
223 if (!test_bit_le(j, dentry_group->bitmap) || len == 0)
224 continue;
225
226 memset(dentry_name, 0, DENTRY_NAME_MAX_LEN);
227 if (S_ISDIR(le16_to_cpu(dentry_group->nsl[j].i_mode)))
228 file_type = DT_DIR;
229 else if (S_ISREG(le16_to_cpu(
230 dentry_group->nsl[j].i_mode)))
231 file_type = DT_REG;
232
233 strncat(dentry_name, dentry_group->filename[j], len);
234 pos = hmdfs_set_pos(dev_id, i, j);
235 is_continue =
236 dir_emit(ctx, dentry_name, len,
237 pos + INUNUMBER_START, file_type);
238 if (!is_continue) {
239 ctx->pos = pos;
240 iterate_result = 1;
241 goto done;
242 }
243 }
244 offset = 0;
245 }
246
247 done:
248 kfree(dentry_name);
249 kfree(dentry_group);
250 return iterate_result;
251 }
252
hmdfs_iterate_cloud(struct file * file,struct dir_context * ctx)253 static int hmdfs_iterate_cloud(struct file *file, struct dir_context *ctx)
254 {
255 int err = 0;
256 loff_t start_pos = ctx->pos;
257
258 if (ctx->pos == -1)
259 return 0;
260 err = analysis_dentry_file_from_cloud(
261 file->f_inode->i_sb->s_fs_info, file, file->private_data, ctx);
262
263 if (err <= 0)
264 ctx->pos = -1;
265
266 trace_hmdfs_iterate_remote(file->f_path.dentry, start_pos, ctx->pos,
267 err);
268 return err;
269 }
270
hmdfs_dir_open_cloud(struct inode * inode,struct file * file)271 int hmdfs_dir_open_cloud(struct inode *inode, struct file *file)
272 {
273 struct clearcache_item *cache_item = NULL;
274
275 get_cloud_cache_file(file->f_path.dentry, file->f_inode->i_sb->s_fs_info);
276 cache_item = hmdfs_find_cache_item(CLOUD_DEVICE,
277 file->f_path.dentry);
278 if (cache_item) {
279 file->private_data = cache_item->filp;
280 get_file(file->private_data);
281 kref_put(&cache_item->ref, release_cache_item);
282 return 0;
283 }
284
285 return -ENOENT;
286 }
287
hmdfs_dir_release_cloud(struct inode * inode,struct file * file)288 static int hmdfs_dir_release_cloud(struct inode *inode, struct file *file)
289 {
290 if (file->private_data)
291 fput(file->private_data);
292 file->private_data = NULL;
293 return 0;
294 }
295
296 const struct file_operations hmdfs_dev_dir_ops_cloud = {
297 .owner = THIS_MODULE,
298 .iterate = hmdfs_iterate_cloud,
299 .open = hmdfs_dir_open_cloud,
300 .release = hmdfs_dir_release_cloud,
301 .fsync = __generic_file_fsync,
302 };
303