* Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
* Use is subject to license terms.
*
- * Copyright (c) 2011, 2012, Intel Corporation.
+ * Copyright (c) 2011, 2013, Intel Corporation.
*/
/*
* This file is part of Lustre, http://www.lustre.org/
#include <lustre_disk.h>
#include <lustre_fid.h>
#include <lu_object.h>
+#include <lu_ref.h>
#include <libcfs/list.h>
static void lu_object_free(const struct lu_env *env, struct lu_object *o);
* and LRU lock, no race with concurrent object lookup is possible
* and we can safely destroy object below.
*/
- cfs_hash_bd_del_locked(site->ls_obj_hash, &bd, &top->loh_hash);
+ if (!test_and_set_bit(LU_OBJECT_UNHASHED, &top->loh_flags))
+ cfs_hash_bd_del_locked(site->ls_obj_hash, &bd, &top->loh_hash);
cfs_hash_bd_unlock(site->ls_obj_hash, &bd, 1);
/*
* Object was already removed from hash and lru above, can
*/
void lu_object_put_nocache(const struct lu_env *env, struct lu_object *o)
{
- set_bit(LU_OBJECT_HEARD_BANSHEE,
- &o->lo_header->loh_flags);
+ set_bit(LU_OBJECT_HEARD_BANSHEE, &o->lo_header->loh_flags);
return lu_object_put(env, o);
}
EXPORT_SYMBOL(lu_object_put_nocache);
/**
+ * Kill the object and take it out of LRU cache.
+ * Currently used by client code for layout change.
+ */
+void lu_object_unhash(const struct lu_env *env, struct lu_object *o)
+{
+ struct lu_object_header *top;
+
+ top = o->lo_header;
+ set_bit(LU_OBJECT_HEARD_BANSHEE, &top->loh_flags);
+ if (!test_and_set_bit(LU_OBJECT_UNHASHED, &top->loh_flags)) {
+ cfs_hash_t *obj_hash = o->lo_dev->ld_site->ls_obj_hash;
+ cfs_hash_bd_t bd;
+
+ cfs_hash_bd_get_and_lock(obj_hash, &top->loh_fid, &bd, 1);
+ cfs_list_del_init(&top->loh_lru);
+ cfs_hash_bd_del_locked(obj_hash, &bd, &top->loh_hash);
+ cfs_hash_bd_unlock(obj_hash, &bd, 1);
+ }
+}
+EXPORT_SYMBOL(lu_object_unhash);
+
+/**
* Allocate new object.
*
* This follows object creation protocol, described in the comment within
int result;
ENTRY;
- /*
- * Create top-level object slice. This will also create
- * lu_object_header.
- */
- top = dev->ld_ops->ldo_object_alloc(env, NULL, dev);
- if (top == NULL)
- RETURN(ERR_PTR(-ENOMEM));
+ /*
+ * Create top-level object slice. This will also create
+ * lu_object_header.
+ */
+ top = dev->ld_ops->ldo_object_alloc(env, NULL, dev);
+ if (top == NULL)
+ RETURN(ERR_PTR(-ENOMEM));
+ if (IS_ERR(top))
+ RETURN(top);
/*
* This is the only place where object fid is assigned. It's constant
* after this point.
*/
- LASSERT(fid_is_igif(f) || fid_ver(f) == 0);
top->lo_header->loh_fid = *f;
layers = &top->lo_header->loh_layers;
do {
int bnr;
int i;
+ if (OBD_FAIL_CHECK(OBD_FAIL_OBD_NO_LRU))
+ RETURN(0);
+
CFS_INIT_LIST_HEAD(&dispose);
/*
* Under LRU list lock, scan LRU list and move unreferenced objects to
* lu_global_init().
*/
struct lu_context_key lu_global_key = {
- .lct_tags = LCT_MD_THREAD | LCT_DT_THREAD |
- LCT_MG_THREAD | LCT_CL_THREAD,
- .lct_init = lu_global_key_init,
- .lct_fini = lu_global_key_fini
+ .lct_tags = LCT_MD_THREAD | LCT_DT_THREAD |
+ LCT_MG_THREAD | LCT_CL_THREAD | LCT_LOCAL,
+ .lct_init = lu_global_key_init,
+ .lct_fini = lu_global_key_fini
};
/**
__u64 ver = cfs_hash_bd_version_get(bd);
if (*version == ver)
- return NULL;
+ return ERR_PTR(-ENOENT);
*version = ver;
bkt = cfs_hash_bd_extra_get(s->ls_obj_hash, bd);
hnode = cfs_hash_bd_peek_locked(s->ls_obj_hash, bd, (void *)f);
if (hnode == NULL) {
lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_MISS);
- return NULL;
+ return ERR_PTR(-ENOENT);
}
h = container_of0(hnode, struct lu_object_header, loh_hash);
return ERR_PTR(-EAGAIN);
}
+static struct lu_object *htable_lookup_nowait(struct lu_site *s,
+ cfs_hash_bd_t *bd,
+ const struct lu_fid *f)
+{
+ cfs_hlist_node_t *hnode;
+ struct lu_object_header *h;
+
+ /* cfs_hash_bd_peek_locked is a somehow "internal" function
+ * of cfs_hash, it doesn't add refcount on object. */
+ hnode = cfs_hash_bd_peek_locked(s->ls_obj_hash, bd, (void *)f);
+ if (hnode == NULL) {
+ lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_MISS);
+ return ERR_PTR(-ENOENT);
+ }
+
+ h = container_of0(hnode, struct lu_object_header, loh_hash);
+ if (unlikely(lu_object_is_dying(h)))
+ return ERR_PTR(-ENOENT);
+
+ cfs_hash_get(s->ls_obj_hash, hnode);
+ lprocfs_counter_incr(s->ls_stats, LU_SS_CACHE_HIT);
+ cfs_list_del_init(&h->loh_lru);
+ return lu_object_top(h);
+}
+
/**
* Search cache for an object with the fid \a f. If such object is found,
* return it. Otherwise, create new object, insert it into cache and return
cfs_hash_bd_get_and_lock(hs, (void *)f, &bd, 1);
o = htable_lookup(s, &bd, f, waiter, &version);
cfs_hash_bd_unlock(hs, &bd, 1);
- if (o != NULL)
+ if (!IS_ERR(o) || PTR_ERR(o) != -ENOENT)
return o;
/*
cfs_hash_bd_lock(hs, &bd, 1);
shadow = htable_lookup(s, &bd, f, waiter, &version);
- if (likely(shadow == NULL)) {
+ if (likely(IS_ERR(shadow) && PTR_ERR(shadow) == -ENOENT)) {
struct lu_site_bkt_data *bkt;
bkt = cfs_hash_bd_extra_get(hs, &bd);
EXPORT_SYMBOL(lu_object_find_at);
/**
+ * Try to find the object in cache without waiting for the dead object
+ * to be released nor allocating object if no cached one was found.
+ *
+ * The found object will be set as LU_OBJECT_HEARD_BANSHEE for purging.
+ */
+void lu_object_purge(const struct lu_env *env, struct lu_device *dev,
+ const struct lu_fid *f)
+{
+ struct lu_site *s = dev->ld_site;
+ cfs_hash_t *hs = s->ls_obj_hash;
+ cfs_hash_bd_t bd;
+ struct lu_object *o;
+
+ cfs_hash_bd_get_and_lock(hs, f, &bd, 1);
+ o = htable_lookup_nowait(s, &bd, f);
+ cfs_hash_bd_unlock(hs, &bd, 1);
+ if (!IS_ERR(o)) {
+ set_bit(LU_OBJECT_HEARD_BANSHEE, &o->lo_header->loh_flags);
+ lu_object_put(env, o);
+ }
+}
+EXPORT_SYMBOL(lu_object_purge);
+
+/**
* Find object with given fid, and return its slice belonging to given device.
*/
struct lu_object *lu_object_find_slice(const struct lu_env *env,
*
* Size of lu_object is (arbitrary) taken as 1K (together with inode).
*/
- cache_size = cfs_num_physpages;
+ cache_size = num_physpages;
#if BITS_PER_LONG == 32
/* limit hashtable size for lowmem systems to low RAM */
- if (cache_size > 1 << (30 - CFS_PAGE_SHIFT))
- cache_size = 1 << (30 - CFS_PAGE_SHIFT) * 3 / 4;
+ if (cache_size > 1 << (30 - PAGE_CACHE_SHIFT))
+ cache_size = 1 << (30 - PAGE_CACHE_SHIFT) * 3 / 4;
#endif
/* clear off unreasonable cache setting. */
lu_cache_percent = LU_CACHE_PERCENT_DEFAULT;
}
cache_size = cache_size / 100 * lu_cache_percent *
- (CFS_PAGE_SIZE / 1024);
+ (PAGE_CACHE_SIZE / 1024);
for (bits = 1; (1 << bits) < cache_size; ++bits) {
;
* Initialize object \a o that is part of compound object \a h and was created
* by device \a d.
*/
-int lu_object_init(struct lu_object *o,
- struct lu_object_header *h, struct lu_device *d)
+int lu_object_init(struct lu_object *o, struct lu_object_header *h,
+ struct lu_device *d)
{
- memset(o, 0, sizeof *o);
- o->lo_header = h;
- o->lo_dev = d;
- lu_device_get(d);
- o->lo_dev_ref = lu_ref_add(&d->ld_reference, "lu_object", o);
- CFS_INIT_LIST_HEAD(&o->lo_linkage);
- return 0;
+ memset(o, 0, sizeof(*o));
+ o->lo_header = h;
+ o->lo_dev = d;
+ lu_device_get(d);
+ lu_ref_add_at(&d->ld_reference, &o->lo_dev_ref, "lu_object", o);
+ CFS_INIT_LIST_HEAD(&o->lo_linkage);
+
+ return 0;
}
EXPORT_SYMBOL(lu_object_init);
*/
void lu_object_fini(struct lu_object *o)
{
- struct lu_device *dev = o->lo_dev;
+ struct lu_device *dev = o->lo_dev;
- LASSERT(cfs_list_empty(&o->lo_linkage));
+ LASSERT(cfs_list_empty(&o->lo_linkage));
- if (dev != NULL) {
- lu_ref_del_at(&dev->ld_reference,
- o->lo_dev_ref , "lu_object", o);
- lu_device_put(dev);
- o->lo_dev = NULL;
- }
+ if (dev != NULL) {
+ lu_ref_del_at(&dev->ld_reference, &o->lo_dev_ref,
+ "lu_object", o);
+ lu_device_put(dev);
+ o->lo_dev = NULL;
+ }
}
EXPORT_SYMBOL(lu_object_fini);
void lu_context_key_quiesce(struct lu_context_key *key)
{
struct lu_context *ctx;
- extern unsigned cl_env_cache_purge(unsigned nr);
if (!(key->lct_tags & LCT_QUIESCENT)) {
/*
* XXX layering violation.
*/
- cl_env_cache_purge(~0);
key->lct_tags |= LCT_QUIESCENT;
/*
* XXX memory barrier has to go here.
}
EXPORT_SYMBOL(lu_env_refill_by_tags);
-static struct cfs_shrinker *lu_site_shrinker = NULL;
+static struct shrinker *lu_site_shrinker;
typedef struct lu_site_stats{
unsigned lss_populated;
return 0;
}
-void lu_debugging_setup(void)
+int lu_debugging_setup(void)
{
- lu_env_init(&lu_debugging_env, ~0);
+ return lu_env_init(&lu_debugging_env, ~0);
}
void lu_context_keys_dump(void)
}
#endif /* __KERNEL__ */
-int cl_global_init(void);
-void cl_global_fini(void);
-int lu_ref_global_init(void);
-void lu_ref_global_fini(void);
-
-int dt_global_init(void);
-void dt_global_fini(void);
-
-int llo_global_init(void);
-void llo_global_fini(void);
-
-/* context key constructor/destructor: lu_ucred_key_init, lu_ucred_key_fini */
-LU_KEY_INIT_FINI(lu_ucred, struct lu_ucred);
-
-static struct lu_context_key lu_ucred_key = {
- .lct_tags = LCT_SESSION,
- .lct_init = lu_ucred_key_init,
- .lct_fini = lu_ucred_key_fini
-};
-
-/**
- * Get ucred key if session exists and ucred key is allocated on it.
- * Return NULL otherwise.
- */
-struct lu_ucred *lu_ucred(const struct lu_env *env)
-{
- if (!env->le_ses)
- return NULL;
- return lu_context_key_get(env->le_ses, &lu_ucred_key);
-}
-EXPORT_SYMBOL(lu_ucred);
-
-/**
- * Get ucred key and check if it is properly initialized.
- * Return NULL otherwise.
- */
-struct lu_ucred *lu_ucred_check(const struct lu_env *env)
-{
- struct lu_ucred *uc = lu_ucred(env);
- if (uc && uc->uc_valid != UCRED_OLD && uc->uc_valid != UCRED_NEW)
- return NULL;
- return uc;
-}
-EXPORT_SYMBOL(lu_ucred_check);
-
-/**
- * Get ucred key, which must exist and must be properly initialized.
- * Assert otherwise.
- */
-struct lu_ucred *lu_ucred_assert(const struct lu_env *env)
-{
- struct lu_ucred *uc = lu_ucred_check(env);
- LASSERT(uc != NULL);
- return uc;
-}
-EXPORT_SYMBOL(lu_ucred_assert);
-
/**
* Initialization of global lu_* data.
*/
if (result != 0)
return result;
- LU_CONTEXT_KEY_INIT(&lu_ucred_key);
- result = lu_context_key_register(&lu_ucred_key);
- if (result != 0)
- return result;
-
/*
* At this level, we don't know what tags are needed, so allocate them
* conservatively. This should not be too bad, because this
* inode, one for ea. Unfortunately setting this high value results in
* lu_object/inode cache consuming all the memory.
*/
- lu_site_shrinker = cfs_set_shrinker(CFS_DEFAULT_SEEKS, lu_cache_shrink);
+ lu_site_shrinker = set_shrinker(DEFAULT_SEEKS, lu_cache_shrink);
if (lu_site_shrinker == NULL)
return -ENOMEM;
-#ifdef __KERNEL__
- result = dt_global_init();
- if (result != 0)
- return result;
-
- result = llo_global_init();
- if (result != 0)
- return result;
-#endif
- result = cl_global_init();
-
return result;
}
*/
void lu_global_fini(void)
{
- cl_global_fini();
-#ifdef __KERNEL__
- llo_global_fini();
- dt_global_fini();
-#endif
if (lu_site_shrinker != NULL) {
- cfs_remove_shrinker(lu_site_shrinker);
+ remove_shrinker(lu_site_shrinker);
lu_site_shrinker = NULL;
}
- lu_context_key_degister(&lu_global_key);
- lu_context_key_degister(&lu_ucred_key);
+ lu_context_key_degister(&lu_global_key);
/*
* Tear shrinker environment down _after_ de-registering
lu_ref_global_fini();
}
-struct lu_buf LU_BUF_NULL = {
- .lb_buf = NULL,
- .lb_len = 0
-};
-EXPORT_SYMBOL(LU_BUF_NULL);
-
static __u32 ls_stats_read(struct lprocfs_stats *stats, int idx)
{
#ifdef LPROCFS
struct lu_kmem_descr *iter = caches;
for (result = 0; iter->ckd_cache != NULL; ++iter) {
- *iter->ckd_cache = cfs_mem_cache_create(iter->ckd_name,
- iter->ckd_size,
- 0, 0);
+ *iter->ckd_cache = kmem_cache_create(iter->ckd_name,
+ iter->ckd_size,
+ 0, 0, NULL);
if (*iter->ckd_cache == NULL) {
result = -ENOMEM;
/* free all previously allocated caches */
*/
void lu_kmem_fini(struct lu_kmem_descr *caches)
{
- int rc;
-
for (; caches->ckd_cache != NULL; ++caches) {
if (*caches->ckd_cache != NULL) {
- rc = cfs_mem_cache_destroy(*caches->ckd_cache);
- LASSERTF(rc == 0, "couldn't destroy %s slab\n",
- caches->ckd_name);
+ kmem_cache_destroy(*caches->ckd_cache);
*caches->ckd_cache = NULL;
}
}
cfs_hash_bd_get_and_lock(hs, (void *)fid, &bd, 1);
shadow = htable_lookup(s, &bd, fid, &waiter, &version);
/* supposed to be unique */
- LASSERT(shadow == NULL);
+ LASSERT(IS_ERR(shadow) && PTR_ERR(shadow) == -ENOENT);
*old = *fid;
bkt = cfs_hash_bd_extra_get(hs, &bd);
cfs_hash_bd_add_locked(hs, &bd, &o->lo_header->loh_hash);
return o;
}
EXPORT_SYMBOL(lu_object_anon);
+
+struct lu_buf LU_BUF_NULL = {
+ .lb_buf = NULL,
+ .lb_len = 0
+};
+EXPORT_SYMBOL(LU_BUF_NULL);
+
+void lu_buf_free(struct lu_buf *buf)
+{
+ LASSERT(buf);
+ if (buf->lb_buf) {
+ LASSERT(buf->lb_len > 0);
+ OBD_FREE_LARGE(buf->lb_buf, buf->lb_len);
+ buf->lb_buf = NULL;
+ buf->lb_len = 0;
+ }
+}
+EXPORT_SYMBOL(lu_buf_free);
+
+void lu_buf_alloc(struct lu_buf *buf, int size)
+{
+ LASSERT(buf);
+ LASSERT(buf->lb_buf == NULL);
+ LASSERT(buf->lb_len == 0);
+ OBD_ALLOC_LARGE(buf->lb_buf, size);
+ if (likely(buf->lb_buf))
+ buf->lb_len = size;
+}
+EXPORT_SYMBOL(lu_buf_alloc);
+
+void lu_buf_realloc(struct lu_buf *buf, int size)
+{
+ lu_buf_free(buf);
+ lu_buf_alloc(buf, size);
+}
+EXPORT_SYMBOL(lu_buf_realloc);
+
+struct lu_buf *lu_buf_check_and_alloc(struct lu_buf *buf, int len)
+{
+ if (buf->lb_buf == NULL && buf->lb_len == 0)
+ lu_buf_alloc(buf, len);
+
+ if ((len > buf->lb_len) && (buf->lb_buf != NULL))
+ lu_buf_realloc(buf, len);
+
+ return buf;
+}
+EXPORT_SYMBOL(lu_buf_check_and_alloc);
+
+/**
+ * Increase the size of the \a buf.
+ * preserves old data in buffer
+ * old buffer remains unchanged on error
+ * \retval 0 or -ENOMEM
+ */
+int lu_buf_check_and_grow(struct lu_buf *buf, int len)
+{
+ char *ptr;
+
+ if (len <= buf->lb_len)
+ return 0;
+
+ OBD_ALLOC_LARGE(ptr, len);
+ if (ptr == NULL)
+ return -ENOMEM;
+
+ /* Free the old buf */
+ if (buf->lb_buf != NULL) {
+ memcpy(ptr, buf->lb_buf, buf->lb_len);
+ OBD_FREE_LARGE(buf->lb_buf, buf->lb_len);
+ }
+
+ buf->lb_buf = ptr;
+ buf->lb_len = len;
+ return 0;
+}
+EXPORT_SYMBOL(lu_buf_check_and_grow);
+