/** * 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; }
/* 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; }
/** * 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; }
static int llog_lvfs_prev_block(struct llog_handle *loghandle, int prev_idx, void *buf, int len) { __u64 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); cur_offset = LLOG_CHUNK_SIZE; llog_skip_over(&cur_offset, 0, prev_idx); while (cur_offset < i_size_read(loghandle->lgh_file->f_dentry->d_inode)) { struct llog_rec_hdr *rec; struct llog_rec_tail *tail; loff_t ppos; ppos = cur_offset; rc = fsfilt_read_record(loghandle->lgh_ctxt->loc_exp->exp_obd, loghandle->lgh_file, buf, len, &ppos); if (rc) { CERROR("Cant read llog block at log id "LPU64 "/%u offset "LPU64"\n", loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, cur_offset); RETURN(rc); } /* put number of bytes read into rc to make code simpler */ rc = ppos - cur_offset; cur_offset = ppos; if (rc == 0) /* end of file, nothing to do */ RETURN(0); if (rc < sizeof(*tail)) { CERROR("Invalid llog block at log id "LPU64"/%u offset " LPU64"\n", loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, cur_offset); RETURN(-EINVAL); } tail = buf + rc - sizeof(struct llog_rec_tail); /* this shouldn't happen */ if (tail->lrt_index == 0) { CERROR("Invalid llog tail at log id "LPU64"/%u offset " LPU64"\n", loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, cur_offset); RETURN(-EINVAL); } if (le32_to_cpu(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. */ rec = buf; if (le32_to_cpu(rec->lrh_index) > prev_idx) { CERROR("missed desired record? %u > %u\n", le32_to_cpu(rec->lrh_index), prev_idx); RETURN(-ENOENT); } RETURN(0); } RETURN(-EIO); }
/* 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_lvfs_next_block(struct llog_handle *loghandle, int *cur_idx, int next_idx, __u64 *cur_offset, void *buf, int len) { int rc; ENTRY; 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); while (*cur_offset < i_size_read(loghandle->lgh_file->f_dentry->d_inode)) { struct llog_rec_hdr *rec; struct llog_rec_tail *tail; loff_t ppos; llog_skip_over(cur_offset, *cur_idx, next_idx); ppos = *cur_offset; rc = fsfilt_read_record(loghandle->lgh_ctxt->loc_exp->exp_obd, loghandle->lgh_file, buf, len, &ppos); if (rc) { CERROR("Cant read llog block at log id "LPU64 "/%u offset "LPU64"\n", loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, *cur_offset); RETURN(rc); } /* put number of bytes read into rc to make code simpler */ rc = ppos - *cur_offset; *cur_offset = ppos; 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 */ RETURN(0); if (rc < sizeof(*tail)) { CERROR("Invalid llog block at log id "LPU64"/%u offset " LPU64"\n", loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, *cur_offset); RETURN(-EINVAL); } rec = buf; tail = (struct llog_rec_tail *)((char *)buf + rc - sizeof(struct llog_rec_tail)); if (LLOG_REC_HDR_NEEDS_SWABBING(rec)) { lustre_swab_llog_rec(rec, tail); } *cur_idx = tail->lrt_index; /* this shouldn't happen */ if (tail->lrt_index == 0) { CERROR("Invalid llog tail at log id "LPU64"/%u offset " LPU64"\n", loghandle->lgh_id.lgl_oid, loghandle->lgh_id.lgl_ogen, *cur_offset); RETURN(-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("missed desired record? %u > %u\n", rec->lrh_index, next_idx); RETURN(-ENOENT); } RETURN(0); } RETURN(-EIO); }
static int llog_lvfs_prev_block(const struct lu_env *env, struct llog_handle *loghandle, int prev_idx, void *buf, int len) { __u64 cur_offset; int rc; if (len == 0 || len & (LLOG_CHUNK_SIZE - 1)) return -EINVAL; CDEBUG(D_OTHER, "looking for log index %u\n", prev_idx); cur_offset = LLOG_CHUNK_SIZE; llog_skip_over(&cur_offset, 0, prev_idx); while (cur_offset < i_size_read(loghandle->lgh_file->f_dentry->d_inode)) { struct llog_rec_hdr *rec, *last_rec; struct llog_rec_tail *tail; loff_t ppos = cur_offset; rc = fsfilt_read_record(loghandle->lgh_ctxt->loc_exp->exp_obd, loghandle->lgh_file, buf, len, &cur_offset); if (rc < 0) { CERROR("Cant read llog block at log id "DOSTID "/%u offset %llu\n", POSTID(&loghandle->lgh_id.lgl_oi), loghandle->lgh_id.lgl_ogen, cur_offset); return rc; } /* put number of bytes read into rc to make code simpler */ rc = cur_offset - ppos; if (rc == 0) /* end of file, nothing to do */ return 0; if (rc < sizeof(*tail)) { CERROR("Invalid llog block at log id "DOSTID"/%u offset%llu\n", POSTID(&loghandle->lgh_id.lgl_oi), loghandle->lgh_id.lgl_ogen, cur_offset); return -EINVAL; } rec = buf; if (LLOG_REC_HDR_NEEDS_SWABBING(rec)) lustre_swab_llog_rec(rec); tail = (struct llog_rec_tail *)(buf + rc - sizeof(struct llog_rec_tail)); /* get the last record in block */ last_rec = (struct llog_rec_hdr *)(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("Invalid llog tail at log id "DOSTID"/%u offset%llu\n", POSTID(&loghandle->lgh_id.lgl_oi), loghandle->lgh_id.lgl_ogen, cur_offset); return -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("missed desired record? %u > %u\n", rec->lrh_index, prev_idx); return -ENOENT; } return 0; } return -EIO; }