X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fldlm%2Fldlm_resource.c;h=490e7c5330534d9a0c8b027a930c0821f8a8ee73;hp=baf935ee4c17ef8f3b29150cd6cf7a4521bce898;hb=5c883ea2748ae9e430a9cd863a9b630b2a74440a;hpb=2250e072c37855d611aa64027945981fe2c8f4d7 diff --git a/lustre/ldlm/ldlm_resource.c b/lustre/ldlm/ldlm_resource.c index baf935e..490e7c5 100644 --- a/lustre/ldlm/ldlm_resource.c +++ b/lustre/ldlm/ldlm_resource.c @@ -111,14 +111,23 @@ static ssize_t seq_watermark_write(struct file *file, const char __user *buffer, size_t count, loff_t *off) { - __s64 value; + struct seq_file *m = file->private_data; + u64 value; __u64 watermark; - __u64 *data = ((struct seq_file *)file->private_data)->private; + __u64 *data = m->private; bool wm_low = (data == &ldlm_reclaim_threshold_mb) ? true : false; + char kernbuf[22] = ""; int rc; - rc = lprocfs_str_with_units_to_s64(buffer, count, &value, 'M'); - if (rc) { + if (count >= sizeof(kernbuf)) + return -EINVAL; + + if (copy_from_user(kernbuf, buffer, count)) + return -EFAULT; + kernbuf[count] = 0; + + rc = sysfs_memparse(kernbuf, count, &value, "MiB"); + if (rc < 0) { CERROR("Failed to set %s, rc = %d.\n", wm_low ? "lock_reclaim_threshold_mb" : "lock_limit_mb", rc); @@ -230,6 +239,7 @@ int ldlm_debugfs_setup(void) if (IS_ERR_OR_NULL(ldlm_debugfs_dir)) { CERROR("LDebugFS failed in ldlm-init\n"); rc = ldlm_debugfs_dir ? PTR_ERR(ldlm_debugfs_dir) : -ENOMEM; + ldlm_debugfs_dir = NULL; GOTO(err, rc); } @@ -240,7 +250,7 @@ int ldlm_debugfs_setup(void) CERROR("LProcFS failed in ldlm-init\n"); rc = ldlm_ns_debugfs_dir ? PTR_ERR(ldlm_ns_debugfs_dir) : -ENOMEM; - GOTO(err_type, rc); + GOTO(err, rc); } ldlm_svc_debugfs_dir = ldebugfs_register("services", @@ -250,24 +260,19 @@ int ldlm_debugfs_setup(void) CERROR("LProcFS failed in ldlm-init\n"); rc = ldlm_svc_debugfs_dir ? PTR_ERR(ldlm_svc_debugfs_dir) : -ENOMEM; - GOTO(err_ns, rc); + GOTO(err, rc); } rc = ldebugfs_add_vars(ldlm_debugfs_dir, ldlm_debugfs_list, NULL); if (rc != 0) { CERROR("LProcFS failed in ldlm-init\n"); - GOTO(err_svc, rc); + GOTO(err, rc); } RETURN(0); -err_svc: - ldebugfs_remove(&ldlm_svc_debugfs_dir); -err_ns: - ldebugfs_remove(&ldlm_ns_debugfs_dir); -err_type: - ldebugfs_remove(&ldlm_debugfs_dir); err: + debugfs_remove_recursive(ldlm_debugfs_dir); ldlm_svc_debugfs_dir = NULL; ldlm_ns_debugfs_dir = NULL; ldlm_debugfs_dir = NULL; @@ -276,14 +281,7 @@ err: void ldlm_debugfs_cleanup(void) { - if (!IS_ERR_OR_NULL(ldlm_svc_debugfs_dir)) - ldebugfs_remove(&ldlm_svc_debugfs_dir); - - if (!IS_ERR_OR_NULL(ldlm_ns_debugfs_dir)) - ldebugfs_remove(&ldlm_ns_debugfs_dir); - - if (!IS_ERR_OR_NULL(ldlm_debugfs_dir)) - ldebugfs_remove(&ldlm_debugfs_dir); + debugfs_remove_recursive(ldlm_debugfs_dir); ldlm_svc_debugfs_dir = NULL; ldlm_ns_debugfs_dir = NULL; @@ -296,12 +294,11 @@ static ssize_t resource_count_show(struct kobject *kobj, struct attribute *attr, struct ldlm_namespace *ns = container_of(kobj, struct ldlm_namespace, ns_kobj); __u64 res = 0; - struct cfs_hash_bd bd; int i; /* result is not strictly consistant */ - cfs_hash_for_each_bucket(ns->ns_rs_hash, &bd, i) - res += cfs_hash_bd_count_get(&bd); + for (i = 0; i < (1 << ns->ns_bucket_bits); i++) + res += atomic_read(&ns->ns_rs_buckets[i].nsb_count); return sprintf(buf, "%lld\n", res); } LUSTRE_RO_ATTR(resource_count); @@ -705,7 +702,7 @@ static void ldlm_namespace_debugfs_unregister(struct ldlm_namespace *ns) CERROR("dlm namespace %s has no procfs dir?\n", ldlm_ns_name(ns)); else - ldebugfs_remove(&ns->ns_debugfs_entry); + debugfs_remove_recursive(ns->ns_debugfs_entry); if (ns->ns_stats != NULL) lprocfs_free_stats(&ns->ns_stats); @@ -768,10 +765,8 @@ static unsigned ldlm_res_hop_hash(struct cfs_hash *hs, return val & mask; } -static unsigned ldlm_res_hop_fid_hash(struct cfs_hash *hs, - const void *key, unsigned mask) +static unsigned int ldlm_res_hop_fid_hash(const struct ldlm_res_id *id, unsigned int bits) { - const struct ldlm_res_id *id = key; struct lu_fid fid; __u32 hash; __u32 val; @@ -784,18 +779,11 @@ static unsigned ldlm_res_hop_fid_hash(struct cfs_hash *hs, hash += (hash >> 4) + (hash << 12); /* mixing oid and seq */ if (id->name[LUSTRE_RES_ID_HSH_OFF] != 0) { val = id->name[LUSTRE_RES_ID_HSH_OFF]; - hash += (val >> 5) + (val << 11); } else { val = fid_oid(&fid); } - hash = hash_long(hash, hs->hs_bkt_bits); - /* give me another random factor */ - hash -= hash_long((unsigned long)hs, val % 11 + 3); - - hash <<= hs->hs_cur_bits - hs->hs_bkt_bits; - hash |= ldlm_res_hop_hash(hs, key, CFS_HASH_NBKT(hs) - 1); - - return hash & mask; + hash += (val >> 5) + (val << 11); + return cfs_hash_32(hash, bits); } static void *ldlm_res_hop_key(struct hlist_node *hnode) @@ -847,66 +835,35 @@ static struct cfs_hash_ops ldlm_ns_hash_ops = { .hs_put = ldlm_res_hop_put }; -static struct cfs_hash_ops ldlm_ns_fid_hash_ops = { - .hs_hash = ldlm_res_hop_fid_hash, - .hs_key = ldlm_res_hop_key, - .hs_keycmp = ldlm_res_hop_keycmp, - .hs_keycpy = NULL, - .hs_object = ldlm_res_hop_object, - .hs_get = ldlm_res_hop_get_locked, - .hs_put = ldlm_res_hop_put -}; - -typedef struct ldlm_ns_hash_def { - enum ldlm_ns_type nsd_type; +static struct { /** hash bucket bits */ unsigned nsd_bkt_bits; /** hash bits */ unsigned nsd_all_bits; - /** hash operations */ - struct cfs_hash_ops *nsd_hops; -} ldlm_ns_hash_def_t; - -static struct ldlm_ns_hash_def ldlm_ns_hash_defs[] = -{ - { - .nsd_type = LDLM_NS_TYPE_MDC, +} ldlm_ns_hash_defs[] = { + [LDLM_NS_TYPE_MDC] = { .nsd_bkt_bits = 11, .nsd_all_bits = 16, - .nsd_hops = &ldlm_ns_fid_hash_ops, }, - { - .nsd_type = LDLM_NS_TYPE_MDT, + [LDLM_NS_TYPE_MDT] = { .nsd_bkt_bits = 14, .nsd_all_bits = 21, - .nsd_hops = &ldlm_ns_fid_hash_ops, }, - { - .nsd_type = LDLM_NS_TYPE_OSC, + [LDLM_NS_TYPE_OSC] = { .nsd_bkt_bits = 8, .nsd_all_bits = 12, - .nsd_hops = &ldlm_ns_hash_ops, }, - { - .nsd_type = LDLM_NS_TYPE_OST, + [LDLM_NS_TYPE_OST] = { .nsd_bkt_bits = 11, .nsd_all_bits = 17, - .nsd_hops = &ldlm_ns_hash_ops, }, - { - .nsd_type = LDLM_NS_TYPE_MGC, - .nsd_bkt_bits = 4, + [LDLM_NS_TYPE_MGC] = { + .nsd_bkt_bits = 3, .nsd_all_bits = 4, - .nsd_hops = &ldlm_ns_hash_ops, }, - { - .nsd_type = LDLM_NS_TYPE_MGT, - .nsd_bkt_bits = 4, + [LDLM_NS_TYPE_MGT] = { + .nsd_bkt_bits = 3, .nsd_all_bits = 4, - .nsd_hops = &ldlm_ns_hash_ops, - }, - { - .nsd_type = LDLM_NS_TYPE_UNKNOWN, }, }; @@ -919,9 +876,6 @@ struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obd, char *name, enum ldlm_ns_type ns_type) { struct ldlm_namespace *ns = NULL; - struct ldlm_ns_bucket *nsb; - struct ldlm_ns_hash_def *nsd; - struct cfs_hash_bd bd; int idx; int rc; @@ -934,15 +888,10 @@ struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obd, char *name, RETURN(NULL); } - for (idx = 0; ; idx++) { - nsd = &ldlm_ns_hash_defs[idx]; - if (nsd->nsd_type == LDLM_NS_TYPE_UNKNOWN) { - CERROR("Unknown type %d for ns %s\n", ns_type, name); - GOTO(out_ref, NULL); - } - - if (nsd->nsd_type == ns_type) - break; + if (ns_type >= ARRAY_SIZE(ldlm_ns_hash_defs) || + ldlm_ns_hash_defs[ns_type].nsd_bkt_bits == 0) { + CERROR("Unknown type %d for ns %s\n", ns_type, name); + GOTO(out_ref, NULL); } OBD_ALLOC_PTR(ns); @@ -950,11 +899,13 @@ struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obd, char *name, GOTO(out_ref, NULL); ns->ns_rs_hash = cfs_hash_create(name, - nsd->nsd_all_bits, nsd->nsd_all_bits, - nsd->nsd_bkt_bits, sizeof(*nsb), + ldlm_ns_hash_defs[ns_type].nsd_all_bits, + ldlm_ns_hash_defs[ns_type].nsd_all_bits, + ldlm_ns_hash_defs[ns_type].nsd_bkt_bits, + 0, CFS_HASH_MIN_THETA, CFS_HASH_MAX_THETA, - nsd->nsd_hops, + &ldlm_ns_hash_ops, CFS_HASH_DEPTH | CFS_HASH_BIGNAME | CFS_HASH_SPIN_BKTLOCK | @@ -962,11 +913,21 @@ struct ldlm_namespace *ldlm_namespace_new(struct obd_device *obd, char *name, if (ns->ns_rs_hash == NULL) GOTO(out_ns, NULL); - cfs_hash_for_each_bucket(ns->ns_rs_hash, &bd, idx) { - nsb = cfs_hash_bd_extra_get(ns->ns_rs_hash, &bd); + ns->ns_bucket_bits = ldlm_ns_hash_defs[ns_type].nsd_all_bits - + ldlm_ns_hash_defs[ns_type].nsd_bkt_bits; + + OBD_ALLOC_LARGE(ns->ns_rs_buckets, + BIT(ns->ns_bucket_bits) * sizeof(ns->ns_rs_buckets[0])); + if (!ns->ns_rs_buckets) + goto out_hash; + + for (idx = 0; idx < (1 << ns->ns_bucket_bits); idx++) { + struct ldlm_ns_bucket *nsb = &ns->ns_rs_buckets[idx]; + at_init(&nsb->nsb_at_estimate, ldlm_enqueue_min, 0); nsb->nsb_namespace = ns; nsb->nsb_reclaim_start = 0; + atomic_set(&nsb->nsb_count, 0); } ns->ns_obd = obd; @@ -1026,6 +987,8 @@ out_sysfs: ldlm_namespace_sysfs_unregister(ns); ldlm_namespace_cleanup(ns, 0); out_hash: + OBD_FREE_LARGE(ns->ns_rs_buckets, + BIT(ns->ns_bucket_bits) * sizeof(ns->ns_rs_buckets[0])); kfree(ns->ns_name); cfs_hash_putref(ns->ns_rs_hash); out_ns: @@ -1093,11 +1056,10 @@ static void cleanup_resource(struct ldlm_resource *res, struct list_head *q, */ unlock_res(res); LDLM_DEBUG(lock, "setting FL_LOCAL_ONLY"); - if (lock->l_flags & LDLM_FL_FAIL_LOC) { - set_current_state(TASK_UNINTERRUPTIBLE); - schedule_timeout(cfs_time_seconds(4)); - set_current_state(TASK_RUNNING); - } + if (lock->l_flags & LDLM_FL_FAIL_LOC) + schedule_timeout_uninterruptible( + cfs_time_seconds(4)); + if (lock->l_completion_ast) lock->l_completion_ast(lock, LDLM_FL_FAILED, NULL); @@ -1187,22 +1149,24 @@ static int __ldlm_namespace_free(struct ldlm_namespace *ns, int force) ldlm_namespace_cleanup(ns, force ? LDLM_FL_LOCAL_ONLY : 0); if (atomic_read(&ns->ns_bref) > 0) { - struct l_wait_info lwi = LWI_INTR(LWI_ON_SIGNAL_NOOP, NULL); int rc; CDEBUG(D_DLMTRACE, "dlm namespace %s free waiting on refcount %d\n", ldlm_ns_name(ns), atomic_read(&ns->ns_bref)); force_wait: if (force) - lwi = LWI_TIMEOUT(cfs_time_seconds(1) / 4, - NULL, NULL); - - rc = l_wait_event(ns->ns_waitq, - atomic_read(&ns->ns_bref) == 0, &lwi); + rc = wait_event_idle_timeout( + ns->ns_waitq, + atomic_read(&ns->ns_bref) == 0, + cfs_time_seconds(1) / 4); + else + rc = l_wait_event_abortable( + ns->ns_waitq, atomic_read(&ns->ns_bref) == 0); /* Forced cleanups should be able to reclaim all references, * so it's safe to wait forever... we can't leak locks... */ - if (force && rc == -ETIMEDOUT) { + if (force && rc == 0) { + rc = -ETIMEDOUT; LCONSOLE_ERROR("Forced cleanup waiting for %s " "namespace with %d resources in use, " "(rc=%d)\n", ldlm_ns_name(ns), @@ -1293,6 +1257,8 @@ void ldlm_namespace_free_post(struct ldlm_namespace *ns) ldlm_namespace_debugfs_unregister(ns); ldlm_namespace_sysfs_unregister(ns); cfs_hash_putref(ns->ns_rs_hash); + OBD_FREE_LARGE(ns->ns_rs_buckets, + BIT(ns->ns_bucket_bits) * sizeof(ns->ns_rs_buckets[0])); kfree(ns->ns_name); /* Namespace \a ns should be not on list at this time, otherwise * this will cause issues related to using freed \a ns in poold @@ -1502,6 +1468,7 @@ ldlm_resource_get(struct ldlm_namespace *ns, struct ldlm_resource *parent, struct cfs_hash_bd bd; __u64 version; int ns_refcount = 0; + int hash; LASSERT(ns != NULL); LASSERT(parent == NULL); @@ -1527,7 +1494,8 @@ ldlm_resource_get(struct ldlm_namespace *ns, struct ldlm_resource *parent, if (res == NULL) return ERR_PTR(-ENOMEM); - res->lr_ns_bucket = cfs_hash_bd_extra_get(ns->ns_rs_hash, &bd); + hash = ldlm_res_hop_fid_hash(name, ns->ns_bucket_bits); + res->lr_ns_bucket = &ns->ns_rs_buckets[hash]; res->lr_name = *name; res->lr_type = type; @@ -1547,7 +1515,7 @@ found: } /* We won! Let's add the resource. */ cfs_hash_bd_add_locked(ns->ns_rs_hash, &bd, &res->lr_hash); - if (cfs_hash_bd_count_get(&bd) == 1) + if (atomic_inc_return(&res->lr_ns_bucket->nsb_count) == 1) ns_refcount = ldlm_namespace_get_return(ns); cfs_hash_bd_unlock(ns->ns_rs_hash, &bd, 1); @@ -1596,7 +1564,7 @@ static void __ldlm_resource_putref_final(struct cfs_hash_bd *bd, cfs_hash_bd_del_locked(nsb->nsb_namespace->ns_rs_hash, bd, &res->lr_hash); lu_ref_fini(&res->lr_reference); - if (cfs_hash_bd_count_get(bd) == 0) + if (atomic_dec_and_test(&nsb->nsb_count)) ldlm_namespace_put(nsb->nsb_namespace); } @@ -1766,7 +1734,7 @@ void ldlm_resource_dump(int level, struct ldlm_resource *res) struct ldlm_lock *lock; unsigned int granted = 0; - CLASSERT(RES_NAME_SIZE == 4); + BUILD_BUG_ON(RES_NAME_SIZE != 4); if (!((libcfs_debug | D_ERROR) & level)) return;