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 * -EINVAL, buffer is exhausted
23 * -EINTR, current task is pending
24 * -EFAULT, something is wrong
25 * 0, success and can do more
26 */
27 int 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,loff_t offset,u64 ino,unsigned int d_type)209 static int hmdfs_actor_merge(struct dir_context *ctx, const char *name,
210 int namelen, loff_t offset, u64 ino,
211 unsigned int d_type)
212 {
213 int ret = 0;
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 return 0;
224
225 if (namelen > NAME_MAX)
226 return -EINVAL;
227 dentry_name = kzalloc(NAME_MAX + 1, GFP_KERNEL);
228 if (!dentry_name)
229 return -ENOMEM;
230
231 strncpy(dentry_name, name, dentry_len);
232
233 cache_entry = allocate_entry(dentry_name, dentry_len, d_type);
234 if (IS_ERR(cache_entry)) {
235 ret = PTR_ERR(cache_entry);
236 goto done;
237 }
238
239 iterate_callback_merge =
240 container_of(ctx, struct hmdfs_iterate_callback_merge, ctx);
241 insert_res =
242 insert_filename(iterate_callback_merge->root, &cache_entry);
243 if (d_type == DT_DIR && insert_res == DT_DIR) {
244 goto done;
245 } else if (d_type == DT_DIR &&
246 (insert_res == DT_REG || insert_res == DT_LNK)) {
247 if (strlen(CONFLICTING_DIR_SUFFIX) > NAME_MAX - dentry_len) {
248 ret = -ENAMETOOLONG;
249 goto delete;
250 }
251 rename_conflicting_directory(dentry_name, &dentry_len);
252 cache_entry->file_type = DT_DIR;
253 } else if ((d_type == DT_REG || d_type == DT_LNK) && insert_res > 0) {
254 if (strlen(CONFLICTING_FILE_SUFFIX) + max_devid_len >
255 NAME_MAX - dentry_len) {
256 ret = -ENAMETOOLONG;
257 goto delete;
258 }
259 rename_conflicting_file(dentry_name, &dentry_len,
260 iterate_callback_merge->dev_id);
261 }
262
263 org_ctx = iterate_callback_merge->caller;
264 ret = org_ctx->actor(org_ctx, dentry_name, dentry_len, org_ctx->pos,
265 ino, d_type);
266 /*
267 * Record original return value, so that the caller can be aware of
268 * different situations.
269 */
270 iterate_callback_merge->result = ret;
271 ret = ret == 0 ? 0 : 1;
272 if (ret && d_type == DT_DIR && cache_entry->file_type == DT_DIR &&
273 (insert_res == DT_REG || insert_res == DT_LNK))
274 cache_entry->file_type = DT_REG;
275
276 delete:
277 if (ret && !insert_res)
278 delete_filename(iterate_callback_merge->root, cache_entry);
279 done:
280 kfree(dentry_name);
281 return ret;
282 }
283
284 struct hmdfs_file_info *
get_next_hmdfs_file_info(struct hmdfs_file_info * fi_head,int device_id)285 get_next_hmdfs_file_info(struct hmdfs_file_info *fi_head, int device_id)
286 {
287 struct hmdfs_file_info *fi_iter = NULL;
288 struct hmdfs_file_info *fi_result = NULL;
289
290 mutex_lock(&fi_head->comrade_list_lock);
291 list_for_each_entry_safe(fi_iter, fi_result, &(fi_head->comrade_list),
292 comrade_list) {
293 if (fi_iter->device_id == device_id)
294 break;
295 }
296 mutex_unlock(&fi_head->comrade_list_lock);
297
298 return fi_result != fi_head ? fi_result : NULL;
299 }
300
get_hmdfs_file_info(struct hmdfs_file_info * fi_head,int device_id)301 struct hmdfs_file_info *get_hmdfs_file_info(struct hmdfs_file_info *fi_head,
302 int device_id)
303 {
304 struct hmdfs_file_info *fi_iter = NULL;
305
306 mutex_lock(&fi_head->comrade_list_lock);
307 list_for_each_entry(fi_iter, &(fi_head->comrade_list), comrade_list) {
308 if (fi_iter->device_id == device_id) {
309 mutex_unlock(&fi_head->comrade_list_lock);
310 return fi_iter;
311 }
312 }
313 mutex_unlock(&fi_head->comrade_list_lock);
314
315 return NULL;
316 }
317
hmdfs_iterate_merge(struct file * file,struct dir_context * ctx)318 int hmdfs_iterate_merge(struct file *file, struct dir_context *ctx)
319 {
320 int err = 0;
321 struct hmdfs_file_info *fi_head = hmdfs_f(file);
322 struct hmdfs_file_info *fi_iter = NULL;
323 struct file *lower_file_iter = NULL;
324 loff_t start_pos = ctx->pos;
325 unsigned long device_id = (unsigned long)((ctx->pos) << 1 >>
326 (POS_BIT_NUM - DEV_ID_BIT_NUM));
327 struct hmdfs_iterate_callback_merge ctx_merge = {
328 .ctx.actor = hmdfs_actor_merge,
329 .caller = ctx,
330 .root = &fi_head->root,
331 .dev_id = device_id
332 };
333
334 /* pos = -1 indicates that all devices have been traversed
335 * or an error has occurred.
336 */
337 if (ctx->pos == -1)
338 return 0;
339
340 fi_iter = get_hmdfs_file_info(fi_head, device_id);
341 if (!fi_iter) {
342 fi_iter = get_next_hmdfs_file_info(fi_head, device_id);
343 // dev_id is changed, parameter is set 0 to get next file info
344 if (fi_iter)
345 ctx_merge.ctx.pos =
346 hmdfs_set_pos(fi_iter->device_id, 0, 0);
347 }
348 while (fi_iter) {
349 ctx_merge.dev_id = fi_iter->device_id;
350 device_id = ctx_merge.dev_id;
351 lower_file_iter = fi_iter->lower_file;
352 lower_file_iter->f_pos = file->f_pos;
353 err = iterate_dir(lower_file_iter, &ctx_merge.ctx);
354 file->f_pos = lower_file_iter->f_pos;
355 ctx->pos = file->f_pos;
356
357 if (err)
358 goto done;
359 /*
360 * ctx->actor return nonzero means buffer is exhausted or
361 * something is wrong, thus we should not continue.
362 */
363 if (ctx_merge.result)
364 goto done;
365 fi_iter = get_next_hmdfs_file_info(fi_head, device_id);
366 if (fi_iter) {
367 file->f_pos = hmdfs_set_pos(fi_iter->device_id, 0, 0);
368 ctx->pos = file->f_pos;
369 }
370 }
371 done:
372 trace_hmdfs_iterate_merge(file->f_path.dentry, start_pos, ctx->pos,
373 err);
374 return err;
375 }
376
do_dir_open_merge(struct file * file,const struct cred * cred,struct hmdfs_file_info * fi_head)377 int do_dir_open_merge(struct file *file, const struct cred *cred,
378 struct hmdfs_file_info *fi_head)
379 {
380 int ret = -EINVAL;
381 struct hmdfs_dentry_info_merge *dim = hmdfs_dm(file->f_path.dentry);
382 struct hmdfs_dentry_comrade *comrade = NULL;
383 struct hmdfs_file_info *fi = NULL;
384 struct path lo_p = { .mnt = file->f_path.mnt };
385 struct file *lower_file = NULL;
386
387 if (IS_ERR_OR_NULL(cred))
388 return ret;
389
390 wait_event(dim->wait_queue, !has_merge_lookup_work(dim));
391
392 mutex_lock(&dim->comrade_list_lock);
393 list_for_each_entry(comrade, &(dim->comrade_list), list) {
394 fi = kzalloc(sizeof(*fi), GFP_KERNEL);
395 if (!fi) {
396 ret = ret ? -ENOMEM : 0;
397 continue; // allow some dir to fail to open
398 }
399 lo_p.dentry = comrade->lo_d;
400 // make sure that dentry will not be dentry_kill before open
401 dget(lo_p.dentry);
402 if (unlikely(d_is_negative(lo_p.dentry))) {
403 hmdfs_info("dentry is negative, try again");
404 kfree(fi);
405 dput(lo_p.dentry);
406 continue; // skip this device
407 }
408 lower_file = dentry_open(&lo_p, file->f_flags, cred);
409 dput(lo_p.dentry);
410 if (IS_ERR(lower_file)) {
411 kfree(fi);
412 continue;
413 }
414 ret = 0;
415 fi->device_id = comrade->dev_id;
416 fi->lower_file = lower_file;
417 mutex_lock(&fi_head->comrade_list_lock);
418 list_add_tail(&fi->comrade_list, &fi_head->comrade_list);
419 mutex_unlock(&fi_head->comrade_list_lock);
420 }
421 mutex_unlock(&dim->comrade_list_lock);
422 return ret;
423 }
424
hmdfs_dir_open_merge(struct inode * inode,struct file * file)425 int hmdfs_dir_open_merge(struct inode *inode, struct file *file)
426 {
427 int ret = 0;
428 struct hmdfs_file_info *fi = NULL;
429
430 fi = kzalloc(sizeof(*fi), GFP_KERNEL);
431 if (!fi)
432 return -ENOMEM;
433
434 file->private_data = fi;
435 fi->root = RB_ROOT;
436 mutex_init(&fi->comrade_list_lock);
437 INIT_LIST_HEAD(&fi->comrade_list);
438
439 ret = do_dir_open_merge(file, hmdfs_sb(inode->i_sb)->cred, fi);
440 if (ret)
441 kfree(fi);
442
443 return ret;
444 }
445
hmdfs_dir_release_merge(struct inode * inode,struct file * file)446 int hmdfs_dir_release_merge(struct inode *inode, struct file *file)
447 {
448 struct hmdfs_file_info *fi_head = hmdfs_f(file);
449 struct hmdfs_file_info *fi_iter = NULL;
450 struct hmdfs_file_info *fi_temp = NULL;
451
452 mutex_lock(&fi_head->comrade_list_lock);
453 list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
454 comrade_list) {
455 list_del_init(&(fi_iter->comrade_list));
456 fput(fi_iter->lower_file);
457 kfree(fi_iter);
458 }
459 mutex_unlock(&fi_head->comrade_list_lock);
460 destroy_tree(&fi_head->root);
461 file->private_data = NULL;
462 kfree(fi_head);
463
464 return 0;
465 }
466
467 static long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg);
468
hmdfs_dir_unlocked_ioctl_merge(struct file * file,unsigned int cmd,unsigned long arg)469 long hmdfs_dir_unlocked_ioctl_merge(struct file *file, unsigned int cmd,
470 unsigned long arg)
471 {
472 struct hmdfs_file_info *fi_head = hmdfs_f(file);
473 struct hmdfs_file_info *fi_iter = NULL;
474 struct hmdfs_file_info *fi_temp = NULL;
475 struct file *lower_file = NULL;
476 int error = -ENOTTY;
477
478 if (cmd == HMDFS_IOC_GET_DST_PATH)
479 return hmdfs_ioc_get_dst_path(file, arg);
480 mutex_lock(&fi_head->comrade_list_lock);
481 list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
482 comrade_list) {
483 if (fi_iter->device_id == 0) {
484 lower_file = fi_iter->lower_file;
485 if (lower_file->f_op->unlocked_ioctl)
486 error = lower_file->f_op->unlocked_ioctl(
487 lower_file, cmd, arg);
488 break;
489 }
490 }
491 mutex_unlock(&fi_head->comrade_list_lock);
492 return error;
493 }
494
hmdfs_dir_compat_ioctl_merge(struct file * file,unsigned int cmd,unsigned long arg)495 long hmdfs_dir_compat_ioctl_merge(struct file *file, unsigned int cmd,
496 unsigned long arg)
497 {
498 struct hmdfs_file_info *fi_head = hmdfs_f(file);
499 struct hmdfs_file_info *fi_iter = NULL;
500 struct hmdfs_file_info *fi_temp = NULL;
501 struct file *lower_file = NULL;
502 int error = -ENOTTY;
503
504 if (cmd == HMDFS_IOC_GET_DST_PATH)
505 return hmdfs_ioc_get_dst_path(file, arg);
506 mutex_lock(&fi_head->comrade_list_lock);
507 list_for_each_entry_safe(fi_iter, fi_temp, &(fi_head->comrade_list),
508 comrade_list) {
509 if (fi_iter->device_id == 0) {
510 lower_file = fi_iter->lower_file;
511 if (lower_file->f_op->compat_ioctl)
512 error = lower_file->f_op->compat_ioctl(
513 lower_file, cmd, arg);
514 break;
515 }
516 }
517 mutex_unlock(&fi_head->comrade_list_lock);
518 return error;
519 }
520
521 const struct file_operations hmdfs_dir_fops_merge = {
522 .owner = THIS_MODULE,
523 .iterate = hmdfs_iterate_merge,
524 .open = hmdfs_dir_open_merge,
525 .release = hmdfs_dir_release_merge,
526 .unlocked_ioctl = hmdfs_dir_unlocked_ioctl_merge,
527 .compat_ioctl = hmdfs_dir_compat_ioctl_merge,
528 };
529
hmdfs_merge_read_iter(struct kiocb * iocb,struct iov_iter * iter)530 static ssize_t hmdfs_merge_read_iter(struct kiocb *iocb, struct iov_iter *iter)
531 {
532 return hmdfs_do_read_iter(iocb->ki_filp, iter, &iocb->ki_pos);
533 }
534
hmdfs_merge_write_iter(struct kiocb * iocb,struct iov_iter * iter)535 ssize_t hmdfs_merge_write_iter(struct kiocb *iocb, struct iov_iter *iter)
536 {
537 return hmdfs_do_write_iter(iocb->ki_filp, iter, &iocb->ki_pos);
538 }
539
hmdfs_file_open_merge(struct inode * inode,struct file * file)540 int hmdfs_file_open_merge(struct inode *inode, struct file *file)
541 {
542 int err = 0;
543 struct file *lower_file = NULL;
544 struct path lo_p = { .mnt = file->f_path.mnt };
545 struct super_block *sb = inode->i_sb;
546 const struct cred *cred = hmdfs_sb(sb)->cred;
547 struct hmdfs_file_info *gfi = NULL;
548 struct dentry *parent = NULL;
549
550 lo_p.dentry = hmdfs_get_fst_lo_d(file->f_path.dentry);
551 if (!lo_p.dentry) {
552 err = -EINVAL;
553 goto out_err;
554 }
555
556 gfi = kzalloc(sizeof(*gfi), GFP_KERNEL);
557 if (!gfi) {
558 err = -ENOMEM;
559 goto out_err;
560 }
561
562 parent = dget_parent(file->f_path.dentry);
563 lower_file = dentry_open(&lo_p, file->f_flags, cred);
564 if (IS_ERR(lower_file)) {
565 err = PTR_ERR(lower_file);
566 kfree(gfi);
567 } else {
568 gfi->lower_file = lower_file;
569 file->private_data = gfi;
570 hmdfs_update_upper_file(file, lower_file);
571 }
572 dput(parent);
573 out_err:
574 dput(lo_p.dentry);
575 return err;
576 }
577
hmdfs_file_flush_merge(struct file * file,fl_owner_t id)578 int hmdfs_file_flush_merge(struct file *file, fl_owner_t id)
579 {
580 struct hmdfs_file_info *gfi = hmdfs_f(file);
581 struct file *lower_file = gfi->lower_file;
582
583 if (lower_file->f_op->flush)
584 return lower_file->f_op->flush(lower_file, id);
585
586 return 0;
587 }
588
hmdfs_ioc_get_writeopen_cnt(struct file * filp,unsigned long arg)589 static long hmdfs_ioc_get_writeopen_cnt(struct file *filp, unsigned long arg)
590 {
591 struct hmdfs_file_info *gfi = hmdfs_f(filp);
592 struct file *lower_file = gfi->lower_file;
593 struct inode *lower_inode = file_inode(lower_file);
594
595 u32 wo_cnt = atomic_read(&(hmdfs_i(lower_inode))->write_opened);
596
597 return put_user(wo_cnt, (int __user *)arg);
598 }
599
copy_string_from_user(unsigned long pos,unsigned long len,char ** data)600 static int copy_string_from_user(unsigned long pos, unsigned long len,
601 char **data)
602 {
603 char *tmp_data;
604
605 if (len >= PATH_MAX)
606 return -EINVAL;
607 if (!access_ok(pos, len))
608 return -EFAULT;
609
610 tmp_data = kzalloc(len + 1, GFP_KERNEL);
611 if (!tmp_data)
612 return -ENOMEM;
613 *data = tmp_data;
614
615 if (copy_from_user(tmp_data, (char __user *)pos, len))
616 return -EFAULT;
617
618 return 0;
619 }
620
hmdfs_get_info_from_user(unsigned long pos,struct hmdfs_dst_info * hdi,struct hmdfs_user_info * data)621 static int hmdfs_get_info_from_user(unsigned long pos,
622 struct hmdfs_dst_info *hdi, struct hmdfs_user_info *data)
623 {
624 int ret = 0;
625
626 if (!access_ok((struct hmdfs_dst_info __user *)pos,
627 sizeof(struct hmdfs_dst_info)))
628 return -ENOMEM;
629 if (copy_from_user(hdi, (struct hmdfs_dst_info __user *)pos,
630 sizeof(struct hmdfs_dst_info)))
631 return -EFAULT;
632
633 ret = copy_string_from_user(hdi->local_path_pos, hdi->local_path_len,
634 &data->local_path);
635 if (ret != 0)
636 return ret;
637
638 ret = copy_string_from_user(hdi->distributed_path_pos,
639 hdi->distributed_path_len,
640 &data->distributed_path);
641 if (ret != 0)
642 return ret;
643
644 ret = copy_string_from_user(hdi->bundle_name_pos, hdi->bundle_name_len,
645 &data->bundle_name);
646 if (ret != 0)
647 return ret;
648
649 return 0;
650 }
651
change_cred(struct dentry * dentry,const char * bundle_name)652 static const struct cred *change_cred(struct dentry *dentry,
653 const char *bundle_name)
654 {
655 int bid;
656 struct cred *cred = NULL;
657 const struct cred *old_cred = NULL;
658
659 cred = prepare_creds();
660 if (!cred) {
661 return NULL;
662 }
663 bid = get_bundle_uid(hmdfs_sb(dentry->d_sb), bundle_name);
664 if (bid != 0) {
665 cred->fsuid = KUIDT_INIT(bid);
666 cred->fsgid = KGIDT_INIT(bid);
667 old_cred = override_creds(cred);
668 }
669
670 return old_cred;
671 }
672
get_file_size(const char * path_value,uint64_t pos)673 static int get_file_size(const char *path_value, uint64_t pos)
674 {
675 int ret;
676 uint64_t size;
677 struct path path;
678 struct kstat buf;
679
680 ret = kern_path(path_value, 0, &path);
681 if (ret)
682 return ret;
683 ret = vfs_getattr(&path, &buf, STATX_BASIC_STATS | STATX_BTIME, 0);
684 path_put(&path);
685 if (ret) {
686 hmdfs_err("call vfs_getattr failed, err %d", ret);
687 return ret;
688 }
689
690 size = buf.size;
691 ret = copy_to_user((uint64_t __user *)pos, &size, sizeof(uint64_t));
692 return ret;
693 }
694
create_link_file(struct hmdfs_user_info * data)695 static int create_link_file(struct hmdfs_user_info *data)
696 {
697 int ret;
698 struct dentry *dentry;
699 struct path path;
700
701 ret = kern_path(data->distributed_path, 0, &path);
702 if (ret == 0){
703 path_put(&path);
704 return ret;
705 }
706
707 dentry = kern_path_create(AT_FDCWD, data->distributed_path, &path, 0);
708 if (IS_ERR(dentry))
709 return PTR_ERR(dentry);
710 ret = vfs_symlink(path.dentry->d_inode, dentry, data->local_path);
711 done_path_create(&path, dentry);
712
713 return ret;
714 }
715
create_dir(const char * path_value,mode_t mode)716 static int create_dir(const char *path_value, mode_t mode)
717 {
718 int err = 0;
719 struct path path;
720 struct dentry *dentry;
721
722 dentry = kern_path_create(AT_FDCWD, path_value, &path, LOOKUP_DIRECTORY);
723 if(PTR_ERR(dentry) == -EEXIST)
724 return 0;
725 if (IS_ERR(dentry))
726 return PTR_ERR(dentry);
727
728 err = vfs_mkdir(d_inode(path.dentry), dentry, mode);
729 if (err && err != -EEXIST)
730 hmdfs_err("vfs_mkdir failed, err = %d", err);
731 done_path_create(&path, dentry);
732
733 return err;
734 }
735
create_dir_recursive(const char * path_value,mode_t mode)736 static int create_dir_recursive(const char *path_value, mode_t mode)
737 {
738 int err = 0;
739 char *tmp_path = kstrdup(path_value, GFP_KERNEL);
740 char *p = tmp_path;
741
742 if (!tmp_path)
743 return -ENOMEM;
744
745 if (*p == '/')
746 p++;
747
748 while (*p) {
749 if (*p == '/') {
750 *p = '\0';
751 err = create_dir(tmp_path, mode);
752 if (err != 0)
753 break;
754 *p = '/';
755 }
756 p++;
757 }
758
759 kfree(tmp_path);
760 return err;
761 }
762
hmdfs_ioc_get_dst_path(struct file * filp,unsigned long arg)763 static long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg)
764 {
765 int ret = 0;
766 const struct cred *old_cred;
767 struct hmdfs_dst_info hdi;
768 struct hmdfs_user_info *data;
769
770 data = kzalloc(sizeof(*data), GFP_KERNEL);
771 if (!data) {
772 ret = -ENOMEM;
773 goto err_free_data;
774 }
775
776 ret = hmdfs_get_info_from_user(arg, &hdi, data);
777 if (ret != 0)
778 goto err_free_all;
779
780 old_cred = change_cred(filp->f_path.dentry, data->bundle_name);
781 if (!old_cred) {
782 ret = -EACCES;
783 goto err_free_all;
784 }
785
786 ret = create_dir_recursive(data->distributed_path, DIR_MODE);
787 if (ret != 0)
788 goto err_revert;
789
790 ret = create_link_file(data);
791 if (ret != 0 && ret != -EEXIST)
792 goto err_revert;
793
794 ret = get_file_size(data->local_path, hdi.size);
795
796 err_revert:
797 revert_creds(old_cred);
798 err_free_all:
799 kfree(data->local_path);
800 kfree(data->distributed_path);
801 kfree(data->bundle_name);
802 err_free_data:
803 kfree(data);
804 return ret;
805 }
806
hmdfs_file_ioctl_merge(struct file * filp,unsigned int cmd,unsigned long arg)807 static long hmdfs_file_ioctl_merge(struct file *filp, unsigned int cmd, unsigned long arg)
808 {
809 switch (cmd) {
810 case HMDFS_IOC_GET_WRITEOPEN_CNT:
811 return hmdfs_ioc_get_writeopen_cnt(filp, arg);
812 case HMDFS_IOC_GET_DST_PATH:
813 return hmdfs_ioc_get_dst_path(filp, arg);
814 default:
815 return -ENOTTY;
816 }
817 }
818
819 /* Transparent transmission of parameters to device_view level,
820 * so file operations are same as device_view local operations.
821 */
822 const struct file_operations hmdfs_file_fops_merge = {
823 .owner = THIS_MODULE,
824 .llseek = hmdfs_file_llseek_local,
825 .read_iter = hmdfs_merge_read_iter,
826 .write_iter = hmdfs_merge_write_iter,
827 .mmap = hmdfs_file_mmap_local,
828 .open = hmdfs_file_open_merge,
829 .flush = hmdfs_file_flush_merge,
830 .release = hmdfs_file_release_local,
831 .fsync = hmdfs_fsync_local,
832 .unlocked_ioctl = hmdfs_file_ioctl_merge,
833 .compat_ioctl = hmdfs_file_ioctl_merge,
834 .splice_read = generic_file_splice_read,
835 .splice_write = iter_file_splice_write,
836 };
837