aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/ioctl.c249
-rw-r--r--fs/btrfs/ioctl.h66
2 files changed, 299 insertions, 16 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index ac2a28f4fa1a..c6044733198d 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -744,16 +744,206 @@ out:
744 return ret; 744 return ret;
745} 745}
746 746
747static noinline int key_in_sk(struct btrfs_key *key,
748 struct btrfs_ioctl_search_key *sk)
749{
750 if (key->objectid < sk->min_objectid)
751 return 0;
752 if (key->offset < sk->min_offset)
753 return 0;
754 if (key->type < sk->min_type)
755 return 0;
756 if (key->objectid > sk->max_objectid)
757 return 0;
758 if (key->type > sk->max_type)
759 return 0;
760 if (key->offset > sk->max_offset)
761 return 0;
762 return 1;
763}
764
765static noinline int copy_to_sk(struct btrfs_root *root,
766 struct btrfs_path *path,
767 struct btrfs_key *key,
768 struct btrfs_ioctl_search_key *sk,
769 char *buf,
770 unsigned long *sk_offset,
771 int *num_found)
772{
773 u64 found_transid;
774 struct extent_buffer *leaf;
775 struct btrfs_ioctl_search_header sh;
776 unsigned long item_off;
777 unsigned long item_len;
778 int nritems;
779 int i;
780 int slot;
781 int found = 0;
782 int ret = 0;
783
784 leaf = path->nodes[0];
785 slot = path->slots[0];
786 nritems = btrfs_header_nritems(leaf);
787
788 if (btrfs_header_generation(leaf) > sk->max_transid) {
789 i = nritems;
790 goto advance_key;
791 }
792 found_transid = btrfs_header_generation(leaf);
793
794 for (i = slot; i < nritems; i++) {
795 item_off = btrfs_item_ptr_offset(leaf, i);
796 item_len = btrfs_item_size_nr(leaf, i);
797
798 if (item_len > BTRFS_SEARCH_ARGS_BUFSIZE)
799 item_len = 0;
800
801 if (sizeof(sh) + item_len + *sk_offset >
802 BTRFS_SEARCH_ARGS_BUFSIZE) {
803 ret = 1;
804 goto overflow;
805 }
806
807 btrfs_item_key_to_cpu(leaf, key, i);
808 if (!key_in_sk(key, sk))
809 continue;
810
811 sh.objectid = key->objectid;
812 sh.offset = key->offset;
813 sh.type = key->type;
814 sh.len = item_len;
815 sh.transid = found_transid;
816
817 /* copy search result header */
818 memcpy(buf + *sk_offset, &sh, sizeof(sh));
819 *sk_offset += sizeof(sh);
820
821 if (item_len) {
822 char *p = buf + *sk_offset;
823 /* copy the item */
824 read_extent_buffer(leaf, p,
825 item_off, item_len);
826 *sk_offset += item_len;
827 found++;
828 }
829
830 if (*num_found >= sk->nr_items)
831 break;
832 }
833advance_key:
834 if (key->offset < (u64)-1)
835 key->offset++;
836 else if (key->type < (u64)-1)
837 key->type++;
838 else if (key->objectid < (u64)-1)
839 key->objectid++;
840 ret = 0;
841overflow:
842 *num_found += found;
843 return ret;
844}
845
846static noinline int search_ioctl(struct inode *inode,
847 struct btrfs_ioctl_search_args *args)
848{
849 struct btrfs_root *root;
850 struct btrfs_key key;
851 struct btrfs_key max_key;
852 struct btrfs_path *path;
853 struct btrfs_ioctl_search_key *sk = &args->key;
854 struct btrfs_fs_info *info = BTRFS_I(inode)->root->fs_info;
855 int ret;
856 int num_found = 0;
857 unsigned long sk_offset = 0;
858
859 path = btrfs_alloc_path();
860 if (!path)
861 return -ENOMEM;
862
863 if (sk->tree_id == 0) {
864 /* search the root of the inode that was passed */
865 root = BTRFS_I(inode)->root;
866 } else {
867 key.objectid = sk->tree_id;
868 key.type = BTRFS_ROOT_ITEM_KEY;
869 key.offset = (u64)-1;
870 root = btrfs_read_fs_root_no_name(info, &key);
871 if (IS_ERR(root)) {
872 printk(KERN_ERR "could not find root %llu\n",
873 sk->tree_id);
874 btrfs_free_path(path);
875 return -ENOENT;
876 }
877 }
878
879 key.objectid = sk->min_objectid;
880 key.type = sk->min_type;
881 key.offset = sk->min_offset;
882
883 max_key.objectid = sk->max_objectid;
884 max_key.type = sk->max_type;
885 max_key.offset = sk->max_offset;
886
887 path->keep_locks = 1;
888
889 while(1) {
890 ret = btrfs_search_forward(root, &key, &max_key, path, 0,
891 sk->min_transid);
892 if (ret != 0) {
893 if (ret > 0)
894 ret = 0;
895 goto err;
896 }
897 ret = copy_to_sk(root, path, &key, sk, args->buf,
898 &sk_offset, &num_found);
899 btrfs_release_path(root, path);
900 if (ret || num_found >= sk->nr_items)
901 break;
902
903 }
904 ret = 0;
905err:
906 sk->nr_items = num_found;
907 btrfs_free_path(path);
908 return ret;
909}
910
911static noinline int btrfs_ioctl_tree_search(struct file *file,
912 void __user *argp)
913{
914 struct btrfs_ioctl_search_args *args;
915 struct inode *inode;
916 int ret;
917
918 if (!capable(CAP_SYS_ADMIN))
919 return -EPERM;
920
921 args = kmalloc(sizeof(*args), GFP_KERNEL);
922 if (!args)
923 return -ENOMEM;
924
925 if (copy_from_user(args, argp, sizeof(*args))) {
926 kfree(args);
927 return -EFAULT;
928 }
929 inode = fdentry(file)->d_inode;
930 ret = search_ioctl(inode, args);
931 if (ret == 0 && copy_to_user(argp, args, sizeof(*args)))
932 ret = -EFAULT;
933 kfree(args);
934 return ret;
935}
936
747/* 937/*
748 Search INODE_REFs to identify path name of 'dirid' directory 938 * Search INODE_REFs to identify path name of 'dirid' directory
749 in a 'tree_id' tree. and sets path name to 'name'. 939 * in a 'tree_id' tree. and sets path name to 'name'.
750*/ 940 */
751static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info, 941static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
752 u64 tree_id, u64 dirid, char *name) 942 u64 tree_id, u64 dirid, char *name)
753{ 943{
754 struct btrfs_root *root; 944 struct btrfs_root *root;
755 struct btrfs_key key; 945 struct btrfs_key key;
756 char *name_stack, *ptr; 946 char *ptr;
757 int ret = -1; 947 int ret = -1;
758 int slot; 948 int slot;
759 int len; 949 int len;
@@ -771,13 +961,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
771 if (!path) 961 if (!path)
772 return -ENOMEM; 962 return -ENOMEM;
773 963
774 name_stack = kzalloc(BTRFS_PATH_NAME_MAX+1, GFP_NOFS); 964 ptr = &name[BTRFS_INO_LOOKUP_PATH_MAX];
775 if (!name_stack) {
776 btrfs_free_path(path);
777 return -ENOMEM;
778 }
779
780 ptr = &name_stack[BTRFS_PATH_NAME_MAX];
781 965
782 key.objectid = tree_id; 966 key.objectid = tree_id;
783 key.type = BTRFS_ROOT_ITEM_KEY; 967 key.type = BTRFS_ROOT_ITEM_KEY;
@@ -802,14 +986,16 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
802 btrfs_item_key_to_cpu(l, &key, slot); 986 btrfs_item_key_to_cpu(l, &key, slot);
803 987
804 if (ret > 0 && (key.objectid != dirid || 988 if (ret > 0 && (key.objectid != dirid ||
805 key.type != BTRFS_INODE_REF_KEY)) 989 key.type != BTRFS_INODE_REF_KEY)) {
990 ret = -ENOENT;
806 goto out; 991 goto out;
992 }
807 993
808 iref = btrfs_item_ptr(l, slot, struct btrfs_inode_ref); 994 iref = btrfs_item_ptr(l, slot, struct btrfs_inode_ref);
809 len = btrfs_inode_ref_name_len(l, iref); 995 len = btrfs_inode_ref_name_len(l, iref);
810 ptr -= len + 1; 996 ptr -= len + 1;
811 total_len += len + 1; 997 total_len += len + 1;
812 if (ptr < name_stack) 998 if (ptr < name)
813 goto out; 999 goto out;
814 1000
815 *(ptr + len) = '/'; 1001 *(ptr + len) = '/';
@@ -824,14 +1010,41 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
824 dirid = key.objectid; 1010 dirid = key.objectid;
825 1011
826 } 1012 }
827 if (ptr < name_stack) 1013 if (ptr < name)
828 goto out; 1014 goto out;
829 strncpy(name, ptr, total_len); 1015 memcpy(name, ptr, total_len);
830 name[total_len]='\0'; 1016 name[total_len]='\0';
831 ret = 0; 1017 ret = 0;
832out: 1018out:
833 btrfs_free_path(path); 1019 btrfs_free_path(path);
834 kfree(name_stack); 1020 return ret;
1021}
1022
1023static noinline int btrfs_ioctl_ino_lookup(struct file *file,
1024 void __user *argp)
1025{
1026 struct btrfs_ioctl_ino_lookup_args *args;
1027 struct inode *inode;
1028 int ret;
1029
1030 if (!capable(CAP_SYS_ADMIN))
1031 return -EPERM;
1032
1033 args = kmalloc(sizeof(*args), GFP_KERNEL);
1034 if (copy_from_user(args, argp, sizeof(*args))) {
1035 kfree(args);
1036 return -EFAULT;
1037 }
1038 inode = fdentry(file)->d_inode;
1039
1040 ret = btrfs_search_path_in_tree(BTRFS_I(inode)->root->fs_info,
1041 args->treeid, args->objectid,
1042 args->name);
1043
1044 if (ret == 0 && copy_to_user(argp, args, sizeof(*args)))
1045 ret = -EFAULT;
1046
1047 kfree(args);
835 return ret; 1048 return ret;
836} 1049}
837 1050
@@ -1430,6 +1643,10 @@ long btrfs_ioctl(struct file *file, unsigned int
1430 return btrfs_ioctl_trans_start(file); 1643 return btrfs_ioctl_trans_start(file);
1431 case BTRFS_IOC_TRANS_END: 1644 case BTRFS_IOC_TRANS_END:
1432 return btrfs_ioctl_trans_end(file); 1645 return btrfs_ioctl_trans_end(file);
1646 case BTRFS_IOC_TREE_SEARCH:
1647 return btrfs_ioctl_tree_search(file, argp);
1648 case BTRFS_IOC_INO_LOOKUP:
1649 return btrfs_ioctl_ino_lookup(file, argp);
1433 case BTRFS_IOC_SYNC: 1650 case BTRFS_IOC_SYNC:
1434 btrfs_sync_fs(file->f_dentry->d_sb, 1); 1651 btrfs_sync_fs(file->f_dentry->d_sb, 1);
1435 return 0; 1652 return 0;
diff --git a/fs/btrfs/ioctl.h b/fs/btrfs/ioctl.h
index bc49914475eb..79c07b104f91 100644
--- a/fs/btrfs/ioctl.h
+++ b/fs/btrfs/ioctl.h
@@ -30,6 +30,68 @@ struct btrfs_ioctl_vol_args {
30 char name[BTRFS_PATH_NAME_MAX + 1]; 30 char name[BTRFS_PATH_NAME_MAX + 1];
31}; 31};
32 32
33#define BTRFS_INO_LOOKUP_PATH_MAX 4080
34struct btrfs_ioctl_ino_lookup_args {
35 __u64 treeid;
36 __u64 objectid;
37 char name[BTRFS_INO_LOOKUP_PATH_MAX];
38};
39
40struct btrfs_ioctl_search_key {
41 /* which root are we searching. 0 is the tree of tree roots */
42 __u64 tree_id;
43
44 /* keys returned will be >= min and <= max */
45 __u64 min_objectid;
46 __u64 max_objectid;
47
48 /* keys returned will be >= min and <= max */
49 __u64 min_offset;
50 __u64 max_offset;
51
52 /* max and min transids to search for */
53 __u64 min_transid;
54 __u64 max_transid;
55
56 /* keys returned will be >= min and <= max */
57 __u32 min_type;
58 __u32 max_type;
59
60 /*
61 * how many items did userland ask for, and how many are we
62 * returning
63 */
64 __u32 nr_items;
65
66 /* align to 64 bits */
67 __u32 unused;
68
69 /* some extra for later */
70 __u64 unused1;
71 __u64 unused2;
72 __u64 unused3;
73 __u64 unused4;
74};
75
76struct btrfs_ioctl_search_header {
77 __u64 transid;
78 __u64 objectid;
79 __u64 offset;
80 __u32 type;
81 __u32 len;
82};
83
84#define BTRFS_SEARCH_ARGS_BUFSIZE (4096 - sizeof(struct btrfs_ioctl_search_key))
85/*
86 * the buf is an array of search headers where
87 * each header is followed by the actual item
88 * the type field is expanded to 32 bits for alignment
89 */
90struct btrfs_ioctl_search_args {
91 struct btrfs_ioctl_search_key key;
92 char buf[BTRFS_SEARCH_ARGS_BUFSIZE];
93};
94
33struct btrfs_ioctl_clone_range_args { 95struct btrfs_ioctl_clone_range_args {
34 __s64 src_fd; 96 __s64 src_fd;
35 __u64 src_offset, src_length; 97 __u64 src_offset, src_length;
@@ -67,4 +129,8 @@ struct btrfs_ioctl_clone_range_args {
67 struct btrfs_ioctl_vol_args) 129 struct btrfs_ioctl_vol_args)
68#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \ 130#define BTRFS_IOC_SNAP_DESTROY _IOW(BTRFS_IOCTL_MAGIC, 15, \
69 struct btrfs_ioctl_vol_args) 131 struct btrfs_ioctl_vol_args)
132#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
133 struct btrfs_ioctl_search_args)
134#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
135 struct btrfs_ioctl_ino_lookup_args)
70#endif 136#endif