static int fld_insert_entry(const struct lu_env *env, struct lu_server_fld *fld, const struct lu_seq_range *range) { struct thandle *th; int rc; ENTRY; th = dt_trans_create(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev)); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = fld_declare_index_create(env, fld, range, th); if (rc != 0) { if (rc == -EEXIST) rc = 0; GOTO(out, rc); } rc = dt_trans_start_local(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev), th); if (rc) GOTO(out, rc); rc = fld_index_create(env, fld, range, th); if (rc == -EEXIST) rc = 0; out: dt_trans_stop(env, lu2dt_dev(fld->lsf_obj->do_lu.lo_dev), th); RETURN(rc); }
/** * Write the special file which contains the list of llog catalogs IDs * * This function writes the CATALOG file which contains the array of llog * catalogs IDs. It is used mostly to store OSP llogs indexed by OST/MDT * number. * * \param[in] env execution environment * \param[in] d corresponding storage device * \param[in] idx position to start from, usually OST/MDT index * \param[in] count how many catalog IDs to write * \param[out] idarray the buffer with the data to write. * \param[in] fid LLOG_CATALOGS_OID for CATALOG object * * \retval 0 on successful write of catalog IDs * \retval negative value on error */ int llog_osd_put_cat_list(const struct lu_env *env, struct dt_device *d, int idx, int count, struct llog_catid *idarray, const struct lu_fid *fid) { struct llog_thread_info *lgi = llog_info(env); struct dt_object *o = NULL; struct thandle *th; int rc, size; if (count == 0) RETURN(0); LASSERT(d); size = sizeof(*idarray) * count; lgi->lgi_off = idx * sizeof(*idarray); lgi->lgi_fid = *fid; o = dt_locate(env, d, &lgi->lgi_fid); if (IS_ERR(o)) RETURN(PTR_ERR(o)); if (!dt_object_exists(o)) GOTO(out, rc = -ENOENT); rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA); if (rc) GOTO(out, rc); if (!S_ISREG(lgi->lgi_attr.la_mode)) { CERROR("%s: CATALOGS is not a regular file!: mode = %o\n", o->do_lu.lo_dev->ld_obd->obd_name, lgi->lgi_attr.la_mode); GOTO(out, rc = -ENOENT); } th = dt_trans_create(env, d); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); lgi->lgi_buf.lb_len = size; lgi->lgi_buf.lb_buf = idarray; rc = dt_declare_record_write(env, o, &lgi->lgi_buf, lgi->lgi_off, th); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(out_trans, rc); rc = dt_record_write(env, o, &lgi->lgi_buf, &lgi->lgi_off, th); if (rc) CDEBUG(D_INODE, "can't write CATALOGS at index %d: rc = %d\n", idx, rc); out_trans: dt_trans_stop(env, d, th); out: lu_object_put(env, &o->do_lu); RETURN(rc); }
/** * Helper function to open llog or create it if doesn't exist. * It hides all transaction handling from caller. */ int llog_open_create(const struct lu_env *env, struct llog_ctxt *ctxt, struct llog_handle **res, struct llog_logid *logid, char *name) { struct dt_device *d; struct thandle *th; int rc; rc = llog_open(env, ctxt, res, logid, name, LLOG_OPEN_NEW); if (rc) return rc; if (llog_exist(*res)) return 0; LASSERT((*res)->lgh_obj != NULL); d = lu2dt_dev((*res)->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, d); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); rc = llog_declare_create(env, *res, th); if (rc == 0) { rc = dt_trans_start_local(env, d, th); if (rc == 0) rc = llog_create(env, *res, th); } dt_trans_stop(env, d, th); out: if (rc) llog_close(env, *res); return rc; }
/* * Helper function for write record in llog. * It hides all transaction handling from caller. * Valid only with local llog. */ int llog_write(const struct lu_env *env, struct llog_handle *loghandle, struct llog_rec_hdr *rec, int idx) { struct dt_device *dt; struct thandle *th; int rc; ENTRY; LASSERT(loghandle); LASSERT(loghandle->lgh_ctxt); LASSERT(loghandle->lgh_obj != NULL); dt = lu2dt_dev(loghandle->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, dt); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = llog_declare_write_rec(env, loghandle, rec, idx, th); if (rc) GOTO(out_trans, rc); th->th_wait_submit = 1; rc = dt_trans_start_local(env, dt, th); if (rc) GOTO(out_trans, rc); down_write(&loghandle->lgh_lock); rc = llog_write_rec(env, loghandle, rec, NULL, idx, th); up_write(&loghandle->lgh_lock); out_trans: dt_trans_stop(env, dt, th); RETURN(rc); }
/* * Helper function for write record in llog. * It hides all transaction handling from caller. * Valid only with local llog. */ int llog_write(const struct lu_env *env, struct llog_handle *loghandle, struct llog_rec_hdr *rec, struct llog_cookie *reccookie, int cookiecount, void *buf, int idx) { struct dt_device *dt; struct thandle *th; int rc; LASSERT(loghandle); LASSERT(loghandle->lgh_ctxt); LASSERT(loghandle->lgh_obj != NULL); dt = lu2dt_dev(loghandle->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, dt); if (IS_ERR(th)) return PTR_ERR(th); rc = llog_declare_write_rec(env, loghandle, rec, idx, th); if (rc) GOTO(out_trans, rc); rc = dt_trans_start_local(env, dt, th); if (rc) GOTO(out_trans, rc); down_write(&loghandle->lgh_lock); rc = llog_write_rec(env, loghandle, rec, reccookie, cookiecount, buf, idx, th); up_write(&loghandle->lgh_lock); out_trans: dt_trans_stop(env, dt, th); return rc; }
static int mdd_convert_linkea(const struct lu_env *env, struct mdd_device *mdd, struct mdd_object *o, const struct lu_name *name) { struct thandle *th; struct lu_fid oldfid; int rc; ENTRY; th = dt_trans_create(env, mdd->mdd_child); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = mdd_declare_links_add(env, o, th, NULL); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, mdd->mdd_child, th); if (rc) GOTO(out, rc); oldfid.f_seq = FID_SEQ_LOCAL_FILE; oldfid.f_oid = MDD_ROOT_INDEX_OID; oldfid.f_ver = 0; rc = mdd_links_rename(env, o, &oldfid, name, &mdd->mdd_root_fid, name, th, NULL, 0, 1); if (rc == -ENOENT || rc == -EEXIST) rc = 0; out: dt_trans_stop(env, mdd->mdd_child, th); RETURN(rc); }
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); }
/** * Write fid into last_oid/last_seq file. **/ int osp_write_last_oid_seq_files(struct lu_env *env, struct osp_device *osp, struct lu_fid *fid, int sync) { struct osp_thread_info *oti = osp_env_info(env); struct lu_buf *lb_oid = &oti->osi_lb; struct lu_buf *lb_oseq = &oti->osi_lb2; loff_t oid_off; loff_t oseq_off; struct thandle *th; int rc; ENTRY; /* Note: through f_oid is only 32bits, it will also write * 64 bits for oid to keep compatiblity with the previous * version. */ lb_oid->lb_buf = &fid->f_oid; lb_oid->lb_len = sizeof(obd_id); oid_off = sizeof(obd_id) * osp->opd_index; lb_oseq->lb_buf = &fid->f_seq; lb_oseq->lb_len = sizeof(obd_id); oseq_off = sizeof(obd_id) * osp->opd_index; th = dt_trans_create(env, osp->opd_storage); if (IS_ERR(th)) RETURN(PTR_ERR(th)); th->th_sync |= sync; rc = dt_declare_record_write(env, osp->opd_last_used_oid_file, lb_oid->lb_len, oid_off, th); if (rc != 0) GOTO(out, rc); rc = dt_declare_record_write(env, osp->opd_last_used_seq_file, lb_oseq->lb_len, oseq_off, th); if (rc != 0) GOTO(out, rc); rc = dt_trans_start_local(env, osp->opd_storage, th); if (rc != 0) GOTO(out, rc); rc = dt_record_write(env, osp->opd_last_used_oid_file, lb_oid, &oid_off, th); if (rc != 0) { CERROR("%s: can not write to last seq file: rc = %d\n", osp->opd_obd->obd_name, rc); GOTO(out, rc); } rc = dt_record_write(env, osp->opd_last_used_seq_file, lb_oseq, &oseq_off, th); if (rc) { CERROR("%s: can not write to last seq file: rc = %d\n", osp->opd_obd->obd_name, rc); GOTO(out, rc); } out: dt_trans_stop(env, osp->opd_storage, th); RETURN(rc); }
/* * Update version of an index file * * \param env - is the environment passed by the caller * \param dev - is the backend dt device storing the index file * \param obj - is the on-disk index that should be updated * \param ver - is the new version */ int lquota_disk_update_ver(const struct lu_env *env, struct dt_device *dev, struct dt_object *obj, __u64 ver) { struct thandle *th; int rc; ENTRY; th = dt_trans_create(env, dev); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = dt_declare_version_set(env, obj, th); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, dev, th); if (rc) GOTO(out, rc); th->th_sync = 1; dt_version_set(env, obj, ver, th); EXIT; out: dt_trans_stop(env, dev, th); return rc; }
static int lfsck_namespace_delete(const struct lu_env *env, struct lfsck_component *com, const struct lu_fid *fid) { struct lfsck_instance *lfsck = com->lc_lfsck; struct lu_fid *key = &lfsck_env_info(env)->lti_fid; struct thandle *handle; struct dt_object *obj = com->lc_obj; int rc; ENTRY; handle = dt_trans_create(env, lfsck->li_bottom); if (IS_ERR(handle)) RETURN(PTR_ERR(handle)); rc = dt_declare_delete(env, obj, (const struct dt_key *)fid, handle); if (rc != 0) GOTO(out, rc); rc = dt_trans_start_local(env, lfsck->li_bottom, handle); if (rc != 0) GOTO(out, rc); fid_cpu_to_be(key, fid); rc = dt_delete(env, obj, (const struct dt_key *)key, handle, BYPASS_CAPA); GOTO(out, rc); out: dt_trans_stop(env, lfsck->li_bottom, handle); return rc; }
/* * Write a global record * * \param env - is the environment passed by the caller * \param obj - is the on-disk global index to be updated * \param id - index to be updated * \param rec - record to be written */ int lquota_disk_write_glb(const struct lu_env *env, struct dt_object *obj, __u64 id, struct lquota_glb_rec *rec) { struct dt_device *dev = lu2dt_dev(obj->do_lu.lo_dev); struct thandle *th; struct dt_key *key = (struct dt_key *)&id; int rc; ENTRY; th = dt_trans_create(env, dev); if (IS_ERR(th)) RETURN(PTR_ERR(th)); /* the entry with 0 key can always be found in IAM file. */ if (id == 0) { rc = dt_declare_delete(env, obj, key, th); if (rc) GOTO(out, rc); } rc = dt_declare_insert(env, obj, (struct dt_rec *)rec, key, th); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, dev, th); if (rc) GOTO(out, rc); dt_write_lock(env, obj, 0); if (id == 0) { struct lquota_glb_rec *tmp; OBD_ALLOC_PTR(tmp); if (tmp == NULL) GOTO(out_lock, rc = -ENOMEM); rc = dt_lookup(env, obj, (struct dt_rec *)tmp, key, BYPASS_CAPA); OBD_FREE_PTR(tmp); if (rc == 0) { rc = dt_delete(env, obj, key, th, BYPASS_CAPA); if (rc) GOTO(out_lock, rc); } rc = 0; } rc = dt_insert(env, obj, (struct dt_rec *)rec, key, th, BYPASS_CAPA, 1); out_lock: dt_write_unlock(env, obj); out: dt_trans_stop(env, dev, th); RETURN(rc); }
static int llog_truncate(const struct lu_env *env, struct dt_object *o) { struct lu_attr la; struct thandle *th; struct dt_device *d; int rc; ENTRY; LASSERT(o); d = lu2dt_dev(o->do_lu.lo_dev); LASSERT(d); rc = dt_attr_get(env, o, &la); if (rc) RETURN(rc); CDEBUG(D_OTHER, "original size "LPU64"\n", la.la_size); rc = sizeof(struct llog_log_hdr) + sizeof(struct llog_mini_rec); if (la.la_size < rc) { CERROR("too small llog: "LPU64"\n", la.la_size); RETURN(0); } /* drop 2 records */ la.la_size = la.la_size - (sizeof(struct llog_mini_rec) * 2); la.la_valid = LA_SIZE; th = dt_trans_create(env, d); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = dt_declare_attr_set(env, o, &la, th); if (rc) GOTO(stop, rc); rc = dt_declare_punch(env, o, la.la_size, OBD_OBJECT_EOF, th); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(stop, rc); rc = dt_punch(env, o, la.la_size, OBD_OBJECT_EOF, th); if (rc) GOTO(stop, rc); rc = dt_attr_set(env, o, &la, th); if (rc) GOTO(stop, rc); stop: dt_trans_stop(env, d, th); RETURN(rc); }
static int lfsck_namespace_store(const struct lu_env *env, struct lfsck_component *com, bool init) { struct dt_object *obj = com->lc_obj; struct lfsck_instance *lfsck = com->lc_lfsck; struct thandle *handle; int len = com->lc_file_size; int rc; ENTRY; lfsck_namespace_cpu_to_le((struct lfsck_namespace *)com->lc_file_disk, (struct lfsck_namespace *)com->lc_file_ram); handle = dt_trans_create(env, lfsck->li_bottom); if (IS_ERR(handle)) { rc = PTR_ERR(handle); CERROR("%s: fail to create trans for storing lfsck_namespace: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); RETURN(rc); } rc = dt_declare_xattr_set(env, obj, lfsck_buf_get(env, com->lc_file_disk, len), XATTR_NAME_LFSCK_NAMESPACE, 0, handle); if (rc != 0) { CERROR("%s: fail to declare trans for storing lfsck_namespace: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); GOTO(out, rc); } rc = dt_trans_start_local(env, lfsck->li_bottom, handle); if (rc != 0) { CERROR("%s: fail to start trans for storing lfsck_namespace: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); GOTO(out, rc); } rc = dt_xattr_set(env, obj, lfsck_buf_get(env, com->lc_file_disk, len), XATTR_NAME_LFSCK_NAMESPACE, init ? LU_XATTR_CREATE : LU_XATTR_REPLACE, handle, BYPASS_CAPA); if (rc != 0) CERROR("%s: fail to store lfsck_namespace: len = %d, " "rc = %d\n", lfsck_lfsck2name(lfsck), len, rc); GOTO(out, rc); out: dt_trans_stop(env, lfsck->li_bottom, handle); return rc; }
int lfsck_bookmark_store(const struct lu_env *env, struct lfsck_instance *lfsck) { struct thandle *handle; struct dt_object *obj = lfsck->li_bookmark_obj; loff_t pos = 0; int len = sizeof(struct lfsck_bookmark); int rc; ENTRY; lfsck_bookmark_cpu_to_le(&lfsck->li_bookmark_disk, &lfsck->li_bookmark_ram); handle = dt_trans_create(env, lfsck->li_bottom); if (IS_ERR(handle)) { rc = PTR_ERR(handle); CERROR("%s: fail to create trans for storing lfsck_bookmark: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); RETURN(rc); } rc = dt_declare_record_write(env, obj, lfsck_buf_get(env, &lfsck->li_bookmark_disk, len), 0, handle); if (rc != 0) { CERROR("%s: fail to declare trans for storing lfsck_bookmark: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); GOTO(out, rc); } rc = dt_trans_start_local(env, lfsck->li_bottom, handle); if (rc != 0) { CERROR("%s: fail to start trans for storing lfsck_bookmark: " "rc = %d\n", lfsck_lfsck2name(lfsck), rc); GOTO(out, rc); } rc = dt_record_write(env, obj, lfsck_buf_get(env, &lfsck->li_bookmark_disk, len), &pos, handle); if (rc != 0) CERROR("%s: fail to store lfsck_bookmark: expected = %d, " "rc = %d\n", lfsck_lfsck2name(lfsck), len, rc); GOTO(out, rc); out: dt_trans_stop(env, lfsck->li_bottom, handle); return rc; }
/** * Helper function to open llog or create it if doesn't exist. * It hides all transaction handling from caller. */ int llog_open_create(const struct lu_env *env, struct llog_ctxt *ctxt, struct llog_handle **res, struct llog_logid *logid, char *name) { struct dt_device *d; struct thandle *th; int rc; ENTRY; rc = llog_open(env, ctxt, res, logid, name, LLOG_OPEN_NEW); if (rc) RETURN(rc); if (llog_exist(*res)) RETURN(0); LASSERT((*res)->lgh_obj != NULL); d = lu2dt_dev((*res)->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, d); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); /* Create update llog object synchronously, which * happens during inialization process see * lod_sub_prep_llog(), to make sure the update * llog object is created before corss-MDT writing * updates into the llog object */ if (ctxt->loc_flags & LLOG_CTXT_FLAG_NORMAL_FID) th->th_sync = 1; th->th_wait_submit = 1; rc = llog_declare_create(env, *res, th); if (rc == 0) { rc = dt_trans_start_local(env, d, th); if (rc == 0) rc = llog_create(env, *res, th); } dt_trans_stop(env, d, th); out: if (rc) llog_close(env, *res); RETURN(rc); }
int llog_destroy(const struct lu_env *env, struct llog_handle *handle) { struct llog_operations *lop; struct dt_device *dt; struct thandle *th; int rc; ENTRY; rc = llog_handle2ops(handle, &lop); if (rc < 0) RETURN(rc); if (lop->lop_destroy == NULL) RETURN(-EOPNOTSUPP); if (handle->lgh_obj == NULL) { /* if lgh_obj == NULL, then it is from client side destroy */ rc = lop->lop_destroy(env, handle, NULL); RETURN(rc); } if (!dt_object_exists(handle->lgh_obj)) RETURN(0); dt = lu2dt_dev(handle->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, dt); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = llog_declare_destroy(env, handle, th); if (rc != 0) GOTO(out_trans, rc); rc = dt_trans_start_local(env, dt, th); if (rc < 0) GOTO(out_trans, rc); rc = lop->lop_destroy(env, handle, th); out_trans: dt_trans_stop(env, dt, th); RETURN(rc); }
static int write_capa_keys(const struct lu_env *env, struct mdt_device *mdt, struct lustre_capa_key *keys) { struct mdt_thread_info *mti; struct lustre_capa_key *tmp; struct thandle *th; loff_t off = 0; int i, rc; mti = lu_context_key_get(&env->le_ctx, &mdt_thread_key); th = dt_trans_create(env, mdt->mdt_bottom); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = dt_declare_record_write(env, mdt->mdt_ck_obj, mdt_buf_const(env, NULL, sizeof(*tmp) * 3), 0, th); if (rc) goto stop; rc = dt_trans_start_local(env, mdt->mdt_bottom, th); if (rc) goto stop; tmp = &mti->mti_capa_key; for (i = 0; i < 2; i++) { lck_cpu_to_le(tmp, &keys[i]); rc = dt_record_write(env, mdt->mdt_ck_obj, mdt_buf_const(env, tmp, sizeof(*tmp)), &off, th); if (rc) break; } stop: dt_trans_stop(env, mdt->mdt_bottom, th); CDEBUG(D_INFO, "write capability keys rc = %d:\n", rc); return rc; }
/* * To enable DNE functionality we need FID of /ROOT directory * (which is / as seen by the clients) to belong to MDT0 and * not to FID_SEQ_LOCAL_FILE or some other local sequence, * which can be used by any node, so can't be part of FLDB. * * Pre-production code was using FID_SEQ_LOCAL_FILE for /ROOT * making few existing setups incompatibile with DNE. This * applies to ZFS-based setups only as ldiskfs-based setups * are still using IGIF to identify /ROOT. * * The intention of this code is to fix on-disk state to use * FID_SEQ_ROOT for /ROOT: * - "." and ".." references in /ROOT itself and it`s subdirectories * - LinkEA in all the objects listed in /ROOT * * Given only ZFS is affected where "." and ".." are not stored, we need to: * - delete "." and ".." from /ROOT and its subdirectories * - rename references in LinkEA in all the objects listed in /ROOT * * This code is subject for removal in 2.5 */ static int mdd_convert_remove_dots(const struct lu_env *env, struct mdd_device *mdd, struct mdd_object *o) { struct thandle *th; const struct dt_key *dot = (const struct dt_key *)"."; const struct dt_key *dotdot = (const struct dt_key *)".."; int rc; if (dt_try_as_dir(env, mdd_object_child(o)) == 0) RETURN(-ENOTDIR); /* remove "."/".." and do not insert them back - not stored in ZFS */ th = dt_trans_create(env, mdd->mdd_child); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = dt_declare_delete(env, mdd_object_child(o), dot, th); if (rc) GOTO(out, rc); rc = dt_declare_delete(env, mdd_object_child(o), dotdot, th); if (rc) GOTO(out, rc); rc = dt_trans_start_local(env, mdd->mdd_child, th); if (rc) GOTO(out, rc); /* ignore non-existing "."/".." - we stored them on disk for * pre-production systems, but this is not how regular ZFS works */ rc = dt_delete(env, mdd_object_child(o), dot, th, BYPASS_CAPA); if (rc == -ENOENT) rc = 0; if (rc) GOTO(out, rc); rc = dt_delete(env, mdd_object_child(o), dotdot, th, BYPASS_CAPA); if (rc == -ENOENT) rc = 0; if (rc) GOTO(out, rc); out: dt_trans_stop(env, mdd->mdd_child, th); RETURN(rc); }
int lfsck_bookmark_store(const struct lu_env *env, struct lfsck_instance *lfsck) { struct thandle *handle; struct dt_object *obj = lfsck->li_bookmark_obj; struct dt_device *dev = lfsck_obj2dev(obj); loff_t pos = 0; int len = sizeof(struct lfsck_bookmark); int rc; ENTRY; lfsck_bookmark_cpu_to_le(&lfsck->li_bookmark_disk, &lfsck->li_bookmark_ram); handle = dt_trans_create(env, dev); if (IS_ERR(handle)) GOTO(log, rc = PTR_ERR(handle)); rc = dt_declare_record_write(env, obj, lfsck_buf_get(env, &lfsck->li_bookmark_disk, len), 0, handle); if (rc != 0) GOTO(out, rc); rc = dt_trans_start_local(env, dev, handle); if (rc != 0) GOTO(out, rc); rc = dt_record_write(env, obj, lfsck_buf_get(env, &lfsck->li_bookmark_disk, len), &pos, handle); GOTO(out, rc); out: dt_trans_stop(env, dev, handle); log: if (rc != 0) CDEBUG(D_LFSCK, "%s: fail to store lfsck_bookmark: rc = %d\n", lfsck_lfsck2name(lfsck), rc); return rc; }
int ofd_object_destroy(const struct lu_env *env, struct ofd_object *fo, int orphan) { struct ofd_device *ofd = ofd_obj2dev(fo); struct thandle *th; int rc = 0; ENTRY; ofd_write_lock(env, fo); if (!ofd_object_exists(fo)) GOTO(unlock, rc = -ENOENT); th = ofd_trans_create(env, ofd); if (IS_ERR(th)) GOTO(unlock, rc = PTR_ERR(th)); dt_declare_ref_del(env, ofd_object_child(fo), th); dt_declare_destroy(env, ofd_object_child(fo), th); if (orphan) rc = dt_trans_start_local(env, ofd->ofd_osd, th); else rc = ofd_trans_start(env, ofd, NULL, th); if (rc) GOTO(stop, rc); ofd_fmd_drop(ofd_info(env)->fti_exp, &fo->ofo_header.loh_fid); dt_ref_del(env, ofd_object_child(fo), th); dt_destroy(env, ofd_object_child(fo), th); stop: ofd_trans_stop(env, ofd, th, rc); unlock: ofd_write_unlock(env, fo); RETURN(rc); }
/** * Implementation of the llog_operations::lop_destroy * * This function destroys the llog and deletes also entry in the * llog directory in case of named llog. Llog should be opened prior that. * Destroy method is not part of external transaction and does everything * inside. * * \param[in] env execution environment * \param[in] loghandle llog handle of the current llog * * \retval 0 on successful destroy * \retval negative value on error */ static int llog_osd_destroy(const struct lu_env *env, struct llog_handle *loghandle) { struct llog_ctxt *ctxt; struct dt_object *o, *llog_dir = NULL; struct dt_device *d; struct thandle *th; char *name = NULL; int rc; ENTRY; ctxt = loghandle->lgh_ctxt; LASSERT(ctxt); o = loghandle->lgh_obj; LASSERT(o); d = lu2dt_dev(o->do_lu.lo_dev); LASSERT(d); LASSERT(d == ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt); th = dt_trans_create(env, d); if (IS_ERR(th)) RETURN(PTR_ERR(th)); if (loghandle->lgh_name) { llog_dir = llog_osd_dir_get(env, ctxt); if (IS_ERR(llog_dir)) GOTO(out_trans, rc = PTR_ERR(llog_dir)); name = loghandle->lgh_name; rc = dt_declare_delete(env, llog_dir, (struct dt_key *)name, th); if (rc) GOTO(out_trans, rc); } dt_declare_ref_del(env, o, th); rc = dt_declare_destroy(env, o, th); if (rc) GOTO(out_trans, rc); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(out_trans, rc); dt_write_lock(env, o, 0); if (dt_object_exists(o)) { if (name) { dt_read_lock(env, llog_dir, 0); rc = dt_delete(env, llog_dir, (struct dt_key *) name, th, BYPASS_CAPA); dt_read_unlock(env, llog_dir); if (rc) { CERROR("%s: can't remove llog %s: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, name, rc); GOTO(out_unlock, rc); } } dt_ref_del(env, o, th); rc = dt_destroy(env, o, th); if (rc) GOTO(out_unlock, rc); } out_unlock: dt_write_unlock(env, o); out_trans: dt_trans_stop(env, d, th); if (llog_dir != NULL) lu_object_put(env, &llog_dir->do_lu); RETURN(rc); }
/* * Update slave or global index copy. * * \param env - the environment passed by the caller * \param qqi - is the qsd_type_info structure managing the index to be * update * \param qid - is the identifier for which we need to update the quota * settings * \param global - is set to true when updating the global index copy and to * false for the slave index copy. * \param ver - is the new version of the index. If equal to 0, the version * of the index isn't changed * \param rec - is the updated record to insert in the index file */ int qsd_update_index(const struct lu_env *env, struct qsd_qtype_info *qqi, union lquota_id *qid, bool global, __u64 ver, void *rec) { struct thandle *th = NULL; struct dt_object *obj; __u64 *new_verp = NULL; int flags = 0; int rc; ENTRY; obj = global ? qqi->qqi_glb_obj : qqi->qqi_slv_obj; /* allocate transaction */ th = dt_trans_create(env, qqi->qqi_qsd->qsd_dev); if (IS_ERR(th)) RETURN(PTR_ERR(th)); /* reserve enough credits to update record in index file */ rc = lquota_disk_declare_write(env, th, obj, qid); if (rc) GOTO(out, rc); /* start local transaction */ rc = dt_trans_start_local(env, qqi->qqi_qsd->qsd_dev, th); if (rc) GOTO(out, rc); if (global) { /* Update record in global index copy */ struct lquota_glb_rec *glb_rec = (struct lquota_glb_rec *)rec; CDEBUG(D_QUOTA, "%s: updating global index hardlimit: "LPU64", " "softlimit: "LPU64" for id "LPU64"\n", qqi->qqi_qsd->qsd_svname, glb_rec->qbr_hardlimit, glb_rec->qbr_softlimit, qid->qid_uid); } else { /* Update record in slave index copy */ struct lquota_slv_rec *slv_rec = (struct lquota_slv_rec *)rec; CDEBUG(D_QUOTA, "%s: update granted to "LPU64" for id "LPU64 "\n", qqi->qqi_qsd->qsd_svname, slv_rec->qsr_granted, qid->qid_uid); } if (ver != 0) { new_verp = &ver; flags = LQUOTA_SET_VER; } /* write new record to index file */ rc = lquota_disk_write(env, th, obj, qid, (struct dt_rec *)rec, flags, new_verp); EXIT; out: dt_trans_stop(env, qqi->qqi_qsd->qsd_dev, th); if (rc) CERROR("%s: failed to update %s index copy for id "LPU64", rc:" "%d\n", qqi->qqi_qsd->qsd_svname, global ? "global" : "slave", qid->qid_uid, rc); else if (flags == LQUOTA_SET_VER) qsd_bump_version(qqi, ver, global); return rc; }
static int llog_osd_destroy(const struct lu_env *env, struct llog_handle *loghandle) { struct llog_thread_info *lgi = llog_info(env); struct llog_ctxt *ctxt; struct dt_object *o, *llog_dir = NULL; struct dt_device *d; struct thandle *th; char *name = NULL; int rc; ENTRY; ctxt = loghandle->lgh_ctxt; LASSERT(ctxt); o = loghandle->lgh_obj; LASSERT(o); d = lu2dt_dev(o->do_lu.lo_dev); LASSERT(d); LASSERT(d == ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt); th = dt_trans_create(env, d); if (IS_ERR(th)) RETURN(PTR_ERR(th)); if (loghandle->lgh_name) { llog_dir = llog_osd_dir_get(env, ctxt); if (IS_ERR(llog_dir)) GOTO(out_trans, rc = PTR_ERR(llog_dir)); dt_declare_ref_del(env, o, th); name = loghandle->lgh_name; rc = dt_declare_delete(env, llog_dir, (struct dt_key *)name, th); if (rc) GOTO(out_trans, rc); } dt_declare_ref_del(env, o, th); rc = dt_declare_destroy(env, o, th); if (rc) GOTO(out_trans, rc); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(out_trans, rc); dt_write_lock(env, o, 0); if (dt_object_exists(o)) { if (name) { dt_ref_del(env, o, th); dt_read_lock(env, llog_dir, 0); rc = dt_delete(env, llog_dir, (struct dt_key *) name, th, BYPASS_CAPA); dt_read_unlock(env, llog_dir); if (rc) { CERROR("%s: can't remove llog %s: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, name, rc); GOTO(out_unlock, rc); } } /* * XXX: compatibility bits * on old filesystems llogs are referenced by the name * on the new ones they are referenced by OI and by * the name */ rc = dt_attr_get(env, o, &lgi->lgi_attr, NULL); if (rc) GOTO(out_unlock, rc); LASSERT(lgi->lgi_attr.la_nlink < 2); if (lgi->lgi_attr.la_nlink == 1) dt_ref_del(env, o, th); rc = dt_destroy(env, o, th); if (rc) GOTO(out_unlock, rc); } out_unlock: dt_write_unlock(env, o); out_trans: dt_trans_stop(env, d, th); if (llog_dir != NULL) lu_object_put(env, &llog_dir->do_lu); RETURN(rc); }
/** * Set attributes of object during write bulk IO processing. * * Change object attributes and write parent FID into extended * attributes when needed. * * \param[in] env execution environment * \param[in] ofd OFD device * \param[in] ofd_obj OFD object * \param[in] la object attributes * \param[in] ff parent FID * * \retval 0 on successful attributes update * \retval negative value on error */ static int ofd_write_attr_set(const struct lu_env *env, struct ofd_device *ofd, struct ofd_object *ofd_obj, struct lu_attr *la, struct filter_fid *ff) { struct ofd_thread_info *info = ofd_info(env); __u64 valid = la->la_valid; int rc; struct thandle *th; struct dt_object *dt_obj; int ff_needed = 0; ENTRY; LASSERT(la); dt_obj = ofd_object_child(ofd_obj); LASSERT(dt_obj != NULL); la->la_valid &= LA_UID | LA_GID; rc = ofd_attr_handle_ugid(env, ofd_obj, la, 0 /* !is_setattr */); if (rc != 0) GOTO(out, rc); if (ff != NULL) { rc = ofd_object_ff_load(env, ofd_obj); if (rc == -ENODATA) ff_needed = 1; else if (rc < 0) GOTO(out, rc); } if (!la->la_valid && !ff_needed) /* no attributes to set */ GOTO(out, rc = 0); th = ofd_trans_create(env, ofd); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); if (la->la_valid) { rc = dt_declare_attr_set(env, dt_obj, la, th); if (rc) GOTO(out_tx, rc); } if (ff_needed) { if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_UNMATCHED_PAIR1)) ff->ff_parent.f_oid = cpu_to_le32(1UL << 31); if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_UNMATCHED_PAIR2)) ff->ff_parent.f_oid = cpu_to_le32(le32_to_cpu(ff->ff_parent.f_oid) - 1); info->fti_buf.lb_buf = ff; info->fti_buf.lb_len = sizeof(*ff); rc = dt_declare_xattr_set(env, dt_obj, &info->fti_buf, XATTR_NAME_FID, 0, th); if (rc) GOTO(out_tx, rc); } /* We don't need a transno for this operation which will be re-executed * anyway when the OST_WRITE (with a transno assigned) is replayed */ rc = dt_trans_start_local(env, ofd->ofd_osd , th); if (rc) GOTO(out_tx, rc); /* set uid/gid */ if (la->la_valid) { rc = dt_attr_set(env, dt_obj, la, th); if (rc) GOTO(out_tx, rc); } /* set filter fid EA */ if (ff_needed) { if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_NOPFID)) GOTO(out_tx, rc); rc = dt_xattr_set(env, dt_obj, &info->fti_buf, XATTR_NAME_FID, 0, th); if (rc == 0) { ofd_obj->ofo_pfid.f_seq = le64_to_cpu(ff->ff_parent.f_seq); ofd_obj->ofo_pfid.f_oid = le32_to_cpu(ff->ff_parent.f_oid); /* Currently, the filter_fid::ff_parent::f_ver is not * the real parent MDT-object's FID::f_ver, instead it * is the OST-object index in its parent MDT-object's * layout EA. */ ofd_obj->ofo_pfid.f_stripe_idx = le32_to_cpu(ff->ff_parent.f_stripe_idx); } } GOTO(out_tx, rc); out_tx: dt_trans_stop(env, ofd->ofd_osd, th); out: la->la_valid = valid; return rc; }
int ofd_precreate_objects(const struct lu_env *env, struct ofd_device *ofd, obd_id id, struct ofd_seq *oseq, int nr, int sync) { struct ofd_thread_info *info = ofd_info(env); struct ofd_object *fo = NULL; struct dt_object *next; struct thandle *th; struct ofd_object **batch; struct lu_fid *fid = &info->fti_fid; obd_id tmp; int rc; int i; int objects = 0; int nr_saved = nr; ENTRY; /* Don't create objects beyond the valid range for this SEQ */ if (unlikely(fid_seq_is_mdt0(ostid_seq(&oseq->os_oi)) && (id + nr) >= IDIF_MAX_OID)) { CERROR("%s:"DOSTID" hit the IDIF_MAX_OID (1<<48)!\n", ofd_name(ofd), id, ostid_seq(&oseq->os_oi)); RETURN(rc = -ENOSPC); } else if (unlikely(!fid_seq_is_mdt0(ostid_seq(&oseq->os_oi)) && (id + nr) >= OBIF_MAX_OID)) { CERROR("%s:"DOSTID" hit the OBIF_MAX_OID (1<<32)!\n", ofd_name(ofd), id, ostid_seq(&oseq->os_oi)); RETURN(rc = -ENOSPC); } OBD_ALLOC(batch, nr_saved * sizeof(struct ofd_object *)); if (batch == NULL) RETURN(-ENOMEM); info->fti_attr.la_valid = LA_TYPE | LA_MODE; /* * We mark object SUID+SGID to flag it for accepting UID+GID from * client on first write. Currently the permission bits on the OST are * never used, so this is OK. */ info->fti_attr.la_mode = S_IFREG | S_ISUID | S_ISGID | 0666; info->fti_dof.dof_type = dt_mode_to_dft(S_IFREG); /* Initialize a/c/m time so any client timestamp will always * be newer and update the inode. ctime = 0 is also handled * specially in osd_inode_setattr(). See LU-221, LU-1042 */ info->fti_attr.la_valid |= LA_ATIME | LA_MTIME | LA_CTIME; info->fti_attr.la_atime = 0; info->fti_attr.la_mtime = 0; info->fti_attr.la_ctime = 0; LASSERT(id != 0); /* prepare objects */ *fid = *lu_object_fid(&oseq->os_lastid_obj->do_lu); for (i = 0; i < nr; i++) { rc = fid_set_id(fid, id + i); if (rc != 0) { if (i == 0) GOTO(out, rc); nr = i; break; } fo = ofd_object_find(env, ofd, fid); if (IS_ERR(fo)) { if (i == 0) GOTO(out, rc = PTR_ERR(fo)); nr = i; break; } ofd_write_lock(env, fo); batch[i] = fo; } info->fti_buf.lb_buf = &tmp; info->fti_buf.lb_len = sizeof(tmp); info->fti_off = 0; th = ofd_trans_create(env, ofd); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); th->th_sync |= sync; rc = dt_declare_record_write(env, oseq->os_lastid_obj, &info->fti_buf, info->fti_off, th); if (rc) GOTO(trans_stop, rc); for (i = 0; i < nr; i++) { fo = batch[i]; LASSERT(fo); if (unlikely(ofd_object_exists(fo))) { /* object may exist being re-created by write replay */ CDEBUG(D_INODE, "object "LPX64"/"LPX64" exists: " DFID"\n", ostid_seq(&oseq->os_oi), id, PFID(lu_object_fid(&fo->ofo_obj.do_lu))); continue; } next = ofd_object_child(fo); LASSERT(next != NULL); rc = dt_declare_create(env, next, &info->fti_attr, NULL, &info->fti_dof, th); if (rc) { nr = i; break; } } rc = dt_trans_start_local(env, ofd->ofd_osd, th); if (rc) GOTO(trans_stop, rc); CDEBUG(D_OTHER, "%s: create new object "DFID" nr %d\n", ofd_name(ofd), PFID(fid), nr); LASSERT(nr > 0); /* When the LFSCK scanning the whole device to verify the LAST_ID file * consistency, it will load the last_id into RAM firstly, and compare * the last_id with each OST-object's ID. If the later one is larger, * then it will regard the LAST_ID file crashed. But during the LFSCK * scanning, the OFD may continue to create new OST-objects. Those new * created OST-objects will have larger IDs than the LFSCK known ones. * So from the LFSCK view, it needs to re-load the last_id from disk * file, and if the latest last_id is still smaller than the object's * ID, then the LAST_ID file is real crashed. * * To make above mechanism to work, before OFD pre-create OST-objects, * it needs to update the LAST_ID file firstly, otherwise, the LFSCK * may cannot get latest last_id although new OST-object created. */ if (!OBD_FAIL_CHECK(OBD_FAIL_LFSCK_SKIP_LASTID)) { tmp = cpu_to_le64(id + nr - 1); dt_write_lock(env, oseq->os_lastid_obj, 0); rc = dt_record_write(env, oseq->os_lastid_obj, &info->fti_buf, &info->fti_off, th); dt_write_unlock(env, oseq->os_lastid_obj); if (rc != 0) GOTO(trans_stop, rc); } for (i = 0; i < nr; i++) { fo = batch[i]; LASSERT(fo); /* Only the new created objects need to be recorded. */ if (ofd->ofd_osd->dd_record_fid_accessed) { lfsck_pack_rfa(&ofd_info(env)->fti_lr, lu_object_fid(&fo->ofo_obj.do_lu)); lfsck_in_notify(env, ofd->ofd_osd, &ofd_info(env)->fti_lr); } if (likely(!ofd_object_exists(fo) && !OBD_FAIL_CHECK(OBD_FAIL_LFSCK_DANGLING))) { next = ofd_object_child(fo); LASSERT(next != NULL); rc = dt_create(env, next, &info->fti_attr, NULL, &info->fti_dof, th); if (rc) break; LASSERT(ofd_object_exists(fo)); } ofd_seq_last_oid_set(oseq, id + i); } objects = i; /* NOT all the wanted objects have been created, * set the LAST_ID as the real created. */ if (unlikely(objects < nr)) { int rc1; info->fti_off = 0; tmp = cpu_to_le64(ofd_seq_last_oid(oseq)); dt_write_lock(env, oseq->os_lastid_obj, 0); rc1 = dt_record_write(env, oseq->os_lastid_obj, &info->fti_buf, &info->fti_off, th); dt_write_unlock(env, oseq->os_lastid_obj); if (rc1 != 0) CERROR("%s: fail to reset the LAST_ID for seq ("LPX64 ") from "LPU64" to "LPU64"\n", ofd_name(ofd), ostid_seq(&oseq->os_oi), id + nr - 1, ofd_seq_last_oid(oseq)); } trans_stop: ofd_trans_stop(env, ofd, th, rc); out: for (i = 0; i < nr_saved; i++) { fo = batch[i]; if (fo) { ofd_write_unlock(env, fo); ofd_object_put(env, fo); } } OBD_FREE(batch, nr_saved * sizeof(struct ofd_object *)); CDEBUG((objects == 0 && rc == 0) ? D_ERROR : D_OTHER, "created %d/%d objects: %d\n", objects, nr_saved, rc); LASSERT(ergo(objects == 0, rc < 0)); RETURN(objects > 0 ? objects : rc); }
/* returns negative on error; 0 if success; 1 if success & log destroyed */ int llog_cancel_rec(const struct lu_env *env, struct llog_handle *loghandle, int index) { struct llog_thread_info *lgi = llog_info(env); struct dt_device *dt; struct llog_log_hdr *llh = loghandle->lgh_hdr; struct thandle *th; int rc; int rc1; bool subtract_count = false; ENTRY; CDEBUG(D_RPCTRACE, "Canceling %d in log "DOSTID"\n", index, POSTID(&loghandle->lgh_id.lgl_oi)); if (index == 0) { CERROR("Can't cancel index 0 which is header\n"); RETURN(-EINVAL); } LASSERT(loghandle != NULL); LASSERT(loghandle->lgh_ctxt != NULL); LASSERT(loghandle->lgh_obj != NULL); dt = lu2dt_dev(loghandle->lgh_obj->do_lu.lo_dev); th = dt_trans_create(env, dt); if (IS_ERR(th)) RETURN(PTR_ERR(th)); rc = llog_declare_write_rec(env, loghandle, &llh->llh_hdr, index, th); if (rc < 0) GOTO(out_trans, rc); if ((llh->llh_flags & LLOG_F_ZAP_WHEN_EMPTY)) rc = llog_declare_destroy(env, loghandle, th); th->th_wait_submit = 1; rc = dt_trans_start_local(env, dt, th); if (rc < 0) GOTO(out_trans, rc); down_write(&loghandle->lgh_lock); /* clear bitmap */ mutex_lock(&loghandle->lgh_hdr_mutex); if (!ext2_clear_bit(index, LLOG_HDR_BITMAP(llh))) { CDEBUG(D_RPCTRACE, "Catalog index %u already clear?\n", index); GOTO(out_unlock, rc); } loghandle->lgh_hdr->llh_count--; subtract_count = true; /* Pass this index to llog_osd_write_rec(), which will use the index * to only update the necesary bitmap. */ lgi->lgi_cookie.lgc_index = index; /* update header */ rc = llog_write_rec(env, loghandle, &llh->llh_hdr, &lgi->lgi_cookie, LLOG_HEADER_IDX, th); if (rc != 0) GOTO(out_unlock, rc); if ((llh->llh_flags & LLOG_F_ZAP_WHEN_EMPTY) && (llh->llh_count == 1) && ((loghandle->lgh_last_idx == LLOG_HDR_BITMAP_SIZE(llh) - 1) || (loghandle->u.phd.phd_cat_handle != NULL && loghandle->u.phd.phd_cat_handle->u.chd.chd_current_log != loghandle))) { /* never try to destroy it again */ llh->llh_flags &= ~LLOG_F_ZAP_WHEN_EMPTY; rc = llog_trans_destroy(env, loghandle, th); if (rc < 0) { /* Sigh, can not destroy the final plain llog, but * the bitmap has been clearly, so the record can not * be accessed anymore, let's return 0 for now, and * the orphan will be handled by LFSCK. */ CERROR("%s: can't destroy empty llog #"DOSTID "#%08x: rc = %d\n", loghandle->lgh_ctxt->loc_obd->obd_name, POSTID(&loghandle->lgh_id.lgl_oi), loghandle->lgh_id.lgl_ogen, rc); GOTO(out_unlock, rc); } rc = LLOG_DEL_PLAIN; } out_unlock: mutex_unlock(&loghandle->lgh_hdr_mutex); up_write(&loghandle->lgh_lock); out_trans: rc1 = dt_trans_stop(env, dt, th); if (rc == 0) rc = rc1; if (rc < 0 && subtract_count) { mutex_lock(&loghandle->lgh_hdr_mutex); loghandle->lgh_hdr->llh_count++; ext2_set_bit(index, LLOG_HDR_BITMAP(llh)); mutex_unlock(&loghandle->lgh_hdr_mutex); } RETURN(rc); }
/** * Read the special file which contains the list of llog catalogs IDs * * This function reads the CATALOGS file which contains the array of llog * catalogs IDs. The main purpose of this file is to store OSP llogs indexed * by OST/MDT number. * * \param[in] env execution environment * \param[in] d corresponding storage device * \param[in] idx position to start from, usually OST/MDT index * \param[in] count how many catalog IDs to read * \param[out] idarray the buffer for the data. If it is NULL then * function returns just number of catalog IDs * in the file. * \param[in] fid LLOG_CATALOGS_OID for CATALOG object * * \retval 0 on successful read of catalog IDs * \retval negative value on error * \retval positive value which is number of records in * the file if \a idarray is NULL */ int llog_osd_get_cat_list(const struct lu_env *env, struct dt_device *d, int idx, int count, struct llog_catid *idarray, const struct lu_fid *fid) { struct llog_thread_info *lgi = llog_info(env); struct dt_object *o = NULL; struct thandle *th; int rc, size; ENTRY; LASSERT(d); size = sizeof(*idarray) * count; lgi->lgi_off = idx * sizeof(*idarray); lgi->lgi_fid = *fid; o = dt_locate(env, d, &lgi->lgi_fid); if (IS_ERR(o)) RETURN(PTR_ERR(o)); if (!dt_object_exists(o)) { th = dt_trans_create(env, d); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); lgi->lgi_attr.la_valid = LA_MODE; lgi->lgi_attr.la_mode = S_IFREG | S_IRUGO | S_IWUSR; lgi->lgi_dof.dof_type = dt_mode_to_dft(S_IFREG); rc = dt_declare_create(env, o, &lgi->lgi_attr, NULL, &lgi->lgi_dof, th); if (rc) GOTO(out_trans, rc); rc = dt_trans_start_local(env, d, th); if (rc) GOTO(out_trans, rc); dt_write_lock(env, o, 0); if (!dt_object_exists(o)) rc = dt_create(env, o, &lgi->lgi_attr, NULL, &lgi->lgi_dof, th); dt_write_unlock(env, o); out_trans: dt_trans_stop(env, d, th); if (rc) GOTO(out, rc); } rc = dt_attr_get(env, o, &lgi->lgi_attr, BYPASS_CAPA); if (rc) GOTO(out, rc); if (!S_ISREG(lgi->lgi_attr.la_mode)) { CERROR("%s: CATALOGS is not a regular file!: mode = %o\n", o->do_lu.lo_dev->ld_obd->obd_name, lgi->lgi_attr.la_mode); GOTO(out, rc = -ENOENT); } CDEBUG(D_CONFIG, "cat list: disk size=%d, read=%d\n", (int)lgi->lgi_attr.la_size, size); /* return just number of llogs */ if (idarray == NULL) { rc = lgi->lgi_attr.la_size / sizeof(*idarray); GOTO(out, rc); } /* read for new ost index or for empty file */ memset(idarray, 0, size); if (lgi->lgi_attr.la_size <= lgi->lgi_off) GOTO(out, rc = 0); if (lgi->lgi_attr.la_size < lgi->lgi_off + size) size = lgi->lgi_attr.la_size - lgi->lgi_off; lgi->lgi_buf.lb_buf = idarray; lgi->lgi_buf.lb_len = size; rc = dt_record_read(env, o, &lgi->lgi_buf, &lgi->lgi_off); if (rc) { CERROR("%s: error reading CATALOGS: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, rc); GOTO(out, rc); } EXIT; out: lu_object_put(env, &o->do_lu); RETURN(rc); }
int ofd_precreate_objects(const struct lu_env *env, struct ofd_device *ofd, obd_id id, struct ofd_seq *oseq, int nr, int sync) { struct ofd_thread_info *info = ofd_info(env); struct ofd_object *fo = NULL; struct dt_object *next; struct thandle *th; struct ofd_object **batch; obd_id tmp; int rc; int i; int objects = 0; int nr_saved = nr; ENTRY; /* Don't create objects beyond the valid range for this SEQ */ if (unlikely(fid_seq_is_mdt0(ostid_seq(&oseq->os_oi)) && (id + nr) >= IDIF_MAX_OID)) { CERROR("%s:"DOSTID" hit the IDIF_MAX_OID (1<<48)!\n", ofd_name(ofd), id, ostid_seq(&oseq->os_oi)); RETURN(rc = -ENOSPC); } else if (unlikely(!fid_seq_is_mdt0(ostid_seq(&oseq->os_oi)) && (id + nr) >= OBIF_MAX_OID)) { CERROR("%s:"DOSTID" hit the OBIF_MAX_OID (1<<32)!\n", ofd_name(ofd), id, ostid_seq(&oseq->os_oi)); RETURN(rc = -ENOSPC); } OBD_ALLOC(batch, nr_saved * sizeof(struct ofd_object *)); if (batch == NULL) RETURN(-ENOMEM); info->fti_attr.la_valid = LA_TYPE | LA_MODE; /* * We mark object SUID+SGID to flag it for accepting UID+GID from * client on first write. Currently the permission bits on the OST are * never used, so this is OK. */ info->fti_attr.la_mode = S_IFREG | S_ISUID | S_ISGID | 0666; info->fti_dof.dof_type = dt_mode_to_dft(S_IFREG); /* Initialize a/c/m time so any client timestamp will always * be newer and update the inode. ctime = 0 is also handled * specially in osd_inode_setattr(). See LU-221, LU-1042 */ info->fti_attr.la_valid |= LA_ATIME | LA_MTIME | LA_CTIME; info->fti_attr.la_atime = 0; info->fti_attr.la_mtime = 0; info->fti_attr.la_ctime = 0; /* prepare objects */ ostid_set_seq(&info->fti_ostid, ostid_seq(&oseq->os_oi)); for (i = 0; i < nr; i++) { ostid_set_id(&info->fti_ostid, id + i); rc = ostid_to_fid(&info->fti_fid, &info->fti_ostid, 0); if (rc) { if (i == 0) GOTO(out, rc); nr = i; break; } fo = ofd_object_find(env, ofd, &info->fti_fid); if (IS_ERR(fo)) { if (i == 0) GOTO(out, rc = PTR_ERR(fo)); nr = i; break; } ofd_write_lock(env, fo); batch[i] = fo; } info->fti_buf.lb_buf = &tmp; info->fti_buf.lb_len = sizeof(tmp); info->fti_off = 0; th = ofd_trans_create(env, ofd); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); th->th_sync |= sync; rc = dt_declare_record_write(env, oseq->os_lastid_obj, sizeof(tmp), info->fti_off, th); if (rc) GOTO(trans_stop, rc); for (i = 0; i < nr; i++) { fo = batch[i]; LASSERT(fo); if (unlikely(ofd_object_exists(fo))) { /* object may exist being re-created by write replay */ CDEBUG(D_INODE, "object "LPX64"/"LPX64" exists: " DFID"\n", ostid_seq(&oseq->os_oi), id, PFID(&info->fti_fid)); continue; } next = ofd_object_child(fo); LASSERT(next != NULL); rc = dt_declare_create(env, next, &info->fti_attr, NULL, &info->fti_dof, th); if (rc) { nr = i; break; } } rc = dt_trans_start_local(env, ofd->ofd_osd, th); if (rc) GOTO(trans_stop, rc); CDEBUG(D_OTHER, "%s: create new object "DFID" nr %d\n", ofd_name(ofd), PFID(&info->fti_fid), nr); for (i = 0; i < nr; i++) { fo = batch[i]; LASSERT(fo); if (likely(!ofd_object_exists(fo))) { next = ofd_object_child(fo); LASSERT(next != NULL); rc = dt_create(env, next, &info->fti_attr, NULL, &info->fti_dof, th); if (rc) break; LASSERT(ofd_object_exists(fo)); } ofd_seq_last_oid_set(oseq, id + i); } objects = i; if (objects > 0) { tmp = cpu_to_le64(ofd_seq_last_oid(oseq)); rc = dt_record_write(env, oseq->os_lastid_obj, &info->fti_buf, &info->fti_off, th); } trans_stop: ofd_trans_stop(env, ofd, th, rc); out: for (i = 0; i < nr_saved; i++) { fo = batch[i]; if (fo) { ofd_write_unlock(env, fo); ofd_object_put(env, fo); } } OBD_FREE(batch, nr_saved * sizeof(struct ofd_object *)); CDEBUG((objects == 0 && rc == 0) ? D_ERROR : D_OTHER, "created %d/%d objects: %d\n", objects, nr_saved, rc); LASSERT(ergo(objects == 0, rc < 0)); RETURN(objects > 0 ? objects : rc); }
/** * Set attributes of object during write bulk IO processing. * * Change object attributes and write parent FID into extended * attributes when needed. * * \param[in] env execution environment * \param[in] ofd OFD device * \param[in] ofd_obj OFD object * \param[in] la object attributes * \param[in] oa obdo * * \retval 0 on successful attributes update * \retval negative value on error */ static int ofd_write_attr_set(const struct lu_env *env, struct ofd_device *ofd, struct ofd_object *ofd_obj, struct lu_attr *la, struct obdo *oa) { struct ofd_thread_info *info = ofd_info(env); struct filter_fid *ff = &info->fti_mds_fid; __u64 valid = la->la_valid; struct thandle *th; struct dt_object *dt_obj; int fl = 0; int rc; ENTRY; LASSERT(la); dt_obj = ofd_object_child(ofd_obj); LASSERT(dt_obj != NULL); la->la_valid &= LA_UID | LA_GID | LA_PROJID; rc = ofd_attr_handle_id(env, ofd_obj, la, 0 /* !is_setattr */); if (rc != 0) GOTO(out, rc); fl = ofd_object_ff_update(env, ofd_obj, oa, ff); if (fl < 0) GOTO(out, rc = fl); if (!la->la_valid && !fl) /* no attributes to set */ GOTO(out, rc = 0); th = ofd_trans_create(env, ofd); if (IS_ERR(th)) GOTO(out, rc = PTR_ERR(th)); if (la->la_valid) { rc = dt_declare_attr_set(env, dt_obj, la, th); if (rc) GOTO(out_tx, rc); } if (fl) { if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_UNMATCHED_PAIR1)) ff->ff_parent.f_oid = cpu_to_le32(1UL << 31); else if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_UNMATCHED_PAIR2)) le32_add_cpu(&ff->ff_parent.f_oid, -1); rc = dt_declare_xattr_set(env, dt_obj, &info->fti_buf, XATTR_NAME_FID, 0, th); if (rc) GOTO(out_tx, rc); } /* We don't need a transno for this operation which will be re-executed * anyway when the OST_WRITE (with a transno assigned) is replayed */ rc = dt_trans_start_local(env, ofd->ofd_osd , th); if (rc) GOTO(out_tx, rc); /* set uid/gid/projid */ if (la->la_valid) { rc = dt_attr_set(env, dt_obj, la, th); if (rc) GOTO(out_tx, rc); } /* set filter fid EA. * FIXME: it holds read lock of ofd object to modify the XATTR_NAME_FID * while the write lock should be held. However, it should work because * write RPCs only modify ff_{parent,layout} and those information will * be the same from all the write RPCs. The reason that fl is not used * in dt_xattr_set() is to allow this race. */ if (fl) { if (OBD_FAIL_CHECK(OBD_FAIL_LFSCK_NOPFID)) GOTO(out_tx, rc); info->fti_buf.lb_buf = ff; info->fti_buf.lb_len = sizeof(*ff); rc = dt_xattr_set(env, dt_obj, &info->fti_buf, XATTR_NAME_FID, 0, th); if (rc == 0) filter_fid_le_to_cpu(&ofd_obj->ofo_ff, ff, sizeof(*ff)); } GOTO(out_tx, rc); out_tx: dt_trans_stop(env, ofd->ofd_osd, th); out: la->la_valid = valid; return rc; }
static int lfsck_namespace_update(const struct lu_env *env, struct lfsck_component *com, const struct lu_fid *fid, __u8 flags, bool force) { struct lfsck_instance *lfsck = com->lc_lfsck; struct lu_fid *key = &lfsck_env_info(env)->lti_fid; struct thandle *handle; struct dt_object *obj = com->lc_obj; int rc; bool exist = false; __u8 tf; ENTRY; rc = lfsck_namespace_lookup(env, com, fid, &tf); if (rc != 0 && rc != -ENOENT) RETURN(rc); if (rc == 0) { if (!force || flags == tf) RETURN(0); exist = true; handle = dt_trans_create(env, lfsck->li_bottom); if (IS_ERR(handle)) RETURN(PTR_ERR(handle)); rc = dt_declare_delete(env, obj, (const struct dt_key *)fid, handle); if (rc != 0) GOTO(out, rc); } else { handle = dt_trans_create(env, lfsck->li_bottom); if (IS_ERR(handle)) RETURN(PTR_ERR(handle)); } rc = dt_declare_insert(env, obj, (const struct dt_rec *)&flags, (const struct dt_key *)fid, handle); if (rc != 0) GOTO(out, rc); rc = dt_trans_start_local(env, lfsck->li_bottom, handle); if (rc != 0) GOTO(out, rc); fid_cpu_to_be(key, fid); if (exist) { rc = dt_delete(env, obj, (const struct dt_key *)key, handle, BYPASS_CAPA); if (rc != 0) { CERROR("%s: fail to insert "DFID": rc = %d\n", lfsck_lfsck2name(com->lc_lfsck), PFID(fid), rc); GOTO(out, rc); } } rc = dt_insert(env, obj, (const struct dt_rec *)&flags, (const struct dt_key *)key, handle, BYPASS_CAPA, 1); GOTO(out, rc); out: dt_trans_stop(env, lfsck->li_bottom, handle); return rc; }