/* * Allocate and initialize a qsd_qtype_info structure for quota type \qtype. * This opens the accounting object and initializes the proc file. * It's called on OSD start when the qsd_prepare() is invoked on the qsd * instance. * * \param env - the environment passed by the caller * \param qsd - is the qsd instance which will be in charge of the new * qsd_qtype_info instance. * \param qtype - is quota type to set up * * \retval - 0 on success and qsd->qsd_type_array[qtype] is allocated, * appropriate error on failure */ static int qsd_qtype_init(const struct lu_env *env, struct qsd_instance *qsd, int qtype) { struct qsd_qtype_info *qqi; int rc; struct obd_uuid uuid; ENTRY; LASSERT(qsd->qsd_type_array[qtype] == NULL); /* allocate structure for this quota type */ OBD_ALLOC_PTR(qqi); if (qqi == NULL) RETURN(-ENOMEM); qsd->qsd_type_array[qtype] = qqi; atomic_set(&qqi->qqi_ref, 1); /* referenced from qsd */ /* set backpointer and other parameters */ qqi->qqi_qsd = qsd; qqi->qqi_qtype = qtype; lu_ref_init(&qqi->qqi_reference); lquota_generate_fid(&qqi->qqi_fid, qsd->qsd_pool_id, QSD_RES_TYPE(qsd), qtype); qqi->qqi_glb_uptodate = false; qqi->qqi_slv_uptodate = false; qqi->qqi_reint = false; init_waitqueue_head(&qqi->qqi_reint_thread.t_ctl_waitq); thread_set_flags(&qqi->qqi_reint_thread, SVC_STOPPED); CFS_INIT_LIST_HEAD(&qqi->qqi_deferred_glb); CFS_INIT_LIST_HEAD(&qqi->qqi_deferred_slv); /* open accounting object */ LASSERT(qqi->qqi_acct_obj == NULL); qqi->qqi_acct_obj = acct_obj_lookup(env, qsd->qsd_dev, qtype); if (IS_ERR(qqi->qqi_acct_obj)) { CDEBUG(D_QUOTA, "%s: no %s space accounting support rc:%ld\n", qsd->qsd_svname, QTYPE_NAME(qtype), PTR_ERR(qqi->qqi_acct_obj)); qqi->qqi_acct_obj = NULL; qsd->qsd_acct_failed = true; } /* open global index copy */ LASSERT(qqi->qqi_glb_obj == NULL); qqi->qqi_glb_obj = lquota_disk_glb_find_create(env, qsd->qsd_dev, qsd->qsd_root, &qqi->qqi_fid, true); if (IS_ERR(qqi->qqi_glb_obj)) { CERROR("%s: can't open global index copy "DFID" %ld\n", qsd->qsd_svname, PFID(&qqi->qqi_fid), PTR_ERR(qqi->qqi_glb_obj)); GOTO(out, rc = PTR_ERR(qqi->qqi_glb_obj)); } qqi->qqi_glb_ver = dt_version_get(env, qqi->qqi_glb_obj); /* open slave index copy */ LASSERT(qqi->qqi_slv_obj == NULL); obd_str2uuid(&uuid, qsd->qsd_svname); qqi->qqi_slv_obj = lquota_disk_slv_find_create(env, qsd->qsd_dev, qsd->qsd_root, &qqi->qqi_fid, &uuid, true); if (IS_ERR(qqi->qqi_slv_obj)) { CERROR("%s: can't open slave index copy "DFID" %ld\n", qsd->qsd_svname, PFID(&qqi->qqi_fid), PTR_ERR(qqi->qqi_slv_obj)); GOTO(out, rc = PTR_ERR(qqi->qqi_slv_obj)); } qqi->qqi_slv_ver = dt_version_get(env, qqi->qqi_slv_obj); /* allocate site */ qqi->qqi_site = lquota_site_alloc(env, qqi, false, qtype, &qsd_lqe_ops); if (IS_ERR(qqi->qqi_site)) { CERROR("%s: can't allocate site "DFID" %ld\n", qsd->qsd_svname, PFID(&qqi->qqi_fid), PTR_ERR(qqi->qqi_site)); GOTO(out, rc = PTR_ERR(qqi->qqi_site)); } /* register proc entry for accounting & global index copy objects */ rc = lprocfs_seq_create(qsd->qsd_proc, qtype == USRQUOTA ? "acct_user" : "acct_group", 0444, &lprocfs_quota_seq_fops, qqi->qqi_acct_obj); if (rc) { CERROR("%s: can't add procfs entry for accounting file %d\n", qsd->qsd_svname, rc); GOTO(out, rc); } rc = lprocfs_seq_create(qsd->qsd_proc, qtype == USRQUOTA ? "limit_user" : "limit_group", 0444, &lprocfs_quota_seq_fops, qqi->qqi_glb_obj); if (rc) { CERROR("%s: can't add procfs entry for global index copy %d\n", qsd->qsd_svname, rc); GOTO(out, rc); } EXIT; out: if (rc) qsd_qtype_fini(env, qsd, qtype); 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 < 0 || oqctl->qc_type >= LL_MAXQUOTAS) 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; dt_object_put(env, obj); /* 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: dt_object_put(env, obj); return rc; }