if (rnb == NULL || rnb->rnb_len == 0)
RETURN_EXIT;
- CDEBUG(D_INFO, "Get data buffer along with open, len %i, i_size %llu\n",
- rnb->rnb_len, i_size_read(inode));
+ /* LU-11595: Server may return whole file and that is OK always or
+ * it may return just file tail and its offset must be aligned with
+ * client PAGE_SIZE to be used on that client, if server's PAGE_SIZE is
+ * smaller then offset may be not aligned and that data is just ignored.
+ */
+ if (rnb->rnb_offset % PAGE_SIZE)
+ RETURN_EXIT;
+
+ /* Server returns whole file or just file tail if it fills in
+ * reply buffer, in both cases total size should be inode size.
+ */
+ if (rnb->rnb_offset + rnb->rnb_len < i_size_read(inode)) {
+ CERROR("%s: server returns off/len %llu/%u < i_size %llu\n",
+ ll_get_fsname(inode->i_sb, NULL, 0), rnb->rnb_offset,
+ rnb->rnb_len, i_size_read(inode));
+ RETURN_EXIT;
+ }
+
+ CDEBUG(D_INFO, "Get data along with open at %llu len %i, i_size %llu\n",
+ rnb->rnb_offset, rnb->rnb_len, i_size_read(inode));
data = (char *)rnb + sizeof(*rnb);
len = mbo->mbo_dom_size;
offset = 0;
} else {
- int tail = mbo->mbo_dom_size % PAGE_SIZE;
+ int tail, pgbits;
+
+ /* File tail offset must be aligned with larger page size
+ * between client and server, so the maximum page size is
+ * used here to align offset.
+ *
+ * NB: DOM feature was introduced when server supports pagebits
+ * already, so it should be always non-zero value. Report error
+ * if it is not for some reason.
+ */
+ if (!req->rq_export->exp_target_data.ted_pagebits) {
+ CERROR("%s: client page bits are not saved on server\n",
+ mdt_obd_name(mdt));
+ RETURN(0);
+ }
+ pgbits = max_t(int, PAGE_SHIFT,
+ req->rq_export->exp_target_data.ted_pagebits);
+ tail = mbo->mbo_dom_size % (1 << pgbits);
- /* no tail or tail can't fit in reply */
+ /* no partial tail or tail can't fit in reply */
if (tail == 0 || len < tail)
RETURN(0);
GOTO(out, rc = -E2BIG);
}
- /* re-take MDT_BODY buffer after the buffer growing above */
+ /* re-take MDT_BODY and NIOBUF_INLINE buffers after the buffer grow */
mbo = req_capsule_server_get(pill, &RMF_MDT_BODY);
fid = &mbo->mbo_fid1;
if (!fid_is_sane(fid))
- RETURN(0);
+ GOTO(out, rc = -EINVAL);
rnb = req_capsule_server_get(tsi->tsi_pill, &RMF_NIOBUF_INLINE);
if (rnb == NULL)
GOTO(out, rc = -EPROTO);
+
buf = (char *)rnb + sizeof(*rnb);
rnb->rnb_len = len;
rnb->rnb_offset = offset;
mo = dt_locate(env, dt, fid);
if (IS_ERR(mo))
- GOTO(out, rc = PTR_ERR(mo));
+ GOTO(out_rnb, rc = PTR_ERR(mo));
LASSERT(mo != NULL);
dt_read_lock(env, mo, 0);
}
CDEBUG(D_INFO, "Read %i (wanted %u) bytes from %llu\n", copied,
len, offset);
- if (copied < len)
+ if (copied < len) {
CWARN("%s: read %i bytes for "DFID
" but wanted %u, is size wrong?\n",
tsi->tsi_exp->exp_obd->obd_name, copied,
PFID(&tsi->tsi_fid), len);
+ /* Ignore partially copied data */
+ copied = 0;
+ }
EXIT;
buf_put:
dt_bufs_put(env, mo, lnb, nr_local);
unlock:
dt_read_unlock(env, mo);
lu_object_put(env, &mo->do_lu);
+out_rnb:
+ rnb->rnb_len = copied;
out:
- if (rnb != NULL)
- rnb->rnb_len = copied;
+ /* Don't fail OPEN request if read-on-open is failed, but drop
+ * a message in log about the error.
+ */
+ if (rc)
+ CDEBUG(D_INFO, "Read-on-open is failed, rc = %d", rc);
+
RETURN(0);
}