Fix lov_mds_md in mdd_create_objects error handler.
Checking whether obd_fail before fsfilt_start.
Free fcc no matter whether fsfilt_commit success or failed.
b=10818
i=adilger
i=green
Details : Direct I/O operations should return actual amount of bytes
transferred rather than requested size.
+Severity : normal
+Frequency : rare
+Bugzilla : 10818
+Description: Memory leak in recovery
+Details : Lov_mds_md was not free in an error handler in mds_create_object.
+ It should also check obd_fail before fsfilt_start, otherwise if
+ fsfilt_start return -EROFS,(failover mds during mds recovery).
+ then the req will return with repmsg->transno = 0 and rc = EROFS.
+ and we met hit the assert LASSERT(req->rq_reqmsg->transno ==
+ req->rq_repmsg->transno) in ptlrpc_replay_interpret. Fcc should
+ be freed no matter whether fsfilt_commit success or not.
+
--------------------------------------------------------------------------------
2007-05-03 Cluster File Systems, Inc. <info@clusterfs.com>
ldlm_policy_data_t *p2_policy);
void mds_commit_cb(struct obd_device *, __u64 last_rcvd, void *data, int error);
int mds_finish_transno(struct mds_obd *mds, struct inode *inode, void *handle,
- struct ptlrpc_request *req, int rc, __u32 op_data);
+ struct ptlrpc_request *req, int rc, __u32 op_data,
+ int force_sync);
void mds_reconstruct_generic(struct ptlrpc_request *req);
void mds_req_from_mcd(struct ptlrpc_request *req, struct mds_client_data *mcd);
int mds_get_parent_child_locked(struct obd_device *obd, struct mds_obd *mds,
sizeof(struct lov_mds_md_join), "lov");
mds_finish_join(mds, req, head_inode, head_lmmj);
cleanup:
- rc = mds_finish_transno(mds, head_inode, handle, req, rc, 0);
+ rc = mds_finish_transno(mds, head_inode, handle, req, rc, 0, 0);
switch(cleanup_phase){
case 3:
llog_close(llh_head);
if (IS_ERR(*handle)) {
rc = PTR_ERR(*handle);
*handle = NULL;
- GOTO(out_oa, rc);
+ GOTO(free_diskmd, rc);
}
rc = fsfilt_set_md(obd, inode, *handle, lmm, lmm_size, "lov");
lmm_buf = lustre_msg_buf(req->rq_repmsg, offset, lmm_size);
LASSERT(lmm_buf);
memcpy(lmm_buf, lmm, lmm_size);
+ free_diskmd:
obd_free_diskmd(mds->mds_osc_exp, &lmm);
out_oa:
oti_free_cookies(&oti);
rc = mds_finish_open(req, dchild, body, flags, &handle, rec, rep, NULL);
rc = mds_finish_transno(mds, dchild->d_inode, handle,
- req, rc, rep ? rep->lock_policy_res1 : 0);
+ req, rc, rep ? rep->lock_policy_res1 : 0, 0);
/* XXX what do we do here if mds_finish_transno itself failed? */
l_dput(dchild);
cleanup:
rc = mds_finish_transno(mds, dchild ? dchild->d_inode : NULL, handle,
- req, rc, rep ? rep->lock_policy_res1 : 0);
+ req, rc, rep ? rep->lock_policy_res1 : 0, 0);
cleanup_no_trans:
switch (cleanup_phase) {
cleanup:
if (req != NULL && reply_body != NULL) {
- rc = mds_finish_transno(mds, pending_dir, handle, req, rc, 0);
+ rc = mds_finish_transno(mds, pending_dir, handle, req, rc, 0, 0);
} else if (handle) {
int err = fsfilt_commit(obd, pending_dir, handle, 0);
if (err) {
/* Assumes caller has already pushed us into the kernel context. */
int mds_finish_transno(struct mds_obd *mds, struct inode *inode, void *handle,
- struct ptlrpc_request *req, int rc, __u32 op_data)
+ struct ptlrpc_request *req, int rc, __u32 op_data,
+ int force_sync)
{
struct mds_export_data *med = &req->rq_export->exp_mds_data;
struct mds_client_data *mcd = med->med_mcd;
}
/* if the export has already been failed, we have no last_rcvd slot */
- if (req->rq_export->exp_failed) {
+ if (req->rq_export->exp_failed || obd->obd_fail) {
CWARN("commit transaction for disconnected client %s: rc %d\n",
req->rq_export->exp_client_uuid.uuid, rc);
if (rc == 0)
CERROR("client idx %d has offset %lld\n", med->med_lr_idx, off);
err = -EINVAL;
} else {
- fsfilt_add_journal_cb(req->rq_export->exp_obd, transno, handle,
- mds_commit_cb, NULL);
+ struct obd_export *exp = req->rq_export;
+
+ if (!force_sync)
+ force_sync = fsfilt_add_journal_cb(exp->exp_obd,transno,
+ handle, mds_commit_cb,
+ NULL);
+
err = fsfilt_write_record(obd, mds->mds_rcvd_filp, mcd,
- sizeof(*mcd), &off,
- req->rq_export->exp_need_sync);
+ sizeof(*mcd), &off,
+ force_sync | exp->exp_need_sync);
+ if (force_sync)
+ mds_commit_cb(obd, transno, NULL, err);
}
if (err) {
struct lov_mds_md *lmm = NULL;
struct llog_cookie *logcookies = NULL;
int lmm_size = 0, need_lock = 1, cookie_size = 0;
- int rc = 0, cleanup_phase = 0, err, locked = 0;
+ int rc = 0, cleanup_phase = 0, err, locked = 0, sync = 0;
unsigned int qcids[MAXQUOTAS] = { 0, 0 };
unsigned int qpids[MAXQUOTAS] = { rec->ur_iattr.ia_uid,
rec->ur_iattr.ia_gid };
EXIT;
cleanup:
if (mlcd != NULL)
- fsfilt_add_journal_cb(req->rq_export->exp_obd, 0, handle,
- mds_cancel_cookies_cb, mlcd);
- err = mds_finish_transno(mds, inode, handle, req, rc, 0);
+ sync = fsfilt_add_journal_cb(req->rq_export->exp_obd, 0, handle,
+ mds_cancel_cookies_cb, mlcd);
+ err = mds_finish_transno(mds, inode, handle, req, rc, 0, sync);
/* do mds to ost setattr if needed */
if (!rc && !err && lmm_size)
mds_osc_setattr_async(obd, inode, lmm, lmm_size,
EXIT;
cleanup:
- err = mds_finish_transno(mds, dir, handle, req, rc, 0);
+ err = mds_finish_transno(mds, dir, handle, req, rc, 0, 0);
if (rc && created) {
/* Destroy the file we just created. This should not need
}
rc = mds_finish_transno(mds, dparent ? dparent->d_inode : NULL,
- handle, req, rc, 0);
+ handle, req, rc, 0, 0);
if (!rc)
(void)obd_set_info_async(mds->mds_osc_exp, strlen("unlinked"),
"unlinked", 0, NULL, NULL);
CERROR("vfs_link error %d\n", rc);
cleanup:
rc = mds_finish_transno(mds, de_tgt_dir ? de_tgt_dir->d_inode : NULL,
- handle, req, rc, 0);
+ handle, req, rc, 0, 0);
EXIT;
switch (cleanup_phase) {
GOTO(cleanup, rc);
cleanup:
rc = mds_finish_transno(mds, de_tgtdir ? de_tgtdir->d_inode : NULL,
- handle, req, rc, 0);
+ handle, req, rc, 0, 0);
switch (cleanup_phase) {
case 4:
LASSERT(rc <= 0);
out_trans:
- err = mds_finish_transno(mds, inode, handle, req, rc, 0);
+ err = mds_finish_transno(mds, inode, handle, req, rc, 0, 0);
out_dput:
l_dput(de);
/* Assumes caller has already pushed us into the kernel context. */
int filter_finish_transno(struct obd_export *exp, struct obd_trans_info *oti,
- int rc)
+ int rc, int force_sync)
{
struct filter_obd *filter = &exp->exp_obd->u.filter;
struct filter_export_data *fed = &exp->exp_filter_data;
fed->fed_lr_idx, fed->fed_lr_off);
err = -EINVAL;
} else {
- fsfilt_add_journal_cb(exp->exp_obd, last_rcvd, oti->oti_handle,
- filter_commit_cb, NULL);
+ if (!force_sync)
+ force_sync = fsfilt_add_journal_cb(exp->exp_obd,
+ last_rcvd,
+ oti->oti_handle,
+ filter_commit_cb,
+ NULL);
+
err = fsfilt_write_record(exp->exp_obd, filter->fo_rcvd_filp,
fcd, sizeof(*fcd), &off,
- exp->exp_need_sync);
+ force_sync | exp->exp_need_sync);
+ if (force_sync)
+ filter_commit_cb(exp->exp_obd, last_rcvd, NULL, err);
}
if (err) {
log_pri = D_ERROR;
unsigned int orig_ids[MAXQUOTAS] = {0, 0};
struct llog_cookie *fcc = NULL;
struct filter_obd *filter;
- int rc, err, locked = 0;
+ int rc, err, locked = 0, sync = 0;
unsigned int ia_valid;
struct inode *inode;
struct iattr iattr;
EXT3_IOC_SETFLAGS, (long)&oa->o_flags);
} else {
rc = fsfilt_setattr(exp->exp_obd, dentry, handle, &iattr, 1);
- if (fcc != NULL) {
+ if (fcc != NULL)
/* set cancel cookie callback function */
- if (fsfilt_add_journal_cb(exp->exp_obd, 0, handle,
- filter_cancel_cookies_cb,
- fcc)) {
- spin_lock(&exp->exp_lock);
- exp->exp_need_sync = 1;
- spin_unlock(&exp->exp_lock);
- } else {
- fcc = NULL;
- }
- }
+ sync = fsfilt_add_journal_cb(exp->exp_obd, 0, handle,
+ filter_cancel_cookies_cb,
+ fcc);
}
if (OBD_FAIL_CHECK(OBD_FAIL_OST_SETATTR_CREDITS))
/* The truncate might have used up our transaction credits. Make
* sure we have one left for the last_rcvd update. */
err = fsfilt_extend(exp->exp_obd, inode, 1, handle);
- rc = filter_finish_transno(exp, oti, rc);
+ rc = filter_finish_transno(exp, oti, rc, sync);
+ if (sync) {
+ filter_cancel_cookies_cb(exp->exp_obd, 0, fcc, rc);
+ fcc = NULL;
+ }
err = fsfilt_commit(exp->exp_obd, inode, handle, 0);
if (err) {
CERROR("error on commit, err = %d\n", err);
if (!rc)
rc = err;
+ } else {
+ fcc = NULL;
}
if (locked) {
struct lvfs_run_ctxt saved;
void *handle = NULL;
struct llog_cookie *fcc = NULL;
- int rc, rc2, cleanup_phase = 0;
+ int rc, rc2, cleanup_phase = 0, sync = 0;
struct iattr iattr;
ENTRY;
cleanup:
switch(cleanup_phase) {
case 4:
- if (fcc != NULL) {
- if (fsfilt_add_journal_cb(obd, 0, oti ?
- oti->oti_handle : handle,
- filter_cancel_cookies_cb,
- fcc) == 0)
- fcc = NULL;
+ if (fcc != NULL)
+ sync = fsfilt_add_journal_cb(obd, 0, oti ?
+ oti->oti_handle : handle,
+ filter_cancel_cookies_cb,
+ fcc);
+ /* If add_journal_cb failed, then filter_finish_transno
+ * will commit the handle and we will do a sync
+ * on commit. then we call callback directly to free
+ * the fcc.
+ */
+ rc = filter_finish_transno(exp, oti, rc, sync);
+ if (sync) {
+ filter_cancel_cookies_cb(obd, 0, fcc, rc);
+ fcc = NULL;
}
- rc = filter_finish_transno(exp, oti, rc);
rc2 = fsfilt_commit(obd, dparent->d_inode, handle, 0);
if (rc2) {
CERROR("error on commit, err = %d\n", rc2);
if (!rc)
rc = rc2;
+ } else {
+ fcc = NULL;
}
case 3:
filter_parent_unlock(dparent);
const char *what, int quiet);
#define filter_oa2dentry(obd, oa) __filter_oa2dentry(obd, oa, __FUNCTION__, 0)
-int filter_finish_transno(struct obd_export *, struct obd_trans_info *, int rc);
+int filter_finish_transno(struct obd_export *, struct obd_trans_info *, int rc,
+ int force_sync);
__u64 filter_next_id(struct filter_obd *, struct obdo *);
__u64 filter_last_id(struct filter_obd *, obd_gr group);
int filter_update_fidea(struct obd_export *exp, struct inode *inode,
up(&inode->i_sem);
cleanup_phase = 3;
- rc = filter_finish_transno(exp, oti, 0);
+ rc = filter_finish_transno(exp, oti, 0, 0);
if (rc)
GOTO(cleanup, rc);
UNLOCK_INODE_MUTEX(inode);
- rc2 = filter_finish_transno(exp, oti, 0);
+ rc2 = filter_finish_transno(exp, oti, 0, 0);
if (rc2 != 0) {
CERROR("can't close transaction: %d\n", rc2);
if (rc == 0)
if (error != 0) {
CDEBUG(D_INODE, "not cancelling llog cookie on error %d\n",
error);
+ OBD_FREE(cookie, sizeof(*cookie));
return;
}
# Abort recovery before client complete
test_33() {
replay_barrier mds
- touch $DIR/$tfile
+ createmany -o $DIR/$tfile-%d 100
fail_abort mds
# this file should be gone, because the replay was aborted
$CHECKSTAT -t file $DIR/$tfile && return 3
+ $CHECKSTAT -t file $DIR/$tfile-* && return 3
+ unlinkmany $DIR/$tfile-%d 0 100
return 0
}
run_test 33 "abort recovery before client does replay"
echo "$LEAK_PORTALS" 1>&2
mv $TMP/debug $TMP/debug-leak.`date +%s` || true
echo "Memory leaks detected"
- [ "$LEAK_LUSTRE" -a $(echo $LEAK_LUSTRE | awk 'leaked=$8 {print leaked % 56}') == 0 ] && echo "ignoring known bug 10818" && return 0
return 254
fi
echo "modules unloaded."