diff options
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 645a17927a8f..ac2a28f4fa1a 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -48,6 +48,7 @@ | |||
48 | #include "print-tree.h" | 48 | #include "print-tree.h" |
49 | #include "volumes.h" | 49 | #include "volumes.h" |
50 | #include "locking.h" | 50 | #include "locking.h" |
51 | #include "ctree.h" | ||
51 | 52 | ||
52 | /* Mask out flags that are inappropriate for the given type of inode. */ | 53 | /* Mask out flags that are inappropriate for the given type of inode. */ |
53 | static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) | 54 | static inline __u32 btrfs_mask_flags(umode_t mode, __u32 flags) |
@@ -743,6 +744,97 @@ out: | |||
743 | return ret; | 744 | return ret; |
744 | } | 745 | } |
745 | 746 | ||
747 | /* | ||
748 | Search INODE_REFs to identify path name of 'dirid' directory | ||
749 | in a 'tree_id' tree. and sets path name to 'name'. | ||
750 | */ | ||
751 | static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, | ||
752 | u64 tree_id, u64 dirid, char *name) | ||
753 | { | ||
754 | struct btrfs_root *root; | ||
755 | struct btrfs_key key; | ||
756 | char *name_stack, *ptr; | ||
757 | int ret = -1; | ||
758 | int slot; | ||
759 | int len; | ||
760 | int total_len = 0; | ||
761 | struct btrfs_inode_ref *iref; | ||
762 | struct extent_buffer *l; | ||
763 | struct btrfs_path *path; | ||
764 | |||
765 | if (dirid == BTRFS_FIRST_FREE_OBJECTID) { | ||
766 | name[0]='\0'; | ||
767 | return 0; | ||
768 | } | ||
769 | |||
770 | path = btrfs_alloc_path(); | ||
771 | if (!path) | ||
772 | return -ENOMEM; | ||
773 | |||
774 | name_stack = kzalloc(BTRFS_PATH_NAME_MAX+1, GFP_NOFS); | ||
775 | if (!name_stack) { | ||
776 | btrfs_free_path(path); | ||
777 | return -ENOMEM; | ||
778 | } | ||
779 | |||
780 | ptr = &name_stack[BTRFS_PATH_NAME_MAX]; | ||
781 | |||
782 | key.objectid = tree_id; | ||
783 | key.type = BTRFS_ROOT_ITEM_KEY; | ||
784 | key.offset = (u64)-1; | ||
785 | root = btrfs_read_fs_root_no_name(info, &key); | ||
786 | if (IS_ERR(root)) { | ||
787 | printk(KERN_ERR "could not find root %llu\n", tree_id); | ||
788 | return -ENOENT; | ||
789 | } | ||
790 | |||
791 | key.objectid = dirid; | ||
792 | key.type = BTRFS_INODE_REF_KEY; | ||
793 | key.offset = 0; | ||
794 | |||
795 | while(1) { | ||
796 | ret = btrfs_search_slot(NULL, root, &key, path, 0, 0); | ||
797 | if (ret < 0) | ||
798 | goto out; | ||
799 | |||
800 | l = path->nodes[0]; | ||
801 | slot = path->slots[0]; | ||
802 | btrfs_item_key_to_cpu(l, &key, slot); | ||
803 | |||
804 | if (ret > 0 && (key.objectid != dirid || | ||
805 | key.type != BTRFS_INODE_REF_KEY)) | ||
806 | goto out; | ||
807 | |||
808 | iref = btrfs_item_ptr(l, slot, struct btrfs_inode_ref); | ||
809 | len = btrfs_inode_ref_name_len(l, iref); | ||
810 | ptr -= len + 1; | ||
811 | total_len += len + 1; | ||
812 | if (ptr < name_stack) | ||
813 | goto out; | ||
814 | |||
815 | *(ptr + len) = '/'; | ||
816 | read_extent_buffer(l, ptr,(unsigned long)(iref + 1), len); | ||
817 | |||
818 | if (key.offset == BTRFS_FIRST_FREE_OBJECTID) | ||
819 | break; | ||
820 | |||
821 | btrfs_release_path(root, path); | ||
822 | key.objectid = key.offset; | ||
823 | key.offset = 0; | ||
824 | dirid = key.objectid; | ||
825 | |||
826 | } | ||
827 | if (ptr < name_stack) | ||
828 | goto out; | ||
829 | strncpy(name, ptr, total_len); | ||
830 | name[total_len]='\0'; | ||
831 | ret = 0; | ||
832 | out: | ||
833 | btrfs_free_path(path); | ||
834 | kfree(name_stack); | ||
835 | return ret; | ||
836 | } | ||
837 | |||
746 | static noinline int btrfs_ioctl_snap_destroy(struct file *file, | 838 | static noinline int btrfs_ioctl_snap_destroy(struct file *file, |
747 | void __user *arg) | 839 | void __user *arg) |
748 | { | 840 | { |