+static loff_t osd_lseek(const struct lu_env *env, struct dt_object *dt,
+ loff_t offset, int whence)
+{
+ struct osd_object *obj = osd_dt_obj(dt);
+ uint64_t size = obj->oo_attr.la_size;
+ uint64_t result = offset;
+ int rc;
+ boolean_t hole = whence == SEEK_HOLE;
+
+ ENTRY;
+
+ LASSERT(dt_object_exists(dt));
+ LASSERT(osd_invariant(obj));
+ LASSERT(offset >= 0);
+
+ /* for SEEK_HOLE treat 'offset' beyond the end of file as in real
+ * hole. LOV to decide after all if that real hole or not.
+ */
+ if (offset >= size)
+ RETURN(hole ? offset : -ENXIO);
+
+ rc = osd_dmu_offset_next(osd_obj2dev(obj)->od_os,
+ obj->oo_dn->dn_object, hole, &result);
+ if (rc == ESRCH)
+ RETURN(-ENXIO);
+
+ /* file was dirty, so fall back to using generic logic:
+ * For HOLE return file size, for DATA the result is set
+ * already to the 'offset' parameter value.
+ */
+ if (rc == EBUSY && hole)
+ result = size;
+
+ /* dmu_offset_next() only works on whole blocks so may return SEEK_HOLE
+ * result as end of the last block instead of logical EOF which we need
+ */
+ if (result > size)
+ result = size;
+
+ RETURN(result);
+}
+