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