static void dsl_deleg_unset_sync(void *arg, dmu_tx_t *tx) { dsl_deleg_arg_t *dda = arg; dsl_dir_t *dd; dsl_pool_t *dp = dmu_tx_pool(tx); objset_t *mos = dp->dp_meta_objset; nvpair_t *whopair = NULL; uint64_t zapobj; VERIFY0(dsl_dir_hold(dp, dda->dda_name, FTAG, &dd, NULL)); zapobj = dd->dd_phys->dd_deleg_zapobj; if (zapobj == 0) { dsl_dir_rele(dd, FTAG); return; } while ((whopair = nvlist_next_nvpair(dda->dda_nvlist, whopair))) { const char *whokey = nvpair_name(whopair); nvlist_t *perms; nvpair_t *permpair = NULL; uint64_t jumpobj; if (nvpair_value_nvlist(whopair, &perms) != 0) { if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == 0) { (void) zap_remove(mos, zapobj, whokey, tx); VERIFY(0 == zap_destroy(mos, jumpobj, tx)); } spa_history_log_internal_dd(dd, "permission who remove", tx, "%s", whokey); continue; } if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) continue; while ((permpair = nvlist_next_nvpair(perms, permpair))) { const char *perm = nvpair_name(permpair); uint64_t n = 0; (void) zap_remove(mos, jumpobj, perm, tx); if (zap_count(mos, jumpobj, &n) == 0 && n == 0) { (void) zap_remove(mos, zapobj, whokey, tx); VERIFY(0 == zap_destroy(mos, jumpobj, tx)); } spa_history_log_internal_dd(dd, "permission remove", tx, "%s %s", whokey, perm); } } dsl_dir_rele(dd, FTAG); }
static void dsl_deleg_unset_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) { dsl_dir_t *dd = arg1; nvlist_t *nvp = arg2; objset_t *mos = dd->dd_pool->dp_meta_objset; nvpair_t *whopair = NULL; uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj; if (zapobj == 0) return; while (whopair = nvlist_next_nvpair(nvp, whopair)) { const char *whokey = nvpair_name(whopair); nvlist_t *perms; nvpair_t *permpair = NULL; uint64_t jumpobj; if (nvpair_value_nvlist(whopair, &perms) != 0) { if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == 0) { (void) zap_remove(mos, zapobj, whokey, tx); VERIFY(0 == zap_destroy(mos, jumpobj, tx)); } spa_history_internal_log(LOG_DS_PERM_WHO_REMOVE, dd->dd_pool->dp_spa, tx, cr, "%s dataset = %llu", whokey, dd->dd_phys->dd_head_dataset_obj); continue; } if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) != 0) continue; while (permpair = nvlist_next_nvpair(perms, permpair)) { const char *perm = nvpair_name(permpair); uint64_t n = 0; (void) zap_remove(mos, jumpobj, perm, tx); if (zap_count(mos, jumpobj, &n) == 0 && n == 0) { (void) zap_remove(mos, zapobj, whokey, tx); VERIFY(0 == zap_destroy(mos, jumpobj, tx)); } spa_history_internal_log(LOG_DS_PERM_REMOVE, dd->dd_pool->dp_spa, tx, cr, "%s %s dataset = %llu", whokey, perm, dd->dd_phys->dd_head_dataset_obj); } } }
/* * The match type in the code for this function should conform to: * * ------------------------------------------------------------------------ * fs type | z_norm | lookup type | match type * ---------|-------------|-------------|---------------------------------- * CS !norm | 0 | 0 | 0 (exact) * CS norm | formX | 0 | MT_NORMALIZE * CI !norm | upper | !ZCIEXACT | MT_NORMALIZE * CI !norm | upper | ZCIEXACT | MT_NORMALIZE | MT_MATCH_CASE * CI norm | upper|formX | !ZCIEXACT | MT_NORMALIZE * CI norm | upper|formX | ZCIEXACT | MT_NORMALIZE | MT_MATCH_CASE * CM !norm | upper | !ZCILOOK | MT_NORMALIZE | MT_MATCH_CASE * CM !norm | upper | ZCILOOK | MT_NORMALIZE * CM norm | upper|formX | !ZCILOOK | MT_NORMALIZE | MT_MATCH_CASE * CM norm | upper|formX | ZCILOOK | MT_NORMALIZE * * Abbreviations: * CS = Case Sensitive, CI = Case Insensitive, CM = Case Mixed * upper = case folding set by fs type on creation (U8_TEXTPREP_TOUPPER) * formX = unicode normalization form set on fs creation */ static int zfs_dropname(zfs_dirlock_t *dl, znode_t *zp, znode_t *dzp, dmu_tx_t *tx, int flag) { int error; if (ZTOZSB(zp)->z_norm) { matchtype_t mt = MT_NORMALIZE; if ((ZTOZSB(zp)->z_case == ZFS_CASE_INSENSITIVE && (flag & ZCIEXACT)) || (ZTOZSB(zp)->z_case == ZFS_CASE_MIXED && !(flag & ZCILOOK))) { mt |= MT_MATCH_CASE; } error = zap_remove_norm(ZTOZSB(zp)->z_os, dzp->z_id, dl->dl_name, mt, tx); } else { error = zap_remove(ZTOZSB(zp)->z_os, dzp->z_id, dl->dl_name, tx); } return (error); }
void dsl_dir_destroy_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) { dsl_dir_t *dd = arg1; objset_t *mos = dd->dd_pool->dp_meta_objset; uint64_t val, obj; ASSERT(RW_WRITE_HELD(&dd->dd_pool->dp_config_rwlock)); ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); /* Remove our reservation. */ val = 0; dsl_dir_set_reservation_sync(dd, &val, cr, tx); ASSERT3U(dd->dd_used_bytes, ==, 0); ASSERT3U(dd->dd_phys->dd_reserved, ==, 0); VERIFY(0 == zap_destroy(mos, dd->dd_phys->dd_child_dir_zapobj, tx)); VERIFY(0 == zap_destroy(mos, dd->dd_phys->dd_props_zapobj, tx)); VERIFY(0 == dsl_deleg_destroy(mos, dd->dd_phys->dd_deleg_zapobj, tx)); VERIFY(0 == zap_remove(mos, dd->dd_parent->dd_phys->dd_child_dir_zapobj, dd->dd_myname, tx)); obj = dd->dd_object; dsl_dir_close(dd, tag); VERIFY(0 == dmu_object_free(mos, obj, tx)); }
void dsl_dir_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) { dsl_dir_t *dd = arg1; objset_t *mos = dd->dd_pool->dp_meta_objset; uint64_t obj; dd_used_t t; ASSERT(RW_WRITE_HELD(&dd->dd_pool->dp_config_rwlock)); ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); /* * Remove our reservation. The impl() routine avoids setting the * actual property, which would require the (already destroyed) ds. */ dsl_dir_set_reservation_sync_impl(dd, 0, tx); ASSERT0(dd->dd_phys->dd_used_bytes); ASSERT0(dd->dd_phys->dd_reserved); for (t = 0; t < DD_USED_NUM; t++) ASSERT0(dd->dd_phys->dd_used_breakdown[t]); VERIFY(0 == zap_destroy(mos, dd->dd_phys->dd_child_dir_zapobj, tx)); VERIFY(0 == zap_destroy(mos, dd->dd_phys->dd_props_zapobj, tx)); VERIFY(0 == dsl_deleg_destroy(mos, dd->dd_phys->dd_deleg_zapobj, tx)); VERIFY(0 == zap_remove(mos, dd->dd_parent->dd_phys->dd_child_dir_zapobj, dd->dd_myname, tx)); obj = dd->dd_object; dsl_dir_close(dd, tag); VERIFY(0 == dmu_object_free(mos, obj, tx)); }
int zfs_set_userquota(zfs_sb_t *zsb, zfs_userquota_prop_t type, const char *domain, uint64_t rid, uint64_t quota) { char buf[32]; int err; dmu_tx_t *tx; uint64_t *objp; boolean_t fuid_dirtied; if (type != ZFS_PROP_USERQUOTA && type != ZFS_PROP_GROUPQUOTA) return (SET_ERROR(EINVAL)); if (zsb->z_version < ZPL_VERSION_USERSPACE) return (SET_ERROR(ENOTSUP)); objp = (type == ZFS_PROP_USERQUOTA) ? &zsb->z_userquota_obj : &zsb->z_groupquota_obj; err = id_to_fuidstr(zsb, domain, rid, buf, B_TRUE); if (err) return (err); fuid_dirtied = zsb->z_fuid_dirty; tx = dmu_tx_create(zsb->z_os); dmu_tx_hold_zap(tx, *objp ? *objp : DMU_NEW_OBJECT, B_TRUE, NULL); if (*objp == 0) { dmu_tx_hold_zap(tx, MASTER_NODE_OBJ, B_TRUE, zfs_userquota_prop_prefixes[type]); } if (fuid_dirtied) zfs_fuid_txhold(zsb, tx); err = dmu_tx_assign(tx, TXG_WAIT); if (err) { dmu_tx_abort(tx); return (err); } mutex_enter(&zsb->z_lock); if (*objp == 0) { *objp = zap_create(zsb->z_os, DMU_OT_USERGROUP_QUOTA, DMU_OT_NONE, 0, tx); VERIFY(0 == zap_add(zsb->z_os, MASTER_NODE_OBJ, zfs_userquota_prop_prefixes[type], 8, 1, objp, tx)); } mutex_exit(&zsb->z_lock); if (quota == 0) { err = zap_remove(zsb->z_os, *objp, buf, tx); if (err == ENOENT) err = 0; } else { err = zap_update(zsb->z_os, *objp, buf, 8, 1, "a, tx); } ASSERT(err == 0); if (fuid_dirtied) zfs_fuid_sync(zsb, tx); dmu_tx_commit(tx); return (err); }
static int osd_dir_delete(const struct lu_env *env, struct dt_object *dt, const struct dt_key *key, struct thandle *th, struct lustre_capa *capa) { struct osd_object *obj = osd_dt_obj(dt); struct osd_device *osd = osd_obj2dev(obj); struct osd_thandle *oh; dmu_buf_t *zap_db = obj->oo_db; int rc; ENTRY; LASSERT(obj->oo_db); LASSERT(udmu_object_is_zap(obj->oo_db)); LASSERT(th != NULL); oh = container_of0(th, struct osd_thandle, ot_super); /* Remove key from the ZAP */ rc = -zap_remove(osd->od_objset.os, zap_db->db_object, (char *) key, oh->ot_tx); if (rc && rc != -ENOENT) CERROR("%s: zap_remove failed: rc = %d\n", osd->od_svname, rc); RETURN(rc); }
int __osd_xattr_del(const struct lu_env *env, struct osd_object *obj, const char *name, struct osd_thandle *oh) { struct osd_device *osd = osd_obj2dev(obj); udmu_objset_t *uos = &osd->od_objset; uint64_t xa_data_obj; int rc; /* try remove xattr from SA at first */ rc = __osd_sa_xattr_del(env, obj, name, oh); if (rc != -ENOENT) return rc; if (obj->oo_xattr == ZFS_NO_OBJECT) return 0; rc = -zap_lookup(uos->os, obj->oo_xattr, name, sizeof(uint64_t), 1, &xa_data_obj); if (rc == -ENOENT) { rc = 0; } else if (rc == 0) { /* * Entry exists. * We'll delete the existing object and ZAP entry. */ rc = __osd_object_free(uos, xa_data_obj, oh->ot_tx); if (rc) return rc; rc = -zap_remove(uos->os, obj->oo_xattr, name, oh->ot_tx); } return rc; }
static void dsl_dataset_user_release_sync_one(dsl_dataset_t *ds, nvlist_t *holds, dmu_tx_t *tx) { dsl_pool_t *dp = ds->ds_dir->dd_pool; objset_t *mos = dp->dp_meta_objset; nvpair_t *pair; for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL; pair = nvlist_next_nvpair(holds, pair)) { int error; const char *holdname = nvpair_name(pair); /* Remove temporary hold if one exists. */ error = dsl_pool_user_release(dp, ds->ds_object, holdname, tx); VERIFY(error == 0 || error == ENOENT); VERIFY0(zap_remove(mos, dsl_dataset_phys(ds)->ds_userrefs_obj, holdname, tx)); ds->ds_userrefs--; spa_history_log_internal_ds(ds, "release", tx, "tag=%s refs=%lld", holdname, (longlong_t)ds->ds_userrefs); } }
/* * This sync task completes (finishes) a condense, deleting the old * mapping and replacing it with the new one. */ static void spa_condense_indirect_complete_sync(void *arg, dmu_tx_t *tx) { spa_condensing_indirect_t *sci = arg; spa_t *spa = dmu_tx_pool(tx)->dp_spa; spa_condensing_indirect_phys_t *scip = &spa->spa_condensing_indirect_phys; vdev_t *vd = vdev_lookup_top(spa, scip->scip_vdev); vdev_indirect_config_t *vic = &vd->vdev_indirect_config; objset_t *mos = spa->spa_meta_objset; vdev_indirect_mapping_t *old_mapping = vd->vdev_indirect_mapping; uint64_t old_count = vdev_indirect_mapping_num_entries(old_mapping); uint64_t new_count = vdev_indirect_mapping_num_entries(sci->sci_new_mapping); ASSERT(dmu_tx_is_syncing(tx)); ASSERT3P(vd->vdev_ops, ==, &vdev_indirect_ops); ASSERT3P(sci, ==, spa->spa_condensing_indirect); for (int i = 0; i < TXG_SIZE; i++) { ASSERT(list_is_empty(&sci->sci_new_mapping_entries[i])); } ASSERT(vic->vic_mapping_object != 0); ASSERT3U(vd->vdev_id, ==, scip->scip_vdev); ASSERT(scip->scip_next_mapping_object != 0); ASSERT(scip->scip_prev_obsolete_sm_object != 0); /* * Reset vdev_indirect_mapping to refer to the new object. */ rw_enter(&vd->vdev_indirect_rwlock, RW_WRITER); vdev_indirect_mapping_close(vd->vdev_indirect_mapping); vd->vdev_indirect_mapping = sci->sci_new_mapping; rw_exit(&vd->vdev_indirect_rwlock); sci->sci_new_mapping = NULL; vdev_indirect_mapping_free(mos, vic->vic_mapping_object, tx); vic->vic_mapping_object = scip->scip_next_mapping_object; scip->scip_next_mapping_object = 0; space_map_free_obj(mos, scip->scip_prev_obsolete_sm_object, tx); spa_feature_decr(spa, SPA_FEATURE_OBSOLETE_COUNTS, tx); scip->scip_prev_obsolete_sm_object = 0; scip->scip_vdev = 0; VERIFY0(zap_remove(mos, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_CONDENSING_INDIRECT, tx)); spa_condensing_indirect_destroy(spa->spa_condensing_indirect); spa->spa_condensing_indirect = NULL; zfs_dbgmsg("finished condense of vdev %llu in txg %llu: " "new mapping object %llu has %llu entries " "(was %llu entries)", vd->vdev_id, dmu_tx_get_txg(tx), vic->vic_mapping_object, new_count, old_count); vdev_config_dirty(spa->spa_root_vdev); }
/* * Unlink zp from dl, and mark zp for reaping if this was the last link. * Can fail if zp is a mount point (EBUSY) or a non-empty directory (EEXIST). * If 'reaped_ptr' is NULL, we put reaped znodes on the delete queue. * If it's non-NULL, we use it to indicate whether the znode needs reaping, * and it's the caller's job to do it. */ int zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag, int *reaped_ptr) { znode_t *dzp = dl->dl_dzp; vnode_t *vp = ZTOV(zp); int zp_is_dir = (vp->v_type == VDIR); int reaped = 0; int error; dnlc_remove(ZTOV(dzp), dl->dl_name); if (!(flag & ZRENAMING)) { dmu_buf_will_dirty(zp->z_dbuf, tx); if (vn_vfswlock(vp)) /* prevent new mounts on zp */ return (EBUSY); if (vn_ismntpt(vp)) { /* don't remove mount point */ vn_vfsunlock(vp); return (EBUSY); } mutex_enter(&zp->z_lock); if (zp_is_dir && !zfs_dirempty(zp)) { /* dir not empty */ mutex_exit(&zp->z_lock); vn_vfsunlock(vp); return (EEXIST); } ASSERT(zp->z_phys->zp_links > zp_is_dir); if (--zp->z_phys->zp_links == zp_is_dir) { zp->z_reap = 1; zp->z_phys->zp_links = 0; reaped = 1; } else { zfs_time_stamper_locked(zp, STATE_CHANGED, tx); } mutex_exit(&zp->z_lock); vn_vfsunlock(vp); } dmu_buf_will_dirty(dzp->z_dbuf, tx); mutex_enter(&dzp->z_lock); dzp->z_phys->zp_size--; /* one dirent removed */ dzp->z_phys->zp_links -= zp_is_dir; /* ".." link from zp */ zfs_time_stamper_locked(dzp, CONTENT_MODIFIED, tx); mutex_exit(&dzp->z_lock); error = zap_remove(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, tx); ASSERT(error == 0); if (reaped_ptr != NULL) *reaped_ptr = reaped; else if (reaped) zfs_dq_add(zp, tx); return (0); }
void dsl_pool_destroy_obsolete_bpobj(dsl_pool_t *dp, dmu_tx_t *tx) { spa_feature_decr(dp->dp_spa, SPA_FEATURE_OBSOLETE_COUNTS, tx); VERIFY0(zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_OBSOLETE_BPOBJ, tx)); bpobj_free(dp->dp_meta_objset, dp->dp_obsolete_bpobj.bpo_object, tx); bpobj_close(&dp->dp_obsolete_bpobj); }
/* * Sync task to begin the condensing process. */ void spa_condense_indirect_start_sync(vdev_t *vd, dmu_tx_t *tx) { spa_t *spa = vd->vdev_spa; spa_condensing_indirect_phys_t *scip = &spa->spa_condensing_indirect_phys; ASSERT0(scip->scip_next_mapping_object); ASSERT0(scip->scip_prev_obsolete_sm_object); ASSERT0(scip->scip_vdev); ASSERT(dmu_tx_is_syncing(tx)); ASSERT3P(vd->vdev_ops, ==, &vdev_indirect_ops); ASSERT(spa_feature_is_active(spa, SPA_FEATURE_OBSOLETE_COUNTS)); ASSERT(vdev_indirect_mapping_num_entries(vd->vdev_indirect_mapping)); uint64_t obsolete_sm_obj = vdev_obsolete_sm_object(vd); ASSERT(obsolete_sm_obj != 0); scip->scip_vdev = vd->vdev_id; scip->scip_next_mapping_object = vdev_indirect_mapping_alloc(spa->spa_meta_objset, tx); scip->scip_prev_obsolete_sm_object = obsolete_sm_obj; /* * We don't need to allocate a new space map object, since * vdev_indirect_sync_obsolete will allocate one when needed. */ space_map_close(vd->vdev_obsolete_sm); vd->vdev_obsolete_sm = NULL; VERIFY0(zap_remove(spa->spa_meta_objset, vd->vdev_top_zap, VDEV_TOP_ZAP_INDIRECT_OBSOLETE_SM, tx)); VERIFY0(zap_add(spa->spa_dsl_pool->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_CONDENSING_INDIRECT, sizeof (uint64_t), sizeof (*scip) / sizeof (uint64_t), scip, tx)); ASSERT3P(spa->spa_condensing_indirect, ==, NULL); spa->spa_condensing_indirect = spa_condensing_indirect_create(spa); zfs_dbgmsg("starting condense of vdev %llu in txg %llu: " "posm=%llu nm=%llu", vd->vdev_id, dmu_tx_get_txg(tx), (u_longlong_t)scip->scip_prev_obsolete_sm_object, (u_longlong_t)scip->scip_next_mapping_object); zthr_wakeup(spa->spa_condense_zthr); }
static int osd_dir_delete(const struct lu_env *env, struct dt_object *dt, const struct dt_key *key, struct thandle *th, struct lustre_capa *capa) { struct osd_object *obj = osd_dt_obj(dt); struct osd_device *osd = osd_obj2dev(obj); struct osd_thandle *oh; dmu_buf_t *zap_db = obj->oo_db; char *name = (char *)key; int rc; ENTRY; LASSERT(obj->oo_db); LASSERT(udmu_object_is_zap(obj->oo_db)); LASSERT(th != NULL); oh = container_of0(th, struct osd_thandle, ot_super); /* * In Orion . and .. were stored in the directory (not generated upon * request as now). we preserve them for backward compatibility */ if (name[0] == '.') { if (name[1] == 0) { RETURN(0); } else if (name[1] == '.' && name[2] == 0) { RETURN(0); } } /* Remove key from the ZAP */ rc = -zap_remove(osd->od_objset.os, zap_db->db_object, (char *) key, oh->ot_tx); #if LUSTRE_VERSION_CODE <= OBD_OCD_VERSION(2, 4, 53, 0) if (unlikely(rc == -ENOENT && name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0)))) rc = 0; #endif if (unlikely(rc && rc != -ENOENT)) CERROR("%s: zap_remove failed: rc = %d\n", osd->od_svname, rc); RETURN(rc); }
static void dsl_bookmark_destroy_sync(void *arg, dmu_tx_t *tx) { dsl_bookmark_destroy_arg_t *dbda = arg; dsl_pool_t *dp = dmu_tx_pool(tx); objset_t *mos = dp->dp_meta_objset; nvpair_t *pair; for (pair = nvlist_next_nvpair(dbda->dbda_success, NULL); pair != NULL; pair = nvlist_next_nvpair(dbda->dbda_success, pair)) { dsl_dataset_t *ds; char *shortname; uint64_t zap_cnt; VERIFY0(dsl_bookmark_hold_ds(dp, nvpair_name(pair), &ds, FTAG, &shortname)); VERIFY0(dsl_dataset_bookmark_remove(ds, shortname, tx)); /* * If all of this dataset's bookmarks have been destroyed, * free the zap object and decrement the feature's use count. */ VERIFY0(zap_count(mos, ds->ds_bookmarks, &zap_cnt)); if (zap_cnt == 0) { dmu_buf_will_dirty(ds->ds_dbuf, tx); VERIFY0(zap_destroy(mos, ds->ds_bookmarks, tx)); ds->ds_bookmarks = 0; spa_feature_decr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx); VERIFY0(zap_remove(mos, ds->ds_object, DS_FIELD_BOOKMARK_NAMES, tx)); } spa_history_log_internal_ds(ds, "remove bookmark", tx, "name=%s", shortname); dsl_dataset_rele(ds, FTAG); } }
static int zfs_dropname(zfs_dirlock_t *dl, znode_t *zp, znode_t *dzp, dmu_tx_t *tx, int flag) { int error; if (zp->z_zfsvfs->z_norm) { if (((zp->z_zfsvfs->z_case == ZFS_CASE_INSENSITIVE) && (flag & ZCIEXACT)) || ((zp->z_zfsvfs->z_case == ZFS_CASE_MIXED) && !(flag & ZCILOOK))) error = zap_remove_norm(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, MT_EXACT, tx); else error = zap_remove_norm(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, MT_FIRST, tx); } else { error = zap_remove(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, tx); } return (error); }
void dsl_dir_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) { dsl_dataset_t *ds = arg1; dsl_dir_t *dd = ds->ds_dir; objset_t *mos = dd->dd_pool->dp_meta_objset; dsl_prop_setarg_t psa; uint64_t value = 0; uint64_t obj; dd_used_t t; ASSERT(RW_WRITE_HELD(&dd->dd_pool->dp_config_rwlock)); ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); /* Remove our reservation. */ dsl_prop_setarg_init_uint64(&psa, "reservation", (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED), &value); psa.psa_effective_value = 0; /* predict default value */ dsl_dir_set_reservation_sync(ds, &psa, tx); ASSERT3U(dd->dd_phys->dd_used_bytes, ==, 0); ASSERT3U(dd->dd_phys->dd_reserved, ==, 0); for (t = 0; t < DD_USED_NUM; t++) ASSERT3U(dd->dd_phys->dd_used_breakdown[t], ==, 0); VERIFY(0 == zap_destroy(mos, dd->dd_phys->dd_child_dir_zapobj, tx)); VERIFY(0 == zap_destroy(mos, dd->dd_phys->dd_props_zapobj, tx)); VERIFY(0 == dsl_deleg_destroy(mos, dd->dd_phys->dd_deleg_zapobj, tx)); VERIFY(0 == zap_remove(mos, dd->dd_parent->dd_phys->dd_child_dir_zapobj, dd->dd_myname, tx)); obj = dd->dd_object; dsl_dir_close(dd, tag); VERIFY(0 == dmu_object_free(mos, obj, tx)); }
static void dsl_dataset_user_release_sync_one(dsl_dataset_t *ds, nvlist_t *holds, dmu_tx_t *tx) { dsl_pool_t *dp = ds->ds_dir->dd_pool; objset_t *mos = dp->dp_meta_objset; uint64_t zapobj; int error; nvpair_t *pair; for (pair = nvlist_next_nvpair(holds, NULL); pair != NULL; pair = nvlist_next_nvpair(holds, pair)) { ds->ds_userrefs--; error = dsl_pool_user_release(dp, ds->ds_object, nvpair_name(pair), tx); VERIFY(error == 0 || error == ENOENT); zapobj = ds->ds_phys->ds_userrefs_obj; VERIFY0(zap_remove(mos, zapobj, nvpair_name(pair), tx)); spa_history_log_internal_ds(ds, "release", tx, "tag=%s refs=%lld", nvpair_name(pair), (longlong_t)ds->ds_userrefs); } }
int __osd_sa_xattr_set(const struct lu_env *env, struct osd_object *obj, const struct lu_buf *buf, const char *name, int fl, struct osd_thandle *oh) { dmu_buf_impl_t *db; uchar_t *nv_value; size_t size; int nv_size; int rc; int too_big = 0; LASSERT(obj->oo_sa_hdl); if (obj->oo_sa_xattr == NULL) { rc = __osd_xattr_cache(env, obj); if (rc) return rc; } LASSERT(obj->oo_sa_xattr); /* Limited to 32k to keep nvpair memory allocations small */ if (buf->lb_len > DXATTR_MAX_ENTRY_SIZE) { too_big = 1; } else { /* Prevent the DXATTR SA from consuming the entire SA * region */ rc = -nvlist_size(obj->oo_sa_xattr, &size, NV_ENCODE_XDR); if (rc) return rc; if (size + buf->lb_len > DXATTR_MAX_SA_SIZE) too_big = 1; } /* even in case of -EFBIG we must lookup xattr and check can we * rewrite it then delete from SA */ rc = -nvlist_lookup_byte_array(obj->oo_sa_xattr, name, &nv_value, &nv_size); if (rc == 0) { if (fl & LU_XATTR_CREATE) { return -EEXIST; } else if (too_big) { rc = -nvlist_remove(obj->oo_sa_xattr, name, DATA_TYPE_BYTE_ARRAY); if (rc < 0) return rc; rc = __osd_sa_xattr_schedule_update(env, obj, oh); return rc == 0 ? -EFBIG : rc; } } else if (rc == -ENOENT) { if (fl & LU_XATTR_REPLACE) return -ENODATA; else if (too_big) return -EFBIG; } else { return rc; } /* Ensure xattr doesn't exist in ZAP */ if (obj->oo_xattr != ZFS_NO_OBJECT) { struct osd_device *osd = osd_obj2dev(obj); uint64_t objid; rc = -zap_lookup(osd->od_os, obj->oo_xattr, name, 8, 1, &objid); if (rc == 0) { rc = -dmu_object_free(osd->od_os, objid, oh->ot_tx); if (rc == 0) zap_remove(osd->od_os, obj->oo_xattr, name, oh->ot_tx); } } rc = -nvlist_add_byte_array(obj->oo_sa_xattr, name, (uchar_t *)buf->lb_buf, buf->lb_len); if (rc) return rc; /* batch updates only for just created dnodes where we * used to set number of EAs in a single transaction */ db = (dmu_buf_impl_t *)obj->oo_db; if (DB_DNODE(db)->dn_allocated_txg == oh->ot_tx->tx_txg) rc = __osd_sa_xattr_schedule_update(env, obj, oh); else rc = __osd_sa_xattr_update(env, obj, oh); return rc; }
/* ARGSUSED */ static void dsl_scan_done(dsl_scan_t *scn, boolean_t complete, dmu_tx_t *tx) { static const char *old_names[] = { "scrub_bookmark", "scrub_ddt_bookmark", "scrub_ddt_class_max", "scrub_queue", "scrub_min_txg", "scrub_max_txg", "scrub_func", "scrub_errors", NULL }; dsl_pool_t *dp = scn->scn_dp; spa_t *spa = dp->dp_spa; int i; /* Remove any remnants of an old-style scrub. */ for (i = 0; old_names[i]; i++) { (void) zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, old_names[i], tx); } if (scn->scn_phys.scn_queue_obj != 0) { VERIFY(0 == dmu_object_free(dp->dp_meta_objset, scn->scn_phys.scn_queue_obj, tx)); scn->scn_phys.scn_queue_obj = 0; } /* * If we were "restarted" from a stopped state, don't bother * with anything else. */ if (scn->scn_phys.scn_state != DSS_SCANNING) return; if (complete) scn->scn_phys.scn_state = DSS_FINISHED; else scn->scn_phys.scn_state = DSS_CANCELED; spa_history_log_internal(spa, "scan done", tx, "complete=%u", complete); if (DSL_SCAN_IS_SCRUB_RESILVER(scn)) { mutex_enter(&spa->spa_scrub_lock); while (spa->spa_scrub_inflight > 0) { cv_wait(&spa->spa_scrub_io_cv, &spa->spa_scrub_lock); } mutex_exit(&spa->spa_scrub_lock); spa->spa_scrub_started = B_FALSE; spa->spa_scrub_active = B_FALSE; /* * If the scrub/resilver completed, update all DTLs to * reflect this. Whether it succeeded or not, vacate * all temporary scrub DTLs. */ vdev_dtl_reassess(spa->spa_root_vdev, tx->tx_txg, complete ? scn->scn_phys.scn_max_txg : 0, B_TRUE); if (complete) { spa_event_notify(spa, NULL, scn->scn_phys.scn_min_txg ? ESC_ZFS_RESILVER_FINISH : ESC_ZFS_SCRUB_FINISH); } spa_errlog_rotate(spa); /* * We may have finished replacing a device. * Let the async thread assess this and handle the detach. */ spa_async_request(spa, SPA_ASYNC_RESILVER_DONE); } scn->scn_phys.scn_end_time = gethrestime_sec(); }
int __osd_sa_xattr_set(const struct lu_env *env, struct osd_object *obj, const struct lu_buf *buf, const char *name, int fl, struct osd_thandle *oh) { uchar_t *nv_value; size_t size; int nv_size; int rc; int too_big = 0; LASSERT(obj->oo_sa_hdl); if (obj->oo_sa_xattr == NULL) { rc = __osd_xattr_cache(env, obj); if (rc) return rc; } LASSERT(obj->oo_sa_xattr); /* Limited to 32k to keep nvpair memory allocations small */ if (buf->lb_len > DXATTR_MAX_ENTRY_SIZE) { too_big = 1; } else { /* Prevent the DXATTR SA from consuming the entire SA * region */ rc = -nvlist_size(obj->oo_sa_xattr, &size, NV_ENCODE_XDR); if (rc) return rc; if (size + buf->lb_len > DXATTR_MAX_SA_SIZE) too_big = 1; } /* even in case of -EFBIG we must lookup xattr and check can we * rewrite it then delete from SA */ rc = -nvlist_lookup_byte_array(obj->oo_sa_xattr, name, &nv_value, &nv_size); if (rc == 0) { if (fl & LU_XATTR_CREATE) { return -EEXIST; } else if (too_big) { rc = -nvlist_remove(obj->oo_sa_xattr, name, DATA_TYPE_BYTE_ARRAY); if (rc < 0) return rc; rc = __osd_sa_xattr_update(env, obj, oh); return rc == 0 ? -EFBIG : rc; } } else if (rc == -ENOENT) { if (fl & LU_XATTR_REPLACE) return -ENODATA; else if (too_big) return -EFBIG; } else { return rc; } /* Ensure xattr doesn't exist in ZAP */ if (obj->oo_xattr != ZFS_NO_OBJECT) { udmu_objset_t *uos = &osd_obj2dev(obj)->od_objset; uint64_t xa_data_obj; rc = -zap_lookup(uos->os, obj->oo_xattr, name, 8, 1, &xa_data_obj); if (rc == 0) { rc = __osd_object_free(uos, xa_data_obj, oh->ot_tx); if (rc == 0) zap_remove(uos->os, obj->oo_xattr, name, oh->ot_tx); } } rc = -nvlist_add_byte_array(obj->oo_sa_xattr, name, (uchar_t *)buf->lb_buf, buf->lb_len); if (rc) return rc; rc = __osd_sa_xattr_update(env, obj, oh); return rc; }
void zfs_rmnode(znode_t *zp) { zfsvfs_t *zfsvfs = zp->z_zfsvfs; objset_t *os = zfsvfs->z_os; znode_t *xzp = NULL; char obj_name[17]; dmu_tx_t *tx; uint64_t acl_obj; int error; ASSERT(ZTOV(zp)->v_count == 0); ASSERT(zp->z_phys->zp_links == 0); /* * If this is an attribute directory, purge its contents. */ if (ZTOV(zp)->v_type == VDIR && (zp->z_phys->zp_flags & ZFS_XATTR)) { if (zfs_purgedir(zp) != 0) { /* * Not enough space to delete some xattrs. * Leave it on the unlinked set. */ return; } } /* * If the file has extended attributes, we're going to unlink * the xattr dir. */ if (zp->z_phys->zp_xattr) { error = zfs_zget(zfsvfs, zp->z_phys->zp_xattr, &xzp); ASSERT(error == 0); } acl_obj = zp->z_phys->zp_acl.z_acl_extern_obj; /* * Set up the transaction. */ tx = dmu_tx_create(os); dmu_tx_hold_free(tx, zp->z_id, 0, DMU_OBJECT_END); dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL); if (xzp) { dmu_tx_hold_bonus(tx, xzp->z_id); dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, TRUE, NULL); } if (acl_obj) dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END); error = dmu_tx_assign(tx, TXG_WAIT); if (error) { /* * Not enough space to delete the file. Leave it in the * unlinked set, leaking it until the fs is remounted (at * which point we'll call zfs_unlinked_drain() to process it). */ dmu_tx_abort(tx); return; } if (xzp) { dmu_buf_will_dirty(xzp->z_dbuf, tx); mutex_enter(&xzp->z_lock); xzp->z_unlinked = B_TRUE; /* mark xzp for deletion */ xzp->z_phys->zp_links = 0; /* no more links to it */ mutex_exit(&xzp->z_lock); zfs_unlinked_add(xzp, tx); } /* Remove this znode from the unlinked set */ error = zap_remove(os, zfsvfs->z_unlinkedobj, zfs_unlinked_hexname(obj_name, zp->z_id), tx); ASSERT3U(error, ==, 0); zfs_znode_delete(zp, tx); dmu_tx_commit(tx); if (xzp) VN_RELE(ZTOV(xzp)); }
static int osd_object_destroy(const struct lu_env *env, struct dt_object *dt, struct thandle *th) { struct osd_thread_info *info = osd_oti_get(env); char *buf = info->oti_str; struct osd_object *obj = osd_dt_obj(dt); struct osd_device *osd = osd_obj2dev(obj); const struct lu_fid *fid = lu_object_fid(&dt->do_lu); struct osd_thandle *oh; int rc; uint64_t oid, zapid; ENTRY; down_write(&obj->oo_guard); if (unlikely(!dt_object_exists(dt) || obj->oo_destroyed)) GOTO(out, rc = -ENOENT); LASSERT(obj->oo_db != NULL); oh = container_of0(th, struct osd_thandle, ot_super); LASSERT(oh != NULL); LASSERT(oh->ot_tx != NULL); /* remove obj ref from index dir (it depends) */ zapid = osd_get_name_n_idx(env, osd, fid, buf, sizeof(info->oti_str)); rc = -zap_remove(osd->od_os, zapid, buf, oh->ot_tx); if (rc) { CERROR("%s: zap_remove(%s) failed: rc = %d\n", osd->od_svname, buf, rc); GOTO(out, rc); } rc = osd_xattrs_destroy(env, obj, oh); if (rc) { CERROR("%s: cannot destroy xattrs for %s: rc = %d\n", osd->od_svname, buf, rc); GOTO(out, rc); } /* Remove object from inode accounting. It is not fatal for the destroy * operation if something goes wrong while updating accounting, but we * still log an error message to notify the administrator */ rc = -zap_increment_int(osd->od_os, osd->od_iusr_oid, obj->oo_attr.la_uid, -1, oh->ot_tx); if (rc) CERROR("%s: failed to remove "DFID" from accounting ZAP for usr" " %d: rc = %d\n", osd->od_svname, PFID(fid), obj->oo_attr.la_uid, rc); rc = -zap_increment_int(osd->od_os, osd->od_igrp_oid, obj->oo_attr.la_gid, -1, oh->ot_tx); if (rc) CERROR("%s: failed to remove "DFID" from accounting ZAP for grp" " %d: rc = %d\n", osd->od_svname, PFID(fid), obj->oo_attr.la_gid, rc); oid = obj->oo_db->db_object; if (unlikely(obj->oo_destroy == OSD_DESTROY_NONE)) { /* this may happen if the destroy wasn't declared * e.g. when the object is created and then destroyed * in the same transaction - we don't need additional * space for destroy specifically */ LASSERT(obj->oo_attr.la_size <= osd_sync_destroy_max_size); rc = -dmu_object_free(osd->od_os, oid, oh->ot_tx); if (rc) CERROR("%s: failed to free %s %llu: rc = %d\n", osd->od_svname, buf, oid, rc); } else if (obj->oo_destroy == OSD_DESTROY_SYNC) { rc = -dmu_object_free(osd->od_os, oid, oh->ot_tx); if (rc) CERROR("%s: failed to free %s %llu: rc = %d\n", osd->od_svname, buf, oid, rc); } else { /* asynchronous destroy */ rc = osd_object_unlinked_add(obj, oh); if (rc) GOTO(out, rc); rc = -zap_add_int(osd->od_os, osd->od_unlinkedid, oid, oh->ot_tx); if (rc) CERROR("%s: zap_add_int() failed %s %llu: rc = %d\n", osd->od_svname, buf, oid, rc); } out: /* not needed in the cache anymore */ set_bit(LU_OBJECT_HEARD_BANSHEE, &dt->do_lu.lo_header->loh_flags); if (rc == 0) obj->oo_destroyed = 1; up_write(&obj->oo_guard); RETURN (0); }
void zfs_rmnode(znode_t *zp) { zfsvfs_t *zfsvfs = zp->z_zfsvfs; objset_t *os = zfsvfs->z_os; znode_t *xzp = NULL; char obj_name[17]; dmu_tx_t *tx; uint64_t acl_obj; int error; #ifndef __APPLE__ ASSERT(ZTOV(zp)->v_count == 0); #endif /*!__APPLE__*/ ASSERT(zp->z_phys->zp_links == 0); #ifdef ZFS_DEBUG znode_stalker(zp, N_zfs_rmnode); #endif /* * If this is an attribute directory, purge its contents. */ #ifdef __APPLE__ if (S_ISDIR(zp->z_phys->zp_mode) && (zp->z_phys->zp_flags & ZFS_XATTR)) #else if (ZTOV(zp)->v_type == VDIR && (zp->z_phys->zp_flags & ZFS_XATTR)) #endif { if (zfs_purgedir(zp) != 0) { /* * Not enough space to delete some xattrs. * Leave it on the unlinked set. */ return; } } /* * If the file has extended attributes, we're going to unlink * the xattr dir. */ if (zp->z_phys->zp_xattr) { error = zfs_zget(zfsvfs, zp->z_phys->zp_xattr, &xzp); ASSERT(error == 0); } acl_obj = zp->z_phys->zp_acl.z_acl_extern_obj; /* * Set up the transaction. */ tx = dmu_tx_create(os); dmu_tx_hold_free(tx, zp->z_id, 0, DMU_OBJECT_END); dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, FALSE, NULL); if (xzp) { dmu_tx_hold_bonus(tx, xzp->z_id); dmu_tx_hold_zap(tx, zfsvfs->z_unlinkedobj, TRUE, NULL); } if (acl_obj) dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END); error = dmu_tx_assign(tx, TXG_WAIT); if (error) { /* * Not enough space to delete the file. Leave it in the * unlinked set, leaking it until the fs is remounted (at * which point we'll call zfs_unlinked_drain() to process it). */ dmu_tx_abort(tx); #ifdef __APPLE__ /*XXX NOEL: double check this path logic. see radar 5182217. * This may be disturbing some of the evict logic * and hence causing the NULL ptr drefs seen every great while * in some of the test cases*/ zp->z_dbuf_held = 0; ZFS_OBJ_HOLD_EXIT(zfsvfs, zp->z_id); dmu_buf_rele(zp->z_dbuf, NULL); #endif /* __APPLE__ */ return; } if (xzp) { dmu_buf_will_dirty(xzp->z_dbuf, tx); mutex_enter(&xzp->z_lock); xzp->z_unlinked = B_TRUE; /* mark xzp for deletion */ xzp->z_phys->zp_links = 0; /* no more links to it */ mutex_exit(&xzp->z_lock); zfs_unlinked_add(xzp, tx); } /* Remove this znode from the unlinked set */ error = zap_remove(os, zfsvfs->z_unlinkedobj, zfs_unlinked_hexname(obj_name, zp->z_id), tx); ASSERT3U(error, ==, 0); zfs_znode_delete(zp, tx); dmu_tx_commit(tx); if (xzp) VN_RELE(ZTOV(xzp)); }
/* * Unlink zp from dl, and mark zp for deletion if this was the last link. * Can fail if zp is a mount point (EBUSY) or a non-empty directory (EEXIST). * If 'unlinkedp' is NULL, we put unlinked znodes on the unlinked list. * If it's non-NULL, we use it to indicate whether the znode needs deletion, * and it's the caller's job to do it. */ int zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag, boolean_t *unlinkedp) { znode_t *dzp = dl->dl_dzp; vnode_t *vp = ZTOV(zp); #ifdef __APPLE__ int zp_is_dir = S_ISDIR(zp->z_phys->zp_mode); #else int zp_is_dir = (vp->v_type == VDIR); #endif boolean_t unlinked = B_FALSE; int error; #ifndef __APPLE__ dnlc_remove(ZTOV(dzp), dl->dl_name); #endif if (!(flag & ZRENAMING)) { dmu_buf_will_dirty(zp->z_dbuf, tx); #ifdef __APPLE__ if (vp) { #endif /* __APPLE__ */ if (vn_vfswlock(vp)) /* prevent new mounts on zp */ return (EBUSY); if (vn_ismntpt(vp)) { /* don't remove mount point */ vn_vfsunlock(vp); return (EBUSY); } #ifdef __APPLE__ } /* if (vp) */ #endif /* __APPLE__ */ mutex_enter(&zp->z_lock); if (zp_is_dir && !zfs_dirempty(zp)) { /* dir not empty */ mutex_exit(&zp->z_lock); #ifdef __APPLE__ return (ENOTEMPTY); #else vn_vfsunlock(vp); return (EEXIST); #endif } if (zp->z_phys->zp_links <= zp_is_dir) { #ifndef __APPLE__ zfs_panic_recover("zfs: link count on %s is %u, " "should be at least %u", zp->z_vnode->v_path ? zp->z_vnode->v_path : "<unknown>", (int)zp->z_phys->zp_links, zp_is_dir + 1); #endif zp->z_phys->zp_links = zp_is_dir + 1; } if (--zp->z_phys->zp_links == zp_is_dir) { zp->z_unlinked = B_TRUE; zp->z_phys->zp_links = 0; unlinked = B_TRUE; } else { zfs_time_stamper_locked(zp, STATE_CHANGED, tx); } mutex_exit(&zp->z_lock); #ifndef __APPLE__ vn_vfsunlock(vp); #endif } dmu_buf_will_dirty(dzp->z_dbuf, tx); mutex_enter(&dzp->z_lock); dzp->z_phys->zp_size--; /* one dirent removed */ dzp->z_phys->zp_links -= zp_is_dir; /* ".." link from zp */ zfs_time_stamper_locked(dzp, CONTENT_MODIFIED, tx); mutex_exit(&dzp->z_lock); error = zap_remove(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, tx); ASSERT(error == 0); if (unlinkedp != NULL) *unlinkedp = unlinked; else if (unlinked) zfs_unlinked_add(zp, tx); return (0); }
/* ARGSUSED */ static void dsl_pool_scrub_cancel_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) { dsl_pool_t *dp = arg1; boolean_t *completep = arg2; if (dp->dp_scrub_func == SCRUB_FUNC_NONE) return; mutex_enter(&dp->dp_scrub_cancel_lock); if (dp->dp_scrub_restart) { dp->dp_scrub_restart = B_FALSE; *completep = B_FALSE; } /* XXX this is scrub-clean specific */ mutex_enter(&dp->dp_spa->spa_scrub_lock); while (dp->dp_spa->spa_scrub_inflight > 0) { cv_wait(&dp->dp_spa->spa_scrub_io_cv, &dp->dp_spa->spa_scrub_lock); } mutex_exit(&dp->dp_spa->spa_scrub_lock); dp->dp_spa->spa_scrub_active = B_FALSE; dp->dp_scrub_func = SCRUB_FUNC_NONE; VERIFY(0 == dmu_object_free(dp->dp_meta_objset, dp->dp_scrub_queue_obj, tx)); dp->dp_scrub_queue_obj = 0; bzero(&dp->dp_scrub_bookmark, sizeof (zbookmark_t)); bzero(&dp->dp_scrub_ddt_bookmark, sizeof (ddt_bookmark_t)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_QUEUE, tx)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_MIN_TXG, tx)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_MAX_TXG, tx)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_BOOKMARK, tx)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_FUNC, tx)); VERIFY(0 == zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_ERRORS, tx)); (void) zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_DDT_BOOKMARK, tx); (void) zap_remove(dp->dp_meta_objset, DMU_POOL_DIRECTORY_OBJECT, DMU_POOL_SCRUB_DDT_CLASS_MAX, tx); spa_history_internal_log(LOG_POOL_SCRUB_DONE, dp->dp_spa, tx, cr, "complete=%u", *completep); /* below is scrub-clean specific */ vdev_scrub_stat_update(dp->dp_spa->spa_root_vdev, POOL_SCRUB_NONE, *completep); /* * If the scrub/resilver completed, update all DTLs to reflect this. * Whether it succeeded or not, vacate all temporary scrub DTLs. */ vdev_dtl_reassess(dp->dp_spa->spa_root_vdev, tx->tx_txg, *completep ? dp->dp_scrub_max_txg : 0, B_TRUE); dp->dp_spa->spa_scrub_started = B_FALSE; if (*completep) spa_event_notify(dp->dp_spa, NULL, dp->dp_scrub_min_txg ? ESC_ZFS_RESILVER_FINISH : ESC_ZFS_SCRUB_FINISH); spa_errlog_rotate(dp->dp_spa); /* * We may have finished replacing a device. * Let the async thread assess this and handle the detach. */ spa_async_request(dp->dp_spa, SPA_ASYNC_RESILVER_DONE); dp->dp_scrub_min_txg = dp->dp_scrub_max_txg = 0; mutex_exit(&dp->dp_scrub_cancel_lock); }
static int osd_object_destroy(const struct lu_env *env, struct dt_object *dt, struct thandle *th) { char *buf = osd_oti_get(env)->oti_str; struct osd_object *obj = osd_dt_obj(dt); struct osd_device *osd = osd_obj2dev(obj); const struct lu_fid *fid = lu_object_fid(&dt->do_lu); struct osd_thandle *oh; int rc; uint64_t zapid; ENTRY; LASSERT(obj->oo_db != NULL); LASSERT(dt_object_exists(dt)); LASSERT(!lu_object_is_dying(dt->do_lu.lo_header)); oh = container_of0(th, struct osd_thandle, ot_super); LASSERT(oh != NULL); LASSERT(oh->ot_tx != NULL); zapid = osd_get_name_n_idx(env, osd, fid, buf); /* remove obj ref from index dir (it depends) */ rc = -zap_remove(osd->od_objset.os, zapid, buf, oh->ot_tx); if (rc) { CERROR("%s: zap_remove() failed: rc = %d\n", osd->od_svname, rc); GOTO(out, rc); } /* Remove object from inode accounting. It is not fatal for the destroy * operation if something goes wrong while updating accounting, but we * still log an error message to notify the administrator */ rc = -zap_increment_int(osd->od_objset.os, osd->od_iusr_oid, obj->oo_attr.la_uid, -1, oh->ot_tx); if (rc) CERROR("%s: failed to remove "DFID" from accounting ZAP for usr" " %d: rc = %d\n", osd->od_svname, PFID(fid), obj->oo_attr.la_uid, rc); rc = -zap_increment_int(osd->od_objset.os, osd->od_igrp_oid, obj->oo_attr.la_gid, -1, oh->ot_tx); if (rc) CERROR("%s: failed to remove "DFID" from accounting ZAP for grp" " %d: rc = %d\n", osd->od_svname, PFID(fid), obj->oo_attr.la_gid, rc); /* kill object */ rc = __osd_object_destroy(env, obj, oh->ot_tx, osd_obj_tag); if (rc) { CERROR("%s: __osd_object_destroy() failed: rc = %d\n", osd->od_svname, rc); GOTO(out, rc); } out: /* not needed in the cache anymore */ set_bit(LU_OBJECT_HEARD_BANSHEE, &dt->do_lu.lo_header->loh_flags); RETURN (0); }
/* * Unlink zp from dl, and mark zp for deletion if this was the last link. * Can fail if zp is a mount point (EBUSY) or a non-empty directory (EEXIST). * If 'unlinkedp' is NULL, we put unlinked znodes on the unlinked list. * If it's non-NULL, we use it to indicate whether the znode needs deletion, * and it's the caller's job to do it. */ int zfs_link_destroy(zfs_dirlock_t *dl, znode_t *zp, dmu_tx_t *tx, int flag, boolean_t *unlinkedp) { znode_t *dzp = dl->dl_dzp; vnode_t *vp = ZTOV(zp); int zp_is_dir = (vp->v_type == VDIR); boolean_t unlinked = B_FALSE; int error; dnlc_remove(ZTOV(dzp), dl->dl_name); if (!(flag & ZRENAMING)) { dmu_buf_will_dirty(zp->z_dbuf, tx); if (vn_vfswlock(vp)) /* prevent new mounts on zp */ return (EBUSY); if (vn_ismntpt(vp)) { /* don't remove mount point */ vn_vfsunlock(vp); return (EBUSY); } mutex_enter(&zp->z_lock); if (zp_is_dir && !zfs_dirempty(zp)) { /* dir not empty */ mutex_exit(&zp->z_lock); vn_vfsunlock(vp); return (ENOTEMPTY); } if (zp->z_phys->zp_links <= zp_is_dir) { zfs_panic_recover("zfs: link count on vnode %p is %u, " "should be at least %u", zp->z_vnode, (int)zp->z_phys->zp_links, zp_is_dir + 1); zp->z_phys->zp_links = zp_is_dir + 1; } if (--zp->z_phys->zp_links == zp_is_dir) { zp->z_unlinked = B_TRUE; zp->z_phys->zp_links = 0; unlinked = B_TRUE; } else { zfs_time_stamper_locked(zp, STATE_CHANGED, tx); } mutex_exit(&zp->z_lock); vn_vfsunlock(vp); } dmu_buf_will_dirty(dzp->z_dbuf, tx); mutex_enter(&dzp->z_lock); dzp->z_phys->zp_size--; /* one dirent removed */ dzp->z_phys->zp_links -= zp_is_dir; /* ".." link from zp */ zfs_time_stamper_locked(dzp, CONTENT_MODIFIED, tx); mutex_exit(&dzp->z_lock); if (zp->z_zfsvfs->z_norm) { if (((zp->z_zfsvfs->z_case == ZFS_CASE_INSENSITIVE) && (flag & ZCIEXACT)) || ((zp->z_zfsvfs->z_case == ZFS_CASE_MIXED) && !(flag & ZCILOOK))) error = zap_remove_norm(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, MT_EXACT, tx); else error = zap_remove_norm(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, MT_FIRST, tx); } else { error = zap_remove(zp->z_zfsvfs->z_os, dzp->z_id, dl->dl_name, tx); } ASSERT(error == 0); if (unlinkedp != NULL) *unlinkedp = unlinked; else if (unlinked) zfs_unlinked_add(zp, tx); return (0); }
void zfs_rmnode(znode_t *zp) { zfsvfs_t *zfsvfs = zp->z_zfsvfs; objset_t *os = zfsvfs->z_os; znode_t *xzp = NULL; char obj_name[17]; dmu_tx_t *tx; uint64_t acl_obj; int error; ASSERT(ZTOV(zp)->v_count == 0); ASSERT(zp->z_phys->zp_links == 0); /* * If this is an attribute directory, purge its contents. */ if (ZTOV(zp)->v_type == VDIR && (zp->z_phys->zp_flags & ZFS_XATTR)) if (zfs_purgedir(zp) != 0) { zfs_delete_t *delq = &zfsvfs->z_delete_head; /* * Add this back to the delete list to be retried later. * * XXX - this could just busy loop on us... */ mutex_enter(&delq->z_mutex); list_insert_tail(&delq->z_znodes, zp); delq->z_znode_count++; mutex_exit(&delq->z_mutex); return; } /* * If the file has extended attributes, unlink the xattr dir. */ if (zp->z_phys->zp_xattr) { error = zfs_zget(zfsvfs, zp->z_phys->zp_xattr, &xzp); ASSERT(error == 0); } acl_obj = zp->z_phys->zp_acl.z_acl_extern_obj; /* * Set up the transaction. */ tx = dmu_tx_create(os); dmu_tx_hold_free(tx, zp->z_id, 0, DMU_OBJECT_END); dmu_tx_hold_zap(tx, zfsvfs->z_dqueue, FALSE, NULL); if (xzp) { dmu_tx_hold_bonus(tx, xzp->z_id); dmu_tx_hold_zap(tx, zfsvfs->z_dqueue, TRUE, NULL); } if (acl_obj) dmu_tx_hold_free(tx, acl_obj, 0, DMU_OBJECT_END); error = dmu_tx_assign(tx, TXG_WAIT); if (error) { zfs_delete_t *delq = &zfsvfs->z_delete_head; dmu_tx_abort(tx); /* * Add this back to the delete list to be retried later. * * XXX - this could just busy loop on us... */ mutex_enter(&delq->z_mutex); list_insert_tail(&delq->z_znodes, zp); delq->z_znode_count++; mutex_exit(&delq->z_mutex); return; } if (xzp) { dmu_buf_will_dirty(xzp->z_dbuf, tx); mutex_enter(&xzp->z_lock); xzp->z_reap = 1; /* mark xzp for deletion */ xzp->z_phys->zp_links = 0; /* no more links to it */ mutex_exit(&xzp->z_lock); zfs_dq_add(xzp, tx); /* add xzp to delete queue */ } /* * Remove this znode from delete queue */ error = zap_remove(os, zfsvfs->z_dqueue, zfs_dq_hexname(obj_name, zp->z_id), tx); ASSERT3U(error, ==, 0); zfs_znode_delete(zp, tx); dmu_tx_commit(tx); if (xzp) VN_RELE(ZTOV(xzp)); }