Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'ceph-for-4.19-rc3' of https://github.com/ceph/ceph-client

Pull ceph fixes from Ilya Dryomov:
"Two rbd patches to complete support for images within namespaces that
went into -rc1 and a use-after-free fix.

The rbd changes have been sitting in a branch for quite a while but
couldn't be included into the -rc1 pull request because of a pending
wire protocol backwards compatibility fixup that only got committed
early this week"

* tag 'ceph-for-4.19-rc3' of https://github.com/ceph/ceph-client:
rbd: support cloning across namespaces
rbd: factor out get_parent_info()
ceph: avoid a use-after-free in ceph_destroy_options()

+190 -63
+179 -58
drivers/block/rbd.c
··· 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); ··· 4586 4584 &rbd_dev->header.features); 4587 4585 } 4588 4586 4587 + struct parent_image_info { 4588 + u64 pool_id; 4589 + const char *pool_ns; 4590 + const char *image_id; 4591 + u64 snap_id; 4592 + 4593 + bool has_overlap; 4594 + u64 overlap; 4595 + }; 4596 + 4597 + /* 4598 + * The caller is responsible for @pii. 4599 + */ 4600 + static int decode_parent_image_spec(void **p, void *end, 4601 + struct parent_image_info *pii) 4602 + { 4603 + u8 struct_v; 4604 + u32 struct_len; 4605 + int ret; 4606 + 4607 + ret = ceph_start_decoding(p, end, 1, "ParentImageSpec", 4608 + &struct_v, &struct_len); 4609 + if (ret) 4610 + return ret; 4611 + 4612 + ceph_decode_64_safe(p, end, pii->pool_id, e_inval); 4613 + pii->pool_ns = ceph_extract_encoded_string(p, end, NULL, GFP_KERNEL); 4614 + if (IS_ERR(pii->pool_ns)) { 4615 + ret = PTR_ERR(pii->pool_ns); 4616 + pii->pool_ns = NULL; 4617 + return ret; 4618 + } 4619 + pii->image_id = ceph_extract_encoded_string(p, end, NULL, GFP_KERNEL); 4620 + if (IS_ERR(pii->image_id)) { 4621 + ret = PTR_ERR(pii->image_id); 4622 + pii->image_id = NULL; 4623 + return ret; 4624 + } 4625 + ceph_decode_64_safe(p, end, pii->snap_id, e_inval); 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 page *req_page, 4634 + struct page *reply_page, 4635 + struct parent_image_info *pii) 4636 + { 4637 + struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; 4638 + size_t reply_len = PAGE_SIZE; 4639 + void *p, *end; 4640 + int ret; 4641 + 4642 + ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc, 4643 + "rbd", "parent_get", CEPH_OSD_FLAG_READ, 4644 + req_page, sizeof(u64), reply_page, &reply_len); 4645 + if (ret) 4646 + return ret == -EOPNOTSUPP ? 1 : ret; 4647 + 4648 + p = page_address(reply_page); 4649 + end = p + reply_len; 4650 + ret = decode_parent_image_spec(&p, end, pii); 4651 + if (ret) 4652 + return ret; 4653 + 4654 + ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc, 4655 + "rbd", "parent_overlap_get", CEPH_OSD_FLAG_READ, 4656 + req_page, sizeof(u64), reply_page, &reply_len); 4657 + if (ret) 4658 + return ret; 4659 + 4660 + p = page_address(reply_page); 4661 + end = p + reply_len; 4662 + ceph_decode_8_safe(&p, end, pii->has_overlap, e_inval); 4663 + if (pii->has_overlap) 4664 + ceph_decode_64_safe(&p, end, pii->overlap, e_inval); 4665 + 4666 + return 0; 4667 + 4668 + e_inval: 4669 + return -EINVAL; 4670 + } 4671 + 4672 + /* 4673 + * The caller is responsible for @pii. 4674 + */ 4675 + static int __get_parent_info_legacy(struct rbd_device *rbd_dev, 4676 + struct page *req_page, 4677 + struct page *reply_page, 4678 + struct parent_image_info *pii) 4679 + { 4680 + struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc; 4681 + size_t reply_len = PAGE_SIZE; 4682 + void *p, *end; 4683 + int ret; 4684 + 4685 + ret = ceph_osdc_call(osdc, &rbd_dev->header_oid, &rbd_dev->header_oloc, 4686 + "rbd", "get_parent", CEPH_OSD_FLAG_READ, 4687 + req_page, sizeof(u64), reply_page, &reply_len); 4688 + if (ret) 4689 + return ret; 4690 + 4691 + p = page_address(reply_page); 4692 + end = p + reply_len; 4693 + ceph_decode_64_safe(&p, end, pii->pool_id, e_inval); 4694 + pii->image_id = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL); 4695 + if (IS_ERR(pii->image_id)) { 4696 + ret = PTR_ERR(pii->image_id); 4697 + pii->image_id = NULL; 4698 + return ret; 4699 + } 4700 + ceph_decode_64_safe(&p, end, pii->snap_id, e_inval); 4701 + pii->has_overlap = true; 4702 + ceph_decode_64_safe(&p, end, pii->overlap, e_inval); 4703 + 4704 + return 0; 4705 + 4706 + e_inval: 4707 + return -EINVAL; 4708 + } 4709 + 4710 + static int get_parent_info(struct rbd_device *rbd_dev, 4711 + struct parent_image_info *pii) 4712 + { 4713 + struct page *req_page, *reply_page; 4714 + void *p; 4715 + int ret; 4716 + 4717 + req_page = alloc_page(GFP_KERNEL); 4718 + if (!req_page) 4719 + return -ENOMEM; 4720 + 4721 + reply_page = alloc_page(GFP_KERNEL); 4722 + if (!reply_page) { 4723 + __free_page(req_page); 4724 + return -ENOMEM; 4725 + } 4726 + 4727 + p = page_address(req_page); 4728 + ceph_encode_64(&p, rbd_dev->spec->snap_id); 4729 + ret = __get_parent_info(rbd_dev, req_page, reply_page, pii); 4730 + if (ret > 0) 4731 + ret = __get_parent_info_legacy(rbd_dev, req_page, reply_page, 4732 + pii); 4733 + 4734 + __free_page(req_page); 4735 + __free_page(reply_page); 4736 + return ret; 4737 + } 4738 + 4589 4739 static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev) 4590 4740 { 4591 4741 struct rbd_spec *parent_spec; 4592 - size_t size; 4593 - void *reply_buf = NULL; 4594 - __le64 snapid; 4595 - void *p; 4596 - void *end; 4597 - u64 pool_id; 4598 - char *image_id; 4599 - u64 snap_id; 4600 - u64 overlap; 4742 + struct parent_image_info pii = { 0 }; 4601 4743 int ret; 4602 4744 4603 4745 parent_spec = rbd_spec_alloc(); 4604 4746 if (!parent_spec) 4605 4747 return -ENOMEM; 4606 4748 4607 - size = sizeof (__le64) + /* pool_id */ 4608 - sizeof (__le32) + RBD_IMAGE_ID_LEN_MAX + /* image_id */ 4609 - sizeof (__le64) + /* snap_id */ 4610 - sizeof (__le64); /* overlap */ 4611 - reply_buf = kmalloc(size, GFP_KERNEL); 4612 - if (!reply_buf) { 4613 - ret = -ENOMEM; 4614 - goto out_err; 4615 - } 4616 - 4617 - snapid = cpu_to_le64(rbd_dev->spec->snap_id); 4618 - ret = rbd_obj_method_sync(rbd_dev, &rbd_dev->header_oid, 4619 - &rbd_dev->header_oloc, "get_parent", 4620 - &snapid, sizeof(snapid), reply_buf, size); 4621 - dout("%s: rbd_obj_method_sync returned %d\n", __func__, ret); 4622 - if (ret < 0) 4749 + ret = get_parent_info(rbd_dev, &pii); 4750 + if (ret) 4623 4751 goto out_err; 4624 4752 4625 - p = reply_buf; 4626 - end = reply_buf + ret; 4627 - ret = -ERANGE; 4628 - ceph_decode_64_safe(&p, end, pool_id, out_err); 4629 - if (pool_id == CEPH_NOPOOL) { 4753 + dout("%s pool_id %llu pool_ns %s image_id %s snap_id %llu has_overlap %d overlap %llu\n", 4754 + __func__, pii.pool_id, pii.pool_ns, pii.image_id, pii.snap_id, 4755 + pii.has_overlap, pii.overlap); 4756 + 4757 + if (pii.pool_id == CEPH_NOPOOL || !pii.has_overlap) { 4630 4758 /* 4631 4759 * Either the parent never existed, or we have 4632 4760 * record of it but the image got flattened so it no ··· 4765 4633 * overlap to 0. The effect of this is that all new 4766 4634 * requests will be treated as if the image had no 4767 4635 * parent. 4636 + * 4637 + * If !pii.has_overlap, the parent image spec is not 4638 + * applicable. It's there to avoid duplication in each 4639 + * snapshot record. 4768 4640 */ 4769 4641 if (rbd_dev->parent_overlap) { 4770 4642 rbd_dev->parent_overlap = 0; ··· 4783 4647 /* The ceph file layout needs to fit pool id in 32 bits */ 4784 4648 4785 4649 ret = -EIO; 4786 - if (pool_id > (u64)U32_MAX) { 4650 + if (pii.pool_id > (u64)U32_MAX) { 4787 4651 rbd_warn(NULL, "parent pool id too large (%llu > %u)", 4788 - (unsigned long long)pool_id, U32_MAX); 4652 + (unsigned long long)pii.pool_id, U32_MAX); 4789 4653 goto out_err; 4790 4654 } 4791 - 4792 - image_id = ceph_extract_encoded_string(&p, end, NULL, GFP_KERNEL); 4793 - if (IS_ERR(image_id)) { 4794 - ret = PTR_ERR(image_id); 4795 - goto out_err; 4796 - } 4797 - ceph_decode_64_safe(&p, end, snap_id, out_err); 4798 - ceph_decode_64_safe(&p, end, overlap, out_err); 4799 4655 4800 4656 /* 4801 4657 * The parent won't change (except when the clone is ··· 4795 4667 * record the parent spec we have not already done so. 4796 4668 */ 4797 4669 if (!rbd_dev->parent_spec) { 4798 - parent_spec->pool_id = pool_id; 4799 - parent_spec->image_id = image_id; 4800 - parent_spec->snap_id = snap_id; 4801 - 4802 - /* TODO: support cloning across namespaces */ 4803 - if (rbd_dev->spec->pool_ns) { 4804 - parent_spec->pool_ns = kstrdup(rbd_dev->spec->pool_ns, 4805 - GFP_KERNEL); 4806 - if (!parent_spec->pool_ns) { 4807 - ret = -ENOMEM; 4808 - goto out_err; 4809 - } 4670 + parent_spec->pool_id = pii.pool_id; 4671 + if (pii.pool_ns && *pii.pool_ns) { 4672 + parent_spec->pool_ns = pii.pool_ns; 4673 + pii.pool_ns = NULL; 4810 4674 } 4675 + parent_spec->image_id = pii.image_id; 4676 + pii.image_id = NULL; 4677 + parent_spec->snap_id = pii.snap_id; 4811 4678 4812 4679 rbd_dev->parent_spec = parent_spec; 4813 4680 parent_spec = NULL; /* rbd_dev now owns this */ 4814 - } else { 4815 - kfree(image_id); 4816 4681 } 4817 4682 4818 4683 /* 4819 4684 * We always update the parent overlap. If it's zero we issue 4820 4685 * a warning, as we will proceed as if there was no parent. 4821 4686 */ 4822 - if (!overlap) { 4687 + if (!pii.overlap) { 4823 4688 if (parent_spec) { 4824 4689 /* refresh, careful to warn just once */ 4825 4690 if (rbd_dev->parent_overlap) ··· 4823 4702 rbd_warn(rbd_dev, "clone is standalone (overlap 0)"); 4824 4703 } 4825 4704 } 4826 - rbd_dev->parent_overlap = overlap; 4705 + rbd_dev->parent_overlap = pii.overlap; 4827 4706 4828 4707 out: 4829 4708 ret = 0; 4830 4709 out_err: 4831 - kfree(reply_buf); 4710 + kfree(pii.pool_ns); 4711 + kfree(pii.image_id); 4832 4712 rbd_spec_put(parent_spec); 4833 - 4834 4713 return ret; 4835 4714 } 4836 4715
+11 -5
fs/ceph/super.c
··· 602 602 603 603 /* 604 604 * create a new fs client 605 + * 606 + * Success or not, this function consumes @fsopt and @opt. 605 607 */ 606 608 static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt, 607 609 struct ceph_options *opt) ··· 611 609 struct ceph_fs_client *fsc; 612 610 int page_count; 613 611 size_t size; 614 - int err = -ENOMEM; 612 + int err; 615 613 616 614 fsc = kzalloc(sizeof(*fsc), GFP_KERNEL); 617 - if (!fsc) 618 - return ERR_PTR(-ENOMEM); 615 + if (!fsc) { 616 + err = -ENOMEM; 617 + goto fail; 618 + } 619 619 620 620 fsc->client = ceph_create_client(opt, fsc); 621 621 if (IS_ERR(fsc->client)) { 622 622 err = PTR_ERR(fsc->client); 623 623 goto fail; 624 624 } 625 + opt = NULL; /* fsc->client now owns this */ 625 626 626 627 fsc->client->extra_mon_dispatch = extra_mon_dispatch; 627 628 fsc->client->osdc.abort_on_full = true; ··· 682 677 ceph_destroy_client(fsc->client); 683 678 fail: 684 679 kfree(fsc); 680 + if (opt) 681 + ceph_destroy_options(opt); 682 + destroy_mount_options(fsopt); 685 683 return ERR_PTR(err); 686 684 } 687 685 ··· 1050 1042 fsc = create_fs_client(fsopt, opt); 1051 1043 if (IS_ERR(fsc)) { 1052 1044 res = ERR_CAST(fsc); 1053 - destroy_mount_options(fsopt); 1054 - ceph_destroy_options(opt); 1055 1045 goto out_final; 1056 1046 } 1057 1047