AC_DEFINE(HAVE_DMU_OBJSET_DISOWN_3ARG, 1,
[Have dmu_objset_disown() with 3 args])
])
+ dnl #
+ dnl # ZFS exports dmu_offet_next
+ dnl #
+ AC_CACHE_CHECK([if ZFS exports 'dmu_offset_next'],
+ [lb_cv_dmu_offset_next], [
+ lb_cv_dmu_offset_next="no"
+ AS_IF([grep -q -E "EXPORT_SYMBOL.*\(dmu_offset_next\)" "$zfssrc/module/zfs/dmu.c" 2>/dev/null],
+ [lb_cv_dmu_offset_next="yes"])
+ ])
+ AS_IF([test "x$lb_cv_dmu_offset_next" = "xyes"], [
+ AC_DEFINE(HAVE_DMU_OFFSET_NEXT, 1,
+ [Have dmu_offset_next() exported])
+ ])
])
AS_IF([test "x$enable_zfs" = xyes], [
__u64 end,
int mode,
struct thandle *th);
+ /**
+ * Do SEEK_HOLE/SEEK_DATA request on object
+ *
+ * \param[in] env execution environment for this thread
+ * \param[in] dt object
+ * \param[in] offset the offset to start seek from
+ * \param[in] whence seek mode, SEEK_HOLE or SEEK_DATA
+ *
+ * \retval hole/data offset on success
+ * \retval negative negated errno on error
+ */
+ loff_t (*dbo_lseek)(const struct lu_env *env, struct dt_object *dt,
+ loff_t offset, int whence);
};
/**
return d->do_body_ops->dbo_fiemap_get(env, d, fm);
}
+static inline loff_t dt_lseek(const struct lu_env *env, struct dt_object *d,
+ loff_t offset, int whence)
+{
+ LASSERT(d);
+ if (d->do_body_ops == NULL)
+ return -EPROTO;
+ if (d->do_body_ops->dbo_lseek == NULL)
+ return -EOPNOTSUPP;
+ return d->do_body_ops->dbo_lseek(env, d, offset, whence);
+}
+
static inline int dt_statfs_info(const struct lu_env *env,
struct dt_device *dev,
struct obd_statfs *osfs,
{
struct lu_buf *buf = &oti->oti_big_buf;
struct dentry *dentry = &oti->oti_obj_dentry;
- struct file *filp = &oti->oti_file;
- const struct file_operations *fops;
+ struct file *filp;
struct lmv_mds_md_v1 *lmv1;
struct osd_check_lmv_buf oclb = {
.ctx.actor = osd_stripe_dir_filldir,
if (le32_to_cpu(lmv1->lmv_magic) != LMV_MAGIC_V1)
GOTO(out, rc = 0);
- fops = inode->i_fop;
- dentry->d_inode = inode;
- dentry->d_sb = inode->i_sb;
- filp->f_pos = 0;
- filp->f_path.dentry = dentry;
- filp->f_flags |= O_NOATIME;
- filp->f_mode = FMODE_64BITHASH | FMODE_NONOTIFY;
- filp->f_mapping = inode->i_mapping;
- filp->f_op = fops;
- filp->private_data = NULL;
- filp->f_cred = current_cred();
- filp->f_inode = inode;
+ filp = osd_quasi_file(oti->oti_env, inode);
rc = osd_security_file_alloc(filp);
if (rc)
goto out;
rc = iterate_dir(filp, &oclb.ctx);
} while (rc >= 0 && oclb.oclb_items > 0 && !oclb.oclb_found &&
filp->f_pos != LDISKFS_HTREE_EOF_64BIT);
- fops->release(inode, filp);
+ inode->i_fop->release(inode, filp);
out:
if (rc < 0)
{
struct osd_object *obj = osd_dt_obj(dt);
struct inode *inode = obj->oo_inode;
- struct osd_thread_info *info = osd_oti_get(env);
- struct dentry *dentry = &info->oti_obj_dentry;
- struct file *file = &info->oti_file;
+ struct file *file = osd_quasi_file(env, inode);
int rc;
ENTRY;
- dentry->d_inode = inode;
- dentry->d_sb = inode->i_sb;
- file->f_path.dentry = dentry;
- file->f_mapping = inode->i_mapping;
- file->f_op = inode->i_fop;
- file->f_inode = inode;
-
rc = vfs_fsync_range(file, start, end, 0);
RETURN(rc);
return child_dentry;
}
+/* build quasi file structure when it is needed to call an inode i_fop */
+static inline struct file *osd_quasi_file_init(const struct lu_env *env,
+ struct dentry *dentry,
+ struct inode *inode)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+
+ info->oti_file.f_path.dentry = dentry;
+ info->oti_file.f_mapping = inode->i_mapping;
+ info->oti_file.f_op = inode->i_fop;
+ info->oti_file.f_inode = inode;
+ info->oti_file.f_pos = 0;
+ info->oti_file.private_data = NULL;
+ info->oti_file.f_cred = current_cred();
+ info->oti_file.f_flags = O_NOATIME;
+ info->oti_file.f_mode = FMODE_64BITHASH | FMODE_NONOTIFY;
+
+ return &info->oti_file;
+}
+
+static inline struct file *osd_quasi_file(const struct lu_env *env,
+ struct inode *inode)
+{
+ struct osd_thread_info *info = osd_oti_get(env);
+
+ info->oti_obj_dentry.d_inode = inode;
+ info->oti_obj_dentry.d_sb = inode->i_sb;
+
+ return osd_quasi_file_init(env, &info->oti_obj_dentry, inode);
+}
+
+static inline struct file *osd_quasi_file_by_dentry(const struct lu_env *env,
+ struct dentry *dentry)
+{
+ return osd_quasi_file_init(env, dentry, dentry->d_inode);
+}
+
extern int osd_trans_declare_op2rb[];
extern int ldiskfs_track_declares_assert;
void osd_trans_dump_creds(const struct lu_env *env, struct thandle *th);
{
struct osd_object *obj = osd_dt_obj(dt);
struct inode *inode = obj->oo_inode;
+ struct file *file;
int rc = 0;
- struct osd_thread_info *info = osd_oti_get(env);
- struct dentry *dentry = &info->oti_obj_dentry;
- struct file *file = &info->oti_file;
ENTRY;
/*
/*
* Because f_op->fallocate() does not have an inode arg
*/
- dentry->d_inode = inode;
- dentry->d_sb = inode->i_sb;
- file->f_path.dentry = dentry;
- file->f_mapping = inode->i_mapping;
- file->f_op = inode->i_fop;
- file->f_inode = inode;
+ file = osd_quasi_file(env, inode);
rc = file->f_op->fallocate(file, mode, start, end - start);
RETURN(rc);
RETURN(rc);
}
+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);
+ struct inode *inode = obj->oo_inode;
+ struct file *file;
+ loff_t result;
+
+ ENTRY;
+
+ LASSERT(dt_object_exists(dt));
+ LASSERT(osd_invariant(obj));
+ LASSERT(inode);
+
+ file = osd_quasi_file(env, inode);
+ result = file->f_op->llseek(file, offset, whence);
+ /* when result is out of file range then it must be virtual hole
+ * at the end of file, but this is not real file end, so return
+ * just -ENXIO and LOV will merge all results
+ */
+ if (result == i_size_read(inode))
+ result = -ENXIO;
+
+ CDEBUG(D_INFO, "seek %s from %lld: %lld\n", whence == SEEK_HOLE ?
+ "hole" : "data", offset, result);
+ RETURN(result);
+}
+
/*
* in some cases we may need declare methods for objects being created
* e.g., when we create symlink
.dbo_ladvise = osd_ladvise,
.dbo_declare_fallocate = osd_declare_fallocate,
.dbo_fallocate = osd_fallocate,
+ .dbo_lseek = osd_lseek,
};
/**
osd_ios_general_scan(struct osd_thread_info *info, struct osd_device *dev,
struct dentry *dentry, filldir_t filldir)
{
- struct osd_ios_filldir_buf buf = {
- .ctx.actor = filldir,
- .oifb_info = info,
- .oifb_dev = dev,
- .oifb_dentry = dentry };
- struct file *filp = &info->oti_file;
- struct inode *inode = dentry->d_inode;
- const struct file_operations *fops = inode->i_fop;
- int rc;
+ struct osd_ios_filldir_buf buf = {
+ .ctx.actor = filldir,
+ .oifb_info = info,
+ .oifb_dev = dev,
+ .oifb_dentry = dentry
+ };
+ struct file *filp;
+ struct inode *inode = dentry->d_inode;
+ int rc;
+
ENTRY;
LASSERT(filldir != NULL);
- filp->f_pos = 0;
- filp->f_path.dentry = dentry;
- filp->f_flags |= O_NOATIME;
- filp->f_mode = FMODE_64BITHASH | FMODE_NONOTIFY;
- filp->f_mapping = inode->i_mapping;
- filp->f_op = fops;
- filp->private_data = NULL;
- filp->f_cred = current_cred();
- filp->f_inode = inode;
+ filp = osd_quasi_file_by_dentry(info->oti_env, dentry);
rc = osd_security_file_alloc(filp);
if (rc)
RETURN(rc);
rc = iterate_dir(filp, &buf.ctx);
} while (rc >= 0 && buf.oifb_items > 0 &&
filp->f_pos != LDISKFS_HTREE_EOF_64BIT);
- fops->release(inode, filp);
+ inode->i_fop->release(inode, filp);
RETURN(rc);
}
RETURN(rc);
}
+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));
+
+ if (offset < 0 || offset >= size)
+ RETURN(-ENXIO);
+
+#ifdef HAVE_DMU_OFFSET_NEXT
+ rc = dmu_offset_next(osd_obj2dev(obj)->od_os, obj->oo_dn->dn_object,
+ hole, &result);
+ if (rc == ESRCH)
+ RETURN(-ENXIO);
+#else
+ /*
+ * In absence of dmu_offset_next() just do nothing but
+ * return EBUSY as does dmu_offset_next() and that means
+ * generic approach should be used.
+ */
+ rc = EBUSY;
+#endif
+ /* file was dirty, so fall back to using generic logic */
+ if (rc == EBUSY && hole)
+ RETURN(-ENXIO); /* see comment below */
+
+ /* when result is out of file range then it must be virtual hole
+ * at the end of file, but this is not real file end, so return
+ * just -ENXIO and LOV will translate it properly.
+ */
+ if (result >= size)
+ RETURN(-ENXIO);
+
+ RETURN(result);
+}
+
struct dt_body_operations osd_body_ops = {
.dbo_read = osd_read,
.dbo_declare_write = osd_declare_write,
.dbo_ladvise = osd_ladvise,
.dbo_declare_fallocate = osd_declare_fallocate,
.dbo_fallocate = osd_fallocate,
+ .dbo_lseek = osd_lseek,
};
struct dt_body_operations osd_body_scrub_ops = {