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) <kreij...@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 majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to