dt_obj_version_t dt_version_get(const struct lu_env *env, struct dt_object *o);
+int dt_read(const struct lu_env *env, struct dt_object *dt,
+ struct lu_buf *buf, loff_t *pos);
int dt_record_read(const struct lu_env *env, struct dt_object *dt,
struct lu_buf *buf, loff_t *pos);
int dt_record_write(const struct lu_env *env, struct dt_object *dt,
const struct lu_buf *buf, loff_t *pos, struct thandle *th);
-
static inline struct thandle *dt_trans_create(const struct lu_env *env,
struct dt_device *d)
{
LASSERTF(dt != NULL, "dt is NULL when we want to write record\n");
LASSERT(th != NULL);
+ LASSERT(dt->do_body_ops);
+ LASSERT(dt->do_body_ops->dbo_declare_write);
rc = dt->do_body_ops->dbo_declare_write(env, dt, size, pos, th);
return rc;
}
} else if (S_ISLNK(la->la_mode) &&
reqbody->valid & OBD_MD_LINKNAME) {
buffer->lb_buf = ma->ma_lmm;
- buffer->lb_len = reqbody->eadatasize;
+ /* eadatasize from client includes NULL-terminator, so
+ * there is no need to read it */
+ buffer->lb_len = reqbody->eadatasize - 1;
rc = mo_readlink(env, next, buffer);
if (unlikely(rc <= 0)) {
CERROR("readlink failed: %d\n", rc);
if (OBD_FAIL_CHECK(OBD_FAIL_MDS_READLINK_EPROTO))
rc -= 2;
repbody->valid |= OBD_MD_LINKNAME;
- repbody->eadatasize = rc;
+ /* we need to report back size with NULL-terminator
+ * because client expects that */
+ repbody->eadatasize = rc + 1;
+ if (repbody->eadatasize != reqbody->eadatasize)
+ CERROR("Read shorter link %d than expected "
+ "%d\n", rc, reqbody->eadatasize - 1);
/* NULL terminate */
- ((char*)ma->ma_lmm)[rc - 1] = 0;
+ ((char*)ma->ma_lmm)[rc] = 0;
CDEBUG(D_INODE, "symlink dest %s, len = %d\n",
(char*)ma->ma_lmm, rc);
rc = 0;
lu_context_key_degister(&dt_key);
}
+/**
+ * Generic read helper. May return an error for partial reads.
+ *
+ * \param env lustre environment
+ * \param dt object to be read
+ * \param buf lu_buf to be filled, with buffer pointer and length
+ * \param pos position to start reading, updated as data is read
+ *
+ * \retval real size of data read
+ * \retval -ve errno on failure
+ */
+int dt_read(const struct lu_env *env, struct dt_object *dt,
+ struct lu_buf *buf, loff_t *pos)
+{
+ LASSERTF(dt != NULL, "dt is NULL when we want to read record\n");
+ return dt->do_body_ops->dbo_read(env, dt, buf, pos, BYPASS_CAPA);
+}
+EXPORT_SYMBOL(dt_read);
+
+/**
+ * Read structures of fixed size from storage. Unlike dt_read(), using
+ * dt_record_read() will return an error for partial reads.
+ *
+ * \param env lustre environment
+ * \param dt object to be read
+ * \param buf lu_buf to be filled, with buffer pointer and length
+ * \param pos position to start reading, updated as data is read
+ *
+ * \retval 0 on successfully reading full buffer
+ * \retval -EFAULT on short read
+ * \retval -ve errno on failure
+ */
int dt_record_read(const struct lu_env *env, struct dt_object *dt,
struct lu_buf *buf, loff_t *pos)
{
vbuf.lb_len = sizeof(version);
rc = dt_xattr_set(env, o, &vbuf, xname, 0, th, BYPASS_CAPA);
- if (rc != 0)
+ if (rc < 0)
CDEBUG(D_INODE, "Can't set version, rc %d\n", rc);
return;
}
{
struct buffer_head *bh;
unsigned long block;
- int osize = size;
+ int osize;
int blocksize;
int csize;
int boffs;
}
blocksize = 1 << inode->i_blkbits;
+ osize = size;
while (size > 0) {
block = *offs >> inode->i_blkbits;
boffs = *offs & (blocksize - 1);
csize = min(blocksize - boffs, size);
bh = ldiskfs_bread(NULL, inode, block, 0, &err);
if (!bh) {
- CERROR("%s: error reading offset %llu (block %lu): "
- "rc = %d\n",
- inode->i_sb->s_id, *offs, block, err);
+ CERROR("%s: can't read %u@%llu on ino %lu: rc = %d\n",
+ LDISKFS_SB(inode->i_sb)->s_es->s_volume_name,
+ csize, *offs, inode->i_ino, err);
return err;
}