return rc;
}
-/* has not lock on pobj yet */
-static int mdd_ni_sanity_check(const struct lu_env *env,
- struct md_object *pobj,
- const struct md_attr *ma)
-{
- struct mdd_object *obj = md2mdd_obj(pobj);
- int rc;
- ENTRY;
-
- if (ma->ma_attr_flags & MDS_PERM_BYPASS)
- RETURN(0);
-
- rc = mdd_may_create(env, obj, NULL, 1, S_ISDIR(ma->ma_attr.la_mode));
-
- RETURN(rc);
-}
-
-/*
- * Partial operation.
- */
-static int mdd_name_insert(const struct lu_env *env,
- struct md_object *pobj,
- const struct lu_name *lname,
- const struct lu_fid *fid,
- const struct md_attr *ma)
-{
- const char *name = lname->ln_name;
- struct lu_attr *la = &mdd_env_info(env)->mti_la_for_fix;
- struct mdd_object *mdd_obj = md2mdd_obj(pobj);
- struct dynlock_handle *dlh;
- struct thandle *handle;
- int is_dir = S_ISDIR(ma->ma_attr.la_mode);
-#ifdef HAVE_QUOTA_SUPPORT
- struct mdd_device *mdd = mdo2mdd(pobj);
- struct md_ucred *uc = md_ucred(env);
- struct obd_device *obd = mdd->mdd_obd_dev;
- struct obd_export *exp = md_quota(env)->mq_exp;
- struct mds_obd *mds = &obd->u.mds;
- unsigned int qids[MAXQUOTAS] = { 0, 0 };
- int quota_opc = 0, rec_pending[MAXQUOTAS] = { 0, 0 };
- cfs_cap_t save = uc->mu_cap;
-#endif
- int rc;
- ENTRY;
-
- /* XXX: this code won't be used ever:
- * DNE uses slightly different approach */
- LBUG();
-
-#ifdef HAVE_QUOTA_SUPPORT
- if (mds->mds_quota) {
- if (!(ma->ma_attr_flags & MDS_QUOTA_IGNORE)) {
- struct lu_attr *la_tmp = &mdd_env_info(env)->mti_la;
-
- rc = mdd_la_get(env, mdd_obj, la_tmp, BYPASS_CAPA);
- if (!rc) {
- void *data = NULL;
- mdd_data_get(env, mdd_obj, &data);
- quota_opc = FSFILT_OP_LINK;
- mdd_quota_wrapper(la_tmp, qids);
- /* get block quota for parent */
- lquota_chkquota(mds_quota_interface_ref, obd,
- exp, qids, rec_pending, 1, NULL,
- LQUOTA_FLAGS_BLK, data, 1);
- }
- } else {
- uc->mu_cap |= CFS_CAP_SYS_RESOURCE_MASK;
- }
- }
-#endif
- handle = mdd_trans_create(env, mdo2mdd(pobj));
- if (IS_ERR(handle))
- GOTO(out_pending, rc = PTR_ERR(handle));
-
- rc = mdd_trans_start(env, mdo2mdd(pobj), handle);
-
- dlh = mdd_pdo_write_lock(env, mdd_obj, name, MOR_TGT_PARENT);
- if (dlh == NULL)
- GOTO(out_trans, rc = -ENOMEM);
-
- rc = mdd_ni_sanity_check(env, pobj, ma);
- if (rc)
- GOTO(out_unlock, rc);
-
- rc = __mdd_index_insert(env, mdd_obj, fid, name, is_dir,
- handle, BYPASS_CAPA);
- if (rc)
- GOTO(out_unlock, rc);
-
- /*
- * For some case, no need update obj's ctime (LA_CTIME is not set),
- * e.g. split_dir.
- * For other cases, update obj's ctime (LA_CTIME is set),
- * e.g. cmr_link.
- */
- if (ma->ma_attr.la_valid & LA_CTIME) {
- la->la_ctime = la->la_mtime = ma->ma_attr.la_ctime;
- la->la_valid = LA_CTIME | LA_MTIME;
- rc = mdd_attr_check_set_internal_locked(env, mdd_obj, la,
- handle, 0);
- }
- EXIT;
-out_unlock:
- mdd_pdo_write_unlock(env, mdd_obj, dlh);
-out_trans:
- mdd_trans_stop(env, mdo2mdd(pobj), rc, handle);
-out_pending:
-#ifdef HAVE_QUOTA_SUPPORT
- if (mds->mds_quota) {
- if (quota_opc) {
- lquota_pending_commit(mds_quota_interface_ref,
- obd, qids, rec_pending, 1);
- /* Trigger dqacq for the parent owner. If failed,
- * the next call for lquota_chkquota will process it*/
- lquota_adjust(mds_quota_interface_ref, obd, 0, qids,
- rc, quota_opc);
- } else {
- uc->mu_cap = save;
- }
- }
-#endif
- return rc;
-}
-
-/* has not lock on pobj yet */
-static int mdd_nr_sanity_check(const struct lu_env *env,
- struct md_object *pobj,
- const struct md_attr *ma)
-{
- struct mdd_object *obj = md2mdd_obj(pobj);
- int rc;
- ENTRY;
-
- if (ma->ma_attr_flags & MDS_PERM_BYPASS)
- RETURN(0);
-
- rc = mdd_may_unlink(env, obj, ma);
-
- RETURN(rc);
-}
-
-/*
- * Partial operation.
- */
-static int mdd_name_remove(const struct lu_env *env,
- struct md_object *pobj,
- const struct lu_name *lname,
- const struct md_attr *ma)
-{
- const char *name = lname->ln_name;
- struct lu_attr *la = &mdd_env_info(env)->mti_la_for_fix;
- struct mdd_object *mdd_obj = md2mdd_obj(pobj);
- struct mdd_device *mdd = mdo2mdd(pobj);
- struct dynlock_handle *dlh;
- struct thandle *handle;
- int is_dir = S_ISDIR(ma->ma_attr.la_mode);
-#ifdef HAVE_QUOTA_SUPPORT
- struct obd_device *obd = mdd->mdd_obd_dev;
- struct mds_obd *mds = &obd->u.mds;
- unsigned int qids[MAXQUOTAS] = { 0, 0 };
- int quota_opc = 0;
-#endif
- int rc;
- ENTRY;
-
- /* XXX: this code won't be used ever:
- * DNE uses slightly different approach */
- LBUG();
-
-#ifdef HAVE_QUOTA_SUPPORT
- if (mds->mds_quota) {
- struct lu_attr *la_tmp = &mdd_env_info(env)->mti_la;
-
- rc = mdd_la_get(env, mdd_obj, la_tmp, BYPASS_CAPA);
- if (!rc) {
- quota_opc = FSFILT_OP_UNLINK_PARTIAL_PARENT;
- mdd_quota_wrapper(la_tmp, qids);
- }
- }
-#endif
- handle = mdd_trans_create(env, mdd);
- if (IS_ERR(handle))
- GOTO(out_pending, rc = PTR_ERR(handle));
-
- rc = mdd_trans_start(env, mdd, handle);
-
- dlh = mdd_pdo_write_lock(env, mdd_obj, name, MOR_TGT_PARENT);
- if (dlh == NULL)
- GOTO(out_trans, rc = -ENOMEM);
-
- rc = mdd_nr_sanity_check(env, pobj, ma);
- if (rc)
- GOTO(out_unlock, rc);
-
- rc = __mdd_index_delete(env, mdd_obj, name, is_dir,
- handle, BYPASS_CAPA);
- if (rc)
- GOTO(out_unlock, rc);
-
- /*
- * For some case, no need update obj's ctime (LA_CTIME is not set),
- * e.g. split_dir.
- * For other cases, update obj's ctime (LA_CTIME is set),
- * e.g. cmr_unlink.
- */
- if (ma->ma_attr.la_valid & LA_CTIME) {
- la->la_ctime = la->la_mtime = ma->ma_attr.la_ctime;
- la->la_valid = LA_CTIME | LA_MTIME;
- rc = mdd_attr_check_set_internal_locked(env, mdd_obj, la,
- handle, 0);
- }
- EXIT;
-out_unlock:
- mdd_pdo_write_unlock(env, mdd_obj, dlh);
-out_trans:
- mdd_trans_stop(env, mdd, rc, handle);
-out_pending:
-#ifdef HAVE_QUOTA_SUPPORT
- /* Trigger dqrel for the parent owner.
- * If failed, the next call for lquota_chkquota will process it. */
- if (quota_opc)
- lquota_adjust(mds_quota_interface_ref, obd, 0, qids, rc,
- quota_opc);
-#endif
- return rc;
-}
-
-/*
- * tobj maybe NULL
- * has mdd_write_lock on tobj alreay, but not on tgt_pobj yet
- */
-static int mdd_rt_sanity_check(const struct lu_env *env,
- struct mdd_object *tgt_pobj,
- struct mdd_object *tobj,
- struct md_attr *ma)
-{
- int rc;
- ENTRY;
-
- if (unlikely(ma->ma_attr_flags & MDS_PERM_BYPASS))
- RETURN(0);
-
- /* XXX: for mdd_rename_tgt, "tobj == NULL" does not mean tobj not
- * exist. In fact, tobj must exist, otherwise the call trace will be:
- * mdt_reint_rename_tgt -> mdo_name_insert -> ... -> mdd_name_insert.
- * When get here, tobj must be NOT NULL, the other case has been
- * processed in cmr_rename_tgt before mdd_rename_tgt and enable
- * MDS_PERM_BYPASS.
- * So check may_delete, but not check nlink of tgt_pobj. */
-
- rc = mdd_may_delete(env, tgt_pobj, tobj, ma, 1, 1);
-
- RETURN(rc);
-}
-
-/* Partial rename op on slave MDD */
-static int mdd_rename_tgt(const struct lu_env *env,
- struct md_object *pobj, struct md_object *tobj,
- const struct lu_fid *lf, const struct lu_name *lname,
- struct md_attr *ma)
-{
- const char *name = lname->ln_name;
- struct lu_attr *la = &mdd_env_info(env)->mti_la_for_fix;
- struct mdd_object *mdd_tpobj = md2mdd_obj(pobj);
- struct mdd_object *mdd_tobj = md2mdd_obj(tobj);
- struct mdd_device *mdd = mdo2mdd(pobj);
- struct dynlock_handle *dlh;
- struct thandle *handle;
-#ifdef HAVE_QUOTA_SUPPORT
- struct obd_device *obd = mdd->mdd_obd_dev;
- struct obd_export *exp = md_quota(env)->mq_exp;
- struct mds_obd *mds = &obd->u.mds;
- unsigned int qcids[MAXQUOTAS] = { 0, 0 };
- unsigned int qpids[MAXQUOTAS] = { 0, 0 };
- int quota_copc = 0, quota_popc = 0;
- int rec_pending[MAXQUOTAS] = { 0, 0 };
-#endif
- int cl_flags = 0;
- int rc;
- ENTRY;
-
- /* XXX: this code won't be used ever:
- * DNE uses slightly different approach */
- LBUG();
-
-#ifdef HAVE_QUOTA_SUPPORT
- if (mds->mds_quota && !tobj) {
- struct lu_attr *la_tmp = &mdd_env_info(env)->mti_la;
-
- rc = mdd_la_get(env, mdd_tpobj, la_tmp, BYPASS_CAPA);
- if (!rc) {
- void *data = NULL;
- mdd_data_get(env, mdd_tpobj, &data);
- quota_popc = FSFILT_OP_LINK;
- mdd_quota_wrapper(la_tmp, qpids);
- /* get block quota for target parent */
- lquota_chkquota(mds_quota_interface_ref, obd, exp,
- qpids, rec_pending, 1, NULL,
- LQUOTA_FLAGS_BLK, data, 1);
- }
- }
-#endif
- handle = mdd_trans_create(env, mdd);
- if (IS_ERR(handle))
- GOTO(out_pending, rc = PTR_ERR(handle));
-
- rc = mdd_trans_start(env, mdd, handle);
-
- dlh = mdd_pdo_write_lock(env, mdd_tpobj, name, MOR_TGT_PARENT);
- if (dlh == NULL)
- GOTO(out_trans, rc = -ENOMEM);
- if (tobj)
- mdd_write_lock(env, mdd_tobj, MOR_TGT_CHILD);
-
- rc = mdd_rt_sanity_check(env, mdd_tpobj, mdd_tobj, ma);
- if (rc)
- GOTO(cleanup, rc);
-
- /*
- * If rename_tgt is called then we should just re-insert name with
- * correct fid, no need to dec/inc parent nlink if obj is dir.
- */
- rc = __mdd_index_delete(env, mdd_tpobj, name, 0, handle, BYPASS_CAPA);
- if (rc)
- GOTO(cleanup, rc);
-
- rc = __mdd_index_insert_only(env, mdd_tpobj, lf, name, handle,
- BYPASS_CAPA);
- if (rc)
- GOTO(cleanup, rc);
-
- LASSERT(ma->ma_attr.la_valid & LA_CTIME);
- la->la_ctime = la->la_mtime = ma->ma_attr.la_ctime;
-
- la->la_valid = LA_CTIME | LA_MTIME;
- rc = mdd_attr_check_set_internal_locked(env, mdd_tpobj, la, handle, 0);
- if (rc)
- GOTO(cleanup, rc);
-
- /*
- * For tobj is remote case cmm layer has processed
- * and pass NULL tobj to here. So when tobj is NOT NULL,
- * it must be local one.
- */
- if (tobj && mdd_object_exists(mdd_tobj)) {
- mdo_ref_del(env, mdd_tobj, handle);
-
- /* Remove dot reference. */
- if (S_ISDIR(ma->ma_attr.la_mode))
- mdo_ref_del(env, mdd_tobj, handle);
-
- la->la_valid = LA_CTIME;
- rc = mdd_attr_check_set_internal(env, mdd_tobj, la, handle, 0);
- if (rc)
- GOTO(cleanup, rc);
-
- rc = mdd_finish_unlink(env, mdd_tobj, ma, handle);
- if (rc)
- GOTO(cleanup, rc);
-
- if (ma->ma_valid & MA_INODE && ma->ma_attr.la_nlink == 0) {
- cl_flags |= CLF_RENAME_LAST;
-#ifdef HAVE_QUOTA_SUPPORT
- if (mds->mds_quota && mdd_tobj->mod_count == 0) {
- quota_copc = FSFILT_OP_UNLINK_PARTIAL_CHILD;
- mdd_quota_wrapper(&ma->ma_attr, qcids);
- }
-#endif
- }
- }
- EXIT;
-cleanup:
- if (tobj)
- mdd_write_unlock(env, mdd_tobj);
- mdd_pdo_write_unlock(env, mdd_tpobj, dlh);
-out_trans:
- if (rc == 0)
- /* Bare EXT record with no RENAME in front of it signifies
- a partial slave op */
- rc = mdd_changelog_ns_store(env, mdd, CL_EXT, cl_flags,
- mdd_tobj, mdd_tpobj, lname, handle);
-
- mdd_trans_stop(env, mdd, rc, handle);
-out_pending:
-#ifdef HAVE_QUOTA_SUPPORT
- if (mds->mds_quota) {
- if (quota_popc)
- lquota_pending_commit(mds_quota_interface_ref, obd,
- qpids, rec_pending, 1);
-
- if (quota_copc)
- /* Trigger dqrel on the target owner of child.
- * If failed, the next call for lquota_chkquota
- * will process it. */
- lquota_adjust(mds_quota_interface_ref, obd, qcids, qpids,
- rc, quota_copc);
- }
-#endif
- return rc;
-}
-
/*
* The permission has been checked when obj created, no need check again.
*/
.mdo_rename = mdd_rename,
.mdo_link = mdd_link,
.mdo_unlink = mdd_unlink,
- .mdo_lum_lmm_cmp = mdd_lum_lmm_cmp,
- .mdo_name_insert = mdd_name_insert,
- .mdo_name_remove = mdd_name_remove,
- .mdo_rename_tgt = mdd_rename_tgt,
.mdo_create_data = mdd_create_data,
};