summaryrefslogtreecommitdiffstats
path: root/fs/ceph/file.c
diff options
context:
space:
mode:
authorChengguang Xu <cgxu519@gmx.com>2018-03-12 22:42:44 -0400
committerIlya Dryomov <idryomov@gmail.com>2018-04-02 04:12:49 -0400
commitbb48bd4dc45f9ee1e44d8e9fcb01023e0d0ba80d (patch)
treeb844653552011036270e965137f7af0ea4345291 /fs/ceph/file.c
parent47474d0b011bb385719e91a60bb9ff7649d66526 (diff)
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: Chengguang Xu <cgxu519@gmx.com> Reviewed-by: "Yan, Zheng" <zyan@redhat.com> Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Diffstat (limited to 'fs/ceph/file.c')
-rw-r--r--fs/ceph/file.c88
1 files changed, 62 insertions, 26 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index a1f0aee29c27..4a92acba1e9c 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -161,13 +161,50 @@ out:
161 return req; 161 return req;
162} 162}
163 163
164static int ceph_init_file_info(struct inode *inode, struct file *file,
165 int fmode, bool isdir)
166{
167 struct ceph_file_info *fi;
168
169 dout("%s %p %p 0%o (%s)\n", __func__, inode, file,
170 inode->i_mode, isdir ? "dir" : "regular");
171 BUG_ON(inode->i_fop->release != ceph_release);
172
173 if (isdir) {
174 struct ceph_dir_file_info *dfi =
175 kmem_cache_zalloc(ceph_dir_file_cachep, GFP_KERNEL);
176 if (!dfi) {
177 ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
178 return -ENOMEM;
179 }
180
181 file->private_data = dfi;
182 fi = &dfi->file_info;
183 dfi->next_offset = 2;
184 dfi->readdir_cache_idx = -1;
185 } else {
186 fi = kmem_cache_zalloc(ceph_file_cachep, GFP_KERNEL);
187 if (!fi) {
188 ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
189 return -ENOMEM;
190 }
191
192 file->private_data = fi;
193 }
194
195 fi->fmode = fmode;
196 spin_lock_init(&fi->rw_contexts_lock);
197 INIT_LIST_HEAD(&fi->rw_contexts);
198
199 return 0;
200}
201
164/* 202/*
165 * initialize private struct file data. 203 * initialize private struct file data.
166 * if we fail, clean up by dropping fmode reference on the ceph_inode 204 * if we fail, clean up by dropping fmode reference on the ceph_inode
167 */ 205 */
168static int ceph_init_file(struct inode *inode, struct file *file, int fmode) 206static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
169{ 207{
170 struct ceph_file_info *fi;
171 int ret = 0; 208 int ret = 0;
172 209
173 switch (inode->i_mode & S_IFMT) { 210 switch (inode->i_mode & S_IFMT) {
@@ -175,22 +212,10 @@ static int ceph_init_file(struct inode *inode, struct file *file, int fmode)
175 ceph_fscache_register_inode_cookie(inode); 212 ceph_fscache_register_inode_cookie(inode);
176 ceph_fscache_file_set_cookie(inode, file); 213 ceph_fscache_file_set_cookie(inode, file);
177 case S_IFDIR: 214 case S_IFDIR:
178 dout("init_file %p %p 0%o (regular)\n", inode, file, 215 ret = ceph_init_file_info(inode, file, fmode,
179 inode->i_mode); 216 S_ISDIR(inode->i_mode));
180 fi = kmem_cache_zalloc(ceph_file_cachep, GFP_KERNEL); 217 if (ret)
181 if (!fi) { 218 return ret;
182 ceph_put_fmode(ceph_inode(inode), fmode); /* clean up */
183 return -ENOMEM;
184 }
185 fi->fmode = fmode;
186
187 spin_lock_init(&fi->rw_contexts_lock);
188 INIT_LIST_HEAD(&fi->rw_contexts);
189
190 fi->next_offset = 2;
191 fi->readdir_cache_idx = -1;
192 file->private_data = fi;
193 BUG_ON(inode->i_fop->release != ceph_release);
194 break; 219 break;
195 220
196 case S_IFLNK: 221 case S_IFLNK:
@@ -462,16 +487,27 @@ out_acl:
462int ceph_release(struct inode *inode, struct file *file) 487int ceph_release(struct inode *inode, struct file *file)
463{ 488{
464 struct ceph_inode_info *ci = ceph_inode(inode); 489 struct ceph_inode_info *ci = ceph_inode(inode);
465 struct ceph_file_info *fi = file->private_data;
466 490
467 dout("release inode %p file %p\n", inode, file); 491 if (S_ISDIR(inode->i_mode)) {
468 ceph_put_fmode(ci, fi->fmode); 492 struct ceph_dir_file_info *dfi = file->private_data;
469 if (fi->last_readdir) 493 dout("release inode %p dir file %p\n", inode, file);
470 ceph_mdsc_put_request(fi->last_readdir); 494 WARN_ON(!list_empty(&dfi->file_info.rw_contexts));
471 kfree(fi->last_name); 495
472 kfree(fi->dir_info); 496 ceph_put_fmode(ci, dfi->file_info.fmode);
473 WARN_ON(!list_empty(&fi->rw_contexts)); 497
474 kmem_cache_free(ceph_file_cachep, fi); 498 if (dfi->last_readdir)
499 ceph_mdsc_put_request(dfi->last_readdir);
500 kfree(dfi->last_name);
501 kfree(dfi->dir_info);
502 kmem_cache_free(ceph_dir_file_cachep, dfi);
503 } else {
504 struct ceph_file_info *fi = file->private_data;
505 dout("release inode %p regular file %p\n", inode, file);
506 WARN_ON(!list_empty(&fi->rw_contexts));
507
508 ceph_put_fmode(ci, fi->fmode);
509 kmem_cache_free(ceph_file_cachep, fi);
510 }
475 511
476 /* wake up anyone waiting for caps on this inode */ 512 /* wake up anyone waiting for caps on this inode */
477 wake_up_all(&ci->i_cap_wq); 513 wake_up_all(&ci->i_cap_wq);