Goffredo Baroncelli
2010-Dec-19 16:19 UTC
[BUG] Calling BTRFS_IOC_TREE_SEARCH for a non existant key
Hi all,
I discovered that when I call the BTRFS_IOC_TREE_SEARCH ioctl for a not
existent key, the ioctl requires a lot of time to be completed.
I tracks down the problem in the function search_ioctl(). It seems that the
function btrfs_search_forward() doesn''t check if key is greater than
max_key.
file ioctl.c
988 static noinline int search_ioctl(struct inode *inode,
989 struct btrfs_ioctl_search_args *args)
[...]
1025 while(1) {
1026 ret = btrfs_search_forward(root, &key, &max_key, path,
0,
1027 sk->min_transid);
1028 if (ret != 0) {
1029 if (ret > 0)
1030 ret = 0;
1031 goto err;
1032 }
1033 ret = copy_to_sk(root, path, &key, sk, args->buf,
1034 &sk_offset, &num_found);
1035 btrfs_release_path(root, path);
1036 if (ret || num_found >= sk->nr_items)
1037 break;
1038 }
The function btrfs_search_forward() doesn''t check the key (or min_key)
against
max_key when the parameter cache_only == 0.
from ctree.c
3624 int btrfs_search_forward(struct btrfs_root *root, struct btrfs_key
*min_key,
3625 struct btrfs_key *max_key,
3626 struct btrfs_path *path, int cache_only,
3627 u64 min_trans)
3628 {
[..]
3678 if (!cache_only)
3679 break;
3680 if (max_key) {
3681 btrfs_node_key(cur, &disk_key,
slot);
3682 if (comp_keys(&disk_key, max_key)
>=
0) {
3683 ret = 1;
3684 goto out;
3685 }
3686 }
So in the function search_ioctl the search is not completed until the
"args"
buffer is filled or the function copy_to_sk detects that key is greater than
sk->max_*.
However the check performed by the function copy_to_sk is not always
sufficient to detect if a key is greater than sk->max_*. For example if
key.objectid > sk->max_objectid but key.offset is < sk->max_offset,
the key is
supposed to be valid.
913 static noinline int copy_to_sk(struct btrfs_root *root,
[...]
970 }
971 advance_key:
972 ret = 0;
973 if (key->offset < (u64)-1 && key->offset <
sk->max_offset)
974 key->offset++;
975 else if (key->type < (u8)-1 && key->type <
sk->max_type) {
976 key->offset = 0;
977 key->type++;
978 } else if (key->objectid < (u64)-1 && key->objectid
< sk->max_objectid) {
979 key->offset = 0;
980 key->type = 0;
981 key->objectid++;
982 } else
983 ret = 1;
984 overflow:
985 *num_found += found;
986 return ret;
987 }
To solve this problem it should be sufficient a key check before the call of
btrfs_search_forward().
But I don''t know if this is a workaround or the root cause is inside
the
function btrfs_search_forward() that doesn''t check the key against
max_key if
cached_only is 0.
Regards
G.Baroncelli
--
gpg key@ keyserver.linux.it: Goffredo Baroncelli (ghigo)
<kreijack@inwind.it>
Key fingerprint = 4769 7E51 5293 D36C 814E C054 BF04 F161 3DC5 0512
--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs"
in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html