Commit bb48bd4d authored by Chengguang Xu's avatar Chengguang Xu Committed by Ilya Dryomov

ceph: optimize memory usage

In current code, regular file and directory use same struct
ceph_file_info to store fs specific data so the struct has to
include some fields which are only used for directory
(e.g., readdir related info), when having plenty of regular files,
it will lead to memory waste.

This patch introduces dedicated ceph_dir_file_info cache for
readdir related thins. So that regular file does not include those
unused fields anymore.
Signed-off-by: default avatarChengguang Xu <cgxu519@gmx.com>
Reviewed-by: default avatar"Yan, Zheng" <zyan@redhat.com>
Signed-off-by: default avatarIlya Dryomov <idryomov@gmail.com>
parent 47474d0b
This diff is collapsed.
......@@ -161,13 +161,50 @@ prepare_open_request(struct super_block *sb, int flags, int create_mode)
return req;
}
static int ceph_init_file_info(struct inode *inode, struct file *file,
int fmode, bool isdir)
{
struct ceph_file_info *fi;
dout("%s %p %p 0%o (%s)\n", __func__, inode, file,
inode->i_mode, isdir ? "dir" : "regular");
BUG_ON(inode->i_fop->release != ceph_release);
if (isdir) {
struct ceph_dir_file_info *dfi =
kmem_cache_zalloc(ceph_dir_file_cachep, GFP_KERNEL);
if (!dfi) {
ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
return -ENOMEM;
}
file->private_data = dfi;
fi = &dfi->file_info;
dfi->next_offset = 2;
dfi->readdir_cache_idx = -1;
} else {
fi = kmem_cache_zalloc(ceph_file_cachep, GFP_KERNEL);
if (!fi) {
ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
return -ENOMEM;
}
file->private_data = fi;
}
fi->fmode = fmode;
spin_lock_init(&fi->rw_contexts_lock);
INIT_LIST_HEAD(&fi->rw_contexts);
return 0;
}
/*
* initialize private struct file data.
* if we fail, clean up by dropping fmode reference on the ceph_inode
*/
static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
{
struct ceph_file_info *fi;
int ret = 0;
switch (inode->i_mode & S_IFMT) {
......@@ -175,22 +212,10 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
ceph_fscache_register_inode_cookie(inode);
ceph_fscache_file_set_cookie(inode, file);
case S_IFDIR:
dout("init_file %p %p 0%o (regular)\n", inode, file,
inode->i_mode);
fi = kmem_cache_zalloc(ceph_file_cachep, GFP_KERNEL);
if (!fi) {
ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
return -ENOMEM;
}
fi->fmode = fmode;
spin_lock_init(&fi->rw_contexts_lock);
INIT_LIST_HEAD(&fi->rw_contexts);
fi->next_offset = 2;
fi->readdir_cache_idx = -1;
file->private_data = fi;
BUG_ON(inode->i_fop->release != ceph_release);
ret = ceph_init_file_info(inode, file, fmode,
S_ISDIR(inode->i_mode));
if (ret)
return ret;
break;
case S_IFLNK:
......@@ -462,16 +487,27 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
int ceph_release(struct inode *inode, struct file *file)
{
struct ceph_inode_info *ci = ceph_inode(inode);
if (S_ISDIR(inode->i_mode)) {
struct ceph_dir_file_info *dfi = file->private_data;
dout("release inode %p dir file %p\n", inode, file);
WARN_ON(!list_empty(&dfi->file_info.rw_contexts));
ceph_put_fmode(ci, dfi->file_info.fmode);
if (dfi->last_readdir)
ceph_mdsc_put_request(dfi->last_readdir);
kfree(dfi->last_name);
kfree(dfi->dir_info);
kmem_cache_free(ceph_dir_file_cachep, dfi);
} else {
struct ceph_file_info *fi = file->private_data;
dout("release inode %p regular file %p\n", inode, file);
WARN_ON(!list_empty(&fi->rw_contexts));
dout("release inode %p file %p\n", inode, file);
ceph_put_fmode(ci, fi->fmode);
if (fi->last_readdir)
ceph_mdsc_put_request(fi->last_readdir);
kfree(fi->last_name);
kfree(fi->dir_info);
WARN_ON(!list_empty(&fi->rw_contexts));
kmem_cache_free(ceph_file_cachep, fi);
}
/* wake up anyone waiting for caps on this inode */
wake_up_all(&ci->i_cap_wq);
......
......@@ -679,6 +679,7 @@ struct kmem_cache *ceph_cap_cachep;
struct kmem_cache *ceph_cap_flush_cachep;
struct kmem_cache *ceph_dentry_cachep;
struct kmem_cache *ceph_file_cachep;
struct kmem_cache *ceph_dir_file_cachep;
static void ceph_inode_init_once(void *foo)
{
......@@ -715,6 +716,10 @@ static int __init init_caches(void)
if (!ceph_file_cachep)
goto bad_file;
ceph_dir_file_cachep = KMEM_CACHE(ceph_dir_file_info, SLAB_MEM_SPREAD);
if (!ceph_dir_file_cachep)
goto bad_dir_file;
error = ceph_fscache_register();
if (error)
goto bad_fscache;
......@@ -722,6 +727,8 @@ static int __init init_caches(void)
return 0;
bad_fscache:
kmem_cache_destroy(ceph_dir_file_cachep);
bad_dir_file:
kmem_cache_destroy(ceph_file_cachep);
bad_file:
kmem_cache_destroy(ceph_dentry_cachep);
......@@ -747,6 +754,7 @@ static void destroy_caches(void)
kmem_cache_destroy(ceph_cap_flush_cachep);
kmem_cache_destroy(ceph_dentry_cachep);
kmem_cache_destroy(ceph_file_cachep);
kmem_cache_destroy(ceph_dir_file_cachep);
ceph_fscache_unregister();
}
......
......@@ -671,6 +671,10 @@ struct ceph_file_info {
spinlock_t rw_contexts_lock;
struct list_head rw_contexts;
};
struct ceph_dir_file_info {
struct ceph_file_info file_info;
/* readdir: position within the dir */
u32 frag;
......
......@@ -262,6 +262,7 @@ extern struct kmem_cache *ceph_cap_cachep;
extern struct kmem_cache *ceph_cap_flush_cachep;
extern struct kmem_cache *ceph_dentry_cachep;
extern struct kmem_cache *ceph_file_cachep;
extern struct kmem_cache *ceph_dir_file_cachep;
/* ceph_common.c */
extern bool libceph_compatible(void *data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment