@@ -4207,11 +4207,13 @@ static ssize_t rbd_parent_show(struct device *dev,
4207
4207
4208
4208
count += sprintf (& buf [count ], "%s"
4209
4209
"pool_id %llu\npool_name %s\n"
4210
+ "pool_ns %s\n"
4210
4211
"image_id %s\nimage_name %s\n"
4211
4212
"snap_id %llu\nsnap_name %s\n"
4212
4213
"overlap %llu\n" ,
4213
4214
!count ? "" : "\n" , /* first? */
4214
4215
spec -> pool_id , spec -> pool_name ,
4216
+ spec -> pool_ns ?: "" ,
4215
4217
spec -> image_id , spec -> image_name ?: "(unknown)" ,
4216
4218
spec -> snap_id , spec -> snap_name ,
4217
4219
rbd_dev -> parent_overlap );
@@ -4584,47 +4586,177 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
4584
4586
& rbd_dev -> header .features );
4585
4587
}
4586
4588
4589
+ struct parent_image_info {
4590
+ u64 pool_id ;
4591
+ const char * pool_ns ;
4592
+ const char * image_id ;
4593
+ u64 snap_id ;
4594
+
4595
+ bool has_overlap ;
4596
+ u64 overlap ;
4597
+ };
4598
+
4599
+ /*
4600
+ * The caller is responsible for @pii.
4601
+ */
4602
+ static int decode_parent_image_spec (void * * p , void * end ,
4603
+ struct parent_image_info * pii )
4604
+ {
4605
+ u8 struct_v ;
4606
+ u32 struct_len ;
4607
+ int ret ;
4608
+
4609
+ ret = ceph_start_decoding (p , end , 1 , "ParentImageSpec" ,
4610
+ & struct_v , & struct_len );
4611
+ if (ret )
4612
+ return ret ;
4613
+
4614
+ ceph_decode_64_safe (p , end , pii -> pool_id , e_inval );
4615
+ pii -> pool_ns = ceph_extract_encoded_string (p , end , NULL , GFP_KERNEL );
4616
+ if (IS_ERR (pii -> pool_ns )) {
4617
+ ret = PTR_ERR (pii -> pool_ns );
4618
+ pii -> pool_ns = NULL ;
4619
+ return ret ;
4620
+ }
4621
+ pii -> image_id = ceph_extract_encoded_string (p , end , NULL , GFP_KERNEL );
4622
+ if (IS_ERR (pii -> image_id )) {
4623
+ ret = PTR_ERR (pii -> image_id );
4624
+ pii -> image_id = NULL ;
4625
+ return ret ;
4626
+ }
4627
+ ceph_decode_64_safe (p , end , pii -> snap_id , e_inval );
4628
+ return 0 ;
4629
+
4630
+ e_inval :
4631
+ return - EINVAL ;
4632
+ }
4633
+
4634
+ static int __get_parent_info (struct rbd_device * rbd_dev ,
4635
+ struct page * req_page ,
4636
+ struct page * reply_page ,
4637
+ struct parent_image_info * pii )
4638
+ {
4639
+ struct ceph_osd_client * osdc = & rbd_dev -> rbd_client -> client -> osdc ;
4640
+ size_t reply_len = PAGE_SIZE ;
4641
+ void * p , * end ;
4642
+ int ret ;
4643
+
4644
+ ret = ceph_osdc_call (osdc , & rbd_dev -> header_oid , & rbd_dev -> header_oloc ,
4645
+ "rbd" , "parent_get" , CEPH_OSD_FLAG_READ ,
4646
+ req_page , sizeof (u64 ), reply_page , & reply_len );
4647
+ if (ret )
4648
+ return ret == - EOPNOTSUPP ? 1 : ret ;
4649
+
4650
+ p = page_address (reply_page );
4651
+ end = p + reply_len ;
4652
+ ret = decode_parent_image_spec (& p , end , pii );
4653
+ if (ret )
4654
+ return ret ;
4655
+
4656
+ ret = ceph_osdc_call (osdc , & rbd_dev -> header_oid , & rbd_dev -> header_oloc ,
4657
+ "rbd" , "parent_overlap_get" , CEPH_OSD_FLAG_READ ,
4658
+ req_page , sizeof (u64 ), reply_page , & reply_len );
4659
+ if (ret )
4660
+ return ret ;
4661
+
4662
+ p = page_address (reply_page );
4663
+ end = p + reply_len ;
4664
+ ceph_decode_8_safe (& p , end , pii -> has_overlap , e_inval );
4665
+ if (pii -> has_overlap )
4666
+ ceph_decode_64_safe (& p , end , pii -> overlap , e_inval );
4667
+
4668
+ return 0 ;
4669
+
4670
+ e_inval :
4671
+ return - EINVAL ;
4672
+ }
4673
+
4674
+ /*
4675
+ * The caller is responsible for @pii.
4676
+ */
4677
+ static int __get_parent_info_legacy (struct rbd_device * rbd_dev ,
4678
+ struct page * req_page ,
4679
+ struct page * reply_page ,
4680
+ struct parent_image_info * pii )
4681
+ {
4682
+ struct ceph_osd_client * osdc = & rbd_dev -> rbd_client -> client -> osdc ;
4683
+ size_t reply_len = PAGE_SIZE ;
4684
+ void * p , * end ;
4685
+ int ret ;
4686
+
4687
+ ret = ceph_osdc_call (osdc , & rbd_dev -> header_oid , & rbd_dev -> header_oloc ,
4688
+ "rbd" , "get_parent" , CEPH_OSD_FLAG_READ ,
4689
+ req_page , sizeof (u64 ), reply_page , & reply_len );
4690
+ if (ret )
4691
+ return ret ;
4692
+
4693
+ p = page_address (reply_page );
4694
+ end = p + reply_len ;
4695
+ ceph_decode_64_safe (& p , end , pii -> pool_id , e_inval );
4696
+ pii -> image_id = ceph_extract_encoded_string (& p , end , NULL , GFP_KERNEL );
4697
+ if (IS_ERR (pii -> image_id )) {
4698
+ ret = PTR_ERR (pii -> image_id );
4699
+ pii -> image_id = NULL ;
4700
+ return ret ;
4701
+ }
4702
+ ceph_decode_64_safe (& p , end , pii -> snap_id , e_inval );
4703
+ pii -> has_overlap = true;
4704
+ ceph_decode_64_safe (& p , end , pii -> overlap , e_inval );
4705
+
4706
+ return 0 ;
4707
+
4708
+ e_inval :
4709
+ return - EINVAL ;
4710
+ }
4711
+
4712
+ static int get_parent_info (struct rbd_device * rbd_dev ,
4713
+ struct parent_image_info * pii )
4714
+ {
4715
+ struct page * req_page , * reply_page ;
4716
+ void * p ;
4717
+ int ret ;
4718
+
4719
+ req_page = alloc_page (GFP_KERNEL );
4720
+ if (!req_page )
4721
+ return - ENOMEM ;
4722
+
4723
+ reply_page = alloc_page (GFP_KERNEL );
4724
+ if (!reply_page ) {
4725
+ __free_page (req_page );
4726
+ return - ENOMEM ;
4727
+ }
4728
+
4729
+ p = page_address (req_page );
4730
+ ceph_encode_64 (& p , rbd_dev -> spec -> snap_id );
4731
+ ret = __get_parent_info (rbd_dev , req_page , reply_page , pii );
4732
+ if (ret > 0 )
4733
+ ret = __get_parent_info_legacy (rbd_dev , req_page , reply_page ,
4734
+ pii );
4735
+
4736
+ __free_page (req_page );
4737
+ __free_page (reply_page );
4738
+ return ret ;
4739
+ }
4740
+
4587
4741
static int rbd_dev_v2_parent_info (struct rbd_device * rbd_dev )
4588
4742
{
4589
4743
struct rbd_spec * parent_spec ;
4590
- size_t size ;
4591
- void * reply_buf = NULL ;
4592
- __le64 snapid ;
4593
- void * p ;
4594
- void * end ;
4595
- u64 pool_id ;
4596
- char * image_id ;
4597
- u64 snap_id ;
4598
- u64 overlap ;
4744
+ struct parent_image_info pii = { 0 };
4599
4745
int ret ;
4600
4746
4601
4747
parent_spec = rbd_spec_alloc ();
4602
4748
if (!parent_spec )
4603
4749
return - ENOMEM ;
4604
4750
4605
- size = sizeof (__le64 ) + /* pool_id */
4606
- sizeof (__le32 ) + RBD_IMAGE_ID_LEN_MAX + /* image_id */
4607
- sizeof (__le64 ) + /* snap_id */
4608
- sizeof (__le64 ); /* overlap */
4609
- reply_buf = kmalloc (size , GFP_KERNEL );
4610
- if (!reply_buf ) {
4611
- ret = - ENOMEM ;
4751
+ ret = get_parent_info (rbd_dev , & pii );
4752
+ if (ret )
4612
4753
goto out_err ;
4613
- }
4614
4754
4615
- snapid = cpu_to_le64 (rbd_dev -> spec -> snap_id );
4616
- ret = rbd_obj_method_sync (rbd_dev , & rbd_dev -> header_oid ,
4617
- & rbd_dev -> header_oloc , "get_parent" ,
4618
- & snapid , sizeof (snapid ), reply_buf , size );
4619
- dout ("%s: rbd_obj_method_sync returned %d\n" , __func__ , ret );
4620
- if (ret < 0 )
4621
- goto out_err ;
4755
+ dout ("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n" ,
4756
+ __func__ , pii .pool_id , pii .pool_ns , pii .image_id , pii .snap_id ,
4757
+ pii .has_overlap , pii .overlap );
4622
4758
4623
- p = reply_buf ;
4624
- end = reply_buf + ret ;
4625
- ret = - ERANGE ;
4626
- ceph_decode_64_safe (& p , end , pool_id , out_err );
4627
- if (pool_id == CEPH_NOPOOL ) {
4759
+ if (pii .pool_id == CEPH_NOPOOL || !pii .has_overlap ) {
4628
4760
/*
4629
4761
* Either the parent never existed, or we have
4630
4762
* record of it but the image got flattened so it no
@@ -4633,6 +4765,10 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4633
4765
* overlap to 0. The effect of this is that all new
4634
4766
* requests will be treated as if the image had no
4635
4767
* parent.
4768
+ *
4769
+ * If !pii.has_overlap, the parent image spec is not
4770
+ * applicable. It's there to avoid duplication in each
4771
+ * snapshot record.
4636
4772
*/
4637
4773
if (rbd_dev -> parent_overlap ) {
4638
4774
rbd_dev -> parent_overlap = 0 ;
@@ -4647,51 +4783,36 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4647
4783
/* The ceph file layout needs to fit pool id in 32 bits */
4648
4784
4649
4785
ret = - EIO ;
4650
- if (pool_id > (u64 )U32_MAX ) {
4786
+ if (pii . pool_id > (u64 )U32_MAX ) {
4651
4787
rbd_warn (NULL , "parent pool id too large (%llu > %u)" ,
4652
- (unsigned long long )pool_id , U32_MAX );
4788
+ (unsigned long long )pii . pool_id , U32_MAX );
4653
4789
goto out_err ;
4654
4790
}
4655
4791
4656
- image_id = ceph_extract_encoded_string (& p , end , NULL , GFP_KERNEL );
4657
- if (IS_ERR (image_id )) {
4658
- ret = PTR_ERR (image_id );
4659
- goto out_err ;
4660
- }
4661
- ceph_decode_64_safe (& p , end , snap_id , out_err );
4662
- ceph_decode_64_safe (& p , end , overlap , out_err );
4663
-
4664
4792
/*
4665
4793
* The parent won't change (except when the clone is
4666
4794
* flattened, already handled that). So we only need to
4667
4795
* record the parent spec we have not already done so.
4668
4796
*/
4669
4797
if (!rbd_dev -> parent_spec ) {
4670
- parent_spec -> pool_id = pool_id ;
4671
- parent_spec -> image_id = image_id ;
4672
- parent_spec -> snap_id = snap_id ;
4673
-
4674
- /* TODO: support cloning across namespaces */
4675
- if (rbd_dev -> spec -> pool_ns ) {
4676
- parent_spec -> pool_ns = kstrdup (rbd_dev -> spec -> pool_ns ,
4677
- GFP_KERNEL );
4678
- if (!parent_spec -> pool_ns ) {
4679
- ret = - ENOMEM ;
4680
- goto out_err ;
4681
- }
4798
+ parent_spec -> pool_id = pii .pool_id ;
4799
+ if (pii .pool_ns && * pii .pool_ns ) {
4800
+ parent_spec -> pool_ns = pii .pool_ns ;
4801
+ pii .pool_ns = NULL ;
4682
4802
}
4803
+ parent_spec -> image_id = pii .image_id ;
4804
+ pii .image_id = NULL ;
4805
+ parent_spec -> snap_id = pii .snap_id ;
4683
4806
4684
4807
rbd_dev -> parent_spec = parent_spec ;
4685
4808
parent_spec = NULL ; /* rbd_dev now owns this */
4686
- } else {
4687
- kfree (image_id );
4688
4809
}
4689
4810
4690
4811
/*
4691
4812
* We always update the parent overlap. If it's zero we issue
4692
4813
* a warning, as we will proceed as if there was no parent.
4693
4814
*/
4694
- if (!overlap ) {
4815
+ if (!pii . overlap ) {
4695
4816
if (parent_spec ) {
4696
4817
/* refresh, careful to warn just once */
4697
4818
if (rbd_dev -> parent_overlap )
@@ -4702,14 +4823,14 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
4702
4823
rbd_warn (rbd_dev , "clone is standalone (overlap 0)" );
4703
4824
}
4704
4825
}
4705
- rbd_dev -> parent_overlap = overlap ;
4826
+ rbd_dev -> parent_overlap = pii . overlap ;
4706
4827
4707
4828
out :
4708
4829
ret = 0 ;
4709
4830
out_err :
4710
- kfree (reply_buf );
4831
+ kfree (pii .pool_ns );
4832
+ kfree (pii .image_id );
4711
4833
rbd_spec_put (parent_spec );
4712
-
4713
4834
return ret ;
4714
4835
}
4715
4836
0 commit comments