return osdmap->get_pg_pool(pool)->get_size();
}
+int Client::get_file_extent_osds(int fd, loff_t off, loff_t *len, vector<int>& osds)
+{
+ Mutex::Locker lock(client_lock);
+
+ Fh *f = get_filehandle(fd);
+ if (!f)
+ return -EBADF;
+ Inode *in = f->inode;
+
+ vector<ObjectExtent> 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<entity_addr_t>& address)
{
Mutex::Locker lock(client_lock);
// expose file layout
int describe_layout(int fd, ceph_file_layout* layout);
int get_file_stripe_address(int fd, loff_t offset, vector<entity_addr_t>& address);
+ int get_file_extent_osds(int fd, loff_t off, loff_t *len, vector<int>& osds);
// expose osdmap
int get_local_osd();
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.
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<int> 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)
{
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);
+}