/* Start / stop recording */ static int mdd_changelog_on(const struct lu_env *env, struct mdd_device *mdd, int on) { int rc = 0; if ((on == 1) && ((mdd->mdd_cl.mc_flags & CLM_ON) == 0)) { LCONSOLE_INFO("%s: changelog on\n", mdd2obd_dev(mdd)->obd_name); if (mdd->mdd_cl.mc_flags & CLM_ERR) { CERROR("Changelogs cannot be enabled due to error " "condition (see %s log).\n", mdd2obd_dev(mdd)->obd_name); rc = -ESRCH; } else { spin_lock(&mdd->mdd_cl.mc_lock); mdd->mdd_cl.mc_flags |= CLM_ON; spin_unlock(&mdd->mdd_cl.mc_lock); rc = mdd_changelog_write_header(env, mdd, CLM_START); } } else if ((on == 0) && ((mdd->mdd_cl.mc_flags & CLM_ON) == CLM_ON)) { LCONSOLE_INFO("%s: changelog off\n",mdd2obd_dev(mdd)->obd_name); rc = mdd_changelog_write_header(env, mdd, CLM_FINI); spin_lock(&mdd->mdd_cl.mc_lock); mdd->mdd_cl.mc_flags &= ~CLM_ON; spin_unlock(&mdd->mdd_cl.mc_lock); } return rc; }
static int mdd_changelog_users_seq_show(struct seq_file *m, void *data) { struct lu_env env; struct mdd_device *mdd = m->private; struct llog_ctxt *ctxt; __u64 cur; int rc; ctxt = llog_get_context(mdd2obd_dev(mdd), LLOG_CHANGELOG_USER_ORIG_CTXT); if (ctxt == NULL) return -ENXIO; LASSERT(ctxt->loc_handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT); rc = lu_env_init(&env, LCT_LOCAL); if (rc) { llog_ctxt_put(ctxt); return rc; } spin_lock(&mdd->mdd_cl.mc_lock); cur = mdd->mdd_cl.mc_index; spin_unlock(&mdd->mdd_cl.mc_lock); seq_printf(m, "current index: %llu\n", cur); seq_printf(m, "%-5s %s\n", "ID", "index"); llog_cat_process(&env, ctxt->loc_handle, lprocfs_changelog_users_cb, m, 0, 0); lu_env_fini(&env); llog_ctxt_put(ctxt); return 0; }
/** * open the PENDING directory for device \a mdd * * The PENDING directory persistently tracks files and directories that were * unlinked from the namespace (nlink == 0) but are still held open by clients. * Those inodes shouldn't be deleted if the MDS crashes, because the clients * would not be able to recover and reopen those files. Instead, these inodes * are linked into the PENDING directory on disk, and only deleted if all * clients close them, or the MDS finishes client recovery without any client * reopening them (i.e. former clients didn't join recovery). * \param d mdd device being started. * * \retval 0 success * \retval -ve index operation error. * */ int orph_index_init(const struct lu_env *env, struct mdd_device *mdd) { struct lu_fid fid; struct dt_object *d; int rc = 0; ENTRY; /* create PENDING dir */ fid_zero(&fid); rc = mdd_local_file_create(env, mdd, &mdd->mdd_local_root_fid, orph_index_name, S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO, &fid); if (rc < 0) RETURN(rc); d = dt_locate(env, mdd->mdd_child, &fid); if (IS_ERR(d)) RETURN(PTR_ERR(d)); LASSERT(lu_object_exists(&d->do_lu)); if (!dt_try_as_dir(env, d)) { CERROR("%s: \"%s\" is not an index: rc = %d\n", mdd2obd_dev(mdd)->obd_name, orph_index_name, rc); lu_object_put(env, &d->do_lu); RETURN(-ENOTDIR); } mdd->mdd_orphans = d; RETURN(0); }
int mdd_procfs_init(struct mdd_device *mdd, const char *name) { struct obd_device *obd = mdd2obd_dev(mdd); struct obd_type *type; int rc; ENTRY; /* at the moment there is no linkage between lu_type * and obd_type, so we lookup obd_type this way */ type = class_search_type(LUSTRE_MDD_NAME); LASSERT(name != NULL); LASSERT(type != NULL); LASSERT(obd != NULL); /* Find the type procroot and add the proc entry for this device */ obd->obd_vars = lprocfs_mdd_obd_vars; mdd->mdd_proc_entry = lprocfs_register(name, type->typ_procroot, obd->obd_vars, mdd); if (IS_ERR(mdd->mdd_proc_entry)) { rc = PTR_ERR(mdd->mdd_proc_entry); CERROR("Error %d setting up lprocfs for %s\n", rc, name); mdd->mdd_proc_entry = NULL; GOTO(out, rc); } rc = 0; EXIT; out: if (rc) mdd_procfs_fini(mdd); return rc; }
static int mdd_fill_fldb(const struct lu_env *env, struct mdd_device *mdd) { struct seq_server_site *ss = mdd_seq_site(mdd); struct lu_seq_range range; int rc; LASSERT(ss->ss_server_seq != NULL); LASSERT(ss->ss_server_fld != NULL); if (ss->ss_server_seq->lss_space.lsr_end == 0) return 0; memcpy(&range, &ss->ss_server_seq->lss_space, sizeof(range)); /* Pre-existing ZFS does not insert any entries to FLDB, we need * to insert it to FLDB during convertion */ range.lsr_start = FID_SEQ_NORMAL; fld_range_set_mdt(&range); mutex_lock(&ss->ss_server_fld->lsf_lock); rc = fld_insert_entry(env, ss->ss_server_fld, &range); mutex_unlock(&ss->ss_server_fld->lsf_lock); LCONSOLE_INFO("%s: insert missing range "DRANGE"\n", mdd2obd_dev(mdd)->obd_name, PRANGE(&range)); return rc; }
/** * Delete unused orphan with FID \a lf from PENDING directory * * \param mdd MDD device finishing recovery * \param lf FID of file or directory to delete * \param key cookie for this entry in index iterator * * \retval 0 success * \retval -ve error */ static int orph_key_test_and_del(const struct lu_env *env, struct mdd_device *mdd, struct lu_fid *lf, struct dt_key *key) { struct mdd_object *mdo; int rc; mdo = mdd_object_find(env, mdd, lf); if (IS_ERR(mdo)) return PTR_ERR(mdo); rc = -EBUSY; if (mdo->mod_count == 0) { CDEBUG(D_HA, "Found orphan "DFID", delete it\n", PFID(lf)); rc = orphan_object_destroy(env, mdo, key); if (rc) /* so replay-single.sh test_37 works */ CERROR("%s: error unlinking orphan "DFID" from " "PENDING: rc = %d\n", mdd2obd_dev(mdd)->obd_name, PFID(lf), rc); } else { mdd_write_lock(env, mdo, MOR_TGT_CHILD); if (likely(mdo->mod_count > 0)) { CDEBUG(D_HA, "Found orphan "DFID" count %d, skip it\n", PFID(lf), mdo->mod_count); mdo->mod_flags |= ORPHAN_OBJ; } mdd_write_unlock(env, mdo); } mdd_object_put(env, mdo); return rc; }
static int mdd_changelog_user_purge(const struct lu_env *env, struct mdd_device *mdd, int id, long long endrec) { struct mdd_changelog_user_data data; struct llog_ctxt *ctxt; int rc; ENTRY; CDEBUG(D_IOCTL, "Purge request: id=%d, endrec=%lld\n", id, endrec); data.mcud_id = id; data.mcud_minid = 0; data.mcud_minrec = 0; data.mcud_usercount = 0; data.mcud_endrec = endrec; spin_lock(&mdd->mdd_cl.mc_lock); endrec = mdd->mdd_cl.mc_index; spin_unlock(&mdd->mdd_cl.mc_lock); if ((data.mcud_endrec == 0) || ((data.mcud_endrec > endrec) && (data.mcud_endrec != MCUD_UNREGISTER))) data.mcud_endrec = endrec; ctxt = llog_get_context(mdd2obd_dev(mdd), LLOG_CHANGELOG_USER_ORIG_CTXT); if (ctxt == NULL) return -ENXIO; LASSERT(ctxt->loc_handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT); rc = llog_cat_process(env, ctxt->loc_handle, mdd_changelog_user_purge_cb, (void *)&data, 0, 0); if ((rc >= 0) && (data.mcud_minrec > 0)) { CDEBUG(D_IOCTL, "Purging changelog entries up to "LPD64 ", referenced by "CHANGELOG_USER_PREFIX"%d\n", data.mcud_minrec, data.mcud_minid); rc = mdd_changelog_llog_cancel(env, mdd, data.mcud_minrec); } else { CWARN("Could not determine changelog records to purge; rc=%d\n", rc); } llog_ctxt_put(ctxt); if (!data.mcud_found) { CWARN("No entry for user %d. Last changelog reference is " LPD64" by changelog user %d\n", data.mcud_id, data.mcud_minrec, data.mcud_minid); rc = -ENOENT; } if (!rc && data.mcud_usercount == 0) /* No more users; turn changelogs off */ rc = mdd_changelog_on(env, mdd, 0); RETURN (rc); }
/** * Lookup method for "fid" object. Only filenames with correct SEQ:OID format * are valid. We also check if object with passed fid exists or not. */ static int obf_lookup(const struct lu_env *env, struct md_object *p, const struct lu_name *lname, struct lu_fid *f, struct md_op_spec *spec) { char *name = (char *)lname->ln_name; struct mdd_device *mdd = mdo2mdd(p); struct mdd_object *child; int rc = 0; while (*name == '[') name++; sscanf(name, SFID, RFID(f)); if (!fid_is_sane(f)) { CWARN("%s: Trying to lookup invalid FID [%s] in %s/%s, FID " "format should be "DFID"\n", mdd2obd_dev(mdd)->obd_name, lname->ln_name, dot_lustre_name, mdd_obf_dir_name, (__u64)FID_SEQ_NORMAL, 1, 0); GOTO(out, rc = -EINVAL); } if (!fid_is_norm(f) && !fid_is_igif(f) && !fid_is_root(f) && !fid_seq_is_dot(f->f_seq)) { CWARN("%s: Trying to lookup invalid FID "DFID" in %s/%s, " "sequence should be >= "LPX64" or within ["LPX64"," ""LPX64"].\n", mdd2obd_dev(mdd)->obd_name, PFID(f), dot_lustre_name, mdd_obf_dir_name, (__u64)FID_SEQ_NORMAL, (__u64)FID_SEQ_IGIF, (__u64)FID_SEQ_IGIF_MAX); GOTO(out, rc = -EINVAL); } /* Check if object with this fid exists */ child = mdd_object_find(env, mdd, f); if (child == NULL) GOTO(out, rc = 0); if (IS_ERR(child)) GOTO(out, rc = PTR_ERR(child)); if (mdd_object_exists(child) == 0) rc = -ENOENT; mdd_object_put(env, child); out: return rc; }
static int mdd_llog_ctxt_get(const struct lu_env *env, struct md_device *m, int idx, void **h) { struct mdd_device *mdd = lu2mdd_dev(&m->md_lu_dev); *h = llog_group_get_ctxt(&mdd2obd_dev(mdd)->obd_olg, idx); return (*h == NULL ? -ENOENT : 0); }
int mdd_txn_stop_cb(const struct lu_env *env, struct thandle *txn, void *cookie) { struct mdd_device *mdd = cookie; struct obd_device *obd = mdd2obd_dev(mdd); LASSERT(obd); return mds_lov_write_objids(obd); }
/** Setup ".lustre" directory object */ static int mdd_dot_lustre_setup(const struct lu_env *env, struct mdd_device *m) { struct md_object *mdo; struct lu_fid fid; int rc; ENTRY; /* Create ".lustre" directory in ROOT. */ fid = LU_DOT_LUSTRE_FID; rc = mdd_local_file_create(env, m, &m->mdd_root_fid, dot_lustre_name, S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO, &fid); if (rc < 0) RETURN(rc); mdo = mdo_locate(env, &m->mdd_md_dev, &fid); if (IS_ERR(mdo)) RETURN(PTR_ERR(mdo)); LASSERT(lu_object_exists(&mdo->mo_lu)); m->mdd_dot_lustre = md2mdd_obj(mdo); rc = mdd_obf_setup(env, m); if (rc) { CERROR("%s: error initializing \"fid\" object: rc = %d.\n", mdd2obd_dev(m)->obd_name, rc); GOTO(out, rc); } rc = mdd_lpf_setup(env, m); if (rc != 0) { CERROR("%s: error initializing \"lost+found\": rc = %d.\n", mdd2obd_dev(m)->obd_name, rc); GOTO(out, rc); } RETURN(0); out: mdd_dot_lustre_cleanup(env, m); return rc; }
/** * Iterate orphan index to cleanup orphan objects after recovery is done. * \param d mdd device in recovery. */ int mdd_orphan_cleanup(const struct lu_env *env, struct mdd_device *d) { int rc = -ENOMEM; char *name = NULL; OBD_ALLOC(name, MTI_NAME_MAXLEN); if (name == NULL) goto out; snprintf(name, MTI_NAME_MAXLEN, "orph_cleanup_%s", mdd2obd_dev(d)->obd_name); rc = mdd_generic_thread_start(&d->mdd_orph_cleanup_thread, __mdd_orphan_cleanup, (void *)d, name); out: if (rc) CERROR("%s: start orphan cleanup thread failed:%d\n", mdd2obd_dev(d)->obd_name, rc); if (name) OBD_FREE(name, MTI_NAME_MAXLEN); return rc; }
static int mdd_convert_object(const struct lu_env *env, struct mdd_device *mdd, const struct lu_fid *fid, const struct lu_name *name) { struct mdd_object *o; struct lu_attr *la = MDD_ENV_VAR(env, cattr); int rc; ENTRY; o = mdd_object_find(env, mdd, fid); if (IS_ERR(o)) { CERROR("%s: can't access the object: rc = %d\n", mdd2obd_dev(mdd)->obd_name, (int)PTR_ERR(o)); RETURN(PTR_ERR(o)); } rc = mdo_attr_get(env, o, la, BYPASS_CAPA); if (rc) GOTO(out, rc); if (S_ISDIR(la->la_mode)) { /* remove "." and ".." if a directory */ rc = mdd_convert_remove_dots(env, mdd, o); if (rc) GOTO(out, rc); } /* update linkEA */ rc = mdd_convert_linkea(env, mdd, o, name); if (rc) CERROR("%s: can't convert: rc = %d\n", mdd2obd_dev(mdd)->obd_name, rc); out: mdd_object_put(env, o); RETURN(0); }
/** Add a CL_MARK record to the changelog * \param mdd * \param markerflags - CLM_* * \retval 0 ok */ int mdd_changelog_write_header(const struct lu_env *env, struct mdd_device *mdd, int markerflags) { struct obd_device *obd = mdd2obd_dev(mdd); struct llog_changelog_rec *rec; struct lu_buf *buf; struct llog_ctxt *ctxt; int reclen; int len = strlen(obd->obd_name); int rc; ENTRY; if (mdd->mdd_cl.mc_mask & (1 << CL_MARK)) { mdd->mdd_cl.mc_starttime = cfs_time_current_64(); RETURN(0); } reclen = llog_data_len(sizeof(*rec) + len); buf = lu_buf_check_and_alloc(&mdd_env_info(env)->mti_big_buf, reclen); if (buf->lb_buf == NULL) RETURN(-ENOMEM); rec = buf->lb_buf; rec->cr.cr_flags = CLF_VERSION; rec->cr.cr_type = CL_MARK; rec->cr.cr_namelen = len; memcpy(changelog_rec_name(&rec->cr), obd->obd_name, rec->cr.cr_namelen); /* Status and action flags */ rec->cr.cr_markerflags = mdd->mdd_cl.mc_flags | markerflags; rec->cr_hdr.lrh_len = llog_data_len(changelog_rec_size(&rec->cr) + rec->cr.cr_namelen); rec->cr_hdr.lrh_type = CHANGELOG_REC; rec->cr.cr_time = cl_time(); spin_lock(&mdd->mdd_cl.mc_lock); rec->cr.cr_index = ++mdd->mdd_cl.mc_index; spin_unlock(&mdd->mdd_cl.mc_lock); ctxt = llog_get_context(obd, LLOG_CHANGELOG_ORIG_CTXT); LASSERT(ctxt); rc = llog_cat_add(env, ctxt->loc_handle, &rec->cr_hdr, NULL); if (rc > 0) rc = 0; llog_ctxt_put(ctxt); /* assume on or off event; reset repeat-access time */ mdd->mdd_cl.mc_starttime = cfs_time_current_64(); RETURN(rc); }
/** * cleanup the context created by llog_setup_named() */ static int mdd_hsm_actions_llog_fini(const struct lu_env *env, struct mdd_device *m) { struct obd_device *obd = mdd2obd_dev(m); struct llog_ctxt *lctxt; ENTRY; lctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT); if (lctxt) { llog_cat_close(env, lctxt->loc_handle); lctxt->loc_handle = NULL; llog_cleanup(env, lctxt); } RETURN(0); }
static int lprocfs_rd_changelog_users(char *page, char **start, off_t off, int count, int *eof, void *data) { struct lu_env env; struct mdd_device *mdd = data; struct llog_ctxt *ctxt; struct cucb_data cucb; __u64 cur; int rc; *eof = 1; ctxt = llog_get_context(mdd2obd_dev(mdd), LLOG_CHANGELOG_USER_ORIG_CTXT); if (ctxt == NULL) return -ENXIO; LASSERT(ctxt->loc_handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT); rc = lu_env_init(&env, LCT_LOCAL); if (rc) { llog_ctxt_put(ctxt); return rc; } spin_lock(&mdd->mdd_cl.mc_lock); cur = mdd->mdd_cl.mc_index; spin_unlock(&mdd->mdd_cl.mc_lock); cucb.count = count; cucb.page = page; cucb.idx = 0; cucb.idx += snprintf(cucb.page + cucb.idx, cucb.count - cucb.idx, "current index: "LPU64"\n", cur); cucb.idx += snprintf(cucb.page + cucb.idx, cucb.count - cucb.idx, "%-5s %s\n", "ID", "index"); llog_cat_process(&env, ctxt->loc_handle, lprocfs_changelog_users_cb, &cucb, 0, 0); lu_env_fini(&env); llog_ctxt_put(ctxt); return cucb.idx; }
/** * set llog methods and create LLOG_AGENT_ORIG_CTXT llog * object in obd_device */ static int mdd_hsm_actions_llog_init(const struct lu_env *env, struct mdd_device *m) { struct obd_device *obd = mdd2obd_dev(m); struct llog_ctxt *ctxt = NULL; int rc; ENTRY; OBD_SET_CTXT_MAGIC(&obd->obd_lvfs_ctxt); obd->obd_lvfs_ctxt.dt = m->mdd_bottom; rc = llog_setup(env, obd, &obd->obd_olg, LLOG_AGENT_ORIG_CTXT, obd, &hsm_actions_logops); if (rc) { CERROR("%s: hsm actions llog setup failed: rc = %d\n", obd->obd_name, rc); RETURN(rc); } ctxt = llog_get_context(obd, LLOG_AGENT_ORIG_CTXT); LASSERT(ctxt); rc = llog_open_create(env, ctxt, &ctxt->loc_handle, NULL, HSM_ACTIONS); if (rc) { CERROR("%s: hsm actions llog open_create failed: rc = %d\n", obd->obd_name, rc); GOTO(out_cleanup, rc); } rc = llog_cat_init_and_process(env, ctxt->loc_handle); if (rc) GOTO(out_close, rc); llog_ctxt_put(ctxt); RETURN(0); out_close: llog_cat_close(env, ctxt->loc_handle); ctxt->loc_handle = NULL; out_cleanup: llog_cleanup(env, ctxt); return rc; }
/** * delete an orphan \a obj from orphan index. * \param obj file or directory. * \param th transaction for index deletion and object destruction. * * \pre obj->mod_count == 0 && ORPHAN_OBJ is set for obj. * * \retval 0 success * \retval -ve index operation error. */ int mdd_orphan_delete(const struct lu_env *env, struct mdd_object *obj, struct thandle *th) { struct mdd_device *mdd = mdo2mdd(&obj->mod_obj); struct dt_object *dor = mdd->mdd_orphans; struct dt_key *key; int rc = 0; ENTRY; LASSERT(mdd_write_locked(env, obj) != 0); LASSERT(obj->mod_flags & ORPHAN_OBJ); LASSERT(obj->mod_count == 0); LASSERT(dor); key = mdd_orphan_key_fill(env, mdo2fid(obj)); dt_write_lock(env, mdd->mdd_orphans, MOR_TGT_ORPHAN); if (OBD_FAIL_CHECK(OBD_FAIL_MDS_ORPHAN_DELETE)) goto ref_del; rc = dt_delete(env, mdd->mdd_orphans, key, th); if (rc == -ENOENT) { key = mdd_orphan_key_fill_20(env, mdo2fid(obj)); rc = dt_delete(env, mdd->mdd_orphans, key, th); } ref_del: if (!rc) { /* lov objects will be destroyed by caller */ mdo_ref_del(env, obj, th); if (S_ISDIR(mdd_object_type(obj))) { mdo_ref_del(env, obj, th); dt_ref_del(env, mdd->mdd_orphans, th); } obj->mod_flags &= ~ORPHAN_OBJ; } else { CERROR("%s: could not delete orphan object "DFID": rc = %d\n", mdd2obd_dev(mdd)->obd_name, PFID(mdo2fid(obj)), rc); } dt_write_unlock(env, mdd->mdd_orphans); RETURN(rc); }
static int mdd_changelog_user_register(const struct lu_env *env, struct mdd_device *mdd, int *id) { struct llog_ctxt *ctxt; struct llog_changelog_user_rec *rec; int rc; ENTRY; ctxt = llog_get_context(mdd2obd_dev(mdd), LLOG_CHANGELOG_USER_ORIG_CTXT); if (ctxt == NULL) RETURN(-ENXIO); OBD_ALLOC_PTR(rec); if (rec == NULL) { llog_ctxt_put(ctxt); RETURN(-ENOMEM); } /* Assume we want it on since somebody registered */ rc = mdd_changelog_on(env, mdd, 1); if (rc) GOTO(out, rc); rec->cur_hdr.lrh_len = sizeof(*rec); rec->cur_hdr.lrh_type = CHANGELOG_USER_REC; spin_lock(&mdd->mdd_cl.mc_user_lock); if (mdd->mdd_cl.mc_lastuser == (unsigned int)(-1)) { spin_unlock(&mdd->mdd_cl.mc_user_lock); CERROR("Maximum number of changelog users exceeded!\n"); GOTO(out, rc = -EOVERFLOW); } *id = rec->cur_id = ++mdd->mdd_cl.mc_lastuser; rec->cur_endrec = mdd->mdd_cl.mc_index; spin_unlock(&mdd->mdd_cl.mc_user_lock); rc = llog_cat_add(env, ctxt->loc_handle, &rec->cur_hdr, NULL); CDEBUG(D_IOCTL, "Registered changelog user %d\n", *id); out: OBD_FREE_PTR(rec); llog_ctxt_put(ctxt); RETURN(rc); }
/** Remove entries with indicies up to and including \a endrec from the * changelog * \param mdd * \param endrec * \retval 0 ok */ static int mdd_changelog_llog_cancel(const struct lu_env *env, struct mdd_device *mdd, long long endrec) { struct obd_device *obd = mdd2obd_dev(mdd); struct llog_ctxt *ctxt; long long unsigned cur; int rc; ctxt = llog_get_context(obd, LLOG_CHANGELOG_ORIG_CTXT); if (ctxt == NULL) return -ENXIO; spin_lock(&mdd->mdd_cl.mc_lock); cur = (long long)mdd->mdd_cl.mc_index; spin_unlock(&mdd->mdd_cl.mc_lock); if (endrec > cur) endrec = cur; /* purge to "0" is shorthand for everything */ if (endrec == 0) endrec = cur; /* If purging all records, write a header entry so we don't have an empty catalog and we're sure to have a valid starting index next time. In case of crash, we just restart with old log so we're allright. */ if (endrec == cur) { /* XXX: transaction is started by llog itself */ rc = mdd_changelog_write_header(env, mdd, CLM_PURGE); if (rc) goto out; } /* Some records were purged, so reset repeat-access time (so we record new mtime update records, so users can see a file has been changed since the last purge) */ mdd->mdd_cl.mc_starttime = cfs_time_current_64(); rc = llog_cancel(env, ctxt, (struct llog_cookie *)&endrec, 0); out: llog_ctxt_put(ctxt); return rc; }
static void mdd_changelog_fini(const struct lu_env *env, struct mdd_device *mdd) { struct obd_device *obd = mdd2obd_dev(mdd); struct llog_ctxt *ctxt; mdd->mdd_cl.mc_flags = 0; ctxt = llog_get_context(obd, LLOG_CHANGELOG_ORIG_CTXT); if (ctxt) { llog_cat_close(env, ctxt->loc_handle); llog_cleanup(env, ctxt); } ctxt = llog_get_context(obd, LLOG_CHANGELOG_USER_ORIG_CTXT); if (ctxt) { llog_cat_close(env, ctxt->loc_handle); llog_cleanup(env, ctxt); } }
static int mdd_changelog_init(const struct lu_env *env, struct mdd_device *mdd) { struct obd_device *obd = mdd2obd_dev(mdd); int rc; mdd->mdd_cl.mc_index = 0; spin_lock_init(&mdd->mdd_cl.mc_lock); mdd->mdd_cl.mc_starttime = cfs_time_current_64(); mdd->mdd_cl.mc_flags = 0; /* off by default */ mdd->mdd_cl.mc_mask = CHANGELOG_DEFMASK; spin_lock_init(&mdd->mdd_cl.mc_user_lock); mdd->mdd_cl.mc_lastuser = 0; rc = mdd_changelog_llog_init(env, mdd); if (rc) { CERROR("%s: changelog setup during init failed: rc = %d\n", obd->obd_name, rc); mdd->mdd_cl.mc_flags |= CLM_ERR; } return rc; }
static int mdd_process_config(const struct lu_env *env, struct lu_device *d, struct lustre_cfg *cfg) { struct mdd_device *m = lu2mdd_dev(d); struct dt_device *dt = m->mdd_child; struct lu_device *next = &dt->dd_lu_dev; int rc; ENTRY; switch (cfg->lcfg_command) { case LCFG_PARAM: { struct obd_device *obd = mdd2obd_dev(m); rc = class_process_proc_param(PARAM_MDD, obd->obd_vars, cfg, m); if (rc > 0 || rc == -ENOSYS) /* we don't understand; pass it on */ rc = next->ld_ops->ldo_process_config(env, next, cfg); break; } case LCFG_SETUP: rc = next->ld_ops->ldo_process_config(env, next, cfg); if (rc) GOTO(out, rc); dt_conf_get(env, dt, &m->mdd_dt_conf); break; case LCFG_CLEANUP: rc = next->ld_ops->ldo_process_config(env, next, cfg); lu_dev_del_linkage(d->ld_site, d); mdd_device_shutdown(env, m, cfg); break; default: rc = next->ld_ops->ldo_process_config(env, next, cfg); break; } out: RETURN(rc); }
static int mdd_changelog_size_ctxt(const struct lu_env *env, struct mdd_device *mdd, int index, __u64 *val) { struct llog_ctxt *ctxt; ctxt = llog_get_context(mdd2obd_dev(mdd), index); if (ctxt == NULL) return -ENXIO; if (!(ctxt->loc_handle->lgh_hdr->llh_flags & LLOG_F_IS_CAT)) { CERROR("%s: ChangeLog has wrong flags: rc = %d\n", ctxt->loc_obd->obd_name, -EINVAL); llog_ctxt_put(ctxt); return -EINVAL; } *val += llog_cat_size(env, ctxt->loc_handle); llog_ctxt_put(ctxt); return 0; }
/** * delete unreferenced files and directories in the PENDING directory * * Files that remain in PENDING after client->MDS recovery has completed * have to be referenced (opened) by some client during recovery, or they * will be deleted here (for clients that did not complete recovery). * * \param mdd MDD device finishing recovery * * \retval 0 success * \retval -ve error */ static int orph_index_iterate(const struct lu_env *env, struct mdd_device *mdd) { struct dt_object *dor = mdd->mdd_orphans; struct lu_dirent *ent = &mdd_env_info(env)->mti_ent; const struct dt_it_ops *iops; struct dt_it *it; struct lu_fid fid; int key_sz = 0; int rc; __u64 cookie; ENTRY; /* In recovery phase, do not need for any lock here */ iops = &dor->do_index_ops->dio_it; it = iops->init(env, dor, LUDA_64BITHASH, BYPASS_CAPA); if (IS_ERR(it)) { rc = PTR_ERR(it); CERROR("%s: cannot clean PENDING: rc = %d\n", mdd2obd_dev(mdd)->obd_name, rc); GOTO(out, rc); } rc = iops->load(env, it, 0); if (rc < 0) GOTO(out_put, rc); if (rc == 0) { CERROR("%s: error loading iterator to clean PENDING\n", mdd2obd_dev(mdd)->obd_name); /* Index contains no zero key? */ GOTO(out_put, rc = -EIO); } do { key_sz = iops->key_size(env, it); /* filter out "." and ".." entries from PENDING dir. */ if (key_sz < 8) goto next; rc = iops->rec(env, it, (struct dt_rec *)ent, LUDA_64BITHASH); if (rc != 0) { CERROR("%s: fail to get FID for orphan it: rc = %d\n", mdd2obd_dev(mdd)->obd_name, rc); goto next; } fid_le_to_cpu(&fid, &ent->lde_fid); if (!fid_is_sane(&fid)) { CERROR("%s: bad FID "DFID" cleaning PENDING\n", mdd2obd_dev(mdd)->obd_name, PFID(&fid)); goto next; } /* kill orphan object */ cookie = iops->store(env, it); iops->put(env, it); rc = orph_key_test_and_del(env, mdd, &fid, (struct dt_key *)ent->lde_name); /* after index delete reset iterator */ if (rc == 0) rc = iops->get(env, it, (const void *)""); else rc = iops->load(env, it, cookie); next: rc = iops->next(env, it); } while (rc == 0); GOTO(out_put, rc = 0); out_put: iops->put(env, it); iops->fini(env, it); out: return rc; }
static int mdd_fix_children(const struct lu_env *env, struct mdd_device *mdd, struct dt_object *o) { struct mdd_thread_info *info = mdd_env_info(env); const struct dt_it_ops *iops; struct lu_name name; struct dt_it *it; struct lu_dirent *ent; int rc; ENTRY; /* scan /ROOT and update all ".." and linkEAs */ ent = (struct lu_dirent *)&info->mti_xattr_buf; iops = &o->do_index_ops->dio_it; it = iops->init(env, o, LUDA_64BITHASH, BYPASS_CAPA); if (IS_ERR(it)) { rc = PTR_ERR(it); CERROR("%s: can't initialize the iterator: rc = %d\n", mdd2obd_dev(mdd)->obd_name, rc); GOTO(out, rc); } rc = iops->load(env, it, 0); if (rc <= 0) GOTO(out_put, rc); do { rc = iops->key_size(env, it); if (rc == 0) goto next; /* calculate max space required for lu_dirent */ rc = lu_dirent_calc_size(rc, 0); LASSERT(rc <= sizeof(info->mti_xattr_buf)); rc = iops->rec(env, it, (struct dt_rec *)ent, LUDA_TYPE); if (rc == 0) { CDEBUG(D_OTHER, "convert %*s -> "DFID"\n", ent->lde_namelen, ent->lde_name, PFID(&ent->lde_fid)); name.ln_namelen = ent->lde_namelen; name.ln_name = ent->lde_name; rc = mdd_convert_object(env, mdd, &ent->lde_fid, &name); if (rc) { CERROR("%s: can't convert "DFID": rc = %d\n", mdd2obd_dev(mdd)->obd_name, PFID(&ent->lde_fid), rc); break; } } next: rc = iops->next(env, it); } while (rc == 0); if (rc > 0) rc = 0; out_put: iops->put(env, it); iops->fini(env, it); out: RETURN(rc); }
int mdd_compat_fixes(const struct lu_env *env, struct mdd_device *mdd) { struct mdd_thread_info *info = mdd_env_info(env); struct mdd_object *root; struct dt_object *o; struct lustre_mdt_attrs *lma; struct lu_buf buf; int rc; ENTRY; /* IGIF FIDS are valid for old 1.8 and 2.[123] ROOT and are kept. * Normal FIDs used by Xyratex 1.8->2.1 upgrade tool are also kept. */ if (fid_is_igif(&mdd->mdd_root_fid) || fid_is_norm(&mdd->mdd_root_fid)) RETURN(0); /* * FID is supposed to be FID_SEQ_ROOT for: * - new ldiskfs fs * - new ZFS fs * - old ZFS fs, by now processed with osd_convert_root_to_new_seq() */ if (fid_seq(&mdd->mdd_root_fid) != FID_SEQ_ROOT) { CERROR("%s: wrong FID "DFID" is used for /ROOT\n", mdd2obd_dev(mdd)->obd_name, PFID(&mdd->mdd_root_fid)); RETURN(-EINVAL); } root = mdd_object_find(env, mdd, &mdd->mdd_root_fid); if (IS_ERR(root)) RETURN(PTR_ERR(root)); o = mdd_object_child(root); CDEBUG(D_OTHER, "/ROOT = "DFID"\n", PFID(&mdd->mdd_root_fid)); if (dt_try_as_dir(env, o) == 0) { CERROR("%s: not a directory\n", mdd2obd_dev(mdd)->obd_name); GOTO(out, rc = -ENOTDIR); } lma = (struct lustre_mdt_attrs *)&info->mti_xattr_buf; CLASSERT(sizeof(info->mti_xattr_buf) >= LMA_OLD_SIZE); buf.lb_len = LMA_OLD_SIZE; buf.lb_buf = lma; rc = mdo_xattr_get(env, root, &buf, XATTR_NAME_LMA, BYPASS_CAPA); if (rc < 0 && rc != -ENODATA) { CERROR("%s: can't fetch LMA: rc = %d\n", mdd2obd_dev(mdd)->obd_name, rc); GOTO(out, rc); } lustre_lma_swab(lma); if (lu_fid_eq(&lma->lma_self_fid, &mdd->mdd_root_fid)) { /* /ROOT has been converted already * or was correct from the beginning */ CDEBUG(D_OTHER, "%s: converted already\n", mdd2obd_dev(mdd)->obd_name); GOTO(out, rc = 0); } /* this is supposed to happen only on pre-production ZFS backend */ if (strcmp(mdd->mdd_bottom->dd_lu_dev.ld_type->ldt_name, LUSTRE_OSD_ZFS_NAME) != 0) { CERROR("%s: "DFID" is used on ldiskfs?!\n", mdd2obd_dev(mdd)->obd_name, PFID(&mdd->mdd_root_fid)); GOTO(out, rc = -ENOTSUPP); } LCONSOLE_INFO("%s: FID of /ROOT has been changed. " "Please remount the clients.\n", mdd2obd_dev(mdd)->obd_name); /* Fill FLDB first */ rc = mdd_fill_fldb(env, mdd); if (rc) GOTO(out, rc); /* remove ./.. from /ROOT */ rc = mdd_convert_remove_dots(env, mdd, root); if (rc) GOTO(out, rc); /* go over the directory, fix all the objects */ rc = mdd_fix_children(env, mdd, o); if (rc) GOTO(out, rc); /* Update LMA on /ROOT. Done for simplicity in MDD, not in osd-zfs. * Correct LMA will imply the whole directory has been coverted * successfully, otherwise it will be retried on next mount. */ rc = mdd_convert_lma(env, mdd, root); out: mdd_object_put(env, root); RETURN(rc); }
static int mdd_changelog_llog_init(const struct lu_env *env, struct mdd_device *mdd) { struct obd_device *obd = mdd2obd_dev(mdd); struct llog_ctxt *ctxt = NULL, *uctxt = NULL; int rc; ENTRY; /* LU-2844 mdd setup failure should not cause umount oops */ if (OBD_FAIL_CHECK(OBD_FAIL_MDS_CHANGELOG_INIT)) RETURN(-EIO); OBD_SET_CTXT_MAGIC(&obd->obd_lvfs_ctxt); obd->obd_lvfs_ctxt.dt = mdd->mdd_bottom; rc = llog_setup(env, obd, &obd->obd_olg, LLOG_CHANGELOG_ORIG_CTXT, obd, &changelog_orig_logops); if (rc) { CERROR("%s: changelog llog setup failed: rc = %d\n", obd->obd_name, rc); RETURN(rc); } ctxt = llog_get_context(obd, LLOG_CHANGELOG_ORIG_CTXT); LASSERT(ctxt); rc = llog_open_create(env, ctxt, &ctxt->loc_handle, NULL, CHANGELOG_CATALOG); if (rc) GOTO(out_cleanup, rc); rc = llog_cat_init_and_process(env, ctxt->loc_handle); if (rc) GOTO(out_close, rc); rc = llog_cat_reverse_process(env, ctxt->loc_handle, changelog_init_cb, mdd); if (rc < 0) { CERROR("%s: changelog init failed: rc = %d\n", obd->obd_name, rc); GOTO(out_close, rc); } CDEBUG(D_IOCTL, "changelog starting index="LPU64"\n", mdd->mdd_cl.mc_index); /* setup user changelog */ rc = llog_setup(env, obd, &obd->obd_olg, LLOG_CHANGELOG_USER_ORIG_CTXT, obd, &changelog_orig_logops); if (rc) { CERROR("%s: changelog users llog setup failed: rc = %d\n", obd->obd_name, rc); GOTO(out_close, rc); } uctxt = llog_get_context(obd, LLOG_CHANGELOG_USER_ORIG_CTXT); LASSERT(ctxt); rc = llog_open_create(env, uctxt, &uctxt->loc_handle, NULL, CHANGELOG_USERS); if (rc) GOTO(out_ucleanup, rc); uctxt->loc_handle->lgh_logops->lop_add = llog_cat_add_rec; uctxt->loc_handle->lgh_logops->lop_declare_add = llog_cat_declare_add_rec; rc = llog_cat_init_and_process(env, uctxt->loc_handle); if (rc) GOTO(out_uclose, rc); rc = llog_cat_reverse_process(env, uctxt->loc_handle, changelog_user_init_cb, mdd); if (rc < 0) { CERROR("%s: changelog user init failed: rc = %d\n", obd->obd_name, rc); GOTO(out_uclose, rc); } /* If we have registered users, assume we want changelogs on */ if (mdd->mdd_cl.mc_lastuser > 0) { rc = mdd_changelog_on(env, mdd, 1); if (rc < 0) GOTO(out_uclose, rc); } llog_ctxt_put(ctxt); llog_ctxt_put(uctxt); RETURN(0); out_uclose: llog_cat_close(env, uctxt->loc_handle); out_ucleanup: llog_cleanup(env, uctxt); out_close: llog_cat_close(env, ctxt->loc_handle); out_cleanup: llog_cleanup(env, ctxt); return rc; }
static int mdd_prepare(const struct lu_env *env, struct lu_device *pdev, struct lu_device *cdev) { struct mdd_device *mdd = lu2mdd_dev(cdev); struct lu_device *next = &mdd->mdd_child->dd_lu_dev; struct lu_fid fid; int rc; ENTRY; rc = next->ld_ops->ldo_prepare(env, cdev, next); if (rc) RETURN(rc); /* Setup local dirs */ fid.f_seq = FID_SEQ_LOCAL_NAME; fid.f_oid = 1; fid.f_ver = 0; rc = local_oid_storage_init(env, mdd->mdd_bottom, &fid, &mdd->mdd_los); if (rc) RETURN(rc); rc = dt_root_get(env, mdd->mdd_child, &mdd->mdd_local_root_fid); if (rc < 0) GOTO(out_los, rc); lu_root_fid(&fid); if (mdd_seq_site(mdd)->ss_node_id == 0) { rc = mdd_local_file_create(env, mdd, &mdd->mdd_local_root_fid, mdd_root_dir_name, S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO, &fid); if (rc != 0) { CERROR("%s: create root fid failed: rc = %d\n", mdd2obd_dev(mdd)->obd_name, rc); GOTO(out_los, rc); } mdd->mdd_root_fid = fid; rc = mdd_dot_lustre_setup(env, mdd); if (rc != 0) { CERROR("%s: initializing .lustre failed: rc = %d\n", mdd2obd_dev(mdd)->obd_name, rc); GOTO(out_los, rc); } rc = mdd_compat_fixes(env, mdd); if (rc != 0) GOTO(out_dot, rc); } else { /* Normal client usually send root access to MDT0 directly, * the root FID on non-MDT0 will only be used by echo client. */ mdd->mdd_root_fid = fid; } rc = orph_index_init(env, mdd); if (rc < 0) GOTO(out_dot, rc); rc = mdd_changelog_init(env, mdd); if (rc != 0) { CERROR("%s: failed to initialize changelog: rc = %d\n", mdd2obd_dev(mdd)->obd_name, rc); GOTO(out_orph, rc); } rc = mdd_hsm_actions_llog_init(env, mdd); if (rc != 0) GOTO(out_changelog, rc); rc = lfsck_register(env, mdd->mdd_bottom, mdd->mdd_child, mdd2obd_dev(mdd), mdd_lfsck_out_notify, mdd, true); if (rc != 0) { CERROR("%s: failed to initialize lfsck: rc = %d\n", mdd2obd_dev(mdd)->obd_name, rc); GOTO(out_hsm, rc); } RETURN(0); out_hsm: mdd_hsm_actions_llog_fini(env, mdd); out_changelog: mdd_changelog_fini(env, mdd); out_orph: orph_index_fini(env, mdd); out_dot: if (mdd_seq_site(mdd)->ss_node_id == 0) mdd_dot_lustre_cleanup(env, mdd); out_los: local_oid_storage_fini(env, mdd->mdd_los); mdd->mdd_los = NULL; return rc; }
static int mdd_orphan_destroy(const struct lu_env *env, struct mdd_object *obj, struct dt_key *key) { struct thandle *th = NULL; struct mdd_device *mdd = mdo2mdd(&obj->mod_obj); bool orphan_exists = true; int rc = 0; ENTRY; th = mdd_trans_create(env, mdd); if (IS_ERR(th)) { rc = PTR_ERR(th); if (rc != -EINPROGRESS) CERROR("%s: cannot get orphan thandle: rc = %d\n", mdd2obd_dev(mdd)->obd_name, rc); RETURN(rc); } mdd_write_lock(env, obj, MOR_TGT_CHILD); rc = mdd_orphan_declare_delete(env, obj, th); if (rc == -ENOENT) orphan_exists = false; else if (rc) GOTO(unlock, rc); if (orphan_exists) { rc = mdo_declare_destroy(env, obj, th); if (rc) GOTO(unlock, rc); } rc = mdd_trans_start(env, mdd, th); if (rc) GOTO(unlock, rc); if (likely(obj->mod_count == 0)) { dt_write_lock(env, mdd->mdd_orphans, MOR_TGT_ORPHAN); rc = dt_delete(env, mdd->mdd_orphans, key, th); if (rc) { CERROR("%s: could not delete orphan "DFID": rc = %d\n", mdd2obd_dev(mdd)->obd_name, PFID(mdo2fid(obj)), rc); } else if (orphan_exists) { mdo_ref_del(env, obj, th); if (S_ISDIR(mdd_object_type(obj))) { mdo_ref_del(env, obj, th); dt_ref_del(env, mdd->mdd_orphans, th); } rc = mdo_destroy(env, obj, th); } else { CWARN("%s: orphan %s "DFID" doesn't exist\n", mdd2obd_dev(mdd)->obd_name, (char *)key, PFID(mdo2fid(obj))); } dt_write_unlock(env, mdd->mdd_orphans); } unlock: mdd_write_unlock(env, obj); rc = mdd_trans_stop(env, mdd, 0, th); RETURN(rc); }