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 * -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 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 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 276delete: 277 if (ret && !insert_res) 278 delete_filename(iterate_callback_merge->root, cache_entry); 279done: 280 kfree(dentry_name); 281 return ret; 282} 283 284struct hmdfs_file_info * 285get_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 301struct 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 318int 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 } 371done: 372 trace_hmdfs_iterate_merge(file->f_path.dentry, start_pos, ctx->pos, 373 err); 374 return err; 375} 376 377int 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 425int 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 446int 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 467static long hmdfs_ioc_get_dst_path(struct file *filp, unsigned long arg); 468 469long 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 495long 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 521const 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 530static 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 535ssize_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 540int 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); 573out_err: 574 dput(lo_p.dentry); 575 return err; 576} 577 578int 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 589static 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 600static 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 621static 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 652static 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 673static 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 695static 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 716static 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 736static 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 763static 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 796err_revert: 797 revert_creds(old_cred); 798err_free_all: 799 kfree(data->local_path); 800 kfree(data->distributed_path); 801 kfree(data->bundle_name); 802err_free_data: 803 kfree(data); 804 return ret; 805} 806 807static 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 */ 822const 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