void daemon_cleanup(struct daemon* daemon) { int i; log_assert(daemon); /* before stopping main worker, handle signals ourselves, so we don't die on multiple reload signals for example. */ signal_handling_record(); log_thread_set(NULL); /* clean up caches because * a) RRset IDs will be recycled after a reload, causing collisions * b) validation config can change, thus rrset, msg, keycache clear */ slabhash_clear(&daemon->env->rrset_cache->table); slabhash_clear(daemon->env->msg_cache); local_zones_delete(daemon->local_zones); daemon->local_zones = NULL; /* key cache is cleared by module desetup during next daemon_fork() */ daemon_remote_clear(daemon->rc); for(i=0; i<daemon->num; i++) worker_delete(daemon->workers[i]); free(daemon->workers); daemon->workers = NULL; daemon->num = 0; #ifdef USE_DNSTAP dt_delete(daemon->dtenv); #endif daemon->cfg = NULL; }
static int out_tx_index_insert_undo(struct mdt_thread_info *info, struct thandle *th, struct tx_arg *arg) { struct dt_object *dt_obj = arg->object; int rc; LASSERT(dt_obj != NULL && !IS_ERR(dt_obj)); CDEBUG(D_OTHER, "index delete "DFID" name: %s\n", PFID(lu_object_fid(&arg->object->do_lu)), (char *)arg->u.insert.key); if (dt_try_as_dir(info->mti_env, dt_obj) == 0) { CERROR("%s: "DFID" is not directory: rc = %d\n", mdt_obd_name(info->mti_mdt), PFID(lu_object_fid(&dt_obj->do_lu)), -ENOTDIR); return -ENOTDIR; } dt_write_lock(info->mti_env, dt_obj, MOR_TGT_CHILD); rc = dt_delete(info->mti_env, dt_obj, arg->u.insert.key, th, NULL); dt_write_unlock(info->mti_env, dt_obj); update_insert_reply(arg->reply, NULL, 0, arg->index, rc); 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; }
/** * 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 inline int mdd_orphan_delete_obj(const struct lu_env *env, struct mdd_device *mdd , struct dt_key *key, struct thandle *th) { struct dt_object *dor = mdd->mdd_orphans; return dt_delete(env, dor, key, th); }
/* * 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); }
/* * 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); }
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); }
static int out_obj_index_delete(const struct lu_env *env, struct dt_object *dt_obj, const struct dt_key *key, struct thandle *th) { int rc; CDEBUG(D_INFO, "%s: index delete "DFID" name: %s\n", dt_obd_name(th->th_dev), PFID(lu_object_fid(&dt_obj->do_lu)), (char *)key); if (dt_try_as_dir(env, dt_obj) == 0) return -ENOTDIR; dt_write_lock(env, dt_obj, MOR_TGT_CHILD); rc = dt_delete(env, dt_obj, key, th, NULL); dt_write_unlock(env, dt_obj); return rc; }
/*! API: run tests. */ int main(int argc, char *argv[]) { plan(8); // Register service and signal handler struct sigaction sa; sa.sa_handler = interrupt_handle; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGALRM, &sa, NULL); // Interrupt /* Initialize */ srand(time(NULL)); pthread_mutex_init(&_runnable_mx, NULL); pthread_mutex_init(&_destructor_mx, NULL); /* Test 1: Create unit */ dt_unit_t *unit = dt_create(2, &runnable, NULL, NULL); ok(unit != NULL, "dthreads: create unit (size %d)", unit->size); if (unit == NULL) { skip_block(7, "No dthreads unit"); goto skip_all; } /* Test 2: Start tasks. */ _runnable_i = 0; ok(dt_start(unit) == 0, "dthreads: start single task"); /* Test 3: Wait for tasks. */ ok(dt_join(unit) == 0, "dthreads: join threads"); /* Test 4: Compare counter. */ int expected = _runnable_cycles * 2; is_int(expected, _runnable_i, "dthreads: result ok"); /* Test 5: Deinitialize */ dt_delete(&unit); ok(unit == NULL, "dthreads: delete unit"); /* Test 6: Wrong values. */ unit = dt_create(-1, NULL, NULL, NULL); ok(unit == NULL, "dthreads: create with negative count"); /* Test 7: NULL operations crashing. */ int ret = 0; ret += dt_activate(0); ret += dt_cancel(0); ret += dt_compact(0); dt_delete(0); ret += dt_is_cancelled(0); ret += dt_join(0); ret += dt_signalize(0, SIGALRM); ret += dt_start(0); ret += dt_stop(0); ret += dt_unit_lock(0); ret += dt_unit_unlock(0); is_int(-1098, ret, "dthreads: correct values when passed NULL context"); /* Test 8: Thread destructor. */ _destructor_data = 0; unit = dt_create(2, 0, destruct, 0); dt_start(unit); dt_stop(unit); dt_join(unit); is_int(2, _destructor_data, "dthreads: destructor with dt_create_coherent()"); dt_delete(&unit); skip_all: pthread_mutex_destroy(&_runnable_mx); pthread_mutex_destroy(&_destructor_mx); return 0; }
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); }
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; }
/** * insert range in fld store. * * \param range range to be inserted * \param th transaction for this operation as it could compound * transaction. * * \retval 0 success * \retval -ve error * * The whole fld index insertion is protected by seq->lss_mutex (see * seq_server_alloc_super), i.e. only one thread will access fldb each * time, so we do not need worry the fld file and cache will being * changed between declare and create. * Because the fld entry can only be increamental, so we will only check * whether it can be merged from the left. **/ int fld_index_create(const struct lu_env *env, struct lu_server_fld *fld, const struct lu_seq_range *new_range, struct thandle *th) { struct lu_seq_range *range; struct lu_seq_range *tmp; struct fld_thread_info *info; int rc = 0; int deleted = 0; struct fld_cache_entry *flde; ENTRY; info = lu_context_key_get(&env->le_ctx, &fld_thread_key); LASSERT_MUTEX_LOCKED(&fld->lsf_lock); range = &info->fti_lrange; memset(range, 0, sizeof(*range)); tmp = &info->fti_irange; rc = fld_index_lookup(env, fld, new_range->lsr_start, range); if (rc != -ENOENT) { rc = rc == 0 ? -EEXIST : rc; GOTO(out, rc); } if (new_range->lsr_start == range->lsr_end && range->lsr_end != 0 && range_compare_loc(new_range, range) == 0) { range_cpu_to_be(tmp, range); rc = dt_delete(env, fld->lsf_obj, (struct dt_key *)&tmp->lsr_start, th, BYPASS_CAPA); if (rc != 0) GOTO(out, rc); memcpy(tmp, new_range, sizeof(*new_range)); tmp->lsr_start = range->lsr_start; deleted = 1; } else { memcpy(tmp, new_range, sizeof(*new_range)); } range_cpu_to_be(tmp, tmp); rc = dt_insert(env, fld->lsf_obj, (struct dt_rec *)tmp, (struct dt_key *)&tmp->lsr_start, th, BYPASS_CAPA, 1); if (rc != 0) { CERROR("%s: insert range "DRANGE" failed: rc = %d\n", fld->lsf_name, PRANGE(new_range), rc); GOTO(out, rc); } flde = fld_cache_entry_create(new_range); if (IS_ERR(flde)) GOTO(out, rc = PTR_ERR(flde)); write_lock(&fld->lsf_cache->fci_lock); if (deleted) fld_cache_delete_nolock(fld->lsf_cache, new_range); rc = fld_cache_insert_nolock(fld->lsf_cache, flde); write_unlock(&fld->lsf_cache->fci_lock); if (rc) OBD_FREE_PTR(flde); out: 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); }
/*! API: run tests. */ static int dt_tests_run(int argc, char *argv[]) { // Register service and signal handler struct sigaction sa; sa.sa_handler = interrupt_handle; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGALRM, &sa, NULL); // Interrupt /* Initialize */ srand(time(NULL)); struct timeval tv; pthread_mutex_init(&_runnable_mx, NULL); /* Test 1: Create unit */ dt_unit_t *unit = dt_test_create(2); ok(unit != 0, "dthreads: create unit (optimal size %d)", unit->size); skip(unit == 0, DT_TEST_COUNT - 1); /* Test 2: Assign a single task. */ ok(dt_test_single(unit), "dthreads: assign single task"); /* Test 3: Start tasks. */ _runnable_i = 0; ok(dt_test_start(unit), "dthreads: start single task"); /* Test 4: Wait for tasks. */ ok(dt_test_join(unit), "dthreads: join threads"); /* Test 5: Compare counter. */ int expected = _runnable_cycles * 1; cmp_ok(_runnable_i, "==", expected, "dthreads: result ok"); /* Test 6: Repurpose threads. */ _runnable_i = 0; ok(dt_test_coherent(unit), "dthreads: repurpose to coherent"); /* Test 7: Restart threads. */ ok(dt_test_start(unit), "dthreads: start coherent unit"); /* Test 8: Repurpose single thread. */ tv.tv_sec = 0; tv.tv_usec = 4000 + rand() % 1000; // 4-5ms note("waiting for %dus to let thread do some work ...", tv.tv_usec); select(0, 0, 0, 0, &tv); ok(dt_test_repurpose(unit, 0), "dthreads: repurpose on-the-fly"); /* Test 9: Cancel blocking thread. */ tv.tv_sec = 0; tv.tv_usec = (250 + rand() % 500) * 1000; // 250-750ms note("waiting for %dms to let thread pretend blocking I/O ...", tv.tv_usec / 1000); select(0, 0, 0, 0, &tv); ok(dt_test_cancel(unit, 0), "dthreads: cancel blocking thread"); /* Test 10: Wait for tasks. */ ok(dt_test_join(unit), "dthreads: join threads"); /* Test 11: Compare counter. */ int expected_lo = _runnable_cycles * (unit->size - 1); cmp_ok(_runnable_i, ">=", expected_lo, "dthreads: result %d is => %d", _runnable_i, expected_lo); /* Test 12: Compare counter #2. */ /*! \note repurpose could trigger next run of the unit if both finished */ int expected_hi = _runnable_cycles * (unit->size + unit->size - 1); cmp_ok(_runnable_i, "<=", expected_hi, "dthreads: result %d is <= %d", _runnable_i, expected_hi); /* Test 13: Reanimate dead threads. */ ok(dt_test_reanimate(unit), "dthreads: reanimate dead threads"); /* Test 14: Deinitialize */ dt_delete(&unit); ok(unit == 0, "dthreads: delete unit"); endskip; /* Test 15: Wrong values. */ unit = dt_create(-1); ok(unit == 0, "dthreads: create with negative count"); unit = dt_create_coherent(dt_optimal_size(), 0, 0); /* Test 16: NULL runnable. */ cmp_ok(dt_start(unit), "==", 0, "dthreads: start with NULL runnable"); /* Test 17: NULL operations crashing. */ int op_count = 14; int expected_min = op_count * -1; // All functions must return -1 at least int ret = 0; lives_ok( { ret += dt_activate(0); // -1 ret += dt_cancel(0); // -1 ret += dt_compact(0); // -1 dt_delete(0); // ret += dt_is_cancelled(0); // 0 ret += dt_join(0); // -1 ret += dt_repurpose(0, 0, 0); // -1 ret += dt_signalize(0, SIGALRM); // -1 ret += dt_start(0); // -1 ret += dt_start_id(0); // -1 ret += dt_stop(0); // -1 ret += dt_stop_id(0); // -1 ret += dt_unit_lock(0); // -1 ret += dt_unit_unlock(0); // -1 }, "dthreads: not crashed while executing functions on NULL context");
/** * 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 a record in a quota index file. * * \param env - is the environment passed by the caller * \param th - is the transaction to use for disk writes * \param obj - is the on-disk index to be updated. * \param id - is the key to be updated * \param rec - is the input record containing the new quota settings. * \param flags - can be LQUOTA_BUMP_VER or LQUOTA_SET_VER. * \param ver - is the new version of the index if LQUOTA_SET_VER is set or is * used to return the new version of the index when * LQUOTA_BUMP_VER is set. * * \retval - 0 on success, appropriate error on failure */ int lquota_disk_write(const struct lu_env *env, struct thandle *th, struct dt_object *obj, union lquota_id *id, struct dt_rec *rec, __u32 flags, __u64 *ver) { struct lquota_thread_info *qti = lquota_info(env); struct dt_key *key = (struct dt_key *)&id->qid_uid; int rc; ENTRY; LASSERT(dt_object_exists(obj)); LASSERT(obj->do_index_ops != NULL); /* lock index */ dt_write_lock(env, obj, 0); /* check whether there is already an existing record for this ID */ rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_rec, key, BYPASS_CAPA); if (rc == 0) { /* delete existing record in order to replace it */ rc = dt_delete(env, obj, key, th, BYPASS_CAPA); if (rc) GOTO(out, rc); } else if (rc == -ENOENT) { /* probably first insert */ rc = 0; } else { GOTO(out, rc); } if (rec != NULL) { /* insert record with updated quota settings */ rc = dt_insert(env, obj, rec, key, th, BYPASS_CAPA, 1); if (rc) { /* try to insert the old one */ rc = dt_insert(env, obj, (struct dt_rec *)&qti->qti_rec, key, th, BYPASS_CAPA, 1); LASSERTF(rc == 0, "failed to insert record in quota " "index "DFID, PFID(lu_object_fid(&obj->do_lu))); GOTO(out, rc); } } if (flags != 0) { LASSERT(ver); if (flags & LQUOTA_BUMP_VER) { /* caller wants to bump the version, let's first read * it */ *ver = dt_version_get(env, obj); (*ver)++; } else { LASSERT(flags & LQUOTA_SET_VER); } dt_version_set(env, obj, *ver, th); } EXIT; out: dt_write_unlock(env, obj); return rc; }