+typedef int (*qmt_glimpse_cb_t)(struct ldlm_lock *, struct lquota_entry *);
+
+struct qmt_gl_lock_array {
+ unsigned long q_max;
+ unsigned long q_cnt;
+ struct ldlm_lock **q_locks;
+};
+
+static void qmt_free_lock_array(struct qmt_gl_lock_array *array)
+{
+ int i;
+
+ if (array->q_max == 0) {
+ LASSERT(array->q_locks == NULL);
+ return;
+ }
+
+ for (i = 0; i < array->q_cnt; i++) {
+ LASSERT(array->q_locks[i]);
+ LDLM_LOCK_RELEASE(array->q_locks[i]);
+ array->q_locks[i] = NULL;
+ }
+ array->q_cnt = 0;
+ OBD_FREE_PTR_ARRAY(array->q_locks, array->q_max);
+ array->q_locks = NULL;
+ array->q_max = 0;
+}
+
+static int qmt_alloc_lock_array(struct ldlm_resource *res,
+ struct qmt_gl_lock_array *array,
+ qmt_glimpse_cb_t cb, void *arg)
+{
+ struct lquota_entry *lqe = arg;
+ struct list_head *pos;
+ unsigned long count = 0;
+ int fail_cnt = 0;
+ ENTRY;
+
+ LASSERT(!array->q_max && !array->q_cnt && !array->q_locks);
+again:
+ if (cb)
+ mutex_lock(&lqe->lqe_glbl_data_lock);
+ lock_res(res);
+ /* scan list of granted locks */
+ list_for_each(pos, &res->lr_granted) {
+ struct ldlm_lock *lock;
+ int rc;
+
+ lock = list_entry(pos, struct ldlm_lock, l_res_link);
+ LASSERT(lock->l_export);
+
+ if (cb != NULL) {
+ rc = cb(lock, arg);
+ /* slave should not be notified */
+ if (rc == 0)
+ continue;
+ }
+
+ count++;
+ if (array->q_max != 0 && array->q_cnt < array->q_max) {
+ array->q_locks[array->q_cnt] = LDLM_LOCK_GET(lock);
+ array->q_cnt++;
+ }
+ }
+ unlock_res(res);
+ if (cb)
+ mutex_unlock(&lqe->lqe_glbl_data_lock);
+
+ if (count > array->q_max) {
+ qmt_free_lock_array(array);
+ if (++fail_cnt > 5)
+ RETURN(-EAGAIN);
+ /*
+ * allocate more slots in case of more qualified locks are
+ * found during next loop
+ */
+ array->q_max = count + count / 2 + 10;
+ count = 0;
+ LASSERT(array->q_locks == NULL && array->q_cnt == 0);
+ OBD_ALLOC_PTR_ARRAY(array->q_locks, array->q_max);
+ if (array->q_locks == NULL) {
+ array->q_max = 0;
+ RETURN(-ENOMEM);
+ }
+
+ goto again;
+ }
+ RETURN(0);
+}
+
+static void qmt_setup_id_desc(struct ldlm_lock *lock, union ldlm_gl_desc *desc,
+ struct lquota_entry *lqe)
+{
+ struct obd_uuid *uuid = &(lock)->l_export->exp_client_uuid;
+ int idx, stype;
+ __u64 qunit;
+ bool edquot;
+
+ stype = qmt_uuid2idx(uuid, &idx);
+ LASSERT(stype >= 0);
+
+ /* DOM case - set global lqe settings */
+ if (qmt_dom(lqe_rtype(lqe), stype)) {
+ edquot = lqe->lqe_edquot;
+ qunit = lqe->lqe_qunit;
+ } else {
+ struct lqe_glbl_data *lgd;
+
+ mutex_lock(&lqe->lqe_glbl_data_lock);
+ lgd = lqe->lqe_glbl_data;
+ if (lgd) {
+ edquot = lgd->lqeg_arr[idx].lge_edquot;
+ qunit = lgd->lqeg_arr[idx].lge_qunit;
+ } else {
+ edquot = lqe->lqe_edquot;
+ qunit = lqe->lqe_qunit;
+ }
+ mutex_unlock(&lqe->lqe_glbl_data_lock);
+ }
+
+ /* fill glimpse descriptor with lqe settings */
+ desc->lquota_desc.gl_flags = edquot ? LQUOTA_FL_EDQUOT : 0;
+ desc->lquota_desc.gl_qunit = qunit;
+ CDEBUG(D_QUOTA, "setup desc: stype %d idx %d, edquot %llu qunit %llu\n",
+ stype, idx, desc->lquota_desc.gl_flags,
+ desc->lquota_desc.gl_qunit);
+}
+