int lfsck_bookmark_setup(const struct lu_env *env, struct lfsck_instance *lfsck) { struct dt_object *root; struct dt_object *obj; int rc; ENTRY; root = dt_locate(env, lfsck->li_bottom, &lfsck->li_local_root_fid); if (IS_ERR(root)) RETURN(PTR_ERR(root)); if (unlikely(!dt_try_as_dir(env, root))) { lu_object_put(env, &root->do_lu); RETURN(-ENOTDIR); } obj = local_file_find_or_create(env, lfsck->li_los, root, lfsck_bookmark_name, S_IFREG | S_IRUGO | S_IWUSR); lu_object_put(env, &root->do_lu); if (IS_ERR(obj)) RETURN(PTR_ERR(obj)); lfsck->li_bookmark_obj = obj; rc = lfsck_bookmark_load(env, lfsck); if (rc == -ENODATA) rc = lfsck_bookmark_init(env, lfsck); RETURN(rc); }
/** * Find the osd object for given fid. * * \param fid need to find the osd object having this fid * * \retval osd_object on success * \retval -ve on error */ struct osd_object *osd_object_find(const struct lu_env *env, struct dt_object *dt, const struct lu_fid *fid) { struct lu_device *ludev = dt->do_lu.lo_dev; struct osd_object *child = NULL; struct lu_object *luch; struct lu_object *lo; /* * at this point topdev might not exist yet * (i.e. MGS is preparing profiles). so we can * not rely on topdev and instead lookup with * our device passed as topdev. this can't work * if the object isn't cached yet (as osd doesn't * allocate lu_header). IOW, the object must be * in the cache, otherwise lu_object_alloc() crashes * -bzzz */ luch = lu_object_find_at(env, ludev, fid, NULL); if (IS_ERR(luch)) return (void *)luch; if (lu_object_exists(luch)) { lo = lu_object_locate(luch->lo_header, ludev->ld_type); if (lo != NULL) child = osd_obj(lo); else LU_OBJECT_DEBUG(D_ERROR, env, luch, "%s: object can't be located "DFID"\n", osd_dev(ludev)->od_svname, PFID(fid)); if (child == NULL) { lu_object_put(env, luch); CERROR("%s: Unable to get osd_object "DFID"\n", osd_dev(ludev)->od_svname, PFID(fid)); child = ERR_PTR(-ENOENT); } } else { LU_OBJECT_DEBUG(D_ERROR, env, luch, "%s: lu_object does not exists "DFID"\n", osd_dev(ludev)->od_svname, PFID(fid)); lu_object_put(env, luch); child = ERR_PTR(-ENOENT); } return child; }
int mdd_local_file_create(const struct lu_env *env, struct mdd_device *mdd, const struct lu_fid *pfid, const char *name, __u32 mode, struct lu_fid *fid) { struct dt_object *parent, *dto; int rc; ENTRY; LASSERT(!fid_is_zero(pfid)); parent = dt_locate(env, mdd->mdd_bottom, pfid); if (unlikely(IS_ERR(parent))) RETURN(PTR_ERR(parent)); /* create local file/dir, if @fid is passed then try to use it */ if (fid_is_zero(fid)) dto = local_file_find_or_create(env, mdd->mdd_los, parent, name, mode); else dto = local_file_find_or_create_with_fid(env, mdd->mdd_bottom, fid, parent, name, mode); if (IS_ERR(dto)) GOTO(out_put, rc = PTR_ERR(dto)); *fid = *lu_object_fid(&dto->do_lu); /* since stack is not fully set up the local_storage uses own stack * and we should drop its object from cache */ lu_object_put_nocache(env, &dto->do_lu); EXIT; out_put: lu_object_put(env, &parent->do_lu); return 0; }
/** * open the PENDING directory for device \a mdd * * The PENDING directory persistently tracks files and directories that were * unlinked from the namespace (nlink == 0) but are still held open by clients. * Those inodes shouldn't be deleted if the MDS crashes, because the clients * would not be able to recover and reopen those files. Instead, these inodes * are linked into the PENDING directory on disk, and only deleted if all * clients close them, or the MDS finishes client recovery without any client * reopening them (i.e. former clients didn't join recovery). * \param d mdd device being started. * * \retval 0 success * \retval -ve index operation error. * */ int orph_index_init(const struct lu_env *env, struct mdd_device *mdd) { struct lu_fid fid; struct dt_object *d; int rc = 0; ENTRY; /* create PENDING dir */ fid_zero(&fid); rc = mdd_local_file_create(env, mdd, &mdd->mdd_local_root_fid, orph_index_name, S_IFDIR | S_IRUGO | S_IWUSR | S_IXUGO, &fid); if (rc < 0) RETURN(rc); d = dt_locate(env, mdd->mdd_child, &fid); if (IS_ERR(d)) RETURN(PTR_ERR(d)); LASSERT(lu_object_exists(&d->do_lu)); if (!dt_try_as_dir(env, d)) { CERROR("%s: \"%s\" is not an index: rc = %d\n", mdd2obd_dev(mdd)->obd_name, orph_index_name, rc); lu_object_put(env, &d->do_lu); RETURN(-ENOTDIR); } mdd->mdd_orphans = d; RETURN(0); }
/* * Called when the MDS is fully configured. We use it to set up local objects * associated with the quota master target. * * \param env - is the environment passed by the caller * \param parent - is the lu_device of the parent, that's to say the mdt * \param ld - is the lu_device associated with the master target * * \retval - 0 on success, appropriate error on failure */ static int qmt_device_prepare(const struct lu_env *env, struct lu_device *parent, struct lu_device *ld) { struct qmt_device *qmt = lu2qmt_dev(ld); struct dt_object *qmt_root; int rc; ENTRY; /* initialize quota master root directory where all index files will be * stored */ qmt_root = lquota_disk_dir_find_create(env, qmt->qmt_child, NULL, QMT_DIR); if (IS_ERR(qmt_root)) { rc = PTR_ERR(qmt_root); CERROR("%s: failed to create master quota directory (%d)\n", qmt->qmt_svname, rc); RETURN(rc); } /* initialize on-disk indexes associated with each pool */ rc = qmt_pool_prepare(env, qmt, qmt_root); lu_object_put(env, &qmt_root->do_lu); RETURN(rc); }
/** * This is helper function to get llog directory object. It is used by named * llog operations to find/insert/delete llog entry from llog directory. * * \param[in] env execution environment * \param[in] ctxt llog context * * \retval dt_object of llog directory * \retval ERR_PTR of negative value on error */ struct dt_object *llog_osd_dir_get(const struct lu_env *env, struct llog_ctxt *ctxt) { struct dt_device *dt; struct dt_thread_info *dti = dt_info(env); struct dt_object *dir; int rc; dt = ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt; if (ctxt->loc_dir == NULL) { rc = dt_root_get(env, dt, &dti->dti_fid); if (rc) return ERR_PTR(rc); dir = dt_locate(env, dt, &dti->dti_fid); if (!IS_ERR(dir) && !dt_try_as_dir(env, dir)) { lu_object_put(env, &dir->do_lu); return ERR_PTR(-ENOTDIR); } } else { lu_object_get(&ctxt->loc_dir->do_lu); dir = ctxt->loc_dir; } return dir; }
static int out_trans_stop(const struct lu_env *env, struct thandle_exec_args *ta, int err) { int i; int rc; ta->ta_handle->th_result = err; rc = dt_trans_stop(env, ta->ta_handle->th_dev, ta->ta_handle); for (i = 0; i < ta->ta_argno; i++) { if (ta->ta_args[i]->object != NULL) { struct dt_object *obj = ta->ta_args[i]->object; /* If the object is being created during this * transaction, we need to remove them from the * cache immediately, because a few layers are * missing in OUT handler, i.e. the object might * not be initialized in all layers */ if (ta->ta_args[i]->exec_fn == out_tx_create_exec) set_bit(LU_OBJECT_HEARD_BANSHEE, &obj->do_lu.lo_header->loh_flags); lu_object_put(env, &ta->ta_args[i]->object->do_lu); ta->ta_args[i]->object = NULL; } } ta->ta_handle = NULL; ta->ta_argno = 0; 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); }
/** * Free given iterator. * * \param di - osd iterator */ static void osd_it_acct_fini(const struct lu_env *env, struct dt_it *di) { struct osd_it_quota *it = (struct osd_it_quota *)di; ENTRY; udmu_zap_cursor_fini(it->oiq_zc); lu_object_put(env, &it->oiq_obj->oo_dt.do_lu); EXIT; }
void orph_index_fini(const struct lu_env *env, struct mdd_device *mdd) { ENTRY; if (mdd->mdd_orphans != NULL) { lu_object_put(env, &mdd->mdd_orphans->do_lu); mdd->mdd_orphans = NULL; } EXIT; }
void fld_index_fini(const struct lu_env *env, struct lu_server_fld *fld) { ENTRY; if (fld->lsf_obj != NULL) { if (!IS_ERR(fld->lsf_obj)) lu_object_put(env, &fld->lsf_obj->do_lu); fld->lsf_obj = NULL; } EXIT; }
/** * Implementation of the llog_operations::lop_create * * This function creates the llog according with llog_handle::lgh_obj * and llog_handle::lgh_name. * * \param[in] env execution environment * \param[in] res llog handle of the current llog * \param[in] th current transaction handle * * \retval 0 on successful create * \retval negative value on error */ static int llog_osd_create(const struct lu_env *env, struct llog_handle *res, struct thandle *th) { struct llog_thread_info *lgi = llog_info(env); struct dt_insert_rec *rec = &lgi->lgi_dt_rec; struct local_oid_storage *los; struct dt_object *o; int rc = 0; ENTRY; LASSERT(env); o = res->lgh_obj; LASSERT(o); /* llog can be already created */ if (dt_object_exists(o)) RETURN(-EEXIST); los = res->private_data; LASSERT(los); dt_write_lock(env, o, 0); if (!dt_object_exists(o)) rc = llog_osd_create_new_object(env, los, o, th); else rc = -EEXIST; dt_write_unlock(env, o); if (rc) RETURN(rc); if (res->lgh_name) { struct dt_object *llog_dir; llog_dir = llog_osd_dir_get(env, res->lgh_ctxt); if (IS_ERR(llog_dir)) RETURN(PTR_ERR(llog_dir)); logid_to_fid(&res->lgh_id, &lgi->lgi_fid); rec->rec_fid = &lgi->lgi_fid; rec->rec_type = S_IFREG; dt_read_lock(env, llog_dir, 0); rc = dt_insert(env, llog_dir, (struct dt_rec *)rec, (struct dt_key *)res->lgh_name, th, BYPASS_CAPA, 1); dt_read_unlock(env, llog_dir); lu_object_put(env, &llog_dir->do_lu); if (rc) CERROR("%s: can't create named llog %s: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, res->lgh_name, rc); } RETURN(rc); }
void seq_store_fini(struct lu_server_seq *seq, const struct lu_env *env) { ENTRY; if (seq->lss_obj != NULL) { if (!IS_ERR(seq->lss_obj)) lu_object_put(env, &seq->lss_obj->do_lu); seq->lss_obj = NULL; } EXIT; }
/** * Initialize slave index object to collect local quota limit for user or group. * * \param env - is the environment passed by the caller * \param dev - is the dt_device storing the slave index object * \param type - is the quota type, either USRQUOTA or GRPQUOTA */ static struct dt_object *quota_obj_lookup(const struct lu_env *env, struct dt_device *dev, int type) { struct lquota_thread_info *qti = lquota_info(env); struct dt_object *obj = NULL; ENTRY; qti->qti_fid.f_seq = FID_SEQ_QUOTA; qti->qti_fid.f_oid = type == USRQUOTA ? LQUOTA_USR_OID : LQUOTA_GRP_OID; qti->qti_fid.f_ver = 0; /* lookup the quota object */ obj = dt_locate(env, dev, &qti->qti_fid); if (IS_ERR(obj)) RETURN(obj); if (!dt_object_exists(obj)) { lu_object_put(env, &obj->do_lu); RETURN(ERR_PTR(-ENOENT)); } if (obj->do_index_ops == NULL) { int rc; /* set up indexing operations */ rc = obj->do_ops->do_index_try(env, obj, &dt_quota_slv_features); if (rc) { CERROR("%s: failed to set up indexing operations for %s" " slave index object rc:%d\n", dev->dd_lu_dev.ld_obd->obd_name, QTYPE_NAME(type), rc); lu_object_put(env, &obj->do_lu); RETURN(ERR_PTR(rc)); } } RETURN(obj); }
/** * Implementation of the llog_operations::lop_declare_create * * This function declares the llog create. It declares also name insert * into llog directory in case of named llog. * * \param[in] env execution environment * \param[in] res llog handle of the current llog * \param[in] th current transaction handle * * \retval 0 on successful create declaration * \retval negative value on error */ static int llog_osd_declare_create(const struct lu_env *env, struct llog_handle *res, struct thandle *th) { struct llog_thread_info *lgi = llog_info(env); struct dt_insert_rec *rec = &lgi->lgi_dt_rec; struct local_oid_storage *los; struct dt_object *o; int rc; ENTRY; LASSERT(res->lgh_obj); LASSERT(th); /* object can be created by another thread */ o = res->lgh_obj; if (dt_object_exists(o)) RETURN(0); los = res->private_data; LASSERT(los); rc = llog_osd_declare_new_object(env, los, o, th); if (rc) RETURN(rc); /* do not declare header initialization here as it's declared * in llog_osd_declare_write_rec() which is always called */ if (res->lgh_name) { struct dt_object *llog_dir; llog_dir = llog_osd_dir_get(env, res->lgh_ctxt); if (IS_ERR(llog_dir)) RETURN(PTR_ERR(llog_dir)); logid_to_fid(&res->lgh_id, &lgi->lgi_fid); rec->rec_fid = &lgi->lgi_fid; rec->rec_type = S_IFREG; rc = dt_declare_insert(env, llog_dir, (struct dt_rec *)rec, (struct dt_key *)res->lgh_name, th); lu_object_put(env, &llog_dir->do_lu); if (rc) CERROR("%s: can't declare named llog %s: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, res->lgh_name, rc); } RETURN(rc); }
/** * Look-up accounting object to collect space usage information for user * or group. * * \param env - is the environment passed by the caller * \param dev - is the dt_device storing the accounting object * \param type - is the quota type, either USRQUOTA or GRPQUOTA */ struct dt_object *acct_obj_lookup(const struct lu_env *env, struct dt_device *dev, int type) { struct lquota_thread_info *qti = lquota_info(env); struct dt_object *obj = NULL; ENTRY; lu_local_obj_fid(&qti->qti_fid, type == USRQUOTA ? ACCT_USER_OID : ACCT_GROUP_OID); /* lookup the accounting object */ obj = dt_locate(env, dev, &qti->qti_fid); if (IS_ERR(obj)) RETURN(obj); if (!dt_object_exists(obj)) { lu_object_put(env, &obj->do_lu); RETURN(ERR_PTR(-ENOENT)); } if (obj->do_index_ops == NULL) { int rc; /* set up indexing operations */ rc = obj->do_ops->do_index_try(env, obj, &dt_acct_features); if (rc) { CERROR("%s: failed to set up indexing operations for %s" " acct object rc:%d\n", dev->dd_lu_dev.ld_obd->obd_name, QTYPE_NAME(type), rc); lu_object_put(env, &obj->do_lu); RETURN(ERR_PTR(rc)); } } RETURN(obj); }
/** * Free given iterator. * * \param di - osd iterator */ static void osd_it_acct_fini(const struct lu_env *env, struct dt_it *di) { struct osd_thread_info *info = osd_oti_get(env); struct osd_it_quota *it = (struct osd_it_quota *)di; ENTRY; osd_zap_cursor_fini(it->oiq_zc); lu_object_put(env, &it->oiq_obj->oo_dt.do_lu); if (it != &info->oti_it_quota) OBD_FREE_PTR(it); else info->oti_it_inline = 0; EXIT; }
static int llog_osd_declare_create(const struct lu_env *env, struct llog_handle *res, struct thandle *th) { struct llog_thread_info *lgi = llog_info(env); struct local_oid_storage *los; struct dt_object *o; int rc; ENTRY; LASSERT(res->lgh_obj); LASSERT(th); /* object can be created by another thread */ o = res->lgh_obj; if (dt_object_exists(o)) RETURN(0); los = res->private_data; LASSERT(los); rc = llog_osd_declare_new_object(env, los, o, th); if (rc) RETURN(rc); rc = dt_declare_record_write(env, o, LLOG_CHUNK_SIZE, 0, th); if (rc) RETURN(rc); if (res->lgh_name) { struct dt_object *llog_dir; llog_dir = llog_osd_dir_get(env, res->lgh_ctxt); if (IS_ERR(llog_dir)) RETURN(PTR_ERR(llog_dir)); dt_declare_ref_add(env, o, th); logid_to_fid(&res->lgh_id, &lgi->lgi_fid); rc = dt_declare_insert(env, llog_dir, (struct dt_rec *)&lgi->lgi_fid, (struct dt_key *)res->lgh_name, th); lu_object_put(env, &llog_dir->do_lu); if (rc) CERROR("%s: can't declare named llog %s: rc = %d\n", o->do_lu.lo_dev->ld_obd->obd_name, res->lgh_name, rc); } RETURN(rc); }
static void osd_index_it_fini(const struct lu_env *env, struct dt_it *di) { struct osd_zap_it *it = (struct osd_zap_it *)di; struct osd_object *obj; ENTRY; LASSERT(it); LASSERT(it->ozi_obj); obj = it->ozi_obj; udmu_zap_cursor_fini(it->ozi_zc); lu_object_put(env, &obj->oo_dt.do_lu); EXIT; }
/* * Look-up a slave index file. * * \param env - is the environment passed by the caller * \param dev - is the backend dt_device where to look-up/create the slave index * \param parent - is the parent directory where to lookup the slave index * \param glb_fid - is the fid of the global index file associated with this * slave index. * \param uuid - is the uuid of slave which is (re)connecting to the master * target * * \retval - pointer to the dt_object of the slave index on success, * appropriate error on failure */ struct dt_object *lquota_disk_slv_find(const struct lu_env *env, struct dt_device *dev, struct dt_object *parent, const struct lu_fid *glb_fid, struct obd_uuid *uuid) { struct lquota_thread_info *qti = lquota_info(env); struct dt_object *slv_idx; int rc; ENTRY; LASSERT(uuid != NULL); CDEBUG(D_QUOTA, "lookup slave index file for %s\n", obd_uuid2str(uuid)); /* generate filename associated with the slave */ rc = lquota_disk_slv_filename(glb_fid, uuid, qti->qti_buf); if (rc) RETURN(ERR_PTR(rc)); /* lookup slave index file */ rc = dt_lookup_dir(env, parent, qti->qti_buf, &qti->qti_fid); if (rc) RETURN(ERR_PTR(rc)); /* name is found, get the object */ slv_idx = dt_locate(env, dev, &qti->qti_fid); if (IS_ERR(slv_idx)) RETURN(slv_idx); if (slv_idx->do_index_ops == NULL) { rc = slv_idx->do_ops->do_index_try(env, slv_idx, &dt_quota_slv_features); if (rc) { CERROR("%s: failed to setup slave index operations for " "%s, rc:%d\n", dev->dd_lu_dev.ld_obd->obd_name, obd_uuid2str(uuid), rc); lu_object_put(env, &slv_idx->do_lu); slv_idx = ERR_PTR(rc); } } RETURN(slv_idx); }
static int llog_osd_close(const struct lu_env *env, struct llog_handle *handle) { struct local_oid_storage *los; int rc = 0; LASSERT(handle->lgh_obj); lu_object_put(env, &handle->lgh_obj->do_lu); los = handle->private_data; LASSERT(los); dt_los_put(los); if (handle->lgh_name) OBD_FREE(handle->lgh_name, strlen(handle->lgh_name) + 1); return rc; }
static int out_trans_stop(const struct lu_env *env, struct thandle_exec_args *ta, int err) { int i; int rc; ta->ta_handle->th_result = err; LASSERT(ta->ta_handle->th_sync != 0); rc = dt_trans_stop(env, ta->ta_dev, ta->ta_handle); for (i = 0; i < ta->ta_argno; i++) { if (ta->ta_args[i].object != NULL) { lu_object_put(env, &ta->ta_args[i].object->do_lu); ta->ta_args[i].object = NULL; } } return rc; }
static struct dt_object *out_object_find(struct mdt_thread_info *info, struct lu_fid *fid) { struct lu_object *obj; struct dt_object *dt_obj; obj = lu_object_find(info->mti_env, &info->mti_mdt->mdt_md_dev.md_lu_dev, fid, NULL); if (IS_ERR(obj)) return (struct dt_object *)obj; dt_obj = out_get_dt_obj(obj); if (IS_ERR(dt_obj)) { lu_object_put(info->mti_env, obj); return ERR_PTR(-ENOENT); } return dt_obj; }
int fld_index_init(struct lu_server_fld *fld, const struct lu_env *env, struct dt_device *dt) { struct dt_object *dt_obj; struct lu_fid fid; int rc; ENTRY; dt_obj = dt_store_open(env, dt, "", fld_index_name, &fid); if (!IS_ERR(dt_obj)) { fld->lsf_obj = dt_obj; rc = dt_obj->do_ops->do_index_try(env, dt_obj, &fld_index_features); if (rc == 0) { LASSERT(dt_obj->do_index_ops != NULL); rc = fld_insert_igif_fld(fld, env); if (rc != 0) { CERROR("insert igif in fld! = %d\n", rc); lu_object_put(env, &dt_obj->do_lu); fld->lsf_obj = NULL; } } else CERROR("%s: File \"%s\" is not an index!\n", fld->lsf_name, fld_index_name); } else { CERROR("%s: Can't find \"%s\" obj %d\n", fld->lsf_name, fld_index_name, (int)PTR_ERR(dt_obj)); rc = PTR_ERR(dt_obj); } RETURN(rc); }
/* * Release a qsd_instance. Companion of qsd_init(). This releases all data * structures associated with the quota slave (on-disk objects, lquota entry * tables, ...). * This function should be called when the OSD is shutting down. * * \param env - is the environment passed by the caller * \param qsd - is the qsd instance to shutdown */ void qsd_fini(const struct lu_env *env, struct qsd_instance *qsd) { int qtype; ENTRY; if (unlikely(qsd == NULL)) RETURN_EXIT; CDEBUG(D_QUOTA, "%s: initiating QSD shutdown\n", qsd->qsd_svname); write_lock(&qsd->qsd_lock); qsd->qsd_stopping = true; write_unlock(&qsd->qsd_lock); /* remove qsd proc entry */ if (qsd->qsd_proc != NULL) { lprocfs_remove(&qsd->qsd_proc); qsd->qsd_proc = NULL; } /* stop the writeback thread */ qsd_stop_upd_thread(qsd); /* shutdown the reintegration threads */ for (qtype = USRQUOTA; qtype < MAXQUOTAS; qtype++) { if (qsd->qsd_type_array[qtype] == NULL) continue; qsd_stop_reint_thread(qsd->qsd_type_array[qtype]); } if (qsd->qsd_ns != NULL) { qsd->qsd_ns = NULL; } /* free per-quota type data */ for (qtype = USRQUOTA; qtype < MAXQUOTAS; qtype++) qsd_qtype_fini(env, qsd, qtype); /* deregister connection to the quota master */ qsd->qsd_exp_valid = false; lustre_deregister_lwp_item(&qsd->qsd_exp); /* release per-filesystem information */ if (qsd->qsd_fsinfo != NULL) { mutex_lock(&qsd->qsd_fsinfo->qfs_mutex); /* remove from the list of fsinfo */ cfs_list_del_init(&qsd->qsd_link); mutex_unlock(&qsd->qsd_fsinfo->qfs_mutex); qsd_put_fsinfo(qsd->qsd_fsinfo); qsd->qsd_fsinfo = NULL; } /* release quota root directory */ if (qsd->qsd_root != NULL) { lu_object_put(env, &qsd->qsd_root->do_lu); qsd->qsd_root = NULL; } /* release reference on dt_device */ if (qsd->qsd_dev != NULL) { lu_ref_del(&qsd->qsd_dev->dd_lu_dev.ld_reference, "qsd", qsd); lu_device_put(&qsd->qsd_dev->dd_lu_dev); qsd->qsd_dev = NULL; } CDEBUG(D_QUOTA, "%s: QSD shutdown completed\n", qsd->qsd_svname); OBD_FREE_PTR(qsd); EXIT; }
/* * Release qsd_qtype_info structure which contains data associated with a * given quota type. This releases the accounting objects. * It's called on OSD cleanup when the qsd instance is released. * * \param env - is the environment passed by the caller * \param qsd - is the qsd instance managing the qsd_qtype_info structure * to be released * \param qtype - is the quota type to be shutdown */ static void qsd_qtype_fini(const struct lu_env *env, struct qsd_instance *qsd, int qtype) { struct qsd_qtype_info *qqi; int repeat = 0; ENTRY; if (qsd->qsd_type_array[qtype] == NULL) RETURN_EXIT; qqi = qsd->qsd_type_array[qtype]; qsd->qsd_type_array[qtype] = NULL; /* all deferred work lists should be empty */ LASSERT(cfs_list_empty(&qqi->qqi_deferred_glb)); LASSERT(cfs_list_empty(&qqi->qqi_deferred_slv)); /* shutdown lquota site */ if (qqi->qqi_site != NULL && !IS_ERR(qqi->qqi_site)) { lquota_site_free(env, qqi->qqi_site); qqi->qqi_site = NULL; } /* The qqi may still be holding by global locks which are being * canceled asynchronously (LU-4365), see the following steps: * * - On server umount, we try to clear all quota locks first by * disconnecting LWP (which will invalidate import and cleanup * all locks on it), however, if quota reint process is holding * the global lock for reintegration at that time, global lock * will fail to be cleared on LWP disconnection. * * - Umount process goes on and stops reint process, the global * lock will be dropped on reint process exit, however, the lock * cancel in done in asynchronous way, so the * qsd_glb_blocking_ast() might haven't been called yet when we * get here. */ while (atomic_read(&qqi->qqi_ref) > 1) { CDEBUG(D_QUOTA, "qqi reference count %u, repeat: %d\n", atomic_read(&qqi->qqi_ref), repeat); repeat++; schedule_timeout_and_set_state(TASK_INTERRUPTIBLE, cfs_time_seconds(1)); } /* by now, all qqi users should have gone away */ LASSERT(atomic_read(&qqi->qqi_ref) == 1); lu_ref_fini(&qqi->qqi_reference); /* release accounting object */ if (qqi->qqi_acct_obj != NULL && !IS_ERR(qqi->qqi_acct_obj)) { lu_object_put(env, &qqi->qqi_acct_obj->do_lu); qqi->qqi_acct_obj = NULL; } /* release slv index */ if (qqi->qqi_slv_obj != NULL && !IS_ERR(qqi->qqi_slv_obj)) { lu_object_put(env, &qqi->qqi_slv_obj->do_lu); qqi->qqi_slv_obj = NULL; qqi->qqi_slv_ver = 0; } /* release global index */ if (qqi->qqi_glb_obj != NULL && !IS_ERR(qqi->qqi_glb_obj)) { lu_object_put(env, &qqi->qqi_glb_obj->do_lu); qqi->qqi_glb_obj = NULL; qqi->qqi_glb_ver = 0; } OBD_FREE_PTR(qqi); EXIT; }
/** * Implementation of the llog_operations::lop_open * * This function opens the llog by its logid or by name, it may open also * non existent llog and assing then new id to it. * The llog_open/llog_close pair works similar to lu_object_find/put, * the object may not exist prior open. The result of open is just dt_object * in the llog header. * * \param[in] env execution environment * \param[in] handle llog handle of the current llog * \param[in] logid logid of llog to open (nameless llog) * \param[in] name name of llog to open (named llog) * \param[in] open_param * LLOG_OPEN_NEW - new llog, may not exist * LLOG_OPEN_EXIST - old llog, must exist * * \retval 0 on successful open, llog_handle::lgh_obj * contains the dt_object of the llog. * \retval negative value on error */ static int llog_osd_open(const struct lu_env *env, struct llog_handle *handle, struct llog_logid *logid, char *name, enum llog_open_param open_param) { struct llog_thread_info *lgi = llog_info(env); struct llog_ctxt *ctxt = handle->lgh_ctxt; struct dt_object *o; struct dt_device *dt; struct ls_device *ls; struct local_oid_storage *los; int rc = 0; ENTRY; LASSERT(env); LASSERT(ctxt); LASSERT(ctxt->loc_exp); LASSERT(ctxt->loc_exp->exp_obd); dt = ctxt->loc_exp->exp_obd->obd_lvfs_ctxt.dt; LASSERT(dt); ls = ls_device_get(dt); if (IS_ERR(ls)) RETURN(PTR_ERR(ls)); mutex_lock(&ls->ls_los_mutex); los = dt_los_find(ls, name != NULL ? FID_SEQ_LLOG_NAME : FID_SEQ_LLOG); mutex_unlock(&ls->ls_los_mutex); LASSERT(los); ls_device_put(env, ls); LASSERT(handle); if (logid != NULL) { logid_to_fid(logid, &lgi->lgi_fid); } else if (name) { struct dt_object *llog_dir; llog_dir = llog_osd_dir_get(env, ctxt); if (IS_ERR(llog_dir)) GOTO(out, rc = PTR_ERR(llog_dir)); dt_read_lock(env, llog_dir, 0); rc = dt_lookup_dir(env, llog_dir, name, &lgi->lgi_fid); dt_read_unlock(env, llog_dir); lu_object_put(env, &llog_dir->do_lu); if (rc == -ENOENT && open_param == LLOG_OPEN_NEW) { /* generate fid for new llog */ rc = local_object_fid_generate(env, los, &lgi->lgi_fid); } if (rc < 0) GOTO(out, rc); OBD_ALLOC(handle->lgh_name, strlen(name) + 1); if (handle->lgh_name) strcpy(handle->lgh_name, name); else GOTO(out, rc = -ENOMEM); } else { LASSERTF(open_param & LLOG_OPEN_NEW, "%#x\n", open_param); /* generate fid for new llog */ rc = local_object_fid_generate(env, los, &lgi->lgi_fid); if (rc < 0) GOTO(out, rc); } o = ls_locate(env, ls, &lgi->lgi_fid, NULL); if (IS_ERR(o)) GOTO(out_name, rc = PTR_ERR(o)); /* No new llog is expected but doesn't exist */ if (open_param != LLOG_OPEN_NEW && !dt_object_exists(o)) GOTO(out_put, rc = -ENOENT); fid_to_logid(&lgi->lgi_fid, &handle->lgh_id); handle->lgh_obj = o; handle->private_data = los; LASSERT(handle->lgh_ctxt); RETURN(rc); out_put: lu_object_put(env, &o->do_lu); out_name: if (handle->lgh_name != NULL) OBD_FREE(handle->lgh_name, strlen(name) + 1); out: dt_los_put(los); 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); }
/** * 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); }
/* * Helper routine to retrieve slave information. * This function converts a quotactl request into quota/accounting object * operations. It is independant of the slave stack which is only accessible * from the OSD layer. * * \param env - is the environment passed by the caller * \param dev - is the dt_device this quotactl is executed on * \param oqctl - is the quotactl request */ int lquotactl_slv(const struct lu_env *env, struct dt_device *dev, struct obd_quotactl *oqctl) { struct lquota_thread_info *qti = lquota_info(env); __u64 key; struct dt_object *obj; struct obd_dqblk *dqblk = &oqctl->qc_dqblk; int rc; ENTRY; if (oqctl->qc_cmd != Q_GETOQUOTA) { /* as in many other places, dev->dd_lu_dev.ld_obd->obd_name * point to an invalid obd_name, to be fixed in LU-1574 */ CERROR("%s: Unsupported quotactl command: %x\n", dev->dd_lu_dev.ld_obd->obd_name, oqctl->qc_cmd); RETURN(-EOPNOTSUPP); } if (oqctl->qc_type != USRQUOTA && oqctl->qc_type != GRPQUOTA) /* no support for directory quota yet */ RETURN(-EOPNOTSUPP); /* qc_id is a 32-bit field while a key has 64 bits */ key = oqctl->qc_id; /* Step 1: collect accounting information */ obj = acct_obj_lookup(env, dev, oqctl->qc_type); if (IS_ERR(obj)) RETURN(-EOPNOTSUPP); if (obj->do_index_ops == NULL) GOTO(out, rc = -EINVAL); /* lookup record storing space accounting information for this ID */ rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_acct_rec, (struct dt_key *)&key); if (rc < 0) GOTO(out, rc); memset(&oqctl->qc_dqblk, 0, sizeof(struct obd_dqblk)); dqblk->dqb_curspace = qti->qti_acct_rec.bspace; dqblk->dqb_curinodes = qti->qti_acct_rec.ispace; dqblk->dqb_valid = QIF_USAGE; lu_object_put(env, &obj->do_lu); /* Step 2: collect enforcement information */ obj = quota_obj_lookup(env, dev, oqctl->qc_type); if (IS_ERR(obj)) RETURN(0); if (obj->do_index_ops == NULL) GOTO(out, rc = 0); memset(&qti->qti_slv_rec, 0, sizeof(qti->qti_slv_rec)); /* lookup record storing enforcement information for this ID */ rc = dt_lookup(env, obj, (struct dt_rec *)&qti->qti_slv_rec, (struct dt_key *)&key); if (rc < 0 && rc != -ENOENT) GOTO(out, rc = 0); if (lu_device_is_md(dev->dd_lu_dev.ld_site->ls_top_dev)) { dqblk->dqb_ihardlimit = qti->qti_slv_rec.qsr_granted; dqblk->dqb_bhardlimit = 0; } else { dqblk->dqb_ihardlimit = 0; dqblk->dqb_bhardlimit = qti->qti_slv_rec.qsr_granted; } dqblk->dqb_valid |= QIF_LIMITS; GOTO(out, rc = 0); out: lu_object_put(env, &obj->do_lu); return rc; }