From: Noah Watkins Date: Fri, 22 Feb 2013 23:46:02 +0000 (-0800) Subject: client: expose extent/osd mapping X-Git-Tag: v0.60~125^2~1 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=e8da4bf9b5470e74404740875a035674ea0a669d;p=ceph.git client: expose extent/osd mapping Signed-off-by: Noah Watkins --- diff --git a/src/client/Client.cc b/src/client/Client.cc index d5ff08ba55d..d8ba59adb60 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -7530,6 +7530,46 @@ int Client::get_pool_replication(int64_t pool) return osdmap->get_pg_pool(pool)->get_size(); } +int Client::get_file_extent_osds(int fd, loff_t off, loff_t *len, vector& osds) +{ + Mutex::Locker lock(client_lock); + + Fh *f = get_filehandle(fd); + if (!f) + return -EBADF; + Inode *in = f->inode; + + vector extents; + Striper::file_to_extents(cct, in->ino, &in->layout, off, 1, extents); + assert(extents.size() == 1); + + pg_t pg = osdmap->object_locator_to_pg(extents[0].oid, extents[0].oloc); + osdmap->pg_to_acting_osds(pg, osds); + if (osds.empty()) + return -EINVAL; + + /* + * Return the remainder of the extent (stripe unit) + * + * If length = 1 is passed to Striper::file_to_extents we get a single + * extent back, but its length is one so we still need to compute the length + * to the end of the stripe unit. + * + * If length = su then we may get 1 or 2 objects back in the extents vector + * which would have to be examined. Even then, the offsets are local to the + * object, so matching up to the file offset is extra work. + * + * It seems simpler to stick with length = 1 and manually compute the + * remainder. + */ + if (len) { + uint64_t su = in->layout.fl_stripe_unit; + *len = su - (off % su); + } + + return 0; +} + int Client::get_file_stripe_address(int fd, loff_t offset, vector& address) { Mutex::Locker lock(client_lock); diff --git a/src/client/Client.h b/src/client/Client.h index 8846e3f9ad7..b0dd069bbe5 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -666,6 +666,7 @@ public: // expose file layout int describe_layout(int fd, ceph_file_layout* layout); int get_file_stripe_address(int fd, loff_t offset, vector& address); + int get_file_extent_osds(int fd, loff_t off, loff_t *len, vector& osds); // expose osdmap int get_local_osd(); diff --git a/src/include/cephfs/libcephfs.h b/src/include/cephfs/libcephfs.h index abfd25cfd7e..afad8cf1e3d 100644 --- a/src/include/cephfs/libcephfs.h +++ b/src/include/cephfs/libcephfs.h @@ -896,6 +896,22 @@ int ceph_get_pool_replication(struct ceph_mount_info *cmount, int pool_id); int ceph_get_file_stripe_address(struct ceph_mount_info *cmount, int fd, loff_t offset, struct sockaddr_storage *addr, int naddr); +/** + * Get the list of OSDs where the objects containing a file offset are located. + * + * @param cmount the ceph mount handle to use. + * @param fd the open file descriptor referring to the file. + * @param offset the offset within the file. + * @param length return the number of bytes between the offset and the end of + * the stripe unit (optional). + * @param osds an integer array to hold the OSD ids. + * @param nosds the size of the integer array. + * @returns the number of items stored in the output array, or -ERANGE if the + * array is not large enough. + */ +int ceph_get_file_extent_osds(struct ceph_mount_info *cmount, int fh, + loff_t offset, loff_t *length, int *osds, int nosds); + /** * Get the file layout stripe unit granularity. * @param cmount the ceph mount handle. diff --git a/src/libcephfs.cc b/src/libcephfs.cc index d2fe0dac861..0c77125fb50 100644 --- a/src/libcephfs.cc +++ b/src/libcephfs.cc @@ -790,6 +790,32 @@ extern "C" int ceph_set_default_preferred_pg(struct ceph_mount_info *cmount, int return -EOPNOTSUPP; } +extern "C" int ceph_get_file_extent_osds(struct ceph_mount_info *cmount, int fh, + loff_t offset, loff_t *length, int *osds, int nosds) +{ + if (nosds < 0) + return -EINVAL; + + if (!cmount->is_mounted()) + return -ENOTCONN; + + vector vosds; + int ret = cmount->get_client()->get_file_extent_osds(fh, offset, length, vosds); + if (ret < 0) + return ret; + + if (!nosds) + return vosds.size(); + + if ((int)vosds.size() > nosds) + return -ERANGE; + + for (int i = 0; i < (int)vosds.size(); i++) + osds[i] = vosds[i]; + + return vosds.size(); +} + extern "C" int ceph_get_file_stripe_address(struct ceph_mount_info *cmount, int fh, loff_t offset, struct sockaddr_storage *addr, int naddr) { diff --git a/src/test/libcephfs/test.cc b/src/test/libcephfs/test.cc index eaf38dba509..4afe01c32d0 100644 --- a/src/test/libcephfs/test.cc +++ b/src/test/libcephfs/test.cc @@ -930,3 +930,53 @@ TEST(LibCephFS, GetPoolReplication) { ceph_shutdown(cmount); } + +TEST(LibCephFS, GetExtentOsds) { + struct ceph_mount_info *cmount; + ASSERT_EQ(ceph_create(&cmount, NULL), 0); + + EXPECT_EQ(-ENOTCONN, ceph_get_file_extent_osds(cmount, 0, 0, NULL, NULL, 0)); + + ASSERT_EQ(ceph_conf_read_file(cmount, NULL), 0); + ASSERT_EQ(ceph_mount(cmount, NULL), 0); + + int stripe_unit = (1<<18); + + /* make a file! */ + char test_file[256]; + sprintf(test_file, "test_extent_osds_%d", getpid()); + int fd = ceph_open_layout(cmount, test_file, O_CREAT|O_RDWR, 0666, + stripe_unit, 2, stripe_unit*2, NULL); + ASSERT_GT(fd, 0); + + /* get back how many osds > 0 */ + int ret = ceph_get_file_extent_osds(cmount, fd, 0, NULL, NULL, 0); + EXPECT_GT(ret, 0); + + loff_t len; + int osds[ret]; + + /* full stripe extent */ + EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 0, &len, osds, ret)); + EXPECT_EQ(len, (loff_t)stripe_unit); + + /* half stripe extent */ + EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, stripe_unit/2, &len, osds, ret)); + EXPECT_EQ(len, (loff_t)stripe_unit/2); + + /* 1.5 stripe unit offset -1 byte */ + EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 3*stripe_unit/2-1, &len, osds, ret)); + EXPECT_EQ(len, (loff_t)stripe_unit/2+1); + + /* 1.5 stripe unit offset +1 byte */ + EXPECT_EQ(ret, ceph_get_file_extent_osds(cmount, fd, 3*stripe_unit/2+1, &len, osds, ret)); + EXPECT_EQ(len, (loff_t)stripe_unit/2-1); + + /* only when more than 1 osd */ + if (ret > 1) + EXPECT_EQ(-ERANGE, ceph_get_file_extent_osds(cmount, fd, 0, NULL, osds, 1)); + + ceph_close(cmount, fd); + + ceph_shutdown(cmount); +}