Ejemplo n.º 1
0
/**
 * Implementation of the llog_operations::lop_prev_block
 *
 * This function finds the llog block to return which contains
 * record with required index but in reverse order - from end of llog
 * to the beginning.
 * It is main part of reverse llog processing.
 *
 * \param[in] env	execution environment
 * \param[in] loghandle	llog handle of the current llog
 * \param[in] prev_idx	target index to find
 * \param[in] buf	pointer to data buffer to fill
 * \param[in] len	required len to read, it is LLOG_CHUNK_SIZE usually.
 *
 * \retval		0 on successful buffer read
 * \retval		negative value on error
 */
static int llog_osd_prev_block(const struct lu_env *env,
			       struct llog_handle *loghandle,
			       int prev_idx, void *buf, int len)
{
	struct llog_thread_info	*lgi = llog_info(env);
	struct dt_object	*o;
	struct dt_device	*dt;
	loff_t			 cur_offset;
	int			 rc;

	ENTRY;

	if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
		RETURN(-EINVAL);

	CDEBUG(D_OTHER, "looking for log index %u\n", prev_idx);

	LASSERT(loghandle);
	LASSERT(loghandle->lgh_ctxt);

	o = loghandle->lgh_obj;
	LASSERT(o);
	LASSERT(dt_object_exists(o));
	dt = lu2dt_dev(o->do_lu.lo_dev);
	LASSERT(dt);

	cur_offset = LLOG_CHUNK_SIZE;
	llog_skip_over(&cur_offset, 0, prev_idx);

	rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA);
	if (rc)
		GOTO(out, rc);

	while (cur_offset < lgi->lgi_attr.la_size) {
		struct llog_rec_hdr	*rec, *last_rec;
		struct llog_rec_tail	*tail;

		lgi->lgi_buf.lb_len = len;
		lgi->lgi_buf.lb_buf = buf;
		rc = dt_read(env, o, &lgi->lgi_buf, &cur_offset);
		if (rc < 0) {
			CERROR("%s: can't read llog block from log "DFID
			       " offset "LPU64": rc = %d\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       PFID(lu_object_fid(&o->do_lu)), cur_offset, rc);
			GOTO(out, rc);
		}

		if (rc == 0) /* end of file, nothing to do */
			GOTO(out, rc);

		if (rc < sizeof(*tail)) {
			CERROR("%s: invalid llog block at log id "DOSTID"/%u "
			       "offset "LPU64"\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       POSTID(&loghandle->lgh_id.lgl_oi),
			       loghandle->lgh_id.lgl_ogen, cur_offset);
			GOTO(out, rc = -EINVAL);
		}

		rec = buf;
		if (LLOG_REC_HDR_NEEDS_SWABBING(rec))
			lustre_swab_llog_rec(rec);

		tail = (struct llog_rec_tail *)((char *)buf + rc -
						sizeof(struct llog_rec_tail));
		/* get the last record in block */
		last_rec = (struct llog_rec_hdr *)((char *)buf + rc -
						   le32_to_cpu(tail->lrt_len));

		if (LLOG_REC_HDR_NEEDS_SWABBING(last_rec))
			lustre_swab_llog_rec(last_rec);
		LASSERT(last_rec->lrh_index == tail->lrt_index);

		/* this shouldn't happen */
		if (tail->lrt_index == 0) {
			CERROR("%s: invalid llog tail at log id "DOSTID"/%u "
			       "offset "LPU64"\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       POSTID(&loghandle->lgh_id.lgl_oi),
			       loghandle->lgh_id.lgl_ogen, cur_offset);
			GOTO(out, rc = -EINVAL);
		}
		if (tail->lrt_index < prev_idx)
			continue;

		/* sanity check that the start of the new buffer is no farther
		 * than the record that we wanted.  This shouldn't happen. */
		if (rec->lrh_index > prev_idx) {
			CERROR("%s: missed desired record? %u > %u\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       rec->lrh_index, prev_idx);
			GOTO(out, rc = -ENOENT);
		}
		GOTO(out, rc = 0);
	}
	GOTO(out, rc = -EIO);
out:
	return rc;
}
Ejemplo n.º 2
0
static int out_read(struct tgt_session_info *tsi)
{
	const struct lu_env	*env = tsi->tsi_env;
	struct tgt_thread_info	*tti = tgt_th_info(env);
	struct object_update	*update = tti->tti_u.update.tti_update;
	struct dt_object	*obj = tti->tti_u.update.tti_dt_object;
	struct object_update_reply *reply = tti->tti_u.update.tti_update_reply;
	int index = tti->tti_u.update.tti_update_reply_index;
	struct lu_rdbuf	*rdbuf;
	struct object_update_result *update_result;
	struct out_read_reply	*orr;
	void *tmp;
	size_t size;
	size_t total_size = 0;
	__u64 pos;
	unsigned int i;
	unsigned int nbufs;
	int rc = 0;
	ENTRY;

	update_result = object_update_result_get(reply, index, NULL);
	LASSERT(update_result != NULL);
	update_result->our_datalen = sizeof(*orr);

	if (!lu_object_exists(&obj->do_lu))
		GOTO(out, rc = -ENOENT);

	tmp = object_update_param_get(update, 0, NULL);
	if (IS_ERR(tmp)) {
		CERROR("%s: empty size for read: rc = %ld\n",
		       tgt_name(tsi->tsi_tgt), PTR_ERR(tmp));
		GOTO(out, rc = PTR_ERR(tmp));
	}
	size = le64_to_cpu(*(size_t *)(tmp));

	tmp = object_update_param_get(update, 1, NULL);
	if (IS_ERR(tmp)) {
		CERROR("%s: empty pos for read: rc = %ld\n",
		       tgt_name(tsi->tsi_tgt), PTR_ERR(tmp));
		GOTO(out, rc = PTR_ERR(tmp));
	}
	pos = le64_to_cpu(*(__u64 *)(tmp));

	/* Put the offset into the begining of the buffer in reply */
	orr = (struct out_read_reply *)update_result->our_data;

	nbufs = (size + OUT_BULK_BUFFER_SIZE - 1) / OUT_BULK_BUFFER_SIZE;
	OBD_ALLOC(rdbuf, sizeof(struct lu_rdbuf) +
			 nbufs * sizeof(rdbuf->rb_bufs[0]));
	if (rdbuf == NULL)
		GOTO(out, rc = -ENOMEM);

	rdbuf->rb_nbufs = 0;
	total_size = 0;
	for (i = 0; i < nbufs; i++) {
		__u32 read_size;

		read_size = size > OUT_BULK_BUFFER_SIZE ?
			    OUT_BULK_BUFFER_SIZE : size;
		OBD_ALLOC(rdbuf->rb_bufs[i].lb_buf, read_size);
		if (rdbuf->rb_bufs[i].lb_buf == NULL)
			GOTO(out_free, rc = -ENOMEM);

		rdbuf->rb_bufs[i].lb_len = read_size;
		dt_read_lock(env, obj, MOR_TGT_CHILD);
		rc = dt_read(env, obj, &rdbuf->rb_bufs[i], &pos);
		dt_read_unlock(env, obj);

		total_size += rc < 0 ? 0 : rc;
		if (rc <= 0)
			break;

		rdbuf->rb_nbufs++;
		size -= read_size;
	}

	/* send pages to client */
	rc = tgt_send_buffer(tsi, rdbuf);
	if (rc < 0)
		GOTO(out_free, rc);

	orr->orr_size = total_size;
	orr->orr_offset = pos;

	orr_cpu_to_le(orr, orr);
	update_result->our_datalen += orr->orr_size;
out_free:
	for (i = 0; i < nbufs; i++) {
		if (rdbuf->rb_bufs[i].lb_buf != NULL) {
			OBD_FREE(rdbuf->rb_bufs[i].lb_buf,
				 rdbuf->rb_bufs[i].lb_len);
		}
	}
	OBD_FREE(rdbuf, sizeof(struct lu_rdbuf) +
			nbufs * sizeof(rdbuf->rb_bufs[0]));
out:
	/* Insert read buffer */
	update_result->our_rc = ptlrpc_status_hton(rc);
	reply->ourp_lens[index] = cfs_size_round(update_result->our_datalen +
						 sizeof(*update_result));
	RETURN(rc);
}
Ejemplo n.º 3
0
/* sets:
 *  - cur_offset to the furthest point read in the log file
 *  - cur_idx to the log index preceeding cur_offset
 * returns -EIO/-EINVAL on error
 */
static int llog_osd_next_block(const struct lu_env *env,
			       struct llog_handle *loghandle, int *cur_idx,
			       int next_idx, __u64 *cur_offset, void *buf,
			       int len)
{
	struct llog_thread_info	*lgi = llog_info(env);
	struct dt_object	*o;
	struct dt_device	*dt;
	int			 rc;

	ENTRY;

	LASSERT(env);
	LASSERT(lgi);

	if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
		RETURN(-EINVAL);

	CDEBUG(D_OTHER, "looking for log index %u (cur idx %u off "LPU64")\n",
	       next_idx, *cur_idx, *cur_offset);

	LASSERT(loghandle);
	LASSERT(loghandle->lgh_ctxt);

	o = loghandle->lgh_obj;
	LASSERT(o);
	LASSERT(dt_object_exists(o));
	dt = lu2dt_dev(o->do_lu.lo_dev);
	LASSERT(dt);

	rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA);
	if (rc)
		GOTO(out, rc);

	while (*cur_offset < lgi->lgi_attr.la_size) {
		struct llog_rec_hdr	*rec, *last_rec;
		struct llog_rec_tail	*tail;

		llog_skip_over(cur_offset, *cur_idx, next_idx);

		/* read up to next LLOG_CHUNK_SIZE block */
		lgi->lgi_buf.lb_len = LLOG_CHUNK_SIZE -
				      (*cur_offset & (LLOG_CHUNK_SIZE - 1));
		lgi->lgi_buf.lb_buf = buf;

		/* Note: read lock is not needed around la_size get above at
		 * the time of dt_attr_get(). There are only two cases that
		 * matter. Either la_size == cur_offset, in which case the
		 * entire read is skipped, or la_size > cur_offset and the loop
		 * is entered and this thread is blocked at dt_read_lock()
		 * until the write is completed. When the write completes, then
		 * the dt_read() will be done with the full length, and will
		 * get the full data.
		 */
		dt_read_lock(env, o, 0);
		rc = dt_read(env, o, &lgi->lgi_buf, cur_offset);
		dt_read_unlock(env, o);
		if (rc < 0) {
			CERROR("%s: can't read llog block from log "DFID
			       " offset "LPU64": rc = %d\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       PFID(lu_object_fid(&o->do_lu)), *cur_offset,
			       rc);
			GOTO(out, rc);
		}

		if (rc < len) {
			/* signal the end of the valid buffer to
			 * llog_process */
			memset(buf + rc, 0, len - rc);
		}

		if (rc == 0) /* end of file, nothing to do */
			GOTO(out, rc);

		if (rc < sizeof(*tail)) {
			CERROR("%s: invalid llog block at log id "LPU64"/%u "
			       "offset "LPU64"\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       loghandle->lgh_id.lgl_oid,
			       loghandle->lgh_id.lgl_ogen, *cur_offset);
			GOTO(out, rc = -EINVAL);
		}

		rec = buf;
		if (LLOG_REC_HDR_NEEDS_SWABBING(rec))
			lustre_swab_llog_rec(rec);

		tail = (struct llog_rec_tail *)((char *)buf + rc -
						sizeof(struct llog_rec_tail));
		/* get the last record in block */
		last_rec = (struct llog_rec_hdr *)((char *)buf + rc -
						   le32_to_cpu(tail->lrt_len));

		if (LLOG_REC_HDR_NEEDS_SWABBING(last_rec))
			lustre_swab_llog_rec(last_rec);
		LASSERT(last_rec->lrh_index == tail->lrt_index);

		*cur_idx = tail->lrt_index;

		/* this shouldn't happen */
		if (tail->lrt_index == 0) {
			CERROR("%s: invalid llog tail at log id "LPU64"/%u "
			       "offset "LPU64"\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       loghandle->lgh_id.lgl_oid,
			       loghandle->lgh_id.lgl_ogen, *cur_offset);
			GOTO(out, rc = -EINVAL);
		}
		if (tail->lrt_index < next_idx)
			continue;

		/* sanity check that the start of the new buffer is no farther
		 * than the record that we wanted.  This shouldn't happen. */
		if (rec->lrh_index > next_idx) {
			CERROR("%s: missed desired record? %u > %u\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       rec->lrh_index, next_idx);
			GOTO(out, rc = -ENOENT);
		}
		GOTO(out, rc = 0);
	}
	GOTO(out, rc = -EIO);
out:
	return rc;
}
Ejemplo n.º 4
0
/**
 * Implementation of the llog_operations::lop_next_block
 *
 * This function finds the the next llog block to return which contains
 * record with required index. It is main part of llog processing.
 *
 * \param[in]     env		execution environment
 * \param[in]     loghandle	llog handle of the current llog
 * \param[in,out] cur_idx	index preceeding cur_offset
 * \param[in]     next_idx	target index to find
 * \param[in,out] cur_offset	furtherst point read in the file
 * \param[in]     buf		pointer to data buffer to fill
 * \param[in]     len		required len to read, it is
 *				LLOG_CHUNK_SIZE usually.
 *
 * \retval			0 on successful buffer read
 * \retval			negative value on error
 */
static int llog_osd_next_block(const struct lu_env *env,
			       struct llog_handle *loghandle, int *cur_idx,
			       int next_idx, __u64 *cur_offset, void *buf,
			       int len)
{
	struct llog_thread_info	*lgi = llog_info(env);
	struct dt_object	*o;
	struct dt_device	*dt;
	int			 rc;

	ENTRY;

	LASSERT(env);
	LASSERT(lgi);

	if (len == 0 || len & (LLOG_CHUNK_SIZE - 1))
		RETURN(-EINVAL);

	CDEBUG(D_OTHER, "looking for log index %u (cur idx %u off "LPU64")\n",
	       next_idx, *cur_idx, *cur_offset);

	LASSERT(loghandle);
	LASSERT(loghandle->lgh_ctxt);

	o = loghandle->lgh_obj;
	LASSERT(o);
	LASSERT(dt_object_exists(o));
	dt = lu2dt_dev(o->do_lu.lo_dev);
	LASSERT(dt);

	rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA);
	if (rc)
		GOTO(out, rc);

	while (*cur_offset < lgi->lgi_attr.la_size) {
		struct llog_rec_hdr	*rec, *last_rec;
		struct llog_rec_tail	*tail;

		llog_skip_over(cur_offset, *cur_idx, next_idx);

		/* read up to next LLOG_CHUNK_SIZE block */
		lgi->lgi_buf.lb_len = LLOG_CHUNK_SIZE -
				      (*cur_offset & (LLOG_CHUNK_SIZE - 1));
		lgi->lgi_buf.lb_buf = buf;

		rc = dt_read(env, o, &lgi->lgi_buf, cur_offset);
		if (rc < 0) {
			CERROR("%s: can't read llog block from log "DFID
			       " offset "LPU64": rc = %d\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       PFID(lu_object_fid(&o->do_lu)), *cur_offset,
			       rc);
			GOTO(out, rc);
		}

		if (rc < len) {
			/* signal the end of the valid buffer to
			 * llog_process */
			memset(buf + rc, 0, len - rc);
		}

		if (rc == 0) /* end of file, nothing to do */
			GOTO(out, rc);

		if (rc < sizeof(*tail)) {
			CERROR("%s: invalid llog block at log id "DOSTID"/%u "
			       "offset "LPU64"\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       POSTID(&loghandle->lgh_id.lgl_oi),
			       loghandle->lgh_id.lgl_ogen, *cur_offset);
			GOTO(out, rc = -EINVAL);
		}

		rec = buf;
		if (LLOG_REC_HDR_NEEDS_SWABBING(rec))
			lustre_swab_llog_rec(rec);

		tail = (struct llog_rec_tail *)((char *)buf + rc -
						sizeof(struct llog_rec_tail));
		/* get the last record in block */
		last_rec = (struct llog_rec_hdr *)((char *)buf + rc -
						   tail->lrt_len);

		if (LLOG_REC_HDR_NEEDS_SWABBING(last_rec))
			lustre_swab_llog_rec(last_rec);
		LASSERT(last_rec->lrh_index == tail->lrt_index);

		*cur_idx = tail->lrt_index;

		/* this shouldn't happen */
		if (tail->lrt_index == 0) {
			CERROR("%s: invalid llog tail at log id "DOSTID"/%u "
			       "offset "LPU64"\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       POSTID(&loghandle->lgh_id.lgl_oi),
			       loghandle->lgh_id.lgl_ogen, *cur_offset);
			GOTO(out, rc = -EINVAL);
		}
		if (tail->lrt_index < next_idx)
			continue;

		/* sanity check that the start of the new buffer is no farther
		 * than the record that we wanted.  This shouldn't happen. */
		if (rec->lrh_index > next_idx) {
			CERROR("%s: missed desired record? %u > %u\n",
			       o->do_lu.lo_dev->ld_obd->obd_name,
			       rec->lrh_index, next_idx);
			GOTO(out, rc = -ENOENT);
		}

		/* Trim unsupported extensions for compat w/ older clients */
		if (!(loghandle->lgh_hdr->llh_flags & LLOG_F_EXT_JOBID))
			changelog_block_trim_ext(rec, last_rec,
						 CLF_VERSION | CLF_RENAME);

		GOTO(out, rc = 0);
	}
	GOTO(out, rc = -EIO);
out:
	return rc;
}