@@ -4584,47 +4584,95 @@ static int rbd_dev_v2_features(struct rbd_device *rbd_dev)
45844584 & rbd_dev -> header .features );
45854585}
45864586
4587+ struct parent_image_info {
4588+ u64 pool_id ;
4589+ const char * image_id ;
4590+ u64 snap_id ;
4591+
4592+ u64 overlap ;
4593+ };
4594+
4595+ /*
4596+ * The caller is responsible for @pii.
4597+ */
4598+ static int __get_parent_info_legacy (struct rbd_device * rbd_dev ,
4599+ struct page * req_page ,
4600+ struct page * reply_page ,
4601+ struct parent_image_info * pii )
4602+ {
4603+ struct ceph_osd_client * osdc = & rbd_dev -> rbd_client -> client -> osdc ;
4604+ size_t reply_len = PAGE_SIZE ;
4605+ void * p , * end ;
4606+ int ret ;
4607+
4608+ ret = ceph_osdc_call (osdc , & rbd_dev -> header_oid , & rbd_dev -> header_oloc ,
4609+ "rbd" , "get_parent" , CEPH_OSD_FLAG_READ ,
4610+ req_page , sizeof (u64 ), reply_page , & reply_len );
4611+ if (ret )
4612+ return ret ;
4613+
4614+ p = page_address (reply_page );
4615+ end = p + reply_len ;
4616+ ceph_decode_64_safe (& p , end , pii -> pool_id , e_inval );
4617+ pii -> image_id = ceph_extract_encoded_string (& p , end , NULL , GFP_KERNEL );
4618+ if (IS_ERR (pii -> image_id )) {
4619+ ret = PTR_ERR (pii -> image_id );
4620+ pii -> image_id = NULL ;
4621+ return ret ;
4622+ }
4623+ ceph_decode_64_safe (& p , end , pii -> snap_id , e_inval );
4624+ ceph_decode_64_safe (& p , end , pii -> overlap , e_inval );
4625+
4626+ return 0 ;
4627+
4628+ e_inval :
4629+ return - EINVAL ;
4630+ }
4631+
4632+ static int get_parent_info (struct rbd_device * rbd_dev ,
4633+ struct parent_image_info * pii )
4634+ {
4635+ struct page * req_page , * reply_page ;
4636+ void * p ;
4637+ int ret ;
4638+
4639+ req_page = alloc_page (GFP_KERNEL );
4640+ if (!req_page )
4641+ return - ENOMEM ;
4642+
4643+ reply_page = alloc_page (GFP_KERNEL );
4644+ if (!reply_page ) {
4645+ __free_page (req_page );
4646+ return - ENOMEM ;
4647+ }
4648+
4649+ p = page_address (req_page );
4650+ ceph_encode_64 (& p , rbd_dev -> spec -> snap_id );
4651+ ret = __get_parent_info_legacy (rbd_dev , req_page , reply_page , pii );
4652+
4653+ __free_page (req_page );
4654+ __free_page (reply_page );
4655+ return ret ;
4656+ }
4657+
45874658static int rbd_dev_v2_parent_info (struct rbd_device * rbd_dev )
45884659{
45894660 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 ;
4661+ struct parent_image_info pii = { 0 };
45994662 int ret ;
46004663
46014664 parent_spec = rbd_spec_alloc ();
46024665 if (!parent_spec )
46034666 return - ENOMEM ;
46044667
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 ;
4668+ ret = get_parent_info (rbd_dev , & pii );
4669+ if (ret )
46124670 goto out_err ;
4613- }
46144671
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 ;
4672+ dout ("%s pool_id %llu image_id %s snap_id %llu overlap %llu\n" ,
4673+ __func__ , pii .pool_id , pii .image_id , pii .snap_id , pii .overlap );
46224674
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 ) {
4675+ if (pii .pool_id == CEPH_NOPOOL ) {
46284676 /*
46294677 * Either the parent never existed, or we have
46304678 * record of it but the image got flattened so it no
@@ -4647,29 +4695,22 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
46474695 /* The ceph file layout needs to fit pool id in 32 bits */
46484696
46494697 ret = - EIO ;
4650- if (pool_id > (u64 )U32_MAX ) {
4698+ if (pii . pool_id > (u64 )U32_MAX ) {
46514699 rbd_warn (NULL , "parent pool id too large (%llu > %u)" ,
4652- (unsigned long long )pool_id , U32_MAX );
4653- goto out_err ;
4654- }
4655-
4656- image_id = ceph_extract_encoded_string (& p , end , NULL , GFP_KERNEL );
4657- if (IS_ERR (image_id )) {
4658- ret = PTR_ERR (image_id );
4700+ (unsigned long long )pii .pool_id , U32_MAX );
46594701 goto out_err ;
46604702 }
4661- ceph_decode_64_safe (& p , end , snap_id , out_err );
4662- ceph_decode_64_safe (& p , end , overlap , out_err );
46634703
46644704 /*
46654705 * The parent won't change (except when the clone is
46664706 * flattened, already handled that). So we only need to
46674707 * record the parent spec we have not already done so.
46684708 */
46694709 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 ;
4710+ parent_spec -> pool_id = pii .pool_id ;
4711+ parent_spec -> image_id = pii .image_id ;
4712+ pii .image_id = NULL ;
4713+ parent_spec -> snap_id = pii .snap_id ;
46734714
46744715 /* TODO: support cloning across namespaces */
46754716 if (rbd_dev -> spec -> pool_ns ) {
@@ -4683,15 +4724,13 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
46834724
46844725 rbd_dev -> parent_spec = parent_spec ;
46854726 parent_spec = NULL ; /* rbd_dev now owns this */
4686- } else {
4687- kfree (image_id );
46884727 }
46894728
46904729 /*
46914730 * We always update the parent overlap. If it's zero we issue
46924731 * a warning, as we will proceed as if there was no parent.
46934732 */
4694- if (!overlap ) {
4733+ if (!pii . overlap ) {
46954734 if (parent_spec ) {
46964735 /* refresh, careful to warn just once */
46974736 if (rbd_dev -> parent_overlap )
@@ -4702,14 +4741,13 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
47024741 rbd_warn (rbd_dev , "clone is standalone (overlap 0)" );
47034742 }
47044743 }
4705- rbd_dev -> parent_overlap = overlap ;
4744+ rbd_dev -> parent_overlap = pii . overlap ;
47064745
47074746out :
47084747 ret = 0 ;
47094748out_err :
4710- kfree (reply_buf );
4749+ kfree (pii . image_id );
47114750 rbd_spec_put (parent_spec );
4712-
47134751 return ret ;
47144752}
47154753
0 commit comments