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 16struct 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 32struct hmdfs_cache_entry { 33 struct rb_node rb_node; 34 int name_len; 35 char *name; 36 int file_type; 37}; 38 39struct hmdfs_user_info { 40 char *local_path; 41 char *distributed_path; 42 char *bundle_name; 43}; 44 45struct 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 66int 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 105static 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 120static 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 128static 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 155found: 156 rb_erase(*node, root); 157 kfree(entry->name); 158 kfree(entry); 159} 160 161static 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 197done: 198 *len = strlen(dentry_name); 199 kfree(buffer); 200} 201 202static 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 209static 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 281delete: 282 if (!ret && !insert_res) 283 delete_filename(iterate_callback_merge->root, cache_entry); 284done: 285 kfree(dentry_name); 286 return ret; 287} 288 289struct hmdfs_file_info * 290get_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 306struct 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 323int 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 } 376done: 377 trace_hmdfs_iterate_merge(file->f_path.dentry, start_pos, ctx->pos, 378 err); 379 return err; 380} 381 382int 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 430int 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 451int 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 472static long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg); 473 474long 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 500long 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 526const 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 535static 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 540ssize_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 545int 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); 578out_err: 579 dput(lo_p.dentry); 580 return err; 581} 582 583int 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 594static 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 605static 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 626static 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 657static 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 678static 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 700static 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 721static 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 741static 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 768static 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 801err_revert: 802 revert_creds(old_cred); 803err_free_all: 804 kfree(data->local_path); 805 kfree(data->distributed_path); 806 kfree(data->bundle_name); 807err_free_data: 808 kfree(data); 809 return ret; 810} 811 812static 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 */ 827const 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