@@ -159,6 +159,71 @@ static int btrfs_read_root_item(int mnt_fd, u64 root_id,
159
159
return 0 ;
160
160
}
161
161
162
+ static struct rb_node * tree_insert (struct rb_root * root ,
163
+ struct subvol_info * si ,
164
+ enum subvol_search_type type )
165
+ {
166
+ struct rb_node * * p = & root -> rb_node ;
167
+ struct rb_node * parent = NULL ;
168
+ struct subvol_info * entry ;
169
+ __s64 comp ;
170
+
171
+ while (* p ) {
172
+ parent = * p ;
173
+ if (type == subvol_search_by_received_uuid ) {
174
+ entry = rb_entry (parent , struct subvol_info ,
175
+ rb_received_node );
176
+
177
+ comp = memcmp (entry -> received_uuid , si -> received_uuid ,
178
+ BTRFS_UUID_SIZE );
179
+ if (!comp ) {
180
+ if (entry -> stransid < si -> stransid )
181
+ comp = -1 ;
182
+ else if (entry -> stransid > si -> stransid )
183
+ comp = 1 ;
184
+ else
185
+ comp = 0 ;
186
+ }
187
+ } else if (type == subvol_search_by_uuid ) {
188
+ entry = rb_entry (parent , struct subvol_info ,
189
+ rb_local_node );
190
+ comp = memcmp (entry -> uuid , si -> uuid , BTRFS_UUID_SIZE );
191
+ } else if (type == subvol_search_by_root_id ) {
192
+ entry = rb_entry (parent , struct subvol_info ,
193
+ rb_root_id_node );
194
+ comp = entry -> root_id - si -> root_id ;
195
+ } else if (type == subvol_search_by_path ) {
196
+ entry = rb_entry (parent , struct subvol_info ,
197
+ rb_path_node );
198
+ comp = strcmp (entry -> path , si -> path );
199
+ } else {
200
+ BUG ();
201
+ }
202
+
203
+ if (comp < 0 )
204
+ p = & (* p )-> rb_left ;
205
+ else if (comp > 0 )
206
+ p = & (* p )-> rb_right ;
207
+ else
208
+ return parent ;
209
+ }
210
+
211
+ if (type == subvol_search_by_received_uuid ) {
212
+ rb_link_node (& si -> rb_received_node , parent , p );
213
+ rb_insert_color (& si -> rb_received_node , root );
214
+ } else if (type == subvol_search_by_uuid ) {
215
+ rb_link_node (& si -> rb_local_node , parent , p );
216
+ rb_insert_color (& si -> rb_local_node , root );
217
+ } else if (type == subvol_search_by_root_id ) {
218
+ rb_link_node (& si -> rb_root_id_node , parent , p );
219
+ rb_insert_color (& si -> rb_root_id_node , root );
220
+ } else if (type == subvol_search_by_path ) {
221
+ rb_link_node (& si -> rb_path_node , parent , p );
222
+ rb_insert_color (& si -> rb_path_node , root );
223
+ }
224
+ return NULL ;
225
+ }
226
+
162
227
int btrfs_subvolid_resolve (int fd , char * path , size_t path_len , u64 subvol_id )
163
228
{
164
229
if (path_len < 1 )
@@ -255,13 +320,101 @@ static int btrfs_subvolid_resolve_sub(int fd, char *path, size_t *path_len,
255
320
return 0 ;
256
321
}
257
322
323
+ static int count_bytes (void * buf , int len , char b )
324
+ {
325
+ int cnt = 0 ;
326
+ int i ;
327
+
328
+ for (i = 0 ; i < len ; i ++ ) {
329
+ if (((char * )buf )[i ] == b )
330
+ cnt ++ ;
331
+ }
332
+ return cnt ;
333
+ }
334
+
258
335
void subvol_uuid_search_add (struct subvol_uuid_search * s ,
259
336
struct subvol_info * si )
260
337
{
261
- if (si ) {
262
- free (si -> path );
263
- free (si );
338
+ int cnt ;
339
+
340
+ tree_insert (& s -> root_id_subvols , si , subvol_search_by_root_id );
341
+ tree_insert (& s -> path_subvols , si , subvol_search_by_path );
342
+
343
+ cnt = count_bytes (si -> uuid , BTRFS_UUID_SIZE , 0 );
344
+ if (cnt != BTRFS_UUID_SIZE )
345
+ tree_insert (& s -> local_subvols , si , subvol_search_by_uuid );
346
+ cnt = count_bytes (si -> received_uuid , BTRFS_UUID_SIZE , 0 );
347
+ if (cnt != BTRFS_UUID_SIZE )
348
+ tree_insert (& s -> received_subvols , si ,
349
+ subvol_search_by_received_uuid );
350
+ }
351
+
352
+ static struct subvol_info * tree_search (struct rb_root * root ,
353
+ u64 root_id , const u8 * uuid ,
354
+ u64 stransid , const char * path ,
355
+ enum subvol_search_type type )
356
+ {
357
+ struct rb_node * n = root -> rb_node ;
358
+ struct subvol_info * entry ;
359
+ __s64 comp ;
360
+
361
+ while (n ) {
362
+ if (type == subvol_search_by_received_uuid ) {
363
+ entry = rb_entry (n , struct subvol_info ,
364
+ rb_received_node );
365
+ comp = memcmp (entry -> received_uuid , uuid ,
366
+ BTRFS_UUID_SIZE );
367
+ if (!comp ) {
368
+ if (entry -> stransid < stransid )
369
+ comp = -1 ;
370
+ else if (entry -> stransid > stransid )
371
+ comp = 1 ;
372
+ else
373
+ comp = 0 ;
374
+ }
375
+ } else if (type == subvol_search_by_uuid ) {
376
+ entry = rb_entry (n , struct subvol_info , rb_local_node );
377
+ comp = memcmp (entry -> uuid , uuid , BTRFS_UUID_SIZE );
378
+ } else if (type == subvol_search_by_root_id ) {
379
+ entry = rb_entry (n , struct subvol_info ,
380
+ rb_root_id_node );
381
+ comp = entry -> root_id - root_id ;
382
+ } else if (type == subvol_search_by_path ) {
383
+ entry = rb_entry (n , struct subvol_info , rb_path_node );
384
+ comp = strcmp (entry -> path , path );
385
+ } else {
386
+ BUG ();
387
+ }
388
+ if (comp < 0 )
389
+ n = n -> rb_left ;
390
+ else if (comp > 0 )
391
+ n = n -> rb_right ;
392
+ else
393
+ return entry ;
264
394
}
395
+ return NULL ;
396
+ }
397
+
398
+ /*
399
+ * this function will be only called if kernel dosen't support uuid tree.
400
+ */
401
+ static struct subvol_info * subvol_uuid_search_old (struct subvol_uuid_search * s ,
402
+ u64 root_id , const u8 * uuid , u64 transid ,
403
+ const char * path ,
404
+ enum subvol_search_type type )
405
+ {
406
+ struct rb_root * root ;
407
+ if (type == subvol_search_by_received_uuid )
408
+ root = & s -> received_subvols ;
409
+ else if (type == subvol_search_by_uuid )
410
+ root = & s -> local_subvols ;
411
+ else if (type == subvol_search_by_root_id )
412
+ root = & s -> root_id_subvols ;
413
+ else if (type == subvol_search_by_path )
414
+ root = & s -> path_subvols ;
415
+ else
416
+ return NULL ;
417
+ return tree_search (root , root_id , uuid , transid , path , type );
265
418
}
266
419
267
420
struct subvol_info * subvol_uuid_search (struct subvol_uuid_search * s ,
@@ -273,6 +426,9 @@ struct subvol_info *subvol_uuid_search(struct subvol_uuid_search *s,
273
426
struct btrfs_root_item root_item ;
274
427
struct subvol_info * info = NULL ;
275
428
429
+ if (!s -> uuid_tree_existed )
430
+ return subvol_uuid_search_old (s , root_id , uuid , transid ,
431
+ path , type );
276
432
switch (type ) {
277
433
case subvol_search_by_received_uuid :
278
434
ret = btrfs_lookup_uuid_received_subvol_item (s -> mnt_fd , uuid ,
@@ -325,15 +481,203 @@ struct subvol_info *subvol_uuid_search(struct subvol_uuid_search *s,
325
481
return info ;
326
482
}
327
483
484
+ static int is_uuid_tree_supported (int fd )
485
+ {
486
+ int ret ;
487
+ struct btrfs_ioctl_search_args args ;
488
+ struct btrfs_ioctl_search_key * sk = & args .key ;
489
+
490
+ memset (& args , 0 , sizeof (args ));
491
+
492
+ sk -> tree_id = BTRFS_ROOT_TREE_OBJECTID ;
493
+
494
+ sk -> min_objectid = BTRFS_UUID_TREE_OBJECTID ;
495
+ sk -> max_objectid = BTRFS_UUID_TREE_OBJECTID ;
496
+ sk -> max_type = BTRFS_ROOT_ITEM_KEY ;
497
+ sk -> min_type = BTRFS_ROOT_ITEM_KEY ;
498
+ sk -> max_offset = (u64 )- 1 ;
499
+ sk -> max_transid = (u64 )- 1 ;
500
+ sk -> nr_items = 1 ;
501
+
502
+ ret = ioctl (fd , BTRFS_IOC_TREE_SEARCH , & args );
503
+ if (ret < 0 )
504
+ return ret ;
505
+
506
+ /* the ioctl returns the number of item it found in nr_items */
507
+ if (sk -> nr_items == 0 )
508
+ return 0 ;
509
+
510
+ return 1 ;
511
+ }
512
+
513
+ /*
514
+ * this function is mainly used to read all root items
515
+ * it will be only used when we use older kernel which uuid
516
+ * tree is not supported yet
517
+ */
328
518
int subvol_uuid_search_init (int mnt_fd , struct subvol_uuid_search * s )
329
519
{
520
+ int ret ;
521
+ struct btrfs_ioctl_search_args args ;
522
+ struct btrfs_ioctl_search_key * sk = & args .key ;
523
+ struct btrfs_ioctl_search_header * sh ;
524
+ struct btrfs_root_item * root_item_ptr ;
525
+ struct btrfs_root_item root_item ;
526
+ struct subvol_info * si = NULL ;
527
+ int root_item_valid = 0 ;
528
+ unsigned long off = 0 ;
529
+ int i ;
530
+ int e ;
531
+ char * path ;
532
+
330
533
s -> mnt_fd = mnt_fd ;
331
534
332
- return 0 ;
535
+ s -> root_id_subvols = RB_ROOT ;
536
+ s -> local_subvols = RB_ROOT ;
537
+ s -> received_subvols = RB_ROOT ;
538
+ s -> path_subvols = RB_ROOT ;
539
+
540
+ ret = is_uuid_tree_supported (mnt_fd );
541
+ if (ret < 0 ) {
542
+ fprintf (stderr ,
543
+ "ERROR: check if we support uuid tree fails- %s\n" ,
544
+ strerror (errno ));
545
+ return ret ;
546
+ } else if (ret ) {
547
+ /* uuid tree is supported */
548
+ s -> uuid_tree_existed = 1 ;
549
+ return 0 ;
550
+ }
551
+ memset (& args , 0 , sizeof (args ));
552
+
553
+ sk -> tree_id = BTRFS_ROOT_TREE_OBJECTID ;
554
+
555
+ sk -> max_objectid = (u64 )- 1 ;
556
+ sk -> max_offset = (u64 )- 1 ;
557
+ sk -> max_transid = (u64 )- 1 ;
558
+ sk -> min_type = BTRFS_ROOT_ITEM_KEY ;
559
+ sk -> max_type = BTRFS_ROOT_BACKREF_KEY ;
560
+ sk -> nr_items = 4096 ;
561
+
562
+ while (1 ) {
563
+ ret = ioctl (mnt_fd , BTRFS_IOC_TREE_SEARCH , & args );
564
+ e = errno ;
565
+ if (ret < 0 ) {
566
+ fprintf (stderr , "ERROR: can't perform the search- %s\n" ,
567
+ strerror (e ));
568
+ return ret ;
569
+ }
570
+ if (sk -> nr_items == 0 )
571
+ break ;
572
+
573
+ off = 0 ;
574
+
575
+ for (i = 0 ; i < sk -> nr_items ; i ++ ) {
576
+ sh = (struct btrfs_ioctl_search_header * )(args .buf +
577
+ off );
578
+ off += sizeof (* sh );
579
+
580
+ if ((sh -> objectid != 5 &&
581
+ sh -> objectid < BTRFS_FIRST_FREE_OBJECTID ) ||
582
+ sh -> objectid > BTRFS_LAST_FREE_OBJECTID )
583
+ goto skip ;
584
+
585
+ if (sh -> type == BTRFS_ROOT_ITEM_KEY ) {
586
+ /* older kernels don't have uuids+times */
587
+ if (sh -> len < sizeof (root_item )) {
588
+ root_item_valid = 0 ;
589
+ goto skip ;
590
+ }
591
+ root_item_ptr = (struct btrfs_root_item * )
592
+ (args .buf + off );
593
+ memcpy (& root_item , root_item_ptr ,
594
+ sizeof (root_item ));
595
+ root_item_valid = 1 ;
596
+ } else if (sh -> type == BTRFS_ROOT_BACKREF_KEY ||
597
+ root_item_valid ) {
598
+ if (!root_item_valid )
599
+ goto skip ;
600
+
601
+ path = btrfs_list_path_for_root (mnt_fd ,
602
+ sh -> objectid );
603
+ if (!path )
604
+ path = strdup ("" );
605
+ if (IS_ERR (path )) {
606
+ ret = PTR_ERR (path );
607
+ fprintf (stderr , "ERROR: unable to "
608
+ "resolve path "
609
+ "for root %llu\n" ,
610
+ sh -> objectid );
611
+ goto out ;
612
+ }
613
+
614
+ si = calloc (1 , sizeof (* si ));
615
+ si -> root_id = sh -> objectid ;
616
+ memcpy (si -> uuid , root_item .uuid ,
617
+ BTRFS_UUID_SIZE );
618
+ memcpy (si -> parent_uuid , root_item .parent_uuid ,
619
+ BTRFS_UUID_SIZE );
620
+ memcpy (si -> received_uuid ,
621
+ root_item .received_uuid ,
622
+ BTRFS_UUID_SIZE );
623
+ si -> ctransid = btrfs_root_ctransid (& root_item );
624
+ si -> otransid = btrfs_root_otransid (& root_item );
625
+ si -> stransid = btrfs_root_stransid (& root_item );
626
+ si -> rtransid = btrfs_root_rtransid (& root_item );
627
+ si -> path = path ;
628
+ subvol_uuid_search_add (s , si );
629
+ root_item_valid = 0 ;
630
+ } else {
631
+ goto skip ;
632
+ }
633
+
634
+ skip :
635
+ off += sh -> len ;
636
+
637
+ /*
638
+ * record the mins in sk so we can make sure the
639
+ * next search doesn't repeat this root
640
+ */
641
+ sk -> min_objectid = sh -> objectid ;
642
+ sk -> min_offset = sh -> offset ;
643
+ sk -> min_type = sh -> type ;
644
+ }
645
+ sk -> nr_items = 4096 ;
646
+ if (sk -> min_offset < (u64 )- 1 )
647
+ sk -> min_offset ++ ;
648
+ else if (sk -> min_objectid < (u64 )- 1 ) {
649
+ sk -> min_objectid ++ ;
650
+ sk -> min_offset = 0 ;
651
+ sk -> min_type = 0 ;
652
+ } else
653
+ break ;
654
+ }
655
+
656
+ out :
657
+ return ret ;
333
658
}
334
659
335
660
void subvol_uuid_search_finit (struct subvol_uuid_search * s )
336
661
{
662
+ struct rb_root * root = & s -> root_id_subvols ;
663
+ struct rb_node * node ;
664
+
665
+ if (!s -> uuid_tree_existed )
666
+ return ;
667
+
668
+ while ((node = rb_first (root ))) {
669
+ struct subvol_info * entry =
670
+ rb_entry (node , struct subvol_info , rb_root_id_node );
671
+
672
+ free (entry -> path );
673
+ rb_erase (node , root );
674
+ free (entry );
675
+ }
676
+
677
+ s -> root_id_subvols = RB_ROOT ;
678
+ s -> local_subvols = RB_ROOT ;
679
+ s -> received_subvols = RB_ROOT ;
680
+ s -> path_subvols = RB_ROOT ;
337
681
}
338
682
339
683
char * path_cat (const char * p1 , const char * p2 )
0 commit comments