*/
/*
* This file is part of Lustre, http://www.lustre.org/
- * Lustre is a trademark of Sun Microsystems, Inc.
*
* lustre/osd-zfs/osd_object.c
*
char *osd_obj_tag = "osd_object";
static int osd_object_sync_delay_us = -1;
-static struct dt_object_operations osd_obj_ops;
-static struct lu_object_operations osd_lu_obj_ops;
-static struct dt_object_operations osd_obj_otable_it_ops;
+static const struct dt_object_operations osd_obj_ops;
+static const struct lu_object_operations osd_lu_obj_ops;
+static const struct dt_object_operations osd_obj_otable_it_ops;
static void
osd_object_sa_fini(struct osd_object *obj)
write_lock(&obj->oo_attr_lock);
list_del_init(&obj->oo_sa_linkage);
write_unlock(&obj->oo_attr_lock);
- if (obj->oo_late_xattr) {
+ if (obj->oo_late_xattr && obj->oo_destroyed == 0) {
/*
* take oo_guard to protect oo_sa_xattr buffer
* from concurrent update by osd_xattr_set()
*/
LASSERT(oh->ot_assigned != 0);
down_write(&obj->oo_guard);
- if (obj->oo_late_attr_set)
- __osd_sa_attr_init(env, obj, oh);
- else if (obj->oo_late_xattr)
- __osd_sa_xattr_update(env, obj, oh);
+ if (obj->oo_destroyed == 0) {
+ if (obj->oo_late_attr_set)
+ __osd_sa_attr_init(env, obj, oh);
+ else if (obj->oo_late_xattr)
+ __osd_sa_xattr_update(env, obj, oh);
+ }
up_write(&obj->oo_guard);
}
sa_spill_rele(obj->oo_sa_hdl);
GOTO(out, rc = 0);
rc = osd_check_lma(env, obj);
- if ((!rc && !remote) || (rc != -EREMCHG))
+ if (rc != -EREMCHG)
GOTO(out, rc);
+ osd_scrub_refresh_mapping(env, osd, fid, oid, DTO_INDEX_DELETE, true,
+ NULL);
+
trigger:
/* We still have chance to get the valid dnode: for the object that is
* referenced by remote name entry, the object on the local MDT will be
}
/* The case NOT allow to trigger OI scrub automatically. */
- if (osd->od_auto_scrub_interval == AS_NEVER)
+ if (osd->od_scrub.os_auto_scrub_interval == AS_NEVER)
GOTO(out, rc);
/* It is me to trigger the OI scrub. */
rc1 = osd_scrub_start(env, osd, SS_CLEAR_DRYRUN |
SS_CLEAR_FAILOUT | SS_AUTO_FULL);
- LCONSOLE_WARN("%s: trigger OI scrub by RPC for the "DFID": rc = %d\n",
- osd_name(osd), PFID(fid), rc1);
+ CDEBUG_LIMIT(D_LFSCK | D_CONSOLE | D_WARNING,
+ "%s: trigger OI scrub by RPC for "DFID"/%#llx: rc = %d\n",
+ osd_name(osd), PFID(fid), oid, rc1);
if (!rc) {
LASSERT(remote);
dt_object_fini(&obj->oo_dt);
/* obj doesn't contain an lu_object_header, so we don't need call_rcu */
OBD_SLAB_FREE_PTR(obj, osd_object_kmem);
- if (unlikely(h)) {
- lu_object_header_fini(h);
- OBD_FREE_PRE(h, sizeof(*h), "kfreed");
- kfree_rcu(h, loh_rcu);
- }
+ if (unlikely(h))
+ lu_object_header_free(h);
}
static int
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",
+ CERROR("%s: failed to free %s/%#llx: 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",
+ CERROR("%s: failed to free %s/%#llx: rc = %d\n",
osd->od_svname, buf, oid, rc);
} else { /* asynchronous destroy */
char *key = info->oti_key;
rc = osd_zap_add(osd, osd->od_unlinked->dn_object,
osd->od_unlinked, key, 8, 1, &oid, oh->ot_tx);
if (rc)
- CERROR("%s: zap_add_int() failed %s %llu: rc = %d\n",
+ CERROR("%s: zap_add_int() failed %s/%#llx: rc = %d\n",
osd->od_svname, buf, oid, rc);
}
}
read_unlock(&obj->oo_attr_lock);
if (attr->la_valid & LA_FLAGS && attr->la_flags & LUSTRE_ORPHAN_FL)
- CDEBUG(D_INFO, "%s: set orphan flag on "DFID" (%llx/%x)\n",
+ CDEBUG(D_INFO, "%s: set orphan flag on "DFID" (%#llx/%#x)\n",
osd_obj2dev(obj)->od_svname,
PFID(lu_object_fid(&dt->do_lu)),
attr->la_valid, obj->oo_lma_flags);
return rc;
}
-/* Simple wrapper on top of qsd API which implement quota transfer for osd
- * setattr needs. As a reminder, only the root user can change ownership of
- * a file, that's why EDQUOT & EINPROGRESS errors are discarded */
-static inline int qsd_transfer(const struct lu_env *env,
- struct qsd_instance *qsd,
- struct lquota_trans *trans, int qtype,
- __u64 orig_id, __u64 new_id, __u64 bspace,
- struct lquota_id_info *qi, bool ignore_edquot)
-{
- int rc;
-
- if (unlikely(qsd == NULL))
- return 0;
-
- LASSERT(qtype >= 0 && qtype < LL_MAXQUOTAS);
- qi->lqi_type = qtype;
-
- /* inode accounting */
- qi->lqi_is_blk = false;
-
- /* one more inode for the new owner ... */
- qi->lqi_id.qid_uid = new_id;
- qi->lqi_space = 1;
- rc = qsd_op_begin(env, qsd, trans, qi, NULL);
- if (ignore_edquot && (rc == -EDQUOT || rc == -EINPROGRESS))
- rc = 0;
- if (rc)
- return rc;
-
- /* and one less inode for the current id */
- qi->lqi_id.qid_uid = orig_id;;
- qi->lqi_space = -1;
- /* can't get EDQUOT when reducing usage */
- rc = qsd_op_begin(env, qsd, trans, qi, NULL);
- if (rc == -EINPROGRESS)
- rc = 0;
- if (rc)
- return rc;
-
- /* block accounting */
- qi->lqi_is_blk = true;
-
- /* more blocks for the new owner ... */
- qi->lqi_id.qid_uid = new_id;
- qi->lqi_space = bspace;
- rc = qsd_op_begin(env, qsd, trans, qi, NULL);
- if (ignore_edquot && (rc == -EDQUOT || rc == -EINPROGRESS))
- rc = 0;
- if (rc)
- return rc;
-
- /* and finally less blocks for the current owner */
- qi->lqi_id.qid_uid = orig_id;
- qi->lqi_space = -bspace;
- rc = qsd_op_begin(env, qsd, trans, qi, NULL);
- /* can't get EDQUOT when reducing usage */
- if (rc == -EINPROGRESS)
- rc = 0;
- return rc;
-}
-
static int osd_declare_attr_set(const struct lu_env *env,
struct dt_object *dt,
const struct lu_attr *attr,
down_read(&obj->oo_guard);
if (unlikely(!dt_object_exists(dt) || obj->oo_destroyed))
- GOTO(out, rc = 0);
+ GOTO(out_sem, rc = 0);
LASSERT(obj->oo_sa_hdl != NULL);
LASSERT(oh->ot_tx != NULL);
if (!found)
dmu_tx_hold_bonus(oh->ot_tx, obj->oo_dn->dn_object);
if (oh->ot_tx->tx_err != 0)
- GOTO(out, rc = -oh->ot_tx->tx_err);
+ GOTO(out_sem, rc = -oh->ot_tx->tx_err);
if (attr && attr->la_valid & LA_FLAGS) {
/* LMA is usually a part of bonus, no need to declare
osd->od_svname,
attr->la_uid, attr->la_gid, bspace, blksize);
}
+ /* to preserve locking order - qsd_transfer() may need to flush
+ * currently running transaction when we're out of quota.
+ */
+ up_read(&obj->oo_guard);
- if (attr && attr->la_valid & LA_UID) {
- /* quota enforcement for user */
- if (attr->la_uid != obj->oo_attr.la_uid) {
- rc = qsd_transfer(env, osd_def_qsd(osd),
- &oh->ot_quota_trans, USRQUOTA,
- obj->oo_attr.la_uid, attr->la_uid,
- bspace, &info->oti_qi, true);
- if (rc)
- GOTO(out, rc);
- }
+ /* quota enforcement for user */
+ if (attr && attr->la_valid & LA_UID &&
+ attr->la_uid != obj->oo_attr.la_uid) {
+ rc = qsd_transfer(env, osd_def_qsd(osd),
+ &oh->ot_quota_trans, USRQUOTA,
+ obj->oo_attr.la_uid, attr->la_uid,
+ bspace, &info->oti_qi);
+ if (rc)
+ GOTO(out, rc);
}
- if (attr && attr->la_valid & LA_GID) {
- /* quota enforcement for group */
- if (attr->la_gid != obj->oo_attr.la_gid) {
- rc = qsd_transfer(env, osd_def_qsd(osd),
- &oh->ot_quota_trans, GRPQUOTA,
- obj->oo_attr.la_gid, attr->la_gid,
- bspace, &info->oti_qi,
- !(attr->la_flags &
- LUSTRE_SET_SYNC_FL));
- if (rc)
- GOTO(out, rc);
- }
+
+ /* quota enforcement for group */
+ if (attr && attr->la_valid & LA_GID &&
+ attr->la_gid != obj->oo_attr.la_gid) {
+ rc = qsd_transfer(env, osd_def_qsd(osd),
+ &oh->ot_quota_trans, GRPQUOTA,
+ obj->oo_attr.la_gid, attr->la_gid,
+ bspace, &info->oti_qi);
+ if (rc)
+ GOTO(out, rc);
}
#ifdef ZFS_PROJINHERIT
- if (attr && attr->la_valid & LA_PROJID) {
- /* quota enforcement for project */
- if (attr->la_projid != obj->oo_attr.la_projid) {
- if (!osd->od_projectused_dn)
- GOTO(out, rc = -EOPNOTSUPP);
-
- /* Usually, if project quota is upgradable for the
- * device, then the upgrade will be done before or when
- * mount the device. So when we come here, this project
- * should have project ID attribute already (that is
- * zero by default). Otherwise, there was something
- * wrong during the former upgrade, let's return failure
- * to report that.
- *
- * Please note that, different from other attributes,
- * you can NOT simply set the project ID attribute under
- * such case, because adding (NOT change) project ID
- * attribute needs to change the object's attribute
- * layout to match zfs backend quota accounting
- * requirement. */
- if (unlikely(!obj->oo_with_projid))
- GOTO(out, rc = -ENXIO);
-
- rc = qsd_transfer(env, osd_def_qsd(osd),
- &oh->ot_quota_trans, PRJQUOTA,
- obj->oo_attr.la_projid,
- attr->la_projid, bspace,
- &info->oti_qi, true);
- if (rc)
- GOTO(out, rc);
- }
+ /* quota enforcement for project */
+ if (attr && attr->la_valid & LA_PROJID &&
+ attr->la_projid != obj->oo_attr.la_projid) {
+ if (!osd->od_projectused_dn)
+ GOTO(out, rc = -EOPNOTSUPP);
+
+ /* Usually, if project quota is upgradable for the
+ * device, then the upgrade will be done before or when
+ * mount the device. So when we come here, this project
+ * should have project ID attribute already (that is
+ * zero by default). Otherwise, there was something
+ * wrong during the former upgrade, let's return failure
+ * to report that.
+ *
+ * Please note that, different from other attributes,
+ * you can NOT simply set the project ID attribute under
+ * such case, because adding (NOT change) project ID
+ * attribute needs to change the object's attribute
+ * layout to match zfs backend quota accounting
+ * requirement.
+ */
+ if (unlikely(!obj->oo_with_projid))
+ GOTO(out, rc = -ENXIO);
+
+ rc = qsd_transfer(env, osd_def_qsd(osd),
+ &oh->ot_quota_trans, PRJQUOTA,
+ obj->oo_attr.la_projid,
+ attr->la_projid, bspace,
+ &info->oti_qi);
+ if (rc)
+ GOTO(out, rc);
}
#endif
out:
+ RETURN(rc);
+out_sem:
up_read(&obj->oo_guard);
RETURN(rc);
}
/* we may fix some attributes, better do not change the source */
obj->oo_attr = *attr;
+ obj->oo_attr.la_size = 0;
+ obj->oo_attr.la_nlink = 0;
obj->oo_attr.la_valid |= LA_SIZE | LA_NLINK | LA_TYPE;
#ifdef ZFS_PROJINHERIT
zde->zde_pad = 0;
zde->zde_dnode = dn->dn_object;
- zde->zde_type = IFTODT(attr->la_mode & S_IFMT);
+ zde->zde_type = S_DT(attr->la_mode & S_IFMT);
zapid = osd_get_name_n_idx(env, osd, fid, buf,
sizeof(info->oti_str), &zdn);
__u64 start, __u64 end)
{
struct osd_device *osd = osd_obj2dev(osd_dt_obj(dt));
- struct dmu_buf_impl *db = osd_dt_obj(dt)->oo_dn->dn_dbuf;
uint64_t txg = 0;
ENTRY;
if (osd->od_dt_dev.dd_rdonly)
RETURN(0);
- mutex_enter(&db->db_mtx);
- if (db->db_last_dirty)
- txg = db->db_last_dirty->dr_txg;
- mutex_exit(&db->db_mtx);
-
+ txg = osd_db_dirty_txg(osd_dt_obj(dt)->oo_dn->dn_dbuf);
if (txg) {
/* the object is dirty or being synced */
if (osd_object_sync_delay_us < 0)
return 0;
}
-static struct dt_object_operations osd_obj_ops = {
+static bool osd_check_stale(struct dt_object *dt)
+{
+ return false;
+}
+
+static const struct dt_object_operations osd_obj_ops = {
.do_read_lock = osd_read_lock,
.do_write_lock = osd_write_lock,
.do_read_unlock = osd_read_unlock,
.do_xattr_list = osd_xattr_list,
.do_object_sync = osd_object_sync,
.do_invalidate = osd_invalidate,
+ .do_check_stale = osd_check_stale,
};
-static struct lu_object_operations osd_lu_obj_ops = {
+static const struct lu_object_operations osd_lu_obj_ops = {
.loo_object_init = osd_object_init,
.loo_object_delete = osd_object_delete,
.loo_object_release = osd_object_release,
return 0;
}
-static struct dt_object_operations osd_obj_otable_it_ops = {
+static const struct dt_object_operations osd_obj_otable_it_ops = {
.do_attr_get = osd_otable_it_attr_get,
.do_index_try = osd_index_try,
};