1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * fs/hmdfs/file_merge.c
4 *
5 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
6 */
7
8 #include "hmdfs_merge_view.h"
9
10 #include <linux/file.h>
11
12 #include "hmdfs.h"
13 #include "hmdfs_trace.h"
14 #include "authority/authentication.h"
15
16 struct hmdfs_iterate_callback_merge {
17 struct dir_context ctx;
18 struct dir_context *caller;
19 /*
20 * Record the return value of 'caller->actor':
21 *
22 * false, buffer is exhausted
23 * false, current task is pending
24 * false, something is wrong
25 * true, success and can do more
26 */
27 bool result ;
28 struct rb_root *root;
29 uint64_t dev_id;
30 };
31
32 struct hmdfs_cache_entry {
33 struct rb_node rb_node;
34 int name_len;
35 char *name;
36 int file_type;
37 };
38
39 struct hmdfs_user_info {
40 char *local_path;
41 char *distributed_path;
42 char *bundle_name;
43 };
44
allocate_entry(const char *name, int namelen, int d_type)45 struct hmdfs_cache_entry *allocate_entry(const char *name, int namelen,
46 int d_type)
47 {
48 struct hmdfs_cache_entry *data;
49
50 data = kmalloc(sizeof(*data), GFP_KERNEL);
51 if (!data)
52 return ERR_PTR(-ENOMEM);
53
54 data->name = kstrndup(name, namelen, GFP_KERNEL);
55 if (!data->name) {
56 kfree(data);
57 return ERR_PTR(-ENOMEM);
58 }
59
60 data->name_len = namelen;
61 data->file_type = d_type;
62
63 return data;
64 }
65
insert_filename(struct rb_root *root, struct hmdfs_cache_entry **new_entry)66 int insert_filename(struct rb_root *root, struct hmdfs_cache_entry **new_entry)
67 {
68 struct rb_node *parent = NULL;
69 struct rb_node **new_node = &(root->rb_node);
70 int cmp_res = 0;
71 struct hmdfs_cache_entry *data = *new_entry;
72
73 while (*new_node) {
74 struct hmdfs_cache_entry *entry = container_of(
75 *new_node, struct hmdfs_cache_entry, rb_node);
76 parent = *new_node;
77
78 if (data->name_len < entry->name_len)
79 cmp_res = -1;
80 else if (data->name_len > entry->name_len)
81 cmp_res = 1;
82 else
83 cmp_res = strncmp(data->name, entry->name,
84 data->name_len);
85
86 if (!cmp_res) {
87 kfree(data->name);
88 kfree(data);
89 *new_entry = entry;
90 return entry->file_type;
91 }
92
93 if (cmp_res < 0)
94 new_node = &((*new_node)->rb_left);
95 else if (cmp_res > 0)
96 new_node = &((*new_node)->rb_right);
97 }
98
99 rb_link_node(&data->rb_node, parent, new_node);
100 rb_insert_color(&data->rb_node, root);
101
102 return 0;
103 }
104
recursive_delete(struct rb_node *node)105 static void recursive_delete(struct rb_node *node)
106 {
107 struct hmdfs_cache_entry *entry = NULL;
108
109 if (!node)
110 return;
111
112 recursive_delete(node->rb_left);
113 recursive_delete(node->rb_right);
114
115 entry = container_of(node, struct hmdfs_cache_entry, rb_node);
116 kfree(entry->name);
117 kfree(entry);
118 }
119
destroy_tree(struct rb_root *root)120 static void destroy_tree(struct rb_root *root)
121 {
122 if (!root)
123 return;
124 recursive_delete(root->rb_node);
125 root->rb_node = NULL;
126 }
127
delete_filename(struct rb_root *root, struct hmdfs_cache_entry *data)128 static void delete_filename(struct rb_root *root,
129 struct hmdfs_cache_entry *data)
130 {
131 struct rb_node **node = &(root->rb_node);
132 struct hmdfs_cache_entry *entry = NULL;
133 int cmp_res = 0;
134
135 while (*node) {
136 entry = container_of(*node, struct hmdfs_cache_entry, rb_node);
137 if (data->name_len < entry->name_len)
138 cmp_res = -1;
139 else if (data->name_len > entry->name_len)
140 cmp_res = 1;
141 else
142 cmp_res = strncmp(data->name, entry->name,
143 data->name_len);
144
145 if (!cmp_res)
146 goto found;
147
148 if (cmp_res < 0)
149 node = &((*node)->rb_left);
150 else if (cmp_res > 0)
151 node = &((*node)->rb_right);
152 }
153 return;
154
155 found:
156 rb_erase(*node, root);
157 kfree(entry->name);
158 kfree(entry);
159 }
160
rename_conflicting_file(char *dentry_name, int *len, unsigned int dev_id)161 static void rename_conflicting_file(char *dentry_name, int *len,
162 unsigned int dev_id)
163 {
164 int i = *len - 1;
165 int dot_pos = -1;
166 char *buffer;
167
168 buffer = kzalloc(DENTRY_NAME_MAX_LEN, GFP_KERNEL);
169 if (!buffer)
170 return;
171
172 while (i >= 0) {
173 if (dentry_name[i] == '/')
174 break;
175 if (dentry_name[i] == '.') {
176 // TODO: 这个修改同步到 CT01
177 dot_pos = i;
178 break;
179 }
180 i--;
181 }
182
183 if (dot_pos == -1) {
184 snprintf(dentry_name + *len, DENTRY_NAME_MAX_LEN - *len,
185 CONFLICTING_FILE_SUFFIX, dev_id);
186 goto done;
187 }
188
189 for (i = 0; i < *len - dot_pos; i++)
190 buffer[i] = dentry_name[i + dot_pos];
191
192 buffer[i] = '\0';
193 snprintf(dentry_name + dot_pos, DENTRY_NAME_MAX_LEN - dot_pos,
194 CONFLICTING_FILE_SUFFIX, dev_id);
195 strcat(dentry_name, buffer);
196
197 done:
198 *len = strlen(dentry_name);
199 kfree(buffer);
200 }
201
rename_conflicting_directory(char *dentry_name, int *len)202 static void rename_conflicting_directory(char *dentry_name, int *len)
203 {
204 snprintf(dentry_name + *len, DENTRY_NAME_MAX_LEN - *len,
205 CONFLICTING_DIR_SUFFIX);
206 *len += strlen(CONFLICTING_DIR_SUFFIX);
207 }
208
hmdfs_actor_merge(struct dir_context *ctx, const char *name, int namelen, long long offset, unsigned long long ino, unsigned int d_type)209 static bool hmdfs_actor_merge(struct dir_context *ctx, const char *name,
210 int namelen, long long offset, unsigned long long ino,
211 unsigned int d_type)
212 {
213 bool ret = true;
214 int insert_res = 0;
215 int max_devid_len = 2;
216 char *dentry_name = NULL;
217 int dentry_len = namelen;
218 struct hmdfs_cache_entry *cache_entry = NULL;
219 struct hmdfs_iterate_callback_merge *iterate_callback_merge = NULL;
220 struct dir_context *org_ctx = NULL;
221
222 if (hmdfs_file_type(name) != HMDFS_TYPE_COMMON) {
223 /*
224 * return true here, so that the caller can continue to next
225 * dentry even if failed on this dentry somehow.
226 */
227 return true;
228 }
229
230
231 if (namelen > NAME_MAX)
232 return false;
233 dentry_name = kzalloc(NAME_MAX + 1, GFP_KERNEL);
234 if (!dentry_name)
235 return false;
236
237 strncpy(dentry_name, name, dentry_len);
238
239 cache_entry = allocate_entry(dentry_name, dentry_len, d_type);
240 if (IS_ERR(cache_entry)) {
241 ret = PTR_ERR(cache_entry);
242 goto done;
243 }
244
245 iterate_callback_merge =
246 container_of(ctx, struct hmdfs_iterate_callback_merge, ctx);
247 insert_res =
248 insert_filename(iterate_callback_merge->root, &cache_entry);
249 if (d_type == DT_DIR && insert_res == DT_DIR) {
250 goto done;
251 } else if (d_type == DT_DIR &&
252 (insert_res == DT_REG || insert_res == DT_LNK)) {
253 if (strlen(CONFLICTING_DIR_SUFFIX) > NAME_MAX - dentry_len) {
254 ret = false;
255 goto delete;
256 }
257 rename_conflicting_directory(dentry_name, &dentry_len);
258 cache_entry->file_type = DT_DIR;
259 } else if ((d_type == DT_REG || d_type == DT_LNK) && insert_res > 0) {
260 if (strlen(CONFLICTING_FILE_SUFFIX) + max_devid_len >
261 NAME_MAX - dentry_len) {
262 ret = false;
263 goto delete;
264 }
265 rename_conflicting_file(dentry_name, &dentry_len,
266 iterate_callback_merge->dev_id);
267 }
268
269 org_ctx = iterate_callback_merge->caller;
270 ret = org_ctx->actor(org_ctx, dentry_name, dentry_len, org_ctx->pos,
271 ino, d_type);
272 /*
273 * Record original return value, so that the caller can be aware of
274 * different situations.
275 */
276 iterate_callback_merge->result = ret;
277 if (!ret && d_type == DT_DIR && cache_entry->file_type == DT_DIR &&
278 (insert_res == DT_REG || insert_res == DT_LNK))
279 cache_entry->file_type = DT_REG;
280
281 delete:
282 if (!ret && !insert_res)
283 delete_filename(iterate_callback_merge->root, cache_entry);
284 done:
285 kfree(dentry_name);
286 return ret;
287 }
288
289 struct hmdfs_file_info *
get_next_hmdfs_file_info(struct hmdfs_file_info *fi_head, int device_id)290 get_next_hmdfs_file_info(struct hmdfs_file_info *fi_head, int device_id)
291 {
292 struct hmdfs_file_info *fi_iter = NULL;
293 struct hmdfs_file_info *fi_result = NULL;
294
295 mutex_lock(&fi_head->comrade_list_lock);
296 list_for_each_entry_safe(fi_iter, fi_result, &(fi_head->comrade_list),
297 comrade_list) {
298 if (fi_iter->device_id == device_id)
299 break;
300 }
301 mutex_unlock(&fi_head->comrade_list_lock);
302
303 return fi_result != fi_head ? fi_result : NULL;
304 }
305
get_hmdfs_file_info(struct hmdfs_file_info *fi_head, int device_id)306 struct hmdfs_file_info *get_hmdfs_file_info(struct hmdfs_file_info *fi_head,
307 int device_id)
308 {
309 struct hmdfs_file_info *fi_iter = NULL;
310
311 mutex_lock(&fi_head->comrade_list_lock);
312 list_for_each_entry(fi_iter, &(fi_head->comrade_list), comrade_list) {
313 if (fi_iter->device_id == device_id) {
314 mutex_unlock(&fi_head->comrade_list_lock);
315 return fi_iter;
316 }
317 }
318 mutex_unlock(&fi_head->comrade_list_lock);
319
320 return NULL;
321 }
322
hmdfs_iterate_merge(struct file *file, struct dir_context *ctx)323 int hmdfs_iterate_merge(struct file *file, struct dir_context *ctx)
324 {
325 int err = 0;
326 struct hmdfs_file_info *fi_head = hmdfs_f(file);
327 struct hmdfs_file_info *fi_iter = NULL;
328 struct file *lower_file_iter = NULL;
329 loff_t start_pos = ctx->pos;
330 unsigned long device_id = (unsigned long)((ctx->pos) << 1 >>
331 (POS_BIT_NUM - DEV_ID_BIT_NUM));
332 struct hmdfs_iterate_callback_merge ctx_merge = {
333 .ctx.actor = hmdfs_actor_merge,
334 .caller = ctx,
335 .root = &fi_head->root,
336 .dev_id = device_id
337 };
338
339 /* pos = -1 indicates that all devices have been traversed
340 * or an error has occurred.
341 */
342 if (ctx->pos == -1)
343 return 0;
344
345 fi_iter = get_hmdfs_file_info(fi_head, device_id);
346 if (!fi_iter) {
347 fi_iter = get_next_hmdfs_file_info(fi_head, device_id);
348 // dev_id is changed, parameter is set 0 to get next file info
349 if (fi_iter)
350 ctx_merge.ctx.pos =
351 hmdfs_set_pos(fi_iter->device_id, 0, 0);
352 }
353 while (fi_iter) {
354 ctx_merge.dev_id = fi_iter->device_id;
355 device_id = ctx_merge.dev_id;
356 lower_file_iter = fi_iter->lower_file;
357 lower_file_iter->f_pos = file->f_pos;
358 err = iterate_dir(lower_file_iter, &ctx_merge.ctx);
359 file->f_pos = lower_file_iter->f_pos;
360 ctx->pos = file->f_pos;
361
362 if (err)
363 goto done;
364 /*
365 * ctx->actor return nonzero means buffer is exhausted or
366 * something is wrong, thus we should not continue.
367 */
368 if (ctx_merge.result)
369 goto done;
370 fi_iter = get_next_hmdfs_file_info(fi_head, device_id);
371 if (fi_iter) {
372 file->f_pos = hmdfs_set_pos(fi_iter->device_id, 0, 0);
373 ctx->pos = file->f_pos;
374 }
375 }
376 done:
377 trace_hmdfs_iterate_merge(file->f_path.dentry, start_pos, ctx->pos,
378 err);
379 return err;
380 }
381
do_dir_open_merge(struct file *file, const struct cred *cred, struct hmdfs_file_info *fi_head)382 int do_dir_open_merge(struct file *file, const struct cred *cred,
383 struct hmdfs_file_info *fi_head)
384 {
385 int ret = -EINVAL;
386 struct hmdfs_dentry_info_merge *dim = hmdfs_dm(file->f_path.dentry);
387 struct hmdfs_dentry_comrade *comrade = NULL;
388 struct hmdfs_file_info *fi = NULL;
389 struct path lo_p = { .mnt = file->f_path.mnt };
390 struct file *lower_file = NULL;
391
392 if (IS_ERR_OR_NULL(cred))
393 return ret;
394
395 wait_event(dim->wait_queue, !has_merge_lookup_work(dim));
396
397 mutex_lock(&dim->comrade_list_lock);
398 list_for_each_entry(comrade, &(dim->comrade_list), list) {
399 fi = kzalloc(sizeof(*fi), GFP_KERNEL);
400 if (!fi) {
401 ret = ret ? -ENOMEM : 0;
402 continue; // allow some dir to fail to open
403 }
404 lo_p.dentry = comrade->lo_d;
405 // make sure that dentry will not be dentry_kill before open
406 dget(lo_p.dentry);
407 if (unlikely(d_is_negative(lo_p.dentry))) {
408 hmdfs_info("dentry is negative, try again");
409 kfree(fi);
410 dput(lo_p.dentry);
411 continue; // skip this device
412 }
413 lower_file = dentry_open(&lo_p, file->f_flags, cred);
414 dput(lo_p.dentry);
415 if (IS_ERR(lower_file)) {
416 kfree(fi);
417 continue;
418 }
419 ret = 0;
420 fi->device_id = comrade->dev_id;
421 fi->lower_file = lower_file;
422 mutex_lock(&fi_head->comrade_list_lock);
423 list_add_tail(&fi->comrade_list, &fi_head->comrade_list);
424 mutex_unlock(&fi_head->comrade_list_lock);
425 }
426 mutex_unlock(&dim->comrade_list_lock);
427 return ret;
428 }
429
hmdfs_dir_open_merge(struct inode *inode, struct file *file)430 int hmdfs_dir_open_merge(struct inode *inode, struct file *file)
431 {
432 int ret = 0;
433 struct hmdfs_file_info *fi = NULL;
434
435 fi = kzalloc(sizeof(*fi), GFP_KERNEL);
436 if (!fi)
437 return -ENOMEM;
438
439 file->private_data = fi;
440 fi->root = RB_ROOT;
441 mutex_init(&fi->comrade_list_lock);
442 INIT_LIST_HEAD(&fi->comrade_list);
443
444 ret = do_dir_open_merge(file, hmdfs_sb(inode->i_sb)->cred, fi);
445 if (ret)
446 kfree(fi);
447
448 return ret;
449 }
450
hmdfs_dir_release_merge(struct inode *inode, struct file *file)451 int hmdfs_dir_release_merge(struct inode *inode, struct file *file)
452 {
453 struct hmdfs_file_info *fi_head = hmdfs_f(file);
454 struct hmdfs_file_info *fi_iter = NULL;
455 struct hmdfs_file_info *fi_temp = NULL;
456
457 mutex_lock(&fi_head->comrade_list_lock);
458 list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
459 comrade_list) {
460 list_del_init(&(fi_iter->comrade_list));
461 fput(fi_iter->lower_file);
462 kfree(fi_iter);
463 }
464 mutex_unlock(&fi_head->comrade_list_lock);
465 destroy_tree(&fi_head->root);
466 file->private_data = NULL;
467 kfree(fi_head);
468
469 return 0;
470 }
471
472 static long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg);
473
hmdfs_dir_unlocked_ioctl_merge(struct file *file, unsigned int cmd, unsigned long arg)474 long hmdfs_dir_unlocked_ioctl_merge(struct file *file, unsigned int cmd,
475 unsigned long arg)
476 {
477 struct hmdfs_file_info *fi_head = hmdfs_f(file);
478 struct hmdfs_file_info *fi_iter = NULL;
479 struct hmdfs_file_info *fi_temp = NULL;
480 struct file *lower_file = NULL;
481 int error = -ENOTTY;
482
483 if (cmd == HMDFS_IOC_GET_DST_PATH)
484 return hmdfs_ioc_get_dst_path(file, arg);
485 mutex_lock(&fi_head->comrade_list_lock);
486 list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
487 comrade_list) {
488 if (fi_iter->device_id == 0) {
489 lower_file = fi_iter->lower_file;
490 if (lower_file->f_op->unlocked_ioctl)
491 error = lower_file->f_op->unlocked_ioctl(
492 lower_file, cmd, arg);
493 break;
494 }
495 }
496 mutex_unlock(&fi_head->comrade_list_lock);
497 return error;
498 }
499
hmdfs_dir_compat_ioctl_merge(struct file *file, unsigned int cmd, unsigned long arg)500 long hmdfs_dir_compat_ioctl_merge(struct file *file, unsigned int cmd,
501 unsigned long arg)
502 {
503 struct hmdfs_file_info *fi_head = hmdfs_f(file);
504 struct hmdfs_file_info *fi_iter = NULL;
505 struct hmdfs_file_info *fi_temp = NULL;
506 struct file *lower_file = NULL;
507 int error = -ENOTTY;
508
509 if (cmd == HMDFS_IOC_GET_DST_PATH)
510 return hmdfs_ioc_get_dst_path(file, arg);
511 mutex_lock(&fi_head->comrade_list_lock);
512 list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
513 comrade_list) {
514 if (fi_iter->device_id == 0) {
515 lower_file = fi_iter->lower_file;
516 if (lower_file->f_op->compat_ioctl)
517 error = lower_file->f_op->compat_ioctl(
518 lower_file, cmd, arg);
519 break;
520 }
521 }
522 mutex_unlock(&fi_head->comrade_list_lock);
523 return error;
524 }
525
526 const struct file_operations hmdfs_dir_fops_merge = {
527 .owner = THIS_MODULE,
528 .iterate_shared = hmdfs_iterate_merge,
529 .open = hmdfs_dir_open_merge,
530 .release = hmdfs_dir_release_merge,
531 .unlocked_ioctl = hmdfs_dir_unlocked_ioctl_merge,
532 .compat_ioctl = hmdfs_dir_compat_ioctl_merge,
533 };
534
hmdfs_merge_read_iter(struct kiocb *iocb, struct iov_iter *iter)535 static ssize_t hmdfs_merge_read_iter(struct kiocb *iocb, struct iov_iter *iter)
536 {
537 return hmdfs_do_read_iter(iocb->ki_filp, iter, &iocb->ki_pos);
538 }
539
hmdfs_merge_write_iter(struct kiocb *iocb, struct iov_iter *iter)540 ssize_t hmdfs_merge_write_iter(struct kiocb *iocb, struct iov_iter *iter)
541 {
542 return hmdfs_do_write_iter(iocb->ki_filp, iter, &iocb->ki_pos);
543 }
544
hmdfs_file_open_merge(struct inode *inode, struct file *file)545 int hmdfs_file_open_merge(struct inode *inode, struct file *file)
546 {
547 int err = 0;
548 struct file *lower_file = NULL;
549 struct path lo_p = { .mnt = file->f_path.mnt };
550 struct super_block *sb = inode->i_sb;
551 const struct cred *cred = hmdfs_sb(sb)->cred;
552 struct hmdfs_file_info *gfi = NULL;
553 struct dentry *parent = NULL;
554
555 lo_p.dentry = hmdfs_get_fst_lo_d(file->f_path.dentry);
556 if (!lo_p.dentry) {
557 err = -EINVAL;
558 goto out_err;
559 }
560
561 gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
562 if (!gfi) {
563 err = -ENOMEM;
564 goto out_err;
565 }
566
567 parent = dget_parent(file->f_path.dentry);
568 lower_file = dentry_open(&lo_p, file->f_flags, cred);
569 if (IS_ERR(lower_file)) {
570 err = PTR_ERR(lower_file);
571 kfree(gfi);
572 } else {
573 gfi->lower_file = lower_file;
574 file->private_data = gfi;
575 hmdfs_update_upper_file(file, lower_file);
576 }
577 dput(parent);
578 out_err:
579 dput(lo_p.dentry);
580 return err;
581 }
582
hmdfs_file_flush_merge(struct file *file, fl_owner_t id)583 int hmdfs_file_flush_merge(struct file *file, fl_owner_t id)
584 {
585 struct hmdfs_file_info *gfi = hmdfs_f(file);
586 struct file *lower_file = gfi->lower_file;
587
588 if (lower_file->f_op->flush)
589 return lower_file->f_op->flush(lower_file, id);
590
591 return 0;
592 }
593
hmdfs_ioc_get_writeopen_cnt(struct file *filp, unsigned long arg)594 static long hmdfs_ioc_get_writeopen_cnt(struct file *filp, unsigned long arg)
595 {
596 struct hmdfs_file_info *gfi = hmdfs_f(filp);
597 struct file *lower_file = gfi->lower_file;
598 struct inode *lower_inode = file_inode(lower_file);
599
600 u32 wo_cnt = atomic_read(&(hmdfs_i(lower_inode))->write_opened);
601
602 return put_user(wo_cnt, (int __user *)arg);
603 }
604
copy_string_from_user(unsigned long pos, unsigned long len, char **data)605 static int copy_string_from_user(unsigned long pos, unsigned long len,
606 char **data)
607 {
608 char *tmp_data;
609
610 if (len >= PATH_MAX)
611 return -EINVAL;
612 if (!access_ok((char __user *)pos, len))
613 return -EFAULT;
614
615 tmp_data = kzalloc(len + 1, GFP_KERNEL);
616 if (!tmp_data)
617 return -ENOMEM;
618 *data = tmp_data;
619
620 if (copy_from_user(tmp_data, (char __user *)pos, len))
621 return -EFAULT;
622
623 return 0;
624 }
625
hmdfs_get_info_from_user(unsigned long pos, struct hmdfs_dst_info *hdi, struct hmdfs_user_info *data)626 static int hmdfs_get_info_from_user(unsigned long pos,
627 struct hmdfs_dst_info *hdi, struct hmdfs_user_info *data)
628 {
629 int ret = 0;
630
631 if (!access_ok((struct hmdfs_dst_info __user *)pos,
632 sizeof(struct hmdfs_dst_info)))
633 return -ENOMEM;
634 if (copy_from_user(hdi, (struct hmdfs_dst_info __user *)pos,
635 sizeof(struct hmdfs_dst_info)))
636 return -EFAULT;
637
638 ret = copy_string_from_user(hdi->local_path_pos, hdi->local_path_len,
639 &data->local_path);
640 if (ret != 0)
641 return ret;
642
643 ret = copy_string_from_user(hdi->distributed_path_pos,
644 hdi->distributed_path_len,
645 &data->distributed_path);
646 if (ret != 0)
647 return ret;
648
649 ret = copy_string_from_user(hdi->bundle_name_pos, hdi->bundle_name_len,
650 &data->bundle_name);
651 if (ret != 0)
652 return ret;
653
654 return 0;
655 }
656
change_cred(struct dentry *dentry, const char *bundle_name)657 static const struct cred *change_cred(struct dentry *dentry,
658 const char *bundle_name)
659 {
660 int bid;
661 struct cred *cred = NULL;
662 const struct cred *old_cred = NULL;
663
664 cred = prepare_creds();
665 if (!cred) {
666 return NULL;
667 }
668 bid = get_bundle_uid(hmdfs_sb(dentry->d_sb), bundle_name);
669 if (bid != 0) {
670 cred->fsuid = KUIDT_INIT(bid);
671 cred->fsgid = KGIDT_INIT(bid);
672 old_cred = override_creds(cred);
673 }
674
675 return old_cred;
676 }
677
get_file_size(const char *path_value, uint64_t pos)678 static int get_file_size(const char *path_value, uint64_t pos)
679 {
680 int ret;
681 uint64_t size;
682 struct path path;
683 struct kstat buf;
684
685 ret = kern_path(path_value, 0, &path);
686 if (ret)
687 return ret;
688 ret = vfs_getattr(&path, &buf, STATX_BASIC_STATS | STATX_BTIME, 0);
689 path_put(&path);
690 if (ret) {
691 hmdfs_err("call vfs_getattr failed, err %d", ret);
692 return ret;
693 }
694
695 size = buf.size;
696 ret = copy_to_user((uint64_t __user *)pos, &size, sizeof(uint64_t));
697 return ret;
698 }
699
create_link_file(struct hmdfs_user_info *data)700 static int create_link_file(struct hmdfs_user_info *data)
701 {
702 int ret;
703 struct dentry *dentry;
704 struct path path;
705
706 ret = kern_path(data->distributed_path, 0, &path);
707 if (ret == 0){
708 path_put(&path);
709 return ret;
710 }
711
712 dentry = kern_path_create(AT_FDCWD, data->distributed_path, &path, 0);
713 if (IS_ERR(dentry))
714 return PTR_ERR(dentry);
715 ret = vfs_symlink(&nop_mnt_idmap, path.dentry->d_inode, dentry, data->local_path);
716 done_path_create(&path, dentry);
717
718 return ret;
719 }
720
create_dir(const char *path_value, mode_t mode)721 static int create_dir(const char *path_value, mode_t mode)
722 {
723 int err = 0;
724 struct path path;
725 struct dentry *dentry;
726
727 dentry = kern_path_create(AT_FDCWD, path_value, &path, LOOKUP_DIRECTORY);
728 if(PTR_ERR(dentry) == -EEXIST)
729 return 0;
730 if (IS_ERR(dentry))
731 return PTR_ERR(dentry);
732
733 err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode);
734 if (err && err != -EEXIST)
735 hmdfs_err("vfs_mkdir failed, err = %d", err);
736 done_path_create(&path, dentry);
737
738 return err;
739 }
740
create_dir_recursive(const char *path_value, mode_t mode)741 static int create_dir_recursive(const char *path_value, mode_t mode)
742 {
743 int err = 0;
744 char *tmp_path = kstrdup(path_value, GFP_KERNEL);
745 char *p = tmp_path;
746
747 if (!tmp_path)
748 return -ENOMEM;
749
750 if (*p == '/')
751 p++;
752
753 while (*p) {
754 if (*p == '/') {
755 *p = '\0';
756 err = create_dir(tmp_path, mode);
757 if (err != 0)
758 break;
759 *p = '/';
760 }
761 p++;
762 }
763
764 kfree(tmp_path);
765 return err;
766 }
767
hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg)768 static long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg)
769 {
770 int ret = 0;
771 const struct cred *old_cred;
772 struct hmdfs_dst_info hdi;
773 struct hmdfs_user_info *data;
774
775 data = kzalloc(sizeof(*data), GFP_KERNEL);
776 if (!data) {
777 ret = -ENOMEM;
778 goto err_free_data;
779 }
780
781 ret = hmdfs_get_info_from_user(arg, &hdi, data);
782 if (ret != 0)
783 goto err_free_all;
784
785 old_cred = change_cred(filp->f_path.dentry, data->bundle_name);
786 if (!old_cred) {
787 ret = -EACCES;
788 goto err_free_all;
789 }
790
791 ret = create_dir_recursive(data->distributed_path, DIR_MODE);
792 if (ret != 0)
793 goto err_revert;
794
795 ret = create_link_file(data);
796 if (ret != 0 && ret != -EEXIST)
797 goto err_revert;
798
799 ret = get_file_size(data->local_path, hdi.size);
800
801 err_revert:
802 revert_creds(old_cred);
803 err_free_all:
804 kfree(data->local_path);
805 kfree(data->distributed_path);
806 kfree(data->bundle_name);
807 err_free_data:
808 kfree(data);
809 return ret;
810 }
811
hmdfs_file_ioctl_merge(struct file *filp, unsigned int cmd, unsigned long arg)812 static long hmdfs_file_ioctl_merge(struct file *filp, unsigned int cmd, unsigned long arg)
813 {
814 switch (cmd) {
815 case HMDFS_IOC_GET_WRITEOPEN_CNT:
816 return hmdfs_ioc_get_writeopen_cnt(filp, arg);
817 case HMDFS_IOC_GET_DST_PATH:
818 return hmdfs_ioc_get_dst_path(filp, arg);
819 default:
820 return -ENOTTY;
821 }
822 }
823
824 /* Transparent transmission of parameters to device_view level,
825 * so file operations are same as device_view local operations.
826 */
827 const struct file_operations hmdfs_file_fops_merge = {
828 .owner = THIS_MODULE,
829 .llseek = hmdfs_file_llseek_local,
830 .read_iter = hmdfs_merge_read_iter,
831 .write_iter = hmdfs_merge_write_iter,
832 .mmap = hmdfs_file_mmap_local,
833 .open = hmdfs_file_open_merge,
834 .flush = hmdfs_file_flush_merge,
835 .release = hmdfs_file_release_local,
836 .fsync = hmdfs_fsync_local,
837 .unlocked_ioctl = hmdfs_file_ioctl_merge,
838 .compat_ioctl = hmdfs_file_ioctl_merge,
839 .splice_read = copy_splice_read,
840 .splice_write = iter_file_splice_write,
841 };
842