diff options
author | Chris Mason <chris.mason@oracle.com> | 2007-05-24 08:34:10 -0400 |
---|---|---|
committer | David Woodhouse <dwmw2@hera.kernel.org> | 2007-05-24 08:34:10 -0400 |
commit | 2b8d99a723a3186a69b5bd941a272dbecae9205b (patch) | |
tree | c3f87b82450110d2df8ac03032bd2e21b8984f19 /fs/btrfs/super.c | |
parent | e06afa839e726959be2166bec4cb85c117e213f1 (diff) |
Btrfs: symlinks and hard links
Signed-off-by: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/super.c')
-rw-r--r-- | fs/btrfs/super.c | 163 |
1 files changed, 147 insertions, 16 deletions
diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index f49cad603ee8..c1a0adde9b1c 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c | |||
@@ -26,11 +26,13 @@ struct btrfs_iget_args { | |||
26 | #define BTRFS_SUPER_MAGIC 0x9123682E | 26 | #define BTRFS_SUPER_MAGIC 0x9123682E |
27 | 27 | ||
28 | static struct inode_operations btrfs_dir_inode_operations; | 28 | static struct inode_operations btrfs_dir_inode_operations; |
29 | static struct inode_operations btrfs_symlink_inode_operations; | ||
29 | static struct inode_operations btrfs_dir_ro_inode_operations; | 30 | static struct inode_operations btrfs_dir_ro_inode_operations; |
30 | static struct super_operations btrfs_super_ops; | 31 | static struct super_operations btrfs_super_ops; |
31 | static struct file_operations btrfs_dir_file_operations; | 32 | static struct file_operations btrfs_dir_file_operations; |
32 | static struct inode_operations btrfs_file_inode_operations; | 33 | static struct inode_operations btrfs_file_inode_operations; |
33 | static struct address_space_operations btrfs_aops; | 34 | static struct address_space_operations btrfs_aops; |
35 | static struct address_space_operations btrfs_symlink_aops; | ||
34 | static struct file_operations btrfs_file_operations; | 36 | static struct file_operations btrfs_file_operations; |
35 | 37 | ||
36 | static void btrfs_read_locked_inode(struct inode *inode) | 38 | static void btrfs_read_locked_inode(struct inode *inode) |
@@ -103,7 +105,8 @@ static void btrfs_read_locked_inode(struct inode *inode) | |||
103 | inode->i_op = &btrfs_dir_inode_operations; | 105 | inode->i_op = &btrfs_dir_inode_operations; |
104 | break; | 106 | break; |
105 | case S_IFLNK: | 107 | case S_IFLNK: |
106 | // inode->i_op = &page_symlink_inode_operations; | 108 | inode->i_op = &btrfs_symlink_inode_operations; |
109 | inode->i_mapping->a_ops = &btrfs_symlink_aops; | ||
107 | break; | 110 | break; |
108 | } | 111 | } |
109 | return; | 112 | return; |
@@ -940,6 +943,41 @@ out_unlock: | |||
940 | return err; | 943 | return err; |
941 | } | 944 | } |
942 | 945 | ||
946 | static int btrfs_link(struct dentry *old_dentry, struct inode *dir, | ||
947 | struct dentry *dentry) | ||
948 | { | ||
949 | struct btrfs_trans_handle *trans; | ||
950 | struct btrfs_root *root = BTRFS_I(dir)->root; | ||
951 | struct inode *inode = old_dentry->d_inode; | ||
952 | int err; | ||
953 | int drop_inode = 0; | ||
954 | |||
955 | if (inode->i_nlink == 0) | ||
956 | return -ENOENT; | ||
957 | |||
958 | inc_nlink(inode); | ||
959 | mutex_lock(&root->fs_info->fs_mutex); | ||
960 | trans = btrfs_start_transaction(root, 1); | ||
961 | btrfs_set_trans_block_group(trans, dir); | ||
962 | atomic_inc(&inode->i_count); | ||
963 | err = btrfs_add_nondir(trans, dentry, inode); | ||
964 | if (err) | ||
965 | drop_inode = 1; | ||
966 | dir->i_sb->s_dirt = 1; | ||
967 | btrfs_update_inode_block_group(trans, dir); | ||
968 | btrfs_update_inode(trans, root, inode); | ||
969 | |||
970 | btrfs_end_transaction(trans, root); | ||
971 | mutex_unlock(&root->fs_info->fs_mutex); | ||
972 | |||
973 | if (drop_inode) { | ||
974 | inode_dec_link_count(inode); | ||
975 | iput(inode); | ||
976 | } | ||
977 | btrfs_btree_balance_dirty(root); | ||
978 | return err; | ||
979 | } | ||
980 | |||
943 | static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans, | 981 | static int btrfs_make_empty_dir(struct btrfs_trans_handle *trans, |
944 | struct btrfs_root *root, | 982 | struct btrfs_root *root, |
945 | u64 objectid, u64 dirid) | 983 | u64 objectid, u64 dirid) |
@@ -2577,33 +2615,25 @@ static int btrfs_rename(struct inode * old_dir, struct dentry *old_dentry, | |||
2577 | } | 2615 | } |
2578 | 2616 | ||
2579 | 2617 | ||
2580 | ret = btrfs_add_link(trans, new_dentry, old_inode); | ||
2581 | if (ret == -EEXIST && new_inode) | ||
2582 | ret = 0; | ||
2583 | else if (ret) | ||
2584 | goto out_fail; | ||
2585 | |||
2586 | ret = btrfs_unlink_trans(trans, root, old_dir, old_dentry); | 2618 | ret = btrfs_unlink_trans(trans, root, old_dir, old_dentry); |
2587 | if (ret) | 2619 | if (ret) |
2588 | goto out_fail; | 2620 | goto out_fail; |
2589 | 2621 | ||
2590 | if (new_inode) { | 2622 | if (new_inode) { |
2591 | new_inode->i_ctime = CURRENT_TIME; | 2623 | new_inode->i_ctime = CURRENT_TIME; |
2592 | di = btrfs_lookup_dir_index_item(trans, root, path, | 2624 | ret = btrfs_unlink_trans(trans, root, new_dir, new_dentry); |
2593 | new_dir->i_ino, | 2625 | if (ret) |
2594 | new_inode->i_ino, | 2626 | goto out_fail; |
2595 | new_dentry->d_name.name, | ||
2596 | new_dentry->d_name.len, -1); | ||
2597 | if (di && !IS_ERR(di)) { | ||
2598 | btrfs_del_item(trans, root, path); | ||
2599 | btrfs_release_path(root, path); | ||
2600 | } | ||
2601 | if (S_ISDIR(new_inode->i_mode)) | 2627 | if (S_ISDIR(new_inode->i_mode)) |
2602 | clear_nlink(new_inode); | 2628 | clear_nlink(new_inode); |
2603 | else | 2629 | else |
2604 | drop_nlink(new_inode); | 2630 | drop_nlink(new_inode); |
2605 | btrfs_update_inode(trans, root, new_inode); | 2631 | btrfs_update_inode(trans, root, new_inode); |
2606 | } | 2632 | } |
2633 | ret = btrfs_add_link(trans, new_dentry, old_inode); | ||
2634 | if (ret) | ||
2635 | goto out_fail; | ||
2636 | |||
2607 | out_fail: | 2637 | out_fail: |
2608 | btrfs_free_path(path); | 2638 | btrfs_free_path(path); |
2609 | btrfs_end_transaction(trans, root); | 2639 | btrfs_end_transaction(trans, root); |
@@ -2611,6 +2641,94 @@ out_fail: | |||
2611 | return ret; | 2641 | return ret; |
2612 | } | 2642 | } |
2613 | 2643 | ||
2644 | static int btrfs_symlink(struct inode *dir, struct dentry *dentry, | ||
2645 | const char *symname) | ||
2646 | { | ||
2647 | struct btrfs_trans_handle *trans; | ||
2648 | struct btrfs_root *root = BTRFS_I(dir)->root; | ||
2649 | struct btrfs_path *path; | ||
2650 | struct btrfs_key key; | ||
2651 | struct inode *inode; | ||
2652 | int err; | ||
2653 | int drop_inode = 0; | ||
2654 | u64 objectid; | ||
2655 | int name_len; | ||
2656 | int datasize; | ||
2657 | char *ptr; | ||
2658 | struct btrfs_file_extent_item *ei; | ||
2659 | |||
2660 | name_len = strlen(symname) + 1; | ||
2661 | if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root)) | ||
2662 | return -ENAMETOOLONG; | ||
2663 | mutex_lock(&root->fs_info->fs_mutex); | ||
2664 | trans = btrfs_start_transaction(root, 1); | ||
2665 | btrfs_set_trans_block_group(trans, dir); | ||
2666 | |||
2667 | err = btrfs_find_free_objectid(trans, root, dir->i_ino, &objectid); | ||
2668 | if (err) { | ||
2669 | err = -ENOSPC; | ||
2670 | goto out_unlock; | ||
2671 | } | ||
2672 | |||
2673 | inode = btrfs_new_inode(trans, root, objectid, | ||
2674 | BTRFS_I(dir)->block_group, S_IFLNK|S_IRWXUGO); | ||
2675 | err = PTR_ERR(inode); | ||
2676 | if (IS_ERR(inode)) | ||
2677 | goto out_unlock; | ||
2678 | |||
2679 | btrfs_set_trans_block_group(trans, inode); | ||
2680 | err = btrfs_add_nondir(trans, dentry, inode); | ||
2681 | if (err) | ||
2682 | drop_inode = 1; | ||
2683 | else { | ||
2684 | inode->i_mapping->a_ops = &btrfs_aops; | ||
2685 | inode->i_fop = &btrfs_file_operations; | ||
2686 | inode->i_op = &btrfs_file_inode_operations; | ||
2687 | } | ||
2688 | dir->i_sb->s_dirt = 1; | ||
2689 | btrfs_update_inode_block_group(trans, inode); | ||
2690 | btrfs_update_inode_block_group(trans, dir); | ||
2691 | if (drop_inode) | ||
2692 | goto out_unlock; | ||
2693 | |||
2694 | path = btrfs_alloc_path(); | ||
2695 | BUG_ON(!path); | ||
2696 | key.objectid = inode->i_ino; | ||
2697 | key.offset = 0; | ||
2698 | key.flags = 0; | ||
2699 | btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY); | ||
2700 | datasize = btrfs_file_extent_calc_inline_size(name_len); | ||
2701 | err = btrfs_insert_empty_item(trans, root, path, &key, | ||
2702 | datasize); | ||
2703 | BUG_ON(err); | ||
2704 | ei = btrfs_item_ptr(btrfs_buffer_leaf(path->nodes[0]), | ||
2705 | path->slots[0], struct btrfs_file_extent_item); | ||
2706 | btrfs_set_file_extent_generation(ei, trans->transid); | ||
2707 | btrfs_set_file_extent_type(ei, | ||
2708 | BTRFS_FILE_EXTENT_INLINE); | ||
2709 | ptr = btrfs_file_extent_inline_start(ei); | ||
2710 | btrfs_memcpy(root, path->nodes[0]->b_data, | ||
2711 | ptr, symname, name_len); | ||
2712 | mark_buffer_dirty(path->nodes[0]); | ||
2713 | btrfs_free_path(path); | ||
2714 | inode->i_op = &btrfs_symlink_inode_operations; | ||
2715 | inode->i_mapping->a_ops = &btrfs_symlink_aops; | ||
2716 | inode->i_size = name_len - 1; | ||
2717 | btrfs_update_inode(trans, root, inode); | ||
2718 | err = 0; | ||
2719 | |||
2720 | out_unlock: | ||
2721 | btrfs_end_transaction(trans, root); | ||
2722 | mutex_unlock(&root->fs_info->fs_mutex); | ||
2723 | |||
2724 | if (drop_inode) { | ||
2725 | inode_dec_link_count(inode); | ||
2726 | iput(inode); | ||
2727 | } | ||
2728 | btrfs_btree_balance_dirty(root); | ||
2729 | return err; | ||
2730 | } | ||
2731 | |||
2614 | static struct file_system_type btrfs_fs_type = { | 2732 | static struct file_system_type btrfs_fs_type = { |
2615 | .owner = THIS_MODULE, | 2733 | .owner = THIS_MODULE, |
2616 | .name = "btrfs", | 2734 | .name = "btrfs", |
@@ -2636,9 +2754,11 @@ static struct inode_operations btrfs_dir_inode_operations = { | |||
2636 | .lookup = btrfs_lookup, | 2754 | .lookup = btrfs_lookup, |
2637 | .create = btrfs_create, | 2755 | .create = btrfs_create, |
2638 | .unlink = btrfs_unlink, | 2756 | .unlink = btrfs_unlink, |
2757 | .link = btrfs_link, | ||
2639 | .mkdir = btrfs_mkdir, | 2758 | .mkdir = btrfs_mkdir, |
2640 | .rmdir = btrfs_rmdir, | 2759 | .rmdir = btrfs_rmdir, |
2641 | .rename = btrfs_rename, | 2760 | .rename = btrfs_rename, |
2761 | .symlink = btrfs_symlink, | ||
2642 | }; | 2762 | }; |
2643 | 2763 | ||
2644 | static struct inode_operations btrfs_dir_ro_inode_operations = { | 2764 | static struct inode_operations btrfs_dir_ro_inode_operations = { |
@@ -2660,6 +2780,11 @@ static struct address_space_operations btrfs_aops = { | |||
2660 | .commit_write = btrfs_commit_write, | 2780 | .commit_write = btrfs_commit_write, |
2661 | }; | 2781 | }; |
2662 | 2782 | ||
2783 | static struct address_space_operations btrfs_symlink_aops = { | ||
2784 | .readpage = btrfs_readpage, | ||
2785 | .writepage = btrfs_writepage, | ||
2786 | }; | ||
2787 | |||
2663 | static struct inode_operations btrfs_file_inode_operations = { | 2788 | static struct inode_operations btrfs_file_inode_operations = { |
2664 | .truncate = btrfs_truncate, | 2789 | .truncate = btrfs_truncate, |
2665 | .getattr = btrfs_getattr, | 2790 | .getattr = btrfs_getattr, |
@@ -2676,6 +2801,12 @@ static struct file_operations btrfs_file_operations = { | |||
2676 | .fsync = btrfs_sync_file, | 2801 | .fsync = btrfs_sync_file, |
2677 | }; | 2802 | }; |
2678 | 2803 | ||
2804 | static struct inode_operations btrfs_symlink_inode_operations = { | ||
2805 | .readlink = generic_readlink, | ||
2806 | .follow_link = page_follow_link_light, | ||
2807 | .put_link = page_put_link, | ||
2808 | }; | ||
2809 | |||
2679 | static int __init init_btrfs_fs(void) | 2810 | static int __init init_btrfs_fs(void) |
2680 | { | 2811 | { |
2681 | int err; | 2812 | int err; |