+ * Convert a struct lu_fid into a struct file_handle
+ *
+ * \param[out] _handle a newly allocated struct file_handle on success
+ * \param[in] fid a Lustre File IDentifier
+ *
+ * \retval 0 on success
+ * \retval negative errno if an error occured
+ *
+ * On success, the caller is responsible for freeing \p handle.
+ */
+int llapi_fid_to_handle(struct file_handle **_handle, const struct lu_fid *fid)
+{
+ struct lustre_file_handle *lfh;
+ struct file_handle *handle;
+
+ if (!_handle || !fid)
+ return -EINVAL;
+
+ handle = calloc(1, sizeof(*handle) + sizeof(*lfh));
+ if (handle == NULL)
+ return -errno;
+
+ handle->handle_bytes = sizeof(*lfh);
+ handle->handle_type = FILEID_LUSTRE;
+ lfh = (struct lustre_file_handle *)handle->f_handle;
+ /* Only lfh->lfh_child needs to be set */
+ lfh->lfh_child = *fid;
+
+ *_handle = handle;
+ return 0;
+}
+
+/**
+ * Attempt to open a file with a Lustre File IDentifier
+ *
+ * \param[in] lustre_fd an open file descriptor for an object in lustre
+ * \param[in] fid a Lustre File IDentifier of the file to open
+ * \param[in] flags open(2) flags
+ *
+ * \retval non-negative file descriptor on success
+ * \retval negative errno if an error occured
+ */
+int llapi_open_by_fid_at(int lustre_fd, const struct lu_fid *fid, int flags)
+{
+ struct file_handle *handle;
+ int fd;
+ int rc;
+
+ rc = llapi_fid_to_handle(&handle, fid);
+ if (rc < 0)
+ return rc;
+
+ /* Sadly open_by_handle_at() only works for root, but this is also the
+ * case for the original approach of opening $MOUNT/.lustre/FID.
+ */
+ fd = open_by_handle_at(lustre_fd, handle, flags);
+ rc = -errno;
+ free(handle);
+
+ return fd < 0 ? rc : fd;
+}
+
+/**