static struct dt_key *mdd_orphan_key_fill(const struct lu_env *env, const struct lu_fid *lf) { char *key = mdd_env_info(env)->mti_key; LASSERT(key); snprintf(key, sizeof(mdd_env_info(env)->mti_key), DFID_NOBRACE, PFID(lf)); return (struct dt_key *)key; }
/* compatibility with orphan files created in versions before 2.11 */ static struct dt_key *mdd_orphan_key_fill_20(const struct lu_env *env, const struct lu_fid *lf) { char *key = mdd_env_info(env)->mti_key; LASSERT(key); snprintf(key, sizeof(mdd_env_info(env)->mti_key), ORPHAN_FILE_NAME_FORMAT_20, fid_seq(lf), fid_oid(lf), fid_ver(lf), ORPH_OP_UNLINK); return (struct dt_key *)key; }
static int mdd_convert_lma(const struct lu_env *env, struct mdd_device *mdd, struct mdd_object *o) { struct lustre_mdt_attrs *lma; struct thandle *th; struct lu_fid fid; struct lu_buf buf; int rc; ENTRY; lu_root_fid(&fid); lma = (struct lustre_mdt_attrs *)&mdd_env_info(env)->mti_xattr_buf; lustre_lma_init(lma, &fid, 0, 0); lustre_lma_swab(lma); buf.lb_buf = lma; buf.lb_len = sizeof(*lma); th = dt_trans_create(env, mdd->mdd_child); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = mdo_declare_xattr_set(env, o, &buf, XATTR_NAME_LMA, 0, th); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, mdd->mdd_child, th); if (rc) GOTO(out, rc); rc = mdo_xattr_set(env, o, &buf, XATTR_NAME_LMA, 0, th, BYPASS_CAPA); out: dt_trans_stop(env, mdd->mdd_child, th); RETURN(rc); }
/** * destroy osd object on mdd and associated ost objects. * * \param obj orphan object * \param mdd used for sending llog msg to osts * * \retval 0 success * \retval -ve error */ static int orphan_object_kill(const struct lu_env *env, struct mdd_object *obj, struct mdd_device *mdd, struct thandle *th) { struct lu_attr *la = &mdd_env_info(env)->mti_la; int rc = 0; ENTRY; /* No need to lock this object as its recovery phase, and * no other thread can access it. But we need to lock it * as its precondition for osd api we using. */ mdo_ref_del(env, obj, th); if (S_ISDIR(mdd_object_type(obj))) { mdo_ref_del(env, obj, th); mdd_orphan_ref_del(env, mdd, th); } else { /* regular file , cleanup linked ost objects */ rc = mdd_la_get(env, obj, la, BYPASS_CAPA); if (rc == 0) rc = mdd_lov_destroy(env, mdd, obj, la); } RETURN(rc); }
static struct dt_key* orph_key_fill_18(const struct lu_env *env, const struct lu_fid *lf) { char *key = mdd_env_info(env)->mti_key; int rc; LASSERT(key); rc = snprintf(key, NAME_MAX + 1, ORPHAN_FILE_NAME_FORMAT_18, (unsigned long long)fid_seq(lf), fid_oid(lf)); if (rc > 0) return (struct dt_key*) key; else return ERR_PTR(rc); }
/** 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); }
static inline int mdd_orphan_insert_obj(const struct lu_env *env, struct mdd_device *mdd, struct mdd_object *obj, __u32 op, struct thandle *th) { struct dt_insert_rec *rec = &mdd_env_info(env)->mti_dt_rec; struct dt_object *dor = mdd->mdd_orphans; const struct lu_fid *lf = mdo2fid(obj); struct dt_key *key = orph_key_fill(env, lf, op); rec->rec_fid = lf; rec->rec_type = mdd_object_type(obj); return dt_insert(env, dor, (const struct dt_rec *)rec, key, th, 1); }
static int orph_index_insert(const struct lu_env *env, struct mdd_object *obj, __u32 op, struct thandle *th) { struct mdd_device *mdd = mdo2mdd(&obj->mod_obj); struct dt_object *dor = mdd->mdd_orphans; const struct lu_fid *lf_dor = lu_object_fid(&dor->do_lu); struct dt_object *next = mdd_object_child(obj); struct dt_insert_rec *rec = &mdd_env_info(env)->mti_dt_rec; int rc; ENTRY; LASSERT(mdd_write_locked(env, obj) != 0); LASSERT(!(obj->mod_flags & ORPHAN_OBJ)); mdd_orphan_write_lock(env, mdd); rc = mdd_orphan_insert_obj(env, mdd, obj, op, th); if (rc) GOTO(out, rc); mdo_ref_add(env, obj, th); if (!S_ISDIR(mdd_object_type(obj))) GOTO(out, rc = 0); mdo_ref_add(env, obj, th); mdd_orphan_ref_add(env, mdd, th); /* try best to fixup directory, dont return errors * from here */ if (!dt_try_as_dir(env, next)) GOTO(out, rc = 0); dt_delete(env, next, (const struct dt_key *)dotdot, th); rec->rec_fid = lf_dor; rec->rec_type = S_IFDIR; dt_insert(env, next, (const struct dt_rec *)rec, (const struct dt_key *)dotdot, th, 1); out: if (rc == 0) obj->mod_flags |= ORPHAN_OBJ; mdd_orphan_write_unlock(env, mdd); RETURN(rc); }
int orph_declare_index_insert(const struct lu_env *env, struct mdd_object *obj, umode_t mode, struct thandle *th) { struct dt_insert_rec *rec = &mdd_env_info(env)->mti_dt_rec; struct mdd_device *mdd = mdo2mdd(&obj->mod_obj); struct dt_key *key; int rc; key = orph_key_fill(env, mdo2fid(obj), ORPH_OP_UNLINK); rec->rec_fid = mdo2fid(obj); rec->rec_type = mode; rc = dt_declare_insert(env, mdd->mdd_orphans, (const struct dt_rec *)rec, key, th); if (rc != 0) return rc; rc = mdo_declare_ref_add(env, obj, th); if (rc) return rc; if (!S_ISDIR(mode)) return 0; rc = mdo_declare_ref_add(env, obj, th); if (rc) return rc; rc = dt_declare_ref_add(env, mdd->mdd_orphans, th); if (rc) return rc; rc = mdo_declare_index_delete(env, obj, dotdot, th); if (rc) return rc; rc = mdo_declare_index_insert(env, obj, lu_object_fid(&mdd->mdd_orphans->do_lu), S_IFDIR, dotdot, th); return rc; }
/** * 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; }
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_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); }
static int orph_index_iterate(const struct lu_env *env, struct mdd_device *mdd) { struct dt_object *dor = mdd->mdd_orphans; char *mti_key = mdd_env_info(env)->mti_orph_key; const struct dt_it_ops *iops; struct dt_it *it; char *key; struct lu_fid fid; int result = 0; 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, BYPASS_CAPA); if (it != NULL) { result = iops->load(env, it, 0); if (result > 0) { /* main cycle */ do { key = (void *)iops->key(env, it); if (IS_ERR(key)) { CERROR("key failed when clean pending.\n"); goto next; } key_sz = iops->key_size(env, it); /* filter out "." and ".." entries from * PENDING dir. */ if (key_sz < 8) goto next; memcpy(mti_key, key, key_sz); mti_key[key_sz] = 0; if (orphan_key_to_fid(mti_key, &fid)) goto next; if (!fid_is_sane(&fid)) { CERROR("fid is not sane when clean pending.\n"); 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 *)mti_key); /* after index delete reset iterator */ if (!rc) result = iops->get(env, it, (const void *)""); else result = iops->load(env, it, cookie); next: result = iops->next(env, it); } while (result == 0); result = 0; } else if (result == 0) { CERROR("Input/Output for clean pending.\n"); /* Index contains no zero key? */ result = -EIO; } iops->put(env, it); iops->fini(env, it); } else { CERROR("not enough memory for clean pending.\n"); result = -ENOMEM; } RETURN(result); }